twm.c revision f66df612
1/*****************************************************************************/
2/*
3
4Copyright 1989, 1998  The Open Group
5Copyright 2005 Hitachi, Ltd.
6
7Permission to use, copy, modify, distribute, and sell this software and its
8documentation for any purpose is hereby granted without fee, provided that
9the above copyright notice appear in all copies and that both that
10copyright notice and this permission notice appear in supporting
11documentation.
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from The Open Group.
26
27*/
28/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
29/**                          Salt Lake City, Utah                           **/
30/**                        Cambridge, Massachusetts                         **/
31/**                                                                         **/
32/**                           All Rights Reserved                           **/
33/**                                                                         **/
34/**    Permission to use, copy, modify, and distribute this software and    **/
35/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
36/**    granted, provided that the above copyright notice appear  in  all    **/
37/**    copies and that both  that  copyright  notice  and  this  permis-    **/
38/**    sion  notice appear in supporting  documentation,  and  that  the    **/
39/**    name of Evans & Sutherland not be used in advertising    **/
40/**    in publicity pertaining to distribution of the  software  without    **/
41/**    specific, written prior permission.                                  **/
42/**                                                                         **/
43/**    EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD    **/
44/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
45/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND    **/
46/**    BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
47/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
48/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
49/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
50/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
51/*****************************************************************************/
52
53/***********************************************************************
54 *
55 * twm - "Tom's Window Manager"
56 *
57 * 27-Oct-1987 Thomas E. LaStrange    File created
58 * 10-Oct-1990 David M. Sternlicht    Storing saved colors on root
59 * 19-Feb-2005 Julien Lafon           Handle print screens for unified Xserver
60 ***********************************************************************/
61
62#include <stdio.h>
63#include <signal.h>
64#include <fcntl.h>
65#include <stdarg.h>
66
67#include "twm.h"
68#include "iconmgr.h"
69#include "add_window.h"
70#include "gc.h"
71#include "parse.h"
72#include "menus.h"
73#include "events.h"
74#include "util.h"
75#include "gram.h"
76#include "screen.h"
77#include "parse.h"
78#include "session.h"
79
80#include <X11/Xproto.h>
81#include <X11/Xatom.h>
82#include <X11/SM/SMlib.h>
83#include <X11/Xmu/Error.h>
84#include <X11/extensions/sync.h>
85#include <X11/Xlocale.h>
86
87#ifdef XPRINT
88#include <X11/extensions/Print.h>
89#endif                          /* XPRINT */
90
91#ifdef HAVE_XRANDR
92#include <X11/extensions/Xrandr.h>
93#endif
94
95static void InitVariables(void);
96
97XtAppContext appContext;        /* Xt application context */
98XtSignalId si;
99
100Display *dpy = NULL;            /* which display are we talking to */
101Window ResizeWindow;            /* the window we are resizing */
102
103int MultiScreen = TRUE;         /* try for more than one screen? */
104int NoPrintscreens = False;     /* ignore special handling of print screens? */
105int NumScreens;                 /* number of screens in ScreenList */
106int HasShape;                   /* server supports shape extension? */
107
108#ifdef HAVE_XRANDR
109int HasXrandr;                  /* server supports Xrandr extension? */
110int XrandrEventBase, XrandrErrorBase;
111#endif
112
113int ShapeEventBase, ShapeErrorBase;
114int HasSync;                    /* server supports SYNC extension? */
115int SyncEventBase, SyncErrorBase;
116ScreenInfo **ScreenList;        /* structures for each screen */
117ScreenInfo *Scr = NULL;         /* the cur and prev screens */
118int PreviousScreen;             /* last screen that we were on */
119int FirstScreen;                /* TRUE ==> first screen of display */
120int message_level = 1;          /* controls error messages */
121static int RedirectError;       /* TRUE ==> another window manager running */
122static int TwmErrorHandler(Display *dpy, XErrorEvent *event);   /* for setting RedirectError */
123static int CatchRedirectError(Display *dpy, XErrorEvent *event);        /* for everything else */
124static void sigHandler(int);
125char Info[INFO_LINES][INFO_SIZE];       /* info strings to print */
126int InfoLines;
127static char *InitFile = NULL;
128
129Cursor UpperLeftCursor;         /* upper Left corner cursor */
130Cursor RightButt;
131Cursor MiddleButt;
132Cursor LeftButt;
133
134XContext TwmContext;            /* context for twm windows */
135XContext MenuContext;           /* context for all menu windows */
136XContext IconManagerContext;    /* context for all window list windows */
137XContext ScreenContext;         /* context to get screen data */
138XContext ColormapContext;       /* context for colormap operations */
139
140XClassHint NoClass;             /* for applications with no class */
141
142XGCValues Gcv;
143
144const char *Home;               /* the HOME environment variable */
145int HomeLen;                    /* length of Home */
146int ParseError;                 /* error parsing the .twmrc file */
147
148int HandlingEvents = FALSE;     /* are we handling events yet? */
149
150Window JunkRoot;                /* junk window */
151Window JunkChild;               /* junk window */
152int JunkX;                      /* junk variable */
153int JunkY;                      /* junk variable */
154unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask;
155
156char *ProgramName;
157int Argc;
158char **Argv;
159
160Bool RestartPreviousState = False;      /* try to restart in previous state */
161
162static unsigned long black, white;
163
164Atom TwmAtoms[11];
165
166Bool use_fontset;               /* use XFontSet-related functions or not */
167
168/* don't change the order of these strings */
169static char *atom_names[11] = {
170    "_MIT_PRIORITY_COLORS",
171    "WM_CHANGE_STATE",
172    "WM_STATE",
173    "WM_COLORMAP_WINDOWS",
174    "WM_PROTOCOLS",
175    "WM_TAKE_FOCUS",
176    "WM_SAVE_YOURSELF",
177    "WM_DELETE_WINDOW",
178    "SM_CLIENT_ID",
179    "WM_CLIENT_LEADER",
180    "WM_WINDOW_ROLE"
181};
182
183#ifdef XPRINT
184/* |hasExtension()| and |IsPrintScreen()| have been stolen from
185 * xc/programs/xdpyinfo/xdpyinfo.c */
186static Bool
187hasExtension(Display *dpy2, char *extname)
188{
189    int num_extensions, i;
190    char **extensions;
191
192    extensions = XListExtensions(dpy2, &num_extensions);
193    for (i = 0; i < num_extensions &&
194         (strcmp(extensions[i], extname) != 0); i++);
195    XFreeExtensionList(extensions);
196    return i != num_extensions;
197}
198
199static Bool
200IsPrintScreen(Screen *s)
201{
202    Display *dpy2 = XDisplayOfScreen(s);
203
204    /* Check whether this is a screen of a print DDX */
205    if (hasExtension(dpy2, XP_PRINTNAME)) {
206        Screen **pscreens;
207        int pscrcount;
208        int i;
209
210        pscreens = XpQueryScreens(dpy2, &pscrcount);
211        for (i = 0; (i < pscrcount) && pscreens; i++) {
212            if (s == pscreens[i]) {
213                return True;
214            }
215        }
216        XFree(pscreens);
217    }
218    return False;
219}
220#endif                          /* XPRINT */
221
222static void
223usage(void)
224{
225    fprintf(stderr, "usage:  %s [-display dpy] [-f file] [-s] [-q] [-v] [-V]"
226#ifdef XPRINT
227            " [-noprint]"
228#endif                          /* XPRINT */
229            " [-clientId id] [-restore file]\n", ProgramName);
230    exit(EXIT_FAILURE);
231}
232
233static Bool
234brief_opt(const char *param, const char *option)
235{
236    size_t have = strlen(++param);
237    size_t want = strlen(option);
238    Bool result = False;
239
240    if (have <= want) {
241        if (!strncmp(param, option, have))
242            result = True;
243    }
244    return result;
245}
246
247/***********************************************************************
248 *
249 *  Procedure:
250 *      main - start of twm
251 *
252 ***********************************************************************
253 */
254
255int
256main(int argc, char *argv[])
257{
258    Window root, parent, *children;
259    unsigned int nchildren;
260    int i, j;
261    char *display_name = NULL;
262    unsigned long valuemask;    /* mask for create windows */
263    XSetWindowAttributes attributes;    /* attributes for create windows */
264    int numManaged, firstscrn, lastscrn, scrnum;
265    int zero = 0;
266    char *restore_filename = NULL;
267    char *client_id = NULL;
268    char *loc;
269
270    ProgramName = argv[0];
271    Argc = argc;
272    Argv = argv;
273
274    for (i = 1; i < argc; i++) {
275        if (argv[i][0] == '-') {
276            switch (argv[i][1]) {
277            case 'V':
278                printf("%s %s\n", APP_NAME, APP_VERSION);
279                exit(EXIT_SUCCESS);
280            case 'd':          /* -display dpy */
281                if (!brief_opt(argv[i], "display"))
282                    usage();
283                if (++i >= argc)
284                    usage();
285                display_name = argv[i];
286                continue;
287            case 's':          /* -single */
288                if (!brief_opt(argv[i], "single"))
289                    usage();
290                MultiScreen = FALSE;
291                continue;
292#ifdef XPRINT
293            case 'n':          /* -noprint */
294                if (!brief_opt(argv[i], "noprint"))
295                    usage();
296                NoPrintscreens = True;
297                continue;
298#endif                          /* XPRINT */
299            case 'f':          /* -file twmrcfilename */
300                if (!brief_opt(argv[i], "file"))
301                    usage();
302                if (++i >= argc)
303                    usage();
304                InitFile = argv[i];
305                continue;
306            case 'v':          /* -verbose */
307                if (!brief_opt(argv[i], "verbose"))
308                    usage();
309                message_level++;
310                continue;
311            case 'c':          /* -clientId */
312                if (!brief_opt(argv[i], "clientId"))
313                    usage();
314                if (++i >= argc)
315                    usage();
316                client_id = argv[i];
317                continue;
318            case 'r':          /* -restore */
319                if (!brief_opt(argv[i], "restore"))
320                    usage();
321                if (++i >= argc)
322                    usage();
323                restore_filename = argv[i];
324                continue;
325            case 'q':          /* -quiet */
326                if (!brief_opt(argv[i], "quiet"))
327                    usage();
328                --message_level;
329                continue;
330            }
331        }
332        usage();
333    }
334
335    loc = setlocale(LC_ALL, "");
336    if (!loc || !strcmp(loc, "C") || !strcmp(loc, "POSIX") ||
337        !XSupportsLocale()) {
338        use_fontset = False;
339    }
340    else {
341        use_fontset = True;
342    }
343
344#define newhandler(sig) \
345    if (signal (sig, SIG_IGN) != SIG_IGN) (void) signal (sig, sigHandler)
346
347    newhandler(SIGINT);
348    newhandler(SIGHUP);
349    newhandler(SIGQUIT);
350    newhandler(SIGTERM);
351
352#undef newhandler
353
354    Home = getenv("HOME");
355    if (Home != NULL) {
356        char *temp_p;
357
358        /*
359         * Make a copy of Home because the string returned by getenv() can be
360         * overwritten by some POSIX.1 and ANSI-C implementations of getenv()
361         * when further calls to getenv() are made
362         */
363
364        temp_p = strdup(Home);
365        Home = temp_p;
366    }
367
368    if (Home == NULL)
369        Home = "./";
370
371    HomeLen = (int) strlen(Home);
372
373    NoClass.res_name = NoName;
374    NoClass.res_class = NoName;
375
376    XtToolkitInitialize();
377    appContext = XtCreateApplicationContext();
378
379    si = XtAppAddSignal(appContext, Done, NULL);
380
381    if (!(dpy = XtOpenDisplay(appContext, display_name, "twm", "twm",
382                              NULL, 0, &zero, NULL))) {
383        twmError("unable to open display \"%s\"", XDisplayName(display_name));
384    }
385
386    if (fcntl(ConnectionNumber(dpy), F_SETFD, 1) == -1) {
387        twmError("unable to mark display connection as close-on-exec");
388    }
389
390    if (restore_filename)
391        ReadWinConfigFile(restore_filename);
392
393    HasShape = XShapeQueryExtension(dpy, &ShapeEventBase, &ShapeErrorBase);
394    HasSync = XSyncQueryExtension(dpy, &SyncEventBase, &SyncErrorBase);
395#ifdef HAVE_XRANDR
396    HasXrandr = XRRQueryExtension(dpy, &XrandrEventBase, &XrandrErrorBase);
397#endif
398    TwmContext = XUniqueContext();
399    MenuContext = XUniqueContext();
400    IconManagerContext = XUniqueContext();
401    ScreenContext = XUniqueContext();
402    ColormapContext = XUniqueContext();
403
404    (void) XInternAtoms(dpy, atom_names, sizeof TwmAtoms / sizeof TwmAtoms[0],
405                        False, TwmAtoms);
406
407    /* Set up the per-screen global information. */
408
409    NumScreens = ScreenCount(dpy);
410
411    if (MultiScreen) {
412        firstscrn = 0;
413        lastscrn = NumScreens - 1;
414    }
415    else {
416        firstscrn = lastscrn = DefaultScreen(dpy);
417    }
418
419    InfoLines = 0;
420
421    /* for simplicity, always allocate NumScreens ScreenInfo struct pointers */
422    ScreenList = calloc((size_t) NumScreens, sizeof(ScreenInfo *));
423    if (ScreenList == NULL) {
424        twmError("Unable to allocate memory for screen list, exiting");
425    }
426    numManaged = 0;
427    PreviousScreen = DefaultScreen(dpy);
428    FirstScreen = TRUE;
429    for (scrnum = firstscrn; scrnum <= lastscrn; scrnum++) {
430#ifdef XPRINT
431        /* Ignore print screens to avoid that users accidentally warp on a
432         * print screen (which are not visible on video displays) */
433        if ((!NoPrintscreens) && IsPrintScreen(XScreenOfDisplay(dpy, scrnum))) {
434            twmWarning("skipping print screen %d", scrnum);
435            continue;
436        }
437#endif                          /* XPRINT */
438
439        /* Make sure property priority colors is empty */
440        XChangeProperty(dpy, RootWindow(dpy, scrnum), _XA_MIT_PRIORITY_COLORS,
441                        XA_CARDINAL, 32, PropModeReplace, NULL, 0);
442        RedirectError = FALSE;
443        XSetErrorHandler(CatchRedirectError);
444        XSelectInput(dpy, RootWindow(dpy, scrnum),
445                     ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
446                     SubstructureRedirectMask | KeyPressMask |
447                     ButtonPressMask | ButtonReleaseMask);
448        XSync(dpy, 0);
449        XSetErrorHandler(TwmErrorHandler);
450
451        if (RedirectError) {
452            if (MultiScreen && NumScreens > 0) {
453                twmWarning("another window manager is already running."
454                           " on screen %d?\n", scrnum);
455            }
456            else {
457                twmWarning("another window manager is already running.");
458            }
459            continue;
460        }
461
462        numManaged++;
463
464        /* Note:  ScreenInfo struct is calloc'ed to initialize to zero. */
465        Scr = ScreenList[scrnum] = calloc(1, sizeof(ScreenInfo));
466        if (Scr == NULL) {
467            twmWarning
468                ("unable to allocate memory for ScreenInfo structure for screen %d.",
469                 scrnum);
470            continue;
471        }
472
473        /* initialize list pointers, remember to put an initialization
474         * in InitVariables also
475         */
476        Scr->BorderColorL = NULL;
477        Scr->IconBorderColorL = NULL;
478        Scr->BorderTileForegroundL = NULL;
479        Scr->BorderTileBackgroundL = NULL;
480        Scr->TitleForegroundL = NULL;
481        Scr->TitleBackgroundL = NULL;
482        Scr->IconForegroundL = NULL;
483        Scr->IconBackgroundL = NULL;
484        Scr->NoTitle = NULL;
485        Scr->MakeTitle = NULL;
486        Scr->AutoRaise = NULL;
487        Scr->IconNames = NULL;
488        Scr->NoHighlight = NULL;
489        Scr->NoStackModeL = NULL;
490        Scr->NoTitleHighlight = NULL;
491        Scr->DontIconify = NULL;
492        Scr->IconMgrNoShow = NULL;
493        Scr->IconMgrShow = NULL;
494        Scr->IconifyByUn = NULL;
495        Scr->IconManagerFL = NULL;
496        Scr->IconManagerBL = NULL;
497        Scr->IconMgrs = NULL;
498        Scr->StartIconified = NULL;
499        Scr->SqueezeTitleL = NULL;
500        Scr->DontSqueezeTitleL = NULL;
501        Scr->WindowRingL = NULL;
502        Scr->WarpCursorL = NULL;
503        /* remember to put an initialization in InitVariables also
504         */
505
506        Scr->screen = scrnum;
507        Scr->d_depth = DefaultDepth(dpy, scrnum);
508        Scr->d_visual = DefaultVisual(dpy, scrnum);
509        Scr->Root = RootWindow(dpy, scrnum);
510        XSaveContext(dpy, Scr->Root, ScreenContext, (XPointer) Scr);
511
512        Scr->TwmRoot.cmaps.number_cwins = 1;
513        Scr->TwmRoot.cmaps.cwins = malloc(sizeof(ColormapWindow *));
514        Scr->TwmRoot.cmaps.cwins[0] =
515            CreateColormapWindow(Scr->Root, True, False);
516        Scr->TwmRoot.cmaps.cwins[0]->visibility = VisibilityPartiallyObscured;
517
518        Scr->cmapInfo.cmaps = NULL;
519        Scr->cmapInfo.maxCmaps =
520            MaxCmapsOfScreen(ScreenOfDisplay(dpy, Scr->screen));
521        Scr->cmapInfo.root_pushes = 0;
522        InstallWindowColormaps(0, &Scr->TwmRoot);
523
524        Scr->StdCmapInfo.head = Scr->StdCmapInfo.tail =
525            Scr->StdCmapInfo.mru = NULL;
526        Scr->StdCmapInfo.mruindex = 0;
527        LocateStandardColormaps();
528
529        Scr->TBInfo.nleft = Scr->TBInfo.nright = 0;
530        Scr->TBInfo.head = NULL;
531        Scr->TBInfo.border = 1;
532        Scr->TBInfo.width = 0;
533        Scr->TBInfo.leftx = 0;
534        Scr->TBInfo.titlex = 0;
535
536        Scr->MyDisplayWidth = DisplayWidth(dpy, scrnum);
537        Scr->MyDisplayHeight = DisplayHeight(dpy, scrnum);
538        Scr->MaxWindowWidth = 32767 - Scr->MyDisplayWidth;
539        Scr->MaxWindowHeight = 32767 - Scr->MyDisplayHeight;
540
541        Scr->XORvalue = (((unsigned long) 1) << Scr->d_depth) - 1;
542
543        if (DisplayCells(dpy, scrnum) < 3)
544            Scr->Monochrome = MONOCHROME;
545        else if (DefaultVisual(dpy, scrnum)->class == GrayScale)
546            Scr->Monochrome = GRAYSCALE;
547        else
548            Scr->Monochrome = COLOR;
549
550        /* setup default colors */
551        Scr->FirstTime = TRUE;
552        GetColor(Scr->Monochrome, &black, "black");
553        Scr->Black = black;
554        GetColor(Scr->Monochrome, &white, "white");
555        Scr->White = white;
556
557        if (FirstScreen) {
558            SetFocus((TwmWindow *) NULL, CurrentTime);
559
560            /* define cursors */
561
562            NewFontCursor(&UpperLeftCursor, "top_left_corner");
563            NewFontCursor(&RightButt, "rightbutton");
564            NewFontCursor(&LeftButt, "leftbutton");
565            NewFontCursor(&MiddleButt, "middlebutton");
566        }
567
568        Scr->iconmgr.x = 0;
569        Scr->iconmgr.y = 0;
570        Scr->iconmgr.width = 150;
571        Scr->iconmgr.height = 5;
572        Scr->iconmgr.next = NULL;
573        Scr->iconmgr.prev = NULL;
574        Scr->iconmgr.lasti = &(Scr->iconmgr);
575        Scr->iconmgr.first = NULL;
576        Scr->iconmgr.last = NULL;
577        Scr->iconmgr.active = NULL;
578        Scr->iconmgr.scr = Scr;
579        Scr->iconmgr.columns = 1;
580        Scr->iconmgr.count = 0;
581        Scr->iconmgr.name = "TWM";
582        Scr->iconmgr.icon_name = "Icons";
583
584        Scr->IconDirectory = NULL;
585
586        Scr->siconifyPm = None;
587        Scr->pullPm = None;
588        Scr->hilitePm = None;
589        Scr->tbpm.xlogo = None;
590        Scr->tbpm.resize = None;
591        Scr->tbpm.question = None;
592        Scr->tbpm.menu = None;
593        Scr->tbpm.delete = None;
594
595        InitVariables();
596        InitMenus();
597
598        /* Parse it once for each screen. */
599        ParseTwmrc(InitFile);
600        assign_var_savecolor(); /* storing pixels for twmrc "entities" */
601        if (Scr->SqueezeTitle == -1)
602            Scr->SqueezeTitle = FALSE;
603        if (!Scr->HaveFonts)
604            CreateFonts();
605        CreateGCs();
606        MakeMenus();
607
608        Scr->TitleBarFont.y += Scr->FramePadding;
609        Scr->TitleHeight = Scr->TitleBarFont.height + Scr->FramePadding * 2;
610        /* make title height be odd so buttons look nice and centered */
611        if (!(Scr->TitleHeight & 1))
612            Scr->TitleHeight++;
613
614        InitTitlebarButtons();  /* menus are now loaded! */
615
616        XGrabServer(dpy);
617        XSync(dpy, 0);
618
619        JunkX = 0;
620        JunkY = 0;
621
622        XQueryTree(dpy, Scr->Root, &root, &parent, &children, &nchildren);
623        CreateIconManagers();
624        if (!Scr->NoIconManagers)
625            Scr->iconmgr.twm_win->icon = TRUE;
626
627        /*
628         * weed out icon windows
629         */
630        for (i = 0; (unsigned) i < nchildren; i++) {
631            if (children[i]) {
632                XWMHints *wmhintsp = XGetWMHints(dpy, children[i]);
633
634                if (wmhintsp) {
635                    if (wmhintsp->flags & IconWindowHint) {
636                        for (j = 0; (unsigned) j < nchildren; j++) {
637                            if (children[j] == wmhintsp->icon_window) {
638                                children[j] = None;
639                                break;
640                            }
641                        }
642                    }
643                    XFree(wmhintsp);
644                }
645            }
646        }
647
648        /*
649         * map all of the non-override windows
650         */
651        for (i = 0; (unsigned) i < nchildren; i++) {
652            if (children[i] && MappedNotOverride(children[i])) {
653                XUnmapWindow(dpy, children[i]);
654                SimulateMapRequest(children[i]);
655            }
656        }
657
658        if (Scr->ShowIconManager && !Scr->NoIconManagers) {
659            Scr->iconmgr.twm_win->icon = FALSE;
660            if (Scr->iconmgr.count) {
661                SetMapStateProp(Scr->iconmgr.twm_win, NormalState);
662                XMapWindow(dpy, Scr->iconmgr.w);
663                XMapWindow(dpy, Scr->iconmgr.twm_win->frame);
664            }
665        }
666
667        attributes.border_pixel = Scr->DefaultC.fore;
668        attributes.background_pixel = Scr->DefaultC.back;
669        attributes.event_mask = (ExposureMask | ButtonPressMask |
670                                 KeyPressMask | ButtonReleaseMask);
671        attributes.backing_store = NotUseful;
672        attributes.cursor = XCreateFontCursor(dpy, XC_hand2);
673        valuemask = (CWBorderPixel | CWBackPixel | CWEventMask |
674                     CWBackingStore | CWCursor);
675        Scr->InfoWindow = XCreateWindow(dpy, Scr->Root, 0, 0,
676                                        (unsigned int) 5, (unsigned int) 5,
677                                        (unsigned int) BW, 0,
678                                        (unsigned int) CopyFromParent,
679                                        (Visual *) CopyFromParent,
680                                        valuemask, &attributes);
681
682        Scr->SizeStringWidth = MyFont_TextWidth(&Scr->SizeFont,
683                                                " 8888 x 8888 ", 13);
684        valuemask = (CWBorderPixel | CWBackPixel | CWBitGravity);
685        attributes.bit_gravity = NorthWestGravity;
686        Scr->SizeWindow = XCreateWindow(dpy, Scr->Root, 0, 0,
687                                        (unsigned int) Scr->SizeStringWidth,
688                                        (unsigned int) (Scr->SizeFont.height +
689                                                        SIZE_VINDENT * 2),
690                                        (unsigned int) BW, 0,
691                                        (unsigned int) CopyFromParent,
692                                        (Visual *) CopyFromParent,
693                                        valuemask, &attributes);
694
695        XUngrabServer(dpy);
696
697        FirstScreen = FALSE;
698        Scr->FirstTime = FALSE;
699    }                           /* for */
700
701    if (numManaged == 0) {
702        if (MultiScreen && NumScreens > 0) {
703            twmError("unable to find any unmanaged %sscreens.\n",
704                     NoPrintscreens ? "" : "video ");
705        }
706        exit(EXIT_FAILURE);
707    }
708
709    (void) ConnectToSessionManager(client_id);
710
711    RestartPreviousState = False;
712    HandlingEvents = TRUE;
713    InitEvents();
714    HandleEvents();
715    exit(EXIT_SUCCESS);
716}
717
718/**
719 * initialize twm variables
720 */
721static void
722InitVariables(void)
723{
724    FreeList(&Scr->BorderColorL);
725    FreeList(&Scr->IconBorderColorL);
726    FreeList(&Scr->BorderTileForegroundL);
727    FreeList(&Scr->BorderTileBackgroundL);
728    FreeList(&Scr->TitleForegroundL);
729    FreeList(&Scr->TitleBackgroundL);
730    FreeList(&Scr->IconForegroundL);
731    FreeList(&Scr->IconBackgroundL);
732    FreeList(&Scr->IconManagerFL);
733    FreeList(&Scr->IconManagerBL);
734    FreeList(&Scr->IconMgrs);
735    FreeList(&Scr->NoTitle);
736    FreeList(&Scr->MakeTitle);
737    FreeList(&Scr->AutoRaise);
738    FreeList(&Scr->IconNames);
739    FreeList(&Scr->NoHighlight);
740    FreeList(&Scr->NoStackModeL);
741    FreeList(&Scr->NoTitleHighlight);
742    FreeList(&Scr->DontIconify);
743    FreeList(&Scr->IconMgrNoShow);
744    FreeList(&Scr->IconMgrShow);
745    FreeList(&Scr->IconifyByUn);
746    FreeList(&Scr->StartIconified);
747    FreeList(&Scr->IconManagerHighlightL);
748    FreeList(&Scr->SqueezeTitleL);
749    FreeList(&Scr->DontSqueezeTitleL);
750    FreeList(&Scr->WindowRingL);
751    FreeList(&Scr->WarpCursorL);
752
753    NewFontCursor(&Scr->FrameCursor, "top_left_arrow");
754    NewFontCursor(&Scr->TitleCursor, "top_left_arrow");
755    NewFontCursor(&Scr->IconCursor, "top_left_arrow");
756    NewFontCursor(&Scr->IconMgrCursor, "top_left_arrow");
757    NewFontCursor(&Scr->MoveCursor, "fleur");
758    NewFontCursor(&Scr->ResizeCursor, "fleur");
759    NewFontCursor(&Scr->MenuCursor, "sb_left_arrow");
760    NewFontCursor(&Scr->ButtonCursor, "hand2");
761    NewFontCursor(&Scr->WaitCursor, "watch");
762    NewFontCursor(&Scr->SelectCursor, "dot");
763    NewFontCursor(&Scr->DestroyCursor, "pirate");
764
765    Scr->Ring = NULL;
766    Scr->RingLeader = NULL;
767
768    Scr->DefaultC.fore = black;
769    Scr->DefaultC.back = white;
770    Scr->BorderColor = black;
771    Scr->BorderTileC.fore = black;
772    Scr->BorderTileC.back = white;
773    Scr->TitleC.fore = black;
774    Scr->TitleC.back = white;
775    Scr->MenuC.fore = black;
776    Scr->MenuC.back = white;
777    Scr->MenuTitleC.fore = black;
778    Scr->MenuTitleC.back = white;
779    Scr->MenuShadowColor = black;
780    Scr->MenuBorderColor = black;
781    Scr->IconC.fore = black;
782    Scr->IconC.back = white;
783    Scr->IconBorderColor = black;
784    Scr->PointerForeground.pixel = black;
785    XQueryColor(dpy, Scr->TwmRoot.cmaps.cwins[0]->colormap->c,
786                &Scr->PointerForeground);
787    Scr->PointerBackground.pixel = white;
788    XQueryColor(dpy, Scr->TwmRoot.cmaps.cwins[0]->colormap->c,
789                &Scr->PointerBackground);
790    Scr->IconManagerC.fore = black;
791    Scr->IconManagerC.back = white;
792    Scr->IconManagerHighlight = black;
793
794    Scr->FramePadding = 2;      /* values that look "nice" on */
795    Scr->TitlePadding = 8;      /* 75 and 100dpi displays */
796    Scr->ButtonIndent = 1;
797    Scr->SizeStringOffset = 0;
798    Scr->BorderWidth = BW;
799    Scr->IconBorderWidth = BW;
800    Scr->MenuBorderWidth = BW;
801    Scr->UnknownWidth = 0;
802    Scr->UnknownHeight = 0;
803    Scr->NumAutoRaises = 0;
804    Scr->NoDefaults = FALSE;
805    Scr->UsePPosition = PPOS_OFF;
806    Scr->FocusRoot = TRUE;
807    Scr->Focus = NULL;
808    Scr->WarpCursor = FALSE;
809    Scr->ForceIcon = FALSE;
810    Scr->NoGrabServer = FALSE;
811    Scr->NoRaiseMove = FALSE;
812    Scr->NoRaiseResize = FALSE;
813    Scr->NoRaiseDeicon = FALSE;
814    Scr->NoRaiseWarp = FALSE;
815    Scr->DontMoveOff = FALSE;
816    Scr->DoZoom = FALSE;
817    Scr->TitleFocus = TRUE;
818    Scr->NoTitlebar = FALSE;
819    Scr->DecorateTransients = FALSE;
820    Scr->IconifyByUnmapping = FALSE;
821    Scr->ShowIconManager = FALSE;
822    Scr->IconManagerDontShow = FALSE;
823    Scr->BackingStore = TRUE;
824    Scr->SaveUnder = TRUE;
825    Scr->RandomPlacement = FALSE;
826    Scr->OpaqueMove = FALSE;
827    Scr->Highlight = TRUE;
828    Scr->StackMode = TRUE;
829    Scr->TitleHighlight = TRUE;
830    Scr->MoveDelta = 1;         /* so that f.deltastop will work */
831    Scr->ZoomCount = 8;
832    Scr->SortIconMgr = FALSE;
833    Scr->Shadow = TRUE;
834    Scr->InterpolateMenuColors = FALSE;
835    Scr->NoIconManagers = FALSE;
836    Scr->ClientBorderWidth = FALSE;
837    Scr->SqueezeTitle = -1;
838    Scr->FirstRegion = NULL;
839    Scr->LastRegion = NULL;
840    Scr->FirstTime = TRUE;
841    Scr->HaveFonts = FALSE;     /* i.e. not loaded yet */
842    Scr->CaseSensitive = TRUE;
843    Scr->WarpUnmapped = FALSE;
844
845    /* setup default fonts; overridden by defaults from system.twmrc */
846#define DEFAULT_NICE_FONT "variable"
847#define DEFAULT_FAST_FONT "fixed"
848
849    Scr->TitleBarFont.font = NULL;
850    Scr->TitleBarFont.fontset = NULL;
851    Scr->TitleBarFont.name = DEFAULT_NICE_FONT;
852    Scr->MenuFont.font = NULL;
853    Scr->MenuFont.fontset = NULL;
854    Scr->MenuFont.name = DEFAULT_NICE_FONT;
855    Scr->IconFont.font = NULL;
856    Scr->IconFont.fontset = NULL;
857    Scr->IconFont.name = DEFAULT_NICE_FONT;
858    Scr->SizeFont.font = NULL;
859    Scr->SizeFont.fontset = NULL;
860    Scr->SizeFont.name = DEFAULT_FAST_FONT;
861    Scr->IconManagerFont.font = NULL;
862    Scr->IconManagerFont.fontset = NULL;
863    Scr->IconManagerFont.name = DEFAULT_NICE_FONT;
864    Scr->DefaultFont.font = NULL;
865    Scr->DefaultFont.fontset = NULL;
866    Scr->DefaultFont.name = DEFAULT_FAST_FONT;
867
868}
869
870void
871CreateFonts(void)
872{
873    GetFont(&Scr->TitleBarFont);
874    GetFont(&Scr->MenuFont);
875    GetFont(&Scr->IconFont);
876    GetFont(&Scr->SizeFont);
877    GetFont(&Scr->IconManagerFont);
878    GetFont(&Scr->DefaultFont);
879    Scr->HaveFonts = TRUE;
880}
881
882void
883RestoreWithdrawnLocation(TwmWindow *tmp)
884{
885    int gravx, gravy;
886    unsigned int bw;
887    XWindowChanges xwc;
888
889    if (XGetGeometry(dpy, tmp->w, &JunkRoot, &xwc.x, &xwc.y,
890                     &JunkWidth, &JunkHeight, &bw, &JunkDepth)) {
891        unsigned mask;
892
893        GetGravityOffsets(tmp, &gravx, &gravy);
894        if (gravy < 0)
895            xwc.y -= tmp->title_height;
896
897        if (bw != (unsigned) tmp->old_bw) {
898            int xoff, yoff;
899
900            if (!Scr->ClientBorderWidth) {
901                xoff = gravx;
902                yoff = gravy;
903            }
904            else {
905                xoff = 0;
906                yoff = 0;
907            }
908
909            xwc.x -= (xoff + 1) * tmp->old_bw;
910            xwc.y -= (yoff + 1) * tmp->old_bw;
911        }
912        if (!Scr->ClientBorderWidth) {
913            xwc.x += gravx * tmp->frame_bw;
914            xwc.y += gravy * tmp->frame_bw;
915        }
916
917        mask = (CWX | CWY);
918        if (bw != (unsigned) tmp->old_bw) {
919            xwc.border_width = tmp->old_bw;
920            mask |= CWBorderWidth;
921        }
922
923        XConfigureWindow(dpy, tmp->w, mask, &xwc);
924
925        if (tmp->wmhints && (tmp->wmhints->flags & IconWindowHint)) {
926            XUnmapWindow(dpy, tmp->wmhints->icon_window);
927        }
928
929    }
930}
931
932void
933Reborder(Time time)
934{
935    TwmWindow *tmp;             /* temp twm window structure */
936    int scrnum;
937
938    /* put a border back around all windows */
939
940    XGrabServer(dpy);
941    for (scrnum = 0; scrnum < NumScreens; scrnum++) {
942        if ((Scr = ScreenList[scrnum]) == NULL)
943            continue;
944
945        InstallWindowColormaps(0, &Scr->TwmRoot);       /* force reinstall */
946        for (tmp = Scr->TwmRoot.next; tmp != NULL; tmp = tmp->next) {
947            RestoreWithdrawnLocation(tmp);
948            XMapWindow(dpy, tmp->w);
949        }
950    }
951
952    XUngrabServer(dpy);
953    SetFocus((TwmWindow *) NULL, time);
954}
955
956static void
957sigHandler(int sig _X_UNUSED)
958{
959    XtNoticeSignal(si);
960}
961
962/**
963 * cleanup and exit twm
964 */
965void
966Done(XtPointer client_data _X_UNUSED, XtSignalId *si2 _X_UNUSED)
967{
968    if (dpy) {
969        Reborder(CurrentTime);
970        XCloseDisplay(dpy);
971    }
972    exit(EXIT_SUCCESS);
973}
974
975/*
976 * Error Handlers.  If a client dies, we'll get a BadWindow error (except for
977 * GetGeometry which returns BadDrawable) for most operations that we do before
978 * manipulating the client's window.
979 */
980
981Bool ErrorOccurred = False;
982XErrorEvent LastErrorEvent;
983
984static int
985TwmErrorHandler(Display *dpy2, XErrorEvent *event)
986{
987    LastErrorEvent = *event;
988    ErrorOccurred = True;
989
990    if ((message_level > 1) &&  /* don't be too obnoxious */
991        event->error_code != BadWindow &&       /* watch for dead puppies */
992        (event->request_code != X_GetGeometry &&        /* of all styles */
993         event->error_code != BadDrawable))
994        XmuPrintDefaultErrorMessage(dpy2, event, stderr);
995    return 0;
996}
997
998static int
999CatchRedirectError(Display *dpy2 _X_UNUSED, XErrorEvent *event)
1000{
1001    RedirectError = TRUE;
1002    LastErrorEvent = *event;
1003    ErrorOccurred = True;
1004    return 0;
1005}
1006
1007void
1008twmError(const char *format, ...)
1009{
1010    va_list ap;
1011
1012    va_start(ap, format);
1013    fprintf(stderr, "%s: error: ", ProgramName);
1014    vfprintf(stderr, format, ap);
1015    fputc('\n', stderr);
1016    va_end(ap);
1017    exit(EXIT_FAILURE);
1018}
1019
1020void
1021twmWarning(const char *format, ...)
1022{
1023    if (message_level > 0) {
1024        va_list ap;
1025
1026        va_start(ap, format);
1027        fprintf(stderr, "%s: warning: ", ProgramName);
1028        vfprintf(stderr, format, ap);
1029        fputc('\n', stderr);
1030        va_end(ap);
1031    }
1032}
1033
1034void
1035twmVerbose(const char *format, ...)
1036{
1037    if (message_level > 1) {
1038        va_list ap;
1039
1040        va_start(ap, format);
1041        fprintf(stderr, "%s: warning: ", ProgramName);
1042        vfprintf(stderr, format, ap);
1043        fputc('\n', stderr);
1044        va_end(ap);
1045    }
1046}
1047
1048void
1049twmMessage(const char *format, ...)
1050{
1051    va_list ap;
1052
1053    va_start(ap, format);
1054    printf("%s: ", ProgramName);
1055    vprintf(format, ap);
1056    putc('\n', stdout);
1057    va_end(ap);
1058
1059    fflush(stdout);
1060}
1061