home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume1 / 8711 / 7 < prev    next >
Text File  |  1990-07-13  |  48KB  |  1,951 lines

  1. Path: uunet!husc6!bbn!rochester!udel!burdvax!bpa!cbmvax!vu-vlsi!devon!ncoast!allbery
  2. From: ganek@apollo.UUCP
  3. Newsgroups: comp.sources.misc
  4. Subject: A sample bitmapped window manager
  5. Message-ID: <5324@ncoast.UUCP>
  6. Date: 8 Nov 87 21:45:39 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Lines: 1939
  9. Approved: allbery@ncoast.UUCP
  10. X-Archive: comp.sources.misc/8711/7
  11.  
  12. The following C code is from the SIGGRAPH '87 course #23
  13. notes. Course #23 was titled "Introduction to Window Management". 
  14. The code is set of routines that can be used to build a 
  15. simple window system and some simple applications. They 
  16. were used to demonstrate some basic windowing principles. 
  17.  
  18. I had promised the student that I would distribute them
  19. electronically. (Better late than never! :-)
  20.  
  21. Any suggestions, improvements or bugs reports would be 
  22. welcomed and may be applied to future courses.  
  23.  
  24.    Daniel E. Ganek  CHM-02-RD
  25.    Apollo Computer Co.
  26.    220 Mill Rd               
  27.    Chelmsford, MA 01824
  28.  
  29.    (617)-256-6600 x8543
  30.    ganek@apollo.UUCP
  31.  
  32. /****start sws.h********/
  33. /*    sws.h - 
  34.  * Include file for the Simple Window System
  35.  * This is used by clients (applications)
  36.  *
  37.  * Author: Daniel E. Ganek    
  38.  * SIGGRAPH '87    
  39.  */
  40.  
  41. #include <sys/types.h>
  42. #include <sys/time.h>
  43.  
  44. /* window system error codes*/
  45.  
  46. #define    sws_no_such_window    -1    /* bad wid */
  47. #define    sws_not_connected    -2    /* window_system_connect not called */
  48. #define    sws_too_many_displays    -3    /* can pen another dislay */
  49. #define    sws_bad_display_name    -4    /* display name unknown */
  50. #define    sws_bad_size        -5    /* zero or negative size window */
  51. #define    sws_bad_background_op    -6    /* invalid background operation */
  52. #define    sws_bad_queue        -7    /* bad qid id */
  53.  
  54. /* define background and foreground "colors" */
  55.  
  56. #define    BACKGROUND    0
  57. #define    FOREGROUND    1
  58.  
  59. /*    
  60.  * Define some window related types: point, area, window_info    
  61.  */
  62.  
  63. typedef    struct    {
  64.     short    int    x;    /* a point = (x,y) */
  65.     short    int    y;
  66. } point;    
  67.  
  68. typedef    struct    {
  69.     point    origin;        /* an area = origin, size */
  70.     point    size;
  71. } area;
  72.  
  73. /* visibility information block */
  74.  
  75. typedef    struct    {
  76.     area    warea;        /* window area */
  77.     area    *vis_list;    /* ptr to visiblity list */
  78. } vis_info;    
  79.  
  80. /*    
  81.  * Input Types
  82.  * This is very simple event record.  In the real world we'd have a device ID and quite an extensive
  83.  * set of data types - here everything is encapsulated into an single 8-bit byte    
  84.  */
  85.  
  86. typedef    struct    {
  87.     struct    timeval    tmstamp;    /* event time */
  88.     long        window;        /* window id */
  89.     point        position;    /* position of locator */
  90.     unsigned char    code;        /* event data/code */
  91.                     /* codes 0-127 are ASCII */
  92.                     /* codes 128-255 are other */
  93. } input_event;
  94.  
  95. /* 
  96.  * Event Codes 
  97.  * Codes 0-127 are the standard ASCII events 
  98.  * use codes 128-255 for our special stuff    
  99.  */
  100.  
  101. #define    LAST_ASCII    0x7F    /* last valid ascii code */
  102. #define    REFRESH        0x80    /* refresh window needed */
  103. #define    ENTER        0x82    /* locator entered window */
  104. #define    EXIT        0x83    /* locator left window */
  105. #define    LOCATOR        0x91    /* locator event */
  106.  
  107. /* mouse buttons down and up*/
  108.  
  109. #define    LEFT        0xA0    /* left mouse button down */
  110. #define    LEFT_UP        0xA1    /* left mouse button up */
  111. #define    MIDDLE        0xA2    /* middle mouse button down*/
  112. #define    MIDDLE_UP    0xA3    /* middle mouse button up */
  113. #define    RIGHT        0xA4    /* right mouse button down */
  114. #define    RIGHT_UP    0xA5    /* right mouse button up */
  115.  
  116. /* 10 function keys f0-f9 down and up */
  117.  
  118. #define    F0    0xB0    
  119. #define    F0_UP    0xB1    
  120. #define    F1    0xB2    
  121. #define    F1_UP    0xB3    
  122. #define    F2    0xB4    
  123. #define    F2_UP    0xB5    
  124. #define    F3    0xB6    
  125. #define    F3_UP    0xB7    
  126. #define    F4    0xB8    
  127. #define    F4_UP    0xB9    
  128. #define    F5    0xBA    
  129. #define    F5_UP    0xBB    
  130. #define    F6    0xBC    
  131. #define    F6_UP    0xBD    
  132. #define    F7    0xBE    
  133. #define    F7_UP    0xBF    
  134. #define    F8    0xC0    
  135. #define    F8_UP    0xC1    
  136. #define    F9    0xC2    
  137. #define    F9_UP    0xC3    
  138.  
  139.  
  140. /*    
  141.  * Input Selection Mask
  142.  * The input selection mask is also greatly simplified. We've    
  143.  * collapsed everything into a small number of bits. Again in    
  144.  * the real world we have to select on a per device and per    
  145.  * code basis, e.g. we'd be able to select any specific ASCII    
  146.  * character. 
  147.  */
  148.  
  149. typedef    long    event_mask;    
  150.  
  151. /* system events */
  152.  
  153. #define    REFRESH_MASK    1<<0    /* window refresh needed */
  154. #define    ENTER_MASK    1<<2    /* locator entered window */
  155. #define    EXIT_MASK    1<<3    /* locator left window */
  156. #define    LOCATOR_MASK    1<<4    /* locator event */
  157. #define    KBD_MASK    1<<5    /* kbd (ASCII) events */
  158. #define    LEFT_MASK    1<<6    /* left mouse button down */
  159. #define    LEFT_UP_MASK    1<<7    /* left mouse button up */
  160. #define    MIDDLE_MASK    1<<8    /* middle mouse button down*/
  161. #define    MIDDLE_UP_MASK    1<<9    /* middle mouse button up */
  162. #define    RIGHT_MASK    1<<10    /* right mouse button down */
  163. #define    RIGHT_UP_MASK    1<<11    /* right mouse button up */
  164.  
  165. /* 10 Functions f0-f9 down and up */
  166.  
  167. #define    F0_MASK        1<<12    
  168. #define    F0_UP_MASK    1<<13    
  169. #define    F1_MASK        1<<14    
  170. #define    F1_UP_MASK    1<<15    
  171. #define    F2_MASK        1<<16    
  172. #define    F2_UP_MASK    1<<17    
  173. #define    F3_MASK        1<<18    
  174. #define    F3_UP_MASK    1<<19    
  175. #define    F4_MASK        1<<20    
  176. #define    F4_UP_MASK    1<<21    
  177. #define    F5_MASK        1<<22    
  178. #define    F5_UP_MASK    1<<23    
  179. #define    F6_MASK        1<<24    
  180. #define    F6_UP_MASK    1<<25    
  181. #define    F7_MASK        1<<26    
  182. #define    F7_UP_MASK    1<<27    
  183. #define    F8_MASK        1<<28    
  184. #define    F8_UP_MASK    1<<29    
  185. #define    F9_MASK        1<<30    
  186. #define    F9_UP_MASK    1<<31    
  187. #define    ALL_EVENTS    -1
  188.  
  189. /* window system functions*/
  190.  
  191. extern    long    window_system_connect();    /* connect to a display system */
  192. extern    long    window_create();        /* create a new window */
  193. extern    long    window_close();            /* close a window */
  194. extern    long    window_pop();            /* pop(raise) a window */
  195. extern    long    window_change();        /* change origin or size */
  196. extern    long    window_wid();            /* return wid of containing point */
  197. extern    long    window_information();        /* return window info */
  198.  
  199. /* input functions */
  200.  
  201. extern    long    input_connect();        /* connect to the input system */
  202. extern    long    input_wait();            /* wait for an input event */
  203. extern    long    input_check();            /* check for input */
  204. extern    long    input_select();            /* declare event interests */
  205. extern    long    input_process();        /* process an input event */
  206. /****end   sws.h********/
  207.  
  208. /****start sws_env.h****/
  209. /* sws_env.h
  210.  * System dependent include file 
  211.  * for the Simple Window System
  212.  *
  213.  * Author: Daniel E. Ganek    
  214.  * SIGGRAPH '87    
  215.  */
  216.  
  217. #define    TRUE    1    
  218. #define    FALSE    0
  219.  
  220. #include "sws.h"    
  221.  
  222. /* 
  223.  * Internal Definitions
  224.  * These are used by the SWS system independent module (sws.c)
  225.  * and the system dependent module.
  226.  */
  227.  
  228. /* 
  229.  * Input event queue - a simple ring buffer with and additional system 
  230.  * dependent piece to handle synchronization.    
  231.  */
  232.  
  233. #define    BUFFER_SIZE    16    /* size of input buffer */    
  234. #define    Q_SYS_SIZE     2    /* size of system specific stuff */
  235.  
  236. typedef    struct    {
  237.     int        in;            /* ring buffer in index */
  238.     int        out;            /* wout index */
  239.     input_event    buffer[BUFFER_SIZE];    /*buffer */
  240.     long        system[Q_SYS_SIZE];    /*system specific data */
  241. } event_queue;
  242.  
  243. /* system routine to handle synchronization */
  244.  
  245. extern    void    system_init_queue();    /* init system specific stuff in queue structure */
  246. extern    void    system_adv_queue();    /* wake up any waiters on the queue */
  247. extern    void    system_wait_queue();    /* wait for an event to appear on the queue */
  248.  
  249.  
  250. /* 
  251.  * Event Routing Block    
  252.  * A list of these hangs off each window 
  253.  * They are used to determine to which queue events are to be routed.    
  254.  */
  255.  
  256. typedef    struct    route_desc    {
  257.     struct    route_desc    *next;    /* forward */
  258.     struct    route_desc    *prev;    /* back ptrs */
  259.     event_mask        mask;    /* mask definig which event to route */
  260.     event_queue        *queue;    /* queue to route them t  */
  261. } route_block;
  262.  
  263. /*
  264.  * Window Input Information    
  265.  * This record contains info relating to input.    
  266.  */
  267.  
  268. typedef    struct    {
  269.     route_block    *erb;    /* event routing block */
  270. } input_info;
  271.  
  272. /*
  273.  *    Window Information    
  274.  * This record contains all info relating to a window, output and input.    
  275.  */
  276.  
  277. typedef    struct    win_rec    {
  278.     struct    win_rec    *next;        /* forward ptr */
  279.     struct    win_rec    *prev;        /* back ptrs */
  280.     vis_info    visinfo;    /* area and visiblity info*/
  281.     input_info    inputinfo;    /* input info */
  282. } window_rec;    
  283.  
  284. /*
  285.  * This record contains all the info relating to a display
  286.  * A display consists of all a screen with windows and input devices.
  287.  */
  288.     
  289. typedef    struct    {
  290.     area        screen;        /* origin and size of screen */
  291.     window_rec    *windows;    /* window list */
  292.     long        back_window;    /* wid of background window */
  293.     route_block    *grab_list;    /* grab list */
  294.     long        locator_wid;    /* window containing locator */
  295.     point        locator_pos;    /* abs position of locator */
  296.     long        *system;    /* system info */
  297. } display_rec;
  298.  
  299.  
  300. /* 
  301.  * Procedure to get display record from system 
  302.  */
  303.  
  304. extern    display_rec    *system_get_display();
  305.     
  306.  
  307. /*
  308.  * System specific versions of malloc, realloc, and free.
  309.  * In a shared memory environment these work out of shared memory
  310.  */
  311.  
  312. extern    char    *sws_malloc();
  313. extern    char    *sws_realloc();
  314. extern    void    sws_free();
  315. /**** end  sws_env.h****/
  316.  
  317. /****start clock.c******/
  318. /*
  319.  * clock.c
  320.  *
  321.  * Author: Daniel E. Ganek    
  322.  * SIGGRAPH '87    
  323.  *
  324.  * Clock program for use with the Simple Window Manager
  325.  * Draws a clock face once every n seconds.
  326.  *
  327.  */
  328.  
  329. #include <stdio.h>        /* some standard stuff */
  330. #include <math.h>
  331. #include "sws.h"        /* window system definitions */
  332.  
  333. #define    N_seconds    2    /* redisplay clock every N_seconds */
  334. #define    TRUE        1    
  335. #define    FALSE        0
  336. #define    TWOPI        6.28318
  337.  
  338. void DispClock();        /* routine to actually draw the clock */
  339.  
  340. main()
  341. {    
  342.     long        bid;    /* background ID */
  343.     long        wid;    /* our window ID */
  344.     vis_info    w_info;    /* size of window, etc. */
  345.     point        center;    /* where to center clock */
  346.     short        radius;    /* radius of clock proper */
  347.     long        status;    /* internal status - if false, exit */
  348.  
  349.  
  350.     bid = window_system_connect(0L);    /* connect to the wid system */
  351.  
  352.     if (bid <= NULL)    /* oops problems */
  353.         return(bid);
  354.  
  355.     /* First create a window for the clock */
  356.  
  357.     w_info.origin.x = 25;
  358.     w_info.origin.y = 25;
  359.     w_info.size.x    = 50;
  360.     w_info.size.y    = 50;
  361.  
  362.     wid = window_create(w_info.origin,w_info.size);
  363.  
  364.     status = (wid > 0);    /* set status */
  365.  
  366.     /*
  367.      * Once every N_second, redraw the clock.    
  368.      *    Get window size,    
  369.      *    Clear window,    
  370.      *    Calculate clock position    
  371.      *    center it in the window, use the smaller    
  372.      *    of x and y dimensions to determine radius    
  373.      *    Draw it    
  374.      */
  375.  
  376.     /* To exit program delete the clock window */    
  377.  
  378.     while (status == TRUE) {
  379.         if ((status = (draw_lock(wid)) > 0)) {
  380.             if ((status = (window_information(wid, &w_info)) > 0) ) {
  381.                 draw_clear(wid,BACKGROUND);
  382.                 center.x = (w_info.size.x - 1)/2;
  383.                 center.y = (w_info.size.y - 1)/2;
  384.                 radius = w_info.size.x < w_info.size.y ? (.9*w_info.size.x/2) : (.9*w_info.size.y/2); 
  385.                 DispClock(wid, center, radius);    
  386.             }
  387.  
  388.             draw_unlock(wid);
  389.         }    
  390.  
  391.         sleep(N_seconds);
  392.     }
  393.  
  394.     return (status);
  395. }
  396.  
  397. /* 
  398.  * This routine displays the image of a clock.    
  399.  * The image consists of a large circle with small    
  400.  * circles at each hour. The time is indicated by    
  401.  * hour and minute hands which are simple lines.    
  402.  */
  403.  
  404. void 
  405. DispClock(wid, center, radius)
  406. short    radius;
  407. long    wid;
  408. point    center;
  409. {
  410.     int        i;
  411.     point        c;
  412.     long        tim;
  413.     struct tm    t;
  414.     float        f_hour;
  415.  
  416.     /* Cursory error check*/
  417.  
  418.     if (radius == 0)    
  419.         return;
  420.  
  421.     /* Draw the outlining circle */
  422.  
  423.     draw_circle(wid, center, radius);
  424.  
  425.     /* Draw the hour tics */
  426.  
  427.     for (i = 0; i < 12; i++) {
  428.         c.x = center.x + .9*radius*sin(i*TWOPI/12) + .5;
  429.         c.y = center.y + .9*radius*cos(i*TWOPI/12) + .5;
  430.         draw_circle(wid,c,(short int)(.05*radius));
  431.     }
  432.  
  433.     /* Get the time and draw hands */
  434.  
  435.     tim = time(NULL);
  436.     t = *localtime(&tim);
  437.  
  438.     /* Draw minute hand */
  439.  
  440.     c.x = center.x + .7*radius*sin(t.tm_min*TWOPI/60) + .5;
  441.     c.y = center.y - .7*radius*cos(t.tm_min*TWOPI/60) + .5;
  442.     draw_line(wid, center, c);
  443.  
  444.     /* Draw hour hand */
  445.  
  446.     f_hour = (t.tm_hour + t.tm_min/60.)*TWOPI/12;
  447.     c.x = center.x + .5*radius*sin(f_hour) + .5;
  448.     c.y = center.y - .5*radius*cos(f_hour) + .5;
  449.     draw_line(wid, center, c);
  450.  
  451.     return;
  452. }    
  453. /**** end  clock.c******/
  454.  
  455. /****start swm.c********/
  456. /*
  457.  * swm.c 
  458.  *
  459.  * Author: Daniel E. Ganek    
  460.  * SIGGRAPH '87    
  461.  *
  462.  * Simple Window Manger for the Simple Window System
  463.  *
  464.  * This is what we refer to as a "minimal" window manager
  465.  * It does the following:
  466.  *    grow window
  467.  *    move window
  468.  *    pop window
  469.  *    close window 
  470.  *    refresh background window
  471.  *
  472.  * It demostrates some of the basic functions
  473.  *    input
  474.  *    refresh(exposure events)
  475.  *    grabbing events
  476.  *
  477.  */
  478.  
  479. #include <stdio.h>
  480. #include "sws.h"
  481.  
  482. #define    TRUE    1    
  483. #define    FALSE    0
  484.  
  485. void    process_event();
  486.  
  487. static    long        bid;    /* background wid */
  488. static    long        qid;    /* our queue id */
  489. static    event_mask    grab;    /* default grab mask */
  490. static    input_event    event;    /* current input event */
  491.  
  492. main()
  493. {
  494.     vis_info    w_info;
  495.     long        wid;            /* window to draw in */
  496.  
  497.     /* Connect us to SWS and get the background ID */
  498.  
  499.     if ((bid = window_system_connect(0L)) <= NULL) 
  500.         return (bid);
  501.  
  502.     qid = input_connect(bid);
  503.  
  504.     /* 
  505.      * We want to grab some function keys for window manager stuff,
  506.      * i.e. POP, CLOSE, MOVE AND GROW
  507.      *
  508.      * We also want refresh events for the backgorund    
  509.      */
  510.  
  511.     grab = F0_MASK | F0_UP_MASK | F1_MASK | F1_UP_MASK |
  512.      F2_MASK | F2_UP_MASK | F3_MASK | F3_UP_MASK;
  513.  
  514.     input_select(0, qid, grab);
  515.     input_select(bid, qid, REFRESH_MASK);
  516.  
  517.     /* just loop waiting for an event we asked for */
  518.     /* and then process it. */
  519.  
  520.     while (TRUE) {
  521.         input_wait(qid,&event);
  522.         process_event(&event);
  523.     }
  524.  
  525.     exit(0);
  526. }
  527.     
  528. /*
  529.  * a simple routine to xor a box
  530.  */
  531.  
  532. void
  533. box(wid, barea)
  534. long    wid;                /* window to draw in */
  535. area    barea;                /* box area */
  536. {
  537.     point    p0;
  538.     point    p1;
  539.  
  540.     draw_lock(wid);
  541.     draw_clip(bid,FALSE);    
  542.  
  543.     p0 = barea.origin;
  544.     p1.x = barea.origin.x + barea.size.x - 1;
  545.     p1.y = p0.y;
  546.     draw_xor(wid, p0, p1);        /* top */
  547.  
  548.     p0.x = p1.x;
  549.     p0.y = p1.y + 1;
  550.     p1.y = barea.origin.y + barea.size.y - 1;
  551.     draw_xor(wid, p0, p1);        /* right */
  552.  
  553.     p0.x = p1.x - 1;
  554.     p0.y = p1.y;
  555.     p1.x = barea.origin.x;
  556.     draw_xor(wid, p0, p1);        /* bottom */
  557.  
  558.     p0.x = p1.x;
  559.     p0.y = p1.y - 1;
  560.     p1.y = barea.origin.y + 1;
  561.     draw_xor(wid, p0, p1);        /* left */
  562.  
  563.     draw_clip(bid, TRUE);        /* turn clipping back on*/
  564.     draw_unlock(wid);    
  565.  
  566.     return;
  567. }
  568.  
  569. /*
  570.  * move_window
  571.  *
  572.  * This routine moves a window. It grabs the locator
  573.  * and follows it with a box. It stops when F2 is let up.
  574.  *
  575.  */ 
  576.  
  577. void
  578. move_window(event)
  579. input_event    *event;
  580. {
  581.     long        wid;        /* window to move */
  582.     vis_info    winfo;
  583.  
  584.     wid = window_wid(event->position);
  585.  
  586.     if (wid == bid)            /* can't move background */
  587.         return;
  588.  
  589.     input_select(0, qid, ALL_EVENTS);    /* grab everything */
  590.     window_information(wid, &winfo);    /* get current origin and size */
  591.     winfo.origin = event->position;        /* start postion */
  592.     box(bid, winfo);            /* draw a box */
  593.  
  594.     while (TRUE) {                /* look for locs and F2 up */
  595.         input_wait(qid, event);        /* wait for next event */
  596.  
  597.         if (event->code == F2_UP) {    /* F2_up */
  598.             box(bid, winfo);    /* erase old box */
  599.             break;            /* all done! */
  600.         }
  601.  
  602.         if (event->code == LOCATOR) {
  603.             box(bid, winfo);        /* erase old box */
  604.             winfo.origin = event->position;    /* move the box */
  605.             box(bid, winfo);        /* redraw box */
  606.         }    
  607.     }
  608.  
  609.     draw_lock(wid);
  610.  
  611.     window_change(wid, winfo);        /* move it */
  612.     window_pop(wid);            /* pop it */
  613.  
  614.     draw_unlock(wid);
  615.  
  616.     input_select(0, qid, grab);        /* back to old grab */
  617.  
  618.     return;
  619. }
  620.  
  621. /*
  622.  * grow_window
  623.  *
  624.  * This routine grows a window. It grabs the locator
  625.  * and follows it with the lower right hand corner of a box.
  626.  * It stops when F3 is let up.
  627.  *
  628.  */ 
  629.  
  630. long
  631. grow_window(event)
  632. input_event    *event;
  633. {
  634.     long        wid;            /* window to grow */
  635.     vis_info    winfo;
  636.     point        new_size;
  637.     char        box_drawn;
  638.  
  639.     wid = window_wid(event->position);
  640.  
  641.     if (wid == bid)                /* can't grow background */
  642.         return;
  643.  
  644.     input_select(0, qid, ALL_EVENTS);    /* grab everything */
  645.     window_information(wid, &winfo);    /* get current origin and size */
  646.     box_drawn = FALSE;            /* no box yet */
  647.  
  648.     while (TRUE) {                /* look for locs and F3 up */
  649.  
  650.         if ((event->code == LOCATOR) || (event->code == F3)) {
  651.  
  652.             /* calc new size */
  653.  
  654.             new_size.x = event->position.x - winfo.origin.x;
  655.             new_size.y = event->position.y - winfo.origin.y;
  656.  
  657.             /* ignore "negative" and small boxes */
  658.  
  659.             if ((new_size.x > 5) && (new_size.y > 5)) {
  660.                 if (box_drawn)
  661.                     box(bid, winfo);        /* erase old box */
  662.  
  663.                 winfo.size = new_size;            /* new box size */
  664.                 box(bid, winfo);            /* draw it */
  665.                 box_drawn = TRUE;
  666.             }
  667.         }
  668.  
  669.         input_wait(qid, event);            /* wait for next event */
  670.  
  671.         if (event->code == F3_UP) {        /* F3_up */
  672.             if (box_drawn)
  673.                 box(bid, winfo);    /* erase old box */
  674.  
  675.             break;    
  676.         }
  677.     }
  678.  
  679.     if ((new_size.x > 5) && (new_size.y > 5)) {    /* ignore "negative" boxes */
  680.         draw_lock(wid);
  681.         window_change(wid, winfo);        /* new size */
  682.         window_pop(wid);            /* pop it */
  683.         draw_unlock(wid);
  684.     }
  685.     else
  686.         box_drawn = FALSE;
  687.  
  688.     input_select(0, qid, grab);            /* back to old grab */
  689.  
  690.     return (box_drawn);
  691. }
  692.  
  693. /*
  694.  * process_event
  695.  * 
  696.  * This routine processes the events we receive.
  697.  * by calling the appropriate routine.
  698.  * Since most routines modify someone elses
  699.  * window, i.e. move it or grow, etc. we 
  700.  * fill it in with the background value until
  701.  * the other guy gets around to fixing it up.
  702.  * 
  703.  * We "own" the background; so we're looking for
  704.  * refresh events for it.    
  705.  *
  706.  */ 
  707.  
  708. void
  709. process_event(event)
  710. input_event    *event;
  711. {
  712.     long    wid;                /* window */
  713.  
  714.     wid = 0;
  715.  
  716.     switch (event->code) {
  717.     case F0:
  718.         wid = window_wid(event->position);
  719.  
  720.         if (window_pop(wid) <= 0)
  721.             wid = 0;
  722.  
  723.         break;
  724.  
  725.     case F1:
  726.         wid = window_wid(event->position);
  727.         window_close(wid);
  728.         wid = 0;
  729.  
  730.         break;
  731.  
  732.     case F2:
  733.         wid = window_wid(event->position);
  734.         move_window(event);    
  735.  
  736.         break;
  737.  
  738.     case F3:
  739.         wid = window_wid(event->position);
  740.  
  741.         if (grow_window(event) <= 0)
  742.             wid = 0;    
  743.         
  744.         break;
  745.  
  746.     case REFRESH:
  747.         if (event->window == bid)
  748.             wid = bid;        /* refresh background */
  749.     }
  750.  
  751.     if (wid) {
  752.         draw_lock(wid);
  753.  
  754.         if (wid != bid) 
  755.             draw_clear(wid, BACKGROUND);    
  756.         else
  757.             draw_clear(wid, FOREGROUND);    /* The "background" color for the bid */
  758.  
  759.         /* is the writing color of other windows */    
  760.  
  761.         draw_unlock(wid);
  762.     }
  763.  
  764.     return;
  765. }
  766. /**** end  swm.c********/
  767.  
  768. /****start sws.c********/
  769. /* 
  770.  * sws.c 
  771.  * Simple Window System
  772.  * 
  773.  * Author: Daniel E. Ganek
  774.  * SIGGRAPH '87
  775.  *
  776.  * This is a simple (almost trivial) window system 
  777.  * There is no window hiearchy; but it does support occluding windows.
  778.  * Input is limited to ASCII keystroke, mouse motion, 
  779.  * mouse buttons, and 10 function keys.
  780.  * 
  781.  * Though simple, this system demostrates many of the functions
  782.  * that must exists in a window system and problems associated
  783.  * with them.  The methods and algorithms included here are 
  784.  * not necessarily the most efficient or desirable. As a matter 
  785.  * of fact, things have been kept simple so as not to confuse
  786.  * the beginner.  NUMEROUS optimizations would be made in a real system.
  787.  */
  788.  
  789. #include <stdio.h>
  790. #include "sws_env.h"
  791.  
  792. #define    max(a, b)    ((a) < (b) ? (b) : (a))    /* std max and min */
  793. #define    min(a, b)    ((a) > (b) ? (b) : (a))
  794.  
  795. /* 
  796.  * static declarations 
  797.  */
  798.  
  799. static    display_rec    *display = NULL;        /* pointer to the display record */
  800. static    int        is_locked;            /* did I already lock the db? */
  801. static    area        null_area = { 0, 0, 0, 0 };    /* handy for zeroing things */
  802.  
  803. /* 
  804.  * forward declarations 
  805.  */
  806.  
  807. window_rec    *check_window();
  808. void        calc_vis_list();
  809.  
  810. /*****************************************************************************************/
  811.  
  812. /* 
  813.  * window_lock 
  814.  * window_unlock 
  815.  *
  816.  * These routines are used to set and release the mutex lock on the 
  817.  * window database. This is necessary in shared memory environment 
  818.  * since we don't want two or more client simultaneously modifying the
  819.  * database!  We rely on system_lock() to do the actual locking.
  820.  *
  821.  * This is not necessary in a server environment, if only the server is
  822.  * accessing the database and display.
  823.  *
  824.  */
  825.  
  826. void
  827. window_lock()
  828. {
  829.     system_lock(display);
  830. }
  831.  
  832. void
  833. window_unlock()
  834. {
  835.  
  836.     system_unlock(display);
  837. }
  838.  
  839.  
  840.  
  841.  
  842. /*****************************************************************************************/
  843.  
  844. /* 
  845.  * window_system_connect 
  846.  *
  847.  * This must be the first routine called by a client, since
  848.  * it connects the client to the display system specified
  849.  * by "display_name".  It returns the wid of the background
  850.  * window. By convention, NULL specifies the default display.
  851.  */
  852.  
  853. long 
  854. window_system_connect(display_name)
  855. char    *display_name;
  856. {
  857.     /* If this is this first time we've been called, do the initialization */
  858.     if (display <= NULL) {
  859.         display = system_get_display(display_name);    /* get screen info pointer */
  860.  
  861.         if(display <= NULL)                /* some sort of error */
  862.             return ((long)display);
  863.  
  864.         if (display->windows == NULL) {            /* if no windows, create */
  865.             /* background same size as screen */
  866.             window_lock();
  867.             display->back_window = window_create(display->screen.origin, display->screen.size); 
  868.             display->locator_wid = display->back_window; /*init locator database */
  869.             window_unlock();
  870.         }
  871.         return ((long)display->back_window);
  872.     }
  873.  
  874.     else                    /* already inited - just return background id */
  875.         return ((long)display->back_window);
  876.  
  877. }
  878.  
  879. /*****************************************************************************************/
  880.  
  881. /* 
  882.  * window_create 
  883.  *
  884.  * This routine creates a new window at the specified origin and specified
  885.  * size.  It places this window on top of all others.  Most windows systems
  886.  * would make this window of null size and not display it.  This would give
  887.  * the application time to fix it up and make it look right.  A window can be
  888.  * larger than the size of the display, the visibility lists will not include
  889.  * any areas outside of the display.
  890.  *
  891.  * After creating the window, this routine recalculates the
  892.  * visibilty areas of all other windows.
  893.  */
  894.  
  895. long
  896. window_create(origin, size)
  897. point    origin;                    /* origin of new window */
  898. point    size;                    /* size of new widnow */
  899. {
  900.     window_rec    *new_window;
  901.  
  902.     /* some checks first */
  903.  
  904.     if (display <= NULL)            /* not inited */
  905.         return (sws_not_connected);
  906.  
  907.     if ((size.x < 0) | (size.y < 0)) 
  908.         return (sws_bad_size);        /* negative size is illegal */
  909.  
  910.     /* alloc memory for new window descriptor */ 
  911.  
  912.     new_window = (window_rec*) sws_malloc(sizeof *new_window);
  913.  
  914.     /* init window descriptor */
  915.  
  916.     new_window->visinfo.warea.origin = origin;
  917.     new_window->visinfo.warea.size = size;
  918.     new_window->visinfo.vis_list = NULL;
  919.  
  920.     /* input stuff */
  921.  
  922.     new_window->inputinfo.erb = NULL;            /* no input selected */
  923.  
  924.     window_lock();                /* make sure no one else is around */
  925.  
  926.     /* insert this window on top of the window list*/
  927.  
  928.     new_window->next = display->windows;
  929.     display->windows = new_window;
  930.     new_window->prev = NULL;
  931.  
  932.     if (new_window->next != NULL) 
  933.         new_window->next->prev = new_window;
  934.  
  935.     /* new window is on top, so recalculate vis lists */
  936.     /* no exposure events are possible. */
  937.  
  938.     calc_vis_list(new_window, FALSE);
  939.  
  940.     window_unlock();            /* all done with db */
  941.  
  942.     return ((long)new_window);
  943. }
  944.  
  945. /*****************************************************************************************/
  946.  
  947. /*
  948.  * window_change 
  949.  *
  950.  * This routine changes the size and origin of a window.
  951.  * Some systems get fancy and have two routines.
  952.  *
  953.  * This routine recalculates the visibility lists; refresh
  954.  * events can be generated.
  955.  *
  956.  */
  957.  
  958. long
  959. window_change(wid, origin, size)
  960. long    wid;                    /*window to change*/
  961. point    origin;                    /*new origin */
  962. point    size;                    /*new size */
  963. {
  964.     window_rec    *window;
  965.  
  966.     /* some checks first */
  967.  
  968.     if (display <= NULL)                /* not inited */
  969.         return (sws_not_connected);
  970.  
  971.     if ((window = check_window(wid)) == NULL)    /* bad ID */
  972.         return (sws_no_such_window);
  973.  
  974.     if (window->next == NULL)            /* can't change background */
  975.         return (sws_bad_background_op);
  976.  
  977.     if ((size.x < 0) || (size.y < 0))        /* no negative size */
  978.         return (sws_bad_size);
  979.  
  980.     window_lock();                    /* make sure no one else is around */
  981.  
  982.     /* change parameters and recalc vis lists */
  983.  
  984.     window->visinfo.warea.size = size;
  985.     window->visinfo.warea.origin = origin;
  986.  
  987.     /* recalc vis lists, refresh possible */
  988.  
  989.     calc_vis_list(window, TRUE);
  990.     window_unlock();                /* all done with db */
  991.  
  992.     return (TRUE);
  993. }
  994.  
  995. /*****************************************************************************************/
  996.  
  997. /* 
  998.  * window_close 
  999.  *
  1000.  * This routine closes, i.e. deletes, a window. All traces of the
  1001.  * window are removed from the system.
  1002.  * 
  1003.  * This routine recalculates the visibility lists; refresh
  1004.  * events can be generated.
  1005.  *
  1006.  */
  1007.  
  1008. long
  1009. window_close(wid)
  1010. long    wid;
  1011. {
  1012.     window_rec    *window;
  1013.     route_block    *erb;
  1014.  
  1015.     /* some check first */
  1016.  
  1017.     if (display <= NULL)                /* not inited */
  1018.         return (sws_not_connected);
  1019.  
  1020.     if ((window = check_window(wid)) == NULL)    /* bad ID */
  1021.         return (sws_no_such_window);
  1022.  
  1023.     if (window->next == NULL)            /* don't touch background */
  1024.         return (sws_bad_background_op);
  1025.  
  1026.     window_lock();                    /* make sure no one else is around */
  1027.  
  1028.     /* first remove window from linked list*/
  1029.  
  1030.     if (window->next != NULL)
  1031.         window->next->prev = window->prev;
  1032.  
  1033.     if (window->prev != NULL)
  1034.         window->prev->next = window->next;
  1035.     else
  1036.         display->windows = window->next;
  1037.  
  1038.     /* recalc vis lists, refresh events possible */
  1039.  
  1040.     calc_vis_list(window->next, TRUE);
  1041.     window_unlock();                /* all done with db */
  1042.  
  1043.     /* free up memory */
  1044.     /* This is usually the source of memory leaks */
  1045.     /* In this case we must delete the vis list, and */
  1046.     /* event routing blocks */
  1047.  
  1048.     erb = window->inputinfo.erb;            /* erb's */
  1049.  
  1050.     while (erb != NULL) {
  1051.         window->inputinfo.erb = erb->next;
  1052.         sws_free(erb);
  1053.         erb = window->inputinfo.erb;
  1054.     }
  1055.  
  1056.     sws_free(window->visinfo.vis_list);        /* vis list */
  1057.     sws_free(window);                /* window record */
  1058.  
  1059.     return (TRUE); 
  1060. }
  1061.  
  1062. /*****************************************************************************************/
  1063.  
  1064. /* 
  1065.  * window_pop 
  1066.  * 
  1067.  * This routine pops (raises) a window to the top of
  1068.  * of the window list. 
  1069.  *
  1070.  * Refresh events are only possible for window being popped.
  1071.  *
  1072.  */
  1073.  
  1074. long
  1075. window_pop(wid)
  1076. long    wid;
  1077. {
  1078.     window_rec    *window;
  1079.  
  1080.     /* some checks first */
  1081.  
  1082.     if (display <= NULL)                /* not inited */
  1083.         return (sws_not_connected);
  1084.  
  1085.     if ((window = check_window(wid)) == NULL)    /* bad ID */
  1086.         return (sws_no_such_window);
  1087.  
  1088.     window_lock();                    /* make sure no one else is around */
  1089.  
  1090.     /* if we were on top, don't bother */
  1091.  
  1092.     if (window->prev == NULL) {
  1093.         window_unlock();
  1094.         return (TRUE); 
  1095.     }
  1096.  
  1097.     /* can't pop, background */
  1098.  
  1099.     if (window->next == NULL) {
  1100.         window_unlock();
  1101.         return (sws_bad_background_op);
  1102.     }
  1103.  
  1104.     /* first remove window from linked list */
  1105.  
  1106.     window->next->prev = window->prev;
  1107.     window->prev->next = window->next;
  1108.  
  1109.     /* now insert on top of the list */
  1110.  
  1111.     window->next = display->windows;        /* we point to old top */
  1112.     display->windows = window;            /* screen points to us */
  1113.     window->prev = NULL;                /* we're on top */
  1114.     window->next->prev = window;            /* next guy points back to us */
  1115.  
  1116.     /* (can't be null) */
  1117.  
  1118.     /* recalc vis lists, refresh events are only possible for window */
  1119.  
  1120.     calc_vis_list(window, FALSE);
  1121.     input_process(window, REFRESH);            /* might get unnecessary REFRESH events */
  1122.     window_unlock();                /* all done with db */
  1123.  
  1124.     return (TRUE);
  1125.  
  1126. }
  1127.  
  1128. /*****************************************************************************************/
  1129.  
  1130. /* 
  1131.  * window_information 
  1132.  * This routine returns interesting info 
  1133.  * about a window: 
  1134.  *    origin
  1135.  *    size
  1136.  *    ptr to vis list
  1137.  *
  1138.  */
  1139.  
  1140. long 
  1141. window_information(wid, winfo)
  1142. long        wid;
  1143. vis_info    *winfo;
  1144. {
  1145.     window_rec    *window;
  1146.  
  1147.     /* some checks first */
  1148.  
  1149.     if (display <= NULL)                /* not inited */
  1150.         return (sws_not_connected);
  1151.  
  1152.     if ((window = check_window(wid)) == NULL)    /* bad ID */
  1153.         return (sws_no_such_window);
  1154.  
  1155.     /* Just copy internal info - this is a bit dangerous */
  1156.     /* since we're giving the app our ptr to the vis lists */
  1157.     /* Some people may consider this a feature! */
  1158.  
  1159.     window_lock();                    /* make sure no one else is around */
  1160.     *winfo = window->visinfo;
  1161.     window_unlock();                /* all done with db */
  1162.  
  1163.     return (TRUE);
  1164. }
  1165.  
  1166. /*****************************************************************************************/
  1167.  
  1168. /* 
  1169.  * window_wid 
  1170.  * This routine return the wid of the topmost 
  1171.  * window containing the point (x, y). This is
  1172.  * used by clients to figure out which window
  1173.  * the locator is pointing to. 
  1174.  *
  1175.  */
  1176.  
  1177. long 
  1178. window_wid(position)
  1179. point    position;
  1180. {
  1181.     window_rec    *window;
  1182.  
  1183.     /* some check first */
  1184.  
  1185.     if (display <= NULL)                /* not inited */
  1186.         return (sws_not_connected);
  1187.  
  1188.     window_lock();                    /* make sure no one else is around */
  1189.  
  1190.     /* Start at the top and look for the first */
  1191.     /* window that contains the point */
  1192.  
  1193.     for (window = display->windows; window != NULL; window = window->next) {
  1194.         if (((position.x > window->visinfo.warea.origin.x)
  1195.          && (position.x <= (window->visinfo.warea.origin.x + window->visinfo.warea.size.x - 1)))
  1196.          && ((position.y > window->visinfo.warea.origin.y)
  1197.          && (position.y <= (window->visinfo.warea.origin.y + window->visinfo.warea.size.y - 1)))) {
  1198.             window_unlock();
  1199.             return ((long)window);
  1200.         }
  1201.     }
  1202.  
  1203.     window_unlock();                /* all done with db */
  1204.  
  1205.     /* if outside just return background */
  1206.     /* We could return NULL */
  1207.  
  1208.     return (display->back_window);
  1209. }
  1210.  
  1211. /*****************************************************************************************/
  1212.  
  1213. /* 
  1214.  * check_window
  1215.  * validates a wid and    returns pointer to the window record 
  1216.  * in our case wid IS the pointer, this routine simply 
  1217.  * checks to see that it is in the current list
  1218.  * this prevents random wid from being used, but is not
  1219.  * so robust as to detect re-use of the same memory
  1220.  *
  1221.  */
  1222.  
  1223. window_rec *
  1224. check_window(wid)
  1225. long    wid;
  1226. {
  1227.     window_rec    *window;
  1228.  
  1229.     /* search the window list */
  1230.  
  1231.     for (window = display->windows; window != NULL; window = window->next)
  1232.         if ((long)window == wid)
  1233.             return (window);            /* found it */
  1234.  
  1235.     /* didn't find it */
  1236.  
  1237.     return (NULL);
  1238. }
  1239.  
  1240. /*****************************************************************************************/
  1241.  
  1242. /*
  1243.  * overlap
  1244.  * little routine to determine if two rectangles overlap
  1245.  * returns TRUE if they do, FALSE otherwise. Doesn't figure
  1246.  * out who's on top.
  1247.  *
  1248.  */
  1249.  
  1250. int
  1251. overlap(a, b)
  1252. area    a;
  1253. area    b;
  1254. {
  1255.     if (a.origin.x >= b.origin.x+b.size.x)    /* a to the right? */
  1256.         return (FALSE); 
  1257.  
  1258.     if (a.origin.y >= b.origin.y+b.size.y)    /* a below? */
  1259.         return (FALSE);
  1260.  
  1261.     if (a.origin.x+a.size.x <= b.origin.x)    /* a above? */
  1262.         return (FALSE);
  1263.  
  1264.     if (a.origin.y+a.size.y <= b.origin.y)    /* a to the left? */
  1265.         return (FALSE);
  1266.  
  1267.     /* If the above tests fail areas overlap */
  1268.  
  1269.     return (TRUE);
  1270. }
  1271.  
  1272. /*****************************************************************************************/
  1273.  
  1274. /*
  1275.  * exclude
  1276.  *
  1277.  * This routine excludes a rectangle(top) from a list of rectangles
  1278.  * note that this routine does not produce an irreducible set; but
  1279.  * does gaurantee that no two rectangles overlap.
  1280.  *
  1281.  * (WARNING: I think there's a bug in here!)
  1282.  *
  1283.  */
  1284.  
  1285.  
  1286. area    *
  1287. exclude (top, list)
  1288. area    top;                    /* area to be exclude */
  1289. area    *list;                    /* list of areas to operate on */
  1290. {
  1291.     area    *new_list;
  1292.     int    i;
  1293.     int    j;
  1294.     int    len;
  1295.  
  1296.     struct    {
  1297.         int    xs;
  1298.         int    xe;
  1299.         int    ys;
  1300.         int    ye
  1301.     } rem, top_limits;
  1302.  
  1303.     /* it's a lot easier using start and end point */
  1304.  
  1305.     top_limits.xs = top.origin.x;
  1306.     top_limits.xe = top.origin.x + top.size.x;
  1307.     top_limits.ys = top.origin.y;
  1308.     top_limits.ye = top.origin.y + top.size.y;
  1309.  
  1310.     j = 0;
  1311.     for (len = 0;list[len].size.x != 0; len++)        /* get list len */
  1312.         ;
  1313.  
  1314.     new_list = (area *)sws_malloc((len+1)*sizeof (*new_list));    /* make new list */
  1315.  
  1316.     /* look for the four exposed strips at top, sides and bottom */
  1317.  
  1318.     for (i = 0; i < len; i++) {
  1319.         if (overlap(top, list[i]) == FALSE)    /*if no overlap, just copy */
  1320.             new_list[j++] = list[i];
  1321.         else {                    /* calc 4 fragments */
  1322.                             /* make enough room for 4 new entries */
  1323.             new_list = (area *)sws_realloc(new_list, max(len+4, j+4)*sizeof (*new_list));
  1324.  
  1325.             rem.xs = list[i].origin.x;    /* start with full area */
  1326.             rem.xe = list[i].origin.x + list[i].size.x;
  1327.             rem.ys = list[i].origin.y;
  1328.             rem.ye = list[i].origin.y + list[i].size.y;
  1329.  
  1330.             if (top_limits.xs > rem.xs) {    /* left side strip */
  1331.                 new_list[j].origin.x = rem.xs;
  1332.                 new_list[j].origin.y = rem.ys;
  1333.                 new_list[j].size.x = top_limits.xs - rem.xs;
  1334.                 new_list[j++].size.y = rem.ye - rem.ys;
  1335.                 rem.xs = top_limits.xs;
  1336.             }
  1337.  
  1338.             if (top_limits.xe < rem.xe) {    /* right side strip */
  1339.                 new_list[j].origin.x = top_limits.xe;
  1340.                 new_list[j].origin.y = rem.ys;
  1341.                 new_list[j].size.x = rem.xe - top_limits.xe;
  1342.                 new_list[j++].size.y = rem.ye - rem.ys;
  1343.                 rem.xe = top_limits.xe;
  1344.             }
  1345.  
  1346.             if (top_limits.ye < rem.ye) {    /* bottom strip */
  1347.                 new_list[j].origin.x = rem.xs;
  1348.                 new_list[j].origin.y = top_limits.ye;
  1349.                 new_list[j].size.x = rem.xe - rem.xs;
  1350.                 new_list[j++].size.y = rem.ye - top_limits.ye;
  1351.                 rem.ye = top_limits.ye;
  1352.             }
  1353.  
  1354.             if (top_limits.ys > rem.ys) {    /* top strip */
  1355.                 new_list[j].origin.x = rem.xs;
  1356.                 new_list[j].origin.y = rem.ys;
  1357.                 new_list[j].size.x = rem.xe - rem.xs;
  1358.                 new_list[j++].size.y = top_limits.ys - rem.ys;
  1359.             }
  1360.         }
  1361.     }
  1362.  
  1363.     /* free the old list and return new */
  1364.  
  1365.     new_list[j] = null_area;    /* insert terminator */
  1366.     sws_free(list);
  1367.  
  1368.     return (new_list);
  1369. }
  1370.  
  1371. /*****************************************************************************************/
  1372.  
  1373. /* calc_vis_list
  1374.  * This routine calculates the visibility list for a set of windows
  1375.  * starting with "start_window" and going down to the bottom.
  1376.  * The resultant vis lists are not irreducible - we could add 
  1377.  * a coalescing routine at the end.
  1378.  *
  1379.  * When we expose an area of a window, we generate an refresh event.
  1380.  * If we don't expose an area we shouldn't generate an refresh event.
  1381.  * That calculation is a bit tedious. Our simple exposure algorithm 
  1382.  * can't tell the difference between exposure and damage. So, we ask
  1383.  * for help from the caller in the form of the "notify" parameter.
  1384.  * If TRUE, we generate refresh events; if FALSE we don't.
  1385.  *
  1386.  * (Doing it right would be a nice excerise for the student) 
  1387.  *
  1388.  */
  1389.  
  1390. void 
  1391. calc_vis_list(start_window, notify)
  1392. window_rec    *start_window;        /* where in the window list to start */
  1393. int        notify;
  1394. {
  1395.     window_rec    *window;
  1396.     window_rec    *super_window;
  1397.     int        i;
  1398.     int        max_len;
  1399.     int        gen_exposure;
  1400.     area        *new_list;
  1401.     point        end;
  1402.  
  1403.     for (window = start_window; window != NULL; window = window->next) {
  1404.         max_len = 10;
  1405.         new_list = (area *)sws_malloc(max_len*sizeof (*new_list));
  1406.  
  1407.         /* Since the physical display can be smaller than the window, 
  1408.          * start with physical display limits and intersect them with
  1409.          * the window limits, if this were hierarchical system we'd
  1410.          * use the parent limits instead of the display limits.
  1411.          */
  1412.  
  1413.         /* first, adjust the origin if necessary */
  1414.  
  1415.         new_list->origin.x = max(display->screen.origin.x, window->visinfo.warea.origin.x);
  1416.         new_list->origin.y = max(display->screen.origin.y, window->visinfo.warea.origin.y);
  1417.  
  1418.         /* now calc the size */
  1419.  
  1420.         end.x = min(display->screen.origin.x + display->size.x, window->visinfo.warea.origin.x + window->visinfo.warea.size.x);
  1421.         end.y = min(display->screen.origin.y + display->size.y, window->visinfo.warea.origin.y + window->visinfo.warea.size.y);
  1422.         new_list->size.x = max(end.x - new_list->origin.x, 0);
  1423.         new_list->size.y = max(end.y - new_list->origin.y, 0);
  1424.  
  1425.         /* if either dim is zero, set the other to zero */
  1426.  
  1427.         if (new_list->size.x != 0 && new_list->size.y != 0) {
  1428.             new_list[1].size.x =0;
  1429.             new_list[1].size.y =0;
  1430.  
  1431.             /* we have a no-zero visibility list, exclude area
  1432.              * covered by a superior window
  1433.              */
  1434.  
  1435.             for (super_window = display->windows;
  1436.              super_window != window; super_window = super_window->next) {
  1437.  
  1438.                 /* check for no overlap first */
  1439.  
  1440.                 if (overlap(super_window->visinfo.warea, window->visinfo.warea))
  1441.                     new_list = exclude(super_window->visinfo.warea, new_list);
  1442.             }
  1443.         }
  1444.  
  1445.         /* all done with this window check to see if */
  1446.         /* we should generate an exposure event */
  1447.  
  1448.         if (window->visinfo.vis_list != NULL) {
  1449.             if (notify) {
  1450.                 /* Compare the old list to the new and if they are different */
  1451.                 /* generate an exposure event. NOTE THAT THIS METHOD WILL */
  1452.                 /* CAUSE SPURIOUS EXPOSURE EVENTS.    (nice exercise for the student!) */
  1453.  
  1454.                 gen_exposure = FALSE;
  1455.  
  1456.                 for (i = 0; new_list[i].size.x + window->visinfo.vis_list[i].size.x != 0; i++) {
  1457.                     /* compare element */
  1458.  
  1459.                     if (!same_area(&window->visinfo.vis_list[i]), &new_list[i]) {
  1460.                         gen_exposure = TRUE;    /* not equal */
  1461.                         break;            /* get out */ 
  1462.                     }
  1463.                 }
  1464.  
  1465.                 if (gen_exposure)
  1466.                     (void)input_process(window, REFRESH); 
  1467.             }
  1468.         }
  1469.  
  1470.         sws_free(window->visinfo.vis_list);    /* free up the old list, and get new one */
  1471.         window->visinfo.vis_list = new_list;
  1472.     }
  1473.  
  1474.     return;
  1475. }
  1476.  
  1477. static
  1478. same_area(a, b)
  1479. area    a, b;
  1480. {
  1481.     if (a.origin.x != b.origin.x || a.origin.y != b.origin.y)
  1482.         return FALSE;
  1483.     if (a.size.x != b.size.x || a.size.y != b.size.y)
  1484.         return FALSE;
  1485.     return TRUE;
  1486. }
  1487.  
  1488. /*****************************************************************************************/
  1489. /* INPUT ROUTINES */
  1490. /*****************************************************************************************/
  1491.  
  1492. /*
  1493.  * input_connect 
  1494.  *
  1495.  * Creates an input connection between the window system
  1496.  * and a client. This conection consists of an event queue 
  1497.  * used to queue input events. Queue is standard ring buffer. 
  1498.  */
  1499.  
  1500. long 
  1501. input_connect()
  1502. {
  1503.     event_queue    *queue;
  1504.  
  1505.     /* some checks first */
  1506.  
  1507.     if (display <= NULL)                /* not inited */
  1508.         return (sws_not_connected);
  1509.  
  1510.     /* create the event queue */
  1511.  
  1512.     queue =    (event_queue *)sws_malloc(sizeof (*queue));
  1513.     queue->in = 0;                    /* set in and out equal - i.e. queue empty */
  1514.     queue->out = 0;
  1515.  
  1516.     /* do system specific init */
  1517.  
  1518.     system_init_queue(queue);
  1519.  
  1520.     return ((long)queue);
  1521.  
  1522. }
  1523.  
  1524. /*****************************************************************************************/
  1525.  
  1526. /*
  1527.  * input_checks 
  1528.  * This routine returns the next event from the input queue 
  1529.  * if none is available it return null.
  1530.  *
  1531.  */
  1532.  
  1533. long
  1534. input_check(queue, event)
  1535. event_queue    *queue;
  1536. input_event    *event;
  1537. {
  1538.     /* some checks first */
  1539.  
  1540.     if (display <= NULL)                /* not inited */
  1541.         return (sws_not_connected);
  1542.  
  1543.     if (queue == NULL)                /* null qid */
  1544.         return (sws_bad_queue);
  1545.  
  1546.     /* if something in queue, get it */
  1547.  
  1548.     if (queue->in != queue->out) {
  1549.         *event = queue->buffer[queue->out];
  1550.         queue->out = (queue->out + 1) % BUFFER_SIZE;
  1551.         return (TRUE);
  1552.     }
  1553.     else 
  1554.         return (FALSE);
  1555. }
  1556.  
  1557. /*****************************************************************************************/
  1558.  
  1559. /*
  1560.  * input_wait returns the next event from the input queue 
  1561.  * if none is available this routine blocks until one is available
  1562.  *
  1563.  */
  1564.  
  1565. long 
  1566. input_wait(queue, event)
  1567. event_queue    *queue;
  1568. input_event    *event;
  1569. {
  1570.     long    result;
  1571.  
  1572.     /* if something in queue or error return it */
  1573.     /* else wait for something */
  1574.  
  1575.     while (TRUE) {
  1576.         if (result = input_check(queue, event))
  1577.             return (result);
  1578.  
  1579.         else
  1580.             system_wait(queue);
  1581.     }
  1582.  
  1583.     /* NOTREACHED */
  1584. }
  1585.  
  1586.  
  1587. /*****************************************************************************************/
  1588.  
  1589. /*
  1590.  * input select 
  1591.  * This routine is used by caller to specify which type
  1592.  * events the caller is interested in. They are is specified 
  1593.  * by an event mask. No events are ever given to a client
  1594.  * unless the client has asked for them.
  1595.  *
  1596.  * There two type of selects:
  1597.  * 
  1598.  *    Normal - caller specifies a wid, if the event occurs
  1599.  *    in that window, all clients who requested it 
  1600.  *    for that window get it - multiple routes!
  1601.  *
  1602.  *    Grab - caller specifies a NULL qid, the caller wants
  1603.  *    all such events whether or not the event occured
  1604.  *    in the window. 
  1605.  *
  1606.  * An event occurs in the window if the locator is in the window
  1607.  * or the event is window related, i.e. EXIT, ENTER, REFRESH.
  1608.  *
  1609.  */
  1610.  
  1611. long 
  1612. input_select(wid, queue, mask)
  1613. long        wid;
  1614. event_queue    *queue;
  1615. event_mask    mask;
  1616. {
  1617.     window_rec    *window;    /* window of interest */
  1618.     route_block    *route_rec;
  1619.     route_block    **last_rec;
  1620.  
  1621.     /* some checks first */
  1622.  
  1623.     if (display <= NULL)                    /* not inited */
  1624.         return (sws_not_connected);
  1625.  
  1626.     if (wid != 0) {
  1627.         if ((window = check_window(wid)) == NULL)    /* bad ID */
  1628.             return (sws_no_such_window);
  1629.  
  1630.         route_rec = window->inputinfo.erb;
  1631.         last_rec = &(window->inputinfo.erb);
  1632.     }
  1633.  
  1634.     else {
  1635.         /* no wid, it's a grab request */
  1636.  
  1637.         route_rec = display->grab_list;
  1638.         last_rec = &display->grab_list;
  1639.     }
  1640.  
  1641.     /* get ptr to first routing block and
  1642.      * see if we already have a mask for it 
  1643.      * if mask = 0, delete the entry
  1644.      */
  1645.  
  1646.     while (route_rec != NULL) {
  1647.         if (route_rec->queue = queue) {            /* found it */
  1648.             if (mask != 0)                /* store new mask */
  1649.                 route_rec->mask = mask;
  1650.  
  1651.             else {                    /* if NULL mask, delete entry */
  1652.                 if (route_rec->next != NULL)
  1653.                     route_rec->next->prev = route_rec->prev;
  1654.  
  1655.                 if (route_rec->prev != NULL)
  1656.                     route_rec->prev->next = route_rec->next;
  1657.  
  1658.                 sws_free(route_rec);
  1659.             }
  1660.  
  1661.             return (TRUE);
  1662.         }
  1663.  
  1664.         else {                        /* keep looking */
  1665.             last_rec = &route_rec;
  1666.             route_rec = route_rec->next;
  1667.         }
  1668.     }
  1669.  
  1670.     /* no entry for this queue, create one (unless mask == 0) */
  1671.  
  1672.     if (mask != 0) {
  1673.  
  1674.         /* get some memory */
  1675.  
  1676.         route_rec = (route_block *)sws_malloc(sizeof (*route_rec));
  1677.         route_rec->queue = queue;            /* store qid */
  1678.         route_rec->mask = mask;                /* current mask */
  1679.         route_rec->prev = *last_rec;            /* fix-up pointers */
  1680.         route_rec->next = NULL;                /* we are the end of list */
  1681.  
  1682.         if (route_rec->prev != NULL) 
  1683.             route_rec->prev->next = route_rec;
  1684.         else
  1685.             *last_rec = route_rec;
  1686.     }
  1687.  
  1688.     return (TRUE);
  1689. }
  1690.  
  1691. /*****************************************************************************************/
  1692.  
  1693. /*
  1694.  * input_process 
  1695.  * This routine takes an event from a client and processes it, i.e,
  1696.  * tries to route it. It is primarily used internally and by an
  1697.  * "input server process". It can be called by any client. 
  1698.  * 
  1699.  * If a wid is specified the event is routed directly to that
  1700.  * window, it cannot be "grabbed". If no wid is specified, 
  1701.  * the event is routed to the window containing the locator.
  1702.  *
  1703.  */
  1704.  
  1705. long 
  1706. input_process(wid, code, data)
  1707. long        wid;                /* route event to this window */
  1708. unsigned char    code;                /* event code */
  1709. point        data;                /* device specific data */
  1710. {
  1711.     void    position_locator();        /* some forward declarations */
  1712.     long    route_event();
  1713.  
  1714.     input_event    event;        /* event to be generated and routed */
  1715.     long        success;    /* boolean as to whether or not we've routed the event */
  1716.     window_rec    *window;    /* window of interest */
  1717.     event_mask    mask;        /* routing mask */
  1718.  
  1719.     if (display <= NULL)            /* not inited */
  1720.         return (sws_not_connected);
  1721.  
  1722.     /* check for device specific processing */
  1723.     /* in our case that's the locator */
  1724.  
  1725.     if (code == LOCATOR) 
  1726.         position_locator(data);        /* this routine will generate enter/exit events */
  1727.  
  1728.     /* check the wid and validate locator postion */
  1729.     /* if wid route to that window, if 0 use wid that locator is in */
  1730.  
  1731.     if (wid != 0) {
  1732.         if ((window = check_window(wid)) == NULL)    /* bad ID */
  1733.             return (sws_no_such_window);
  1734.  
  1735.         event.window = wid;                /* store the window ID */
  1736.     }
  1737.  
  1738.     else {                            /* no wid, use locator wid */
  1739.  
  1740.         /* bad locator wid */
  1741.  
  1742.         if ((window = check_window(display->locator_wid)) == NULL)
  1743.             position_locator(display->locator_pos);        /* fix it */
  1744.  
  1745.         event.window = display->locator_wid;
  1746.     }
  1747.  
  1748.     /* now generate an event record and route it to all who want it */
  1749.  
  1750.     gettimeofday(&event.tmstamp, NULL);        /* get timestamp */
  1751.     event.code = code;                /* store code */
  1752.     success = FALSE;                /* we haven't routed yet */
  1753.     mask = 0;                    /* force mask generation */
  1754.  
  1755.     /* if no wid initially specified, check grab list */
  1756.  
  1757.     if (wid == 0) {
  1758.         event.window = display->back_window;        /* for grabs use backgropund wid */
  1759.         event.position = display->locator_pos;        /* and abs position */
  1760.         success = route_event(display->grab_list, &event, &mask, FALSE);
  1761.     }
  1762.  
  1763.     /* if no grab, try window routing list */
  1764.  
  1765.     if (success == FALSE ) {
  1766.         window = check_window(event.window);        /* get window ptr */
  1767.  
  1768.         /* calculate relative position of locator in window */
  1769.  
  1770.         event.position.x = display->locator_pos.x - window->visinfo.warea.origin.x;
  1771.         event.position.y = display->locator_pos.y - window->visinfo.warea.origin.y;
  1772.         success = route_event(window->inputinfo.erb, &event, &mask, TRUE);
  1773.     }
  1774.  
  1775.     return (success);
  1776. }
  1777.  
  1778. /*****************************************************************************************/
  1779.  
  1780. /*
  1781.  * route_event 
  1782.  * This routine routes an event, using the specified routing list
  1783.  * It calculates and returns a mask for the event.
  1784.  * If multi_route is TRUE, the event is routed to multiple clients.
  1785.  *
  1786.  */
  1787.  
  1788. long 
  1789. route_event(list, event, mask, multi_route)
  1790. route_block    *list;
  1791. input_event    *event;
  1792. event_mask    *mask;
  1793. long        multi_route;
  1794. {
  1795.     route_block *route_rec;
  1796.     long        in;
  1797.     long        success;
  1798.  
  1799.     /* Generate a mask if necessary.
  1800.      * This is really cumbersome since we crammed 
  1801.      * all events into a single 32 bit mask. In the
  1802.      * real world we would have set up a cleaner relation.
  1803.      */
  1804.  
  1805.     if (*mask == 0)
  1806.         switch (event->code) {
  1807.         case LOCATOR:    *mask = LOCATOR_MASK;    break;
  1808.         case REFRESH:    *mask = REFRESH_MASK;    break;
  1809.         case ENTER:    *mask = ENTER_MASK;    break;
  1810.         case EXIT:    *mask = EXIT_MASK;    break;
  1811.         case LEFT:    *mask = LEFT_MASK;    break;
  1812.         case LEFT_UP:    *mask = LEFT_UP_MASK;    break;
  1813.         case MIDDLE:    *mask = MIDDLE_MASK;    break;
  1814.         case MIDDLE_UP:    *mask = MIDDLE_UP_MASK;    break;
  1815.         case RIGHT:    *mask = RIGHT_MASK;    break;
  1816.         case RIGHT_UP:    *mask = RIGHT_UP_MASK;    break;
  1817.         case F0:    *mask = F0_MASK;    break;
  1818.         case F0_UP:    *mask = F0_UP_MASK;    break;
  1819.         case F1:    *mask = F1_MASK;    break;
  1820.         case F1_UP:    *mask = F1_UP_MASK;    break;
  1821.         case F2:    *mask = F2_MASK;    break;
  1822.         case F2_UP:    *mask = F2_UP_MASK;    break;
  1823.         case F3:    *mask = F3_MASK;    break;
  1824.         case F3_UP:    *mask = F3_UP_MASK;    break;
  1825.         case F4:    *mask = F4_MASK;    break;
  1826.         case F4_UP:    *mask = F4_UP_MASK;    break;
  1827.         case F5:    *mask = F5_MASK;    break;
  1828.         case F5_UP:    *mask = F5_UP_MASK;    break;
  1829.         case F6:    *mask = F6_MASK;    break;
  1830.         case F6_UP:    *mask = F6_UP_MASK;    break;
  1831.         case F7:    *mask = F7_MASK;    break;
  1832.         case F7_UP:    *mask = F7_UP_MASK;    break;
  1833.         case F8:    *mask = F8_MASK;    break;
  1834.         case F8_UP:    *mask = F8_UP_MASK;    break;
  1835.         case F9:    *mask = F9_MASK;    break;
  1836.         case F9_UP:    *mask = F9_UP_MASK;    break;
  1837.         default:    *mask = KBD_MASK;    break;    /* event->code <= LAST_ASCII */
  1838.         }
  1839.  
  1840.     /* Try to route the event, look at each mask on the routing list. */
  1841.     /* Keep going until the list is exhausted unless no multiple routes */
  1842.     /* were specified. In that case exit on the first route */
  1843.  
  1844.     success = FALSE;
  1845.     route_rec = list;
  1846.  
  1847.     while (route_rec != NULL) {            /* look for a match */
  1848.         if (route_rec->mask & *mask) {        /* found one */
  1849.             in = (route_rec->queue->in + 1) % BUFFER_SIZE;    /* calc new in */
  1850.             if (in != route_rec->queue->out) {    /* check for overflow */
  1851.                 route_rec->queue->buffer[route_rec->queue->in] = *event;    /* there's room */
  1852.                 route_rec->queue->in = in;    /* advance the in */
  1853.                 system_adv(route_rec->queue);    /* wake up waiters */
  1854.                 success = TRUE;    /* successful route */
  1855.             }
  1856.         }
  1857.  
  1858.         if (success && (multi_route == FALSE)) 
  1859.             break;
  1860.  
  1861.         route_rec = route_rec->next;    /* go thru all routing blocks */
  1862.     }
  1863.  
  1864.     return (success);
  1865. }
  1866.  
  1867. /*****************************************************************************************/
  1868.  
  1869. /*
  1870.  * position_locator
  1871.  * This routine keeps track of the position of the locator.  It will generate
  1872.  * EXIT and ENTER EVENTS as the locator moves from window to window.
  1873.  *
  1874.  * It also moves the cursor pattern.
  1875.  */
  1876.  
  1877. void
  1878. position_locator(position)
  1879. point    position;
  1880. {
  1881.     long    new_wid;
  1882.  
  1883.     /* get wid of new position */
  1884.  
  1885.     new_wid = window_wid(position);
  1886.  
  1887.     if (display->locator_wid != new_wid) {        /* it's different */
  1888.         if (display->locator_wid != 0) 
  1889.             /* generate an exit event */
  1890.             input_process(display->locator_wid, EXIT);
  1891.  
  1892.         display->locator_pos = position;    /* new position */
  1893.         display->locator_wid = new_wid;    /* new wid */ 
  1894.  
  1895.         /* generate an enter event */
  1896.         input_process(display->locator_wid, ENTER);
  1897.     }
  1898.  
  1899.     else                        /* same wid, just new position */
  1900.         display->locator_pos = position;
  1901.  
  1902.  
  1903.     draw_cursor(position);                /* fix up the cursor */
  1904.  
  1905.     return;
  1906. }
  1907. /**** end  sws.c********/
  1908.  
  1909. /****start sis.c********/
  1910. /*
  1911.  * sis.c 
  1912.  * Simple Input Server 
  1913.  * for the Simple Window System
  1914.  *
  1915.  * Author: Daniel E. Ganek    
  1916.  * SIGGRAPH '87    
  1917.  *
  1918.  */
  1919.  
  1920. #include <stdio.h>
  1921. #include "sws_env.h"
  1922.  
  1923. main()
  1924. {
  1925.     long    bid;        /* background wid */
  1926.     char    code;        /* input code */
  1927.     point    data;        /* input data */
  1928.  
  1929.     /* Connect us to the SWS - we're probably the first ones */
  1930.  
  1931.     if ((bid = window_system_connect(0L)) <= NULL) 
  1932.         return (bid);
  1933.  
  1934.     /*
  1935.      * Just loop getting an input event from the system and    
  1936.      * processing it.  To convert this to a general purpose    
  1937.      * server replace "get_system_input" with a "get_event"    
  1938.      * routine and replace "input_process" with a switch    
  1939.      * statement to process either input events or client    
  1940.      * requests.
  1941.      */
  1942.  
  1943.     while (TRUE) {
  1944.         get_system_input(&code, &data);    /* get a system event */
  1945.         input_process(0, code, data);    /* give it to the SWS */
  1946.     }                    /* and let it route it */
  1947.  
  1948.     exit(0);
  1949. }
  1950. /**** end  sis.c********/
  1951.