diff options
Diffstat (limited to '')
-rw-r--r-- | ecore/src/e_events.c | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/ecore/src/e_events.c b/ecore/src/e_events.c new file mode 100644 index 0000000..0a8f442 --- /dev/null +++ b/ecore/src/e_events.c @@ -0,0 +1,430 @@ +#include "Ecore.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* glocal (yes global/local) variabels for events */ +Ecore_Event_Fd_Handler *fd_handlers = NULL; +Ecore_Event_Ipc_Handler *ipc_handlers = NULL; +Ecore_Event_Pid_Handler *pid_handlers = NULL; +Ecore_Event_Timer *timers = NULL; + +Ecore_Event *events = NULL; +Ecore_Event *last_event = NULL; + +int __quit_ev_loop = 0; + +/* local functions for event handling */ +static void ecore_handle_event_timer(void); +static void ecore_handle_zero_event_timer(void); + +/* public functions */ + +/* add an event to the end of the event queue */ +void +ecore_add_event(Ecore_Event_Type type, void *event, + void (*ev_free) (void *event)) +{ + Ecore_Event *ev; + + ev = NEW(Ecore_Event, 1); + ev->type = type; + ev->ignore = 0; + ev->event = event; + ev->next = NULL; + ev->ev_free = ev_free; + if (!events) + events = ev; + else + last_event->next = ev; + last_event = ev; +} + +/* delete an event from the event queue */ +void +ecore_del_event(void *event) +{ + Ecore_Event *ev, *pev; + + pev = NULL; + ev = events; + while (ev) + { + if (ev->event == event) + { + if (pev) + pev->next = ev->next; + else + events = ev->next; + if (!ev->next) + last_event = pev; + if ((ev->event) && (ev->ev_free)) + (*ev->ev_free) (ev->event); + FREE(ev); + return; + } + pev = ev; + ev = ev->next; + } +} + +void +ecore_del_all_events(void) +{ + Ecore_Event *ev, *pev; + + ev = events; + while (ev) + { + pev = ev; + ev = ev->next; + if ((pev->event) && (pev->ev_free)) + pev->ev_free(pev->event); + FREE(pev); + } + events = NULL; + last_event = NULL; +} + +Ecore_Event * +ecore_get_last_event(void) +{ + return last_event; +} + +/* add a callback handler if fd is active for reading */ +void +ecore_add_event_fd(int fd, void (*func) (int fd)) +{ + Ecore_Event_Fd_Handler *fd_h; + + /* new handler struct */ + fd_h = NEW(Ecore_Event_Fd_Handler, 1); + fd_h->next = fd_handlers; + fd_h->fd = fd; + fd_h->func = func; + fd_handlers = fd_h; +} + +/* delete handler for fd */ +void +ecore_del_event_fd(int fd) +{ + START_LIST_DEL(Ecore_Event_Fd_Handler, fd_handlers, (_p->fd == fd)); + FREE(_p); + END_LIST_DEL; +} + +void +ecore_add_event_pid(pid_t pid, void (*func) (pid_t pid)) +{ + Ecore_Event_Pid_Handler *pid_h; + + /* delete the old handler */ + ecore_del_event_pid(pid); + /* new handler struct */ + pid_h = NEW(Ecore_Event_Pid_Handler, 1); + pid_h->next = pid_handlers; + pid_h->pid = pid; + pid_h->func = func; + pid_handlers = pid_h; +} + +void +ecore_del_event_pid(pid_t pid) +{ + START_LIST_DEL(Ecore_Event_Pid_Handler, pid_handlers, (_p->pid == pid)); + FREE(_p); + END_LIST_DEL; +} + +void +ecore_add_event_ipc(int ipc, void (*func) (int ipc)) +{ + Ecore_Event_Ipc_Handler *ipc_h; + + /* delete the old handler */ + ecore_del_event_ipc(ipc); + /* new handler struct */ + ipc_h = NEW(Ecore_Event_Ipc_Handler, 1); + ipc_h->next = ipc_handlers; + ipc_h->ipc = ipc; + ipc_h->func = func; + ipc_handlers = ipc_h; +} + +void +ecore_del_event_ipc(int ipc) +{ + START_LIST_DEL(Ecore_Event_Ipc_Handler, ipc_handlers, (_p->ipc == ipc)); + FREE(_p); + END_LIST_DEL; +} + +/* sit in this loop forever and process events */ +void +ecore_event_loop(void) +{ + int fdcount, fdsize, ipccount, ipcsize; + int timed_out, were_events; + double time1, time2, prev_time = 0.0; + struct timeval tval; + fd_set fdset, ipcset; + Ecore_Event_Fd_Handler *fd_h; + Ecore_Event_Pid_Handler *pid_h; + Ecore_Event_Ipc_Handler *ipc_h; + + /* init some of the time variables */ + time1 = ecore_get_time(); + time2 = time1 - prev_time; + prev_time = time1; + while (__quit_ev_loop == 0) + { + /* state setup */ + timed_out = 0; + were_events = 0; + + /* setup fd array from list of listening fd's */ + fdsize = 0; + FD_ZERO(&fdset); + /* for ever fd handler add the fd to the array and incriment fdsize */ + for (fd_h = fd_handlers; fd_h; fd_h = fd_h->next) + { + FD_SET(fd_h->fd, &fdset); + if (fd_h->fd > fdsize) + fdsize = fd_h->fd; + } + fdcount = 1; + ipcsize = 0; + FD_ZERO(&ipcset); + /* for ever fd handler add the fd to the array and incriment fdsize */ + for (ipc_h = ipc_handlers; ipc_h; ipc_h = ipc_h->next) + { + FD_SET(ipc_h->ipc, &ipcset); + if (ipc_h->ipc > ipcsize) + ipcsize = ipc_h->ipc; + } + ipccount = 1; + /* if there are timers setup adjust timeout value and select */ + if (timers) + { + if (timers->just_added) + { + timers->just_added = 0; + time1 = timers->in; + } + else + { + time1 = timers->in - time2; + if (time1 < 0.0) + time1 = 0.0; + timers->in = time1; + } + tval.tv_sec = (long)time1; + tval.tv_usec = (long)((time1 - ((double)tval.tv_sec)) * 1000000); + if (tval.tv_sec < 0) + tval.tv_sec = 0; + if (tval.tv_usec <= 1000) + tval.tv_usec = 1000; + ecore_handle_zero_event_timer(); + if ((!ecore_events_pending()) && (!ecore_event_signal_events_pending())) + fdcount = select(fdsize + 1, &fdset, NULL, NULL, &tval); + } + /* no timers - just sit and block */ + else + { + if ((!ecore_events_pending()) && (!ecore_event_signal_events_pending())) + fdcount = select(fdsize + 1, &fdset, NULL, NULL, NULL); + } + for (pid_h = pid_handlers; pid_h; pid_h = pid_h->next) + pid_h->func(pid_h->pid); + + /* see if we have any new ipc connections */ + tval.tv_sec = 0; + tval.tv_usec = 0; + ipccount += select(ipcsize + 1, &ipcset, NULL, NULL, &tval); + + /* return < 0 - error or signal interrupt */ + if (fdcount < 0) + { + /* error */ + if ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF)) + { + fprintf(stderr, "Lost connection to X display.\n"); + exit(1); + } + } + /* timers are available and its a timeout */ + if ((timers) && (fdcount == 0)) + { + ecore_handle_event_timer(); + timed_out = 1; + } + if (fdcount < 0) + fdcount = 0; + if (ecore_events_pending()) + { + fdcount++; + FD_SET(ecore_x_get_fd(), &fdset); + } + /* fd's are active */ + if (fdcount > 0) + { + /* for every fd handler - if its fd is set - call the func */ + for (fd_h = fd_handlers; fd_h;) + { + Ecore_Event_Fd_Handler *fdh; + + fdh = fd_h; + fd_h = fd_h->next; + if (FD_ISSET(fdh->fd, &fdset)) + fdh->func(fdh->fd); + } + } + + /* ipc clients are active */ + if (ipccount > 0) + { + for (ipc_h = ipc_handlers; ipc_h;) + { + Ecore_Event_Ipc_Handler *ipch; + + ipch = ipc_h; + ipc_h = ipc_h->next; + if (FD_ISSET(ipch->ipc, &ipcset)) + ipch->func(ipch->ipc); + } + } + if (events) + ecore_event_filter(events); + if (events) + { + ecore_event_filter_events_handle(events); + were_events = 1; + } + ecore_del_all_events(); + if ((timed_out) || (were_events)) + ecore_event_filter_idle_handle(); + ecore_flush(); + time1 = ecore_get_time(); + time2 = time1 - prev_time; + prev_time = time1; + } + __quit_ev_loop = 0; +} + +/* set a flag to 0 so that we can quit the event loop and shutdown + * properly */ +void +ecore_event_loop_quit(void) +{ + __quit_ev_loop = 1; +} + +/* add a timeout funcitont o be called in "in" seconds with name name */ +void +ecore_add_event_timer(char *name, double in, void (*func) (int val, void *data), + int val, void *data) +{ + Ecore_Event_Timer *timer, *ptr, *pptr; + double tally; + + if (name) + ecore_del_event_timer(name); + timer = NEW(Ecore_Event_Timer, 1); + timer->next = NULL; + timer->func = func; + timer->data = data; + timer->val = val; + timer->just_added = 1; + timer->in = in; + timer->name = strdup(name); + if (!timers) + timers = timer; + else + { + pptr = NULL; + ptr = timers; + tally = 0.0; + while (ptr) + { + tally += ptr->in; + if (tally > in) + { + tally -= ptr->in; + timer->next = ptr; + if (pptr) + pptr->next = timer; + else + timers = timer; + timer->in -= tally; + if (timer->next) + timer->next->in -= timer->in; + return; + } + pptr = ptr; + ptr = ptr->next; + } + if (pptr) + pptr->next = timer; + else + timers = timer; + timer->in -= tally; + } +} + +/* delete a timer timeout entry named "name" */ +void * +ecore_del_event_timer(char *name) +{ + Ecore_Event_Timer *timer, *ptr, *pptr; + + pptr = NULL; + ptr = timers; + while (ptr) + { + timer = ptr; + if (!strcmp(timer->name, name)) + { + void *data; + + if (pptr) + pptr->next = timer->next; + else + timers = timer->next; + if (timer->next) + timer->next->in += timer->in; + IF_FREE(timer->name); + data = timer->data; + FREE(timer); + return data; + } + pptr = ptr; + ptr = ptr->next; + } + return NULL; +} + +/* private functions */ +static void +ecore_handle_event_timer(void) +{ + Ecore_Event_Timer *timer; + + if (!timers) + return; + timer = timers; + timers = timer->next; + (*(timer->func)) (timer->val, timer->data); + IF_FREE(timer->name); + FREE(timer); +} + +static void +ecore_handle_zero_event_timer(void) +{ + while ((timers) && (timers->in == 0.0)) + ecore_handle_event_timer(); +} |