home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / drivers / a066_1 / !VMode / c / vmode
Text File  |  1992-03-03  |  25KB  |  1,172 lines

  1. /* #define DEBUG */
  2.  
  3. /* $Id: c.vmode 1.5 92/03/04 16:34:11 bdb Exp $
  4.  *
  5.  * $Log:    c.vmode $
  6.  * Revision 1.5  92/03/04  16:34:11  bdb
  7.  * Better start up
  8.  * 
  9.  * Revision 1.4  92/03/02  17:24:51  bdb
  10.  * Trap and use palette changes.
  11.  * Added magnifier - fixed cursor vs this
  12.  * Title changing
  13.  * Fixed rogue cursor bug
  14.  * Only pass on f12 and send other keys to task.
  15.  * And mode number with 127
  16.  * Trapped VDU 21
  17.  * Prevented status lag update on menu allowing multiple resumes
  18.  * 
  19.  * Revision 1.3  92/02/25  11:45:32  bdb
  20.  * Changed newtasks behaviour to only trap on -ctrl ones,
  21.  * and no longer use weird patch. This supports a newtask
  22.  * command to replace taskwindow.
  23.  * 
  24.  * Revision 1.2  92/02/20  11:03:22  bdb
  25.  * Added cursor, passing on keys
  26.  * dbox_query replaces error box.
  27.  * 
  28.  * Revision 1.1  92/02/19  16:28:10  bdb
  29.  * Initial revision
  30.  * 
  31.  */
  32.  
  33. #define REVISION "$Revision: 1.5 $"
  34. #define VERSION ( REVISION " " __DATE__ " " __TIME__ + 11 )
  35.  
  36. #include "wimp.h"
  37. #include "wimpt.h"
  38. #include "win.h"
  39. #include "event.h"
  40. #include "res.h"
  41. #include "resspr.h"
  42. #include "menu.h"
  43. #include "template.h"
  44. #include "dbox.h"
  45. #include "dboxquery.h"
  46. #include "alarm.h"
  47. #include "baricon.h"
  48. #include "xfersend.h"
  49. #include "saveas.h"
  50. #include "werr.h"
  51. #include "magnify.h"
  52. #include "flex.h"
  53. #include "visdelay.h"
  54. #include "akbd.h"
  55. #include "pointer.h"
  56. #include "bbc.h"
  57. #include "colourtran.h"
  58. #include "kernel.h"
  59. #include "swis.h"
  60. #include "swiv.h"
  61.  
  62. #include <stdlib.h>
  63. #include <string.h>
  64. #include <stdarg.h>
  65. #include <signal.h>
  66.  
  67. #define min(x,y) ((x)<(y)?(x):(y))
  68. #define max(x,y) ((x)>(y)?(x):(y))
  69.  
  70.  
  71. enum themenu { MNULL, MKILL, MRECONNECT, MSUSPEND, MRESUME, MZOOM, MSAVE };
  72. #define themenuinit "Kill,Reconnect,Suspend,Resume,>Zoom,>Save"
  73.  
  74. enum state { TDEAD, TSUSPENDED, TRUNNING };
  75.  
  76. /* Container for info about a window */
  77. typedef struct win
  78. { wimp_w w;             /* window handle */
  79.   struct win *next;
  80.   sprite_area *area;
  81.   int osx,osy;
  82.   int winx,winy;
  83.   int *save_area;
  84.   char *pixtrans;
  85.   wimp_t task;
  86.   int mode;
  87.   int l2bpp;
  88.   int xeig,yeig;
  89.   int changed;
  90.   enum state state;
  91.   int charx,chary;
  92.   int curx,cury;
  93.   char xvduq[10];
  94.   int xvduqwant;
  95.   int xvduqpos;
  96.   int magm,magd;
  97.   int tlen;
  98.   char title[256];      /* displayed title of window - indirecttext pts here */
  99. } win;
  100.  
  101. static os_error NoMem = { 0, "Out of Memory" };
  102.  
  103. static win *thewins = NULL;
  104. static int newtasks = 1; /* Catch new taskwindows */
  105.  
  106. static menu themenu;
  107. static menu barmenu=NULL;
  108. static wimp_i theicon;
  109.  
  110. static int wimpversion;
  111.  
  112. /* Saved win during drag or save/open message bounce */
  113. static win *savewin = NULL;
  114.  
  115. /* Prototypes */
  116.  
  117. #include "VMode.h"
  118.  
  119. int main
  120. ( int argc, char *argv[] )
  121. {
  122.   int i;
  123.   init(argc,argv);
  124.   for (;;)
  125.   { event_process();
  126.   }
  127.   return 0;
  128. }
  129.  
  130. void init
  131. ( int argc, char *argv[] )
  132. {
  133.   wimp_msgstr m;
  134.   int i;
  135.     wimpversion = wimpt_init("VMode");
  136. #ifdef DEBUG
  137.     signal(SIGABRT, SIG_DFL);
  138.     signal(SIGFPE, SIG_DFL);
  139.     signal(SIGILL, SIG_DFL);
  140.     signal(SIGSEGV, SIG_DFL);
  141.     signal(SIGTERM, SIG_DFL);
  142. #endif
  143.     res_init("VMode");
  144.     resspr_init();
  145.     template_init();
  146.     dbox_init();
  147.     alarm_init();
  148.     visdelay_init();
  149.     flex_init();
  150.     win_add_unknown_event_processor( unknownevent, NULL );
  151.     theicon = baricon( "!VMode", 1, barclick );
  152.     event_attachmenumaker( win_ICONBAR, barmenumaker, barmenuproc, NULL );
  153.     themenu = menu_new( "VMode", themenuinit );
  154.     newtasks = atoi(getenv("VMode$NewTasks"));
  155.     if (argc>1)
  156.     { m.data.chars[0]=0;
  157.       for (i=1;i<argc;i++)
  158.       { strcat(m.data.chars,argv[i]);
  159.         strcat(m.data.chars," ");
  160.       }
  161.       m.hdr.action = 0x808c5; /* TaskWindow_NewTask */
  162.       m.hdr.your_ref = 0;
  163.       m.hdr.size = sizeof(m.hdr)+( ( strlen( m.data.chars ) + 4 ) & -4 );
  164.       wimpt_noerr(wimp_sendmessage(wimp_ESENDWANTACK, &m, NULL));
  165.     }
  166. }
  167.  
  168. sprite_id *SprPtr
  169. (sprite_header *s)
  170. {
  171.         static sprite_id id;
  172.         id.tag = sprite_id_addr;
  173.         id.s.addr = s;
  174.         return &id;
  175. }
  176.  
  177. sprite_id *SprNam
  178. (char *s)
  179. {
  180.         static sprite_id id;
  181.         id.tag = sprite_id_name;
  182.         id.s.name = s;
  183.         return &id;
  184. }
  185.  
  186. menu menumaker
  187. ( void *h )
  188. { win *w = h;
  189.   menu_setflags( themenu, MKILL, 0, (w->state==TDEAD) );
  190.   menu_setflags( themenu, MRECONNECT, 0, (w->state!=TDEAD) );
  191.   menu_setflags( themenu, MSUSPEND, 0, (w->state!=TRUNNING) );
  192.   menu_setflags( themenu, MRESUME, 0, (w->state!=TSUSPENDED) );
  193.   return themenu;
  194. }
  195.  
  196. void menuproc
  197. ( void *h, char *hit )
  198. { wimp_mousestr m;
  199.   wimp_msgstr msg;
  200.   win *w = h;
  201.   wimpt_noerr( wimp_get_point_info( &m ) );
  202.   switch ( hit[0] )
  203.   { case MKILL:
  204.       msg.hdr.action = 0x808c4; /* TaskWindow_Morite */
  205.       w->state = TDEAD;
  206.       newtitleflag(w," Terminating");
  207.       goto sendit;
  208.     case MRECONNECT:
  209.       if (w->state==TDEAD)
  210.         startit(w);
  211.       break;
  212.     case MSUSPEND:
  213.       if (w->state==TDEAD)
  214.         break;
  215.       msg.hdr.action = 0x808c6; /* TaskWindow_Suspend */
  216.       w->state = TSUSPENDED;
  217.       newtitleflag(w," Suspended");
  218.       goto sendit;
  219.     case MRESUME:
  220.       if (w->state==TDEAD)
  221.         break;
  222.       msg.hdr.action = 0x808c7; /* TaskWindow_Resume */
  223.       w->state = TRUNNING;
  224.       newtitleflag(w," Running");
  225. sendit:
  226.       msg.hdr.your_ref = 0;
  227.       msg.hdr.size = 20;
  228.       wimpt_noerr( wimp_sendmessage( wimp_ESEND, &msg, w->task ) );
  229.       break;
  230.     case MZOOM:
  231.       magnify_select(&w->magm,&w->magd,999,999,&magchange,w);
  232.       break;
  233.     case MSAVE:
  234.       saveas( 0xff9, "screendump", 1, saveproc, 0, 0, w );
  235.       break;
  236.   }
  237. }
  238.  
  239. void magchange
  240. ( void *h )
  241. { win *w = h;
  242.   newwinsize(w);
  243. }
  244.  
  245. BOOL saveproc
  246. ( char *filename, void *h )
  247. { win *w = h;
  248.   wimp_paletteword *p = paladdr(w);
  249.   BOOL b;
  250.   int i,n;
  251.   n = 1<<(1<<w->l2bpp);
  252.   if (3 != w->l2bpp)
  253.     for (i = n; --i >= 0; )
  254.       p[2*i+1] = p[2*i] = p[i];
  255.   b = !wimpt_complain(sprite_area_save(w->area,filename));
  256.   if (3 != w->l2bpp)
  257.     for (i = 0; i < n; i++)
  258.       p[i] = p[2*i];
  259.   if ( b && xfersend_file_is_safe() )
  260.     h = NULL; /* maybe fiddle title */
  261.   return b;
  262. }
  263.  
  264. void winevent
  265. ( wimp_eventstr *e, void *h )
  266. { BOOL more;
  267.   win *w = h;
  268.   wimp_redrawstr r;
  269.   switch ( e->e )
  270.   { case wimp_EREDRAW:
  271.       if (wimpt_checkmode())
  272.         coltable(w);
  273.       r.w = e->data.o.w;
  274.       wimpt_noerr(wimp_redraw_wind(&r,&more));
  275.       while (more)
  276.       { wimp_box cur;
  277.         sprite_factors scale;
  278.         scale.xmag=w->magm<<w->xeig;
  279.         scale.ymag=w->magm<<w->yeig;
  280.         scale.xdiv=w->magd*wimpt_dx();
  281.         scale.ydiv=w->magd*wimpt_dy();
  282.         wimpt_noerr(sprite_put_scaled( w->area, SprNam("screen"), 0,
  283.                  r.box.x0-r.scx, r.box.y1-r.scy-w->winy, &scale, w->pixtrans));
  284.         bbc_gcol(4,0);
  285.         cur.x0 = w->curx*w->charx*w->magm/w->magd;
  286.         cur.y1 = -w->cury*w->chary*w->magm/w->magd;
  287.         cur.x1 = (w->curx+1)*w->charx*w->magm/w->magd;
  288.         cur.y0 = -(w->cury+1)*w->chary*w->magm/w->magd;
  289.         bbc_rectanglefill(cur.x0+r.box.x0-r.scx,cur.y0+r.box.y1-r.scy,cur.x1-cur.x0-wimpt_dx(),cur.y1-cur.y0-wimpt_dy());
  290.         wimpt_noerr(wimp_get_rectangle(&r,&more));
  291.       }
  292.       break;
  293.     case wimp_EOPEN:
  294.       wimp_open_wind( &e->data.o );
  295.       break;
  296.     case wimp_ECLOSE:
  297.       if (w->state==TDEAD || confirm("Task active. Kill and close?"))
  298.         freewin( w );
  299.       break;
  300.     case wimp_EBUT:
  301.       {
  302.         switch ( e->data.but.m.bbits )
  303.         { case wimp_BCLICKLEFT:
  304.           case wimp_BCLICKRIGHT:
  305.           case wimp_BDRAGLEFT:
  306.           case wimp_BDRAGRIGHT:
  307.           case wimp_BRIGHT:
  308.           case wimp_BLEFT:
  309.             grabcaret(w);
  310.             break;
  311.         }
  312.         break;
  313.       }
  314.     case wimp_EKEY:
  315.       { int code = e->data.key.chcode;
  316.         if ((code&~0x30)==0x1CC) /* pass f12 through */
  317.           wimp_processkey(code);
  318.         else
  319.         { e->data.msg.hdr.action = 0x808c0; /* TaskWindow_Input */
  320.           e->data.msg.hdr.your_ref = 0;
  321.           e->data.msg.hdr.size = 28;
  322.           e->data.msg.data.words[0]=1;
  323.           e->data.msg.data.words[1]=code;
  324.           wimpt_noerr( wimp_sendmessage( wimp_ESEND, &e->data.msg, w->task ) );
  325.       } }
  326.       break;
  327.     case wimp_ESEND: case wimp_ESENDWANTACK:
  328.       switch ( e->data.msg.hdr.action )
  329.       { case wimp_MCLOSEDOWN:
  330.           while (thewins)
  331.             freewin(thewins);
  332.           exit(0);
  333.           break;
  334.       }
  335.       break;
  336.   }
  337. }
  338.  
  339. BOOL oktoquit
  340. ( void )
  341. {
  342.   win *w;
  343.   for ( w=thewins; w ; w=w->next)
  344.     if (w->state!=TDEAD)
  345.       break;
  346.   if ( w )
  347.     if ( confirm( "There are still tasks running under !VMode. Really quit?" ) )
  348.       w=NULL;
  349.   return w==NULL;
  350. }
  351.  
  352. BOOL unknownevent
  353. ( wimp_eventstr *e, void *h )
  354. { win *w=h;
  355.   sprite_state s, s2;
  356.   wimp_redrawstr r;
  357.   int *box;
  358.   int s1;
  359.   switch ( e->e )
  360.   { case wimp_ENULL:
  361.       s1 = 0;
  362.       for (w = thewins; w; w = w->next)
  363.       { if (w->changed)
  364.         { int cx,cy;
  365.           wimpt_noerr(sprite_outputtosprite(w->area, SprNam("screen"), w->save_area, s1?&s2:&s));
  366.           s1 = 1;
  367.           swix(OS_ChangedBox,IN(R0)|OUT(R1),-1,&box);
  368.           r.w = w->w;
  369.           r.box.x0 = (box[1]<<w->xeig)*w->magm/w->magd;
  370.           r.box.y0 = (box[2]<<w->yeig)*w->magm/w->magd-w->winy;
  371.           r.box.x1 = (box[3]+1<<w->xeig)*w->magm/w->magd;
  372.           r.box.y1 = (box[4]+1<<w->yeig)*w->magm/w->magd-w->winy;
  373.           swix(OS_ChangedBox,IN(R0),2);
  374.           if (r.box.x1>r.box.x0 && r.box.y1>r.box.y0)
  375.             wimpt_noerr(wimp_force_redraw(&r));
  376.           cx = bbc_pos();
  377.           cy = bbc_vpos();
  378.           if ( cx!=w->curx || cy!=w->cury )
  379.           { r.w = w->w;
  380.             r.box.x0 = w->curx*w->charx*w->magm/w->magd;
  381.             r.box.y1 = -w->cury*w->chary*w->magm/w->magd;
  382.             r.box.x1 = (w->curx+1)*w->charx*w->magm/w->magd;
  383.             r.box.y0 = -(w->cury+1)*w->chary*w->magm/w->magd;
  384.             wimpt_noerr(wimp_force_redraw(&r));
  385.             w->curx = cx;
  386.             w->cury = cy;
  387.             r.w = w->w;
  388.             r.box.x0 = w->curx*w->charx*w->magm/w->magd;
  389.             r.box.y1 = -w->cury*w->chary*w->magm/w->magd;
  390.             r.box.x1 = (w->curx+1)*w->charx*w->magm/w->magd;
  391.             r.box.y0 = -(w->cury+1)*w->chary*w->magm/w->magd;
  392.             wimpt_noerr(wimp_force_redraw(&r));
  393.           }
  394.           w->changed = 0;
  395.       } }
  396.       if (s1)
  397.         wimpt_noerr(sprite_restorestate(s));
  398.       break;
  399.     case wimp_ESEND: case wimp_ESENDWANTACK:
  400.       w = savewin;
  401.       switch ( e->data.msg.hdr.action )
  402.       { case wimp_MPREQUIT:
  403.           if ( !oktoquit() )
  404.           { ack( &e->data.msg );
  405.             return TRUE;
  406.           }
  407.           break;
  408.         case wimp_SAVEDESK:
  409.           { int fh = e->data.msg.data.savedesk.filehandle;
  410.             rofprintf( fh, "Run %s\n", getenv("VMode$Dir") );
  411.           }
  412.           break;
  413.         case 0x808c5: /* TaskWindow_NewTask */
  414.           if (e->data.msg.hdr.your_ref)
  415.           { if (!thewins)
  416.               exit(0);
  417.             else
  418.               break;
  419.           }
  420.           if (newtasks && strstr(&e->data.msg.data.chars[0],"-ctrl"))
  421.           {
  422.             ack(&e->data.msg);
  423. /* the weird flag is now set to 0, since the above message cannot have really
  424.  * come from taskwindow as its too broken to pass -ctrl through, and so we
  425.  * don't have to worry about its other bugs
  426.  */
  427.             launchone(&e->data.msg.data.chars[0]);
  428.           }
  429.           break;
  430.         case 0x808c3: /* TaskWindow_Morio */
  431.           for (w = thewins; w; w = w->next )
  432.             if (w->task==e->data.msg.hdr.task)
  433.             { w->state = TDEAD;
  434.               newtitleflag(w, " Finished");
  435.             }
  436.           break;
  437.         case 0x808c2: /* TaskWindow_Ego */
  438.           w = (win *)e->data.msg.data.words[0];
  439.           w->task = e->data.msg.hdr.task;
  440.           w->state = TRUNNING;
  441.           newtitleflag(w, " Running");
  442.           break;
  443.         case 0x808c1: /* TaskWindow_Output */
  444.           for ( w=thewins ; w ; w=w->next )
  445.             if (w->task==e->data.msg.hdr.task)
  446.               break;
  447.           if (w)
  448.             scribble( w, (char *)&e->data.msg.data.words[1], e->data.msg.data.words[0] );
  449.           break;
  450.       }
  451.       break;
  452.     case wimp_EACK:
  453.       break;
  454.   }
  455.   return FALSE;
  456. }
  457.  
  458. void barclick
  459. ( wimp_i i )
  460. { i = i;
  461.   launchone("taskwindow -ctrl");
  462. }
  463.  
  464. void launchone
  465. ( char *cmd )
  466. { wimp_wind *t;
  467.   wimp_wstate s;
  468.   win *w=claim(sizeof(win));
  469.   w->next = thewins;
  470.   thewins = w;
  471.   t = template_syshandle( "window" );
  472.   strcpy(w->title,cmd);
  473.   w->tlen = strlen(w->title);
  474.   t->title.indirecttext.buffer = w->title;
  475.   t->title.indirecttext.bufflen = 256;
  476.   wimpt_noerr( wimp_create_wind( t, &w->w ) );
  477.   win_register_event_handler( w->w, winevent, (void *)w );
  478.   event_attachmenumaker( w->w, menumaker, menuproc, (void *)w );
  479.   w->area = NULL;
  480.   w->pixtrans = NULL;
  481.   w->save_area = NULL;
  482.   w->magm = w->magd = 1;
  483.   if (!modeclear(w,0))
  484.   {
  485.     wimpt_noerr( wimp_get_wind_state( w->w, &s ) );
  486.     wimpt_noerr( wimp_open_wind( &s.o ) );
  487.     event_setmask( 0 );
  488.     startit(w);
  489.     grabcaret(w);
  490.   }
  491.   else
  492.     freewin(w);
  493. }
  494.  
  495. void startit
  496. ( win *w )
  497. { char buf[256];
  498. /* NB taskwindow seems only to recognise a reply to a request for a server if
  499.  * hex no.s with no &'s or flag names are used... odd!
  500.  */
  501. /*    if (weird)
  502.       sprintf( buf,"%s %08x  %08x ", w->title, wimpt_task(), (int)w );
  503.     else */
  504.   w->title[w->tlen] = 0;
  505.   sprintf( buf,"%s -task &%08x -txt &%08x ", w->title, wimpt_task(), (int)w );
  506.   wimp_starttask(buf);
  507.   w->state = TDEAD;
  508.   strcpy(w->title+w->tlen," Starting");
  509. }
  510.  
  511. void grabcaret
  512. ( win *w )
  513. { wimp_caretstr c;
  514.   c.w = w->w;
  515.   c.i = -1;
  516.   c.x = 100;
  517.   c.y = -100;
  518.   c.height = 0|(1<<25); /* invisible */
  519.   c.index = 0;
  520.   wimpt_noerr(wimp_set_caret_pos(&c));
  521. }
  522.  
  523. static int pal2[2]=
  524. {
  525. 0x0,
  526. 0xF0F0F007,
  527. };
  528. static int pal4[4]=
  529. {
  530. 0x0,
  531. 0xF001,
  532. 0xF0F003,
  533. 0xF0F0F007,
  534. };
  535. static int pal16[16]=
  536. {
  537. 0x0,
  538. 0xF001,
  539. 0xF00002,
  540. 0xF0F003,
  541. 0xF0000004,
  542. 0xF000F005,
  543. 0xF0F00006,
  544. 0xF0F0F007,
  545. 0x8,
  546. 0xF009,
  547. 0xF0000A,
  548. 0xF0F00B,
  549. 0xF000000C,
  550. 0xF000F00D,
  551. 0xF0F0000E,
  552. 0xF0F0F00F,
  553. };
  554. static int pal256[256]=
  555. {
  556. 0x10,
  557. 0x10101010,
  558. 0x20202010,
  559. 0x30303010,
  560. 0x4010,
  561. 0x10105010,
  562. 0x20206010,
  563. 0x30307010,
  564. 0x40000010,
  565. 0x50101010,
  566. 0x60202010,
  567. 0x70303010,
  568. 0x40004010,
  569. 0x50105010,
  570. 0x60206010,
  571. 0x70307010,
  572. 0x8010,
  573. 0x10109010,
  574. 0x2020A010,
  575. 0x3030B010,
  576. 0xC010,
  577. 0x1010D010,
  578. 0x2020E010,
  579. 0x3030F010,
  580. 0x40008010,
  581. 0x50109010,
  582. 0x6020A010,
  583. 0x7030B010,
  584. 0x4000C010,
  585. 0x5010D010,
  586. 0x6020E010,
  587. 0x7030F010,
  588. 0x400010,
  589. 0x10501010,
  590. 0x20602010,
  591. 0x30703010,
  592. 0x404010,
  593. 0x10505010,
  594. 0x20606010,
  595. 0x30707010,
  596. 0x40400010,
  597. 0x50501010,
  598. 0x60602010,
  599. 0x70703010,
  600. 0x40404010,
  601. 0x50505010,
  602. 0x60606010,
  603. 0x70707010,
  604. 0x408010,
  605. 0x10509010,
  606. 0x2060A010,
  607. 0x3070B010,
  608. 0x40C010,
  609. 0x1050D010,
  610. 0x2060E010,
  611. 0x3070F010,
  612. 0x40408010,
  613. 0x50509010,
  614. 0x6060A010,
  615. 0x7070B010,
  616. 0x4040C010,
  617. 0x5050D010,
  618. 0x6060E010,
  619. 0x7070F010,
  620. 0x800010,
  621. 0x10901010,
  622. 0x20A02010,
  623. 0x30B03010,
  624. 0x804010,
  625. 0x10905010,
  626. 0x20A06010,
  627. 0x30B07010,
  628. 0x40800010,
  629. 0x50901010,
  630. 0x60A02010,
  631. 0x70B03010,
  632. 0x40804010,
  633. 0x50905010,
  634. 0x60A06010,
  635. 0x70B07010,
  636. 0x808010,
  637. 0x10909010,
  638. 0x20A0A010,
  639. 0x30B0B010,
  640. 0x80C010,
  641. 0x1090D010,
  642. 0x20A0E010,
  643. 0x30B0F010,
  644. 0x40808010,
  645. 0x50909010,
  646. 0x60A0A010,
  647. 0x70B0B010,
  648. 0x4080C010,
  649. 0x5090D010,
  650. 0x60A0E010,
  651. 0x70B0F010,
  652. 0xC00010,
  653. 0x10D01010,
  654. 0x20E02010,
  655. 0x30F03010,
  656. 0xC04010,
  657. 0x10D05010,
  658. 0x20E06010,
  659. 0x30F07010,
  660. 0x40C00010,
  661. 0x50D01010,
  662. 0x60E02010,
  663. 0x70F03010,
  664. 0x40C04010,
  665. 0x50D05010,
  666. 0x60E06010,
  667. 0x70F07010,
  668. 0xC08010,
  669. 0x10D09010,
  670. 0x20E0A010,
  671. 0x30F0B010,
  672. 0xC0C010,
  673. 0x10D0D010,
  674. 0x20E0E010,
  675. 0x30F0F010,
  676. 0x40C08010,
  677. 0x50D09010,
  678. 0x60E0A010,
  679. 0x70F0B010,
  680. 0x40C0C010,
  681. 0x50D0D010,
  682. 0x60E0E010,
  683. 0x70F0F010,
  684. 0x80000010,
  685. 0x90101010,
  686. 0xA0202010,
  687. 0xB0303010,
  688. 0x80004010,
  689. 0x90105010,
  690. 0xA0206010,
  691. 0xB0307010,
  692. 0xC0000010,
  693. 0xD0101010,
  694. 0xE0202010,
  695. 0xF0303010,
  696. 0xC0004010,
  697. 0xD0105010,
  698. 0xE0206010,
  699. 0xF0307010,
  700. 0x80008010,
  701. 0x90109010,
  702. 0xA020A010,
  703. 0xB030B010,
  704. 0x8000C010,
  705. 0x9010D010,
  706. 0xA020E010,
  707. 0xB030F010,
  708. 0xC0008010,
  709. 0xD0109010,
  710. 0xE020A010,
  711. 0xF030B010,
  712. 0xC000C010,
  713. 0xD010D010,
  714. 0xE020E010,
  715. 0xF030F010,
  716. 0x80400010,
  717. 0x90501010,
  718. 0xA0602010,
  719. 0xB0703010,
  720. 0x80404010,
  721. 0x90505010,
  722. 0xA0606010,
  723. 0xB0707010,
  724. 0xC0400010,
  725. 0xD0501010,
  726. 0xE0602010,
  727. 0xF0703010,
  728. 0xC0404010,
  729. 0xD0505010,
  730. 0xE0606010,
  731. 0xF0707010,
  732. 0x80408010,
  733. 0x90509010,
  734. 0xA060A010,
  735. 0xB070B010,
  736. 0x8040C010,
  737. 0x9050D010,
  738. 0xA060E010,
  739. 0xB070F010,
  740. 0xC0408010,
  741. 0xD0509010,
  742. 0xE060A010,
  743. 0xF070B010,
  744. 0xC040C010,
  745. 0xD050D010,
  746. 0xE060E010,
  747. 0xF070F010,
  748. 0x80800010,
  749. 0x90901010,
  750. 0xA0A02010,
  751. 0xB0B03010,
  752. 0x80804010,
  753. 0x90905010,
  754. 0xA0A06010,
  755. 0xB0B07010,
  756. 0xC0800010,
  757. 0xD0901010,
  758. 0xE0A02010,
  759. 0xF0B03010,
  760. 0xC0804010,
  761. 0xD0905010,
  762. 0xE0A06010,
  763. 0xF0B07010,
  764. 0x80808010,
  765. 0x90909010,
  766. 0xA0A0A010,
  767. 0xB0B0B010,
  768. 0x8080C010,
  769. 0x9090D010,
  770. 0xA0A0E010,
  771. 0xB0B0F010,
  772. 0xC0808010,
  773. 0xD0909010,
  774. 0xE0A0A010,
  775. 0xF0B0B010,
  776. 0xC080C010,
  777. 0xD090D010,
  778. 0xE0A0E010,
  779. 0xF0B0F010,
  780. 0x80C00010,
  781. 0x90D01010,
  782. 0xA0E02010,
  783. 0xB0F03010,
  784. 0x80C04010,
  785. 0x90D05010,
  786. 0xA0E06010,
  787. 0xB0F07010,
  788. 0xC0C00010,
  789. 0xD0D01010,
  790. 0xE0E02010,
  791. 0xF0F03010,
  792. 0xC0C04010,
  793. 0xD0D05010,
  794. 0xE0E06010,
  795. 0xF0F07010,
  796. 0x80C08010,
  797. 0x90D09010,
  798. 0xA0E0A010,
  799. 0xB0F0B010,
  800. 0x80C0C010,
  801. 0x90D0D010,
  802. 0xA0E0E010,
  803. 0xB0F0F010,
  804. 0xC0C08010,
  805. 0xD0D09010,
  806. 0xE0E0A010,
  807. 0xF0F0B010,
  808. 0xC0C0C010,
  809. 0xD0D0D010,
  810. 0xE0E0E010,
  811. 0xF0F0F010,
  812. };
  813. static int *bpptab[4]={pal2,pal4,pal16,pal256};
  814.  
  815. void modefree
  816. ( win *w )
  817. {
  818.   if (w->area)
  819.     flex_free((flex_ptr)&w->area);
  820.   if (w->save_area)
  821.     free(w->save_area);
  822.   w->save_area=NULL;
  823.   if (w->pixtrans)
  824.     free(w->pixtrans);
  825.   w->pixtrans=NULL;
  826. }
  827.  
  828. os_error *modeclear
  829. ( win*w, int mode )
  830. {
  831.   int size,bpp,x,y,wid;
  832.   sprite_state s;
  833.   os_error *err;
  834.   w->mode = mode;
  835.   x = bbc_modevar(mode,bbc_XWindLimit)+1;
  836.   y = bbc_modevar(mode,bbc_YWindLimit)+1;
  837.   w->l2bpp = bbc_modevar(mode,bbc_Log2BPP);
  838.   bpp = 1 << w->l2bpp;
  839.   wid = x*bpp+31&~31;
  840.   w->osx = x << (w->xeig=bbc_modevar(mode,bbc_XEigFactor));
  841.   w->osy = y << (w->yeig=bbc_modevar(mode,bbc_YEigFactor));
  842.   w->charx = 8 << w->xeig;
  843.   w->chary = (bbc_modevar(mode,bbc_ModeFlags)&(1<<5)?16:8) << w->yeig;
  844.   size = sizeof(sprite_area)+sizeof(sprite_header)+wid/8*y+(8<<bpp);
  845.   if (!flex_alloc((flex_ptr)&w->area, size))
  846.     return wimpt_complain(&NoMem);
  847.   sprite_area_initialise(w->area, size);
  848.   err=wimpt_complain(sprite_create(w->area, "screen", sprite_haspalette, x, y, mode));
  849.   if (err) return err;    
  850.   wimpt_noerr(sprite_sizeof_spritecontext(w->area, SprNam("screen"), &size));
  851.   w->save_area = claim(size);
  852.   w->save_area[0]=0;
  853.   if (3!=w->l2bpp)
  854.     memcpy(paladdr(w),bpptab[w->l2bpp],sizeof(int)<<bpp);
  855.   w->pixtrans = claim(1<<bpp);
  856.   if (!w->save_area || !w->pixtrans)
  857.     return wimpt_complain(&NoMem);
  858.   wimpt_noerr(sprite_outputtosprite(w->area,  SprNam("screen"), w->save_area, &s));
  859.   swix(OS_ChangedBox,IN(R0),1);
  860.   swix(OS_ChangedBox,IN(R0),2);
  861.   w->xvduqpos = 0;
  862.   w->curx = -1;
  863.   wimpt_noerr(sprite_restorestate(s));
  864.   coltable(w);
  865.   newwinsize(w);
  866.   return NULL;
  867. }
  868.  
  869. void newwinsize
  870. ( win *w )
  871. {
  872.   wimp_redrawstr r;
  873.   wimp_wstate state;
  874.   w->winx = w->osx*w->magm/w->magd;
  875.   w->winy = w->osy*w->magm/w->magd;
  876.   r.w = w->w;
  877.   r.box.x0 = 0; r.box.x1 = w->winx; r.box.y0 = -w->winy; r.box.y1 = 0;
  878.   wimpt_noerr( wimp_get_wind_state( w->w, &state ) );
  879.   if (state.o.box.x1 > state.o.box.x0+w->winx)
  880.       state.o.box.x1 = state.o.box.x0+w->winx;
  881.   if (state.o.box.y0 < state.o.box.y1-w->winy)
  882.       state.o.box.y0 = state.o.box.y1-w->winy;
  883.   if (state.o.x < w->winx - (state.o.box.x1 - state.o.box.x0))
  884.       state.o.x = w->winx - (state.o.box.x1 - state.o.box.x0);
  885.   if (state.o.y < (state.o.box.y1 - state.o.box.y0) - w->winy)
  886.       state.o.y = (state.o.box.y1 - state.o.box.y0) - w->winy;
  887.   wimpt_noerr(wimp_open_wind(&state.o));
  888.   wimpt_noerr(wimp_set_extent(&r));
  889.   wimpt_noerr(wimp_force_redraw(&r));
  890. }
  891.  
  892. wimp_paletteword *paladdr
  893. ( win *w )
  894. {
  895.   sprite_ptr p;
  896.   if (3==w->l2bpp)
  897.     return (wimp_paletteword *)pal256;
  898.   wimpt_noerr(sprite_select_rp(w->area,SprNam("screen"),&p));
  899.   return (wimp_paletteword *)((sprite_header *)p+1);
  900. }
  901.  
  902. void coltable
  903. ( win *w )
  904.   wimpt_noerr(colourtran_select_table(w->mode,paladdr(w),-1,(wimp_paletteword *)-1,w->pixtrans));
  905. }
  906.  
  907. void scribble
  908. ( win *w, char *data, int size )
  909. {
  910.   sprite_state s;
  911.   char *p;
  912.   int q,n;
  913.   wimpt_noerr(sprite_outputtosprite(w->area,  SprNam("screen"), w->save_area, &s));
  914.   if (w->xvduqpos>0)
  915.   { n = w->xvduqwant;
  916.     memcpy(w->xvduq+w->xvduqpos,data,n);
  917.     if (size<n)
  918.     { w->xvduqpos += size;
  919.       w->xvduqwant = n-size;
  920.       goto ret;
  921.     }
  922.     else
  923.     { p = w->xvduq;
  924.       goto doq;
  925.     }
  926.   }
  927.   for (p=data; size>0; p++,size--)
  928.   { if (!(19<=*p && *p<=22))
  929.       continue;
  930.     if (p-data)
  931.       swix( OS_WriteN, IN(R0|R1), data, p-data );
  932.     data = p;
  933.     swix(OS_Byte,IN(R0|R1|R2)|OUT(R1),218,0,255,&q);
  934.     if (q)
  935.       continue;
  936.     n = *data==19?6:
  937.         *data==20?1:
  938.         *data==21?1:
  939.                   2;
  940.     if (size<n)
  941.     { memcpy(w->xvduq,p,size);
  942.       w->xvduqpos = size;
  943.       w->xvduqwant = n-size;
  944.       n = size;
  945.     }
  946.     else
  947.     { wimpt_noerr(sprite_restorestate(s));
  948. doq:  switch(*p)
  949.       {
  950.         case 22:
  951.           modefree(w);
  952.           if (modeclear(w,p[1]&127))
  953.           { freewin(w);
  954.             return;
  955.           }
  956.           break;
  957.         case 19:
  958.           if (3!=w->l2bpp)
  959.           { int c=p[1]%(1<<(1<<w->l2bpp));
  960.             if (0<=p[2] && p[2]<16)
  961.               paladdr(w)[c].word = pal16[p[2]];
  962.             else if (p[2]==16)
  963.               memcpy(&paladdr(w)[c].bytes.gcol,&p[2],4);
  964.             coltable(w);
  965.             newwinsize(w);
  966.           }
  967.           break;
  968.         case 20:
  969.           if (3!=w->l2bpp)
  970.             memcpy(paladdr(w),bpptab[w->l2bpp],sizeof(int)<<(1<<w->l2bpp));
  971.           coltable(w);
  972.           newwinsize(w);
  973.           break;
  974.       }
  975.       wimpt_noerr(sprite_outputtosprite(w->area,  SprNam("screen"), w->save_area, &s));
  976.     }
  977.     --n;
  978.     size -= n;
  979.     p = data += n;
  980.     data++;     /* to match what will happen to p */
  981.   }
  982.   if (p-data)
  983.     swix( OS_WriteN, IN(R0|R1), data, p-data );
  984. ret:
  985.   w->changed = 1;
  986.   wimpt_noerr(sprite_restorestate(s));
  987. }
  988.  
  989. menu barmenumaker
  990. ( void *h )
  991. {
  992.   h=h;
  993.   if ( !event_is_menu_being_recreated() )
  994.   { if ( barmenu )
  995.       menu_dispose( &barmenu, 0 );
  996.     barmenu = menu_new( "VMode", ">Info,NewTasks,Quit" );
  997.     menu_setflags( barmenu, 2, newtasks, 0 );
  998.   }
  999.   return barmenu;
  1000. }
  1001.  
  1002. void barmenuproc
  1003. ( void *h, char *hit )
  1004. {
  1005.   h=h;
  1006.   switch (hit[0])
  1007.   { case 1:
  1008.       infobox();
  1009.       break;
  1010.     case 2:
  1011.       newtasks = ! newtasks;
  1012.       break;
  1013.     case 3:
  1014.       if ( oktoquit() )
  1015.       { while (thewins)
  1016.           freewin(thewins);
  1017.         exit(0);
  1018.       }
  1019.       break;
  1020.   }
  1021. }
  1022.  
  1023. /*
  1024.  * Window manipulation
  1025.  */
  1026.  
  1027. void newtitleflag
  1028. ( win *w, char *n )
  1029. { wimp_redrawstr r;
  1030.   wimp_wstate s;
  1031.   strcpy( w->title+w->tlen, n );
  1032.   r.w = w->w;
  1033.   wimpt_noerr( wimp_getwindowoutline( &r ) );
  1034.   wimpt_noerr( wimp_get_wind_state( w->w, &s ) );
  1035.   r.w = -1;
  1036.   r.box.y0 = s.o.box.y1;
  1037.   wimpt_noerr( wimp_force_redraw( &r ) );
  1038. }
  1039.  
  1040. void behind
  1041. ( win *w, int where )
  1042. { wimp_wstate s;  
  1043.   wimpt_noerr( wimp_get_wind_state( w->w, &s ) );
  1044.   s.o.behind = where;
  1045.   wimpt_noerr( wimp_open_wind( &s.o ) );
  1046. }
  1047.  
  1048. void freewin
  1049. ( win *w )
  1050. {
  1051.   win **w1;
  1052.   if ( w->w )
  1053.   { win_register_event_handler( w->w, 0, 0 );
  1054.     alarm_removeall( (void *)w );
  1055.     wimpt_noerr(wimp_delete_wind(w->w));
  1056.   }
  1057.   for ( w1=&thewins; *w1!=w; w1=&(*w1)->next )
  1058.     if ( !*w1 )
  1059.       werr( 1, "Chain of windows broken" );
  1060.   if (w->state!=TDEAD)
  1061.   { wimp_msgstr msg;
  1062.     msg.hdr.action = 0x808c4; /* TaskWindow_Morite */
  1063.     msg.hdr.your_ref = 0;
  1064.     msg.hdr.size = 20;
  1065.     wimpt_noerr( wimp_sendmessage( wimp_ESEND, &msg, w->task ) );
  1066.   }
  1067.   *w1 = w->next;
  1068.   modefree(w);
  1069.   free(w);
  1070. }
  1071.  
  1072. /*
  1073.  * Wimp utility
  1074.  */
  1075.  
  1076. int confirm
  1077. ( char *s )
  1078. { return dboxquery(s)==dboxquery_YES;
  1079. }
  1080.  
  1081. void infobox
  1082. ( void )
  1083. { dbox d;
  1084.   d = dbox_new("info");
  1085.   dbox_setfield(d, 3, VERSION );
  1086.   dbox_show(d);
  1087.   dbox_fillin(d);
  1088.   dbox_dispose(&d);
  1089. }
  1090.  
  1091. /*
  1092.  * Safe memory allocation
  1093.  */
  1094.  
  1095. void *claim
  1096. ( int size )
  1097. { void *p;
  1098.   p = malloc( size );
  1099.   if ( !p )
  1100.     werr( 1, "out of memory" );
  1101.   return p;
  1102. }
  1103.  
  1104. void *reclaim
  1105. ( void *q, int size )
  1106. { void *p;
  1107.   p = realloc( q, size );
  1108.   if ( !p )
  1109.     werr( 1, "out of memory" );
  1110.   return p;
  1111. }
  1112.  
  1113. /*
  1114.  * Stuff to deal with sending Wimp messages
  1115.  */
  1116.  
  1117. void ack
  1118. ( wimp_msgstr* msg )
  1119. {
  1120.   msg->hdr.your_ref = msg->hdr.my_ref;
  1121.   wimpt_noerr( wimp_sendmessage( wimp_ESEND, msg, msg->hdr.task ) );
  1122. }
  1123.  
  1124. void rofprintf
  1125. ( int fh, char *fmt, ... )
  1126. { char buf[256];
  1127.   va_list arg;
  1128.   _kernel_osgbpb_block b;
  1129.   va_start( arg, fmt );
  1130.   vsprintf( buf, fmt, arg );
  1131.   va_end( arg );
  1132.   b.dataptr = buf;
  1133.   b.nbytes = strlen( buf );
  1134.   if (_kernel_osgbpb( 2, fh, &b )==_kernel_ERROR)
  1135.     wimpt_complain( (os_error *)_kernel_last_oserror() );
  1136. }
  1137.  
  1138. void strins
  1139. ( char *d, char *s )
  1140. /* Insert string s at the beginning of string d */
  1141. {
  1142.   int l=strlen(s);
  1143.   int m=strlen(d);
  1144.   memmove(&d[l],d,m+1);
  1145.   memmove(d,s,l);
  1146. }
  1147.  
  1148. char *strdup
  1149. ( char *d )
  1150. {
  1151.   int m=strlen(d);
  1152.   char *p = claim(m+1);
  1153.   if (p)
  1154.     strcpy( p, d );
  1155.   return p;
  1156. }
  1157.  
  1158. char *strjoin
  1159. ( char *s, char *t )
  1160. {
  1161.   int m=strlen(s);
  1162.   int n=strlen(t);
  1163.   char *p = claim( m+n+1 );
  1164.   if (p)
  1165.   { strcpy( p, s );
  1166.     strcpy( p+m, t );
  1167.   }
  1168.   return p;
  1169. }
  1170.  
  1171.