home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 2
/
AUCD2.iso
/
program
/
vista.arc
/
c
/
task
< prev
next >
Wrap
Text File
|
1996-02-01
|
36KB
|
1,323 lines
// **************************************************************************
// Copyright 1996 David Allison
//
// VV VV IIIIII SSSSS TTTTTT AA
// VV VV II SS TT AA AA
// VV VV II SSSS TT AA AA
// VV VV II SS TT AAAAAAAA
// VV IIIIII SSSS TT AA AA
//
// MULTI-THREADED C++ WIMP CLASS LIBRARY
// for RISC OS
// **************************************************************************
//
// P U B L I C D O M A I N L I C E N C E
// -------------------------------------------
//
// This library is copyright. You may not sell the library for
// profit, but you may sell products which use it providing
// those products are presented as executable code and are not
// libraries themselves. The library is supplied without any
// warranty and the copyright owner cannot be held responsible for
// damage resulting from failure of any part of this library.
//
// See the User Manual for details of the licence.
//
// *************************************************************************
//
// c.task
//
#include "Vista:task.h"
#include <kernel.h>
#include <swis.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
ControlThread::ControlThread(Task *t, int event, int *buf)
: Thread ("control")
{
task = t ;
next = NULL ;
init (event, buf) ;
}
ControlThread::~ControlThread()
{
}
void ControlThread::init(int event, int *buf)
{
this->event = event ;
memcpy (this->buf, buf, sizeof (this->buf)) ;
}
void ControlThread::run()
{
int caught = 0 ;
Window *w ;
_kernel_oserror err ;
_kernel_oserror *e ;
_kernel_swi_regs r ;
int adjust_hit ; // adjust was hit on menu
Object *object ;
#ifdef __EASY_C
try
#endif
{
switch (event)
{
case Task::ENULL:
break ;
case Task::EREDRAW: /* this is handled as a special case */
#if 0
w = task->find_window (buf[0]) ;
if (w == NULL)
break ;
w->redraw() ;
#endif
break ;
case Task::EOPEN:
w = task->find_window (buf[0]) ;
if (w == NULL)
break ;
w->open(buf[1],buf[2],buf[3],buf[4], buf[5], buf[6], buf[7]) ;
break ;
case Task::ECLOSE:
w = task->find_window (buf[0]) ;
if (w == NULL)
break ;
w->close() ;
break ;
case Task::EPTRLEAVE:
case Task::EPTRENTER:
w = task->find_window (buf[0]) ;
if (w == NULL)
break ;
w->pointer (event == Task::EPTRENTER) ;
break ;
case Task::EBUT:
if (buf[3] >= 0) // in a window?
{
w = task->find_window (buf[3]) ; // find the window
if (w == NULL)
break ;
if (buf[2] & Task::BMID) // menu button?
{
Icon *icon ;
bool found = false ;
if (buf[4] != -1 && (icon = w->find_icon(buf[4])) != NULL) // find icon
{
task->current_menu = icon->display_menu (buf[0], buf[1], buf[2], buf[4]) ;
if (task->current_menu != NULL)
{
found = true ;
task->current_menu_icon = icon ;
}
}
if (!found && (object = w->find_object (buf[0], buf[1])) != NULL) // find object
{
task->current_menu = object->display_menu (buf[0], buf[1], buf[2], buf[4]) ;
if (task->current_menu != NULL)
{
found = true ;
task->current_menu_object = object ;
}
}
if (!found)
{
task->current_menu = w->display_menu (buf[0], buf[1], buf[2], buf[4]) ;
task->current_menu_window = w ;
}
}
else
{
if (buf[4] != -1) // on an icon?
{
Icon *icon ;
if ((icon = w->find_icon(buf[4])) != NULL) // find it
{
icon->click (buf[0], buf[1], buf[2], buf[4]) ; // say clicked
break ;
}
}
if ((object = w->find_object (buf[0], buf[1])) != NULL)
{
if (buf[2] & (4 * 16 + 16))
object->drag (buf[0], buf[1], buf[2]) ;
else if (buf[2] & (4 + 1))
object->double_click (buf[0], buf[1], buf[2]) ;
else
object->click (buf[0], buf[1], buf[2]) ;
}
else
w->click(buf[0], buf[1], buf[2], buf[4]) ; // tell window
}
}
else if (buf[3] == -2) // icon bar
{
task->current_menu_window = NULL ; // no window
task->current_menu_icon = NULL ; // no icon
task->current_menu_object = NULL ; // no object
if (buf[2] & Task::BMID)
{
if (task->iconbar_menu != NULL)
{
task->current_menu = task->iconbar_menu ;
task->pre_menu (task->iconbar_menu) ; // any user modifications
task->iconbar_menu->iconbar_adjust (buf[0], buf[1]) ;
task->iconbar_menu->open(buf[0] - 48, buf[1]) ;
}
else
{
char *menu_name = task->get_iconbar_menu (buf[4]) ;
if (menu_name != NULL)
{
task->current_menu = task->menus->find (menu_name) ;
task->current_menu->iconbar_adjust (buf[0], buf[1]) ;
task->current_menu->open (buf[0] - 48, buf[1]) ;
}
}
}
else
task->click (buf[0], buf[1], buf[2], buf[4]) ;
}
break ;
case Task::EUSERDRAG:
if (task->dragging_sprite)
{
_kernel_swi (DragASprite_Stop, &r, &r) ;
task->dragging_sprite = false ;
}
if (task->object_dragger != NULL)
{
task->object_dragger->end_drag (buf[0], buf[1], buf[2], buf[3], task->object_dragger_id) ;
task->object_dragger = NULL ;
}
if (task->dragger != NULL)
{
task->dragger->drag(buf[0], buf[1], buf[2], buf[3],task->dragger_id) ;
task->dragger = NULL ;
}
break ;
case Task::EKEY:
w = task->find_window (buf[0]) ;
if (w == NULL)
break ;
if (buf[1] != -1) // pressed in an icon?
{
Icon *icon ;
if ((icon = w->find_icon(buf[1])) != NULL) // find it
{
icon->key (buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]) ; // say key pressed
break ;
}
}
if ((object = w->find_object (buf[0], buf[1])) != NULL)
object->key (buf[2], buf[3], buf[4], buf[5], buf[6]) ;
else
w->key (buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]) ;
break ;
case Task::EMENU:
{
int pointer_info[5] ;
r.r[1] = (int)pointer_info ;
if ((e = _kernel_swi (Wimp_GetPointerInfo, &r, &r)) != NULL)
throw (e) ;
adjust_hit = pointer_info[2] & 1 ;
if (!task->current_menu->invalid_selection(buf))
{
MenuItem *items = task->current_menu->selection (buf) ;
if (task->current_menu_icon != NULL)
task->current_menu_icon->menu (items) ;
else if (task->current_menu_object != NULL)
task->current_menu_object->menu (items) ;
else if (task->current_menu_window != NULL)
task->current_menu_window->menu (items) ;
else
task->menu (items) ;
}
if (adjust_hit)
task->current_menu->open (0,0) ;
break ;
}
case Task::ESCROLL:
w = task->find_window (buf[0]) ;
if (w == NULL)
break ;
w->scroll (buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]) ;
break ;
case Task::ELOSECARET:
case Task::EGAINCARET:
w = task->find_window (buf[0]) ;
if (w == NULL)
break ;
w->caret (r.r[0] == Task::EGAINCARET, buf[1], buf[2], buf[3], buf[4], buf[5]) ;
break ;
case Task::EPOLLNONZERO:
task->poll_word_non_zero ((int *)buf[0], buf[1]) ;
break ;
case Task::ESEND:
case Task::ESENDWANTACK:
switch (buf[4])
{
case Task::Message_Quit: // quit message
task->exit() ;
break ;
case Task::Message_ModeChange: // mode change message
{
int iblock[3] ;
int oblock[2] ;
for (w = task->windows ; w != NULL ; w = w->next) // tell windows
w->mode_change() ;
r.r[0] = 0 ; // see PRM 3-416
r.r[1] = (int)"" ;
r.r[2] = 0x10 ;
r.r[3] = -1 ;
r.r[4] = -1 ;
if ((e = _kernel_swi (Font_Paint, &r, &r)) != NULL)
throw (e) ;
r.r[0] = (int)iblock ;
r.r[1] = (int)oblock ;
iblock[0] = 4 ;
iblock[1] = 5 ;
iblock[2] = -1 ;
if ((e = _kernel_swi (OS_ReadVduVariables, &r, &r)) != NULL)
throw (e) ;
task->xeigfactor = oblock[0] ;
task->yeigfactor = oblock[1] ;
break ;
}
case Task::Message_MenuWarning: // menu warning
{
MenuItem *items = task->current_menu->selection (buf+8) ;
if (task->current_menu_icon != NULL)
task->current_menu_icon->menu (items) ;
else if (task->current_menu_object != NULL)
task->current_menu_object->menu (items) ;
else if (task->current_menu_window != NULL)
task->current_menu_window->menu (items) ;
else
task->menu (items) ;
break ;
}
case Task::Message_HelpRequest:
{
char *help_reply = NULL ;
w = task->find_window (buf[8]) ;
if (w != NULL)
{
if (buf[9] != -1) // pressed in an icon?
{
Icon *icon ;
if ((icon = w->find_icon(buf[9])) != NULL) // find it
help_reply = icon->help (buf[5], buf[6], buf[7]) ;
}
if (help_reply == NULL && (object = w->find_object (buf[5], buf[6])) != NULL)
help_reply = object->help (buf[5], buf[6], buf[7]) ;
if (help_reply == NULL)
help_reply = w->help (buf[5], buf[6], buf[7], buf[9]) ;
}
if (help_reply == NULL)
help_reply = task->help (buf[5],buf[6],buf[7],buf[8],buf[9]) ;
if (help_reply != NULL)
{
int len = strlen (help_reply) + 1 ; // allow of 0 at end
int my_ref ;
task->send_message (Task::ESEND, Task::Message_HelpReply, buf[1], my_ref, buf[2], len, help_reply) ;
}
break ;
}
default:
{
Task::receiver *r = task->find_receiver (buf[4], buf[3]) ;
if (r != NULL)
r->channel->receive (buf[4], buf[1], buf[2], buf[3], buf[0] - 20, &buf[5]) ;
break;
}
}
break ;
case Task::EACK:
break ;
}
}
#ifdef __EASY_C
catch (TaskError t)
{
err.errnum = 0 ;
strcpy (err.errmess, task->lookup(t.buf)) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)task->program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
if (t.fatal)
task->exit(t.fatal) ;
}
catch (_kernel_oserror *e)
{
r.r[0] = (int)e ;
r.r[1] = 0 ;
r.r[2] = (int)task->program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
}
catch (char *s)
{
err.errnum = 0 ;
strcpy (err.errmess, task->lookup(s)) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)task->program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
}
#endif
task->delete_deferred (this) ;
}
DebugWin::DebugWin (Task *t)
: Window (t,"debug")
{
text = NULL ;
Window::Info *inf = info() ;
min_height = inf->extent.y1 - inf->extent.y0 ;
}
DebugWin::~DebugWin()
{
if (text != NULL)
delete text ;
}
void DebugWin::print (char *format...)
{
char buffer[1024] ;
va_list arg ;
va_start (arg,format) ;
vsprintf (buffer,format,arg) ;
if (text == NULL)
text = new TextObject (this, "text", buffer, 8, -8) ;
else
text->insert_line (buffer) ;
int height = text->height() + 16 ;
if (height > min_height)
set_height (height) ;
Window::State *s = state() ;
do_open (s->box.x0, s->box.y0, s->box.x1, s->box.y1, 0, ((s->box.y1 - s->box.y0)/2) - height) ;
do_redraw() ;
}
static char *signals[] = {
"Abort",
"Floating point exception",
"Illegal instruction",
"Interrupt",
"Segmentation fault",
"Terminate",
"Stack overflow"
} ;
static char *application ;
void signal_handler(int sig)
{
thread_disable_ints() ;
thread_stop_ticker(ThreadManager::current_manager) ;
// raise(sig) ;
::print ("%s has received signal \"%s\" and must exit immediately",application,signals[sig]) ;
exit(1) ;
}
Task *main_task ;
void dprintf (char *format...)
{
if (main_task->debug == NULL)
return ;
char buf[1024] ;
va_list arg ;
va_start (arg,format) ;
vsprintf (buf,format,arg) ;
main_task->debug->print (buf) ;
}
Task::Task (char *taskname, char *applname, char *spritename, char *icon_menu, int priority, int position, int wimp_version, int *message_list)
{
char buffer[256] ;
_kernel_swi_regs r ;
_kernel_osfile_block b ;
_kernel_oserror *err ;
char resources[256] ;
#ifdef __EASY_C
try
#endif
{
init(taskname, applname, icon_menu, wimp_version, message_list) ;
//
// create icon on iconbar
//
strcpy (icon_name, spritename) ;
IconData icon_data ;
icon_data.indirectsprite.name = icon_name ;
icon_data.indirectsprite.spritearea = spr_area ;
icon_data.indirectsprite.nameisname = 1 ;
iconbar_icon = new Icon (priority, position, 0, 0, 70, 76,
(Icon::iconflags)(Icon::ISPRITE + Icon::INDIRECT + Icon::IHCENTRE + (Icon::IBTYPE * 3)),
&icon_data) ;
icon_handle = iconbar_icon->handle ;
}
#ifdef __EASY_C
catch (TaskError t)
{
_kernel_oserror err ;
err.errnum = 0 ;
strcpy (err.errmess, t.buf) ;
_kernel_raise_error (&err) ;
if (t.fatal)
exit(t.fatal) ;
}
catch (_kernel_oserror *e)
{
_kernel_swi_regs r ;
r.r[0] = (int)e ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
catch (char *s)
{
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
strcpy (err.errmess, lookup(s)) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
#endif
}
//
// create a task without an icon on the icon bar
//
Task::Task (char *taskname, char *applname, int wimp_version, int *message_list)
{
char buffer[256] ;
_kernel_swi_regs r ;
_kernel_osfile_block b ;
_kernel_oserror *err ;
char resources[256] ;
#ifdef __EASY_C
try
#endif
{
init(taskname, applname, NULL, wimp_version, message_list) ;
}
#ifdef __EASY_C
catch (TaskError t)
{
_kernel_oserror err ;
err.errnum = 0 ;
strcpy (err.errmess, t.buf) ;
_kernel_raise_error (&err) ;
if (t.fatal)
exit(t.fatal) ;
}
catch (_kernel_oserror *e)
{
_kernel_swi_regs r ;
r.r[0] = (int)e ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
catch (char *s)
{
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
strcpy (err.errmess, lookup(s)) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
#endif
}
Task::Task (char *taskname, char *applname, Icon *iconbar, char *icon_menu, int priority, int position, int wimp_version, int *message_list)
{
char buffer[256] ;
_kernel_swi_regs r ;
_kernel_osfile_block b ;
_kernel_oserror *err ;
char resources[256] ;
#ifdef __EASY_C
try
#endif
{
init(taskname, applname, icon_menu, wimp_version, message_list) ;
iconbar_icon = iconbar ;
icon_handle = iconbar->handle ;
}
#ifdef __EASY_C
catch (TaskError t)
{
_kernel_oserror err ;
err.errnum = 0 ;
strcpy (err.errmess, t.buf) ;
_kernel_raise_error (&err) ;
if (t.fatal)
exit(t.fatal) ;
}
catch (_kernel_oserror *e)
{
_kernel_swi_regs r ;
r.r[0] = (int)e ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
catch (char *s)
{
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
strcpy (err.errmess, lookup(s)) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
#endif
}
void Task::init(char *taskname, char *applname, char *iconmenu, int wimp_version, int *message_list)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
int iblock[3] ;
int oblock[2] ;
char buffer[256] ;
_kernel_osfile_block b ;
char resources[256] ;
dragger = NULL ; // no dragger yet
object_dragger = NULL ; // no dragger yet
waiting = 0 ;
receivers = NULL ;
last_receiver = NULL ;
windows = NULL ;
last_window = NULL ;
poll_mask = 1 ; // no null events by default
r.r[0] = (int)iblock ;
r.r[1] = (int)oblock ;
iblock[0] = 4 ;
iblock[1] = 5 ;
iblock[2] = -1 ;
if ((e = _kernel_swi (OS_ReadVduVariables, &r, &r)) != NULL)
throw (e) ;
xeigfactor = oblock[0] ;
yeigfactor = oblock[1] ;
open_fonts = NULL ;
num_open_fonts = max_open_fonts = 0 ;
control_threads = NULL ;
deferred_deletions = NULL ;
main_task = this ;
FILE *fp ;
sprintf (resources, "<%s$Dir>.Resources.Country", applname) ;
if ((fp = fopen (resources, "r")) == NULL)
#ifdef __EASY_C
throw TaskError (1,"Unable to open resources country file %s",resources) ;
#else
{
char str[256] ;
sprintf (str,"Unable to open resources country file %s",resources) ;
__throw (str) ;
}
#endif
if (fscanf (fp,"%s",country) != 1)
throw ("Unable to read country name") ;
fclose (fp) ;
program = applname ;
application = applname ;
//
// read and initialise sprites
//
sprintf (buffer,"<%s$Dir>.!Sprites",applname) ;
spr_area = (sprite_area*)1 ;
int er = _kernel_osfile (5, buffer, &b) ;
if (er == 1)
{
spr_area = (sprite_area*)new char[b.start+4] ;
spr_area->size = b.start+4 ;
spr_area->number = 0 ;
spr_area->sproff = 16 ;
spr_area->freeoff = 16 ;
r.r[0] = 10 + 256 ;
r.r[1] = (int)spr_area ;
r.r[2] = (int)buffer ;
if ((e = _kernel_swi (OS_SpriteOp, &r, &r)) != NULL)
throw (e) ;
}
//
// initialise the wimp task
//
r.r[0] = wimp_version ;
r.r[1] = 'T' +
('A' << 8) +
('S' << 16) +
('K' << 24);
r.r[2] = (int) taskname;
r.r[3] = (int) message_list ;
if ((e = _kernel_swi (Wimp_Initialise, &r, &r)) != NULL)
throw (e) ;
handle = r.r[1] ;
//
// read in the messages from the resources file
//
sprintf (buffer,"<%s$Dir>.Resources.%s.Messages",applname, country) ;
messages = new MsgTrans (buffer) ;
//
// read in the templates
//
sprintf (buffer,"<%s$Dir>.Resources.%s.Templates",applname, country) ;
templates = new Template (this,buffer) ;
//
// read in all the menus from the resources file
//
sprintf (buffer,"<%s$Dir>.Resources.%s.Menus",applname, country) ;
menus = new MenuSet (this, buffer) ;
if (iconmenu != NULL)
{
iconbar_menu = menus->find (iconmenu) ;
if (iconbar_menu == NULL)
throw ("No such menu") ;
}
else
iconbar_menu = NULL ;
if (find_template ("debug") != NULL)
debug = new DebugWin (this) ;
else
debug = NULL ;
// allocate the thread manager
thread_manager = new ThreadManager ;
// initialise the thread package
thread_init(thread_manager) ;
// trap signals to make them stop the threads
signal (SIGABRT, signal_handler) ;
signal (SIGILL, signal_handler) ;
signal (SIGINT, signal_handler) ;
signal (SIGSEGV, signal_handler) ;
signal (SIGSTAK, signal_handler) ;
signal (SIGTERM, signal_handler) ;
}
Task::~Task()
{
Window *w, *nw ;
for (w = windows ; w != NULL ; w = nw)
{
nw = w->next ;
delete w ;
}
for (int i = 0 ; i < max_open_fonts ; i++)
if (open_fonts[i] != -1)
close_font (open_fonts[i]) ;
}
//
// spawn a new task, returning the task handle for it
//
int Task::spawn (char *command...)
{
va_list arg ;
char buf[1024] ;
_kernel_swi_regs r ;
_kernel_oserror *e ;
thread_manager->stop_threads() ;
va_start (arg, command) ;
vsprintf (buf, command, arg) ;
r.r[0] = (int)buf ;
if ((e = _kernel_swi (Wimp_StartTask, &r, &r)) != NULL)
{
thread_manager->resume_threads() ;
throw (e) ;
}
thread_manager->resume_threads() ;
return r.r[0] ;
}
//
// add a window to the start of the task windows list
//
void Task::add_window (Window *w)
{
if (windows == NULL)
windows = last_window = w ;
else
{
last_window->next = w ;
w->prev = last_window ;
last_window = w ;
}
}
void Task::remove_window (Window *w)
{
if (w->prev == NULL)
windows = w->next ;
else
w->prev->next = w->next ;
if (w->next == NULL)
last_window = w->prev ;
else
w->next->prev = w->prev ;
}
//
// remove a window and put it on the deleted queue to be really deleted (destructor called)
// when thread finishes. The window will actually be removed from the task when the
// destructor is called
//
void Task::delete_window (Window *w)
{
delete_deferred(w) ;
}
void Task::delete_deferred (DeferredDelete *d)
{
d->next = deferred_deletions ;
deferred_deletions = d ;
}
Window *Task::find_window (int handle)
{
Window *w, *w1 ;
for (w = windows ; w != NULL ; w = w->next)
if ((w1 = w->find_window (handle)) != NULL)
return w1 ;
// no such window
return NULL ;
}
Task::receiver *Task::find_receiver (int message, int your_ref)
{
receiver *r ;
for (r = last_receiver ; r != NULL ; r = r->prev) // search backwards
if (message == r->message && r->channel->accept (your_ref))
return r ;
return NULL ;
}
void Task::run()
{
#ifdef __EASY_C
try
#endif
{
_kernel_oserror *e ;
_kernel_swi_regs r ;
int buf[256/sizeof(int)] ; // event buffer
DeferredDelete *next ;
running = 1 ;
threads_running = 0 ;
// debug->print ("running task, poll_mask = %d",poll_mask) ;
while (running)
{
r.r[0] = thread_manager->num_running_threads == 0 ? poll_mask : poll_mask & ~(1 << ENULL);
r.r[1] = (int)buf ;
if ((e = _kernel_swi (Wimp_Poll, &r, &r)) != NULL)
throw (e) ;
if (r.r[0] == EREDRAW)
{
Window *w ;
w = find_window(buf[0]) ;
if (w != NULL)
w->redraw() ;
continue ;
}
if (r.r[0] != ENULL)
{
last_event = (Task::events)r.r[0] ;
memcpy (last_event_data, buf, sizeof buf) ;
}
if (thread_manager->num_running_threads > 0 || r.r[0] != ENULL) // any threads to run
{
threads_running = 1 ;
if (r.r[0] != ENULL) // need to process event?
{
// if (r.r[0] != EREDRAW)
// debug->print ("spawning control thread for event %d",r.r[0]) ;
spawn_control_thread(r.r[0], buf) ; // process the event in a thread
}
thread_manager->run (5) ; // run all threads
// if (r.r[0] != EREDRAW && r.r[0] != ENULL)
// debug->print ("end of run, event = %d",r.r[0]) ;
threads_running = 0 ;
}
while (deferred_deletions != NULL)
{
next = deferred_deletions->next ;
delete deferred_deletions ; // has virtual destructor, so real object will be deleted
deferred_deletions = next ;
}
}
}
#ifdef __EASY_C
catch (TaskError t)
{
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
strcpy (err.errmess, lookup(t.buf)) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
if (t.fatal)
exit(t.fatal) ;
}
catch (_kernel_oserror *e)
{
_kernel_swi_regs r ;
r.r[0] = (int)e ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
catch (char *s)
{
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
strcpy (err.errmess, lookup(s)) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
exit (1) ;
}
#endif
}
void Task::send_message (events event, int action, int &task, int &my_ref, int your_ref, int data_length, void *data, int icon)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
int block [256/sizeof(int)] ;
r.r[0] = (int)event ;
r.r[1] = (int)block ;
r.r[2] = task ;
r.r[3] = icon ;
if (data_length < 0 || data_length > (256-20))
throw ("Illegal message length") ;
block[0] = ((data_length + 3) & ~3) + 20 ;
block[3] = your_ref ;
block[4] = action ;
memcpy (&block[5], data, data_length) ;
if ((e = _kernel_swi (Wimp_SendMessage, &r, &r)) != NULL)
throw (e) ;
my_ref = block[2] ;
}
void Task::sleep (ThreadResource *thread, int pri)
{
thread_manager->sleep (thread,pri) ;
}
void Task::sleep (int time)
{
thread_manager->sleep (time) ;
}
void Task::yield ()
{
thread_manager->yield () ;
}
void Task::exit (int status)
{
thread_manager->exit() ;
_kernel_swi_regs r ;
r.r[0] = handle ;
r.r[1] = 'T' +
('A' << 8) +
('S' << 16) +
('K' << 24);
_kernel_swi (Wimp_CloseDown, &r, &r) ;
::exit(status) ;
}
void Task::print (char *format,...)
{
va_list arg ;
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
va_start (arg,format) ;
vsprintf (err.errmess, format, arg) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
}
//
// icon bar click
//
void Task::click (int x, int y, int buttons, int icon)
{
}
char *Task::get_iconbar_menu(int icon)
{
return NULL ;
}
void Task::pre_menu(Menu *menu)
{
}
void Task::menu (MenuItem items[])
{
}
void Task::register_drag (Window *dragger, int id, bool dragging_sprite)
{
if (this->dragger != NULL)
throw ("Already dragging") ;
this->dragger = dragger ;
this->dragging_sprite = dragging_sprite ;
dragger_id = id ;
}
void Task::register_object_drag (Object *dragger, int id, bool dragging_sprite)
{
if (this->object_dragger != NULL)
throw ("Already dragging an object") ;
this->dragging_sprite = dragging_sprite ;
this->object_dragger = dragger ;
object_dragger_id = id ;
}
//
// add a receiver to the end of the receiver queue
//
void Task::add_receiver (Channel *channel, int message)
{
receiver *r ;
r = new receiver (channel, message) ;
if (receivers == NULL)
receivers = last_receiver = r ;
else
{
last_receiver->next = r ;
r->prev = last_receiver ;
last_receiver = r ;
}
}
void Task::remove_receiver (Channel *channel, int message)
{
for (receiver *r = receivers ; r != NULL ; r = r->next)
if (r->channel == channel && r->message == message)
{
if (r->prev == NULL)
receivers = r->next ;
else
r->prev->next = r->next ;
if (r->next == NULL)
last_receiver = r->prev ;
else
r->next->prev = r->prev ;
delete r ;
}
}
int Task::open_font (char *name, int xsize, int ysize)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
r.r[1] = (int)name ;
r.r[2] = xsize * 16 ;
r.r[3] = ysize * 16 ;
r.r[4] = 0 ;
r.r[5] = 0 ;
if ((e = _kernel_swi (Font_FindFont, &r, &r)) != NULL)
throw (e) ;
int font_handle = r.r[0] ;
if (num_open_fonts == max_open_fonts)
{
if (open_fonts == NULL)
open_fonts = (int*)malloc (sizeof (int) * 10) ;
else
open_fonts = (int*)realloc (open_fonts, (max_open_fonts + 10) * sizeof (int)) ;
if (open_fonts == NULL)
throw ("Out of memory") ;
for (int i = 0 ; i < 10 ; i++)
open_fonts[max_open_fonts+i] = -1 ;
max_open_fonts += 10 ;
}
for (int i = 0 ; i < max_open_fonts ; i++)
if (open_fonts[i] == -1)
{
open_fonts[i] = font_handle ;
num_open_fonts++ ;
break ;
}
return font_handle ;
}
void Task::close_font (int handle)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
r.r[0] = handle ;
if ((e = _kernel_swi (Font_LoseFont, &r, &r)) != NULL)
throw (e) ;
for (int i = 0 ; i < max_open_fonts ; i++)
if (open_fonts[i] == handle)
{
open_fonts[i] = -1 ;
num_open_fonts-- ;
return ;
}
throw ("Font handle not found in task memory") ;
}
//
// spawn a new control thread
//
void Task::spawn_control_thread(int event, int *buf)
{
ControlThread *t ;
t = new ControlThread (this, event, buf) ;
if (event == EREDRAW || event == ESENDWANTACK) // redraw request?
t->setpriority(40) ;
else
t->setpriority(60) ;
t->start() ;
}
void Task::enter_critical()
{
thread_disable_ints() ;
}
void Task::exit_critical()
{
thread_enable_ints() ;
}
void *Task::find_sprite (char *name)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
if ((e = _kernel_swi (Wimp_BaseOfSprites, &r, &r)) != NULL)
throw (e) ;
int ram = r.r[1] ;
int p ;
int num_sprites ;
int i ;
p = ram + *((int*)(ram + 8)) ; // get address of first sprite
num_sprites = ram + *((int*)(ram + 4)) ;
for (i = 0 ; i < num_sprites ; i++)
{
if (strncmp ((char*)(p + 4), name, 12) == 0)
return (void*)p ;
p += *(int*)p ;
}
return NULL ;
}
void Task::poll_word_non_zero (int *poll_word, int contents)
{
}
void Task::set_menu (Menu *menu, Icon *icon)
{
current_menu = menu ;
current_menu_icon = icon ;
}
void Task::set_menu (Menu *menu, Object *object)
{
current_menu = menu ;
current_menu_object = object ;
}
void Task::set_menu (Menu *menu, Window *window)
{
current_menu = menu ;
current_menu_window = window ;
}
char *Task::help (int mx, int my, int buttons, int window, int icon)
{
return NULL ;
}
void Task::show_threads()
{
thread_manager->show_threads() ;
}
//
// TaskError class. Used to carry exceptions to a catch handler for errors
//
TaskError::TaskError (int f, char *format...)
{
va_list arg ;
va_start (arg,format) ;
vsprintf (buf, format, arg) ;
fatal = f ;
}
void print (char *format,...)
{
va_list arg ;
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
va_start (arg,format) ;
vsprintf (err.errmess, format, arg) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)"Wimp Program" ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
}
#ifndef __EASY_C
// this is defined because of a 'sorry not implemented' error from cfront.
char *Task::lookup (char *token)
{
char *s ;
if ((s = messages->lookup(token)) != NULL)
return s ;
return token ;
}
void __throw (_kernel_oserror *e)
{
_kernel_swi_regs r ;
r.r[0] = (int)e ;
r.r[1] = 0 ;
r.r[2] = (int)main_task->program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
main_task->exit(1) ;
}
void __throw (char *s)
{
_kernel_oserror err ;
_kernel_swi_regs r ;
err.errnum = 0 ;
strcpy (err.errmess, s) ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)main_task->program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
main_task->exit (1) ;
}
void werr (int fatal, char *format...)
{
_kernel_oserror err ;
_kernel_swi_regs r ;
va_list arg ;
va_start (arg, format) ;
vsprintf (err.errmess,format,arg) ;
err.errnum = 0 ;
r.r[0] = (int)&err ;
r.r[1] = 0 ;
r.r[2] = (int)main_task->program ;
_kernel_swi (Wimp_ReportError, &r, &r) ;
if (fatal)
main_task->exit (1) ;
}
#endif