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