/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for 
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #                                      
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    Event.c
    Author:  Copyright  1992, 1993, 1994 John Winters
             (mucked about by Jason Williams and Tim Browse)
             (and by Julian Smith)
    Version: 1.11 (26 Sep 1995)
    Purpose: High-level WIMP event dispatch to a hierarchy of user event
             handling functions.
    Mods:
    PJC:     Added Desk_Event_Initialise3 and allowed support for the
             NonZero Poll Word event

    JCW:     Fixed incorrect releasing of NULL events on Desk_event_ANY release.
    
    05 Jun 1995 JS       Changed external globals to work with SDLS, and moved 
                         Desk_Event_taskhandle into a separate .c file
    
    26 Sep 1995 JS Desk_Event__Ref_taskname now in 'taskname.c'.
    
    29 Feb 1996 JS Added Desk_Debug_Assert that handler function is > 0x8000.
	
	08 May 1996 JS atexit isn't used in module builds - atexit doesn't work for module tasks.
*/

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include "Desk.Error.h"
#include "Desk.WimpSWIs.h"
#include "Desk.DeskMem.h"
#include "Desk.Debug.h"

#include "EventDefs.h"


/* Error message definitions.
   These are ALL the messages produced by this module, and have been defined
   here so that it is easier for you to alter them or replace them with
   msgtrans tags.
   Error numbers are also included: Currently, the error number is unused
   so they are defined starting from ERRBASE. If you wish to use the error
   number in your Error reporting code, then you will have to set ERRBASE to
   a suitable value to ensure that all errors produced have unique numbers.
*/
#define ERRBASE  1
#define ERR1     ERRBASE+0
#define ERRMESS1 "Can't allocate memory for an icon record"
#define ERR2     ERRBASE+1
#define ERRMESS2 "Can't allocate memory for a window record"
#define ERR3     ERRBASE+2
#define ERRMESS3 "Can't allocate memory to record an event claim"
#define ERR4     ERRBASE+3
#define ERRMESS4 "Attempt to claim invalid event type"
#define ERR5     ERRBASE+4
#define ERRMESS5 "Can't trace event claim"


/* JS 22 Mar 1995
Need to make these global non-static variables visible to this file.
Event.h #defines them so that any reference to 'Desk_Event_mask' (for eg)
actually calls the function 'Desk_Event__Ref_mask', so that the DLL 
application start-time is correctly set so that the correct instance
data is returned.
*/

Desk_event_pollmask  Desk_Event_mask = 0;
Desk_event_pollblock Desk_Event_lastevent;
Desk_task_handle     Desk_Event_taskhandle  = 0;
unsigned int    Desk_Event_wimpversion = 0;

#ifdef _DLL
Desk_event_pollmask         *Desk_Event__Ref_mask( void)        { return &Desk_Event_mask;        }
extern int             *Desk_Event__Ref_taskhandle( void)  { return &Desk_Event_taskhandle;  }
extern unsigned int    *Desk_Event__Ref_wimpversion( void) { return &Desk_Event_wimpversion; }
extern Desk_event_pollblock *Desk_Event__Ref_lastevent( void)   { return &Desk_Event_lastevent;   }
#endif




static short usagecounts[Desk_wimp_NUMBEROFEVENTS]= {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};




/*
   PJC: needed to remove the 'const' declaration so that
   the list can be altered on the fly
*/
static Desk_event_class eventclass [Desk_event_MAXEVENTS] =
{
    notrelated,     /* NULL             */
    windowrelated,  /* redraw           */
    windowrelated,  /* open window      */
    windowrelated,  /* close window     */
    windowrelated,  /* pointer leave    */
    windowrelated,  /* pointer enter    */
    iconrelated,    /* Mouse click      */
    notrelated,     /* drag finished    */
    iconrelated,    /* keypress         */
    notrelated,     /* menu selection   */
    windowrelated,  /* scroll           */
    iconrelated,    /* lose caret       */
    iconrelated,    /* gain caret       */
    notrelated,     /* nonzero pollword */
    nonexistent,    /* 14               */
    nonexistent,    /* 15               */
    nonexistent,    /* 16               */
    notrelated,     /* Message          */
    notrelated,     /* Message recorded */
    notrelated      /* Message ack      */
};

static Desk_linklist_header catchalls = {NULL, NULL};

static Desk_linklist_header eventqueues[Desk_event_MAXEVENTS] =
{
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL},
  {NULL, NULL}
};


static Desk_linklist_header Desk_window_anchor = {NULL, NULL};
static void *currentscan = NULL;




/* prototypes for the 3 handler functions used in the Desk_event_handlers list */
static Desk_bool DispatchIconEvents(Desk_event_pollblock *event, void *reference);
static Desk_bool DispatchWindowEvents(Desk_event_pollblock *event, void *reference);
static Desk_bool DispatchMiscEvents(Desk_event_pollblock *event, void *reference);

static Desk_event_handler Desk_event_handlers[Desk_wimp_NUMBEROFEVENTS] = {
    DispatchMiscEvents,
    DispatchWindowEvents,
    DispatchWindowEvents,
    DispatchWindowEvents,
    DispatchWindowEvents,
    DispatchWindowEvents,
    DispatchIconEvents,
    DispatchMiscEvents,
    DispatchIconEvents,
    DispatchMiscEvents,
    DispatchWindowEvents,
    DispatchIconEvents,
    DispatchIconEvents,
    NULL,
    NULL,
    NULL,
    NULL,
    DispatchMiscEvents,
    DispatchMiscEvents,
    DispatchMiscEvents
};


/* which events can be masked out? */
static const char Desk_event_masks[Desk_event_MAXEVENTS] = {
  Desk_bool_TRUE,          /* Null             */
  Desk_bool_FALSE,         /* Redraw Window    */
  Desk_bool_FALSE,         /* Open Window      */
  Desk_bool_FALSE,         /* Close Window     */
  Desk_bool_TRUE,          /* Pointer Leaving  */
  Desk_bool_TRUE,          /* Pointer Entering */
  Desk_bool_FALSE,         /* Click            */
  Desk_bool_FALSE,         /* Drag finish      */
  Desk_bool_FALSE,         /* Key              */
  Desk_bool_FALSE,         /* Menu Selection   */
  Desk_bool_FALSE,         /* Scroll           */
  Desk_bool_TRUE,          /* Lose caret       */
  Desk_bool_TRUE,          /* Gain caret       */
  Desk_bool_TRUE,          /* NonZero PollWord */
  Desk_bool_FALSE,         /* Reserved         */
  Desk_bool_FALSE,         /* Reserved         */
  Desk_bool_FALSE,         /* Reserved         */
  Desk_bool_FALSE,         /* Message          */
  Desk_bool_TRUE,          /* Message Recorded */
  Desk_bool_TRUE           /* Message Ack      */
};


/* =========================================================================
   Functions
   ========================================================================= */





static void IncrementUsage(Desk_event_type event)
{
  if ((usagecounts[event])++ == 0)      /* increment count: if not used b4...*/
  {
    Desk_Event_mask.value &= ~(1 << event);  /* then stop masking event out       */

    /* PJC: if NZPW event type, also set bit 22 */
    if (event == Desk_event_NONZEROPOLLWORD)
      Desk_Event_mask.data.r3ispollwordptr = Desk_bool_TRUE;
  }
}



static void DecrementUsage(Desk_event_type event)
{
  if (--(usagecounts[event]) == 0)      /* decrement count: if not used now..*/
  {
    if (Desk_event_masks[event])             /* then mask the event out           */
      Desk_Event_mask.value |= 1 << event;

    /* PJC: if NZPW event type, also clear bit 22 */
    if (event == Desk_event_NONZEROPOLLWORD)
      Desk_Event_mask.data.r3ispollwordptr = Desk_bool_FALSE;
  }
}



static Desk_event_iconrecord *CreateIconRecord(Desk_event_windowrecord *windowrecord,
                                          Desk_icon_handle        icon)
{
  Desk_event_iconrecord *current;

  current = Desk_DeskMem_Malloc(sizeof(Desk_event_iconrecord));
    current->icon = icon;
    Desk_LinkList_Init(&(current->claimlist));
    Desk_LinkList_AddToTail(&(windowrecord->iconlist), &(current->header));

  return(current);
}



static Desk_event_windowrecord *CreateWindowRecord(Desk_window_handle window)
{
  Desk_event_windowrecord *current;

  current = Desk_DeskMem_Malloc(sizeof(Desk_event_windowrecord));
    current->window = window;
    Desk_LinkList_Init(&(current->iconlist));
    Desk_LinkList_Init(&(current->claimlist));
    Desk_LinkList_AddToTail(&Desk_window_anchor, &(current->header));
  return(current);
}



static Desk_event_iconrecord *FindIcon(Desk_event_windowrecord *windowrecord,
                                  Desk_icon_handle        icon)
{
  Desk_event_iconrecord *current;

  current = Desk_LinkList_FirstItem(&(windowrecord->iconlist));
  while (current != NULL)
  {
    if (current->icon == icon)
      break;
    current = Desk_LinkList_NextItem(&(current->header));
  }
  return(current);
}



static Desk_event_windowrecord *FindWindow(Desk_window_handle window)
{
  Desk_event_windowrecord *current;

  current = Desk_LinkList_FirstItem(&Desk_window_anchor);
  while (current != NULL)
  {
    if (current->window == window)
      break;
    current = Desk_LinkList_NextItem(&(current->header));
  }

  return(current);
}



extern Desk_bool Desk_Event_Claim(Desk_event_type eventtype,
                        Desk_window_handle window,  Desk_icon_handle icon,
                        Desk_event_handler handler, void *reference)
{
  Desk_event_claimrecord  *record;
  Desk_event_iconrecord   *iconrecord;
  Desk_event_windowrecord *windowrecord;
  int                index;
  Desk_bool               result;

  result = Desk_bool_FALSE;
  if ((eventtype == Desk_event_ANY) ||
       ((eventtype >= 0) && (eventtype < Desk_wimp_NUMBEROFEVENTS) &&
        (eventclass[eventtype] != nonexistent)))
  {
    record = Desk_DeskMem_Malloc(sizeof(Desk_event_claimrecord));

    record->eventtype = eventtype;
    record->handler   = handler;
    record->reference = reference;

    if (window == Desk_event_ANY)
    {
      if (eventtype == Desk_event_ANY)
      {
        /* Any events to any window (lowest level of hierarchy) */
        Desk_LinkList_AddToHead(&catchalls, &(record->header));
        result = Desk_bool_TRUE;

        for (index = 1; index < Desk_event_MAXEVENTS; index++)
          if (eventclass[index] != nonexistent)
            IncrementUsage( (Desk_event_type) index);
      }
      else
      {
        /* Specific event to any window */
        Desk_LinkList_AddToHead(&(eventqueues[eventtype]), &(record->header));
        result = Desk_bool_TRUE;

        IncrementUsage(eventtype);
      }
    }
    else
    {
      /* Claims for specific windows... */
      windowrecord = FindWindow(window);/* Find/Make claim record for window */
      if (windowrecord == NULL)
        windowrecord = CreateWindowRecord(window);

      if (windowrecord != NULL)
      {
        if (icon == Desk_event_ANY)
        {
          /* Specific window, any icon */
          if (eventtype == Desk_event_ANY)
          {
            /* Specific window, any icon, any event */
            Desk_LinkList_AddToTail(&(windowrecord->claimlist), &(record->header));
            result = Desk_bool_TRUE;

            /* NULL events are not included in "Desk_event_ANY", so start from 1 */
            for (index = 1; index < Desk_event_MAXEVENTS; index++)
              if (eventclass[index] != nonexistent)
                IncrementUsage ( (Desk_event_type) index);
          }
          else
          {
            /* specific window, any icon, specific event */
            Desk_LinkList_AddToHead(&(windowrecord->claimlist), &(record->header));
            result = Desk_bool_TRUE;

            IncrementUsage(eventtype);
          }

        }
        else
        {
          /* Specific window, specific icon */
          iconrecord = FindIcon(windowrecord, icon);
          if (iconrecord == NULL)
              iconrecord = CreateIconRecord(windowrecord, icon);

          if (iconrecord != NULL)
          {
            if (eventtype == Desk_event_ANY)
            {
              /* specific window, specific icon, any event */
              Desk_LinkList_AddToTail(&(iconrecord->claimlist), &(record->header));
              result = Desk_bool_TRUE;

              /* NULL events are not included in "Desk_event_ANY" so start from 1 */
              for (index = 1; index < Desk_event_MAXEVENTS; index++)
                if (eventclass[index] != nonexistent)
                  IncrementUsage( (Desk_event_type) index);
            }
            else
            {
              /* specific window, specific icon, specific event */
              Desk_LinkList_AddToHead(&(iconrecord->claimlist), &(record->header));
              result = Desk_bool_TRUE;

              IncrementUsage(eventtype);
            }
          }
        }
      }
    }
    if (result == Desk_bool_FALSE)
        Desk_DeskMem_Free (record);
  }
  else	{
    /*Desk_Error_ReportInternal(ERR4, ERRMESS4);*/
    Desk_Debug_Printf( Desk_error_PLACE "Attempt to claim invalid event type\n");
  }

  return(result);
}



static void LoseClaim(Desk_linklist_header *listheader,
                      Desk_event_claimrecord *claimrecord)
{
  int index;

  if (claimrecord->eventtype == Desk_event_ANY)
  {
    /* "Desk_event_ANY" does not include Desk_event_NULL, so start from 1 */
    for (index = 1; index < Desk_wimp_NUMBEROFEVENTS; index++)
      if (eventclass[index] != nonexistent)
              DecrementUsage( (Desk_event_type) index);
  }
  else
    DecrementUsage(claimrecord->eventtype);

  if (claimrecord == currentscan)
    currentscan = NULL; /* Make other routines aware we have deleted the item
                           that they are currently scanning                  */

  Desk_LinkList_Unlink(listheader, &(claimrecord->header));

  Desk_DeskMem_Free(claimrecord);
}



static Desk_bool RemoveClaim(Desk_linklist_header *header,
                        Desk_event_type      eventtype,
                        Desk_event_handler   handler, void *reference,
                        int             *lastone)
/* Returns Desk_bool_TRUE if it found and removed the claim.
 * If it did, it also returns a flag: lastone == Desk_bool_TRUE if no more claims left
 * on this event
 */
{
  Desk_event_claimrecord *claimrecord;
  Desk_bool result;

  result = Desk_bool_FALSE;
  claimrecord = Desk_LinkList_FirstItem(header);

  while (claimrecord != NULL)
  {
    if ((claimrecord->eventtype == eventtype) &&
        (claimrecord->handler   == handler)   &&
        (claimrecord->reference == reference))
    {
      LoseClaim(header, claimrecord);
      result = Desk_bool_TRUE;
      break;
    }

    claimrecord = Desk_LinkList_NextItem(&(claimrecord->header));
  }

  if ((result) && (lastone != NULL))
    *lastone = (Desk_LinkList_FirstItem(header) == NULL);    /* return the result */

  return(result);
}



static void LoseIcon(Desk_linklist_header *list, Desk_event_iconrecord *iconrecord)
{
  Desk_event_claimrecord *claimrecord;

  while ((claimrecord = Desk_LinkList_FirstItem(&(iconrecord->claimlist))) != NULL)
    LoseClaim(&(iconrecord->claimlist), claimrecord);

  Desk_LinkList_Unlink(list, &(iconrecord->header));
  Desk_DeskMem_Free(iconrecord);
}



static void LoseWindow(Desk_event_windowrecord *windowrecord)
{
  Desk_LinkList_Unlink(&Desk_window_anchor, &(windowrecord->header));
  Desk_DeskMem_Free(windowrecord);
}



extern Desk_bool Desk_Event_Release(Desk_event_type event,
                          Desk_window_handle  window, Desk_icon_handle icon,
                          Desk_event_handler handler, void *reference)
{
  Desk_event_windowrecord *windowrecord;
  Desk_event_iconrecord *iconrecord;
  int  lastone;
  Desk_bool result;

  result = Desk_bool_FALSE;

  if (window == Desk_event_ANY)
  {
    if (event == Desk_event_ANY)
      result = RemoveClaim(&catchalls, event, handler, reference, NULL);
    else
      result = RemoveClaim (&(eventqueues[event]),
                               event, handler, reference, NULL);
  }
  else
  {
    windowrecord = FindWindow(window);
    if (windowrecord != NULL)
    {
      if (icon == Desk_event_ANY)
        result = RemoveClaim(&(windowrecord->claimlist),
                                 event, handler, reference, NULL);
      else
      {
        iconrecord = FindIcon(windowrecord, icon);
        if (iconrecord != NULL)
        {
          if (RemoveClaim(&(iconrecord->claimlist),
                                      event, handler, reference, &lastone))
          {
            result = Desk_bool_TRUE;
            if (lastone)
              LoseIcon(&(windowrecord->iconlist), iconrecord);
          }
        }
      }

      if (result)
      {
        if ((Desk_LinkList_FirstItem(&(windowrecord->iconlist)) == NULL) &&
            (Desk_LinkList_FirstItem(&(windowrecord->claimlist)) == NULL))
          LoseWindow(windowrecord);
      }
    }
  }

  if (!result)	{
  	Desk_Debug_Printf( "Can't trace event claim\n");
  	/*Desk_Error_ReportInternal(ERR5, ERRMESS5);*/
  	}

  return (result) ;
}



extern void Desk_Event_ReleaseWindow(Desk_window_handle window)
{
  Desk_event_claimrecord  *claimrecord;
  Desk_event_iconrecord   *iconrecord;
  Desk_event_windowrecord *windowrecord;

  windowrecord = FindWindow(window);
  if (windowrecord != NULL)
  {
    while ((claimrecord = Desk_LinkList_FirstItem(&(windowrecord->claimlist)))
           != NULL)
      LoseClaim(&(windowrecord->claimlist), claimrecord) ;

    while ((iconrecord = Desk_LinkList_FirstItem(&(windowrecord->iconlist)))
           != NULL)
      LoseIcon(&(windowrecord->iconlist), iconrecord);

    LoseWindow(windowrecord);
  }
}



/* Event dispatchers. These functions take in an event, and find the highest-
 * priority user event handler, which is then called to process the event
 */

static Desk_bool ScanMiscQueue(Desk_linklist_header *queue, Desk_event_pollblock *event)
{
  Desk_event_claimrecord *current;

  current = Desk_LinkList_FirstItem(queue);
  while (current != NULL)
  {
    currentscan = current;
    
    Desk_Debug_Assert( ((void*) current->handler) > ((void*) 0x8000));
    
    if (current->handler(event, current->reference))
      return(Desk_bool_TRUE);                    /* User handler has handled the event */

    if (currentscan == current)
      current = Desk_LinkList_NextItem(&(current->header));
    else
      current = Desk_LinkList_FirstItem(queue);/* item deleted out from under us! */
  }
  return(Desk_bool_FALSE);
}



static Desk_bool DispatchMiscEvents(Desk_event_pollblock *event, void *reference)
/* Processes any general event that either is non-window-specific, or has not
 * been processed by any higher-level handlers. If NO handler at this level
 * manages to handle the event, then only default action is to check for the
 * QUIT message, and quit if necessary.
 */
{
  Desk_bool dummy;
  Desk_linklist_header *queue;

  Desk_UNUSED( reference);
  
  queue = &eventqueues[event->type];          /* Try specific event handlers */
  dummy = ScanMiscQueue(queue, event);

  if (!dummy)
    dummy = ScanMiscQueue(&catchalls, event);      /* Try catch-all handlers */

  /* User handlers haven't processed event, so check for QUIT message */
  /* unless we are building a module-version of DeskLib, in which	*/
  /* case ignore Desk_message_QUIT - leave handling to the client.		*/

#ifndef Desk__MODULE_CLIENT
  if (!dummy)
    if (((event->type == Desk_event_USERMESSAGE) ||
         (event->type == Desk_event_USERMESSAGERECORDED)) &&
         (event->data.message.header.action == Desk_message_QUIT))
      exit(0);          /* Just die. atexit() handlers should tidy up for us */
#endif

  return(Desk_bool_TRUE);   /* Always assume we have handled the event, because we are
                     the last event handler that will ever be called...      */
}



static Desk_bool ScanWindowQueue(Desk_linklist_header *queue, Desk_event_pollblock *event)
{
  Desk_event_claimrecord *current;

  current = Desk_LinkList_FirstItem(queue);
  while (current != NULL)
  {
    currentscan = current ;
    if ((current->eventtype == event->type) ||
        (current->eventtype == Desk_event_ANY))
        {
        Desk_Debug_Assert( (void*) current->handler > (void*) 0x8000);
        if (current->handler(event, current->reference))
          return(Desk_bool_TRUE);                      /* User handler has handled event */
        }

    if (currentscan == current)
      current = Desk_LinkList_NextItem(&(current->header));
    else
      current = Desk_LinkList_FirstItem(queue);/* item deleted out from under us! */
  }
  return(Desk_bool_FALSE);
}



static Desk_bool DispatchIconEvents(Desk_event_pollblock *event, void *reference)
{
  Desk_icon_handle        icon;
  Desk_event_iconrecord   *iconrecord;
  Desk_window_handle      window;
  Desk_event_windowrecord *windowrecord;

  Desk_UNUSED( reference);
  
  if (event->type == Desk_event_CLICK)
    window = event->data.mouse.window;
  else
    window = event->data.openblock.window;

  windowrecord = FindWindow(window);
  if (windowrecord != NULL)
  {
    switch (event->type)
    {
      case Desk_event_CLICK:
        icon = event->data.mouse.icon;
        break;

      case Desk_event_KEY:
        icon = event->data.key.caret.icon;
        break;

      case Desk_event_LOSECARET:
      case Desk_event_GAINCARET:
        icon = event->data.caret.icon;
        break;

      default:
        icon = -1;
        break;
    }

    if (icon != -1)
    {
      iconrecord = FindIcon(windowrecord, icon);
      if (iconrecord != NULL)
        if (ScanWindowQueue(&(iconrecord->claimlist), event))
          return(Desk_bool_TRUE);  /* event handled */
    }

    if (ScanWindowQueue(&(windowrecord->claimlist), event))
      return(Desk_bool_TRUE);  /* event handled */
  }

/* Unable to find a highlevel handler for this event, so fallback to the
 * low-level handlers...
 */

  return(DispatchMiscEvents(event, NULL));
}



static Desk_bool DispatchWindowEvents(Desk_event_pollblock *event, void *reference)
{
  Desk_window_handle      window;
  Desk_event_windowrecord *windowrecord;

  Desk_UNUSED( reference);
  
  window = event->data.openblock.window;
  windowrecord = FindWindow(window);

  if (windowrecord != NULL)
    if (ScanWindowQueue(&(windowrecord->claimlist), event))
      return(Desk_bool_TRUE);  /* Window handler has dealt with the event */

/* Unable to find a highlevel handler for this event, so fallback to the
 * low-level handlers...
 */

  return(DispatchMiscEvents(event, NULL));
}


Desk_SDLS_PtrFn( static, void, Desk_Event__ExitFunction( void))
/* This function is called at exit, to tidy up as we quit		*/
/* cc gives 'Warning: extern 'Desk_Event__ExitFunction' not declared in 	*/
/* header' when compilation is for a DLL.				*/
/* cc warns about extern ... not declared in header in SDLS compiles	*/
{
  if (Desk_Event_taskhandle > 0)
    Desk_Wimp_CloseDown(Desk_Event_taskhandle);
    Desk_Event_taskhandle = 0;
}




/* And now, ladies and gentlemen, the routines you have all been waiting
 * for... I give you... the amazing Eventi brothers...
 */

extern void Desk_Event_Initialise(const char *taskname)
{
  Desk_Event_Initialise3(taskname, 200, NULL);
}



extern void Desk_Event_Initialise3(const char *taskname, int version, const int *messages)
{
  int index;

#ifndef Desk__MODULE_CLIENT
	atexit( Desk_SDLS_dllEntry( Desk_Event__ExitFunction));
/* atexit doesn't work well in C module tasks...	*/
#endif

  for (index = 0; index < Desk_event_MAXEVENTS; index++)
  {
    if (Desk_event_masks[index])
      Desk_Event_mask.value |= 1 << index;
  }  

  if (version >= 300)
  {
    eventclass[Desk_event_NONZEROPOLLWORD] = notrelated;
    Desk_event_handlers[Desk_event_NONZEROPOLLWORD] = DispatchMiscEvents;
  }

  Desk_Event_wimpversion = version;
  
  
  Desk_Wimp_Initialise(&Desk_Event_wimpversion,
                                     taskname, &Desk_Event_taskhandle, messages);

  Desk_Event_taskname = taskname;
  
  Desk_Debug_Printf( Desk_error_PLACE "Desk_Event_Initialise3. taskhandle is address 0x%p, 0x%x\n",
  	&Desk_Event_taskhandle, Desk_Event_taskhandle
  	);
}


extern void Desk_Event_Process(Desk_event_pollblock *event)
{
  Desk_event_handler handler;

  handler = (Desk_event_handler) (Desk_event_handlers[event->type]);
  handler(event, NULL);
}


extern void Desk_Event_Poll(void)
{
  Desk_Wimp_Poll(Desk_Event_mask, &Desk_Event_lastevent);
  Desk_Event_Process(&Desk_Event_lastevent);
}


extern void Desk_Event_CloseDown(void)
{
#ifndef Desk__MODULE_CLIENT
  exit(0);  /* Desk_Wimp_CloseDown is handled by the ExitFunction */
#else
	Desk_Event__ExitFunction();
/* atexit doesn't work well in C module tasks...	*/
#endif
}
