home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 2 / AUCD2.iso / program / vista.arc / c / task < prev    next >
Text File  |  1996-02-01  |  36KB  |  1,323 lines

  1. // **************************************************************************
  2. //                     Copyright 1996 David Allison
  3. //
  4. //             VV    VV    IIIIII     SSSSS     TTTTTT       AA
  5. //             VV    VV      II      SS           TT       AA  AA
  6. //             VV    VV      II        SSSS       TT      AA    AA
  7. //              VV  VV       II           SS      TT      AAAAAAAA
  8. //                VV       IIIIII     SSSS        TT      AA    AA
  9. //
  10. //                    MULTI-THREADED C++ WIMP CLASS LIBRARY
  11. //                                for RISC OS
  12. // **************************************************************************
  13. //
  14. //             P U B L I C    D O M A I N    L I C E N C E
  15. //             -------------------------------------------
  16. //
  17. //     This library is copyright. You may not sell the library for
  18. //     profit, but you may sell products which use it providing
  19. //     those products are presented as executable code and are not
  20. //     libraries themselves.  The library is supplied without any
  21. //     warranty and the copyright owner cannot be held responsible for
  22. //     damage resulting from failure of any part of this library.
  23. //
  24. //          See the User Manual for details of the licence.
  25. //
  26. // *************************************************************************
  27.  
  28.  
  29.  
  30. //
  31. // c.task
  32. //
  33.  
  34. #include "Vista:task.h"
  35. #include <kernel.h>
  36. #include <swis.h>
  37. #include <stdio.h>
  38. #include <string.h>
  39. #include <stdarg.h>
  40. #include <stdlib.h>
  41. #include <signal.h>
  42. #include <setjmp.h>
  43.  
  44.  
  45.  
  46. ControlThread::ControlThread(Task *t, int event, int *buf)
  47.    : Thread ("control")
  48.    {
  49.    task = t ;
  50.    next = NULL ;
  51.    init (event, buf) ;
  52.    }
  53.  
  54. ControlThread::~ControlThread()
  55.    {
  56.    }
  57.  
  58. void ControlThread::init(int event, int *buf)
  59.    {
  60.    this->event = event ;
  61.    memcpy (this->buf, buf, sizeof (this->buf)) ;
  62.    }
  63.  
  64. void ControlThread::run()
  65.    {
  66.    int caught = 0 ;
  67.    Window *w ;
  68.    _kernel_oserror err ;
  69.    _kernel_oserror *e ;
  70.    _kernel_swi_regs r ;
  71.    int adjust_hit ;                 // adjust was hit on menu
  72.    Object *object ;
  73. #ifdef __EASY_C
  74.    try
  75. #endif
  76.       {
  77.       switch (event)
  78.          {
  79.          case Task::ENULL:
  80.             break ;
  81.          case Task::EREDRAW:             /* this is handled as a special case */
  82. #if 0
  83.             w = task->find_window (buf[0]) ;
  84.             if (w == NULL)
  85.                break ;
  86.             w->redraw() ;
  87. #endif
  88.             break ;
  89.          case Task::EOPEN:
  90.             w = task->find_window (buf[0]) ;
  91.             if (w == NULL)
  92.                break ;
  93.             w->open(buf[1],buf[2],buf[3],buf[4], buf[5], buf[6], buf[7]) ;
  94.             break ;
  95.          case Task::ECLOSE:
  96.             w = task->find_window (buf[0]) ;
  97.             if (w == NULL)
  98.                break ;
  99.             w->close() ;
  100.             break ;
  101.          case Task::EPTRLEAVE:
  102.          case Task::EPTRENTER:
  103.             w = task->find_window (buf[0]) ;
  104.             if (w == NULL)
  105.                break ;
  106.             w->pointer (event == Task::EPTRENTER) ;
  107.             break ;
  108.          case Task::EBUT:
  109.             if (buf[3] >= 0)           // in a window?
  110.                {
  111.                w = task->find_window (buf[3]) ;             // find the window
  112.                if (w == NULL)
  113.                   break ;
  114.                if (buf[2] & Task::BMID)                     // menu button?
  115.                   {
  116.                   Icon *icon ;
  117.                   bool found = false ;
  118.                   if (buf[4] != -1 && (icon = w->find_icon(buf[4])) != NULL)   // find icon
  119.                      {
  120.                      task->current_menu = icon->display_menu (buf[0], buf[1], buf[2], buf[4]) ;
  121.                      if (task->current_menu != NULL)
  122.                         {
  123.                         found = true ;
  124.                         task->current_menu_icon = icon ;
  125.                         }
  126.                      }
  127.                   if (!found && (object = w->find_object (buf[0], buf[1])) != NULL) // find object
  128.                      {
  129.                      task->current_menu = object->display_menu (buf[0], buf[1], buf[2], buf[4]) ;
  130.                      if (task->current_menu != NULL)
  131.                         {
  132.                         found = true ;
  133.                         task->current_menu_object = object ;
  134.                         }
  135.                      }
  136.                   if (!found)
  137.                      {
  138.                      task->current_menu = w->display_menu (buf[0], buf[1], buf[2], buf[4]) ;
  139.                      task->current_menu_window = w ;
  140.                      }
  141.                   }
  142.                else
  143.                   {
  144.                   if (buf[4] != -1)         // on an icon?
  145.                      {
  146.                      Icon *icon ;
  147.                      if ((icon = w->find_icon(buf[4])) != NULL)   // find it
  148.                         {
  149.                         icon->click (buf[0], buf[1], buf[2], buf[4]) ;   // say clicked
  150.                         break ;
  151.                         }
  152.                      }
  153.                   if ((object = w->find_object (buf[0], buf[1])) != NULL)
  154.                      {
  155.                      if (buf[2] & (4 * 16 + 16))
  156.                         object->drag (buf[0], buf[1], buf[2]) ;
  157.                      else if (buf[2] & (4 + 1))
  158.                         object->double_click (buf[0], buf[1], buf[2]) ;
  159.                      else
  160.                         object->click (buf[0], buf[1], buf[2]) ;
  161.                      }
  162.                   else
  163.                      w->click(buf[0], buf[1], buf[2], buf[4]) ;   // tell window
  164.                   }
  165.                }
  166.             else if (buf[3] == -2)   // icon bar
  167.                {
  168.                task->current_menu_window = NULL ;         // no window
  169.                task->current_menu_icon = NULL ;           // no icon
  170.                task->current_menu_object = NULL ;         // no object
  171.                if (buf[2] & Task::BMID)
  172.                   {
  173.                   if (task->iconbar_menu != NULL)
  174.                      {
  175.                      task->current_menu = task->iconbar_menu ;
  176.                      task->pre_menu (task->iconbar_menu) ;            // any user modifications
  177.                      task->iconbar_menu->iconbar_adjust (buf[0], buf[1]) ;
  178.                      task->iconbar_menu->open(buf[0] - 48, buf[1]) ;
  179.                      }
  180.                   else
  181.                      {
  182.                      char *menu_name = task->get_iconbar_menu (buf[4]) ;
  183.                      if (menu_name != NULL)
  184.                         {
  185.                         task->current_menu = task->menus->find (menu_name) ;
  186.                         task->current_menu->iconbar_adjust (buf[0], buf[1]) ;
  187.                         task->current_menu->open (buf[0] - 48, buf[1]) ;
  188.                         }
  189.                      }
  190.                   }
  191.                else
  192.                   task->click (buf[0], buf[1], buf[2], buf[4]) ;
  193.                }
  194.             break ;
  195.          case Task::EUSERDRAG:
  196.             if (task->dragging_sprite)
  197.                {
  198.                _kernel_swi (DragASprite_Stop, &r, &r) ;
  199.                task->dragging_sprite = false ;
  200.                }
  201.             if (task->object_dragger != NULL)
  202.                {
  203.                task->object_dragger->end_drag (buf[0], buf[1], buf[2], buf[3], task->object_dragger_id) ;
  204.                task->object_dragger = NULL ;
  205.                }
  206.             if (task->dragger != NULL)
  207.                {
  208.                task->dragger->drag(buf[0], buf[1], buf[2], buf[3],task->dragger_id) ;
  209.                task->dragger = NULL ;
  210.                }
  211.             break ;
  212.          case Task::EKEY:
  213.             w = task->find_window (buf[0]) ;
  214.             if (w == NULL)
  215.                break ;
  216.             if (buf[1] != -1)                 // pressed in an icon?
  217.                {
  218.                Icon *icon ;
  219.                if ((icon = w->find_icon(buf[1])) != NULL)   // find it
  220.                   {
  221.                   icon->key (buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]) ;   // say key pressed
  222.                   break ;
  223.                   }
  224.                }
  225.             if ((object = w->find_object (buf[0], buf[1])) != NULL)
  226.                object->key (buf[2], buf[3], buf[4], buf[5], buf[6]) ;
  227.             else
  228.                w->key (buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]) ;
  229.             break ;
  230.          case Task::EMENU:
  231.             {
  232.             int pointer_info[5] ;
  233.             r.r[1] = (int)pointer_info ;
  234.             if ((e = _kernel_swi (Wimp_GetPointerInfo, &r, &r)) != NULL)
  235.                throw (e) ;
  236.             adjust_hit = pointer_info[2] & 1 ;
  237.             if (!task->current_menu->invalid_selection(buf))
  238.                {
  239.                MenuItem *items = task->current_menu->selection (buf) ;
  240.                if (task->current_menu_icon != NULL)
  241.                   task->current_menu_icon->menu (items) ;
  242.                else if (task->current_menu_object != NULL)
  243.                   task->current_menu_object->menu (items) ;
  244.                else if (task->current_menu_window != NULL)
  245.                   task->current_menu_window->menu (items) ;
  246.                else
  247.                   task->menu (items) ;
  248.                }
  249.             if (adjust_hit)
  250.                task->current_menu->open (0,0) ;
  251.             break ;
  252.             }
  253.          case Task::ESCROLL:
  254.             w = task->find_window (buf[0]) ;
  255.             if (w == NULL)
  256.                break ;
  257.             w->scroll (buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]) ;
  258.             break ;
  259.          case Task::ELOSECARET:
  260.          case Task::EGAINCARET:
  261.             w = task->find_window (buf[0]) ;
  262.             if (w == NULL)
  263.                break ;
  264.             w->caret (r.r[0] == Task::EGAINCARET, buf[1], buf[2], buf[3], buf[4], buf[5]) ;
  265.             break ;
  266.          case Task::EPOLLNONZERO:
  267.             task->poll_word_non_zero ((int *)buf[0], buf[1]) ;
  268.             break ;
  269.          case Task::ESEND:
  270.          case Task::ESENDWANTACK:
  271.             switch (buf[4])
  272.                {
  273.                case Task::Message_Quit:                       // quit message
  274.                   task->exit() ;
  275.                   break ;
  276.  
  277.                case Task::Message_ModeChange:                  // mode change message
  278.                   {
  279.                   int iblock[3] ;
  280.                   int oblock[2] ;
  281.  
  282.               for (w = task->windows ; w != NULL ; w = w->next)  // tell windows
  283.                  w->mode_change() ;
  284.               r.r[0] = 0 ;                                  // see PRM 3-416
  285.               r.r[1] = (int)"" ;
  286.               r.r[2] = 0x10 ;
  287.               r.r[3] = -1 ;
  288.               r.r[4] = -1 ;
  289.               if ((e = _kernel_swi (Font_Paint, &r, &r)) != NULL)
  290.                      throw (e) ;
  291.                   r.r[0] = (int)iblock ;
  292.                   r.r[1] = (int)oblock ;
  293.                   iblock[0] = 4 ;
  294.                   iblock[1] = 5 ;
  295.                   iblock[2] = -1 ;
  296.                   if ((e = _kernel_swi (OS_ReadVduVariables, &r, &r)) != NULL)
  297.                      throw (e) ;
  298.                   task->xeigfactor = oblock[0] ;
  299.                   task->yeigfactor = oblock[1] ;
  300.               break ;
  301.                   }
  302.  
  303.                case Task::Message_MenuWarning:            // menu warning
  304.                   {
  305.                   MenuItem *items = task->current_menu->selection (buf+8) ;
  306.                   if (task->current_menu_icon != NULL)
  307.                      task->current_menu_icon->menu (items) ;
  308.                   else if (task->current_menu_object != NULL)
  309.                      task->current_menu_object->menu (items) ;
  310.                   else if (task->current_menu_window != NULL)
  311.                      task->current_menu_window->menu (items) ;
  312.                   else
  313.                      task->menu (items) ;
  314.                   break ;
  315.                   }
  316.  
  317.                case Task::Message_HelpRequest:
  318.                   {
  319.                   char *help_reply = NULL ;
  320.                   w = task->find_window (buf[8]) ;
  321.                   if (w != NULL)
  322.                      {
  323.                      if (buf[9] != -1)                 // pressed in an icon?
  324.                         {
  325.                         Icon *icon ;
  326.                         if ((icon = w->find_icon(buf[9])) != NULL)   // find it
  327.                            help_reply = icon->help (buf[5], buf[6], buf[7]) ;
  328.                         }
  329.                      if (help_reply == NULL && (object = w->find_object (buf[5], buf[6])) != NULL)
  330.                         help_reply = object->help (buf[5], buf[6], buf[7]) ;
  331.                      if (help_reply == NULL)
  332.                         help_reply = w->help (buf[5], buf[6], buf[7], buf[9]) ;
  333.                      }
  334.                   if (help_reply == NULL)
  335.                      help_reply = task->help (buf[5],buf[6],buf[7],buf[8],buf[9]) ;
  336.                   if (help_reply != NULL)
  337.                      {
  338.                      int len = strlen (help_reply) + 1 ;   // allow of 0 at end
  339.                      int my_ref ;
  340.                      task->send_message (Task::ESEND, Task::Message_HelpReply, buf[1], my_ref, buf[2], len, help_reply) ;
  341.                      }
  342.                   break ;
  343.                   }
  344.  
  345.                default:
  346.                   {
  347.                   Task::receiver *r = task->find_receiver (buf[4], buf[3]) ;
  348.                   if (r != NULL)
  349.                      r->channel->receive (buf[4], buf[1], buf[2], buf[3], buf[0] - 20, &buf[5]) ;
  350.                   break;
  351.                   }
  352.                }
  353.             break ;
  354.          case Task::EACK:
  355.             break ;
  356.          }
  357.       }
  358. #ifdef __EASY_C
  359.    catch (TaskError t)
  360.       {
  361.       err.errnum = 0 ;
  362.       strcpy (err.errmess, task->lookup(t.buf)) ;
  363.       r.r[0] = (int)&err ;
  364.       r.r[1] = 0 ;
  365.       r.r[2] = (int)task->program ;
  366.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  367.       if (t.fatal)
  368.          task->exit(t.fatal) ;
  369.       }
  370.  
  371.    catch (_kernel_oserror *e)
  372.       {
  373.       r.r[0] = (int)e ;
  374.       r.r[1] = 0 ;
  375.       r.r[2] = (int)task->program ;
  376.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  377.       }
  378.    catch (char *s)
  379.       {
  380.       err.errnum = 0 ;
  381.       strcpy (err.errmess, task->lookup(s)) ;
  382.       r.r[0] = (int)&err ;
  383.       r.r[1] = 0 ;
  384.       r.r[2] = (int)task->program ;
  385.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  386.       }
  387. #endif
  388.    task->delete_deferred (this) ;
  389.    }
  390.  
  391.  
  392. DebugWin::DebugWin (Task *t)
  393.    : Window (t,"debug")
  394.    {
  395.    text = NULL ;
  396.    Window::Info *inf = info() ;
  397.    min_height = inf->extent.y1 - inf->extent.y0 ;
  398.    }
  399.  
  400. DebugWin::~DebugWin()
  401.    {
  402.    if (text != NULL)
  403.       delete text ;
  404.    }
  405.  
  406. void DebugWin::print (char *format...)
  407.    {
  408.    char buffer[1024] ;
  409.    va_list arg ;
  410.    va_start (arg,format) ;
  411.    vsprintf (buffer,format,arg) ;
  412.    if (text == NULL)
  413.       text = new TextObject (this, "text", buffer, 8, -8) ;
  414.    else
  415.       text->insert_line (buffer) ;
  416.    int height = text->height() + 16 ;
  417.    if (height > min_height)
  418.       set_height (height) ;
  419.    Window::State *s = state() ;
  420.    do_open (s->box.x0, s->box.y0, s->box.x1, s->box.y1, 0, ((s->box.y1 - s->box.y0)/2) - height) ;
  421.    do_redraw() ;
  422.    }
  423.  
  424. static char *signals[] = {
  425.                                "Abort",
  426.                                "Floating point exception",
  427.                                "Illegal instruction",
  428.                                "Interrupt",
  429.                                "Segmentation fault",
  430.                                "Terminate",
  431.                                "Stack overflow"
  432.                          } ;
  433. static char *application ;
  434.  
  435. void signal_handler(int sig)
  436.    {
  437.    thread_disable_ints() ;
  438.    thread_stop_ticker(ThreadManager::current_manager) ;
  439. //   raise(sig) ;
  440.    ::print ("%s has received signal \"%s\" and must exit immediately",application,signals[sig]) ;
  441.    exit(1) ;
  442.    }
  443.  
  444. Task *main_task ;
  445.  
  446. void dprintf (char *format...)
  447.    {
  448.    if (main_task->debug == NULL)
  449.       return ;
  450.    char buf[1024] ;
  451.    va_list arg ;
  452.    va_start (arg,format) ;
  453.    vsprintf (buf,format,arg) ;
  454.    main_task->debug->print (buf) ;
  455.    }
  456.  
  457. Task::Task (char *taskname, char *applname, char *spritename, char *icon_menu, int priority, int position, int wimp_version, int *message_list)
  458.    {
  459.    char buffer[256] ;
  460.    _kernel_swi_regs r ;
  461.    _kernel_osfile_block b ;
  462.    _kernel_oserror *err ;
  463.    char resources[256] ;
  464.  
  465. #ifdef __EASY_C
  466.    try
  467. #endif
  468.       {
  469.       init(taskname, applname, icon_menu, wimp_version, message_list) ;
  470.  
  471.    //
  472.    // create icon on iconbar
  473.    //
  474.  
  475.       strcpy (icon_name, spritename) ;
  476.       IconData icon_data ;
  477.       icon_data.indirectsprite.name = icon_name ;
  478.       icon_data.indirectsprite.spritearea = spr_area ;
  479.       icon_data.indirectsprite.nameisname = 1 ;
  480.  
  481.       iconbar_icon = new Icon (priority, position, 0, 0, 70, 76,
  482.                               (Icon::iconflags)(Icon::ISPRITE + Icon::INDIRECT + Icon::IHCENTRE + (Icon::IBTYPE * 3)),
  483.                               &icon_data) ;
  484.       icon_handle = iconbar_icon->handle ;
  485.       }
  486. #ifdef __EASY_C
  487.    catch (TaskError t)
  488.       {
  489.       _kernel_oserror err ;
  490.       err.errnum = 0 ;
  491.       strcpy (err.errmess, t.buf) ;
  492.       _kernel_raise_error (&err) ;
  493.       if (t.fatal)
  494.          exit(t.fatal) ;
  495.       }
  496.  
  497.    catch (_kernel_oserror *e)
  498.       {
  499.       _kernel_swi_regs r ;
  500.       r.r[0] = (int)e ;
  501.       r.r[1] = 0 ;
  502.       r.r[2] = (int)program ;
  503.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  504.       exit (1) ;
  505.       }
  506.  
  507.    catch (char *s)
  508.       {
  509.       _kernel_oserror err ;
  510.       _kernel_swi_regs r ;
  511.       err.errnum = 0 ;
  512.       strcpy (err.errmess, lookup(s)) ;
  513.       r.r[0] = (int)&err ;
  514.       r.r[1] = 0 ;
  515.       r.r[2] = (int)program ;
  516.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  517.       exit (1) ;
  518.       }
  519. #endif
  520.    }
  521.  
  522. //
  523. // create a task without an icon on the icon bar
  524. //
  525.  
  526. Task::Task (char *taskname, char *applname, int wimp_version, int *message_list)
  527.    {
  528.    char buffer[256] ;
  529.    _kernel_swi_regs r ;
  530.    _kernel_osfile_block b ;
  531.    _kernel_oserror *err ;
  532.    char resources[256] ;
  533.  
  534. #ifdef __EASY_C
  535.    try
  536. #endif
  537.       {
  538.       init(taskname, applname, NULL, wimp_version, message_list) ;
  539.       }
  540. #ifdef __EASY_C
  541.    catch (TaskError t)
  542.       {
  543.       _kernel_oserror err ;
  544.       err.errnum = 0 ;
  545.       strcpy (err.errmess, t.buf) ;
  546.       _kernel_raise_error (&err) ;
  547.       if (t.fatal)
  548.          exit(t.fatal) ;
  549.       }
  550.  
  551.    catch (_kernel_oserror *e)
  552.       {
  553.       _kernel_swi_regs r ;
  554.       r.r[0] = (int)e ;
  555.       r.r[1] = 0 ;
  556.       r.r[2] = (int)program ;
  557.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  558.       exit (1) ;
  559.       }
  560.  
  561.    catch (char *s)
  562.       {
  563.       _kernel_oserror err ;
  564.       _kernel_swi_regs r ;
  565.       err.errnum = 0 ;
  566.       strcpy (err.errmess, lookup(s)) ;
  567.       r.r[0] = (int)&err ;
  568.       r.r[1] = 0 ;
  569.       r.r[2] = (int)program ;
  570.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  571.       exit (1) ;
  572.       }
  573. #endif
  574.    }
  575.  
  576.  
  577. Task::Task (char *taskname, char *applname, Icon *iconbar, char *icon_menu, int priority, int position, int wimp_version, int *message_list)
  578.    {
  579.    char buffer[256] ;
  580.    _kernel_swi_regs r ;
  581.    _kernel_osfile_block b ;
  582.    _kernel_oserror *err ;
  583.    char resources[256] ;
  584.  
  585. #ifdef __EASY_C
  586.    try
  587. #endif
  588.       {
  589.       init(taskname, applname, icon_menu, wimp_version, message_list) ;
  590.       iconbar_icon = iconbar ;
  591.       icon_handle = iconbar->handle ;
  592.       }
  593. #ifdef __EASY_C
  594.    catch (TaskError t)
  595.       {
  596.       _kernel_oserror err ;
  597.       err.errnum = 0 ;
  598.       strcpy (err.errmess, t.buf) ;
  599.       _kernel_raise_error (&err) ;
  600.       if (t.fatal)
  601.          exit(t.fatal) ;
  602.       }
  603.  
  604.    catch (_kernel_oserror *e)
  605.       {
  606.       _kernel_swi_regs r ;
  607.       r.r[0] = (int)e ;
  608.       r.r[1] = 0 ;
  609.       r.r[2] = (int)program ;
  610.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  611.       exit (1) ;
  612.       }
  613.  
  614.    catch (char *s)
  615.       {
  616.       _kernel_oserror err ;
  617.       _kernel_swi_regs r ;
  618.       err.errnum = 0 ;
  619.       strcpy (err.errmess, lookup(s)) ;
  620.       r.r[0] = (int)&err ;
  621.       r.r[1] = 0 ;
  622.       r.r[2] = (int)program ;
  623.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  624.       exit (1) ;
  625.       }
  626. #endif
  627.    }
  628.  
  629. void Task::init(char *taskname, char *applname, char *iconmenu, int wimp_version, int *message_list)
  630.    {
  631.    _kernel_swi_regs r ;
  632.    _kernel_oserror *e ;
  633.    int iblock[3] ;
  634.    int oblock[2] ;
  635.    char buffer[256] ;
  636.    _kernel_osfile_block b ;
  637.    char resources[256] ;
  638.  
  639.    dragger = NULL ;            // no dragger yet
  640.    object_dragger = NULL ;            // no dragger yet
  641.    waiting = 0 ;
  642.    receivers = NULL ;
  643.    last_receiver = NULL ;
  644.    windows = NULL ;
  645.    last_window = NULL ;
  646.    poll_mask = 1 ;                   // no null events by default
  647.    r.r[0] = (int)iblock ;
  648.    r.r[1] = (int)oblock ;
  649.    iblock[0] = 4 ;
  650.    iblock[1] = 5 ;
  651.    iblock[2] = -1 ;
  652.    if ((e = _kernel_swi (OS_ReadVduVariables, &r, &r)) != NULL)
  653.       throw (e) ;
  654.    xeigfactor = oblock[0] ;
  655.    yeigfactor = oblock[1] ;
  656.    open_fonts = NULL ;
  657.    num_open_fonts = max_open_fonts = 0 ;
  658.    control_threads = NULL ;
  659.    deferred_deletions = NULL ;
  660.  
  661.    main_task = this ;
  662.    FILE *fp ;
  663.    sprintf (resources, "<%s$Dir>.Resources.Country", applname) ;
  664.    if ((fp = fopen (resources, "r")) == NULL)
  665. #ifdef __EASY_C
  666.       throw TaskError (1,"Unable to open resources country file %s",resources) ;
  667. #else
  668.      {
  669.      char str[256] ;
  670.      sprintf (str,"Unable to open resources country file %s",resources) ;
  671.       __throw (str) ;
  672.      }
  673. #endif
  674.    if (fscanf (fp,"%s",country) != 1)
  675.       throw ("Unable to read country name") ;
  676.    fclose (fp) ;
  677.    program = applname ;
  678.    application = applname ;
  679. //
  680. // read and initialise sprites
  681. //
  682.  
  683.    sprintf (buffer,"<%s$Dir>.!Sprites",applname) ;
  684.    spr_area = (sprite_area*)1 ;
  685.    int er = _kernel_osfile (5, buffer, &b) ;
  686.    if (er == 1)
  687.       {
  688.       spr_area = (sprite_area*)new char[b.start+4] ;
  689.       spr_area->size = b.start+4 ;
  690.       spr_area->number = 0 ;
  691.       spr_area->sproff = 16 ;
  692.       spr_area->freeoff = 16 ;
  693.       r.r[0] = 10 + 256 ;
  694.       r.r[1] = (int)spr_area ;
  695.       r.r[2] = (int)buffer ;
  696.       if ((e = _kernel_swi (OS_SpriteOp, &r, &r)) != NULL)
  697.          throw (e) ;
  698.       }
  699.  
  700. //
  701. // initialise the wimp task
  702. //
  703.  
  704.    r.r[0] = wimp_version ;
  705.    r.r[1] = 'T' +
  706.            ('A' << 8) +
  707.            ('S' << 16) +
  708.            ('K' << 24);
  709.    r.r[2] = (int) taskname;
  710.    r.r[3] = (int) message_list ;
  711.    if ((e = _kernel_swi (Wimp_Initialise, &r, &r)) != NULL)
  712.       throw (e) ;
  713.    handle = r.r[1] ;
  714.  
  715. //
  716. // read in the messages from the resources file
  717. //
  718.  
  719.    sprintf (buffer,"<%s$Dir>.Resources.%s.Messages",applname, country) ;
  720.    messages = new MsgTrans (buffer) ;
  721.  
  722.  
  723. //
  724. // read in the templates
  725. //
  726.    sprintf (buffer,"<%s$Dir>.Resources.%s.Templates",applname, country) ;
  727.    templates = new Template (this,buffer) ;
  728.  
  729.  
  730. //
  731. // read in all the menus from the resources file
  732. //
  733.  
  734.    sprintf (buffer,"<%s$Dir>.Resources.%s.Menus",applname, country) ;
  735.    menus = new MenuSet (this, buffer) ;
  736.  
  737.    if (iconmenu != NULL)
  738.       {
  739.       iconbar_menu = menus->find (iconmenu) ;
  740.       if (iconbar_menu == NULL)
  741.       throw ("No such menu") ;
  742.       }
  743.    else
  744.       iconbar_menu = NULL ;
  745.  
  746.    if (find_template ("debug") != NULL)
  747.       debug = new DebugWin (this) ;
  748.    else
  749.       debug = NULL ;
  750.  
  751. // allocate the thread manager
  752.  
  753.    thread_manager = new ThreadManager ;
  754.  
  755. // initialise the thread package
  756.  
  757.    thread_init(thread_manager) ;
  758.  
  759.  
  760. // trap signals to make them stop the threads
  761.  
  762.    signal (SIGABRT, signal_handler) ;
  763.    signal (SIGILL, signal_handler) ;
  764.    signal (SIGINT, signal_handler) ;
  765.    signal (SIGSEGV, signal_handler) ;
  766.    signal (SIGSTAK, signal_handler) ;
  767.    signal (SIGTERM, signal_handler) ;
  768.    }
  769.  
  770.  
  771. Task::~Task()
  772.    {
  773.    Window *w, *nw ;
  774.  
  775.    for (w = windows ; w != NULL ; w = nw)
  776.       {
  777.       nw = w->next ;
  778.       delete w ;
  779.       }
  780.    for (int i = 0 ; i < max_open_fonts ; i++)
  781.       if (open_fonts[i] != -1)
  782.          close_font (open_fonts[i]) ;
  783.    }
  784.  
  785. //
  786. // spawn a new task, returning the task handle for it
  787. //
  788.  
  789. int Task::spawn (char *command...)
  790.    {
  791.    va_list arg ;
  792.    char buf[1024] ;
  793.    _kernel_swi_regs r ;
  794.    _kernel_oserror *e ;
  795.    thread_manager->stop_threads() ;
  796.    va_start (arg, command) ;
  797.    vsprintf (buf, command, arg) ;
  798.    r.r[0] = (int)buf ;
  799.    if ((e = _kernel_swi (Wimp_StartTask, &r, &r)) != NULL)
  800.       {
  801.       thread_manager->resume_threads() ;
  802.       throw (e) ;
  803.       }
  804.    thread_manager->resume_threads() ;
  805.    return r.r[0] ;
  806.    }
  807.  
  808.  
  809. //
  810. // add a window to the start of the task windows list
  811. //
  812.  
  813. void Task::add_window (Window *w)
  814.    {
  815.    if (windows == NULL)
  816.       windows = last_window = w ;
  817.    else
  818.       {
  819.       last_window->next = w ;
  820.       w->prev = last_window ;
  821.       last_window = w ;
  822.       }
  823.    }
  824.  
  825. void Task::remove_window (Window *w)
  826.    {
  827.    if (w->prev == NULL)
  828.       windows = w->next ;
  829.    else
  830.       w->prev->next = w->next ;
  831.    if (w->next == NULL)
  832.       last_window = w->prev ;
  833.    else
  834.       w->next->prev = w->prev ;
  835.    }
  836.  
  837. //
  838. // remove a window and put it on the deleted queue to be really deleted (destructor called)
  839. // when thread finishes.  The window will actually be removed from the task when the
  840. // destructor is called
  841. //
  842.  
  843.  
  844. void Task::delete_window (Window *w)
  845.    {
  846.    delete_deferred(w) ;
  847.    }
  848.  
  849. void Task::delete_deferred (DeferredDelete *d)
  850.    {
  851.    d->next = deferred_deletions ;
  852.    deferred_deletions = d ;
  853.    }
  854.  
  855.  
  856. Window *Task::find_window (int handle)
  857.    {
  858.    Window *w, *w1 ;
  859.  
  860.    for (w = windows ; w != NULL ; w = w->next)
  861.       if ((w1 = w->find_window (handle)) != NULL)
  862.          return w1 ;
  863.  
  864. // no such window
  865.    return NULL ;
  866.    }
  867.  
  868. Task::receiver *Task::find_receiver (int message, int your_ref)
  869.    {
  870.    receiver *r ;
  871.    for (r = last_receiver ; r != NULL ; r = r->prev)                 // search backwards
  872.        if (message == r->message && r->channel->accept (your_ref))
  873.           return r ;
  874.    return NULL ;
  875.    }
  876.  
  877. void Task::run()
  878.    {
  879. #ifdef __EASY_C
  880.    try
  881. #endif
  882.       {
  883.       _kernel_oserror *e ;
  884.       _kernel_swi_regs r ;
  885.       int buf[256/sizeof(int)] ;           // event buffer
  886.       DeferredDelete *next ;
  887.  
  888.       running = 1 ;
  889.       threads_running = 0 ;
  890. //      debug->print ("running task, poll_mask = %d",poll_mask) ;
  891.       while (running)
  892.          {
  893.          r.r[0] = thread_manager->num_running_threads == 0 ? poll_mask : poll_mask & ~(1 << ENULL);
  894.          r.r[1] = (int)buf ;
  895.          if ((e = _kernel_swi (Wimp_Poll, &r, &r)) != NULL)
  896.             throw (e) ;
  897.          if (r.r[0] == EREDRAW)
  898.             {
  899.             Window *w ;
  900.             w = find_window(buf[0]) ;
  901.             if (w != NULL)
  902.                w->redraw() ;
  903.             continue ;
  904.             }
  905.          if (r.r[0] != ENULL)
  906.             {
  907.             last_event = (Task::events)r.r[0] ;
  908.             memcpy (last_event_data, buf, sizeof buf) ;
  909.             }
  910.          if (thread_manager->num_running_threads > 0 || r.r[0] != ENULL)      // any threads to run
  911.             {
  912.             threads_running = 1 ;
  913.             if (r.r[0] != ENULL)                      // need to process event?
  914.                {
  915. //               if (r.r[0] != EREDRAW)
  916. //                  debug->print ("spawning control thread for event %d",r.r[0]) ;
  917.                spawn_control_thread(r.r[0], buf) ;              // process the event in a thread
  918.                }
  919.             thread_manager->run (5) ;                // run all threads
  920. //            if (r.r[0] != EREDRAW && r.r[0] != ENULL)
  921. //               debug->print ("end of run, event = %d",r.r[0]) ;
  922.             threads_running = 0 ;
  923.             }
  924.          while (deferred_deletions != NULL)
  925.             {
  926.             next = deferred_deletions->next ;
  927.             delete deferred_deletions ;         // has virtual destructor, so real object will be deleted
  928.             deferred_deletions = next ;
  929.             }
  930.          }
  931.       }
  932. #ifdef __EASY_C
  933.    catch (TaskError t)
  934.       {
  935.       _kernel_oserror err ;
  936.       _kernel_swi_regs r ;
  937.       err.errnum = 0 ;
  938.       strcpy (err.errmess, lookup(t.buf)) ;
  939.       r.r[0] = (int)&err ;
  940.       r.r[1] = 0 ;
  941.       r.r[2] = (int)program ;
  942.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  943.       if (t.fatal)
  944.          exit(t.fatal) ;
  945.       }
  946.  
  947.    catch (_kernel_oserror *e)
  948.       {
  949.       _kernel_swi_regs r ;
  950.       r.r[0] = (int)e ;
  951.       r.r[1] = 0 ;
  952.       r.r[2] = (int)program ;
  953.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  954.       exit (1) ;
  955.       }
  956.    catch (char *s)
  957.       {
  958.       _kernel_oserror err ;
  959.       _kernel_swi_regs r ;
  960.       err.errnum = 0 ;
  961.       strcpy (err.errmess, lookup(s)) ;
  962.       r.r[0] = (int)&err ;
  963.       r.r[1] = 0 ;
  964.       r.r[2] = (int)program ;
  965.       _kernel_swi (Wimp_ReportError, &r, &r) ;
  966.       exit (1) ;
  967.       }
  968. #endif
  969.    }
  970.  
  971.  
  972. void Task::send_message (events event, int action, int &task, int &my_ref, int your_ref, int data_length, void *data, int icon)
  973.    {
  974.    _kernel_swi_regs r ;
  975.    _kernel_oserror *e ;
  976.    int block [256/sizeof(int)] ;
  977.    r.r[0] = (int)event ;
  978.    r.r[1] = (int)block ;
  979.    r.r[2] = task ;
  980.    r.r[3] = icon ;
  981.    if (data_length < 0 || data_length > (256-20))
  982.       throw ("Illegal message length") ;
  983.    block[0] = ((data_length + 3) & ~3) + 20 ;
  984.    block[3] = your_ref ;
  985.    block[4] = action ;
  986.    memcpy (&block[5], data, data_length) ;
  987.    if ((e = _kernel_swi (Wimp_SendMessage, &r, &r)) != NULL)
  988.       throw (e) ;
  989.    my_ref = block[2] ;
  990.    }
  991.  
  992. void Task::sleep (ThreadResource *thread, int pri)
  993.    {
  994.    thread_manager->sleep (thread,pri) ;
  995.    }
  996.  
  997. void Task::sleep (int time)
  998.    {
  999.    thread_manager->sleep (time) ;
  1000.    }
  1001.  
  1002. void Task::yield ()
  1003.    {
  1004.    thread_manager->yield () ;
  1005.    }
  1006.  
  1007.  
  1008. void Task::exit (int status)
  1009.    {
  1010.    thread_manager->exit() ;
  1011.    _kernel_swi_regs r ;
  1012.     r.r[0] = handle ;
  1013.     r.r[1] = 'T' +
  1014.             ('A' << 8) +
  1015.             ('S' << 16) +
  1016.             ('K' << 24);
  1017.    _kernel_swi (Wimp_CloseDown, &r, &r) ;
  1018.    ::exit(status) ;
  1019.    }
  1020.  
  1021. void Task::print (char *format,...)
  1022.    {
  1023.    va_list arg ;
  1024.    _kernel_oserror err ;
  1025.    _kernel_swi_regs r ;
  1026.    err.errnum = 0 ;
  1027.    va_start (arg,format) ;
  1028.    vsprintf (err.errmess, format, arg) ;
  1029.    r.r[0] = (int)&err ;
  1030.    r.r[1] = 0 ;
  1031.    r.r[2] = (int)program ;
  1032.    _kernel_swi (Wimp_ReportError, &r, &r) ;
  1033.    }
  1034.  
  1035. //
  1036. // icon bar click
  1037. //
  1038.  
  1039. void Task::click (int x, int y, int buttons, int icon)
  1040.    {
  1041.    }
  1042.  
  1043. char *Task::get_iconbar_menu(int icon)
  1044.    {
  1045.    return NULL ;
  1046.    }
  1047.  
  1048. void Task::pre_menu(Menu *menu)
  1049.    {
  1050.    }
  1051.  
  1052.  
  1053. void Task::menu (MenuItem items[])
  1054.    {
  1055.    }
  1056.  
  1057.  
  1058. void Task::register_drag (Window *dragger, int id, bool dragging_sprite)
  1059.    {
  1060.    if (this->dragger != NULL)
  1061.       throw ("Already dragging")  ;
  1062.    this->dragger = dragger ;
  1063.    this->dragging_sprite = dragging_sprite ;
  1064.    dragger_id = id ;
  1065.    }
  1066.  
  1067. void Task::register_object_drag (Object *dragger, int id, bool dragging_sprite)
  1068.    {
  1069.    if (this->object_dragger != NULL)
  1070.       throw ("Already dragging an object")  ;
  1071.    this->dragging_sprite = dragging_sprite ;
  1072.    this->object_dragger = dragger ;
  1073.    object_dragger_id = id ;
  1074.    }
  1075.  
  1076.  
  1077. //
  1078. // add a receiver to the end of the receiver queue
  1079. //
  1080.  
  1081. void Task::add_receiver (Channel *channel, int message)
  1082.    {
  1083.    receiver *r ;
  1084.    r = new receiver (channel, message) ;
  1085.    if (receivers == NULL)
  1086.       receivers = last_receiver = r ;
  1087.    else
  1088.       {
  1089.       last_receiver->next = r ;
  1090.       r->prev = last_receiver ;
  1091.       last_receiver = r ;
  1092.       }
  1093.    }
  1094.  
  1095. void Task::remove_receiver (Channel *channel, int message)
  1096.    {
  1097.    for (receiver *r = receivers ; r != NULL ; r = r->next)
  1098.       if (r->channel == channel && r->message == message)
  1099.          {
  1100.          if (r->prev == NULL)
  1101.             receivers = r->next ;
  1102.          else
  1103.             r->prev->next = r->next ;
  1104.          if (r->next == NULL)
  1105.             last_receiver = r->prev ;
  1106.          else
  1107.             r->next->prev = r->prev ;
  1108.          delete r ;
  1109.          }
  1110.    }
  1111.  
  1112. int Task::open_font (char *name, int xsize, int ysize)
  1113.    {
  1114.    _kernel_swi_regs r ;
  1115.    _kernel_oserror *e ;
  1116.    r.r[1] = (int)name ;
  1117.    r.r[2] = xsize * 16 ;
  1118.    r.r[3] = ysize * 16 ;
  1119.    r.r[4] = 0 ;
  1120.    r.r[5] = 0 ;
  1121.    if ((e = _kernel_swi (Font_FindFont, &r, &r)) != NULL)
  1122.       throw (e) ;
  1123.    int font_handle = r.r[0] ;
  1124.    if (num_open_fonts == max_open_fonts)
  1125.       {
  1126.       if (open_fonts == NULL)
  1127.          open_fonts = (int*)malloc (sizeof (int) * 10) ;
  1128.       else
  1129.          open_fonts = (int*)realloc (open_fonts, (max_open_fonts + 10) * sizeof (int)) ;
  1130.       if (open_fonts == NULL)
  1131.       throw ("Out of memory") ;
  1132.       for (int i = 0 ; i < 10 ; i++)
  1133.          open_fonts[max_open_fonts+i] = -1 ;
  1134.       max_open_fonts += 10 ;
  1135.       }
  1136.    for (int i = 0 ; i < max_open_fonts ; i++)
  1137.       if (open_fonts[i] == -1)
  1138.          {
  1139.          open_fonts[i] = font_handle ;
  1140.          num_open_fonts++ ;
  1141.          break ;
  1142.          }
  1143.    return font_handle ;
  1144.    }
  1145.  
  1146. void Task::close_font (int handle)
  1147.    {
  1148.    _kernel_swi_regs r ;
  1149.    _kernel_oserror *e ;
  1150.    r.r[0] = handle ;
  1151.    if ((e = _kernel_swi (Font_LoseFont, &r, &r)) != NULL)
  1152.       throw (e) ;
  1153.    for (int i = 0 ; i < max_open_fonts ; i++)
  1154.       if (open_fonts[i] == handle)
  1155.          {
  1156.          open_fonts[i] = -1 ;
  1157.          num_open_fonts-- ;
  1158.          return ;
  1159.          }
  1160.       throw ("Font handle not found in task memory") ;
  1161.    }
  1162.  
  1163. //
  1164. // spawn a new control thread
  1165. //
  1166.  
  1167. void Task::spawn_control_thread(int event, int *buf)
  1168.    {
  1169.    ControlThread *t ;
  1170.    t = new ControlThread (this, event, buf) ;
  1171.    if (event == EREDRAW || event == ESENDWANTACK)             // redraw request?
  1172.       t->setpriority(40) ;
  1173.    else
  1174.       t->setpriority(60) ;
  1175.    t->start() ;
  1176.    }
  1177.  
  1178.  
  1179.  
  1180. void Task::enter_critical()
  1181.    {
  1182.    thread_disable_ints() ;
  1183.    }
  1184.  
  1185. void Task::exit_critical()
  1186.    {
  1187.    thread_enable_ints() ;
  1188.    }
  1189.  
  1190. void *Task::find_sprite (char *name)
  1191.    {
  1192.    _kernel_swi_regs r ;
  1193.    _kernel_oserror *e ;
  1194.    if ((e = _kernel_swi (Wimp_BaseOfSprites, &r, &r)) != NULL)
  1195.       throw (e) ;
  1196.    int ram = r.r[1] ;
  1197.    int p ;
  1198.    int num_sprites ;
  1199.    int i ;
  1200.    p = ram + *((int*)(ram + 8)) ;         // get address of first sprite
  1201.    num_sprites = ram + *((int*)(ram + 4)) ;
  1202.    for (i = 0 ; i < num_sprites ; i++)
  1203.       {
  1204.       if (strncmp ((char*)(p + 4), name, 12) == 0)
  1205.          return (void*)p ;
  1206.       p += *(int*)p ;
  1207.       }
  1208.    return NULL ;
  1209.    }
  1210.  
  1211.  
  1212. void Task::poll_word_non_zero (int *poll_word, int contents)
  1213.    {
  1214.    }
  1215.  
  1216. void Task::set_menu (Menu *menu, Icon *icon)
  1217.    {
  1218.    current_menu = menu ;
  1219.    current_menu_icon = icon ;
  1220.    }
  1221.  
  1222. void Task::set_menu (Menu *menu, Object *object)
  1223.    {
  1224.    current_menu = menu ;
  1225.    current_menu_object = object ;
  1226.    }
  1227.  
  1228. void Task::set_menu (Menu *menu, Window *window)
  1229.    {
  1230.    current_menu = menu ;
  1231.    current_menu_window = window ;
  1232.    }
  1233.  
  1234. char *Task::help (int mx, int my, int buttons, int window, int icon)
  1235.    {
  1236.    return NULL ;
  1237.    }
  1238.  
  1239. void Task::show_threads()
  1240.    {
  1241.    thread_manager->show_threads() ;
  1242.    }
  1243. //
  1244. // TaskError class.  Used to carry exceptions to a catch handler for errors
  1245. //
  1246.  
  1247.  
  1248. TaskError::TaskError (int f, char *format...)
  1249.    {
  1250.    va_list arg ;
  1251.    va_start (arg,format) ;
  1252.    vsprintf (buf, format, arg) ;
  1253.    fatal = f ;
  1254.    }
  1255.  
  1256. void print (char *format,...)
  1257.    {
  1258.    va_list arg ;
  1259.    _kernel_oserror err ;
  1260.    _kernel_swi_regs r ;
  1261.    err.errnum = 0 ;
  1262.    va_start (arg,format) ;
  1263.    vsprintf (err.errmess, format, arg) ;
  1264.    r.r[0] = (int)&err ;
  1265.    r.r[1] = 0 ;
  1266.    r.r[2] = (int)"Wimp Program" ;
  1267.    _kernel_swi (Wimp_ReportError, &r, &r) ;
  1268.    }
  1269.  
  1270. #ifndef __EASY_C
  1271.  
  1272. // this is defined because of a 'sorry not implemented' error from cfront.
  1273.  
  1274. char *Task::lookup (char *token)
  1275.    {
  1276.    char *s ;
  1277.    if ((s = messages->lookup(token)) != NULL)
  1278.       return s ;
  1279.    return token ;
  1280.    }
  1281.  
  1282.  
  1283. void __throw (_kernel_oserror *e)
  1284.    {
  1285.    _kernel_swi_regs r ;
  1286.    r.r[0] = (int)e ;
  1287.    r.r[1] = 0 ;
  1288.    r.r[2] = (int)main_task->program ;
  1289.    _kernel_swi (Wimp_ReportError, &r, &r) ;
  1290.    main_task->exit(1) ;
  1291.    }
  1292.  
  1293. void __throw (char *s)
  1294.    {
  1295.    _kernel_oserror err ;
  1296.    _kernel_swi_regs r ;
  1297.    err.errnum = 0 ;
  1298.    strcpy (err.errmess, s) ;
  1299.    r.r[0] = (int)&err ;
  1300.    r.r[1] = 0 ;
  1301.    r.r[2] = (int)main_task->program ;
  1302.    _kernel_swi (Wimp_ReportError, &r, &r) ;
  1303.    main_task->exit (1) ;
  1304.    }
  1305.  
  1306. void werr (int fatal, char *format...)
  1307.    {
  1308.    _kernel_oserror err ;
  1309.    _kernel_swi_regs r ;
  1310.    va_list arg ;
  1311.    va_start (arg, format) ;
  1312.    vsprintf (err.errmess,format,arg) ;
  1313.    err.errnum = 0 ;
  1314.    r.r[0] = (int)&err ;
  1315.    r.r[1] = 0 ;
  1316.    r.r[2] = (int)main_task->program ;
  1317.    _kernel_swi (Wimp_ReportError, &r, &r) ;
  1318.    if (fatal)
  1319.       main_task->exit (1) ;
  1320.    }
  1321.  
  1322. #endif
  1323.