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