]> Pileus Git - wmpus/blob - sys-x11.c
ed2a9e4d77bd04004ad0a5591319a726f0118c49
[wmpus] / sys-x11.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <search.h>
4
5 #include <X11/Xlib.h>
6 #include <X11/Xproto.h>
7 #include <X11/keysym.h>
8
9 #include "util.h"
10 #include "sys.h"
11 #include "wm.h"
12
13 /* Internal structures */
14 struct win_sys {
15         Window   xid;
16         Display *dpy;
17 };
18
19 typedef struct {
20         Key_t key;
21         int   sym;
22 } keymap_t;
23
24 /* Global data */
25 void *win_cache = NULL;
26
27 /* Conversion functions */
28 keymap_t key2sym[] = {
29         {key_left    , XK_Left },
30         {key_right   , XK_Right},
31         {key_up      , XK_Up   },
32         {key_down    , XK_Down },
33         {key_home    , XK_Home },
34         {key_end     , XK_End  },
35         {key_pageup  , XK_Prior},
36         {key_pagedown, XK_Next },
37         {key_f1      , XK_F1   },
38         {key_f2      , XK_F2   },
39         {key_f3      , XK_F3   },
40         {key_f4      , XK_F4   },
41         {key_f5      , XK_F5   },
42         {key_f6      , XK_F6   },
43         {key_f7      , XK_F7   },
44         {key_f8      , XK_F8   },
45         {key_f9      , XK_F9   },
46         {key_f10     , XK_F10  },
47         {key_f11     , XK_F11  },
48         {key_f12     , XK_F12  },
49 };
50
51 /* - Modifiers */
52 mod_t x2mod(unsigned int state, int up)
53 {
54         return (mod_t){
55                .alt   = !!(state & Mod1Mask   ),
56                .ctrl  = !!(state & ControlMask),
57                .shift = !!(state & ShiftMask  ),
58                .win   = !!(state & Mod4Mask   ),
59                .up    = up,
60         };
61 }
62
63 unsigned int mod2x(mod_t mod)
64 {
65         return mod.alt   ? Mod1Mask    : 0
66              | mod.ctrl  ? ControlMask : 0
67              | mod.shift ? ShiftMask   : 0
68              | mod.win   ? Mod4Mask    : 0;
69 }
70
71 /* - Keycodes */
72 Key_t x2key(KeySym sym)
73 {
74         keymap_t *km = map_getr(key2sym,sym);
75         return km ? km->key : sym;
76 }
77
78 KeySym key2x(Key_t key)
79 {
80         keymap_t *km = map_get(key2sym,key);
81         return km ? km->sym : key;
82 }
83
84 Key_t x2btn(int btn)
85 {
86         return btn + key_mouse0;
87 }
88
89 int btn2x(Key_t key)
90 {
91         return key - key_mouse0;
92 }
93
94 /* - Pointers */
95 ptr_t x2ptr(XEvent *_ev)
96 {
97         XKeyEvent *ev = &_ev->xkey;
98         return (ptr_t){ev->x, ev->y, ev->x_root, ev->y_root};
99 }
100
101 /* Helper functions */
102 win_t *win_new(Display *dpy, Window xid)
103 {
104         XWindowAttributes attr;
105         XGetWindowAttributes(dpy, xid, &attr);
106         win_t *win    = new0(win_t);
107         win->x        = attr.x;
108         win->y        = attr.y;
109         win->w        = attr.width;
110         win->h        = attr.height;
111         win->sys      = new0(win_sys_t);
112         win->sys->dpy = dpy;
113         win->sys->xid = xid;
114         printf("win_new: %p = %p, %d\n", win, dpy, (int)xid);
115         return win;
116 }
117
118 int win_cmp(const void *_a, const void *_b)
119 {
120         const win_t *a = _a, *b = _b;
121         if (a->sys->dpy < b->sys->dpy) return -1;
122         if (a->sys->dpy > b->sys->dpy) return  1;
123         if (a->sys->xid < b->sys->xid) return -1;
124         if (a->sys->xid > b->sys->xid) return  1;
125         return 0;
126 }
127
128 win_t *win_find(Display *dpy, Window xid)
129 {
130         if (!dpy || !xid)
131                 return NULL;
132         //printf("win_find: %p, %d\n", dpy, (int)xid);
133         win_sys_t sys = {.dpy=dpy, .xid=xid};
134         win_t     tmp = {.sys=&sys};
135         return *(win_t**)(tfind(&tmp, &win_cache, win_cmp) ?:
136                 tsearch(win_new(dpy,xid), &win_cache, win_cmp));
137 }
138
139 void win_remove(win_t *win)
140 {
141         tdelete(win, &win_cache, win_cmp);
142         free(win->sys);
143         free(win);
144 }
145
146 /* Callbacks */
147 void process_event(int type, XEvent *ev, win_t *root)
148 {
149         Display  *dpy = root->sys->dpy;
150         Window    rid = root->sys->xid;
151
152         /* Common data for all these events ... */
153         win_t *win = NULL; ptr_t ptr; mod_t mod;
154         if (type == KeyPress    || type == KeyRelease    ||
155             type == ButtonPress || type == ButtonRelease ||
156             type == MotionNotify) {
157                 Window xid = ev->xkey.subwindow ?: rid;
158                 win = win_find(dpy,xid);
159                 ptr = x2ptr(ev);
160                 mod = x2mod(ev->xkey.state, type==KeyRelease||type==ButtonRelease);
161         }
162
163         /* Split based on event */
164         //printf("event: %d\n", type);
165         if (type == KeyPress) {
166                 while (XCheckTypedEvent(dpy, KeyPress, ev));
167                 KeySym sym = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0);
168                 wm_handle_key(win, x2key(sym), mod, ptr);
169         }
170         else if (type == KeyRelease) {
171                 //printf("release: %d\n", type);
172         }
173         else if (type == ButtonPress) {
174                 wm_handle_key(win, x2btn(ev->xbutton.button), mod, ptr);
175                 XGrabPointer(dpy, win->sys->xid, True, PointerMotionMask|ButtonReleaseMask,
176                                 GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
177         }
178         else if (type == ButtonRelease) {
179                 XUngrabPointer(dpy, CurrentTime);
180                 wm_handle_key(win, x2btn(ev->xbutton.button), mod, ptr);
181         }
182         else if (type == MotionNotify) {
183                 while (XCheckTypedEvent(dpy, MotionNotify, ev));
184                 wm_handle_ptr(win, ptr);
185         }
186         else if (type == ConfigureNotify) {
187                 //printf("configure: %d\n", type);
188         }
189         else if (type == MapNotify) {
190                 //printf("map: %d\n", type);
191         }
192         else if (type == DestroyNotify) {
193                 //printf("destory: %d\n", type);
194                 win_remove(win_find(dpy,ev->xdestroywindow.window));
195         }
196         else if (type == UnmapNotify) {
197                 //printf("unmap: %d\n", type);
198                 wm_remove(win_find(dpy,ev->xmap.window));
199         }
200         else if (type == ConfigureRequest) {
201                 XConfigureRequestEvent *cre = &ev->xconfigurerequest;
202                 XWindowChanges wc = {
203                         .x     = cre->x,     .y      = cre->y,
204                         .width = cre->width, .height = cre->height,
205                 };
206                 printf("configure_req: %d - %x, (0x%lx) %dx%d @ %d,%d\n",
207                                 type, (int)cre->window, cre->value_mask,
208                                 cre->height, cre->width, cre->x, cre->y);
209                 XConfigureWindow(dpy, cre->window, cre->value_mask, &wc);
210         }
211         else if (type == MapRequest) {
212                 printf("map_req: %d\n", type);
213                 wm_insert(win_find(dpy,ev->xmaprequest.window));
214                 XMapWindow(dpy,ev->xmaprequest.window);
215         }
216         else {
217                 printf("unknown event: %d\n", type);
218         }
219 }
220
221 /*****************
222  * Sys functions *
223  *****************/
224 void sys_move(win_t *win, int x, int y, int w, int h)
225 {
226         //printf("sys_move: %p - %d,%d  %dx%d\n", win, x, y, w, h);
227         win->x = x; win->y = y;
228         win->w = w; win->h = h;
229         XMoveResizeWindow(win->sys->dpy, win->sys->xid, x, y, w, h);
230 }
231
232 void sys_raise(win_t *win)
233 {
234         //printf("sys_raise: %p\n", win);
235         XRaiseWindow(win->sys->dpy, win->sys->xid);
236 }
237
238 void sys_focus(win_t *win)
239 {
240         //printf("sys_raise: %p\n", win);
241         XSetInputFocus(win->sys->dpy, win->sys->xid,
242                         RevertToNone, CurrentTime);
243 }
244
245 void sys_watch(win_t *win, Key_t key, mod_t mod)
246 {
247         if (key_mouse0 <= key && key <= key_mouse7)
248                 XGrabButton(win->sys->dpy, btn2x(key), mod2x(mod), win->sys->xid, True,
249                                 mod.up ? ButtonReleaseMask : ButtonPressMask,
250                                 GrabModeAsync, GrabModeAsync, None, None);
251         else
252                 XGrabKey(win->sys->dpy, XKeysymToKeycode(win->sys->dpy, key2x(key)),
253                                 mod2x(mod), win->sys->xid, True, GrabModeAsync, GrabModeAsync);
254 }
255
256 win_t *sys_init(void)
257 {
258         Display *dpy = XOpenDisplay(NULL);
259         Window   xid = DefaultRootWindow(dpy);
260         XSelectInput(dpy, xid, SubstructureNotifyMask|SubstructureRedirectMask);
261         return win_find(dpy, xid);
262 }
263
264 void sys_run(win_t *root)
265 {
266         /* Add each initial window */
267         unsigned int nkids;
268         Window par, win, *kids = NULL;
269         if (XQueryTree(root->sys->dpy, root->sys->xid,
270                                 &par, &win, &kids, &nkids))
271                 for(int i = 0; i < nkids; i++)
272                         wm_insert(win_find(root->sys->dpy, kids[i]));
273
274         /* Main loop */
275         for(;;)
276         {
277                 XEvent ev;
278                 XNextEvent(root->sys->dpy, &ev);
279                 process_event(ev.type, &ev, root);
280         }
281 }