Blob


1 #include <u.h>
2 #include "x11-inc.h"
3 #include <libc.h>
4 #include <draw.h>
5 #include <thread.h>
6 #include <cursor.h>
7 #include <mouse.h>
8 #include <memdraw.h>
9 #include "x11-memdraw.h"
11 int _windowhasfocus = 1;
12 int _wantfocuschanges;
14 void
15 moveto(Mousectl *m, Point pt)
16 {
17 _xmoveto(pt);
18 }
20 void
21 closemouse(Mousectl *mc)
22 {
23 if(mc == nil)
24 return;
26 /* postnote(PNPROC, mc->pid, "kill");
27 */
28 do; while(nbrecv(mc->c, &mc->m) > 0);
29 close(mc->mfd);
30 close(mc->cfd);
31 free(mc->file);
32 chanfree(mc->c);
33 chanfree(mc->resizec);
34 free(mc);
35 }
37 int
38 readmouse(Mousectl *mc)
39 {
40 if(mc->display)
41 flushimage(mc->display, 1);
42 if(recv(mc->c, &mc->m) < 0){
43 fprint(2, "readmouse: %r\n");
44 return -1;
45 }
46 return 0;
47 }
49 /*
50 * This is necessary because some X libraries (e.g., on FC3)
51 * use an inordinate amount of stack space to do _xsetcursor.
52 * Perhaps instead there should be a generic "run this X routine"
53 * stack that you send a function and argument to.
54 */
55 static
56 void
57 _cursorproc(void *arg)
58 {
59 Mousectl *mc;
60 Cursor *c;
62 mc = arg;
63 threadsetname("cursorproc (sigh)");
64 for(;;){
65 c = recvp(mc->ccursor);
66 _xsetcursor(c);
67 sendp(mc->ccursorwait, nil);
68 }
69 }
71 static
72 void
73 _ioproc(void *arg)
74 {
75 int fd, one, buttons;
76 Atom a;
77 ulong mask;
78 Mouse m;
79 Mousectl *mc;
80 XEvent xevent;
82 one = 1;
83 mc = arg;
84 threadsetname("mouseproc");
85 memset(&m, 0, sizeof m);
86 mc->pid = getpid();
87 mask = MouseMask|ExposureMask|StructureNotifyMask;
88 XSelectInput(_x.mousecon, _x.drawable, mask);
89 fd = XConnectionNumber(_x.mousecon);
90 buttons = 0;
91 for(;;){
92 XNextEvent(_x.mousecon, &xevent);
93 switch(xevent.type){
94 case Expose:
95 _xexpose(&xevent, _x.mousecon);
96 continue;
97 case DestroyNotify:
98 if(_xdestroy(&xevent, _x.mousecon)){
99 /* drain it before sending */
100 /* apps that care can notice we sent a 0 */
101 /* otherwise we'll have getwindow send SIGHUP */
102 nbrecv(mc->resizec, 0);
103 nbrecv(mc->resizec, 0);
104 send(mc->resizec, 0);
106 continue;
107 case ConfigureNotify:
108 if(_xconfigure(&xevent, _x.mousecon))
109 nbsend(mc->resizec, &one);
110 continue;
111 case SelectionRequest:
112 _xselect(&xevent, _x.mousecon);
113 continue;
114 case ButtonPress:
115 case ButtonRelease:
116 case MotionNotify:
117 /* If the motion notifications are backing up, skip over some. */
118 if(0 && xevent.type == MotionNotify){
119 while(XCheckWindowEvent(_x.mousecon, _x.drawable, MouseMask, &xevent)){
120 if(xevent.type != MotionNotify)
121 break;
124 m.buttons = buttons;
125 if(_xtoplan9mouse(_x.mousecon, &xevent, &m) < 0)
126 continue;
127 buttons = m.buttons;
128 send(mc->c, &m);
129 /*
130 * mc->Mouse is updated after send so it doesn't have wrong value if we block during send.
131 * This means that programs should receive into mc->Mouse (see readmouse() above) if
132 * they want full synchrony.
133 */
134 mc->m = m;
135 break;
136 case ClientMessage:
137 if(xevent.xclient.message_type == _x.wmprotos){
138 a = xevent.xclient.data.l[0];
139 if(_wantfocuschanges && a == _x.takefocus){
140 _windowhasfocus = 1;
141 _x.newscreenr = _x.screenr;
142 nbsend(mc->resizec, &one);
143 }else if(_wantfocuschanges && a == _x.losefocus){
144 _windowhasfocus = 0;
145 _x.newscreenr = _x.screenr;
146 nbsend(mc->resizec, &one);
149 break;
154 Mousectl*
155 initmouse(char *file, Image *i)
157 Mousectl *mc;
159 mc = mallocz(sizeof(Mousectl), 1);
160 if(i)
161 mc->display = i->display;
162 mc->c = chancreate(sizeof(Mouse), 0);
163 chansetname(mc->c, "mousec");
164 mc->resizec = chancreate(sizeof(int), 2);
165 chansetname(mc->resizec, "resizec");
166 mc->ccursor = chancreate(sizeof(void*), 0);
167 chansetname(mc->ccursor, "ccursor");
168 mc->ccursorwait = chancreate(sizeof(void*), 0);
169 chansetname(mc->ccursor, "ccursorwait");
170 proccreate(_ioproc, mc, 256*1024);
171 proccreate(_cursorproc, mc, 256*1024); /* sigh */
172 return mc;
175 void
176 setcursor(Mousectl *mc, Cursor *c)
178 qlock(&mc->cursorlock);
179 sendp(mc->ccursor, c);
180 recvp(mc->ccursorwait);
181 qunlock(&mc->cursorlock);
184 /*
185 * Send the mouse event back to the window manager.
186 * So that 9term can tell rio to pop up its button3 menu.
187 * Note that we're using _x.mousecon in a few places,
188 * so we have to be sure that the mouse proc isn't using it
189 * when we call! This is all a bit wonky and should be
190 * avoided unless you know what you're doing.
191 */
192 void
193 bouncemouse(Mouse *m)
195 XButtonEvent e;
196 XWindow dw;
198 e.type = ButtonPress;
199 e.state = 0;
200 e.button = 0;
201 if(m->buttons&1)
202 e.button = 1;
203 else if(m->buttons&2)
204 e.button = 2;
205 else if(m->buttons&4)
206 e.button = 3;
207 e.same_screen = 1;
208 XTranslateCoordinates(_x.display, _x.drawable,
209 DefaultRootWindow(_x.display),
210 m->xy.x, m->xy.y, &e.x_root, &e.y_root, &dw);
211 e.root = DefaultRootWindow(_x.mousecon);
212 e.window = e.root;
213 e.subwindow = None;
214 e.x = e.x_root;
215 e.y = e.y_root;
216 #undef time
217 e.time = CurrentTime;
218 XUngrabPointer(_x.mousecon, m->msec);
219 XSendEvent(_x.mousecon, e.root, True, ButtonPressMask, (XEvent*)&e);
220 XFlush(_x.mousecon);