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