home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gwm18a.zip / gwm.c < prev    next >
C/C++ Source or Header  |  1996-05-23  |  27KB  |  1,003 lines

  1. /* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
  2.  * Copyright 1989 Massachusetts Institute of Technology
  3.  */
  4. /******************************\
  5. *                    *
  6. * BULL WINDOW MANAGER for X11  *
  7. *                    *
  8. *     main body           *
  9. *                    *
  10. \******************************/
  11.  
  12. /* include */
  13. #include    <stdio.h>
  14. #include    "EXTERN.h"
  15. #include    "wool.h"
  16. #include    "wl_atom.h"
  17. #include    "wl_string.h"
  18. #include    "wl_list.h"
  19. #include    "wl_client.h"
  20. #include     "wl_func.h"
  21. #include    "yacc.h"
  22. #include "wl_number.h"
  23. #include <X11/Xlib.h>
  24. #include "wl_pixmap.h"
  25. #include    "INTERN.h"
  26. #include     "gwm.h"
  27. #include     <signal.h> 
  28. #include     <ctype.h> 
  29. #include <sys/time.h>
  30. #ifdef NEED_SELECT_H
  31. #include <sys/select.h>
  32. #endif
  33.  
  34. /* external */
  35.  
  36. #ifdef NOXEHTYPE
  37. typedef int (*XErrorHandler) ();
  38. extern XErrorHandler XSetErrorHandler ();
  39. #endif
  40.  
  41. #ifdef NO_GWM_LOG
  42. #define GWM_log()
  43. #endif
  44. #ifndef GWM_LOG_ID
  45. #define GWM_LOG_ID 0
  46. #endif
  47.  
  48. /* a comment string to tell "what" is this binary (precompiled? etc...) 
  49.  * e.g, in makefile: C_COMPILER= cc -DGWM_LOG_NAME='\"-D-alpha\"'
  50.  */
  51. #ifndef GWM_LOG_NAME
  52. #define GWM_LOG_NAME ""
  53. #endif
  54.  
  55. extern int XError();
  56. extern int      InitWool();
  57. extern Wob      LookUpWob();
  58. extern          InitScreens();
  59. extern Wob      NewClientWindow();
  60. extern void     ScreenClose();
  61. extern void    DecorateWindows();
  62. extern char    *wool_fix_path();
  63. extern         NoXError();
  64. extern GWMScreenContext RegisterScreen();
  65. extern void GWM_BusErrorSignalHandler();
  66. extern ClientWindow LookUpClient();
  67. DECLARE_strchr;
  68.  
  69. /* local */
  70.  
  71. static char     err[] = "\007GWM:";
  72. static int GWM_Decorate_one_window=0;
  73. static int GWM_Decorate_all_windows=0;
  74. static int GWM_is_initialized = 0;
  75. static int GWM_RetryStart = 0;
  76.  
  77. /* routines */
  78.  
  79. int         GWM_Initialize();
  80.  
  81.  
  82. int gwm_stdin = 0, gwm_prompt = 0;
  83.  
  84.  
  85. /*
  86.  * Main body of GWM:
  87.  *     - parse arguments
  88.  *     - initialize X
  89.  *     - initialize Wool
  90.  *     - read user profile
  91.  *     - decorate all already present windows
  92.  *     - enter main loop: GWM_ProcessEvents
  93.  */
  94.  
  95. int
  96. main(argc, argv)
  97. int             argc;
  98. char           *argv[];
  99. {
  100. //    malloc_init();            /* FIRST THING TO DO!!! */
  101. #ifdef MONITOR
  102.     moncontrol(0);            /* do not trace profile read */
  103. #endif /* MONITOR */
  104.     GWM_argc = argc;
  105.     GWM_argv = argv;
  106.     GWM_getopts(argc, argv);        /* options & open display */
  107.     if (gwm_stdin && gwm_prompt) {
  108.     printf("> ");
  109.     fflush(stdout);
  110.     }
  111.     RegisterScreens();
  112.  
  113.     if (wool_error_occurred(GWM_Initialize))    /* Init wool and display */
  114.     GWM_Abort("cannot initialize");
  115.  
  116.     if (wool_error_in_profile && !wool_continue_reading_on_error)
  117.     GWM_Abort("error while reading profile");
  118.  
  119.     if (wool_error_occurred(InitScreens))    /* screen and syswd */
  120.     GWM_Abort("cannot set up");
  121.  
  122.     if (wool_error_occurred(DecorateWindows) &&
  123.     !wool_continue_reading_on_error)/* existing windows */
  124.     GWM_Abort("cannot decorate windows");
  125.  
  126.     FOR_ALL_SCREENS {            /* call opening on all screens */
  127.     SetTarget(Context -> rootWob);
  128.     WOOL_send(WOOL_eval, Context -> rootWob -> opening,
  129.           (Context -> rootWob -> opening));
  130.     decrease_reference(Context -> rootWob -> opening);
  131.     Context -> rootWob -> opening = NULL;
  132.     } END_OF_ALL_SCREENS;
  133.  
  134.     /* send signal if a process is waiting for gwm to come up */
  135.     if (GWM_kill_pid) {
  136.     kill(GWM_kill_pid, GWM_kill_pid_sig);
  137.     }
  138.  
  139.     GWM_is_initialized = 1;
  140.     GWM_log();
  141.     if (set_wool_error_resume_point()) { /* wool_error will jump here */
  142.     if (GWM_is_restarting || GWM_is_ending)
  143.         GWM_BusErrorSignalHandler(0); /* skip wool when error in ending */
  144.     zrt_gc(0);
  145.     if (GWM_window_being_decorated) {
  146.         Window w = GWM_window_being_decorated -> client;
  147.         ClientWindowClose(GWM_window_being_decorated);
  148.         GWM_window_being_decorated = 0;
  149.         XMapWindow(dpy, w);
  150.     }
  151.     }
  152.  
  153. #ifdef MONITOR
  154.     moncontrol(1);            /* only trace main loop */
  155. #endif /* MONITOR */
  156.     GWM_ProcessEvents(1);        /* MAIN LOOP (never returns!) */
  157.     return 0;
  158. }
  159.  
  160. /* fatal init error handler */
  161.  
  162. GWM_Abort(message)
  163. char * message;
  164. {
  165.     fprintf(stderr, "%s -- %s, aborting\n", err, message);
  166.     exit(-1);
  167. }
  168.  
  169.  
  170. void read_stdin()
  171. {
  172.     static int bi, len, pn, is;
  173.     static char *b = NULL;
  174.     char buf[1024], c;
  175.     int n, i;
  176.  
  177.     if (!b) {
  178.     b = Malloc(len = 1024);
  179.     pn = is = 0;
  180.     strcpy(b, "(print ");
  181.     bi = 7;
  182.     }
  183.  
  184.     if ((n = read(0, buf, 1024)) > 0) {
  185.     for (i = 0; i < n; i++) {
  186.         c = b[bi++] = buf[i];
  187.         if (c == '(' && !is) pn++;
  188.         else if (c == ')' && !is) pn--;
  189.         else if (c ==  '"') is ^= 1;
  190.         else if (c == '\n' && !pn && !is) {
  191.         b[bi-1] = '\0';
  192.         strcat(b, " \"\\n\")");
  193.         wool_execute_string(b);
  194.         bi = 7;
  195.         }
  196.         if (bi == len - 10)
  197.         b = Realloc(b, len += 1024);
  198.     }
  199.     if (buf[i-1] == '\n' && gwm_prompt) {
  200.         if (pn)
  201.         printf("%d> ", pn);
  202.         else
  203.         printf("> ");
  204.         fflush(stdout);
  205.     }
  206.     }
  207. }
  208.  
  209.  
  210. /* The main loop of GWM:
  211.  *     - wait for an event
  212.  *     - look if it is for the hook (X window) of a wob
  213.  *       (or the client of a window), then dispatch it to the concerned
  214.  *       wob
  215.  *     - if it is a new window being mapped, decorate it
  216.  *     - the server is grabbed, redirect events to grabbing wob
  217.  * 
  218.  * If blocking is 1, the loop never ends, whereas if it is 0, it returns as
  219.  * soons as the queue is empty (via the XPending call)
  220.  */
  221.  
  222. GWM_ProcessEvents(blocking)
  223. int    blocking;
  224. {
  225.     EventData       evt;
  226.     Wob             wob;
  227.     struct timeval to;
  228.     fd_set fds;
  229.     int s = 0;
  230.     int local_zrt_size = zrt_size;
  231.  
  232. #ifdef DEBUG
  233.     wob = 0;            /* entry point for dbx */
  234. #endif /* DEBUG */
  235.  
  236.     if (gwm_stdin) {
  237.     FD_ZERO(&fds);
  238.     FD_SET(0, &fds);
  239.     to.tv_sec = to.tv_usec = 0;
  240.     s = select(1, &fds, NULL, NULL, &to);
  241.     }
  242.     while (blocking || XPending(dpy) || s > 0) {
  243.  
  244.     if (gwm_stdin && !XPending(dpy)) {
  245.         FD_ZERO(&fds);
  246.         FD_SET(0, &fds);
  247.         FD_SET(ConnectionNumber(dpy), &fds);
  248.         to.tv_sec = to.tv_usec = 0;
  249.         s = select(FD_SETSIZE, &fds, NULL, NULL, blocking ? NULL : &to);
  250.  
  251.         if (s > 0 && FD_ISSET(0, &fds))
  252.         read_stdin();
  253.         s = 0;
  254.         goto next_event;
  255.     }
  256.  
  257.     XNextEvent(dpy, &evt);
  258.     TraceDo('e',GWM_prettyprint_event("XEV: ", &evt, "\n"));
  259.  
  260.     if (EventProperties[evt.xany.type] & EPTime) {
  261.         Time newtime = *((Time *)(((char *)(&evt)) +
  262.                       EventTimeFieldOffset[evt.xany.type]));
  263.         if (newtime) {        /* sometimes the X Server goofs up */
  264.         GWMTime = newtime;
  265.         }
  266.     }
  267.  
  268.     if (wob = LookUpWob(evt.xany.window)) {
  269.         if (GWM_ServerGrabbed) {
  270.         if(event_is_grabbable(evt)) {
  271.             if (GWM_GrabChildEvents
  272.             || !IsAnAncestor(GWM_ServerGrabbed, wob))
  273.             wob = GWM_ServerGrabbed;
  274.             WOOL_send(WOOL_process_event, wob, (wob, &evt));
  275.         } else if (event_is_redirectable(evt)) {
  276.             if (wob ==  GWM_ServerGrabbed
  277.             || (!GWM_GrabChildEvents
  278.                 && IsAnAncestor(GWM_ServerGrabbed, wob))
  279.             || IsNotGrabDiscarded(&evt)) {
  280.             WOOL_send(WOOL_process_event, wob, (wob, &evt));
  281.             }
  282.         } else {
  283.             WOOL_send(WOOL_process_event, wob, (wob, &evt));
  284.         }
  285.         } else {
  286.         WOOL_send(WOOL_process_event, wob, (wob, &evt));
  287.         }
  288.     } else if (wob = (Wob) LookUpClient(evt.xany.window)) {
  289.          WOOL_send(WOOL_process_event, wob, (wob, &evt));
  290.     } else if (evt.xany.type == MappingNotify) {
  291.         XRefreshKeyboardMapping(&evt.xmapping);
  292.     } else if (evt.xany.type == ColormapNotify) {
  293.         Update_colormap_in_colormap_windows_list(&evt);
  294.     } else if (MeterEventHandler(&evt)) {
  295.         ;
  296. #ifdef DEBUG
  297.     } else {
  298.         wool_printf("Received event %s", eventtype[evt.type]);
  299.         wool_printf(" for unknown window 0x%x\n", evt.xany.window);
  300. #endif /* DEBUG */
  301.     }
  302.     if (event_is_key_or_button(evt))/* store last button */
  303.         bcopy(&evt, &GWM_LastEvent, sizeof(XEvent));
  304.  
  305.       next_event:
  306.     zrt_gc(local_zrt_size);
  307.     if (blocking)
  308.         dft_gc();
  309.     }
  310. }
  311.  
  312. #ifndef NO_GWM_LOG
  313. /* sends an UDP packet to keep count of all GWM running, if you want to
  314.  * sends your host name, or GWM_LOG_ID (string) if you dont want to send me
  315.  * this info
  316.  */
  317.  
  318. GWM_log()
  319. {
  320.     char buf[256];
  321.  
  322.     if (getenv("NO_GWM_LOG"))
  323.     return;
  324.     sprintf(buf, "%s%s STARTED", GWM_version_name, GWM_LOG_NAME);
  325. #ifndef DEBUG
  326.     KoalaSpy_SendPacket(0, 0, "gwm", GWM_LOG_ID, buf);
  327. #endif /* DEBUG */
  328. }
  329. #endif /* !NO_GWM_LOG */
  330.  
  331. /*
  332.  * Initialize GCs used in wool
  333.  */
  334.  
  335. InitGC()
  336. {
  337.     XGCValues       gc_values;
  338.  
  339.     FOR_ALL_SCREENS {
  340.     gc_values.graphics_exposures = False;
  341.     gc_values.function = GXinvert;
  342.     Context -> gc.Invert = XCreateGC(dpy, Context -> root,
  343.                   GCGraphicsExposures | GCFunction, &gc_values);
  344.     gc_values.foreground = Context -> pixel.Fore;
  345.     gc_values.background = Context -> pixel.Back;
  346.     gc_values.function = GXcopy;
  347.     Context -> gc.Work = XCreateGC(dpy, Context -> root,
  348.          GCGraphicsExposures | GCForeground | GCBackground | GCFunction,
  349.                        &gc_values);
  350.     gc_values.ts_x_origin = 0;
  351.     gc_values.ts_y_origin = 0;
  352.     gc_values.function = GXcopy;
  353.     gc_values.fill_style = FillStippled;
  354.     Context -> gc.Set = XCreateGC(dpy, Context -> root,
  355.             GCFunction | GCTileStipXOrigin | GCGraphicsExposures
  356.                  | GCTileStipYOrigin | GCFillStyle, &gc_values);
  357.     gc_values.ts_x_origin = 0;
  358.     gc_values.ts_y_origin = 0;
  359.     gc_values.function = GXcopy;
  360.     gc_values.fill_style = FillTiled;
  361.     Context -> gc.Tile = XCreateGC(dpy, Context -> root,
  362.             GCFunction | GCTileStipXOrigin | GCGraphicsExposures
  363.                  | GCTileStipYOrigin | GCFillStyle, &gc_values);
  364.     gc_values.function = GXinvert;
  365.     Context -> gc.Back = XCreateGC(dpy, Context -> root,
  366.                   GCGraphicsExposures | GCFunction, &gc_values);
  367.     gc_values.line_width = 0;
  368.     gc_values.foreground = 0xfd;
  369.     gc_values.function = GXxor;
  370.     gc_values.subwindow_mode = IncludeInferiors;
  371.     Context -> gc.Draw = XCreateGC(dpy, Context -> root,
  372.            GCGraphicsExposures | GCLineWidth | GCForeground | GCFunction
  373.                        | GCSubwindowMode, &gc_values);
  374.     MakeDefaultBitmap();
  375.     gc_values.function = GXinvert;
  376.     Context -> gc.Bitmap = XCreateGC(dpy, Context -> DefaultBitmap,
  377.                   GCGraphicsExposures | GCFunction, &gc_values);
  378.     }END_OF_ALL_SCREENS;
  379. }
  380.  
  381. /*
  382.  * GWM_Initialize
  383.  * initialize:
  384.  *     X
  385.  *     Wool
  386.  *     internal variables
  387.  */
  388.  
  389. int
  390. GWM_Initialize()
  391. {
  392.     XSetWindowAttributes attributes;
  393.  
  394.     GWM_SignalsInit();
  395.     XrmInitialize();
  396.     SetUpDefaults();
  397.     InitGC();
  398.     if (InitWool() != OK)
  399.     return FatalError;
  400.  
  401.     /* a hack for compilers chocking on wl_event.c initialisations on
  402.        offsets of structures instead of instance
  403.        code provided by:
  404.        Rodney McDuff <mcduff@newton.physics.uq.oz.au>
  405.        */
  406. #ifdef NO_STRUCTURE_OFFSETS
  407.     /* assign nonzero values to EventTimeFieldOffset[]
  408.        since apollo compiler complains at determining structure
  409.        sizes at compile time */
  410.     {
  411.     XEvent dummy_evt_ptr;
  412. #define XEventFieldOffset(evt_type, field) \
  413.     (((char *)(&(dummy_evt_ptr.evt_type.field))) - \
  414.         ((char *)(&(dummy_evt_ptr.type))))
  415.         ;
  416.     EventTimeFieldOffset[2] = XEventFieldOffset(xkey, time);
  417.     EventTimeFieldOffset[3] = XEventFieldOffset(xkey, time);
  418.     EventTimeFieldOffset[4] = XEventFieldOffset(xbutton, time);
  419.     EventTimeFieldOffset[5] = XEventFieldOffset(xbutton, time);
  420.     EventTimeFieldOffset[6] = XEventFieldOffset(xmotion, time);
  421.     EventTimeFieldOffset[7] = XEventFieldOffset(xcrossing, time);
  422.     EventTimeFieldOffset[8] = XEventFieldOffset(xcrossing, time);
  423.     EventTimeFieldOffset[28] = XEventFieldOffset(xproperty, time);
  424.     EventTimeFieldOffset[29] = XEventFieldOffset(xselectionclear, time);
  425.     EventTimeFieldOffset[30] = XEventFieldOffset(xselectionrequest, time);
  426.     EventTimeFieldOffset[31] = XEventFieldOffset(xselection, time);    
  427.     }
  428. #endif /* NO_STRUCTURE_OFFSETS */
  429.  
  430.     /* Manage Windows */
  431.     attributes.event_mask = KeyPressMask | ButtonPressMask | ButtonReleaseMask
  432.     | EnterWindowMask | LeaveWindowMask | FocusChangeMask
  433.     | SubstructureRedirectMask;
  434.     XSetErrorHandler(NoXError);
  435.     XSync(dpy, False);
  436.     FOR_ALL_SCREENS {
  437.     ErrorStatus = 0;
  438.     XChangeWindowAttributes(dpy, Context -> root,
  439.                 CWEventMask, &attributes);
  440.     XSync(dpy, False);
  441.     if (ErrorStatus && (!GWM_Decorate_all_windows)) {
  442.         fprintf(stderr,
  443.             "GWM: cannot get control of windows on screen #%d!\n%s\n",
  444.             Context -> screen,
  445.          "Maybe another window manager is running on the display?");
  446.         if (GWM_RetryStart) {
  447.         fprintf(stderr, "Retrying... kill your other window manager!\n");
  448.         do {
  449.             ErrorStatus = 0;
  450.             XChangeWindowAttributes(dpy, Context -> root,
  451.                         CWEventMask, &attributes);
  452.             XSync(dpy, False);
  453.         } while(ErrorStatus);
  454.         fprintf(stderr, "OK for screen %d\n", Context -> screen);
  455.         } else {
  456.         exit(1);
  457.         }
  458.     }
  459.     }END_OF_ALL_SCREENS;
  460.     GWM_re_init_PointerRoot();
  461.     XSetErrorHandler(XError);
  462.     return OK;
  463. }
  464.  
  465. /* re-init pointerroot */
  466.  
  467. GWM_re_init_PointerRoot()
  468. {
  469.     XSelectInput(dpy, Context -> root, 0);
  470.     XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  471. }
  472.  
  473. /* CloseEverything
  474.  * n =     0 normal (end)
  475.  *     1 error (we can still print messages)
  476.  *     -1 fatal error (connection closed)
  477.  */
  478.  
  479. #ifdef VOID_SIGNALS
  480. void
  481. #endif
  482. GWM_end(n)
  483. int n;
  484. {
  485. #ifdef MONITOR
  486.     moncontrol(0);            /* do not trace ending code */
  487. #endif /* MONITOR */
  488.     if (n >= 0 && GWM_is_initialized) {
  489.     XSetErrorHandler(NoXError);
  490.     GWM_re_init_PointerRoot();
  491.     XSync(dpy, True);
  492.     if (!GWM_is_ending && Context -> rootWob) {
  493.         GWM_is_ending = 1;
  494.         wool_do_print_errors = 0;
  495.         FOR_ALL_SCREENS {
  496.         SetTarget(Context -> rootWob);
  497.         ScreenClose(Context -> rootWob);
  498.         }END_OF_ALL_SCREENS;
  499.     }
  500.     XCloseDisplay(dpy);
  501.     }
  502.     exit(n);
  503. }
  504.  
  505. /* wool_end is calling GWM_end */
  506. wool_end(n)
  507. int n;
  508. {
  509.     GWM_end(n);
  510. }
  511.  
  512. /* signals management
  513.  */
  514.  
  515. static int GWM_in_fatal_error;
  516.  
  517. /* We try to handle bus errors gracefully, i.e. by trying to trigger a
  518.  * wool_error and going on, but aborting if we get one more
  519.  */
  520.  
  521. void
  522. GWM_FatalSignalHandler(sig)
  523. int    sig;
  524. {
  525.     if (!GWM_in_fatal_error) {
  526.     GWM_in_fatal_error = 1;
  527.     XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  528.     XSync(dpy, True);
  529.     if (wool_is_reading_file)
  530.         fprintf(stderr, "\n\"%s\": line %d:\n", wool_is_reading_file,
  531.         yylineno);
  532.     wool_stack_dump(1);
  533.     fprintf(stderr,
  534.         "\007\nGWM: Fatal error due to UNIX signal # %d -- Aborting\n",
  535.         sig);
  536.     }
  537.     exit(sig);
  538. }
  539.  
  540. /* Try to handle bus errors as normal errors, execpt that:
  541.  *     - if 2 bus errors come within 1 second, abort.
  542.  *     - if we were ending, just end, (in case the end code is faulty)
  543.  *     - ditto for restarting
  544.  */
  545.  
  546. void
  547. GWM_BusErrorSignalHandler(sig)
  548. int    sig;
  549. {
  550.     int             current_time;
  551.     static int      aborting;
  552.  
  553.     if (GWM_Window_being_opened)
  554.         XMapWindow(dpy, GWM_Window_being_opened -> hook);
  555.  
  556.     if (GWM_is_restarting) {
  557.     XCloseDisplay(dpy);
  558.     execvp(GWM_is_restarting[0], GWM_is_restarting);
  559.     }
  560.     if (GWM_is_ending)
  561.     GWM_end(-1);
  562.     current_time = time(0);
  563.     if (current_time == GWM_time_of_last_bus_error) {
  564.     if (aborting) {
  565.         exit(-1);
  566.     } else {
  567.         aborting = 1;
  568.         GWM_is_ending = 1;
  569.         fprintf(stderr,
  570.             "\007\nGWM: Internal error: bus error -- restarting\n");
  571.         XCloseDisplay(dpy);
  572.         execvp(GWM_argv[0], GWM_argv);
  573.     }
  574.     }
  575.     else {
  576.     GWM_time_of_last_bus_error = current_time;
  577. #ifdef SYSV
  578.     signal(sig, GWM_BusErrorSignalHandler);
  579. #endif /* SYSV */
  580.     wool_error(INTERNAL_ERROR, "bus error");
  581.     }
  582. }
  583.  
  584. GWM_SignalsInit()
  585. {
  586.     signal(SIGHUP, SIG_IGN);
  587.     /* keep signals for dbx debugging */
  588. #ifndef DEBUG
  589.     signal(SIGINT, GWM_end);
  590.     signal(SIGQUIT, GWM_end);
  591.     signal(SIGTERM, GWM_end);
  592.     signal(SIGFPE, GWM_FatalSignalHandler);
  593.     signal(SIGILL, GWM_BusErrorSignalHandler);
  594. #ifdef SIGBUS
  595.     signal(SIGBUS, GWM_BusErrorSignalHandler);
  596. #endif
  597.     signal(SIGSEGV, GWM_BusErrorSignalHandler);
  598. #ifdef SIGSYS
  599.     signal(SIGSYS, GWM_FatalSignalHandler);
  600. #endif
  601. #endif /* DEBUG     */
  602. }
  603.  
  604. /*
  605.  * functions to process events in the queue
  606.  */
  607.  
  608. WOOL_OBJECT
  609. wool_process_masked_events(mask)
  610. int    mask;        /* such as ExposureMask, SubstructureNotifyMask */
  611. {
  612.     EventData       evt;
  613.     Wob             wob;
  614.  
  615.     SAVE_EVENT_CONTEXT;
  616.     XSync(dpy, 0);
  617.     while (XCheckMaskEvent(dpy, mask, &evt)) {
  618.     if ((wob = LookUpWob(evt.xany.window))
  619.         || (wob = (Wob) LookUpClient(evt.xany.window))) {
  620.         WOOL_send(WOOL_process_event, wob, (wob, &evt));
  621.     }
  622.     }
  623.     RESTORE_EVENT_CONTEXT;
  624.     return NIL;
  625. }
  626.  
  627. /* to remove unmapped events
  628.    problem: argument w does not seem to be correctly passed, so use global
  629. */
  630.  
  631. static Window WindowUnmapped;
  632.  
  633. int
  634. GWM_remove_unmap_event(d, evt, arg)
  635. Display *d;
  636. XEvent *evt;
  637. XPointer arg;
  638. {
  639.     if (evt->xany.type == UnmapNotify
  640.     && evt->xunmap.window == WindowUnmapped)
  641.     return 1;
  642.     else
  643.     return 0;
  644. }
  645.  
  646. wool_process_unmap_events(w)
  647. Window w;
  648. {
  649.     XEvent       evt;
  650.  
  651.     XSync(dpy, 0);
  652.     WindowUnmapped = w;
  653.     while (XCheckIfEvent(dpy, &evt, GWM_remove_unmap_event, (char *)w))
  654.     ;
  655. }
  656.  
  657. WOOL_OBJECT
  658. wool_process_exposes()
  659. {
  660.     return wool_process_masked_events(ExposureMask);
  661. }
  662.  
  663. /*
  664.  *  initialize X and Context
  665.  */
  666.  
  667. GWM_OpenDisplay(display)
  668. char           *display;
  669. {
  670.     GWM_Display = (char *) XDisplayName(display);
  671.     if ((dpy = XOpenDisplay(display)) == NULL) {
  672.     fprintf(stderr, "%s Cannot XOpenDisplay on %s\n",
  673.         err, XDisplayName(display));
  674.     exit(1);
  675.     }
  676. #ifdef SHAPE
  677.     GWM_ShapeExtension = XShapeQueryExtension(dpy, &GWM_ShapeEventBase,
  678.                           &GWM_ShapeErrorBase);
  679. #endif /* SHAPE */
  680.     if (GWM_Synchronize)
  681.     XSynchronize(dpy, 1);
  682.     GWM_ScreenCount = ScreenCount(dpy);
  683.     wob_context = XUniqueContext();
  684.     client_context = XUniqueContext();
  685.     XSetErrorHandler(XError);
  686. }
  687.  
  688. /* options handling
  689.  */
  690.  
  691. char *
  692. path_append(old_path, new_path)
  693. char *old_path;
  694. char *new_path;
  695. {
  696.     char *path;
  697.     static int path_was_malloced;
  698.  
  699.     switch(*new_path){
  700.     case '+': case '-':        /* append & prepend */
  701.     if(path_was_malloced)
  702.         path = Realloc(old_path, strlen(old_path) + strlen(new_path) + 1);
  703.     else
  704.         path = Malloc(strlen(old_path) + strlen(new_path) + 1);
  705.     path_was_malloced = 1;
  706.     strcpy(path, (*new_path == '+' ? old_path : new_path+1));
  707.     strcat(path, ":");
  708.     strcat(path, (*new_path == '+' ? new_path+1 : old_path));
  709.     break;
  710.     default:            /* replace */
  711.     if(path_was_malloced)
  712.             Free(old_path);
  713.     path = new_path;
  714.     path_was_malloced = 0;
  715.     }
  716.     return path;
  717. }
  718.  
  719. usage()
  720. {
  721.     fprintf(stderr, "USAGE:   gwm OPTIONS [host:display]\n");
  722.     fprintf(stderr, "OPTIONS:\n");    
  723.     fprintf(stderr, "    -f file      use file instead of .gwmrc\n");
  724.     fprintf(stderr, "    -p path      force GWMPATH\n");    
  725.     fprintf(stderr, "    -p +path     appends to GWMPATH\n");    
  726.     fprintf(stderr, "    -p -path     prepends to GWMPATH\n");    
  727.     fprintf(stderr, "    -d display   manage display\n");
  728.     fprintf(stderr, "    -x screens   do not manage screens e.g. -x3,2,5\n");
  729.     fprintf(stderr, "    -k pid       send signal (def. SIGALRM) to pid when init is done\n");
  730.     fprintf(stderr, "    -K signal    number of signal to send for -k option\n");
  731.     fprintf(stderr, "    -1    manages only 1 screen, the default one\n");
  732.     fprintf(stderr, "    -r    retries till it can manage screens\n");
  733.     fprintf(stderr, "    -i    input focus remains PointerRoot\n");
  734.     fprintf(stderr, "    -F    no freeze: never freeze server\n");
  735.     fprintf(stderr, "    -t    to turn tracing on (as (trace 1))\n");    
  736.     fprintf(stderr, "    -m    to map all windows on startup\n");    
  737.     fprintf(stderr, "    -s    synchronize X calls\n");    
  738.     fprintf(stderr, "    -q    quiet: do not print startup banner\n");
  739.     fprintf(stderr, "    -a    asynchronously obeys button clicks\n");
  740.     fprintf(stderr, "    -D    debug: does not abort on error in profile\n");
  741.     fprintf(stderr, "    -W    decorate over another Window Manager\n");
  742.     fprintf(stderr, "    -w window_id decorate ONLY one window\n");
  743.     fprintf(stderr, "    -I    read WOOL commands from stdin\n");
  744.     fprintf(stderr, "    -P    together with -I: print prompts\n");
  745. #ifdef DEBUG
  746.     fprintf(stderr, "    -T flags to trace some items:\n");
  747.     fprintf(stderr, "          f  for fsm events\n");
  748.     fprintf(stderr, "          e  for all X events\n");
  749.     fprintf(stderr, "          l  for all file loads\n");
  750.     fprintf(stderr, "          m  for malloc/frees\n");
  751. #endif
  752.     fprintf(stderr, "\nGWMPATH is %s\n", wool_path);
  753.     fprintf(stderr, "built-in path was  %s\n", DEFAULT_WLPATH);
  754. }
  755.  
  756. GWM_getopts(argc, argv)
  757. int             argc;
  758. char           *argv[];
  759.  
  760. {
  761.     extern int      optind;
  762.     extern char    *optarg;
  763.     char        *display_name = 0;
  764.     char            *s;
  765.     int             c, errflag = 0;
  766.  
  767.     wool_user_profile_name = WOOL_USER_PROFILE;
  768.     wool_text_extension = WOOL_TEXT_EXTENSION;
  769.  
  770.     /* initialize paths (put .:$HOME before built-ins) */
  771.     wool_path = wool_fix_path(DEFAULT_WLPATH);
  772.     if ((s = (char *) getenv(WLPROFILE_USER_VARIABLE)) && (s[0] != '\0'))
  773.     wool_user_profile_name = s;         
  774.     if ((s = (char *) getenv(WLPATH_SHELL_VARIABLE)) && (s[0] != '\0'))
  775.     wool_path = s;
  776.     if ((s = (char *) getenv("GWM_MONOSCREEN")) && (s[0] != '\0'))
  777.     GWM_Monoscreen = 1;
  778.  
  779.     while ((c = getopt(argc, argv, "mtsb:p:f:DFT:w:Wd:iax:1qrk:K:IP")) != EOF) {
  780.     switch ((char) c) {
  781.     case 'I':
  782.         gwm_stdin = 1;
  783.         break;
  784.     case 'P':
  785.         gwm_prompt = 1;
  786.         break;
  787. #ifdef USER_DEBUG
  788.     case 't':        /* set trace level */
  789.         wool_tracing_on = 1;
  790.         break;
  791. #endif /* USER_DEBUG */
  792. #ifdef DEBUG
  793.     case 'T':
  794.         GWM_Tracelevel = atoi(optarg);
  795.         WlTraceFlags = optarg;
  796. /* Current traceflags:
  797.  * l load files
  798.  * e All X events received 
  799.  * f fsm MATCH/REJECTS
  800.  * m mallocs
  801.  * s spy
  802.  */
  803.         break;
  804. #endif /* DEBUG */
  805.     case 'i':
  806.         GWM_No_set_focus = 1;
  807.         break;
  808.     case 'm':        /* map all windows found on startup */
  809.         GWM_Mapall = 1;
  810.         break;
  811.     case 's':        /* no synchro in DEBUG mode */
  812.         GWM_Synchronize = 1;
  813.         break;
  814.     case 'r':        /* retry on StructureRedirect */
  815.         GWM_RetryStart = 1;
  816.         break;
  817.     case 'f':
  818.         wool_user_profile_name = optarg;
  819.         break;
  820.     case 'p':
  821.         wool_path = path_append(wool_path, optarg);
  822.         break;
  823.     case 'D':
  824.         wool_continue_reading_on_error = 1;
  825.         break;
  826.     case 'F':
  827.         GWM_GrabServer = 0;
  828.         break;
  829.     case 'w':
  830.         GWM_Decorate_one_window = atoi(optarg);
  831.         break;
  832.     case 'W':
  833.         GWM_Decorate_all_windows = 1;
  834.         break;
  835.     case 'd':
  836.         display_name = optarg;
  837.         break;
  838.     case 'x':
  839.         GWM_ScreensNotManaged = optarg;
  840.         break;
  841.     case 'a':
  842.         GWM_UserSynchronous = 0;
  843.         break;
  844.     case '1':
  845.         GWM_Monoscreen = 1;
  846.         break;
  847.     case 'q':
  848.         GWM_quiet = 1;
  849.         break;
  850.     case 'k':
  851.         GWM_kill_pid = atoi(optarg);
  852.         break;
  853.     case 'K':
  854.         GWM_kill_pid_sig = atoi(optarg);
  855.         break;
  856.     case '?':        /* usage */
  857.     default:
  858.         errflag++;
  859.         break;
  860.     }
  861.     }
  862.  
  863.     if (!GWM_kill_pid_sig)
  864.     GWM_kill_pid_sig = SIGALRM;
  865.  
  866.     if(!GWM_quiet || errflag)
  867.     GWM_print_banner();
  868.  
  869.     if (errflag) {
  870.     usage();
  871.     exit(1);
  872.     }
  873.     GWM_OpenDisplay(optind < argc ? argv[optind] : display_name);
  874. }
  875.  
  876. /*
  877.  * executes a function. Returns 1 on first wool_error, and aborts function.
  878.  */
  879.  
  880. int
  881. wool_error_occurred(function)
  882. int    (*function)();
  883. {
  884.     if (set_wool_error_resume_point()) {
  885.     return 1;
  886.     }
  887.     ASSERT(function);
  888.     (*function)();
  889.     return 0;
  890. }
  891.  
  892. void
  893. DecorateWindows()
  894. /*
  895.  * called to make wobs other all pre-existing windows
  896.  */
  897. {
  898.     Window          dummywin, parent;    /* dummy parent */
  899.     Window         *children;        /* list of root sons */
  900.     unsigned int    nchildren;        /* number of children */
  901.     ClientWindow    wob;
  902.     int             i;
  903.  
  904.     FOR_ALL_SCREENS {
  905.     if (XQueryTree(dpy, Context -> root, &dummywin, &parent,
  906.                &children, &nchildren)) {
  907.         SetTarget(Context -> rootWob);
  908.         GWM_ProcessingExistingWindows = 1;
  909.         for (i = 0; i < nchildren; i++) {
  910.         if (wob = LookUpClient(children[i]))
  911.             ClientWindowInitialMap(wob);
  912.         else if ((Mapped(children[i]) || GWM_Mapall)
  913.             && ((!GWM_Decorate_one_window)
  914.             || (GWM_Decorate_one_window == children[i]))) {
  915.             if (wob = (ClientWindow)
  916.             DecorateWindow(children[i],
  917.                        Context -> rootWob, 1, 1)) {
  918.             ClientWindowInitialMap(wob);
  919.             }
  920.         }
  921.         }
  922.         GWM_ProcessingExistingWindows = 0;
  923.         XFreeN(children);
  924.     }
  925.     }END_OF_ALL_SCREENS;
  926. }
  927.  
  928. /* initialise managed screens */
  929.  
  930. InitScreens()
  931. {
  932.     FOR_ALL_SCREENS {
  933.     SetTarget(Context -> rootWob);
  934.     SetUpScreen(Context -> rootWob,
  935.             WOOL_send(WOOL_eval, WL_describe_screen_call,
  936.                   (WL_describe_screen_call)));
  937.     ScreenOpen(Context -> rootWob);
  938.     }END_OF_ALL_SCREENS;
  939. }
  940.  
  941. /* set up the list of managed screens: GWMManagedScreens */
  942.  
  943. RegisterScreens()   
  944. {
  945.     int             screen_num;
  946.     int             number_of_managed_screens = 0;
  947.  
  948.     GWMManagedScreens = (GWMScreenContext *)
  949.     Calloc(sizeof(GWMScreenContext), ScreenCount(dpy));
  950.  
  951.     /* parse list of non-managed screens and pokes them */
  952.     mark_numbers_in_list(ScreenCount(dpy), GWM_ScreensNotManaged,
  953.              GWMManagedScreens);
  954.  
  955.     /* poke 1 in used screens, 0 in unused  and count them
  956.      * manage only DefaultScreen if we are in Monoscreen mode
  957.      */
  958.     for (screen_num = 0; screen_num < ScreenCount(dpy); screen_num++) {
  959.     if (GWMManagedScreens[screen_num]) {
  960.         GWMManagedScreens[screen_num] = NULL;
  961.     } else if ((!GWM_Monoscreen) || screen_num == DefaultScreen(dpy)) {
  962.         GWMManagedScreens[screen_num] = (GWMScreenContext) 1;
  963.         number_of_managed_screens++;
  964.     }
  965.     }
  966.  
  967.     /* (abort if none left) */
  968.     if (!number_of_managed_screens)
  969.     GWM_Abort("no screen left to manage");
  970.  
  971.     /* allocates and registers the managed screens */
  972.     for (screen_num = 0; screen_num < ScreenCount(dpy); screen_num++) {
  973.     if (GWMManagedScreens[screen_num]) {
  974.         GWMManagedScreens[screen_num] = RegisterScreen(screen_num);
  975.     }
  976.     }
  977. }
  978.  
  979.  
  980. /* parses a comma-separated list of numbers (string) and pokes 1 in the list
  981.  * if comprised beetween 0 and max_n
  982.  */
  983.  
  984. mark_numbers_in_list(max_n, string, list)
  985. int    max_n;
  986. char   *string;
  987. WOOL_OBJECT   *list;
  988. {
  989.     int             n;
  990.  
  991.     while (string && *string) {
  992.     n = atoi(string);
  993.     if (*string >= '0' && *string <= '9'
  994.         && n >= 0 && n < ScreenCount(dpy))
  995.         list[n] = (WOOL_OBJECT) 1;
  996.     if (string = strchr(string, ','))
  997.         string++;
  998.     else
  999.         return;
  1000.     }
  1001. }
  1002.  
  1003.