home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / mw2 / mw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-03  |  36.0 KB  |  1,437 lines

  1. /*
  2.  * mw: use the window subroutines from uw for a MiNT window manager under AES.
  3.  *
  4.  * For testing w_output and such, define OTEST; this creates a program that
  5.  * just echoes keyboard input to the top window, with no MiNT-ness at all.
  6.  */
  7.  
  8. #define __OLD_WAY__    /* for evnt_multi() */
  9. #include <gemfast.h>
  10. #include <aesbind.h>
  11. #include <vdibind.h>
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <errno.h>
  16. #include <osbind.h>
  17. #include <linea.h>
  18.  
  19. #include "mw.h"        /* output from RCS for the resource file names */
  20. #include "mwdefs.h"    /* various definitions */
  21.  
  22. /* for MiNT */
  23. #include <mintbind.h>
  24. #include <signal.h>
  25.  
  26. #define INBUFSIZ 1024
  27.  
  28. int work_in[11];
  29. int work_out[57];
  30. int pxyarray[20];
  31. int msgbuff[8];
  32.  
  33. int phys_handle, screen_handle;
  34. int ncolors;        /* used by ESCb and ESCc */
  35.  
  36. /* evnt_multi data return spaces */
  37. long dummy;
  38. int sdummy;
  39. int key;
  40.  
  41. /*
  42.  * Character stuff (fonts, keymaps).
  43.  */
  44. FNT    *fnttbl[10];            /* List of pointers to fonts avail */
  45. int    fontsavail;            /* Number of fonts available */
  46. FNT    *tempfont;            /* font pointer */
  47. int    menu_key_map[0x100];        /* menu objects indexed by key map
  48.                        (alt key) read from object file */
  49. int fontmenuobj[] = {            /* array of font menu object numbers */
  50.     FNT8X8,
  51.     FNT8X16,
  52.     FNT6X7,
  53.     FNTOWN,
  54.     FNTALT,
  55.     FNTTNY,
  56.     FNTOTH,
  57.     /* Add new font menu items here! */
  58.     0
  59. };
  60.  
  61. OBJECT *menubar;    /* used in startup & finish */
  62.  
  63. char *caps_table;    /* keyboard table for caps-locked keys (sigh) */
  64.  
  65. /*
  66.  * globals imported by winsubr
  67.  */
  68.  
  69. struct wi_str *wlist;    /* a pointer into the window ring */
  70.  
  71. int scr_x, scr_y, scr_w, scr_h;        /* screen workxywh (?) */
  72. FNT *curfont;        /* ptr to current font (internal format(?)) */
  73. WIN_MFDB screen_mf;        /* mfdb for the screen */
  74. int mouse;        /* visibility flag for mouse */
  75. int audibell, visibell;        /* what to do on bell */
  76.  
  77. extern char *getmem();    /* in winsubr.c */
  78.  
  79. /*
  80.  * Resource file first/last objects in menu bar. These have to be the first
  81.  * & last (numerically) which are allowed to have hot-keys assigned to
  82.  * them.  "About ..." is a poor choice since the items after that in the
  83.  * resource are the space-holders for the accessories.  So you can't bind
  84.  * a key to About... So what?  Big deal.
  85.  */
  86.  
  87. #define FIRSTOBJ MENUEDIT
  88. #define LASTOBJ REFONT
  89.  
  90. /* read a font from a file */
  91. void
  92. loadfont (name)
  93. char *name;
  94. {
  95.   FNT * curfont;
  96.   char *tmpfnt;
  97.   char menustr[20];
  98.   char namestr[20];
  99.   int shift;
  100.   unsigned int mask;
  101.   int i;
  102.   char *getmem();
  103.  
  104.   if ((curfont = (FNT *) getmem((long)sizeof(FNT))) == NULL)
  105.     return;
  106.   i = Fopen(name, 0);
  107.   if (i<0) return;
  108.   (void)Fread(i, 2048L, curfont->f_data);
  109.   (void)Fclose(i);
  110.   curfont->inc_x = MINMAX(curfont->f_data[16], 1, 8);
  111.   curfont->inc_y = MINMAX(curfont->f_data[32], 1, 16);
  112.   curfont->nchars = 128;
  113.   shift = 8-curfont->inc_x;
  114.   mask = (1<<curfont->inc_x)-1;
  115.   tmpfnt = curfont->f_data;
  116.   for (i=0; i<2048; i++) {
  117.     *tmpfnt = (*tmpfnt>>shift)&mask;
  118.     tmpfnt++;
  119.   }
  120.   sscanf(name, "wind%3s", namestr);
  121.   sprintf(menustr, "%d x %d %s font", curfont->inc_x, curfont->inc_y,
  122.     namestr);
  123.   set_menu_string(menustr, fontmenuobj[fontsavail]);
  124.  
  125.   fnttbl[fontsavail] = curfont;
  126.   fontsavail++;
  127.   return;
  128. }
  129.  
  130. void
  131. startup()
  132. {
  133.     int i,j;
  134.     char *tmpfnt;
  135.  
  136.     /* start up everything: appl_init, menu, and the like */
  137.  
  138.     appl_init();
  139.     if (!rsrc_load("mw.rsc")) {
  140.       form_alert(1,"[1][Can't find resource file!][ Quit ]");
  141.       appl_exit();
  142.       exit(0);
  143.     }
  144.     rsrc_gaddr(R_TREE, MENUBAR, &menubar);
  145.  
  146.     /*
  147.      * Fill menu_key_map by scanning object strings for ALTINDICATOR.
  148.      */
  149.     for (i = FIRSTOBJ; i <= LASTOBJ; i++) {
  150.     if (menubar[i].ob_type == G_STRING) {
  151.         char * found;
  152.  
  153.         found = index((char *)menubar[i].ob_spec, ALTINDICATOR);
  154.         if (found != NULL) {
  155.         menu_key_map[*(++found)] = i;
  156.         }
  157.     }
  158.     }
  159.  
  160.     /*
  161.      * set caps_table to the base of the table mapping scan codes to
  162.      * ASCII codes when the CAPS-LOCK key is used.
  163.      */
  164.     caps_table = *(((char **)Keytbl(-1L,-1L,-1L))+2);
  165.  
  166.     menu_bar(menubar, 1);
  167.  
  168.     /* set mouse symbol to arrow */
  169.     graf_mouse(ARROW, NULL);
  170.     mouse = 1;
  171.  
  172.     /* get screen handle and sizes, open virtual workstation */
  173.     phys_handle = graf_handle(&sdummy, &sdummy, &sdummy, &sdummy);
  174.     wind_get(0, WF_WORKXYWH, &scr_x, &scr_y, &scr_w, &scr_h);
  175.     work_in[0] = Getrez() + 2;
  176.     for (i=1; i<10; work_in[i++]=1);
  177.     work_in[10] = 2;
  178.     screen_handle = phys_handle;
  179.     v_opnvwk(work_in, &screen_handle, work_out);
  180.     if (screen_handle == 0) {
  181.         /* out of handles */
  182.     form_alert(1,"[1][Sorry, VDI is out of|workstation handles.][ Quit ]");
  183.         appl_exit();
  184.         exit(1);
  185.     }
  186.  
  187.     /* set up screen mfdb.  Set 'ptr' to NULL and VDI does the rest. */
  188.  
  189.     screen_mf.ptr = NULL;
  190.     ncolors = work_out[13];
  191.  
  192.     /*
  193.      * now set up the system fonts
  194.      */
  195.     fontsavail = 0;
  196.     if ((curfont = (FNT *)getmem((long)sizeof(FNT))) != NULL) {
  197.     /* GCC specific */
  198.     (void)linea0();
  199.     tmpfnt = __fonts[1]->dat_table;    /* 8 x 8 system font */
  200.  
  201.     for (i=0; i<256; i++)
  202.         for (j=0; j<8; j++)
  203.         curfont->f_data[i*16+j] = tmpfnt[i+j*256];
  204.     curfont->inc_x = 8;
  205.     curfont->inc_y = 8;
  206.     curfont->nchars = 256;
  207.  
  208.     set_menu_string("8 x 8 sys font", fontmenuobj[fontsavail]);
  209.  
  210.     fnttbl[fontsavail] = curfont;
  211.     fontsavail++;
  212.     }
  213.  
  214.     if ((curfont = (FNT *)getmem((long)sizeof(FNT))) != NULL) {
  215.     /* GCC specific */
  216.     (void)linea0();
  217.     tmpfnt = __fonts[2]->dat_table;    /* 8 x 16 system font */
  218.  
  219.     for (i=0; i<256; i++)
  220.         for (j=0; j<16; j++)
  221.         curfont->f_data[i*16+j] = tmpfnt[i+j*256];
  222.     curfont->inc_x = 8;
  223.     curfont->inc_y = 16;
  224.     curfont->nchars = 256;
  225.  
  226.     set_menu_string("8 x 16 sys font", fontmenuobj[fontsavail]);
  227.  
  228.     fnttbl[fontsavail] = curfont;
  229.     fontsavail++;
  230.     }
  231.  
  232.     /* set up 6 x 6 system font */
  233.     if ((curfont = (FNT *)getmem((long)sizeof(FNT))) != NULL) {
  234.     /* GCC specific */
  235.     (void)linea0();
  236.     tmpfnt = __fonts[0]->dat_table;
  237.  
  238.     for (i=0; i<256; i++) {
  239.         int bitpos, index, offset;
  240.  
  241.         bitpos = i*6;
  242.         index = bitpos >> 3;
  243.         offset = bitpos & ~(~0<<3);
  244.         for (j=0; j<6; j++) /* for each pixel row in character */
  245.         curfont->f_data[i*16+j+1] = ((tmpfnt[index+j*192] << offset) +
  246.           (tmpfnt[index+j*192+1] >> (8-offset) & ~(~0<<offset)))>>2 & 63;
  247.         curfont->f_data[i*16+0] = 0; /* extra empty row */
  248.     }
  249.     curfont->inc_x = 6;
  250.     curfont->inc_y = 7;
  251.     curfont->nchars = 256;
  252.  
  253.     /*
  254.      * The 6x6 system font can be made better.  (dot the i and j.)
  255.      * This is a bad hack, but it makes it easier to read.
  256.      */
  257.     curfont->f_data[105*16+1] = 8;
  258.     curfont->f_data[105*16+2] = 0;
  259.     curfont->f_data[105*16+5] = 8;
  260.     curfont->f_data[106*16+5] = 20;
  261.     curfont->f_data[106*16+6] = 8;
  262.     curfont->f_data[106*16+2] = 0;
  263.  
  264.     set_menu_string("6 x 7 sys font", fontmenuobj[fontsavail]);
  265.     fnttbl[fontsavail] = curfont;
  266.     fontsavail++;
  267.     }
  268.  
  269.     /*
  270.      * Load font file(s) if any.
  271.      */
  272.  
  273.     loadfont("windstd.fnt");
  274.     loadfont("windalt.fnt");
  275.     loadfont("windtny.fnt");
  276.     loadfont("windoth.fnt");
  277.   
  278.     /*
  279.      * Disable unused font entries.
  280.      */
  281.     for (i = fontsavail; fontmenuobj[i] != 0; i++) {
  282.     set_menu_string("unavailable font", fontmenuobj[i]);
  283.     objc_change(menubar, fontmenuobj[i], 0, 0, 0, 0, 0, DISABLED, 0);
  284.     }
  285. }
  286.  
  287. void
  288. finish()
  289. {
  290.     /* close all windows and clean up */
  291.  
  292.     if (!mouse) graf_mouse(M_ON,NULL);
  293.  
  294.     while (wlist) {
  295. #ifndef OTEST
  296.       if (wlist->pid > 0)
  297.         (void)Pkill(-wlist->pid,SIGHUP);
  298. #endif
  299.     w_close(wlist);
  300.     }
  301.  
  302.     menu_bar(menubar, 0);
  303.     v_clsvwk(screen_handle);
  304.     appl_exit();
  305.     exit(0);
  306. }
  307.  
  308. #ifndef OTEST
  309. /* open a PTY, force a shell to it.  Fill in *pfd, *ppid, return 0 or errno */
  310.  
  311. int get_pipe(shell,pfd,ppid)
  312. char *shell;
  313. int *pfd;
  314. int *ppid;
  315. {
  316.     char pathbuf[80];
  317.     int i;
  318.     int masterfd, slavefd, pid;
  319.     int oldtty;
  320.  
  321.     /* sanity check: does the shell even exist */
  322.     if (!shell) return ENOENT;
  323.     if ((i = Fopen(shell,0)) < 0) return -i;
  324.     (void)Fclose(i);
  325.  
  326.     for (i = 0; i < 999; i++) {
  327.     sprintf(pathbuf,"q:\\pty.%03d",i);
  328.     masterfd = Fcreate(pathbuf, 0x04 | 0x02);
  329.     if (masterfd > 0) {
  330.         *pfd = masterfd;
  331.         goto gotpty;
  332.     }
  333.     }
  334.     return EMFILE;    /* no pty */
  335.  
  336. gotpty:
  337.     slavefd = Fopen(pathbuf,2);
  338.     if (slavefd < 0) {
  339.     (void)Fclose(masterfd);
  340.     return -slavefd;    /* can't open PTY twice(?!) */
  341.     }
  342.     if ((oldtty = Fdup(-1)) < 0) {
  343.     (void)Fclose(masterfd);
  344.     (void)Fclose(slavefd);
  345.     return -oldtty;        /* can't dup old controlling terminal */
  346.     }
  347.     (void)Fforce(-1,slavefd);
  348.     (void)Fforce(0,slavefd);
  349.     (void)Fforce(1,slavefd);
  350.     (void)Fforce(2,slavefd);
  351.     pid = Pexec(100,shell,"\0",0L);    /* might fail */
  352.     (void)Fforce(-1,oldtty);
  353.     (void)Fforce(0,oldtty);
  354.     (void)Fforce(1,oldtty);
  355.     (void)Fforce(2,oldtty);
  356.     (void)Fclose(slavefd);            /* close my copy */
  357.     (void)Fclose(oldtty);            /* close copy of tty */
  358.     *ppid = pid;
  359.     return (pid < 0 ? -pid : 0);    /* return 0 on success */
  360. }
  361. #endif
  362.  
  363. /* "fast" controls "window flourish" (grow/shrink boxes) */
  364. int fast = 1;
  365.  
  366. /*
  367.  * jerky_updates controls whether or not you get an update before each
  368.  * non-printing character in the output stream.  With it on things are
  369.  * faster; with it off, things are smoother.
  370.  */
  371. int jerky_updates = 1;
  372.  
  373. /*
  374.  * mouseflicker controls just that: with it ON, the mouse flickers, but
  375.  * it is almost always visible: it gets turned off before redraws and
  376.  * immediately turned on afterwards.  With it OFF, the mouse is turned
  377.  * off before a redraw, then left off until it moves (or you quit or close
  378.  * the last window).
  379.  */
  380. int mouseflicker = 1;
  381.  
  382. char alertbuf[40*4+3*9+3];
  383.  
  384. #ifdef ALARMTEST
  385. #define NALARMS 10
  386. static long alarmtimes[NALARMS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
  387. char *dotime(long);
  388. char *wkstr(long);
  389. #define Waketime(datime) trap_14_wl(47,datime)
  390. #define Shutdown() trap_14_w(65)
  391. int min_adder = 1;
  392. #endif
  393.  
  394. void
  395. main(argc,argv)
  396. int argc;
  397. char *argv[];
  398. {
  399.     int event;
  400.     int menuitem = 0;        /* Alt sequence mapped to menu item */
  401.     int cx, cy, cw, ch;        /* temps used for form_center */
  402.     int mx, my, mb, mk;        /* mouse coordinates from event_multi */
  403.     int buttonstate = 2;    /* button state to wait for next. */
  404.     int clicks;            /* number of clicks seen by evnt_multi. */
  405.     int cnt;
  406.     int tmp;
  407.     OBJECT *obj_tmp;
  408.     TEDINFO *ted_tmp;
  409.     struct wi_str *wp, *temp_wp;
  410.  
  411.     int sliders = 0;        /* set by menu items, arguments to w_open */
  412.     int titles = 1;
  413.     int xsiz, ysiz;
  414.     int last_x = 80, last_y = 50;  /* last size you asked for in SHELLOTH */
  415.  
  416.     /* MiNT stuff */
  417.     char *shell;        /* name of shell to start in new windows */
  418.     char cbuf[INBUFSIZ+1];
  419.     extern char *getenv();
  420.     int tempfd;
  421.     int temppid;
  422.     long readfds, reads;
  423.     long maxread;
  424.     int tmppid;
  425.     long err;
  426.  
  427.     audibell = 1;
  428.     visibell = 1;
  429.  
  430.     startup();
  431.  
  432.     /* initialize mouse flicker and flourish checkmarks to default values */
  433.     menu_icheck(menubar,MFAST, !fast);
  434.     menu_icheck(menubar,MSFLICKR, mouseflicker);
  435.     menu_icheck(menubar,JERKY, jerky_updates);
  436.     menu_icheck(menubar,AUDIBELL, audibell);
  437.     menu_icheck(menubar,VISIBELL, visibell);
  438.     menu_icheck(menubar,TITLES,titles);
  439.     menu_icheck(menubar,SLIDERS,sliders);
  440.     
  441.  
  442.     /* set curfont to the 8x8 system font and check that menu item */
  443.     curfont = fnttbl[0];
  444.     objc_change(menubar, FNT8X8, 0, 0, 0, 0, 0, CHECKED, 0);
  445.  
  446.     xsiz = 80;
  447.     ysiz = 25;
  448.  
  449.     /* find the name of our shell: the arg, or $SHELL, or MWINIT.PRG */
  450.  
  451.     if (argc > 1) shell = argv[1];
  452.     else {
  453.     shell = getenv("SHELL");
  454.     if (!shell) shell = "MWINIT.PRG";
  455.     }
  456.  
  457.     /* open the first window */
  458.     if (w_open(shell, 0, 0, xsiz, ysiz, sliders, titles, curfont)) {
  459.     /* can't open the window */
  460.     exit(0);
  461.     }
  462.  
  463. /* if get_pipe fails, finish will be called, and we don't want to kill MiNT! */
  464.     wlist->pid = 0;
  465.  
  466. #ifndef OTEST
  467.     /* open the first shell */
  468.     if ((err = get_pipe(shell,&tempfd,&temppid))) {
  469.     sprintf(alertbuf,"[1][Sorry, can't open your shell:|%s][ Quit ]",
  470.             strerror(err));
  471.     form_alert(1,alertbuf);
  472.     finish();
  473.     }
  474.  
  475.     /* associate the shell pid, the pipe, and the window */
  476.     wlist->fd = tempfd;
  477.     wlist->pid = temppid;
  478.  
  479.     readfds = (1L << tempfd);
  480. #endif
  481.  
  482.     for (;;) {
  483.     if (menuitem) {
  484.          /* 
  485.           * this fork is run when you have faked a menu item with an
  486.           * ALT key.  Wee fall through as if MU_MESAG / MN_SELECTED /
  487.           * menuitem came back from AES.
  488.           *
  489.           * We do not invert any menu titles; below, menu_tnormal
  490.           * will not be called because msgbuff[3] contains -1.
  491.           */
  492.         event = MU_MESAG;
  493.         msgbuff[0] = MN_SELECTED;
  494.         msgbuff[3] = -1;
  495.         msgbuff[4] = menuitem;
  496.         menuitem = 0;
  497.     }
  498.     else {
  499.         /* if mouseflicker is ON, "mouse" will never be false */
  500.         if (!mouse) {
  501.         if (!wlist) {
  502.             /* no windows -- show the mouse */
  503.             mouse = 1;
  504.             graf_mouse(M_ON,NULL);
  505.         }
  506.         else {
  507.             /* get the mouse location so we can wait for it to move */
  508.             graf_mkstate(&mx,&my,&sdummy,&sdummy);
  509.         }
  510.         }
  511.  
  512.         /* this is the main event */
  513.         event = MU_MESAG | MU_KEYBD | MU_TIMER | (mouse ? 0 : MU_M1);
  514.         *(long *)0x003ffffc = 0;
  515.         event = evnt_multi(event,
  516.         2, 2, buttonstate,
  517.         1, mx, my, 1, 1,
  518.         0, 0, 0, 0, 0,
  519.         msgbuff,
  520.         0, 0,    /* use "timer 0" mode */
  521.         &mx, &my, &mb, &mk,
  522.         &key, &clicks);
  523.         }
  524.  
  525. /*
  526.     if (event != MU_TIMER) {
  527.         sprintf(alertbuf,"\r\nEvent: %x (%s%s%s%s%s)\r\n",
  528.         event,
  529.         (event & MU_MESAG ? "MESAG " : ""),
  530.         (event & MU_KEYBD ? "KEYBD " : ""),
  531.         (event & MU_TIMER ? "TIMER " : ""),
  532.         (event & MU_BUTTON ? "BUTTON " : ""),
  533.         (event & MU_M1 ? "M1 " : ""));
  534.         w_output(wlist,alertbuf,strlen(alertbuf));
  535.     }
  536. */
  537.  
  538.     if (event & MU_M1) {
  539.             /* mouse was hidden and moved: show it */
  540.             mouse = 1;
  541.             graf_mouse(M_ON,NULL);
  542.     }
  543.  
  544.     if (event & MU_KEYBD) {
  545.         /*
  546.          * Write the key to the pipe of the current window, unless
  547.          * it's an ALT key that matches a menu item.
  548.          */
  549.  
  550.         unsigned char keyval = key & 0xff;
  551.         long keyindex = key >> 8;
  552.         long keywrite;
  553.  
  554.         if (keyval == 0 &&
  555.         (menuitem = menu_key_map[caps_table[keyindex]])) {
  556.             /* do nothing: setting menuitem is all that's needed. */
  557.         }
  558.         else {
  559.         if (wlist) {
  560.             keywrite = (keyindex << 16) | keyval;
  561. #ifndef OTEST
  562.             if (Foutstat(wlist->fd)) (void)Fputchar(wlist->fd,keywrite,0);
  563. #else
  564. #ifdef ALARMTEST
  565.             if (keyval == 0x14) {
  566.             long now = Gettime();
  567.             sprintf(alertbuf,"It's %s\r\n",dotime(now));
  568.             w_output(wlist,alertbuf,strlen(alertbuf));
  569.             }
  570.             else if (keyval >= '0' && keyval <= '9') {
  571.                 min_adder = keyval - '0';
  572.                 sprintf(alertbuf,"Adding %d minutes a pop\r\n",
  573.                                     min_adder);
  574.             w_output(wlist,alertbuf,strlen(alertbuf));
  575.             }
  576.             else
  577. #endif
  578.             w_output(wlist,(char *)&keyval,1);
  579. #endif
  580.             /* else ignore the key (process can't accept output) */
  581.         }
  582.         /* else there are no windows, thus nowhere to write to */
  583.         }
  584.         }
  585.  
  586. #ifndef OTEST
  587.     if (event == MU_TIMER) {
  588.         /*
  589.          * We get here only if the ONLY event was a timer event. Read
  590.          * from pipes; if nothing waiting, Syield(). (note: Fselect
  591.          * always does at least one Syield, or used to)
  592.          */
  593.  
  594.         reads = readfds;
  595.         if (!Fselect(1,&reads,0L,0L)) {
  596.         /* really no work to do at all */
  597.         }
  598.         else {
  599.         if (!wlist) {
  600.             form_alert(1,"[Bomb! Fselect but no windows!][ Ok ]");
  601.             finish();
  602.         }
  603.         wp = wlist;
  604.         do {
  605.             if (reads & (1L << wp->fd)) {
  606.             maxread = Finstat(wp->fd);
  607.             if (maxread > 0) {
  608.                 if (maxread > INBUFSIZ) maxread = INBUFSIZ;
  609.                 maxread = Fread(wp->fd, maxread, cbuf);
  610.                 w_output(wp,(unsigned char *)cbuf,(short)maxread);
  611.             }
  612.             else if (maxread < 0) {
  613.                 /* child exited */
  614.                 (void)Fclose(wp->fd);    /* expect it to work */
  615.                 (void)Pwait3(1,0L);    /* kill the zombie */
  616.                 readfds &= ~(1 << wp->fd);
  617.                 temp_wp = wp;
  618.                 wp = wp->prev;    /* goes to wp->next later */
  619.                 w_close(temp_wp);
  620.                 /* if we just nuked the last window, stop looping */
  621.                 if (!wlist) break;
  622.             }
  623.             else {
  624.                     /* fd maxread is zero (should never happen) */
  625.             }
  626.             }
  627.             wp = wp->next;
  628.         } while (wp != wlist);
  629.         }
  630.     }
  631. #else
  632. #ifdef ALARMTEST
  633.     /* if (event & MU_TIMER) */ {
  634.         int i;
  635.         long now;
  636.         long plus_some_minutes(long t);
  637.  
  638.         now = Gettime();
  639.         sprintf(alertbuf,"It's %s\r\n",dotime(now));
  640.         w_output(wlist,alertbuf,strlen(alertbuf));
  641.  
  642.         for (i=0; i<NALARMS; i++) {
  643.         if (alarmtimes[i] == -1) {
  644.             /* do nothing */
  645.         }
  646.         else if (alarmtimes[i] <= now) {
  647.             sprintf(alertbuf,"%d: %s alarm happened!\r\n",
  648.                     i,dotime(alarmtimes[i]));
  649.             w_output(wlist,alertbuf,strlen(alertbuf));
  650.             /* schedule this alarm for one minute from now */
  651.             alarmtimes[i] = plus_some_minutes(now);
  652.             Waketime(alarmtimes[i]);
  653.             check_ram();
  654.             Shutdown();
  655.                 }
  656.         else {
  657.             err = Waketime(alarmtimes[i]);
  658.         }
  659.         }
  660.         }
  661.         if ((event & MU_MESAG) &&
  662.         (msgbuff[0] == MN_SELECTED) &&
  663.         (msgbuff[4] == MALARM)) {
  664.             do_alarm();
  665.     }
  666. #endif
  667. #endif
  668.  
  669.     if (event & MU_MESAG) {
  670.         switch (msgbuff[0]) {
  671.         case MN_SELECTED:
  672.         switch (msgbuff[4]) {
  673.         case MENUEDIT:
  674.             do_editkeys();
  675.             break;
  676.         case WINRESIZ:
  677.             if (!wlist) break;
  678.             xsiz = wlist->x_chrs;
  679.             ysiz = wlist->y_chrs;
  680.             if (!size_dial(&xsiz,&ysiz)) break;
  681.             tmppid = wlist->pid;
  682.             if (w_resize(wlist, xsiz, ysiz, 
  683.             wlist->sliders, wlist->titles, 0)) {
  684.                 /* lost the window! Do what we can... */
  685. #ifndef OTEST
  686.                 (void)Pkill(tmppid,SIGHUP);
  687. #endif
  688.             }
  689.             break;
  690.  
  691.         /* "refont" -- reopen the window in the selected font */
  692.         case REFONT:
  693.             if (!wlist) break;
  694.             tmppid = wlist->pid;
  695.             if (w_resize(wlist, wlist->x_chrs, wlist->y_chrs,
  696.             wlist->sliders, wlist->titles, 1)) {
  697.                 /* lost the window! Do what we can... */
  698. #ifndef OTEST
  699.                 (void)Pkill(tmppid,SIGHUP);
  700. #endif
  701.             }
  702.             break;
  703.  
  704.         case FQUIT:
  705.             finish();
  706.  
  707.         case DABOUT:
  708.             s_dial(ABOUT, 3);
  709.             break;
  710.  
  711.         case WRENAME:
  712.             if (!wlist) break;    /* no window to rename */
  713.             rsrc_gaddr(R_TREE, NEWNAME, &obj_tmp);
  714.             ted_tmp = (TEDINFO *) obj_tmp[FLD1].ob_spec;
  715.             strcpy(ted_tmp->te_ptext, wlist->name);
  716.             form_center(obj_tmp, &cx, &cy, &cw, &ch);
  717.             form_dial(FMD_START, 0, 0, 20, 10, cx, cy, cw, ch);
  718.             if (!fast)
  719.             form_dial(FMD_GROW, 0, 0, 20, 10, cx, cy, cw, ch);
  720.             objc_draw(obj_tmp, 0, 5, cx, cy, cw, ch);
  721.             tmp = form_do(obj_tmp, FLD1);
  722.             if (!fast)
  723.             form_dial(FMD_SHRINK, 0, 0, 20, 10, cx, cy, cw, ch);
  724.             form_dial(FMD_FINISH, 0, 0, 20, 10, cx, cy, cw, ch);
  725.             objc_change(obj_tmp, tmp, 0, cx, cy, cw, ch, NONE, 0);
  726.             if (tmp == OKRENAME)
  727.             w_rename(wlist, (char *) ted_tmp->te_ptext);
  728.             break;
  729.  
  730.         case JERKY:
  731.             jerky_updates = !jerky_updates;
  732.             menu_icheck(menubar,JERKY, jerky_updates);
  733.             break;
  734.  
  735.         case MSFLICKR:
  736.             mouseflicker = !mouseflicker;
  737.             menu_icheck(menubar,MSFLICKR, mouseflicker);
  738.             break;
  739.  
  740.         case MFAST:
  741.             menu_icheck(menubar, MFAST, fast);
  742.             fast = !fast;
  743.             break;
  744.  
  745.         case FNT8X8:
  746.         case FNT8X16:
  747.         case FNT6X7:
  748.         case FNTOWN:
  749.         case FNTALT:
  750.         case FNTTNY:
  751.         case FNTOTH:
  752.         /* Add new font menu items here! */
  753.             for (cnt = 0; fontmenuobj[cnt] != 0; cnt++) {
  754.             if (fontmenuobj[cnt] != msgbuff[4]) {
  755.                 /* un-check any font that isn't the new one */
  756.                 objc_change(menubar, fontmenuobj[cnt],
  757.                 0, 0, 0, 0, 0, NONE, 0);
  758.             }
  759.             else {
  760.                 /* this is the new font: set it & checkmark it */
  761.                 curfont = fnttbl[cnt];
  762.                 objc_change(menubar, msgbuff[4],
  763.                 0, 0, 0, 0, 0, CHECKED, 0);
  764.             }
  765.             }
  766.             break;
  767.  
  768.         case AUDIBELL:
  769.             audibell = !audibell;
  770.             objc_change(menubar, AUDIBELL, 0, 0, 0, 0, 0,
  771.             audibell? CHECKED: 0, 0);
  772.             break;
  773.  
  774.         case VISIBELL:
  775.             visibell = !visibell;
  776.             objc_change(menubar, VISIBELL, 0, 0, 0, 0, 0,
  777.             visibell? CHECKED: 0, 0);
  778.         break;
  779.  
  780.         case SHRNKWIN:    /* Shrink window to iconic size */
  781.             if (wlist) {
  782.             w_shrink(wlist);
  783.                     }
  784.                     break;
  785.  
  786.         case BOTTOMTO:    /* send bottom window to top */
  787.             w_bottom();
  788.             break;
  789.  
  790.         case HIDEWIN:    /* send top window to bottom */
  791.             w_hide();
  792.             break;
  793.  
  794.         case OSIZEWIN:
  795.             if (wlist) {
  796.             w_full(wlist);
  797.             }
  798.             break;
  799.  
  800.         case SLIDERS:    /* toggle sliders for new windows */
  801.             sliders = !sliders;
  802.             menu_icheck(menubar, SLIDERS, sliders);
  803.             break;
  804.  
  805.         case TITLES:    /* enable/disable window headers */
  806.             titles = !titles;
  807.             menu_icheck(menubar, TITLES, titles);
  808.             break;
  809.  
  810.         case SETGADG: {        /* set gadgets based on settings */
  811.             tmppid = wlist->pid;
  812.             if (w_resize(wlist, wlist->x_chrs, wlist->y_chrs,
  813.             sliders, titles, 0)) {
  814.                 /* list the window! */
  815. #ifndef OTEST
  816.                 (void)Pkill(tmppid,SIGHUP);
  817. #endif
  818.             }
  819.             /* make this the "main" style for this window */
  820.             wlist->wi_mainstyle = wlist->wi_style;
  821.             break;
  822.         }
  823.  
  824.         case GADGETS: {        /* toggle gadgets for this window */
  825.             int tmpslide, tmptitle;
  826.  
  827.             if (!wlist) break;
  828.             /*
  829.              * If your original ("main") style includes all sliders,
  830.              * this toggles between all and nothing.  Otherwise,
  831.              * it toggles between your "main" style and everything.
  832.              */
  833.             if (wlist->wi_mainstyle == (WI_WITHSLD|WI_WITHTITLE)) {
  834.                 /* main style is full style */
  835.                 if (wlist->wi_style == wlist->wi_mainstyle) {
  836.                     /* already all, so make it none */
  837.                     tmpslide = 0;
  838.                     tmptitle = 0;
  839.                 }
  840.                 else {
  841.                     tmpslide = 1;
  842.                     tmptitle = 1;
  843.                 }
  844.             }
  845.             else if (wlist->wi_style != wlist->wi_mainstyle) {
  846.             /* reset back to mainstyle */
  847.             tmpslide = (wlist->wi_mainstyle & WI_WITHSLD);
  848.             tmptitle = (wlist->wi_mainstyle & WI_WITHTITLE);
  849.             }
  850.             else {
  851.             /* add sliders and title bar */
  852.             tmpslide = 1;
  853.             tmptitle = 1;
  854.             }
  855.             tmppid = wlist->pid;
  856.             if (w_resize(wlist, wlist->x_chrs, wlist->y_chrs,
  857.                 tmpslide, tmptitle, 0)) {
  858.                 /* lost the window! Do what we can... */
  859. #ifndef OTEST
  860.                 (void)Pkill(tmppid,SIGHUP);
  861. #endif
  862.             }
  863.             break;
  864.             }
  865.  
  866.         case CLOSE:
  867.             if (!wlist) break;
  868. #ifndef OTEST
  869.             (void)Pkill(-wlist->pid,SIGHUP);
  870. #endif
  871.             break;
  872.  
  873.         case SETOTHER:    /* set the "other" size */
  874.             size_dial(&last_x,&last_y);
  875.             break;
  876.  
  877.         case NEWWIND:    /* new window 25x80*/
  878.         case NEWOTHER:    /* new other */
  879.             if (msgbuff[4] == NEWWIND) {
  880.             /* default window size */
  881.             xsiz = 80;
  882.             ysiz = 25;
  883.             }
  884.             else if (msgbuff[4] == NEWOTHER) {
  885.             xsiz = last_x;
  886.             ysiz = last_y;
  887.             }
  888.             if (!w_open(shell, 0, 0, xsiz, ysiz, 
  889.             sliders, titles, curfont)) {
  890.                 /* create a shell and a pipe */
  891. #ifndef OTEST
  892.                 if ((err = get_pipe(shell,&tempfd,&temppid))) {
  893.                     sprintf(alertbuf,
  894.                         "[1][ Sorry, can't open your shell: |"
  895.                     " %s ][ Cancel ]",strerror(err));
  896.                 form_alert(1,alertbuf);
  897.                 w_close(wlist);
  898.                 }
  899.                 else {
  900.                 wlist->fd = tempfd;
  901.                 wlist->pid = temppid;
  902.                 readfds |= (1L << tempfd);
  903.                         }
  904. #endif
  905.                 }
  906.             break;
  907.             }
  908.         if (msgbuff[3] != -1) menu_tnormal(menubar, msgbuff[3], 1);
  909.         break;
  910.  
  911.         case WM_NEWTOP:
  912.             /* one of my windows is newly the top window */
  913.             /* I don't happen to care... Do I? */
  914.         break;
  915.  
  916.         case WM_TOPPED:
  917.         if (!wlist) break;
  918.         wp = wlist;
  919.         do {
  920.             if (wp->aes_handle == msgbuff[3]) {
  921.             w_top(wp);
  922.             break;
  923.             }
  924.             wp = wp->next;
  925.         } while (wp != wlist);
  926.         break;
  927.  
  928.         case WM_SIZED:
  929.         case WM_MOVED:
  930.         if (!wlist) break;
  931.         wp = wlist;
  932.         do {
  933.             if (wp->aes_handle == msgbuff[3]) {
  934.             w_move(wp, msgbuff[4], msgbuff[5], msgbuff[6], msgbuff[7]);
  935.             break;
  936.             }
  937.             wp = wp->next;
  938.         } while (wp != wlist);
  939.         break;
  940.  
  941.         case WM_CLOSED:
  942.         /* kill the process; the window will close when he's dead */
  943.         if (!wlist) break;
  944.         wp = wlist;
  945.         do {
  946.             if (wp->aes_handle == msgbuff[3]) {
  947. #ifndef OTEST
  948.             (void)Pkill(-wp->pid,SIGHUP);
  949. #endif
  950.             break;
  951.             }
  952.             wp = wp->next;
  953.         } while (wp != wlist);
  954.         break;
  955.  
  956.         case WM_REDRAW: {
  957.         if (!wlist) break;
  958.         wp = wlist;
  959.         do {
  960.             if (wp->aes_handle == msgbuff[3]) {
  961.             w_redraw(wp,FM_COPY, msgbuff[4], msgbuff[5],
  962.                          msgbuff[6], msgbuff[7]);
  963.             break;
  964.             }
  965.             wp = wp->next;
  966.         } while (wp != wlist);
  967.         break;
  968.         }
  969.  
  970.         case WM_FULLED:
  971.         if (!wlist) break;
  972.         wp = wlist;
  973.         do {
  974.             if (wp->aes_handle == msgbuff[3]) {
  975.             w_full(wp);
  976.             break;
  977.             }
  978.             wp = wp->next;
  979.         } while (wp != wlist);
  980.         break;
  981.  
  982.         case WM_ARROWED:
  983.         if (!wlist) break;
  984.         wp = wlist;
  985.         do {
  986.             if (wp->aes_handle == msgbuff[3]) {
  987.             w_arrow(wp,msgbuff[4]);
  988.             break;
  989.             }
  990.             wp = wp->next;
  991.         } while (wp != wlist);
  992.         break;
  993.  
  994.         case WM_HSLID:
  995.         case WM_VSLID:
  996.         if (!wlist) break;
  997.         wp = wlist;
  998.         do {
  999.             if (wp->aes_handle == msgbuff[3]) {
  1000.             w_slide(wp, msgbuff[0] == WM_HSLID, msgbuff[4]);
  1001.             break;
  1002.             }
  1003.             wp = wp->next;
  1004.         } while (wp != wlist);
  1005.         break;
  1006.         }
  1007.         }
  1008.     }
  1009. }
  1010.  
  1011. /*
  1012.  * s_dial performs a simple dialog with buttons and text only.
  1013.  * The index of the terminating button is returned.
  1014.  * If action == 1, the dialog is displayed.  If action == 2, it is
  1015.  * removed.  If action == 3, both operations are done and form_do is
  1016.  * called.
  1017.  */
  1018. int s_dial(tree, action)
  1019. int tree, action;
  1020. {
  1021.     int tmp = 0;
  1022.     int cx, cy, cw, ch;
  1023.     OBJECT *obj_tmp;
  1024.  
  1025.     rsrc_gaddr(R_TREE, tree, &obj_tmp);
  1026.     form_center(obj_tmp, &cx, &cy, &cw, &ch);
  1027.     if (action & 1) {
  1028.     form_dial(FMD_START, 0, 0, 20, 10, cx, cy, cw, ch);
  1029.     if (!fast) form_dial(FMD_GROW, 0, 0, 20, 10, cx, cy, cw, ch);
  1030.     objc_draw(obj_tmp, 0, 5, cx, cy, cw, ch);
  1031.     }
  1032.     if (action == 3) {
  1033.     tmp = form_do(obj_tmp, 0);
  1034.     }
  1035.     if (action & 2) {
  1036.     if (!fast) form_dial(FMD_SHRINK, 0, 0, 20, 10, cx, cy, cw, ch);
  1037.     form_dial(FMD_FINISH, 0, 0, 20, 10, cx, cy, cw, ch);
  1038.     objc_change(obj_tmp, tmp, 0, cx, cy, cw, ch, NONE, 0);
  1039.     }
  1040.     return (tmp);
  1041. }
  1042.  
  1043. /*
  1044.  * set_menu_string sets the menu string for the specified menu object to
  1045.  * newstr.
  1046.  */
  1047. void
  1048. set_menu_string(newstr, object)
  1049. register char * newstr;
  1050. int object;
  1051. {
  1052.     register char * oldstr;
  1053.  
  1054.     oldstr = (char *) menubar[object].ob_spec + 2;
  1055.     while (*oldstr && *newstr)
  1056.     *oldstr++ = *newstr++;
  1057.     if (*oldstr)
  1058.     *oldstr = ' ';
  1059. }
  1060.  
  1061. int
  1062. size_dial(pxsiz,pysiz)
  1063. int *pxsiz;
  1064. int *pysiz;
  1065. {
  1066.     /*
  1067.      * Enter rows and columns dialog
  1068.      */
  1069.     int cx, cy, cw, ch;
  1070.     int xsiz = *pxsiz;
  1071.     int ysiz = *pysiz;
  1072.     char *rowstr, *colstr;
  1073.     int tmp;
  1074.     OBJECT *obj_tmp;
  1075.     TEDINFO *ted_tmp;
  1076.  
  1077.     /* show the mouse if it's hidden */
  1078.     /* if mouseflicker is ON, "mouse" will never be false. */
  1079.     if (!mouse) {
  1080.     mouse = 1;
  1081.     graf_mouse(M_ON,NULL);
  1082.     }
  1083.  
  1084.     rsrc_gaddr(R_TREE, WINDSIZE, &obj_tmp);
  1085.     ted_tmp = (TEDINFO *) obj_tmp[WINDROWS].ob_spec;
  1086.     rowstr = ((char *)ted_tmp->te_ptext);
  1087.     if (ysiz < 2) ysiz = 2;
  1088.     if (xsiz < 2) xsiz = 2;
  1089.     if (ysiz > 99) ysiz = 99;
  1090.     if (xsiz > 300) xsiz = 300;
  1091.     ted_tmp = (TEDINFO *) obj_tmp[WINDCOLS].ob_spec;
  1092.     colstr = ((char *)ted_tmp->te_ptext);
  1093.     sprintf(rowstr,"%02d",ysiz);
  1094.     sprintf(colstr,"%03d",xsiz);
  1095.  
  1096.     form_center(obj_tmp, &cx, &cy, &cw, &ch);
  1097.     form_dial(FMD_START, 0, 0, 20, 10, cx, cy, cw, ch);
  1098.     if (!fast)
  1099.         form_dial(FMD_GROW, 0, 0, 20, 10, cx, cy, cw, ch);
  1100.     objc_draw(obj_tmp, 0, 5, cx, cy, cw, ch);
  1101.     tmp = form_do(obj_tmp, WINDROWS);
  1102.     if (!fast)
  1103.         form_dial(FMD_SHRINK, 0, 0, 20, 10, cx, cy, cw, ch);
  1104.     form_dial(FMD_FINISH, 0, 0, 20, 10, cx, cy, cw, ch);
  1105.     objc_change(obj_tmp, tmp, 0, cx, cy, cw, ch, NONE, 0);
  1106.     if (tmp == WINDCANC)
  1107.         return(FALSE);
  1108.     xsiz = xatoi(colstr);
  1109.     ysiz = xatoi(rowstr);
  1110.     if (xsiz < 10)
  1111.         xsiz = 10;
  1112.     if (xsiz > 300)
  1113.         xsiz = 300;
  1114.     if (ysiz < 2)
  1115.         ysiz = 2;
  1116.     if (ysiz > 99)
  1117.         ysiz = 99;
  1118.     *pxsiz = xsiz;
  1119.     *pysiz = ysiz;
  1120.     return (TRUE);
  1121. }
  1122.  
  1123. int
  1124. xatoi(s)
  1125. char *s;
  1126. {
  1127.     int result = 0;
  1128.     char c;
  1129.  
  1130.     while (c = *s++) {
  1131.     if (c >= '0' && c <= '9') {
  1132.         result *= 10;
  1133.         result += (c - '0');
  1134.     }
  1135.     else return result;
  1136.     }
  1137.     return result;
  1138. }
  1139.  
  1140. void
  1141. do_editkeys()
  1142. {
  1143.     /*
  1144.      * Enter function-key-edit dialog
  1145.      */
  1146.     int cx, cy, cw, ch;
  1147.     char *namestr, *keystr;
  1148.     int tmp;
  1149.     OBJECT *obj_tmp;
  1150.     TEDINFO *ted_tmp;
  1151.     int cycle, direction;
  1152.     char *found;
  1153.  
  1154.     /* show the mouse if it's hidden */
  1155.     /* if mouseflicker is ON, "mouse" will never be false. */
  1156.     if (!mouse) {
  1157.     mouse = 1;
  1158.     graf_mouse(M_ON,NULL);
  1159.     }
  1160.  
  1161.     rsrc_gaddr(R_TREE, EDITKEYS, &obj_tmp);
  1162.     ted_tmp = (TEDINFO *) obj_tmp[ITEMNAME].ob_spec;
  1163.     namestr = ((char *)ted_tmp->te_ptext);
  1164.     ted_tmp = (TEDINFO *) obj_tmp[ITEMKEY].ob_spec;
  1165.     keystr = ((char *)ted_tmp->te_ptext);
  1166.  
  1167.     for (cycle = FIRSTOBJ; cycle <= LASTOBJ; cycle++) {
  1168.     /* if it's a string & it doesn't start with dash... */
  1169.     if (menubar[cycle].ob_type == G_STRING &&
  1170.         *(char *)menubar[cycle].ob_spec != '-')
  1171.         break;
  1172.     }
  1173.     if (cycle > LASTOBJ) return;        /* no strings in the menu?! */
  1174.     strncpy(namestr,(char *)menubar[cycle].ob_spec,20);
  1175.     if (found = index((char *)menubar[cycle].ob_spec, ALTINDICATOR)) {
  1176.     *keystr = *(found+1);
  1177.     }
  1178.     else *keystr = ' ';
  1179.  
  1180.     form_center(obj_tmp, &cx, &cy, &cw, &ch);
  1181.     form_dial(FMD_START, 0, 0, 20, 10, cx, cy, cw, ch);
  1182.     if (!fast)
  1183.         form_dial(FMD_GROW, 0, 0, 20, 10, cx, cy, cw, ch);
  1184.     objc_draw(obj_tmp, 0, 5, cx, cy, cw, ch);
  1185.     while (1) {
  1186.         /* tmp comes back with hi bit set to indicate double-clicks */
  1187.     tmp = (form_do(obj_tmp, ITEMKEY) & 0x7fff);
  1188.  
  1189.     /* (do this regardless of what button you used to get out) */
  1190.     /* see if you changed the one you were looking at */
  1191.     if (found && *(found+1) != *keystr) {
  1192.         /* Had a def'n and you changed it. */
  1193.         /* un-set the old meaning */
  1194.         menu_key_map[*(found+1)] = 0;
  1195.         if (!*keystr || *keystr == ' ') {
  1196.         /* changed to nothing */
  1197.         *found = ' ';
  1198.         *(found+1) = ' ';
  1199.         }
  1200.         else {
  1201.         /* changed to something */
  1202.         *(found+1) = *keystr;
  1203.         menu_key_map[*keystr] = cycle;
  1204.         }
  1205.     }
  1206.     else if (!found && *keystr && *keystr != ' ') {
  1207.         /* didn't have a def'n and you gave one */
  1208.         menu_key_map[*keystr] = cycle;
  1209.         for (found = (char *)menubar[cycle].ob_spec; *found; found++) ;
  1210.         *(--found) = *keystr;
  1211.         *(--found) = ALTINDICATOR;
  1212.     }
  1213.     /* else you didn't change it */
  1214.  
  1215.     if (tmp != ITEMOK) {
  1216.         direction = (tmp == ITEMNEXT ? 1 : -1);
  1217.         for (cycle += direction;
  1218.          cycle <= LASTOBJ && cycle >= FIRSTOBJ;
  1219.          cycle += direction) {
  1220.             if (menubar[cycle].ob_type == G_STRING &&
  1221.             *(char *)menubar[cycle].ob_spec != '-')
  1222.                 break;
  1223.         }
  1224.         if (cycle > LASTOBJ) cycle = FIRSTOBJ;
  1225.         else if (cycle < FIRSTOBJ) cycle = LASTOBJ;
  1226.  
  1227.         strncpy(namestr,(char *)menubar[cycle].ob_spec,20);
  1228.         if (found = index((char *)menubar[cycle].ob_spec, ALTINDICATOR)) {
  1229.         *keystr = *(found+1);
  1230.         }
  1231.         else *keystr = ' ';
  1232.  
  1233.         /* de-select the "next" button, redraw */
  1234.         /* should clip the redraw to the parts that matter */
  1235.         objc_change(obj_tmp,ITEMNEXT,0,cx,cy,cw,ch,NORMAL,0);
  1236.         objc_draw(obj_tmp,0,5,cx,cy,cw,ch);
  1237.     }
  1238.     else break;
  1239.     }
  1240.     if (!fast)
  1241.         form_dial(FMD_SHRINK, 0, 0, 20, 10, cx, cy, cw, ch);
  1242.     form_dial(FMD_FINISH, 0, 0, 20, 10, cx, cy, cw, ch);
  1243.     objc_change(obj_tmp, tmp, 0, cx, cy, cw, ch, NONE, 0);
  1244.     return;
  1245. }
  1246.  
  1247. #ifdef ALARMTEST
  1248.  
  1249. check_ram()
  1250. {
  1251.     static unsigned long *buf = 0;
  1252.     static long size;
  1253.     static int num_errors = 0;
  1254.     unsigned long i;
  1255.  
  1256.     if (!buf) {
  1257.         size = (Malloc(-1L)/4) *4;
  1258.         buf = (unsigned long *)Malloc(size);
  1259.         for (i=0; i<(size/4); i++) buf[i] = i;
  1260.     }
  1261.     else {
  1262.         for (i=0; i<(size/4); i++) {
  1263.             if (buf[i] != i) {
  1264.                 num_errors++;
  1265.                 /* re-init the buffer */
  1266.                 for (i=0; i<(size/4); i++) buf[i] = i;
  1267.                 break;
  1268.             }
  1269.         }
  1270.         sprintf(alertbuf,"%d errors so far\r\n",num_errors);
  1271.         w_output(wlist,alertbuf,strlen(alertbuf));
  1272.     }
  1273. }
  1274.  
  1275. char *wkstrs[] = { 
  1276.     "You won", "In the past", "You don't win", "Time zeroed as you asked",
  1277.     "First of that month", "This time tomorrow"
  1278. };
  1279.  
  1280. char *wkstr(long v)
  1281. {
  1282.     if (v < 0 || v > 4) return "Unknown";
  1283.     else return wkstrs[v];
  1284. }
  1285.  
  1286. /*
  1287.  * advance a time by one minute.  BUT - don't include seconds.
  1288.  * Since we aren't including seconds, we round the input to the
  1289.  * NEAREST minute (not just rounding down).
  1290.  */
  1291.  
  1292. long plus_some_minutes(long t)
  1293. {
  1294.     long month = ((t >> 21) & 0xf);
  1295.     long day = ((t >> 16) & 0x1f);
  1296.     long year = ((t >> 25) & 0x7f);
  1297.     long hour = ((t >> 11) & 0x1f);
  1298.     long minute = ((t >> 5) & 0x3f);
  1299.     long second = ((t & 0x1f) << 1);
  1300.  
  1301.     if (second >= 30) minute += 1;
  1302.     second = 0;
  1303.     minute += min_adder;
  1304.     if (minute >= 60) {
  1305.         minute -= 60;
  1306.         hour += 1;
  1307.         if (hour >= 24) {
  1308.         hour -= 24;
  1309.         day += 1;
  1310.         }
  1311.     }
  1312.     return ((year << 25) | (month << 21) | (day << 16) |
  1313.         (hour << 11) | (minute << 5) | (second >> 1));
  1314. }
  1315.  
  1316. /*
  1317.  * return a printable string for a datime value
  1318.  */
  1319.  
  1320. char *dotime(long t)
  1321. {
  1322.     static char tbuf[18];
  1323.  
  1324.     sprintf(tbuf,"%02ld/%02ld/%02ld %02ld:%02ld:%02ld",
  1325.     ((t >> 21) & 0xf),
  1326.     ((t >> 16) & 0x1f),
  1327.     ((t >> 25) & 0x7f) + 80,
  1328.     ((t >> 11) & 0x1f),
  1329.     ((t >> 5) & 0x3f),
  1330.     ((t & 0x1f) << 1));
  1331. /*
  1332.     sprintf(alertbuf,"dotime(%lx) -> %s\r\n",t,tbuf);
  1333.     w_output(wlist,alertbuf,strlen(alertbuf));
  1334. */
  1335.     return tbuf;
  1336. }
  1337.  
  1338. long untime(char *s)
  1339. {
  1340.     long year, month, day, hour, minute, second;
  1341.     long t;
  1342.  
  1343. #define twodigits(s) (((*(s) - '0') * 10) + (*((s)+1) - '0'))
  1344.  
  1345.     month = twodigits(s);
  1346.     day = twodigits(s+2);
  1347.     year = twodigits(s+4) - 80;
  1348.     hour = twodigits(s+6);
  1349.     minute = twodigits(s+8);
  1350.     second = twodigits(s+10);
  1351.  
  1352.     t = (year << 25) | (month << 21) | (day << 16) |
  1353.         (hour << 11) | (minute << 5) | (second >> 1);
  1354. /*
  1355.     sprintf(alertbuf,"untime %s -> %lx\r\n",s,t);
  1356.     w_output(wlist,alertbuf,strlen(alertbuf));
  1357. */
  1358.     return t;
  1359. }
  1360.  
  1361. /*
  1362.  * do the alarm dialog box
  1363.  */
  1364.  
  1365. do_alarm()
  1366. {
  1367.     int cx, cy, cw, ch;
  1368.     OBJECT *obj_tmp;
  1369.     TEDINFO *ted_tmp;
  1370.     char *alstr, *numstr;
  1371.     int cycle;
  1372.     int tmp;
  1373.     int direction;
  1374.  
  1375.  
  1376.     if (!mouse) {
  1377.     mouse = 1;
  1378.     graf_mouse(M_ON, NULL);
  1379.     }
  1380.  
  1381.     rsrc_gaddr(R_TREE, TALARM, &obj_tmp);
  1382.     ted_tmp = (TEDINFO *) obj_tmp[ALRMTIME].ob_spec;
  1383.     alstr = ((char *)ted_tmp->te_ptext);
  1384.     ted_tmp = (TEDINFO *) obj_tmp[ALRMNUM].ob_spec;
  1385.     numstr = ((char *)ted_tmp->te_ptext);
  1386.  
  1387.     form_center(obj_tmp, &cx, &cy, &cw, &ch);
  1388.     form_dial(FMD_START, 0, 0, 20, 10, cx, cy, cw, ch);
  1389.  
  1390. /*    objc_draw(obj_tmp, 0, 5, cx, cy, cw, ch); */
  1391.  
  1392.     cycle = 0;
  1393.  
  1394.     while (1) {
  1395.     sprintf(numstr,"%d",cycle);
  1396.     if (alarmtimes[cycle] == -1) {
  1397.         *alstr = '\0';
  1398.     }
  1399.     else {
  1400.         char *p, *tmpstr = dotime(alarmtimes[cycle]);
  1401.         /* funky strcpy with no punctuation */
  1402.         for (p = alstr; *tmpstr; ) {
  1403.         *p++ = *tmpstr++;
  1404.         *p++ = *tmpstr++;
  1405.         tmpstr++;
  1406.         }
  1407.         *p = '\0';
  1408.     }
  1409.     objc_draw(obj_tmp,0,5,cx,cy,cw,ch);
  1410.     tmp = (form_do(obj_tmp,ALRMTIME) & 0x7f);
  1411.  
  1412.     /* regardless of what button you used to get out... */
  1413.     if (*alstr) {
  1414. /*        w_output(wlist,alstr,strlen(alstr)); */
  1415.         alarmtimes[cycle] = untime(alstr);
  1416.         /* truncate seconds down to zero */
  1417.         alarmtimes[cycle] &= ~0x1f;
  1418.     }
  1419.     else alarmtimes[cycle] = -1;    /* you cleared it */
  1420.  
  1421.     if (tmp != ALRMOK) {
  1422.         direction = (tmp == ALRMNEXT ? 1 : -1);
  1423.         cycle += direction;
  1424.         if (cycle < 0) cycle = 0;
  1425.         if (cycle >= NALARMS) cycle = NALARMS-1;
  1426.         /* de-select the "next" button, redraw */
  1427.         objc_change(obj_tmp,ITEMNEXT,0,cx,cy,cw,ch,NORMAL,0);
  1428.     }
  1429.     else break; /* you exited with "OK" */
  1430.     }
  1431.     form_dial(FMD_FINISH,0,0,20,10,cx,cy,cw,ch);
  1432.     objc_change(obj_tmp,tmp,0,cx,cy,cw,ch,NONE,0);
  1433.     return(TRUE);
  1434. }
  1435.  
  1436. #endif
  1437.