@@ 0,0 1,204 @@
+#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 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 b = lastbuttons ^ m.buttons;
+ lastbuttons = m.buttons;
+ if(b&4 && m.buttons&4)
+ lastR = g;
+ if(b&2 && m.buttons&2)
+ lastM = g;
+ if(b&1 && m.buttons&1)
+ lastL = g;
+
+ if(!g)
+ return 0;
+
+ wlock(&g->lock);
+ if(!g->listening){
+ wunlock(&g->lock);
+ return 0;
+ }
+
+ b = g->buttons ^ m.buttons;
+ g->buttons = m.buttons;
+
+ Event e;
+ 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;
+}<
\ No newline at end of file