ref: ab90a480eb5233abc4d7122739c24656dd42cc94
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 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;
}