Home | History | Annotate | Line # | Download | only in src
      1 /*****************************************************************************/
      2 /*
      3 
      4 Copyright 1989, 1998  The Open Group
      5 Copyright 2005 Hitachi, Ltd.
      6 
      7 Permission to use, copy, modify, distribute, and sell this software and its
      8 documentation for any purpose is hereby granted without fee, provided that
      9 the above copyright notice appear in all copies and that both that
     10 copyright notice and this permission notice appear in supporting
     11 documentation.
     12 
     13 The above copyright notice and this permission notice shall be included in
     14 all copies or substantial portions of the Software.
     15 
     16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     19 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22 
     23 Except as contained in this notice, the name of The Open Group shall not be
     24 used in advertising or otherwise to promote the sale, use or other dealings
     25 in 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 
     90 static void InitVariables(void);
     91 
     92 static XtSignalId si;
     93 
     94 Display *dpy = NULL;            /* which display are we talking to */
     95 Window ResizeWindow;            /* the window we are resizing */
     96 
     97 int NumScreens;                 /* number of screens in ScreenList */
     98 int HasShape;                   /* server supports shape extension? */
     99 
    100 #ifdef HAVE_XRANDR
    101 int HasXrandr;                  /* server supports Xrandr extension? */
    102 int XrandrEventBase, XrandrErrorBase;
    103 #endif
    104 
    105 int ShapeEventBase, ShapeErrorBase;
    106 int HasSync;                    /* server supports SYNC extension? */
    107 int SyncEventBase, SyncErrorBase;
    108 ScreenInfo **ScreenList;        /* structures for each screen */
    109 ScreenInfo *Scr = NULL;         /* the cur and prev screens */
    110 int PreviousScreen;             /* last screen that we were on */
    111 int message_level = 1;          /* controls error messages */
    112 static int RedirectError;       /* TRUE ==> another window manager running */
    113 static int TwmErrorHandler(Display *dpy, XErrorEvent *event);   /* for setting RedirectError */
    114 static int CatchRedirectError(Display *dpy, XErrorEvent *event);        /* for everything else */
    115 static void sigHandler(int);
    116 char Info[INFO_LINES][INFO_SIZE];       /* info strings to print */
    117 int InfoLines;
    118 
    119 Cursor UpperLeftCursor;         /* upper Left corner cursor */
    120 Cursor RightButt;
    121 Cursor MiddleButt;
    122 Cursor LeftButt;
    123 
    124 XContext TwmContext;            /* context for twm windows */
    125 XContext MenuContext;           /* context for all menu windows */
    126 XContext IconManagerContext;    /* context for all window list windows */
    127 XContext ScreenContext;         /* context to get screen data */
    128 XContext ColormapContext;       /* context for colormap operations */
    129 
    130 XClassHint NoClass;             /* for applications with no class */
    131 
    132 XGCValues Gcv;
    133 
    134 const char *Home;               /* the HOME environment variable */
    135 int HomeLen;                    /* length of Home */
    136 int ParseError;                 /* error parsing the .twmrc file */
    137 
    138 int HandlingEvents = FALSE;     /* are we handling events yet? */
    139 
    140 char *ProgramName;
    141 int Argc;
    142 char **Argv;
    143 
    144 Bool RestartPreviousState = False;      /* try to restart in previous state */
    145 
    146 static unsigned long black, white;
    147 
    148 Atom TwmAtoms[11];
    149 
    150 Bool use_fontset;               /* use XFontSet-related functions or not */
    151 
    152 /* don't change the order of these strings */
    153 static 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 
    167 static _X_NORETURN void
    168 usage(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 
    175 static Bool
    176 brief_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 
    197 int
    198 main(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  */
    655 static void
    656 InitVariables(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 
    804 void
    805 CreateFonts(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 
    816 static void
    817 DestroyFonts(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 
    836 void
    837 RestoreWithdrawnLocation(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 
    888 void
    889 Reborder(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 
    912 static void
    913 sigHandler(int sig _X_UNUSED)
    914 {
    915     XtNoticeSignal(si);
    916 }
    917 
    918 /**
    919  * cleanup and exit twm
    920  */
    921 void
    922 Done(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 
    940 Bool ErrorOccurred = False;
    941 XErrorEvent LastErrorEvent;
    942 
    943 static int
    944 TwmErrorHandler(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 
    957 static int
    958 CatchRedirectError(Display *dpy2 _X_UNUSED, XErrorEvent *event)
    959 {
    960     RedirectError = TRUE;
    961     LastErrorEvent = *event;
    962     ErrorOccurred = True;
    963     return 0;
    964 }
    965 
    966 void
    967 twmError(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 
    979 void
    980 twmWarning(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 
    993 void
    994 twmVerbose(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 
   1007 void
   1008 twmMessage(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