ctwm_main.c revision 0bbfda8a
1/* 2 * Copyright 1988 by Evans & Sutherland Computer Corporation, 3 * Salt Lake City, Utah 4 * Portions Copyright 1989 by the Massachusetts Institute of Technology 5 * Cambridge, Massachusetts 6 * 7 * $XConsortium: twm.c,v 1.124 91/05/08 11:01:54 dave Exp $ 8 * 9 * twm - "Tom's Window Manager" 10 * 11 * 27-Oct-87 Thomas E. LaStrange File created 12 * 10-Oct-90 David M. Sternlicht Storing saved colors on root 13 * 14 * Copyright 1992 Claude Lecommandeur. 15 * 16 * Do the necessary modification to be integrated in ctwm. 17 * Can no longer be used for the standard twm. 18 * 19 * 22-April-92 Claude Lecommandeur. 20 */ 21 22#include "ctwm.h" 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <signal.h> 27#include <unistd.h> 28#include <locale.h> 29 30#ifdef __WAIT_FOR_CHILDS 31# include <sys/wait.h> 32#endif 33 34#include <fcntl.h> 35#include <X11/Xproto.h> 36#include <X11/Xatom.h> 37#include <X11/Xmu/Error.h> 38#include <X11/extensions/shape.h> 39 40 41#include "ctwm_atoms.h" 42#include "ctwm_main.h" 43#include "clargs.h" 44#include "add_window.h" 45#include "gc.h" 46#include "parse.h" 47#include "version.h" 48#include "colormaps.h" 49#include "events.h" 50#include "util.h" 51#include "mask_screen.h" 52#include "animate.h" 53#include "screen.h" 54#include "icons.h" 55#include "iconmgr.h" 56#include "list.h" 57#include "session.h" 58#include "occupation.h" 59#include "otp.h" 60#include "cursor.h" 61#include "windowbox.h" 62#include "captive.h" 63#include "vscreen.h" 64#include "win_decorations_init.h" 65#include "win_ops.h" 66#include "win_regions.h" 67#include "win_utils.h" 68#include "workspace_manager.h" 69#ifdef SOUNDS 70# include "sound.h" 71#endif 72 73#include "gram.tab.h" 74 75 76XtAppContext appContext; /* Xt application context */ 77Display *dpy; /* which display are we talking to */ 78Window ResizeWindow; /* the window we are resizing */ 79 80int NumScreens; /* number of screens in ScreenList */ 81bool HasShape; /* server supports shape extension? */ 82int ShapeEventBase, ShapeErrorBase; 83ScreenInfo **ScreenList; /* structures for each screen */ 84ScreenInfo *Scr = NULL; /* the cur and prev screens */ 85int PreviousScreen; /* last screen that we were on */ 86static bool RedirectError; /* true ==> another window manager running */ 87/* for settting RedirectError */ 88static int CatchRedirectError(Display *display, XErrorEvent *event); 89/* for everything else */ 90static int TwmErrorHandler(Display *display, XErrorEvent *event); 91static Window CreateCaptiveRootWindow(int x, int y, 92 unsigned int width, unsigned int height); 93static void InternUsefulAtoms(void); 94ScreenInfo *InitScreenInfo(int scrnum, Window croot, int crootx, int crooty, 95 unsigned int crootw, unsigned int crooth); 96static bool MappedNotOverride(Window w); 97 98Cursor UpperLeftCursor; 99Cursor TopRightCursor, 100 TopLeftCursor, 101 BottomRightCursor, 102 BottomLeftCursor, 103 LeftCursor, 104 RightCursor, 105 TopCursor, 106 BottomCursor; 107 108Cursor RightButt; 109Cursor MiddleButt; 110Cursor LeftButt; 111 112XContext TwmContext; /* context for twm windows */ 113XContext MenuContext; /* context for all menu windows */ 114XContext ScreenContext; /* context to get screen data */ 115XContext ColormapContext; /* context for colormap operations */ 116 117XClassHint NoClass; /* for applications with no class */ 118 119XGCValues Gcv; 120 121char *Home; /* the HOME environment variable */ 122int HomeLen; /* length of Home */ 123 124bool HandlingEvents = false; /* are we handling events yet? */ 125 126/* 127 * Various junk vars for xlib calls. Many calls have to get passed these 128 * pointers to return values into, but in a lot of cases we don't care 129 * about some/all of them, and since xlib blindly derefs and stores into 130 * them, we can't just pass NULL for the ones we don't care about. So we 131 * make this set of globals to use as standin. These should never be 132 * used or read in our own code; use real vars for the values we DO use 133 * from the calls. 134 */ 135Window JunkRoot, JunkChild; 136int JunkX, JunkY; 137unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask; 138 139char *ProgramName; 140int Argc; 141char **Argv; 142 143bool RestartPreviousState = true; /* try to restart in previous state */ 144 145bool RestartFlag = false; 146SIGNAL_T Restart(int signum); 147SIGNAL_T Crash(int signum); 148#ifdef __WAIT_FOR_CHILDS 149SIGNAL_T ChildExit(int signum); 150#endif 151 152/*********************************************************************** 153 * 154 * Procedure: 155 * main - start of twm 156 * 157 *********************************************************************** 158 */ 159 160int 161ctwm_main(int argc, char *argv[]) 162{ 163 int numManaged, firstscrn, lastscrn; 164 bool FirstScreen; 165 166 setlocale(LC_ALL, ""); 167 168 ProgramName = argv[0]; 169 Argc = argc; 170 Argv = argv; 171 172 173 /* 174 * Run consistency check. This is mostly to keep devs from 175 * accidental screwups; if a user ever sees anything from this, 176 * something went very very wrong. 177 */ 178 chk_keytable_order(); 179 180 /* 181 * Parse-out command line args, and check the results. 182 */ 183 clargs_parse(argc, argv); 184 clargs_check(); 185 /* If we get this far, it was all good */ 186 187 188#define newhandler(sig, action) \ 189 if (signal (sig, SIG_IGN) != SIG_IGN) signal (sig, action) 190 191 newhandler(SIGINT, Done); 192 signal(SIGHUP, Restart); 193 newhandler(SIGQUIT, Done); 194 newhandler(SIGTERM, Done); 195#ifdef __WAIT_FOR_CHILDS 196 newhandler(SIGCHLD, ChildExit); 197#endif 198 signal(SIGALRM, SIG_IGN); 199#ifdef NOTRAP 200 signal(SIGSEGV, Crash); 201 signal(SIGBUS, Crash); 202#endif 203 204#undef newhandler 205 206 // Various bits of code care about $HOME 207 Home = getenv("HOME"); 208 if(Home == NULL) { 209 Home = "./"; 210 } 211 HomeLen = strlen(Home); 212 213 214 // XXX This is only used in AddWindow(), and is probably bogus to 215 // have globally.... 216 NoClass.res_name = NoName; 217 NoClass.res_class = NoName; 218 219 220 /* 221 * Initialize our X connection and state bits. 222 */ 223 { 224 int zero = 0; // Fakey 225 226 XtToolkitInitialize(); 227 appContext = XtCreateApplicationContext(); 228 229 if(!(dpy = XtOpenDisplay(appContext, CLarg.display_name, "twm", "twm", 230 NULL, 0, &zero, NULL))) { 231 fprintf(stderr, "%s: unable to open display \"%s\"\n", 232 ProgramName, XDisplayName(CLarg.display_name)); 233 exit(1); 234 } 235 236 if(fcntl(ConnectionNumber(dpy), F_SETFD, FD_CLOEXEC) == -1) { 237 fprintf(stderr, 238 "%s: unable to mark display connection as close-on-exec\n", 239 ProgramName); 240 exit(1); 241 } 242 } 243 244 245 // Load session stuff 246 if(CLarg.restore_filename) { 247 ReadWinConfigFile(CLarg.restore_filename); 248 } 249 250 // Load up info about X extensions 251 HasShape = XShapeQueryExtension(dpy, &ShapeEventBase, &ShapeErrorBase); 252 253 // Allocate contexts/atoms/etc we use 254 TwmContext = XUniqueContext(); 255 MenuContext = XUniqueContext(); 256 ScreenContext = XUniqueContext(); 257 ColormapContext = XUniqueContext(); 258 InitWorkSpaceManagerContext(); 259 260 InternUsefulAtoms(); 261 262 // Allocate/define common cursors 263 NewFontCursor(&TopLeftCursor, "top_left_corner"); 264 NewFontCursor(&TopRightCursor, "top_right_corner"); 265 NewFontCursor(&BottomLeftCursor, "bottom_left_corner"); 266 NewFontCursor(&BottomRightCursor, "bottom_right_corner"); 267 NewFontCursor(&LeftCursor, "left_side"); 268 NewFontCursor(&RightCursor, "right_side"); 269 NewFontCursor(&TopCursor, "top_side"); 270 NewFontCursor(&BottomCursor, "bottom_side"); 271 272 NewFontCursor(&UpperLeftCursor, "top_left_corner"); 273 NewFontCursor(&RightButt, "rightbutton"); 274 NewFontCursor(&LeftButt, "leftbutton"); 275 NewFontCursor(&MiddleButt, "middlebutton"); 276 277 278 // Prep up the per-screen global info 279 NumScreens = ScreenCount(dpy); 280 if(CLarg.MultiScreen) { 281 firstscrn = 0; 282 lastscrn = NumScreens - 1; 283 } 284 else { 285 firstscrn = lastscrn = DefaultScreen(dpy); 286 } 287 288 // For simplicity, pre-allocate NumScreens ScreenInfo struct pointers 289 ScreenList = calloc(NumScreens, sizeof(ScreenInfo *)); 290 if(ScreenList == NULL) { 291 fprintf(stderr, "%s: Unable to allocate memory for screen list, exiting.\n", 292 ProgramName); 293 exit(1); 294 } 295 296 // Initialize 297 PreviousScreen = DefaultScreen(dpy); 298 299 300 // Do a little early initialization 301#ifdef EWMH 302 EwmhInit(); 303#endif /* EWMH */ 304#ifdef SOUNDS 305 // Needs init'ing before we get to config parsing 306 sound_init(); 307#endif 308 InitEvents(); 309 310 // Start looping over the screens 311 numManaged = 0; 312 FirstScreen = true; 313 for(int scrnum = firstscrn ; scrnum <= lastscrn; scrnum++) { 314 Window croot; 315 unsigned long attrmask; 316 int crootx, crooty; 317 unsigned int crootw, crooth; 318 bool screenmasked; 319 char *welcomefile; 320 321 /* 322 * First, setup the root window for the screen. 323 */ 324 if(CLarg.is_captive) { 325 // Captive ctwm. We make a fake root. 326 XWindowAttributes wa; 327 if(CLarg.capwin && XGetWindowAttributes(dpy, CLarg.capwin, &wa)) { 328 Window junk; 329 croot = CLarg.capwin; 330 crootw = wa.width; 331 crooth = wa.height; 332 XTranslateCoordinates(dpy, CLarg.capwin, wa.root, 0, 0, &crootx, &crooty, 333 &junk); 334 } 335 else { 336 // Fake up default size. Probably ideally should be 337 // configurable, but even more ideally we wouldn't have 338 // captive... 339 crootx = crooty = 100; 340 crootw = 1280; 341 crooth = 768; 342 croot = CreateCaptiveRootWindow(crootx, crooty, crootw, crooth); 343 } 344 } 345 else { 346 // Normal; get the real display's root. 347 croot = RootWindow(dpy, scrnum); 348 crootx = 0; 349 crooty = 0; 350 crootw = DisplayWidth(dpy, scrnum); 351 crooth = DisplayHeight(dpy, scrnum); 352 } 353 354 // Initialize to empty. This gets populated with SaveColor{} 355 // results. String values get done via assign_var_savecolor() 356 // call below, but keyword choicse wind up getting put in on the 357 // fly during config file parsing, so we have to clear it before 358 // we get to the config. 359 // XXX Maybe we should change that... 360 XChangeProperty(dpy, croot, XA__MIT_PRIORITY_COLORS, 361 XA_CARDINAL, 32, PropModeReplace, NULL, 0); 362 363 364 /* 365 * Create ScreenInfo for this Screen, and populate various 366 * default/initial config. 367 */ 368 Scr = ScreenList[scrnum] = InitScreenInfo(scrnum, croot, 369 crootx, crooty, crootw, crooth); 370 if(Scr == NULL) { 371 fprintf(stderr, 372 "%s: unable to allocate memory for ScreenInfo structure" 373 " for screen %d.\n", 374 ProgramName, scrnum); 375 continue; 376 } 377 378 // Not trying to take over if we're just checking config or 379 // making a new captive ctwm. 380 if(CLarg.cfgchk || CLarg.is_captive) { 381 Scr->takeover = false; 382 } 383 384 // Other misc adjustments to default config. 385 Scr->ShowWelcomeWindow = CLarg.ShowWelcomeWindow; 386 387 388#ifdef EWMH 389 // Early EWMH setup 390 EwmhInitScreenEarly(Scr); 391#endif /* EWMH */ 392 393 // Early OTP setup 394 OtpScrInitData(Scr); 395 396 397 /* 398 * Subscribe to various events on the root window. Because X 399 * only allows a single client to subscribe to 400 * SubstructureRedirect and ButtonPress bits, this also serves to 401 * mutex who is The WM for the root window, and thus (aside from 402 * captive) the Screen. 403 * 404 * To catch whether that failed, we set a special one-shot error 405 * handler to flip a var that we test to find out whether the 406 * redirect failed. 407 */ 408 XSync(dpy, 0); // Flush possible previous errors 409 RedirectError = false; 410 XSetErrorHandler(CatchRedirectError); 411 attrmask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask | 412 SubstructureRedirectMask | KeyPressMask | ButtonPressMask | 413 ButtonReleaseMask; 414#ifdef EWMH 415 attrmask |= StructureNotifyMask; 416#endif /* EWMH */ 417 if(CLarg.is_captive) { 418 attrmask |= StructureNotifyMask; 419 } 420 XSelectInput(dpy, croot, attrmask); 421 XSync(dpy, 0); // Flush the RedirectError, if we had one 422 423 // Back to our normal handler 424 XSetErrorHandler(TwmErrorHandler); 425 426 if(RedirectError && Scr->takeover) { 427 fprintf(stderr, "%s: another window manager is already running", 428 ProgramName); 429 if(CLarg.MultiScreen && NumScreens > 0) { 430 fprintf(stderr, " on screen %d?\n", scrnum); 431 } 432 else { 433 fprintf(stderr, "?\n"); 434 } 435 436 // XSetErrorHandler() isn't local to the Screen; it's for the 437 // whole connection. We wind up in a slightly weird state 438 // once we've set it up, but decided we aren't taking over 439 // this screen, but resetting it would be a little weird too, 440 // because maybe we have taken over some other screen. So, 441 // just throw up our hands. 442 continue; 443 } 444 445 446 // We now manage it (or are in the various special circumstances 447 // where it's near enough). 448 numManaged ++; 449 450 451 // Now we can stash some info about the screen 452 Scr->d_depth = DefaultDepth(dpy, scrnum); 453 Scr->d_visual = DefaultVisual(dpy, scrnum); 454 Scr->RealRoot = RootWindow(dpy, scrnum); 455 456 // Now that we have d_depth... 457 Scr->XORvalue = (((unsigned long) 1) << Scr->d_depth) - 1; 458 459 // Stash up a ref to our Scr on the root, so we can find the 460 // right Scr for events etc. 461 XSaveContext(dpy, Scr->Root, ScreenContext, (XPointer) Scr); 462 463 // Init captive bits 464 if(CLarg.is_captive) { 465 Scr->CaptiveRoot = croot; 466 Scr->captivename = AddToCaptiveList(CLarg.captivename); 467 if(Scr->captivename) { 468 XmbSetWMProperties(dpy, croot, 469 Scr->captivename, Scr->captivename, 470 NULL, 0, NULL, NULL, NULL); 471 } 472 } 473 474 475 // Init some colormap bits 476 { 477 // 1 on the root 478 Scr->RootColormaps.number_cwins = 1; 479 Scr->RootColormaps.cwins = malloc(sizeof(ColormapWindow *)); 480 Scr->RootColormaps.cwins[0] = CreateColormapWindow(Scr->Root, true, 481 false); 482 Scr->RootColormaps.cwins[0]->visibility = VisibilityPartiallyObscured; 483 484 // Initialize storage for all maps the Screen can hold 485 Scr->cmapInfo.cmaps = NULL; 486 Scr->cmapInfo.maxCmaps = MaxCmapsOfScreen(ScreenOfDisplay(dpy, Scr->screen)); 487 Scr->cmapInfo.root_pushes = 0; 488 InstallColormaps(0, &Scr->RootColormaps); 489 490 // Setup which we're using 491 Scr->StdCmapInfo.head = Scr->StdCmapInfo.tail 492 = Scr->StdCmapInfo.mru = NULL; 493 Scr->StdCmapInfo.mruindex = 0; 494 LocateStandardColormaps(); 495 } 496 497 498 // Are we monochrome? Or do we care this millennium? 499 if(CLarg.Monochrome || DisplayCells(dpy, scrnum) < 3) { 500 Scr->Monochrome = MONOCHROME; 501 } 502 else { 503 Scr->Monochrome = COLOR; 504 } 505 506 507 // With the colormap/monochrome bits set, we can setup our 508 // default color bits. 509 GetColor(Scr->Monochrome, &(Scr->Black), "black"); 510 GetColor(Scr->Monochrome, &(Scr->White), "white"); 511 512 Scr->MenuShadowColor = Scr->Black; 513 Scr->IconBorderColor = Scr->Black; 514 Scr->IconManagerHighlight = Scr->Black; 515 516#define SETFB(fld) Scr->fld.fore = Scr->Black; Scr->fld.back = Scr->White; 517 SETFB(DefaultC) 518 SETFB(BorderColorC) 519 SETFB(BorderTileC) 520 SETFB(TitleC) 521 SETFB(MenuC) 522 SETFB(MenuTitleC) 523 SETFB(IconC) 524 SETFB(IconManagerC) 525 SETFB(workSpaceMgr.windowcp) 526 SETFB(workSpaceMgr.curColors) 527 SETFB(workSpaceMgr.defColors) 528#undef SETFB 529 530 531 // The first time around, we focus onto the root [of the first 532 // Screen]. Maybe we should revisit this... 533 if(FirstScreen) { 534 // XXX This func also involves a lot of stuff that isn't 535 // setup yet, and probably only works by accident. Maybe we 536 // should just manually extract out the couple bits we 537 // actually want to run? 538 SetFocus(NULL, CurrentTime); 539 FirstScreen = false; 540 } 541 542 // Create default icon manager memory bits (in the first 543 // workspace) 544 AllocateIconManager("TWM", "Icons", "", 1); 545 546 547 /* 548 * Mask over the screen with our welcome window stuff if we were 549 * asked to on the command line/environment; too early to get 550 * info from config file about it. 551 */ 552 screenmasked = false; 553 if(Scr->ShowWelcomeWindow && (welcomefile = getenv("CTWM_WELCOME_FILE"))) { 554 screenmasked = true; 555 MaskScreen(welcomefile); 556 } 557 558 559 /* 560 * Load up config file 561 */ 562 if(CLarg.cfgchk) { 563 if(LoadTwmrc(CLarg.InitFile) == false) { 564 /* Error return */ 565 fprintf(stderr, "Errors found\n"); 566 exit(1); 567 } 568 else { 569 fprintf(stderr, "No errors found\n"); 570 exit(0); 571 } 572 } 573 else { 574 LoadTwmrc(CLarg.InitFile); 575 } 576 577 578 /* 579 * Setup stuff relating to VirtualScreens. If something to do 580 * with it is set in the config, this all implements stuff needed 581 * for that. If not, InitVirtualScreens() creates a single one 582 * mirroring our real root. 583 */ 584 InitVirtualScreens(Scr); 585#ifdef EWMH 586 EwmhInitVirtualRoots(Scr); 587#endif /* EWMH */ 588 589 // Setup WSM[s] (per-vscreen) 590 ConfigureWorkSpaceManager(); 591 592 // If the config wants us to show the splash screen and we 593 // haven't already, do it now. 594 if(Scr->ShowWelcomeWindow && !screenmasked) { 595 MaskScreen(NULL); 596 } 597 598 599 600 /* 601 * Do various setup based on the results from the config file. 602 */ 603 if(Scr->ClickToFocus) { 604 Scr->FocusRoot = false; 605 Scr->TitleFocus = false; 606 } 607 608 if(Scr->use3Dborders) { 609 Scr->ClientBorderWidth = false; 610 } 611 612 613 /* 614 * Various decoration default overrides for 3d/2d. Values that 615 * [presumtively] look "nice" on 75/100dpi displays. -100 is a 616 * sentinel value we set before the config file parsing; since 617 * these defaults differ for 3d vs not, we can't just set them as 618 * default before the parse. 619 */ 620#define SETDEF(fld, num) if(Scr->fld == -100) { Scr->fld = num; } 621 if(Scr->use3Dtitles) { 622 SETDEF(FramePadding, 0); 623 SETDEF(TitlePadding, 0); 624 SETDEF(ButtonIndent, 0); 625 SETDEF(TBInfo.border, 0); 626 } 627 else { 628 SETDEF(FramePadding, 2); 629 SETDEF(TitlePadding, 8); 630 SETDEF(ButtonIndent, 1); 631 SETDEF(TBInfo.border, 1); 632 } 633#undef SETDEF 634 635 // These values are meaningless in !3d cases, so always zero them 636 // out. 637 if(! Scr->use3Dtitles) { 638 Scr->TitleShadowDepth = 0; 639 Scr->TitleButtonShadowDepth = 0; 640 } 641 if(! Scr->use3Dborders) { 642 Scr->BorderShadowDepth = 0; 643 } 644 if(! Scr->use3Dmenus) { 645 Scr->MenuShadowDepth = 0; 646 } 647 if(! Scr->use3Diconmanagers) { 648 Scr->IconManagerShadowDepth = 0; 649 } 650 if(! Scr->use3Dborders) { 651 Scr->ThreeDBorderWidth = 0; 652 } 653 654 // Setup colors stuff 655 if(!Scr->BeNiceToColormap) { 656 // Default pair 657 GetShadeColors(&Scr->DefaultC); 658 659 // Various conditionally 3d bits 660 if(Scr->use3Dtitles) { 661 GetShadeColors(&Scr->TitleC); 662 } 663 if(Scr->use3Dmenus) { 664 GetShadeColors(&Scr->MenuC); 665 } 666 if(Scr->use3Dmenus) { 667 GetShadeColors(&Scr->MenuTitleC); 668 } 669 if(Scr->use3Dborders) { 670 GetShadeColors(&Scr->BorderColorC); 671 } 672 } 673 674 // Defaults for IconRegion bits that aren't set. 675 for(IconRegion *ir = Scr->FirstRegion; ir; ir = ir->next) { 676 if(ir->TitleJustification == TJ_UNDEF) { 677 ir->TitleJustification = Scr->IconJustification; 678 } 679 if(ir->Justification == IRJ_UNDEF) { 680 ir->Justification = Scr->IconRegionJustification; 681 } 682 if(ir->Alignement == IRA_UNDEF) { 683 ir->Alignement = Scr->IconRegionAlignement; 684 } 685 } 686 687 // Put the results of SaveColor{} into _MIT_PRIORITY_COLORS. 688 assign_var_savecolor(); 689 690 // Setup cursor values that weren't give in the config 691#define DEFCURSOR(name, val) if(!Scr->name) NewFontCursor(&Scr->name, val) 692 DEFCURSOR(FrameCursor, "top_left_arrow"); 693 DEFCURSOR(TitleCursor, "top_left_arrow"); 694 DEFCURSOR(IconCursor, "top_left_arrow"); 695 DEFCURSOR(IconMgrCursor, "top_left_arrow"); 696 DEFCURSOR(MoveCursor, "fleur"); 697 DEFCURSOR(ResizeCursor, "fleur"); 698 DEFCURSOR(MenuCursor, "sb_left_arrow"); 699 DEFCURSOR(ButtonCursor, "hand2"); 700 DEFCURSOR(WaitCursor, "watch"); 701 DEFCURSOR(SelectCursor, "dot"); 702 DEFCURSOR(DestroyCursor, "pirate"); 703 DEFCURSOR(AlterCursor, "question_arrow"); 704#undef DEFCURSOR 705 706 // Load up fonts for the screen. 707 // 708 // XXX HaveFonts is kinda stupid, however it gets useful in one 709 // place: when loading button bindings, we make some sort of 710 // "menu" for things (x-ref GotButton()), and the menu gen code 711 // needs to load font stuff, so if that happened in the config 712 // process, we would have already run CreateFonts(). Of course, 713 // that's a order-dependent bit of the config file parsing too; 714 // if you define the fonts too late, they wouldn't have been set 715 // by then, and we won't [re]try them now... arg. 716 if(!Scr->HaveFonts) { 717 CreateFonts(Scr); 718 } 719 720 // Adjust settings for titlebar. Must follow CreateFonts() call 721 // so we know these bits are populated 722 Scr->TitleBarFont.y += Scr->FramePadding; 723 Scr->TitleHeight = Scr->TitleBarFont.height + Scr->FramePadding * 2; 724 if(Scr->use3Dtitles) { 725 Scr->TitleHeight += 2 * Scr->TitleShadowDepth; 726 } 727 /* make title height be odd so buttons look nice and centered */ 728 if(!(Scr->TitleHeight & 1)) { 729 Scr->TitleHeight++; 730 } 731 732 // Setup GC's for drawing, so we can start making stuff we have 733 // to actually draw. Could move earlier, has to preceed a lot of 734 // following. 735 CreateGCs(); 736 737 // Create and draw the menus we config'd 738 MakeMenus(); 739 740 // Load up the images for titlebar buttons 741 InitTitlebarButtons(); 742 743 // Allocate controls for WindowRegion's. Has to follow 744 // workspaces setup, but doesn't talk to X. 745 CreateWindowRegions(); 746 747 // Copy the icon managers over to workspaces past the first as 748 // necessary. AllocateIconManager() and the config parsing 749 // already made them on the first WS. 750 AllocateOtherIconManagers(); 751 752 // Create the windows for our icon managers now that all our 753 // tracking for it is setup. 754 CreateIconManagers(); 755 756 // Create the WSM window (per-vscreen) and stash info on the root 757 // about our WS's. 758 CreateWorkSpaceManager(); 759 760 // Create the f.occupy window 761 CreateOccupyWindow(); 762 763 // Setup TwmWorkspaces menu. Needs workspaces setup, as well as 764 // menus made. 765 MakeWorkspacesMenu(); 766 767 // setup WindowBox's 768 createWindowBoxes(); 769 770 // Initialize Xrm stuff; things with setting occupation etc use 771 // Xrm bits. 772 XrmInitialize(); 773 774#ifdef EWMH 775 // Set EWMH-related properties on various root-ish windows, for 776 // other programs to read to find out how we view the world. 777 EwmhInitScreenLate(Scr); 778#endif /* EWMH */ 779 780 781 /* 782 * Look up and handle all the windows on the screen. 783 */ 784 { 785 Window parent, *children; 786 unsigned int nchildren; 787 788 XQueryTree(dpy, Scr->Root, &croot, &parent, &children, &nchildren); 789 790 /* Weed out icon windows */ 791 for(int i = 0; i < nchildren; i++) { 792 if(children[i]) { 793 XWMHints *wmhintsp = XGetWMHints(dpy, children[i]); 794 795 if(wmhintsp) { 796 if(wmhintsp->flags & IconWindowHint) { 797 for(int j = 0; j < nchildren; j++) { 798 if(children[j] == wmhintsp->icon_window) { 799 children[j] = None; 800 break; 801 } 802 } 803 } 804 XFree(wmhintsp); 805 } 806 } 807 } 808 809 /* 810 * Map all of the non-override windows. This winds down 811 * into AddWindow() and friends through SimulateMapRequest(), 812 * so this is where we actually adopt the windows on the 813 * screen. 814 */ 815 for(int i = 0; i < nchildren; i++) { 816 if(children[i] && MappedNotOverride(children[i])) { 817 XUnmapWindow(dpy, children[i]); 818 SimulateMapRequest(children[i]); 819 } 820 } 821 822 /* 823 * At this point, we've adopted all the windows currently on 824 * the screen (aside from those we're intentionally not). 825 * Note that this happens _before_ the various other windows 826 * we create below, which is why they don't wind up getting 827 * TwmWindow's tied to them or show up in icon managers, etc. 828 * We'd need to actually make it _explicit_ that those 829 * windows aren't tracked by us if we changed that order... 830 */ 831 } 832 833 834 // Show the WSM window if we should 835 if(Scr->ShowWorkspaceManager && Scr->workSpaceManagerActive) { 836 VirtualScreen *vs; 837 if(Scr->WindowMask) { 838 XRaiseWindow(dpy, Scr->WindowMask); 839 } 840 for(vs = Scr->vScreenList; vs != NULL; vs = vs->next) { 841 SetMapStateProp(vs->wsw->twm_win, NormalState); 842 XMapWindow(dpy, vs->wsw->twm_win->frame); 843 if(vs->wsw->twm_win->StartSqueezed) { 844 Squeeze(vs->wsw->twm_win); 845 } 846 else { 847 XMapWindow(dpy, vs->wsw->w); 848 } 849 vs->wsw->twm_win->mapped = true; 850 } 851 } 852 853 854 /* 855 * Setup the Info window, used for f.identify and f.version. 856 */ 857 { 858 unsigned long valuemask; 859 XSetWindowAttributes attributes; 860 861 attributes.border_pixel = Scr->DefaultC.fore; 862 attributes.background_pixel = Scr->DefaultC.back; 863 attributes.event_mask = (ExposureMask | ButtonPressMask | 864 KeyPressMask | ButtonReleaseMask); 865 NewFontCursor(&attributes.cursor, "hand2"); 866 valuemask = (CWBorderPixel | CWBackPixel | CWEventMask | CWCursor); 867 Scr->InfoWindow.win = 868 XCreateWindow(dpy, Scr->Root, 0, 0, 869 5, 5, 870 0, 0, 871 CopyFromParent, CopyFromParent, 872 valuemask, &attributes); 873 } 874 875 876 /* 877 * Setup the Size/Position window for showing during resize/move 878 * operations. 879 */ 880 { 881 int sx, sy; 882 XRectangle ink_rect; 883 XRectangle logical_rect; 884 unsigned long valuemask; 885 XSetWindowAttributes attributes; 886 887 XmbTextExtents(Scr->SizeFont.font_set, 888 " 8888 x 8888 ", 13, 889 &ink_rect, &logical_rect); 890 Scr->SizeStringWidth = logical_rect.width; 891 valuemask = (CWBorderPixel | CWBackPixel | CWBitGravity); 892 attributes.bit_gravity = NorthWestGravity; 893 894 if(Scr->CenterFeedbackWindow) { 895 sx = (Scr->rootw / 2) - (Scr->SizeStringWidth / 2); 896 sy = (Scr->rooth / 2) - ((Scr->SizeFont.height + SIZE_VINDENT * 2) / 2); 897 if(Scr->SaveUnder) { 898 attributes.save_under = True; 899 valuemask |= CWSaveUnder; 900 } 901 } 902 else { 903 sx = 0; 904 sy = 0; 905 } 906 Scr->SizeWindow = XCreateWindow(dpy, Scr->Root, sx, sy, 907 Scr->SizeStringWidth, 908 (Scr->SizeFont.height + 909 SIZE_VINDENT * 2), 910 0, 0, 911 CopyFromParent, 912 CopyFromParent, 913 valuemask, &attributes); 914 } 915 916 // Create util window used in animation 917 Scr->ShapeWindow = XCreateSimpleWindow(dpy, Scr->Root, 0, 0, 918 Scr->rootw, Scr->rooth, 0, 0, 0); 919 920 921 // Clear out the splash screen if we had one 922 if(Scr->ShowWelcomeWindow) { 923 UnmaskScreen(); 924 } 925 926 // Done setting up this Screen. x-ref XXX's about whether this 927 // element is worth anything... 928 Scr->FirstTime = false; 929 } // for each screen on display 930 931 932 // We're not much of a window manager if we didn't get stuff to 933 // manage... 934 if(numManaged == 0) { 935 if(CLarg.MultiScreen && NumScreens > 0) 936 fprintf(stderr, "%s: unable to find any unmanaged screens\n", 937 ProgramName); 938 exit(1); 939 } 940 941 // Hook up session 942 ConnectToSessionManager(CLarg.client_id); 943 944#ifdef SOUNDS 945 // Announce ourselves 946 sound_load_list(); 947 play_startup_sound(); 948#endif 949 950 // Hard-reset this flag. 951 // XXX This doesn't seem right? 952 RestartPreviousState = true; 953 954 // Do some late initialization 955 HandlingEvents = true; 956 StartAnimation(); 957 958 // Main loop. 959 HandleEvents(); 960 961 // Should never get here... 962 fprintf(stderr, "Shouldn't return from HandleEvents()!\n"); 963 exit(1); 964} 965 966 967/** 968 * Initialize ScreenInfo for a Screen. This allocates the struct, 969 * assigns in the info we pass it about the screen and dimensions, and 970 * then puts in our various default/fallback/sentinel/etc values to 971 * prepare it for later use. 972 * 973 * It is intentional that this doesn't do any of the initialization that 974 * involves calling out to X functions; it operates as a pure function. 975 * This makes it easier to use it to fake up a ScreenInfo for something 976 * that isn't actually an X Screen, for testing etc. 977 * 978 * \param scrnum The Screen number (e.g, :0.0 -> 0) 979 * \param croot The X Window for the Screen's root window 980 * \param crootx Root X coordinate 981 * \param crooty Root Y coordinate 982 * \param crootw Root width 983 * \param crooth Root height 984 * \return Allocated and populated ScreenInfo 985 */ 986ScreenInfo * 987InitScreenInfo(int scrnum, Window croot, int crootx, int crooty, 988 unsigned int crootw, unsigned int crooth) 989{ 990 ScreenInfo *scr; 991 scr = calloc(1, sizeof(ScreenInfo)); 992 if(scr == NULL) { 993 return NULL; 994 } 995 // Because of calloc(), it's already all 0 bytes, which are NULL and 996 // false and 0 and similar. Some following initializations are 997 // nugatory because of that, but are left for clarity. 998 999 // Poison the global Scr to protect against typos 1000#define Scr StupidProgrammer 1001 1002 1003 // Basic pieces about the X screen we're talking about, and some 1004 // derived dimension-related bits. 1005 scr->screen = scrnum; 1006 scr->XineramaRoot = scr->Root = croot; 1007 scr->rootx = scr->crootx = crootx; 1008 scr->rooty = scr->crooty = crooty; 1009 scr->rootw = scr->crootw = crootw; 1010 scr->rooth = scr->crooth = crooth; 1011 1012 // Don't allow icon titles wider than the screen 1013 scr->MaxIconTitleWidth = scr->rootw; 1014 1015 // Attempt to come up with a sane default for the max sizes. Start 1016 // by limiting so that a window with its left/top on the right/bottom 1017 // edge of the screen can't extend further than X can address (signed 1018 // 16-bit). However, when your screen size starts approaching that 1019 // limit, reducing the max window sizes too much gets stupid too, so 1020 // set an arbitrary floor on how low this will take it. 1021 // MaxWindowSize in the config will override whatever's here anyway. 1022 scr->MaxWindowWidth = 32767 - (scr->rootx + scr->rootw); 1023 scr->MaxWindowHeight = 32767 - (scr->rooty + scr->rooth); 1024 if(scr->MaxWindowWidth < 4096) { 1025 scr->MaxWindowWidth = 4096; 1026 } 1027 if(scr->MaxWindowHeight < 4096) { 1028 scr->MaxWindowHeight = 4096; 1029 } 1030 1031 1032 // Flags used in the code to keep track of where in various processes 1033 // (especially startup) we are. 1034 scr->HaveFonts = false; 1035 1036 // Flag which basically means "initial screen setup time". 1037 // XXX Not clear to what extent this should even exist; a lot of 1038 // uses are fairly bogus. 1039 scr->FirstTime = true; 1040 1041 // We're a WM, we're usually trying to take over (x-ref later code in 1042 // caller) 1043 scr->takeover = true; 1044 1045 // Sentinel values for defaulting config values 1046 scr->FramePadding = -100; 1047 scr->TitlePadding = -100; 1048 scr->ButtonIndent = -100; 1049 scr->TBInfo.border = -100; 1050 1051 // Default values for all sorts of config params 1052 scr->SizeStringOffset = 0; 1053 scr->ThreeDBorderWidth = 6; 1054 scr->BorderWidth = BW; 1055 scr->IconBorderWidth = BW; 1056 scr->NumAutoRaises = 0; 1057 scr->NumAutoLowers = 0; 1058 scr->TransientOnTop = 30; 1059 scr->NoDefaults = false; 1060 scr->UsePPosition = PPOS_OFF; 1061 scr->UseSunkTitlePixmap = false; 1062 scr->FocusRoot = true; 1063 scr->WarpCursor = false; 1064 scr->ForceIcon = false; 1065 scr->NoGrabServer = true; 1066 scr->NoRaiseMove = false; 1067 scr->NoRaiseResize = false; 1068 scr->NoRaiseDeicon = false; 1069 scr->RaiseOnWarp = true; 1070 scr->DontMoveOff = false; 1071 scr->DoZoom = false; 1072 scr->TitleFocus = true; 1073 scr->IconManagerFocus = true; 1074 scr->StayUpMenus = false; 1075 scr->WarpToDefaultMenuEntry = false; 1076 scr->ClickToFocus = false; 1077 scr->SloppyFocus = false; 1078 scr->SaveWorkspaceFocus = false; 1079 scr->NoIconTitlebar = false; 1080 scr->NoTitlebar = false; 1081 scr->DecorateTransients = true; 1082 scr->IconifyByUnmapping = false; 1083 scr->ShowIconManager = false; 1084 scr->ShowWorkspaceManager = false; 1085 scr->WMgrButtonShadowDepth = 2; 1086 scr->WMgrVertButtonIndent = 5; 1087 scr->WMgrHorizButtonIndent = 5; 1088 scr->BorderShadowDepth = 2; 1089 scr->TitleShadowDepth = 2; 1090 scr->TitleButtonShadowDepth = 2; 1091 scr->MenuShadowDepth = 2; 1092 scr->IconManagerShadowDepth = 2; 1093 scr->AutoOccupy = false; 1094 scr->TransientHasOccupation = false; 1095 scr->DontPaintRootWindow = false; 1096 scr->IconManagerDontShow = false; 1097 scr->BackingStore = false; 1098 scr->SaveUnder = true; 1099 scr->RandomPlacement = RP_ALL; 1100 scr->RandomDisplacementX = 30; 1101 scr->RandomDisplacementY = 30; 1102 scr->DoOpaqueMove = true; 1103 scr->OpaqueMove = false; 1104 scr->OpaqueMoveThreshold = 200; 1105 scr->OpaqueResize = false; 1106 scr->DoOpaqueResize = true; 1107 scr->OpaqueResizeThreshold = 1000; 1108 scr->Highlight = true; 1109 scr->StackMode = true; 1110 scr->TitleHighlight = true; 1111 scr->MoveDelta = 1; 1112 scr->MoveOffResistance = -1; 1113 scr->MovePackResistance = 20; 1114 scr->ZoomCount = 8; 1115 scr->SortIconMgr = true; 1116 scr->Shadow = true; 1117 scr->InterpolateMenuColors = false; 1118 scr->NoIconManagers = false; 1119 scr->ClientBorderWidth = false; 1120 scr->SqueezeTitle = false; 1121 scr->FirstTime = true; 1122 scr->CaseSensitive = true; 1123 scr->WarpUnmapped = false; 1124 scr->WindowRingAll = false; 1125 scr->WarpRingAnyWhere = true; 1126 scr->ShortAllWindowsMenus = false; 1127 scr->use3Diconmanagers = false; 1128 scr->use3Dmenus = false; 1129 scr->use3Dtitles = false; 1130 scr->use3Dborders = false; 1131 scr->use3Dwmap = false; 1132 scr->SunkFocusWindowTitle = false; 1133 scr->ClearShadowContrast = 50; 1134 scr->DarkShadowContrast = 40; 1135 scr->BeNiceToColormap = false; 1136 scr->BorderCursors = false; 1137 scr->IconJustification = TJ_CENTER; 1138 scr->IconRegionJustification = IRJ_CENTER; 1139 scr->IconRegionAlignement = IRA_CENTER; 1140 scr->TitleJustification = TJ_LEFT; 1141 scr->IconifyStyle = ICONIFY_NORMAL; 1142 scr->ReallyMoveInWorkspaceManager = false; 1143 scr->ShowWinWhenMovingInWmgr = false; 1144 scr->ReverseCurrentWorkspace = false; 1145 scr->DontWarpCursorInWMap = false; 1146 scr->XMoveGrid = 1; 1147 scr->YMoveGrid = 1; 1148 scr->CenterFeedbackWindow = false; 1149 scr->ShrinkIconTitles = false; 1150 scr->AutoRaiseIcons = false; 1151 scr->AutoFocusToTransients = false; 1152 scr->OpenWindowTimeout = 0; 1153 scr->RaiseWhenAutoUnSqueeze = false; 1154 scr->RaiseOnClick = false; 1155 scr->RaiseOnClickButton = 1; 1156 scr->IgnoreModifier = 0; 1157 scr->IgnoreCaseInMenuSelection = false; 1158 scr->PackNewWindows = false; 1159 scr->AlwaysSqueezeToGravity = false; 1160 scr->NoWarpToMenuTitle = false; 1161 scr->DontToggleWorkspaceManagerState = false; 1162 scr->NameDecorations = true; 1163 scr->ForceFocus = false; 1164 scr->BorderTop = 0; 1165 scr->BorderBottom = 0; 1166 scr->BorderLeft = 0; 1167 scr->BorderRight = 0; 1168 scr->PixmapDirectory = PIXMAP_DIRECTORY; 1169#ifdef EWMH 1170 scr->PreferredIconWidth = 48; 1171 scr->PreferredIconHeight = 48; 1172#endif 1173 1174 1175 // WorkSpaceManager stuff 1176 scr->workSpaceMgr.initialstate = WMS_map; 1177 scr->workSpaceMgr.buttonStyle = STYLE_NORMAL; 1178 scr->workSpaceMgr.vspace = scr->WMgrVertButtonIndent; 1179 scr->workSpaceMgr.hspace = scr->WMgrHorizButtonIndent; 1180 1181 scr->workSpaceMgr.occupyWindow = calloc(1, sizeof(OccupyWindow)); 1182 scr->workSpaceMgr.occupyWindow->vspace = scr->WMgrVertButtonIndent; 1183 scr->workSpaceMgr.occupyWindow->hspace = scr->WMgrHorizButtonIndent; 1184 scr->workSpaceMgr.occupyWindow->name = "Occupy Window"; 1185 scr->workSpaceMgr.occupyWindow->icon_name = "Occupy Window Icon"; 1186 1187 scr->workSpaceMgr.name = "WorkSpaceManager"; 1188 scr->workSpaceMgr.icon_name = "WorkSpaceManager Icon"; 1189 1190 1191 // Setup default fonts in case the config file doesn't 1192#define DEFAULT_NICE_FONT "-*-helvetica-bold-r-normal-*-*-120-*" 1193#define DEFAULT_FAST_FONT "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-*" 1194#define SETFONT(fld, var) (scr->fld##Font.basename = DEFAULT_##var##_FONT) 1195 1196 SETFONT(TitleBar, NICE); 1197 SETFONT(Menu, NICE); 1198 SETFONT(Icon, NICE); 1199 SETFONT(Size, FAST); 1200 SETFONT(IconManager, NICE); 1201 SETFONT(Default, FAST); 1202 scr->workSpaceMgr.windowFont.basename = 1203 "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1"; 1204 1205#undef SETFONT 1206#undef DEFAULT_FAST_FONT 1207#undef DEFAULT_NICE_FONT 1208 1209 // Cleanup poisoning 1210#undef Scr 1211 return scr; 1212} 1213 1214 1215void CreateFonts(ScreenInfo *scr) 1216{ 1217#define LOADFONT(fld) (GetFont(&scr->fld##Font)) 1218 LOADFONT(TitleBar); 1219 LOADFONT(Menu); 1220 LOADFONT(Icon); 1221 LOADFONT(Size); 1222 LOADFONT(IconManager); 1223 LOADFONT(Default); 1224 LOADFONT(workSpaceMgr.window); 1225#undef LOADFONT 1226 1227 scr->HaveFonts = true; 1228} 1229 1230 1231void RestoreWithdrawnLocation(TwmWindow *tmp) 1232{ 1233 int gravx, gravy; 1234 unsigned int bw, mask; 1235 XWindowChanges xwc; 1236 1237 if(tmp->UnmapByMovingFarAway && !visible(tmp)) { 1238 XMoveWindow(dpy, tmp->frame, tmp->frame_x, tmp->frame_y); 1239 } 1240 if(tmp->squeezed) { 1241 Squeeze(tmp); 1242 } 1243 if(XGetGeometry(dpy, tmp->w, &JunkRoot, &xwc.x, &xwc.y, 1244 &JunkWidth, &JunkHeight, &bw, &JunkDepth)) { 1245 1246 GetGravityOffsets(tmp, &gravx, &gravy); 1247 if(gravy < 0) { 1248 xwc.y -= tmp->title_height; 1249 } 1250 xwc.x += gravx * tmp->frame_bw3D; 1251 xwc.y += gravy * tmp->frame_bw3D; 1252 1253 if(bw != tmp->old_bw) { 1254 int xoff, yoff; 1255 1256 if(!Scr->ClientBorderWidth) { 1257 xoff = gravx; 1258 yoff = gravy; 1259 } 1260 else { 1261 xoff = 0; 1262 yoff = 0; 1263 } 1264 1265 xwc.x -= (xoff + 1) * tmp->old_bw; 1266 xwc.y -= (yoff + 1) * tmp->old_bw; 1267 } 1268 if(!Scr->ClientBorderWidth) { 1269 xwc.x += gravx * tmp->frame_bw; 1270 xwc.y += gravy * tmp->frame_bw; 1271 } 1272 1273 mask = (CWX | CWY); 1274 if(bw != tmp->old_bw) { 1275 xwc.border_width = tmp->old_bw; 1276 mask |= CWBorderWidth; 1277 } 1278 1279#if 0 1280 if(tmp->vs) { 1281 xwc.x += tmp->vs->x; 1282 xwc.y += tmp->vs->y; 1283 } 1284#endif 1285 1286 if(tmp->winbox && tmp->winbox->twmwin && tmp->frame) { 1287 int xbox, ybox; 1288 if(XGetGeometry(dpy, tmp->frame, &JunkRoot, &xbox, &ybox, 1289 &JunkWidth, &JunkHeight, &bw, &JunkDepth)) { 1290 ReparentWindow(dpy, tmp, WinWin, Scr->Root, xbox, ybox); 1291 } 1292 } 1293 XConfigureWindow(dpy, tmp->w, mask, &xwc); 1294 1295 if(tmp->wmhints->flags & IconWindowHint) { 1296 XUnmapWindow(dpy, tmp->wmhints->icon_window); 1297 } 1298 1299 } 1300} 1301 1302 1303/*********************************************************************** 1304 * 1305 * Procedure: 1306 * Done - cleanup and exit twm 1307 * 1308 * Returned Value: 1309 * none 1310 * 1311 * Inputs: 1312 * none 1313 * 1314 * Outputs: 1315 * none 1316 * 1317 * Special Considerations: 1318 * none 1319 * 1320 *********************************************************************** 1321 */ 1322 1323void Reborder(Time mytime) 1324{ 1325 TwmWindow *tmp; /* temp twm window structure */ 1326 int scrnum; 1327 ScreenInfo *savedScreen; /* Its better to avoid coredumps */ 1328 1329 /* put a border back around all windows */ 1330 1331 XGrabServer(dpy); 1332 savedScreen = Scr; 1333 for(scrnum = 0; scrnum < NumScreens; scrnum++) { 1334 if((Scr = ScreenList[scrnum]) == NULL) { 1335 continue; 1336 } 1337 1338 InstallColormaps(0, &Scr->RootColormaps); /* force reinstall */ 1339 for(tmp = Scr->FirstWindow; tmp != NULL; tmp = tmp->next) { 1340 RestoreWithdrawnLocation(tmp); 1341 XMapWindow(dpy, tmp->w); 1342 } 1343 } 1344 Scr = savedScreen; 1345 XUngrabServer(dpy); 1346 SetFocus(NULL, mytime); 1347} 1348 1349SIGNAL_T Done(int signum) 1350{ 1351#ifdef SOUNDS 1352 play_exit_sound(); 1353#endif 1354 Reborder(CurrentTime); 1355#ifdef EWMH 1356 EwmhTerminate(); 1357#endif /* EWMH */ 1358 XDeleteProperty(dpy, Scr->Root, XA_WM_WORKSPACESLIST); 1359 if(CLarg.is_captive) { 1360 RemoveFromCaptiveList(Scr->captivename); 1361 } 1362 XCloseDisplay(dpy); 1363 exit(0); 1364} 1365 1366SIGNAL_T Crash(int signum) 1367{ 1368 Reborder(CurrentTime); 1369 XDeleteProperty(dpy, Scr->Root, XA_WM_WORKSPACESLIST); 1370 if(CLarg.is_captive) { 1371 RemoveFromCaptiveList(Scr->captivename); 1372 } 1373 XCloseDisplay(dpy); 1374 1375 fprintf(stderr, "\nCongratulations, you have found a bug in ctwm\n"); 1376 fprintf(stderr, "If a core file was generated in your directory,\n"); 1377 fprintf(stderr, "can you please try extract the stack trace,\n"); 1378 fprintf(stderr, 1379 "and mail the results, and a description of what you were doing,\n"); 1380 fprintf(stderr, "to ctwm@ctwm.org. Thank you for your support.\n"); 1381 fprintf(stderr, "...exiting ctwm now.\n\n"); 1382 1383 abort(); 1384} 1385 1386 1387SIGNAL_T Restart(int signum) 1388{ 1389 fprintf(stderr, "%s: setting restart flag\n", ProgramName); 1390 RestartFlag = true; 1391} 1392 1393void DoRestart(Time t) 1394{ 1395 RestartFlag = false; 1396 1397 StopAnimation(); 1398 XSync(dpy, 0); 1399 Reborder(t); 1400 XSync(dpy, 0); 1401 1402 if(smcConn) { 1403 SmcCloseConnection(smcConn, 0, NULL); 1404 } 1405 1406 fprintf(stderr, "%s: restarting: %s\n", 1407 ProgramName, *Argv); 1408 execvp(*Argv, Argv); 1409 fprintf(stderr, "%s: unable to restart: %s\n", ProgramName, *Argv); 1410} 1411 1412#ifdef __WAIT_FOR_CHILDS 1413/* 1414 * Handler for SIGCHLD. Needed to avoid zombies when an .xinitrc 1415 * execs ctwm as the last client. (All processes forked off from 1416 * within .xinitrc have been inherited by ctwm during the exec.) 1417 * Jens Schweikhardt <jens@kssun3.rus.uni-stuttgart.de> 1418 */ 1419SIGNAL_T 1420ChildExit(int signum) 1421{ 1422 int Errno = errno; 1423 signal(SIGCHLD, ChildExit); /* reestablish because we're a one-shot */ 1424 waitpid(-1, NULL, WNOHANG); /* reap dead child, ignore status */ 1425 errno = Errno; /* restore errno for interrupted sys calls */ 1426} 1427#endif 1428 1429/* 1430 * Error Handlers. If a client dies, we'll get a BadWindow error (except for 1431 * GetGeometry which returns BadDrawable) for most operations that we do before 1432 * manipulating the client's window. 1433 */ 1434 1435static XErrorEvent LastErrorEvent; 1436 1437static int TwmErrorHandler(Display *display, XErrorEvent *event) 1438{ 1439 LastErrorEvent = *event; 1440 1441 if(CLarg.PrintErrorMessages && /* don't be too obnoxious */ 1442 event->error_code != BadWindow && /* watch for dead puppies */ 1443 (event->request_code != X_GetGeometry && /* of all styles */ 1444 event->error_code != BadDrawable)) { 1445 XmuPrintDefaultErrorMessage(display, event, stderr); 1446 } 1447 return 0; 1448} 1449 1450 1451/* ARGSUSED*/ 1452static int CatchRedirectError(Display *display, XErrorEvent *event) 1453{ 1454 RedirectError = true; 1455 LastErrorEvent = *event; 1456 return 0; 1457} 1458 1459/* 1460 * XA_MIT_PRIORITY_COLORS Create priority colors if necessary. 1461 * XA_WM_END_OF_ANIMATION Used to throttle animation. 1462 */ 1463 1464Atom XCTWMAtom[NUM_CTWM_XATOMS]; 1465 1466void InternUsefulAtoms(void) 1467{ 1468 XInternAtoms(dpy, XCTWMAtomNames, NUM_CTWM_XATOMS, False, XCTWMAtom); 1469} 1470 1471static Window 1472CreateCaptiveRootWindow(int x, int y, 1473 unsigned int width, unsigned int height) 1474{ 1475 int scrnum; 1476 Window ret; 1477 XWMHints wmhints; 1478 1479 scrnum = DefaultScreen(dpy); 1480 ret = XCreateSimpleWindow(dpy, RootWindow(dpy, scrnum), 1481 x, y, width, height, 2, WhitePixel(dpy, scrnum), 1482 BlackPixel(dpy, scrnum)); 1483 wmhints.initial_state = NormalState; 1484 wmhints.input = True; 1485 wmhints.flags = InputHint | StateHint; 1486 1487 XmbSetWMProperties(dpy, ret, "Captive ctwm", NULL, NULL, 0, NULL, 1488 &wmhints, NULL); 1489 XChangeProperty(dpy, ret, XA_WM_CTWM_ROOT, XA_WINDOW, 32, 1490 PropModeReplace, (unsigned char *) &ret, 1); 1491 XSelectInput(dpy, ret, StructureNotifyMask); 1492 XMapWindow(dpy, ret); 1493 return (ret); 1494} 1495 1496 1497/* 1498 * Return true if a window is not set to override_redirect ("Hey! WM! 1499 * Leave those wins alone!"), and isn't unmapped. Used during startup to 1500 * fake mapping for wins that should be up. 1501 */ 1502static bool 1503MappedNotOverride(Window w) 1504{ 1505 XWindowAttributes wa; 1506 1507 XGetWindowAttributes(dpy, w, &wa); 1508 return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True)); 1509} 1510