#include "gui.h" #include "gui_defs.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <stdarg.h> /*****************************************************************/ /* generic functions */ /*****************************************************************/ static void event_list_append(struct gui *g, struct event *e) { struct event_list *new; new = calloc(1, sizeof(struct event_list)); if (new == NULL) OOM; new->item = e; if (g->queued_events == NULL) { g->queued_events = new; new->last = new; return; } g->queued_events->last->next = new; g->queued_events->last = new; } static void free_event(struct event *e) { switch (e->type) { case REPACK: /* nothing */ break; case DIRTY: /* nothing */ break; } free(e); } static int events_equal(struct event *e1, struct event *e2) { if (e1->type != e2->type) return 0; switch (e1->type) { case REPACK: { struct repack_event *re1 = (struct repack_event *)e1; struct repack_event *re2 = (struct repack_event *)e2; return re1->id == re2->id; } case DIRTY: { struct dirty_event *re1 = (struct dirty_event *)e1; struct dirty_event *re2 = (struct dirty_event *)e2; return re1->id == re2->id; }} /* unreachable */ abort(); } /*****************************************************************/ /* sending events */ /*****************************************************************/ static event *new_event_repack(int id) { struct repack_event *ret; ret = calloc(1, sizeof(struct repack_event)); if (ret == NULL) OOM; ret->id = id; return ret; } static event *new_event_dirty(int id) { struct dirty_event *ret; ret = calloc(1, sizeof(struct dirty_event)); if (ret == NULL) OOM; ret->id = id; return ret; } static void compress_event_list(struct gui *g) { struct event *last; struct event_list *cur; /* basic compression, to be refined */ /* pickup last event and remove every copy of it found before * if it's DIRTY or REPACK */ last = g->queued_events->last->item; if (last->type == DIRTY || last->type == REPACK) { cur = g->queued_events; while (cur->item != last) { if (cur->item != NULL && events_equal(cur->item, last)) { free_event(cur->item); cur->item = NULL; } cur = cur->next; } } } void send_event(gui *_gui, enum event_type type, ...) { LOGD("send_event %d\n", type); struct gui *g = _gui; int do_write = 0; va_list ap; struct event *e = NULL; /* initialization not necessary but gcc is not happy */ if (g->queued_events == NULL) do_write = 1; va_start(ap, type); switch (type) { case REPACK: { int id; id = va_arg(ap, int); e = new_event_repack(id); break; } case DIRTY: { int id; id = va_arg(ap, int); e = new_event_dirty(id); break; } } va_end(ap); e->type = type; event_list_append(g, e); compress_event_list(g); if (do_write) { char c = 1; if (write(g->event_pipe[1], &c, 1) != 1) ERR("error writing to pipe: %s\n", strerror(errno)); } } /*****************************************************************/ /* processing events */ /*****************************************************************/ static void repack_event(struct gui *g, int id) { struct widget *w = find_widget(g, id); if (w == NULL) { WARN("widget id %d not found\n", id); return; } w->repack(g, w); } /* TODO: put that function somewhere else? */ static struct toplevel_window_widget *get_toplevel_window(struct widget *w) { while (w != NULL) { if (w->type == TOPLEVEL_WINDOW) return (struct toplevel_window_widget *)w; w = w->parent; } return NULL; } static void dirty_event(struct gui *g, int id) { struct widget *w = find_widget(g, id); struct toplevel_window_widget *win; if (w == NULL) { WARN("widget id %d not found\n", id); return; } win = get_toplevel_window(w); if (win == NULL) { WARN("widget id %d not contained in a window\n", id); return; } g->xwin = win->x; w->clear(g, w); w->paint(g, w); g->xwin = NULL; g->repainted = 1; } static void process_event(struct gui *g, struct event *e) { LOGD("processing event type %d\n", e->type); switch (e->type) { case REPACK: repack_event(g, ((struct repack_event *)e)->id); break; case DIRTY: dirty_event(g, ((struct dirty_event *)e)->id); break; } } /* TODO: events' compression */ void gui_events(gui *_gui) { struct gui *g = _gui; LOGD("gui_events START: head %p\n", g->queued_events); while (g->queued_events) { struct event_list *cur = g->queued_events; g->queued_events = cur->next; if (g->queued_events) g->queued_events->last = cur->last; if (cur->item != NULL) { process_event(g, cur->item); free_event(cur->item); } free(cur); } LOGD("gui_events DONE\n"); }