2003-09-30 17:47:42 +00:00
|
|
|
#include <u.h>
|
2004-03-26 01:59:35 +00:00
|
|
|
#include "x11-inc.h"
|
2003-09-30 17:47:42 +00:00
|
|
|
#include <libc.h>
|
|
|
|
#include <draw.h>
|
|
|
|
#include <thread.h>
|
|
|
|
#include <cursor.h>
|
|
|
|
#include <mouse.h>
|
|
|
|
#include <memdraw.h>
|
|
|
|
#include "x11-memdraw.h"
|
|
|
|
|
2004-03-30 05:03:29 +00:00
|
|
|
int _windowhasfocus = 1;
|
|
|
|
int _wantfocuschanges;
|
|
|
|
|
2003-09-30 17:47:42 +00:00
|
|
|
void
|
|
|
|
moveto(Mousectl *m, Point pt)
|
|
|
|
{
|
2003-12-11 17:48:38 +00:00
|
|
|
_xmoveto(pt);
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
closemouse(Mousectl *mc)
|
|
|
|
{
|
|
|
|
if(mc == nil)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* postnote(PNPROC, mc->pid, "kill");
|
|
|
|
*/
|
|
|
|
do; while(nbrecv(mc->c, &mc->m) > 0);
|
|
|
|
close(mc->mfd);
|
|
|
|
close(mc->cfd);
|
|
|
|
free(mc->file);
|
|
|
|
chanfree(mc->c);
|
|
|
|
chanfree(mc->resizec);
|
|
|
|
free(mc);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
readmouse(Mousectl *mc)
|
|
|
|
{
|
|
|
|
if(mc->display)
|
|
|
|
flushimage(mc->display, 1);
|
|
|
|
if(recv(mc->c, &mc->m) < 0){
|
|
|
|
fprint(2, "readmouse: %r\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-08 17:56:35 +00:00
|
|
|
/*
|
|
|
|
* This is necessary because some X libraries (e.g., on FC3)
|
|
|
|
* use an inordinate amount of stack space to do _xsetcursor.
|
|
|
|
* Perhaps instead there should be a generic "run this X routine"
|
|
|
|
* stack that you send a function and argument to.
|
|
|
|
*/
|
|
|
|
static
|
|
|
|
void
|
|
|
|
_cursorproc(void *arg)
|
|
|
|
{
|
|
|
|
Mousectl *mc;
|
|
|
|
Cursor *c;
|
|
|
|
|
|
|
|
mc = arg;
|
|
|
|
threadsetname("cursorproc (sigh)");
|
|
|
|
for(;;){
|
|
|
|
c = recvp(mc->ccursor);
|
|
|
|
_xsetcursor(c);
|
|
|
|
sendp(mc->ccursorwait, nil);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-30 17:47:42 +00:00
|
|
|
static
|
|
|
|
void
|
|
|
|
_ioproc(void *arg)
|
|
|
|
{
|
2004-12-26 23:24:32 +00:00
|
|
|
int fd, one, buttons;
|
2004-03-30 05:03:29 +00:00
|
|
|
Atom a;
|
2003-10-11 02:47:43 +00:00
|
|
|
ulong mask;
|
2003-09-30 17:47:42 +00:00
|
|
|
Mouse m;
|
|
|
|
Mousectl *mc;
|
|
|
|
XEvent xevent;
|
|
|
|
|
|
|
|
one = 1;
|
|
|
|
mc = arg;
|
|
|
|
threadsetname("mouseproc");
|
|
|
|
memset(&m, 0, sizeof m);
|
|
|
|
mc->pid = getpid();
|
2003-10-11 02:47:43 +00:00
|
|
|
mask = MouseMask|ExposureMask|StructureNotifyMask;
|
|
|
|
XSelectInput(_x.mousecon, _x.drawable, mask);
|
2004-02-29 22:10:26 +00:00
|
|
|
fd = XConnectionNumber(_x.mousecon);
|
2004-12-26 23:24:32 +00:00
|
|
|
buttons = 0;
|
2003-09-30 17:47:42 +00:00
|
|
|
for(;;){
|
2003-10-11 02:47:43 +00:00
|
|
|
XNextEvent(_x.mousecon, &xevent);
|
2003-09-30 17:47:42 +00:00
|
|
|
switch(xevent.type){
|
|
|
|
case Expose:
|
2003-12-11 17:48:38 +00:00
|
|
|
_xexpose(&xevent, _x.mousecon);
|
2003-09-30 17:47:42 +00:00
|
|
|
continue;
|
2003-11-23 18:15:43 +00:00
|
|
|
case DestroyNotify:
|
2003-12-11 17:48:38 +00:00
|
|
|
if(_xdestroy(&xevent, _x.mousecon)){
|
2003-11-23 18:15:43 +00:00
|
|
|
/* drain it before sending */
|
|
|
|
/* apps that care can notice we sent a 0 */
|
|
|
|
/* otherwise we'll have getwindow send SIGHUP */
|
|
|
|
nbrecv(mc->resizec, 0);
|
|
|
|
nbrecv(mc->resizec, 0);
|
|
|
|
send(mc->resizec, 0);
|
|
|
|
}
|
|
|
|
continue;
|
2003-09-30 17:47:42 +00:00
|
|
|
case ConfigureNotify:
|
2003-12-11 17:48:38 +00:00
|
|
|
if(_xconfigure(&xevent, _x.mousecon))
|
2003-09-30 17:47:42 +00:00
|
|
|
nbsend(mc->resizec, &one);
|
|
|
|
continue;
|
2003-10-11 02:47:43 +00:00
|
|
|
case SelectionRequest:
|
2003-12-11 17:48:38 +00:00
|
|
|
_xselect(&xevent, _x.mousecon);
|
2003-10-11 02:47:43 +00:00
|
|
|
continue;
|
2003-09-30 17:47:42 +00:00
|
|
|
case ButtonPress:
|
|
|
|
case ButtonRelease:
|
|
|
|
case MotionNotify:
|
2004-03-31 05:15:02 +00:00
|
|
|
/* If the motion notifications are backing up, skip over some. */
|
2004-12-26 23:24:32 +00:00
|
|
|
if(0 && xevent.type == MotionNotify){
|
2004-03-31 05:15:02 +00:00
|
|
|
while(XCheckWindowEvent(_x.mousecon, _x.drawable, MouseMask, &xevent)){
|
|
|
|
if(xevent.type != MotionNotify)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-12-26 23:24:32 +00:00
|
|
|
m.buttons = buttons;
|
2003-12-11 17:48:38 +00:00
|
|
|
if(_xtoplan9mouse(_x.mousecon, &xevent, &m) < 0)
|
2003-09-30 17:47:42 +00:00
|
|
|
continue;
|
2004-12-26 23:24:32 +00:00
|
|
|
buttons = m.buttons;
|
2003-09-30 17:47:42 +00:00
|
|
|
send(mc->c, &m);
|
|
|
|
/*
|
|
|
|
* mc->Mouse is updated after send so it doesn't have wrong value if we block during send.
|
|
|
|
* This means that programs should receive into mc->Mouse (see readmouse() above) if
|
|
|
|
* they want full synchrony.
|
|
|
|
*/
|
|
|
|
mc->m = m;
|
|
|
|
break;
|
2004-03-30 05:03:29 +00:00
|
|
|
case ClientMessage:
|
|
|
|
if(xevent.xclient.message_type == _x.wmprotos){
|
|
|
|
a = xevent.xclient.data.l[0];
|
|
|
|
if(_wantfocuschanges && a == _x.takefocus){
|
|
|
|
_windowhasfocus = 1;
|
|
|
|
_x.newscreenr = _x.screenr;
|
|
|
|
nbsend(mc->resizec, &one);
|
|
|
|
}else if(_wantfocuschanges && a == _x.losefocus){
|
|
|
|
_windowhasfocus = 0;
|
|
|
|
_x.newscreenr = _x.screenr;
|
|
|
|
nbsend(mc->resizec, &one);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mousectl*
|
|
|
|
initmouse(char *file, Image *i)
|
|
|
|
{
|
|
|
|
Mousectl *mc;
|
|
|
|
|
|
|
|
mc = mallocz(sizeof(Mousectl), 1);
|
|
|
|
if(i)
|
|
|
|
mc->display = i->display;
|
|
|
|
mc->c = chancreate(sizeof(Mouse), 0);
|
2004-12-26 23:24:32 +00:00
|
|
|
chansetname(mc->c, "mousec");
|
2003-09-30 17:47:42 +00:00
|
|
|
mc->resizec = chancreate(sizeof(int), 2);
|
2004-12-26 23:24:32 +00:00
|
|
|
chansetname(mc->resizec, "resizec");
|
2005-02-08 17:56:35 +00:00
|
|
|
mc->ccursor = chancreate(sizeof(void*), 0);
|
|
|
|
chansetname(mc->ccursor, "ccursor");
|
|
|
|
mc->ccursorwait = chancreate(sizeof(void*), 0);
|
|
|
|
chansetname(mc->ccursor, "ccursorwait");
|
2005-01-23 16:02:04 +00:00
|
|
|
proccreate(_ioproc, mc, 256*1024);
|
2005-02-08 17:56:35 +00:00
|
|
|
proccreate(_cursorproc, mc, 256*1024); /* sigh */
|
2003-09-30 17:47:42 +00:00
|
|
|
return mc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
setcursor(Mousectl *mc, Cursor *c)
|
|
|
|
{
|
2005-02-08 17:56:35 +00:00
|
|
|
qlock(&mc->cursorlock);
|
|
|
|
sendp(mc->ccursor, c);
|
|
|
|
recvp(mc->ccursorwait);
|
|
|
|
qunlock(&mc->cursorlock);
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
2004-04-24 04:52:49 +00:00
|
|
|
/*
|
|
|
|
* Send the mouse event back to the window manager.
|
|
|
|
* So that 9term can tell rio to pop up its button3 menu.
|
|
|
|
* Note that we're using _x.mousecon in a few places,
|
|
|
|
* so we have to be sure that the mouse proc isn't using it
|
|
|
|
* when we call! This is all a bit wonky and should be
|
|
|
|
* avoided unless you know what you're doing.
|
|
|
|
*/
|
2004-03-30 05:03:29 +00:00
|
|
|
void
|
|
|
|
bouncemouse(Mouse *m)
|
|
|
|
{
|
|
|
|
XButtonEvent e;
|
2004-04-24 04:52:49 +00:00
|
|
|
XWindow dw;
|
2004-03-30 05:03:29 +00:00
|
|
|
|
|
|
|
e.type = ButtonPress;
|
|
|
|
e.state = 0;
|
|
|
|
e.button = 0;
|
|
|
|
if(m->buttons&1)
|
|
|
|
e.button = 1;
|
|
|
|
else if(m->buttons&2)
|
|
|
|
e.button = 2;
|
|
|
|
else if(m->buttons&4)
|
|
|
|
e.button = 3;
|
2004-04-24 04:52:49 +00:00
|
|
|
e.same_screen = 1;
|
|
|
|
XTranslateCoordinates(_x.display, _x.drawable,
|
|
|
|
DefaultRootWindow(_x.display),
|
|
|
|
m->xy.x, m->xy.y, &e.x_root, &e.y_root, &dw);
|
|
|
|
e.root = DefaultRootWindow(_x.mousecon);
|
|
|
|
e.window = e.root;
|
|
|
|
e.subwindow = None;
|
|
|
|
e.x = e.x_root;
|
|
|
|
e.y = e.y_root;
|
2004-03-30 05:03:29 +00:00
|
|
|
#undef time
|
|
|
|
e.time = CurrentTime;
|
2004-04-24 04:52:49 +00:00
|
|
|
XUngrabPointer(_x.mousecon, m->msec);
|
|
|
|
XSendEvent(_x.mousecon, e.root, True, ButtonPressMask, (XEvent*)&e);
|
|
|
|
XFlush(_x.mousecon);
|
2004-03-30 05:03:29 +00:00
|
|
|
}
|