ref: c51962a648b3f38fc378ad0081b1d1aa037142d5
dir: /event.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <mouse.h> #include <keyboard.h> #include <thread.h> #include "guifs.h" GuiElement * elementat(Point p) { GuiElement *g = nil; rlock(&root->lock); if(ptinrect(p, root->rect)) g = root; runlock(&root->lock); while(g){ GuiElement *next = nil; rlock(&g->lock); for(int n = 0; n < g->nchildren && next == nil; n++){ GuiElement *child = g->children[n]; rlock(&child->lock); if(ptinrect(p, child->rect)) /* TODO: does not account for floating elements (not a thing yet) */ next = child; runlock(&child->lock); } runlock(&g->lock); if(next) g = next; else break; } return g; } typedef struct SendEvent SendEvent; struct SendEvent { Channel *chan; char *event; }; void sendeventthread(void *arg) { SendEvent *s = arg; send(s->chan, &s->event); } void sendevent(GuiElement *g, Event event) { SendEvent *s = emalloc(sizeof(SendEvent)); s->chan = g->events; Event *e = emalloc(sizeof(Event)); memcpy(e, &event, sizeof(Event)); switch(e->type){ case Xmousedown: s->event = smprint("mousedown %C\n", e->r); break; case Xmouseup: s->event = smprint("mouseup %C\n", e->r); break; case Xmouseclick: s->event = smprint("mouseclick %C\n", e->r); break; case Xmousescroll: s->event = smprint("mousescroll %s\n", e->direction == Up ? "up" : "down"); break; case Xmenuhit: s->event = smprint("menuhit %c %d %s\n", e->hit.button, e->hit.which, e->hit.text); break; case Xkeyboard: s->event = smprint("key %C\n", e->r); break; default: s->event = smprint("???\n"); break; } if(nbsend(s->chan, &s->event) == 0) threadcreate(sendeventthread, s, 1024); } int mouseevent(Mouse m) { GuiElement *g = elementat(mousexy); static int lastbuttons = 0; static GuiElement *lastL = nil; static GuiElement *lastM = nil; static GuiElement *lastR = nil; int down = 0; int b = lastbuttons ^ m.buttons; lastbuttons = m.buttons; if(b&4 && m.buttons&4){ lastR = g; down = 3; } if(b&2 && m.buttons&2){ lastM = g; down = 2; } if(b&1 && m.buttons&1){ lastL = g; down = 1; } if(!g) return 0; wlock(&g->lock); Event e; MenuSpec *ms = getprop(g, Pmenus, 0).menus; if(down >= 1 && down <= 3 && ms->menus[down-1] != nil){ int which = menuhit(down, mousectl, ms->menus[down-1], nil); e.type = Xmenuhit; e.hit.button = (down == 1) ? 'L' : (down == 2) ? 'M' : 'R'; e.hit.which = which; e.hit.text = ms->menus[down-1]->item[which]; if(g->listening && which != -1) sendevent(g, e); wunlock(&g->lock); switch(down){ case 1: lastL = nil; break; case 2: lastM = nil; break; case 3: lastR = nil; break; } lastbuttons = lastbuttons ^ (1<<(down-1)); return 1; } if(!g->listening){ wunlock(&g->lock); return 0; } b = g->buttons ^ m.buttons; g->buttons = m.buttons; if(b&16 && m.buttons&16){ e.type = Xmousescroll; e.direction = Down; sendevent(g, e); } if(b&8 && m.buttons&8){ e.type = Xmousescroll; e.direction = Up; sendevent(g, e); } if(b&4){ e.type = (m.buttons&4) ? Xmousedown : Xmouseup; e.r = 'R'; sendevent(g, e); if(e.type == Xmouseup){ if(lastR == g){ e.type = Xmouseclick; sendevent(g, e); } lastR = nil; } } if(b&2){ e.type = (m.buttons&2) ? Xmousedown : Xmouseup; e.r = 'M'; sendevent(g, e); if(e.type == Xmouseup){ if(lastM == g){ e.type = Xmouseclick; sendevent(g, e); } lastM = nil; } } if(b&1){ e.type = (m.buttons&1) ? Xmousedown : Xmouseup; e.r = 'L'; sendevent(g, e); if(e.type == Xmouseup){ if(lastL == g){ e.type = Xmouseclick; sendevent(g, e); } lastL = nil; } } wunlock(&g->lock); return 0; } int keyboardevent(Rune r) { if(r == Kdel){ /* The user hit DEL */ postnote(PNGROUP, getpid(), "interrupt"); exits("interrupt"); } GuiElement *g = elementat(mousexy); if(!g) return 0; wlock(&g->lock); if(g->listening){ Event e; e.type = Xkeyboard; e.r = r; sendevent(g, e); } if(g->type == Gtextbox){ PropVal val = getprop(g, Ptext, 0); long len = runestrlen(val.text); Rune *text = emalloc(sizeof(Rune) * (len + 2)); memcpy(text, val.text, sizeof(Rune) * len); text[len] = r; val.text = text; setprop(g, Ptext, val, 0); } wunlock(&g->lock); return 1; }