Blame


1 e573cb09 2020-09-27 op /*
2 e573cb09 2020-09-27 op * Copyright (c) 2020 Omar Polo <op@omarpolo.com>
3 e573cb09 2020-09-27 op *
4 e573cb09 2020-09-27 op * Permission to use, copy, modify, and distribute this software for any
5 e573cb09 2020-09-27 op * purpose with or without fee is hereby granted, provided that the above
6 e573cb09 2020-09-27 op * copyright notice and this permission notice appear in all copies.
7 e573cb09 2020-09-27 op *
8 e573cb09 2020-09-27 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 e573cb09 2020-09-27 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 e573cb09 2020-09-27 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 e573cb09 2020-09-27 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 e573cb09 2020-09-27 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 e573cb09 2020-09-27 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 e573cb09 2020-09-27 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 e573cb09 2020-09-27 op */
16 e573cb09 2020-09-27 op
17 e573cb09 2020-09-27 op #include "star-platinum.h"
18 e573cb09 2020-09-27 op
19 e573cb09 2020-09-27 op #include <err.h>
20 e0041ee5 2020-10-01 op #include <signal.h>
21 13cc0916 2020-09-30 op #include <stdarg.h>
22 e573cb09 2020-09-27 op #include <stdio.h>
23 e573cb09 2020-09-27 op #include <string.h>
24 e573cb09 2020-09-27 op #include <unistd.h>
25 e573cb09 2020-09-27 op
26 e573cb09 2020-09-27 op #include <X11/XKBlib.h>
27 e573cb09 2020-09-27 op #include <X11/Xutil.h>
28 e573cb09 2020-09-27 op
29 e573cb09 2020-09-27 op #ifndef __OpenBSD__
30 e573cb09 2020-09-27 op # define pledge(a, b) 0
31 e573cb09 2020-09-27 op #endif
32 e573cb09 2020-09-27 op
33 e573cb09 2020-09-27 op extern FILE *yyin;
34 e573cb09 2020-09-27 op char *fname;
35 e573cb09 2020-09-27 op
36 e573cb09 2020-09-27 op extern int yylineno;
37 e573cb09 2020-09-27 op int yyparse(void);
38 e573cb09 2020-09-27 op
39 e573cb09 2020-09-27 op struct group *config;
40 e573cb09 2020-09-27 op int goterror = 0;
41 e573cb09 2020-09-27 op
42 e573cb09 2020-09-27 op Display *d;
43 e573cb09 2020-09-27 op
44 e573cb09 2020-09-27 op int ignored_modifiers[] = {
45 ecc6fa05 2020-09-29 op 0, /* no modifiers */
46 e573cb09 2020-09-27 op LockMask, /* caps lock */
47 e573cb09 2020-09-27 op Mod2Mask, /* num lock */
48 e573cb09 2020-09-27 op Mod3Mask, /* scroll lock */
49 e573cb09 2020-09-27 op Mod5Mask, /* ? */
50 e573cb09 2020-09-27 op };
51 e573cb09 2020-09-27 op
52 e573cb09 2020-09-27 op #define IGNORE_MODIFIERS (LockMask | Mod2Mask | Mod3Mask | Mod5Mask)
53 e573cb09 2020-09-27 op
54 13cc0916 2020-09-30 op __attribute__((__format__ (__printf__, 1, 2)))
55 e573cb09 2020-09-27 op void
56 13cc0916 2020-09-30 op yyerror(const char *fmt, ...)
57 e573cb09 2020-09-27 op {
58 13cc0916 2020-09-30 op va_list ap;
59 13cc0916 2020-09-30 op size_t l;
60 13cc0916 2020-09-30 op
61 13cc0916 2020-09-30 op va_start(ap, fmt);
62 13cc0916 2020-09-30 op
63 e573cb09 2020-09-27 op goterror = 1;
64 13cc0916 2020-09-30 op fprintf(stderr, "%s:%d ", fname, yylineno);
65 13cc0916 2020-09-30 op vfprintf(stderr, fmt, ap);
66 13cc0916 2020-09-30 op
67 13cc0916 2020-09-30 op l = strlen(fmt);
68 13cc0916 2020-09-30 op if (l > 0 && fmt[l-1] != '\n')
69 13cc0916 2020-09-30 op fprintf(stderr, "\n");
70 13cc0916 2020-09-30 op
71 13cc0916 2020-09-30 op va_end(ap);
72 e573cb09 2020-09-27 op }
73 e573cb09 2020-09-27 op
74 e573cb09 2020-09-27 op char *
75 e573cb09 2020-09-27 op find_config()
76 e573cb09 2020-09-27 op {
77 e573cb09 2020-09-27 op char *home, *xdg, *t;
78 e573cb09 2020-09-27 op int free_xdg = 0;
79 e573cb09 2020-09-27 op
80 e573cb09 2020-09-27 op home = getenv("HOME");
81 e573cb09 2020-09-27 op xdg = getenv("XDG_CONFIG_HOME");
82 e573cb09 2020-09-27 op
83 e573cb09 2020-09-27 op if (home == NULL && xdg == NULL)
84 e573cb09 2020-09-27 op return NULL;
85 e573cb09 2020-09-27 op
86 e573cb09 2020-09-27 op /* file in home directory >>>>>> XDG shit */
87 e573cb09 2020-09-27 op if (home != NULL) {
88 e573cb09 2020-09-27 op if (asprintf(&t, "%s/.star-platinum.conf", home) == -1)
89 e573cb09 2020-09-27 op return NULL;
90 e573cb09 2020-09-27 op if (access(t, R_OK) == 0)
91 e573cb09 2020-09-27 op return t;
92 e573cb09 2020-09-27 op
93 e573cb09 2020-09-27 op free(t);
94 e573cb09 2020-09-27 op /* continue to search */
95 e573cb09 2020-09-27 op }
96 e573cb09 2020-09-27 op
97 e573cb09 2020-09-27 op /* sanitize XDG_CONFIG_HOME */
98 e573cb09 2020-09-27 op if (xdg == NULL) {
99 e573cb09 2020-09-27 op free_xdg = 1;
100 e573cb09 2020-09-27 op if (asprintf(&xdg, "%s/.config", home) == -1)
101 e573cb09 2020-09-27 op return NULL;
102 e573cb09 2020-09-27 op }
103 e573cb09 2020-09-27 op
104 e573cb09 2020-09-27 op if (asprintf(&t, "%s/star-platinum.conf", xdg) == -1)
105 e573cb09 2020-09-27 op goto err;
106 e573cb09 2020-09-27 op
107 e573cb09 2020-09-27 op if (access(t, R_OK) == 0)
108 e573cb09 2020-09-27 op return t;
109 e573cb09 2020-09-27 op free(t);
110 e573cb09 2020-09-27 op
111 e573cb09 2020-09-27 op err:
112 e573cb09 2020-09-27 op if (free_xdg)
113 e573cb09 2020-09-27 op free(xdg);
114 e573cb09 2020-09-27 op
115 e573cb09 2020-09-27 op return NULL;
116 e573cb09 2020-09-27 op }
117 e573cb09 2020-09-27 op
118 e573cb09 2020-09-27 op int
119 e573cb09 2020-09-27 op main(int argc, char **argv)
120 e573cb09 2020-09-27 op {
121 e573cb09 2020-09-27 op int status = 0, dump_config = 0, conftest = 0, ch;
122 e573cb09 2020-09-27 op XEvent e;
123 e573cb09 2020-09-27 op Window root;
124 e0041ee5 2020-10-01 op
125 e0041ee5 2020-10-01 op signal(SIGCHLD, SIG_IGN); /* don't allow zombies */
126 e573cb09 2020-09-27 op
127 e573cb09 2020-09-27 op fname = NULL;
128 e573cb09 2020-09-27 op while ((ch = getopt(argc, argv, "c:dn")) != -1) {
129 e573cb09 2020-09-27 op switch (ch) {
130 e573cb09 2020-09-27 op case 'c':
131 e573cb09 2020-09-27 op free(fname);
132 e573cb09 2020-09-27 op if ((fname = strdup(optarg)) == NULL)
133 e573cb09 2020-09-27 op err(1, "strdup");
134 e573cb09 2020-09-27 op break;
135 e573cb09 2020-09-27 op
136 e573cb09 2020-09-27 op case 'd':
137 e573cb09 2020-09-27 op dump_config = 1;
138 e573cb09 2020-09-27 op break;
139 e573cb09 2020-09-27 op
140 e573cb09 2020-09-27 op case 'n':
141 e573cb09 2020-09-27 op conftest = 1;
142 e573cb09 2020-09-27 op break;
143 e573cb09 2020-09-27 op
144 e573cb09 2020-09-27 op default:
145 e573cb09 2020-09-27 op fprintf(stderr, "USAGE: %s [-dn] [-c conf]\n", *argv);
146 e573cb09 2020-09-27 op return 1;
147 e573cb09 2020-09-27 op }
148 e573cb09 2020-09-27 op }
149 e573cb09 2020-09-27 op
150 e573cb09 2020-09-27 op if (fname == NULL) {
151 e573cb09 2020-09-27 op if ((fname = find_config()) == NULL)
152 e573cb09 2020-09-27 op errx(1, "can't find a configuration file");
153 e573cb09 2020-09-27 op }
154 e573cb09 2020-09-27 op
155 e573cb09 2020-09-27 op if ((yyin = fopen(fname, "r")) == NULL)
156 e573cb09 2020-09-27 op err(1, "cannot open %s", fname);
157 e573cb09 2020-09-27 op yyparse();
158 e573cb09 2020-09-27 op fclose(yyin);
159 e573cb09 2020-09-27 op
160 e573cb09 2020-09-27 op free(fname);
161 e573cb09 2020-09-27 op fname = NULL;
162 e573cb09 2020-09-27 op
163 e573cb09 2020-09-27 op if (goterror)
164 ecc6fa05 2020-09-29 op return 1;
165 e573cb09 2020-09-27 op
166 e573cb09 2020-09-27 op if (dump_config)
167 e573cb09 2020-09-27 op printgroup(config);
168 e573cb09 2020-09-27 op
169 e573cb09 2020-09-27 op if (conftest) {
170 e573cb09 2020-09-27 op recfree_group(config);
171 e573cb09 2020-09-27 op return 0;
172 e573cb09 2020-09-27 op }
173 e573cb09 2020-09-27 op
174 e573cb09 2020-09-27 op if ((d = XOpenDisplay(NULL)) == NULL) {
175 e573cb09 2020-09-27 op recfree_group(config);
176 e573cb09 2020-09-27 op return 1;
177 e573cb09 2020-09-27 op }
178 e573cb09 2020-09-27 op
179 fe0dcf4e 2020-09-29 op XSetErrorHandler(&error_handler);
180 fe0dcf4e 2020-09-29 op
181 e573cb09 2020-09-27 op root = DefaultRootWindow(d);
182 e573cb09 2020-09-27 op
183 c21d6eaf 2020-10-08 op grabkey_matching_windows();
184 e573cb09 2020-09-27 op
185 c21d6eaf 2020-10-08 op XSelectInput(d, root, SubstructureNotifyMask | KeyPressMask);
186 e573cb09 2020-09-27 op XFlush(d);
187 e573cb09 2020-09-27 op
188 e0041ee5 2020-10-01 op pledge("stdio proc exec", NULL);
189 e573cb09 2020-09-27 op
190 e573cb09 2020-09-27 op while (1) {
191 e573cb09 2020-09-27 op XNextEvent(d, &e);
192 e573cb09 2020-09-27 op switch (e.type) {
193 e573cb09 2020-09-27 op case KeyRelease:
194 e573cb09 2020-09-27 op case KeyPress:
195 e573cb09 2020-09-27 op process_event(config, (XKeyEvent*)&e);
196 e573cb09 2020-09-27 op break;
197 e573cb09 2020-09-27 op
198 c21d6eaf 2020-10-08 op case MapNotify: {
199 c21d6eaf 2020-10-08 op XMapEvent *ev = (XMapEvent*)&e;
200 c21d6eaf 2020-10-08 op grab_matching_keys(ev->window);
201 c21d6eaf 2020-10-08 op break;
202 c21d6eaf 2020-10-08 op }
203 c21d6eaf 2020-10-08 op
204 c21d6eaf 2020-10-08 op case UnmapNotify:
205 c21d6eaf 2020-10-08 op case ConfigureNotify:
206 c21d6eaf 2020-10-08 op case CreateNotify:
207 c21d6eaf 2020-10-08 op case DestroyNotify:
208 c21d6eaf 2020-10-08 op case ClientMessage:
209 c21d6eaf 2020-10-08 op /* ignored */
210 c21d6eaf 2020-10-08 op break;
211 c21d6eaf 2020-10-08 op
212 e573cb09 2020-09-27 op default:
213 e573cb09 2020-09-27 op printf("Unknown event %d\n", e.type);
214 e573cb09 2020-09-27 op break;
215 e573cb09 2020-09-27 op }
216 e573cb09 2020-09-27 op }
217 e573cb09 2020-09-27 op
218 e573cb09 2020-09-27 op XCloseDisplay(d);
219 e573cb09 2020-09-27 op recfree_group(config);
220 e573cb09 2020-09-27 op return status;
221 e573cb09 2020-09-27 op }
222 e573cb09 2020-09-27 op
223 e573cb09 2020-09-27 op
224 e573cb09 2020-09-27 op /* xlib */
225 e573cb09 2020-09-27 op
226 fe0dcf4e 2020-09-29 op int
227 fe0dcf4e 2020-09-29 op error_handler(Display *d, XErrorEvent *e)
228 fe0dcf4e 2020-09-29 op {
229 fe0dcf4e 2020-09-29 op fprintf(stderr, "Xlib error %d\n", e->type);
230 fe0dcf4e 2020-09-29 op return 1;
231 fe0dcf4e 2020-09-29 op }
232 fe0dcf4e 2020-09-29 op
233 e573cb09 2020-09-27 op /* TODO: it should grab ALL POSSIBLE COMBINATIONS of `ignored_modifiers`! */
234 e573cb09 2020-09-27 op void
235 c85d4bf3 2020-10-08 op grabkey(struct key k, Window w)
236 e573cb09 2020-09-27 op {
237 e573cb09 2020-09-27 op static size_t len = sizeof(ignored_modifiers)/sizeof(int);
238 e573cb09 2020-09-27 op size_t i;
239 e573cb09 2020-09-27 op
240 e573cb09 2020-09-27 op /* printf("Grabbing "); printkey(k); printf("\n"); */
241 e573cb09 2020-09-27 op for (i = 0; i < len; ++i) {
242 ecc6fa05 2020-09-29 op XGrabKey(d, XKeysymToKeycode(d, k.key),
243 e573cb09 2020-09-27 op k.modifier | ignored_modifiers[i],
244 c85d4bf3 2020-10-08 op w, False, GrabModeAsync, GrabModeAsync);
245 c21d6eaf 2020-10-08 op }
246 c21d6eaf 2020-10-08 op }
247 c21d6eaf 2020-10-08 op
248 c21d6eaf 2020-10-08 op void
249 c21d6eaf 2020-10-08 op grab_matching_keys(Window w)
250 c21d6eaf 2020-10-08 op {
251 c21d6eaf 2020-10-08 op XClassHint ch;
252 c21d6eaf 2020-10-08 op struct group *g;
253 c21d6eaf 2020-10-08 op struct rule *r;
254 c21d6eaf 2020-10-08 op
255 c21d6eaf 2020-10-08 op if (!XGetClassHint(d, w, &ch))
256 c21d6eaf 2020-10-08 op return;
257 c21d6eaf 2020-10-08 op
258 c21d6eaf 2020-10-08 op for (g = config; g != NULL; g = g->next) {
259 c21d6eaf 2020-10-08 op if (!group_match(g, w))
260 c21d6eaf 2020-10-08 op continue;
261 c21d6eaf 2020-10-08 op
262 c21d6eaf 2020-10-08 op for (r = g->rules; r != NULL; r = r->next)
263 c21d6eaf 2020-10-08 op grabkey(r->key, w);
264 e573cb09 2020-09-27 op }
265 c21d6eaf 2020-10-08 op }
266 c21d6eaf 2020-10-08 op
267 c21d6eaf 2020-10-08 op int
268 c21d6eaf 2020-10-08 op grabkey_matching_windows()
269 c21d6eaf 2020-10-08 op {
270 c21d6eaf 2020-10-08 op Window root, parent, *children;
271 c21d6eaf 2020-10-08 op unsigned int len, i;
272 c21d6eaf 2020-10-08 op
273 c21d6eaf 2020-10-08 op root = DefaultRootWindow(d);
274 c21d6eaf 2020-10-08 op if (!XQueryTree(d, root, &root, &parent, &children, &len))
275 c21d6eaf 2020-10-08 op return 0;
276 c21d6eaf 2020-10-08 op
277 c21d6eaf 2020-10-08 op for (i = 0; i < len; ++i)
278 c21d6eaf 2020-10-08 op grab_matching_keys(children[i]);
279 c21d6eaf 2020-10-08 op
280 c21d6eaf 2020-10-08 op return 1;
281 e573cb09 2020-09-27 op }
282 e573cb09 2020-09-27 op
283 e573cb09 2020-09-27 op KeySym
284 e573cb09 2020-09-27 op keycode_to_keysym(unsigned int kc)
285 e573cb09 2020-09-27 op {
286 e573cb09 2020-09-27 op /* group 0 (?). shift level is 0 because we don't want it*/
287 e573cb09 2020-09-27 op return XkbKeycodeToKeysym(d, kc, 0, 0);
288 e573cb09 2020-09-27 op }
289 e573cb09 2020-09-27 op
290 e573cb09 2020-09-27 op Window
291 e573cb09 2020-09-27 op focused_window()
292 e573cb09 2020-09-27 op {
293 e573cb09 2020-09-27 op Window w;
294 e573cb09 2020-09-27 op int revert_to;
295 e573cb09 2020-09-27 op
296 e573cb09 2020-09-27 op /* one can use (at least) three way to obtain the current
297 e573cb09 2020-09-27 op * focused window using xlib:
298 e573cb09 2020-09-27 op *
299 e573cb09 2020-09-27 op * - XQueryTree : you traverse tre tree until you find the
300 e573cb09 2020-09-27 op * window
301 e573cb09 2020-09-27 op *
302 e573cb09 2020-09-27 op * - looking at _NET_ACTIVE_WINDOW in the root window, but
303 e573cb09 2020-09-27 op * depedns on the window manager to set it
304 e573cb09 2020-09-27 op *
305 e573cb09 2020-09-27 op * - using XGetInputFocus
306 e573cb09 2020-09-27 op *
307 e573cb09 2020-09-27 op * I don't know the pro/cons of these, but XGetInputFocus
308 e573cb09 2020-09-27 op * seems the easiest.
309 e573cb09 2020-09-27 op */
310 e573cb09 2020-09-27 op XGetInputFocus(d, &w, &revert_to);
311 e573cb09 2020-09-27 op return w;
312 e573cb09 2020-09-27 op }
313 e573cb09 2020-09-27 op
314 e573cb09 2020-09-27 op void
315 2eb11d8e 2020-10-04 op send_fake(Window w, struct key k, XKeyEvent *original)
316 e573cb09 2020-09-27 op {
317 e573cb09 2020-09-27 op XKeyEvent e;
318 e573cb09 2020-09-27 op
319 2eb11d8e 2020-10-04 op /*
320 2eb11d8e 2020-10-04 op * this needs to be hijacked. original->window is the root
321 2eb11d8e 2020-10-04 op * window (since we grabbed the key there) and we want to
322 2eb11d8e 2020-10-04 op * deliver the key to another window.
323 2eb11d8e 2020-10-04 op */
324 2eb11d8e 2020-10-04 op e.window = w;
325 e573cb09 2020-09-27 op
326 2eb11d8e 2020-10-04 op /* this is the fake key */
327 e573cb09 2020-09-27 op e.keycode = XKeysymToKeycode(d, k.key);
328 e573cb09 2020-09-27 op e.state = k.modifier;
329 e573cb09 2020-09-27 op
330 2eb11d8e 2020-10-04 op /* the rest is just copying fields from the original event */
331 2eb11d8e 2020-10-04 op e.type = original->type;
332 2eb11d8e 2020-10-04 op e.display = original->display;
333 2eb11d8e 2020-10-04 op e.root = original->root;
334 2eb11d8e 2020-10-04 op e.subwindow = original->subwindow;
335 2eb11d8e 2020-10-04 op e.time = original->time;
336 2eb11d8e 2020-10-04 op e.same_screen = original->same_screen;
337 2eb11d8e 2020-10-04 op e.x = original->x;
338 2eb11d8e 2020-10-04 op e.y = original->y;
339 2eb11d8e 2020-10-04 op e.x_root = original->x_root;
340 2eb11d8e 2020-10-04 op e.y_root = original->y_root;
341 2eb11d8e 2020-10-04 op
342 e573cb09 2020-09-27 op XSendEvent(d, w, True, KeyPressMask, (XEvent*)&e);
343 e573cb09 2020-09-27 op XFlush(d);
344 e573cb09 2020-09-27 op }
345 e573cb09 2020-09-27 op
346 e573cb09 2020-09-27 op int
347 e573cb09 2020-09-27 op window_match_class(Window w, const char *class)
348 e573cb09 2020-09-27 op {
349 e573cb09 2020-09-27 op XClassHint ch;
350 e573cb09 2020-09-27 op int matched;
351 e573cb09 2020-09-27 op
352 ecc6fa05 2020-09-29 op if (!XGetClassHint(d, w, &ch)) {
353 e573cb09 2020-09-27 op fprintf(stderr, "XGetClassHint failed\n");
354 e573cb09 2020-09-27 op return 0;
355 e573cb09 2020-09-27 op }
356 e573cb09 2020-09-27 op
357 e573cb09 2020-09-27 op matched = !strcmp(ch.res_class, class);
358 e573cb09 2020-09-27 op
359 e573cb09 2020-09-27 op XFree(ch.res_name);
360 e573cb09 2020-09-27 op XFree(ch.res_class);
361 e573cb09 2020-09-27 op
362 e573cb09 2020-09-27 op return matched;
363 e573cb09 2020-09-27 op }
364 e573cb09 2020-09-27 op
365 e573cb09 2020-09-27 op
366 e573cb09 2020-09-27 op /* action */
367 e573cb09 2020-09-27 op
368 e573cb09 2020-09-27 op void
369 2eb11d8e 2020-10-04 op do_action(struct action a, Window focused, XKeyEvent *original)
370 e573cb09 2020-09-27 op {
371 e573cb09 2020-09-27 op switch (a.type) {
372 e573cb09 2020-09-27 op case AFAKE:
373 2eb11d8e 2020-10-04 op send_fake(focused, a.send_key, original);
374 e573cb09 2020-09-27 op break;
375 e573cb09 2020-09-27 op
376 e573cb09 2020-09-27 op case ASPECIAL:
377 e573cb09 2020-09-27 op switch (a.special) {
378 e573cb09 2020-09-27 op case ATOGGLE:
379 e573cb09 2020-09-27 op case AACTIVATE:
380 e573cb09 2020-09-27 op case ADEACTIVATE:
381 e573cb09 2020-09-27 op printf("TODO\n");
382 e573cb09 2020-09-27 op break;
383 e573cb09 2020-09-27 op
384 e573cb09 2020-09-27 op case AIGNORE:
385 e573cb09 2020-09-27 op break;
386 e573cb09 2020-09-27 op
387 e573cb09 2020-09-27 op default:
388 e573cb09 2020-09-27 op /* unreachable */
389 e573cb09 2020-09-27 op abort();
390 e573cb09 2020-09-27 op }
391 ecc6fa05 2020-09-29 op break;
392 e573cb09 2020-09-27 op
393 e0041ee5 2020-10-01 op case AEXEC: {
394 e0041ee5 2020-10-01 op pid_t p;
395 e0041ee5 2020-10-01 op const char *sh;
396 c7063e0e 2020-10-04 op
397 c7063e0e 2020-10-04 op /* exec only on key press */
398 c7063e0e 2020-10-04 op if (original->type == KeyRelease)
399 c7063e0e 2020-10-04 op break;
400 e0041ee5 2020-10-01 op
401 e0041ee5 2020-10-01 op switch (p = fork()) {
402 e0041ee5 2020-10-01 op case -1:
403 e0041ee5 2020-10-01 op err(1, "fork");
404 e0041ee5 2020-10-01 op
405 e0041ee5 2020-10-01 op case 0:
406 e0041ee5 2020-10-01 op if ((sh = getenv("SHELL")) == NULL)
407 e0041ee5 2020-10-01 op sh = "/bin/sh";
408 e0041ee5 2020-10-01 op printf("before exec'ing %s -c '%s'\n", sh, a.str);
409 e0041ee5 2020-10-01 op execlp(sh, sh, "-c", a.str, NULL);
410 e0041ee5 2020-10-01 op err(1, "execlp");
411 e0041ee5 2020-10-01 op }
412 e0041ee5 2020-10-01 op
413 e0041ee5 2020-10-01 op break;
414 e0041ee5 2020-10-01 op }
415 e0041ee5 2020-10-01 op
416 e573cb09 2020-09-27 op default:
417 e573cb09 2020-09-27 op /* unreachable */
418 e573cb09 2020-09-27 op abort();
419 e573cb09 2020-09-27 op }
420 e573cb09 2020-09-27 op }
421 e573cb09 2020-09-27 op
422 e0041ee5 2020-10-01 op void
423 e0041ee5 2020-10-01 op free_action(struct action a)
424 e0041ee5 2020-10-01 op {
425 e0041ee5 2020-10-01 op if (a.type == AEXEC)
426 e0041ee5 2020-10-01 op free(a.str);
427 e0041ee5 2020-10-01 op }
428 e0041ee5 2020-10-01 op
429 e573cb09 2020-09-27 op
430 e573cb09 2020-09-27 op /* match */
431 e573cb09 2020-09-27 op
432 e573cb09 2020-09-27 op struct match *
433 e573cb09 2020-09-27 op new_match(int prop, char *s)
434 e573cb09 2020-09-27 op {
435 e573cb09 2020-09-27 op struct match *m;
436 e573cb09 2020-09-27 op
437 e573cb09 2020-09-27 op if ((m = calloc(1, sizeof(*m))) == NULL)
438 e573cb09 2020-09-27 op err(1, "calloc");
439 e573cb09 2020-09-27 op m->prop = prop;
440 e573cb09 2020-09-27 op m->str = s;
441 e573cb09 2020-09-27 op return m;
442 e573cb09 2020-09-27 op }
443 e573cb09 2020-09-27 op
444 e573cb09 2020-09-27 op void
445 e573cb09 2020-09-27 op recfree_match(struct match *m)
446 e573cb09 2020-09-27 op {
447 e573cb09 2020-09-27 op struct match *mt;
448 e573cb09 2020-09-27 op
449 e573cb09 2020-09-27 op if (m == NULL)
450 e573cb09 2020-09-27 op return;
451 e573cb09 2020-09-27 op
452 e573cb09 2020-09-27 op mt = m->next;
453 e573cb09 2020-09-27 op free(m->str);
454 e573cb09 2020-09-27 op free(m);
455 e573cb09 2020-09-27 op recfree_match(mt);
456 e573cb09 2020-09-27 op }
457 e573cb09 2020-09-27 op
458 e573cb09 2020-09-27 op int
459 e573cb09 2020-09-27 op match_window(struct match *m, Window w)
460 e573cb09 2020-09-27 op {
461 ecc6fa05 2020-09-29 op switch (m->prop) {
462 9f53ba9b 2020-09-29 op case MANY:
463 9f53ba9b 2020-09-29 op return 1;
464 9f53ba9b 2020-09-29 op
465 e573cb09 2020-09-27 op case MCLASS:
466 e573cb09 2020-09-27 op return window_match_class(w, m->str);
467 e573cb09 2020-09-27 op break;
468 e573cb09 2020-09-27 op
469 e573cb09 2020-09-27 op default:
470 e573cb09 2020-09-27 op /* unreachable */
471 e573cb09 2020-09-27 op abort();
472 e573cb09 2020-09-27 op }
473 e573cb09 2020-09-27 op }
474 e573cb09 2020-09-27 op
475 e573cb09 2020-09-27 op
476 e573cb09 2020-09-27 op /* rule */
477 e573cb09 2020-09-27 op
478 e573cb09 2020-09-27 op struct rule *
479 e573cb09 2020-09-27 op new_rule(struct key k, struct action a)
480 e573cb09 2020-09-27 op {
481 e573cb09 2020-09-27 op struct rule *r;
482 e573cb09 2020-09-27 op
483 e573cb09 2020-09-27 op if ((r = calloc(1, sizeof(*r))) == NULL)
484 e573cb09 2020-09-27 op err(1, "calloc");
485 e573cb09 2020-09-27 op memcpy(&r->key, &k, sizeof(k));
486 e573cb09 2020-09-27 op memcpy(&r->action, &a, sizeof(a));
487 e573cb09 2020-09-27 op return r;
488 e573cb09 2020-09-27 op }
489 e573cb09 2020-09-27 op
490 e573cb09 2020-09-27 op void
491 e573cb09 2020-09-27 op recfree_rule(struct rule *r)
492 e573cb09 2020-09-27 op {
493 e573cb09 2020-09-27 op struct rule *rt;
494 e573cb09 2020-09-27 op
495 e573cb09 2020-09-27 op if (r == NULL)
496 e573cb09 2020-09-27 op return;
497 e573cb09 2020-09-27 op
498 e573cb09 2020-09-27 op rt = r->next;
499 e573cb09 2020-09-27 op free(r);
500 e573cb09 2020-09-27 op recfree_rule(rt);
501 e573cb09 2020-09-27 op }
502 e573cb09 2020-09-27 op
503 e573cb09 2020-09-27 op int
504 e573cb09 2020-09-27 op rule_matched(struct rule *r, struct key k)
505 e573cb09 2020-09-27 op {
506 e573cb09 2020-09-27 op unsigned int m;
507 e573cb09 2020-09-27 op
508 e573cb09 2020-09-27 op m = k.modifier;
509 e573cb09 2020-09-27 op m &= ~IGNORE_MODIFIERS; /* clear ignored modifiers */
510 e573cb09 2020-09-27 op
511 e573cb09 2020-09-27 op return r->key.modifier == m
512 e573cb09 2020-09-27 op && r->key.key == k.key;
513 e573cb09 2020-09-27 op }
514 e573cb09 2020-09-27 op
515 e573cb09 2020-09-27 op
516 e573cb09 2020-09-27 op /* group */
517 e573cb09 2020-09-27 op
518 e573cb09 2020-09-27 op struct group *
519 e573cb09 2020-09-27 op new_group(struct match *matches, struct rule *rules)
520 e573cb09 2020-09-27 op {
521 e573cb09 2020-09-27 op struct group *g;
522 e573cb09 2020-09-27 op
523 e573cb09 2020-09-27 op if ((g = calloc(1, sizeof(*g))) == NULL)
524 e573cb09 2020-09-27 op err(1, "calloc");
525 e573cb09 2020-09-27 op g->matches = matches;
526 e573cb09 2020-09-27 op g->rules = rules;
527 e573cb09 2020-09-27 op return g;
528 e573cb09 2020-09-27 op }
529 e573cb09 2020-09-27 op
530 e573cb09 2020-09-27 op void
531 e573cb09 2020-09-27 op recfree_group(struct group *g)
532 e573cb09 2020-09-27 op {
533 e573cb09 2020-09-27 op struct group *gt;
534 e573cb09 2020-09-27 op
535 e573cb09 2020-09-27 op if (g == NULL)
536 e573cb09 2020-09-27 op return;
537 e573cb09 2020-09-27 op
538 e573cb09 2020-09-27 op gt = g->next;
539 e573cb09 2020-09-27 op recfree_match(g->matches);
540 e573cb09 2020-09-27 op recfree_rule(g->rules);
541 e573cb09 2020-09-27 op free(g);
542 e573cb09 2020-09-27 op recfree_group(gt);
543 e573cb09 2020-09-27 op }
544 e573cb09 2020-09-27 op
545 e573cb09 2020-09-27 op void
546 e573cb09 2020-09-27 op process_event(struct group *g, XKeyEvent *e)
547 e573cb09 2020-09-27 op {
548 e573cb09 2020-09-27 op Window focused;
549 e573cb09 2020-09-27 op struct rule *r;
550 e573cb09 2020-09-27 op struct key pressed = {
551 e573cb09 2020-09-27 op .modifier = e->state,
552 e573cb09 2020-09-27 op .key = keycode_to_keysym(e->keycode),
553 e573cb09 2020-09-27 op };
554 e573cb09 2020-09-27 op
555 e573cb09 2020-09-27 op focused = focused_window();
556 e573cb09 2020-09-27 op
557 e573cb09 2020-09-27 op for (; g != NULL; g = g->next) {
558 e573cb09 2020-09-27 op if (!group_match(g, focused))
559 e573cb09 2020-09-27 op continue;
560 e573cb09 2020-09-27 op
561 e573cb09 2020-09-27 op for (r = g->rules; r != NULL; r = r->next) {
562 e573cb09 2020-09-27 op if (rule_matched(r, pressed)) {
563 2eb11d8e 2020-10-04 op do_action(r->action, focused, e);
564 e573cb09 2020-09-27 op return;
565 e573cb09 2020-09-27 op }
566 e573cb09 2020-09-27 op }
567 e573cb09 2020-09-27 op }
568 e573cb09 2020-09-27 op
569 2eb11d8e 2020-10-04 op send_fake(focused, pressed, e);
570 e573cb09 2020-09-27 op }
571 e573cb09 2020-09-27 op
572 e573cb09 2020-09-27 op int
573 e573cb09 2020-09-27 op group_match(struct group *g, Window w)
574 e573cb09 2020-09-27 op {
575 e573cb09 2020-09-27 op struct match *m;
576 e573cb09 2020-09-27 op
577 e573cb09 2020-09-27 op for (m = g->matches; m != NULL; m = m->next)
578 e573cb09 2020-09-27 op if (match_window(m, w))
579 e573cb09 2020-09-27 op return 1;
580 e573cb09 2020-09-27 op return 0;
581 e573cb09 2020-09-27 op }
582 e573cb09 2020-09-27 op
583 e573cb09 2020-09-27 op
584 e573cb09 2020-09-27 op /* debug/dump stuff */
585 e573cb09 2020-09-27 op
586 e573cb09 2020-09-27 op void
587 e573cb09 2020-09-27 op printkey(struct key k)
588 e573cb09 2020-09-27 op {
589 e573cb09 2020-09-27 op if (k.modifier & ControlMask)
590 e573cb09 2020-09-27 op printf("C-");
591 e573cb09 2020-09-27 op if (k.modifier & ShiftMask)
592 e573cb09 2020-09-27 op printf("S-");
593 e573cb09 2020-09-27 op if (k.modifier & Mod1Mask)
594 e573cb09 2020-09-27 op printf("M-");
595 e573cb09 2020-09-27 op if (k.modifier & Mod4Mask)
596 e573cb09 2020-09-27 op printf("s-");
597 e573cb09 2020-09-27 op
598 e573cb09 2020-09-27 op printf("%s", XKeysymToString(k.key));
599 e573cb09 2020-09-27 op }
600 e573cb09 2020-09-27 op
601 e573cb09 2020-09-27 op void
602 e573cb09 2020-09-27 op printaction(struct action a)
603 e573cb09 2020-09-27 op {
604 e0041ee5 2020-10-01 op switch (a.type) {
605 e0041ee5 2020-10-01 op case ASPECIAL:
606 e573cb09 2020-09-27 op switch (a.special) {
607 e573cb09 2020-09-27 op case ATOGGLE: printf("toggle"); break;
608 e573cb09 2020-09-27 op case AACTIVATE: printf("activate"); break;
609 e573cb09 2020-09-27 op case ADEACTIVATE: printf("deactivate"); break;
610 e573cb09 2020-09-27 op case AIGNORE: printf("ignore"); break;
611 e0041ee5 2020-10-01 op default: abort(); /* unreachable */
612 e573cb09 2020-09-27 op }
613 e0041ee5 2020-10-01 op break;
614 e0041ee5 2020-10-01 op
615 e0041ee5 2020-10-01 op case AFAKE:
616 e573cb09 2020-09-27 op printf("send key ");
617 e573cb09 2020-09-27 op printkey(a.send_key);
618 e0041ee5 2020-10-01 op break;
619 e0041ee5 2020-10-01 op
620 e0041ee5 2020-10-01 op case AEXEC:
621 e0041ee5 2020-10-01 op printf("exec %s", a.str);
622 e0041ee5 2020-10-01 op break;
623 e0041ee5 2020-10-01 op
624 e0041ee5 2020-10-01 op default:
625 e0041ee5 2020-10-01 op /* unreachable */
626 e0041ee5 2020-10-01 op abort();
627 e573cb09 2020-09-27 op }
628 e573cb09 2020-09-27 op }
629 e573cb09 2020-09-27 op
630 e573cb09 2020-09-27 op void
631 e573cb09 2020-09-27 op printmatch(struct match *m)
632 e573cb09 2020-09-27 op {
633 e573cb09 2020-09-27 op if (m == NULL) {
634 e573cb09 2020-09-27 op printf("(null)");
635 e573cb09 2020-09-27 op return;
636 e573cb09 2020-09-27 op }
637 e573cb09 2020-09-27 op printf("match ");
638 e573cb09 2020-09-27 op switch (m->prop) {
639 e0041ee5 2020-10-01 op case MANY:
640 e0041ee5 2020-10-01 op printf("all");
641 e0041ee5 2020-10-01 op break;
642 e573cb09 2020-09-27 op case MCLASS:
643 e0041ee5 2020-10-01 op printf("class %s", m->str);
644 e573cb09 2020-09-27 op break;
645 e573cb09 2020-09-27 op default:
646 e0041ee5 2020-10-01 op /* unreachable */
647 e573cb09 2020-09-27 op abort();
648 e573cb09 2020-09-27 op }
649 e573cb09 2020-09-27 op
650 e573cb09 2020-09-27 op if (m->next == NULL)
651 e573cb09 2020-09-27 op printf("\n");
652 e573cb09 2020-09-27 op else {
653 e573cb09 2020-09-27 op printf(" ; ");
654 e573cb09 2020-09-27 op printmatch(m->next);
655 e573cb09 2020-09-27 op }
656 e573cb09 2020-09-27 op }
657 e573cb09 2020-09-27 op
658 e573cb09 2020-09-27 op void
659 e573cb09 2020-09-27 op printrule(struct rule *r)
660 e573cb09 2020-09-27 op {
661 e573cb09 2020-09-27 op if (r == NULL) {
662 e573cb09 2020-09-27 op printf("(null)");
663 e573cb09 2020-09-27 op return;
664 e573cb09 2020-09-27 op }
665 e573cb09 2020-09-27 op printf("on ");
666 e573cb09 2020-09-27 op printkey(r->key);
667 e573cb09 2020-09-27 op printf(" do ");
668 e573cb09 2020-09-27 op printaction(r->action);
669 e573cb09 2020-09-27 op printf("\n");
670 e573cb09 2020-09-27 op
671 e573cb09 2020-09-27 op if (r->next != NULL)
672 e573cb09 2020-09-27 op printrule(r->next);
673 e573cb09 2020-09-27 op }
674 e573cb09 2020-09-27 op
675 e573cb09 2020-09-27 op void
676 e573cb09 2020-09-27 op printgroup(struct group *g)
677 e573cb09 2020-09-27 op {
678 e573cb09 2020-09-27 op if (g == NULL) {
679 e573cb09 2020-09-27 op printf("(null)");
680 e573cb09 2020-09-27 op return;
681 e573cb09 2020-09-27 op }
682 e573cb09 2020-09-27 op printmatch(g->matches);
683 e573cb09 2020-09-27 op printf("\n");
684 e573cb09 2020-09-27 op printrule(g->rules);
685 e573cb09 2020-09-27 op printf("\n\n");
686 e573cb09 2020-09-27 op
687 e573cb09 2020-09-27 op if (g->next != NULL)
688 e573cb09 2020-09-27 op printgroup(g->next);
689 e573cb09 2020-09-27 op }