/* * event.c * * Handling and dispatching events * * © 1994-1998 Straylight */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Steel library. * * Steel is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * Steel is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Steel. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*----- Header files ------------------------------------------------------*/ #include #include #include "event.h" #include "wimpt.h" #include "win.h" #include "menu.h" #include "msgs.h" #include "werr.h" #include "alarm.h" #include "mem.h" #include "swis.h" #define dbox__INTERNALS #include "dbox.h" /*----- Global variables --------------------------------------------------*/ static wimp_emask event__mask=wimp_EMNULL; static menu event__currentMenu; static event_menu_maker event__currentMaker; static event_menu_proc event__menuProc; static void *event__menuHandle; /* --- For bodging menus which move around in memory --- */ static int event__menuX; static int event__menuY; static BOOL event__recreating; static event_menuPurpose event__purpose; static BOOL event__returnMenuHelp; /*----- Event masks -------------------------------------------------------*/ void event_setmask (wimp_emask mask) { event__mask = mask; } wimp_emask event_getmask (void) { if (win_any_idles()) return (event__mask&~wimp_EMNULL); else return (event__mask); } /*----- Menu button handling ----------------------------------------------*/ typedef struct event__midbstr { event_midbhandler proc; int gadget; void *handlea; void *handleb; void *handlec; } event__midbstr; /* * BOOL event_attachMidbHandler(wimp_w w, * event_midbhandler proc, * int gadget, * void *handlea, * void *handleb, * void *handlec) * * Use * Registers a function to be called by event when a menu button event is * received by a particular window. Typically, this handler will display a * menu at the mouse coordinates, although you can do anything you want. * * You shouldn't need to call this function very much. It's really for * allowing other systems to supply menu attachment functions like event_- * attachmenu etc. * * Parameters * wimp_w == the window to which to attach the function * event_midbhandler proc == the function to call when a menu button event * is received for the window * others == arguments to be passed (unprocessed) to proc when it's called. * * Returns * TRUE if the attachment succeeded. */ BOOL event_attachMidbHandler(wimp_w w, event_midbhandler proc, int gadget, void *handlea, void *handleb, void *handlec) { event__midbstr *e=win_getmenuh(w); if (!e && proc) { if (e=mem_alloc(sizeof(event__midbstr)),!e) { werr(FALSE,msgs_lookup("eventNMAM:Not enough memory to attach menu")); return (FALSE); } win_setmenuh(w,e); } if (proc) { e->proc=proc; e->gadget=gadget; e->handlea=handlea; e->handleb=handleb; e->handlec=handlec; } else if (e) { mem_free(e); win_setmenuh(w,0); } return (TRUE); } void event_attachedMenu(wimp_w w, menu *m, event_menu_maker *mk, event_menu_proc *proc, void **handle) { event__midbstr *e=win_getmenuh(w); if (e) { *m=(e->gadget ? 0 : e->handlea); *mk=(e->gadget ? (event_menu_maker)e->handlea : 0); *proc=(event_menu_proc)e->handleb; *handle=e->handlec; } else { *m=0; *mk=0; *proc=0; *handle=0; } } /*----- Menu displaying ---------------------------------------------------*/ /* * void event__displayMenu(void) * * Use * Displays (or redisplays) the current menu. It is assumed that the menu * maker has been called to set up the current menu pointer. */ static void event__displayMenu(void) { wimp_menustr *m; m=menu_syshandle(event__currentMenu); if (win_anyWindows()==FALSE) { werr(FALSE, msgs_lookup("eventTMWM:Too many windows - " "%s could not create menu."), wimpt_programname()); } else wimpt_noerr(wimp_create_menu(m,event__menuX,event__menuY)); } /* * void event__findMenu(BOOL iconbar) * * Use * Sets up the global event__menuX and event__menuY for the current menu * for a subsequent call of event__displayMenu. Also (as a side-effect) * calls the menu maker. * * Parameters * BOOL iconbar == whether the menu has been opened from the iconbar */ static void event__findMenu(BOOL iconbar) { wimp_mousestr m; wimp_menustr *mn; wimp_menuitem *it; int height; if (event__currentMaker) { event__recreating=FALSE; event__currentMenu=event__currentMaker(event__menuHandle); } wimpt_noerr(wimp_get_point_info(&m)); event__menuX=m.x-64; if (iconbar) { mn=menu_syshandle(event__currentMenu); height=0; it=(wimp_menuitem *)(mn+1); for (;;) { height+=44; /* I know it may not be, but it should. */ if (it->flags & wimp_MSEPARATE) height+=24; if (it->flags & wimp_MLAST) break; it++; } event__menuY=96+height; } else event__menuY=m.y; } /* * void event_openMenu(menu it,event_menu_proc proc,void *handle) * void event_makeMenu(event_menu_maker it,event_menu_proc proc,void *handle) * void event_openIconbarMenu(...) * void event_makeIconbarMenu(...) * * Use * Opens a menu onto the screen and tells your routine when it's finished. * * Parameters * menu it == the menu or menu maker procedure * event_menu_proc proc == the menu handler function * void *handle == it's jolly old handle */ void event_openMenu(menu it,event_menu_proc proc,void *handle) { event__currentMenu=it; event__currentMaker=0; event__menuProc=proc; event__menuHandle=handle; event__findMenu(FALSE); event__displayMenu(); } void event_makeMenu(event_menu_maker maker,event_menu_proc proc,void *handle) { event__currentMaker=maker; event__menuProc=proc; event__menuHandle=handle; event__findMenu(FALSE); event__displayMenu(); } void event_openIconbarMenu(menu it,event_menu_proc proc,void *handle) { event__currentMenu=it; event__currentMaker=0; event__menuProc=proc; event__menuHandle=handle; event__findMenu(TRUE); event__displayMenu(); } void event_makeIconbarMenu(event_menu_maker maker, event_menu_proc proc, void *handle) { event__currentMaker=maker; event__menuProc=proc; event__menuHandle=handle; event__findMenu(TRUE); event__displayMenu(); } /*----- Menu attachment ---------------------------------------------------*/ /* * event__defaultmidb(wimp_w w, * int made, * void *handlea, * void *handleb, * void *handlec) * * Use * Default menu button handler for windows (to support event_attachmenu * etc.) * * Parameters * As for an event_midbhandler. */ static void event__defaultmidb(wimp_w w, int made, void *handlea, void *handleb, void *handlec) { if (w==win_ICONBAR) { if (!made) { event_openIconbarMenu((menu)handlea, (event_menu_proc)handleb, handlec); } else { event_makeIconbarMenu((event_menu_maker)handlea, (event_menu_proc)handleb, handlec); } } else { if (!made) { event_openMenu((menu)handlea, (event_menu_proc)handleb, handlec); } else { event_makeMenu((event_menu_maker)handlea, (event_menu_proc)handleb, handlec); } } } /*----- Default menu attachment -------------------------------------------*/ /* * void event_attachmenu(wimp_w w,menu m,event_menu_proc p,void *handle) * * Use * Attaches a menu to a window so that it opens when you click menu on it. * * Parameters * wimp_w w == the window to attach to * menu m == the menu to attach to it * event_menu_proc p == what to do when a menu item is chosen * void *handle == something else to send to p */ BOOL event_attachmenu(wimp_w w,menu m,event_menu_proc p,void *handle) { return (event_attachMidbHandler(w, event__defaultmidb, FALSE, m, (void *)p, handle)); } /* * void event_attachmenumaker(wimp_w w, * event_menu_maker m, * event_menu_proc p, * void *handle) * * Use * Attaches a menu to a window so that it opens when you click menu on it. * * Parameters * wimp_w w == the window to attach to * event_menu_maker m == how to create the menu * event_menu_proc p == what to do when a menu item is chosen * void *handle == something else to send to p */ BOOL event_attachmenumaker(wimp_w w, event_menu_maker m, event_menu_proc p, void *handle) { return (event_attachMidbHandler(w, event__defaultmidb, TRUE, (void *)m, (void *)p, handle)); } /*----- Pointless window counting -----------------------------------------*/ BOOL event_anywindows(void) { return(win_activeno() != 0); } /*----- Event processing -- the interesting bit ---------------------------*/ void event_returnMenuHelp(BOOL doit) { event__returnMenuHelp=doit; } event_menuPurpose event_whyMenuEvent(void) { return (event__purpose); } BOOL event_is_menu_being_recreated(void) { return event__recreating; } void (event_process)(void) { event_process(); } /* * void event__menuHit(int *hits) * * Use * Sends a menu hit array to the current menu handling procedure * * Parameters * int *hits == an array of menu hits (WIMP-style) to convert to obscure * RISC_OSLib format (1-indexed :-( ) and bundled to an event handler. */ static void event__menuHit(int *hits) { int i; char buff[9]; /* Silly event -- using chars! */ if (event__currentMenu) { for (i=0;hits[i]!=-1;i++) buff[i]=hits[i]+1; buff[i]=hits[i]+1; event__menuProc(event__menuHandle,buff); } } /* * void event__process(void) * * Use * Processes events :-) */ void event__process(void) { wimp_eventstr e; int i; static BOOL lastWasMenu; int nextAlarm; /* --- Terminate the app if it has no windows --- */ if (!event_anywindows()) exit(0); /* --- If we just clicked on a menu, we may need to reopen it --- */ if (lastWasMenu && event__currentMenu && wimpt_last_event()->e==wimp_EMENU) { wimp_mousestr m; wimpt_noerr(wimp_get_point_info(&m)); if (m.bbits & wimp_BRIGHT) { if (event__currentMaker) { event__recreating=TRUE; event__currentMenu=event__currentMaker(event__menuHandle); } event__displayMenu(); } else { i=-1; event__purpose=event_MENUDELETE; event__menuHit(&i); } } /* --- Get an event from wimpt and process it --- */ wimpt_noerr(wimpt_poll(event_getmask(),&e)); lastWasMenu=FALSE; switch (e.e) { case wimp_ENULL: while (alarm_next(&nextAlarm) && alarm_timenow()-nextAlarm>=0) alarm_callnext(); break; case wimp_EBUT: if (e.data.but.m.bbits & wimp_BMID) { wimp_w w=(e.data.but.m.w<=-1) ? win_ICONBAR : e.data.but.m.w; event__midbstr *m=win_getmenuh(w); if (m) { (m->proc)(w,m->gadget,m->handlea,m->handleb,m->handlec); return; } } break; case wimp_EMENU: event__purpose=event_MENUSELECT; event__menuHit(e.data.menu); lastWasMenu=TRUE; break; case wimp_ESEND: case wimp_ESENDWANTACK: switch (e.data.msg.hdr.action) { case wimp_MMENUWARN: if (e.data.msg.data.words[0]>0x8000) { if (win_anyWindows()==FALSE) { werr(FALSE, msgs_lookup("eventTMWS:Too many windows - " "%s could not create submenu."), wimpt_programname()); } else { wimpt_noerr(wimp_create_submenu( (wimp_menustr *)e.data.msg.data.words[0], e.data.msg.data.words[1], e.data.msg.data.words[2])); } } else { for (i=3;e.data.msg.data.words[i] != -1;i++) /* blank! */; e.data.msg.data.words[i++] = -1; event__purpose=event_MENUSUBMENU; event__menuHit(e.data.msg.data.words+3); } break; case wimp_MHELPREQUEST: if (event__returnMenuHelp && e.data.msg.data.helprequest.m.w!=dbox__menuDboxWindow()) { int buff[20]; wimpt_noerr(wimp_getmenustate(1, buff, e.data.msg.data.helprequest.m.w, e.data.msg.data.helprequest.m.i)); if (buff[0]!=-1) { event__purpose=event_MENUHELP; event__menuHit(buff); } } break; case 0x400C9: /* Message_MenusDeleted */ e.e=wimp_EMENU; e.data.menu[0]=-1; event__purpose=event_MENUDELETE; event__menuHit(e.data.menu); break; } break; } if (!win_processevent(&e)) { /* --- Default event handling --- */ switch (e.e) { case wimp_EREDRAW: werr(TRUE,msgs_lookup("Internal error: unserviced redraw event")); break; case wimp_EOPEN: wimpt_noerr(wimp_open_wind(&e.data.o)); break; case wimp_EKEY: wimp_processkey(e.data.key.chcode); break; } } } void event_clear_current_menu(void) { wimpt_noerr(wimp_create_menu((wimp_menustr*)-1,0,0)); if (event__currentMenu) { int i=-1; event__purpose=event_MENUDELETE; event__menuHit(&i); event__currentMenu=0; } }