💾 Archived View for gemini.rmf-dev.com › repo › Vaati › cwm › files › 7610400b9dffa5c74eefefc778a88b… captured on 2023-03-20 at 18:15:26. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
0 /*
1 * calmwm - the calm window manager
2 *
3 * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * $OpenBSD$
18 */
19
20 #include <sys/types.h>
21 #include <sys/queue.h>
22
23 #include <err.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <pwd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include "calmwm.h"
33
34 static const char *conf_bind_mask(const char *, unsigned int *);
35 static void conf_unbind_key(struct conf *, struct bind_ctx *);
36 static void conf_unbind_mouse(struct conf *, struct bind_ctx *);
37
38 static const struct {
39 int num;
40 const char *name;
41 } group_binds[] = {
42 { 0, "nogroup" },
43 { 1, "one" },
44 { 2, "two" },
45 { 3, "three" },
46 { 4, "four" },
47 { 5, "five" },
48 { 6, "six" },
49 { 7, "seven" },
50 { 8, "eight" },
51 { 9, "nine" },
52 };
53 static int cursor_binds[] = {
54 XC_left_ptr, /* CF_NORMAL */
55 XC_fleur, /* CF_MOVE */
56 XC_bottom_right_corner, /* CF_RESIZE */
57 XC_question_arrow, /* CF_QUESTION */
58 };
59 static const char *color_binds[] = {
60 "#CCCCCC", /* CWM_COLOR_BORDER_ACTIVE */
61 "#666666", /* CWM_COLOR_BORDER_INACTIVE */
62 "#FC8814", /* CWM_COLOR_BORDER_URGENCY */
63 "blue", /* CWM_COLOR_BORDER_GROUP */
64 "red", /* CWM_COLOR_BORDER_UNGROUP */
65 "black", /* CWM_COLOR_MENU_FG */
66 "white", /* CWM_COLOR_MENU_BG */
67 "black", /* CWM_COLOR_MENU_FONT */
68 "", /* CWM_COLOR_MENU_FONT_SEL */
69 };
70 static const struct {
71 const char *tag;
72 void (*handler)(void *, struct cargs *);
73 enum context context;
74 int flag;
75 } name_to_func[] = {
76 #define FUNC_CC(t, h, n) \
77 #t, kbfunc_ ## h, CWM_CONTEXT_CC, n
78 #define FUNC_SC(t, h, n) \
79 #t, kbfunc_ ## h, CWM_CONTEXT_SC, n
80
81 { FUNC_CC(window-lower, client_lower, 0) },
82 { FUNC_CC(window-raise, client_raise, 0) },
83 { FUNC_CC(window-hide, client_hide, 0) },
84 { FUNC_CC(window-close, client_close, 0) },
85 { FUNC_CC(window-delete, client_close, 0) },
86 { FUNC_CC(window-htile, client_htile, 0) },
87 { FUNC_CC(window-vtile, client_vtile, 0) },
88 { FUNC_CC(window-stick, client_toggle_sticky, 0) },
89 { FUNC_CC(window-fullscreen, client_toggle_fullscreen, 0) },
90 { FUNC_CC(window-maximize, client_toggle_maximize, 0) },
91 { FUNC_CC(window-vmaximize, client_toggle_vmaximize, 0) },
92 { FUNC_CC(window-hmaximize, client_toggle_hmaximize, 0) },
93 { FUNC_CC(window-freeze, client_toggle_freeze, 0) },
94 { FUNC_CC(window-group, client_toggle_group, 0) },
95 { FUNC_CC(window-movetogroup-1, client_movetogroup, 1) },
96 { FUNC_CC(window-movetogroup-2, client_movetogroup, 2) },
97 { FUNC_CC(window-movetogroup-3, client_movetogroup, 3) },
98 { FUNC_CC(window-movetogroup-4, client_movetogroup, 4) },
99 { FUNC_CC(window-movetogroup-5, client_movetogroup, 5) },
100 { FUNC_CC(window-movetogroup-6, client_movetogroup, 6) },
101 { FUNC_CC(window-movetogroup-7, client_movetogroup, 7) },
102 { FUNC_CC(window-movetogroup-8, client_movetogroup, 8) },
103 { FUNC_CC(window-movetogroup-9, client_movetogroup, 9) },
104 { FUNC_CC(window-snap-up, client_snap, (CWM_UP)) },
105 { FUNC_CC(window-snap-down, client_snap, (CWM_DOWN)) },
106 { FUNC_CC(window-snap-right, client_snap, (CWM_RIGHT)) },
107 { FUNC_CC(window-snap-left, client_snap, (CWM_LEFT)) },
108 { FUNC_CC(window-snap-up-right, client_snap, (CWM_UP_RIGHT)) },
109 { FUNC_CC(window-snap-up-left, client_snap, (CWM_UP_LEFT)) },
110 { FUNC_CC(window-snap-down-right, client_snap, (CWM_DOWN_RIGHT)) },
111 { FUNC_CC(window-snap-down-left, client_snap, (CWM_DOWN_LEFT)) },
112 { FUNC_CC(window-move, client_move, 0) },
113 { FUNC_CC(window-move-up, client_move, (CWM_UP)) },
114 { FUNC_CC(window-move-down, client_move, (CWM_DOWN)) },
115 { FUNC_CC(window-move-right, client_move, (CWM_RIGHT)) },
116 { FUNC_CC(window-move-left, client_move, (CWM_LEFT)) },
117 { FUNC_CC(window-move-up-big, client_move, (CWM_UP_BIG)) },
118 { FUNC_CC(window-move-down-big, client_move, (CWM_DOWN_BIG)) },
119 { FUNC_CC(window-move-right-big, client_move, (CWM_RIGHT_BIG)) },
120 { FUNC_CC(window-move-left-big, client_move, (CWM_LEFT_BIG)) },
121 { FUNC_CC(window-resize, client_resize, 0) },
122 { FUNC_CC(window-resize-up, client_resize, (CWM_UP)) },
123 { FUNC_CC(window-resize-down, client_resize, (CWM_DOWN)) },
124 { FUNC_CC(window-resize-right, client_resize, (CWM_RIGHT)) },
125 { FUNC_CC(window-resize-left, client_resize, (CWM_LEFT)) },
126 { FUNC_CC(window-resize-up-big, client_resize, (CWM_UP_BIG)) },
127 { FUNC_CC(window-resize-down-big, client_resize, (CWM_DOWN_BIG)) },
128 { FUNC_CC(window-resize-right-big, client_resize, (CWM_RIGHT_BIG)) },
129 { FUNC_CC(window-resize-left-big, client_resize, (CWM_LEFT_BIG)) },
130 { FUNC_CC(window-menu-label, client_menu_label, 0) },
131
132 { FUNC_SC(window-cycle, client_cycle, (CWM_CYCLE_FORWARD)) },
133 { FUNC_SC(window-rcycle, client_cycle, (CWM_CYCLE_REVERSE)) },
134 { FUNC_SC(window-cycle-ingroup, client_cycle,
135 (CWM_CYCLE_FORWARD | CWM_CYCLE_INGROUP)) },
136 { FUNC_SC(window-rcycle-ingroup, client_cycle,
137 (CWM_CYCLE_REVERSE | CWM_CYCLE_INGROUP)) },
138
139 { FUNC_SC(group-cycle, group_cycle, (CWM_CYCLE_FORWARD)) },
140 { FUNC_SC(group-rcycle, group_cycle, (CWM_CYCLE_REVERSE)) },
141 { FUNC_SC(group-last, group_last, 0) },
142 { FUNC_SC(group-toggle-all, group_toggle_all, 0) },
143 { FUNC_SC(group-toggle-1, group_toggle, 1) },
144 { FUNC_SC(group-toggle-2, group_toggle, 2) },
145 { FUNC_SC(group-toggle-3, group_toggle, 3) },
146 { FUNC_SC(group-toggle-4, group_toggle, 4) },
147 { FUNC_SC(group-toggle-5, group_toggle, 5) },
148 { FUNC_SC(group-toggle-6, group_toggle, 6) },
149 { FUNC_SC(group-toggle-7, group_toggle, 7) },
150 { FUNC_SC(group-toggle-8, group_toggle, 8) },
151 { FUNC_SC(group-toggle-9, group_toggle, 9) },
152 { FUNC_SC(group-only-1, group_only, 1) },
153 { FUNC_SC(group-only-2, group_only, 2) },
154 { FUNC_SC(group-only-3, group_only, 3) },
155 { FUNC_SC(group-only-4, group_only, 4) },
156 { FUNC_SC(group-only-5, group_only, 5) },
157 { FUNC_SC(group-only-6, group_only, 6) },
158 { FUNC_SC(group-only-7, group_only, 7) },
159 { FUNC_SC(group-only-8, group_only, 8) },
160 { FUNC_SC(group-only-9, group_only, 9) },
161 { FUNC_SC(group-close-1, group_close, 1) },
162 { FUNC_SC(group-close-2, group_close, 2) },
163 { FUNC_SC(group-close-3, group_close, 3) },
164 { FUNC_SC(group-close-4, group_close, 4) },
165 { FUNC_SC(group-close-5, group_close, 5) },
166 { FUNC_SC(group-close-6, group_close, 6) },
167 { FUNC_SC(group-close-7, group_close, 7) },
168 { FUNC_SC(group-close-8, group_close, 8) },
169 { FUNC_SC(group-close-9, group_close, 9) },
170
171 { FUNC_SC(pointer-move-up, ptrmove, (CWM_UP)) },
172 { FUNC_SC(pointer-move-down, ptrmove, (CWM_DOWN)) },
173 { FUNC_SC(pointer-move-left, ptrmove, (CWM_LEFT)) },
174 { FUNC_SC(pointer-move-right, ptrmove, (CWM_RIGHT)) },
175 { FUNC_SC(pointer-move-up-big, ptrmove, (CWM_UP_BIG)) },
176 { FUNC_SC(pointer-move-down-big, ptrmove, (CWM_DOWN_BIG)) },
177 { FUNC_SC(pointer-move-left-big, ptrmove, (CWM_LEFT_BIG)) },
178 { FUNC_SC(pointer-move-right-big, ptrmove, (CWM_RIGHT_BIG)) },
179
180 { FUNC_SC(menu-cmd, menu_cmd, 0) },
181 { FUNC_SC(menu-group, menu_group, 0) },
182 { FUNC_SC(menu-ssh, menu_ssh, 0) },
183 { FUNC_SC(menu-window, menu_client, CWM_MENU_WINDOW_ALL) },
184 { FUNC_SC(menu-window-hidden, menu_client, CWM_MENU_WINDOW_HIDDEN) },
185 { FUNC_SC(menu-exec, menu_exec, 0) },
186 { FUNC_SC(menu-exec-wm, menu_wm, 0) },
187
188 { FUNC_SC(terminal, exec_term, 0) },
189 { FUNC_SC(lock, exec_lock, 0) },
190 { FUNC_SC(restart, cwm_status, CWM_EXEC_WM) },
191 { FUNC_SC(quit, cwm_status, CWM_QUIT) },
192 };
193 static unsigned int ignore_mods[] = {
194 0, LockMask, Mod2Mask, Mod2Mask | LockMask
195 };
196 static const struct {
197 const char ch;
198 int mask;
199 } bind_mods[] = {
200 { 'S', ShiftMask },
201 { 'C', ControlMask },
202 { 'M', Mod1Mask },
203 { '4', Mod4Mask },
204 { '5', Mod5Mask },
205 };
206 static const struct {
207 const char *key;
208 const char *func;
209 } key_binds[] = {
210 { "CM-Return", "terminal" },
211 { "CM-Delete", "lock" },
212 { "M-question", "menu-exec" },
213 { "CM-w", "menu-exec-wm" },
214 { "M-period", "menu-ssh" },
215 { "M-Return", "window-hide" },
216 { "M-Down", "window-lower" },
217 { "M-Up", "window-raise" },
218 { "M-slash", "menu-window" },
219 { "C-slash", "menu-cmd" },
220 { "M-Tab", "window-cycle" },
221 { "MS-Tab", "window-rcycle" },
222 { "CM-n", "window-menu-label" },
223 { "CM-x", "window-close" },
224 { "CM-a", "group-toggle-all" },
225 { "CM-0", "group-toggle-all" },
226 { "CM-1", "group-toggle-1" },
227 { "CM-2", "group-toggle-2" },
228 { "CM-3", "group-toggle-3" },
229 { "CM-4", "group-toggle-4" },
230 { "CM-5", "group-toggle-5" },
231 { "CM-6", "group-toggle-6" },
232 { "CM-7", "group-toggle-7" },
233 { "CM-8", "group-toggle-8" },
234 { "CM-9", "group-toggle-9" },
235 { "M-Right", "group-cycle" },
236 { "M-Left", "group-rcycle" },
237 { "CM-g", "window-group" },
238 { "CM-f", "window-fullscreen" },
239 { "CM-m", "window-maximize" },
240 { "CM-s", "window-stick" },
241 { "CM-equal", "window-vmaximize" },
242 { "CMS-equal", "window-hmaximize" },
243 { "CMS-f", "window-freeze" },
244 { "CMS-r", "restart" },
245 { "CMS-q", "quit" },
246 { "M-h", "window-move-left" },
247 { "M-j", "window-move-down" },
248 { "M-k", "window-move-up" },
249 { "M-l", "window-move-right" },
250 { "MS-h", "window-move-left-big" },
251 { "MS-j", "window-move-down-big" },
252 { "MS-k", "window-move-up-big" },
253 { "MS-l", "window-move-right-big" },
254 { "CM-h", "window-resize-left" },
255 { "CM-j", "window-resize-down" },
256 { "CM-k", "window-resize-up" },
257 { "CM-l", "window-resize-right" },
258 { "CMS-h", "window-resize-left-big" },
259 { "CMS-j", "window-resize-down-big" },
260 { "CMS-k", "window-resize-up-big" },
261 { "CMS-l", "window-resize-right-big" },
262 },
263 mouse_binds[] = {
264 { "1", "menu-window" },
265 { "2", "menu-group" },
266 { "3", "menu-cmd" },
267 { "M-1", "window-move" },
268 { "CM-1", "window-group" },
269 { "M-2", "window-resize" },
270 { "M-3", "window-lower" },
271 { "CMS-3", "window-hide" },
272 };
273
274 void
275 conf_init(struct conf *c)
276 {
277 const char *home;
278 struct passwd *pw;
279 unsigned int i;
280
281 c->stickygroups = 0;
282 c->bwidth = 1;
283 c->mamount = 1;
284 c->htile = 50;
285 c->vtile = 50;
286 c->snapdist = 0;
287 c->ngroups = 0;
288 c->nameqlen = 5;
289
290 TAILQ_INIT(&c->ignoreq);
291 TAILQ_INIT(&c->autogroupq);
292 TAILQ_INIT(&c->keybindq);
293 TAILQ_INIT(&c->mousebindq);
294 TAILQ_INIT(&c->cmdq);
295 TAILQ_INIT(&c->wmq);
296
297 for (i = 0; i < nitems(key_binds); i++)
298 conf_bind_key(c, key_binds[i].key, key_binds[i].func);
299
300 for (i = 0; i < nitems(mouse_binds); i++)
301 conf_bind_mouse(c, mouse_binds[i].key, mouse_binds[i].func);
302
303 for (i = 0; i < nitems(color_binds); i++)
304 c->color[i] = xstrdup(color_binds[i]);
305
306 conf_cmd_add(c, "lock", "xlock");
307 conf_cmd_add(c, "term", "xterm");
308 conf_wm_add(c, "cwm", "cwm");
309
310 c->font = xstrdup("sans-serif:pixelsize=14:bold");
311 c->wmname = xstrdup("CWM");
312
313 home = getenv("HOME");
314 if ((home == NULL) || (*home == '\0')) {
315 pw = getpwuid(getuid());
316 if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0')
317 home = pw->pw_dir;
318 else
319 home = "/";
320 }
321 xasprintf(&c->conf_file, "%s/%s", home, ".cwmrc");
322 xasprintf(&c->known_hosts, "%s/%s", home, ".ssh/known_hosts");
323 }
324
325 void
326 conf_clear(struct conf *c)
327 {
328 struct autogroup *ag;
329 struct bind_ctx *kb, *mb;
330 struct winname *wn;
331 struct cmd_ctx *cmd, *wm;
332 int i;
333
334 while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) {
335 TAILQ_REMOVE(&c->cmdq, cmd, entry);
336 free(cmd->name);
337 free(cmd->path);
338 free(cmd);
339 }
340 while ((wm = TAILQ_FIRST(&c->wmq)) != NULL) {
341 TAILQ_REMOVE(&c->wmq, wm, entry);
342 free(wm->name);
343 free(wm->path);
344 free(wm);
345 }
346 while ((kb = TAILQ_FIRST(&c->keybindq)) != NULL) {
347 TAILQ_REMOVE(&c->keybindq, kb, entry);
348 free(kb);
349 }
350 while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) {
351 TAILQ_REMOVE(&c->autogroupq, ag, entry);
352 free(ag->class);
353 free(ag->name);
354 free(ag);
355 }
356 while ((wn = TAILQ_FIRST(&c->ignoreq)) != NULL) {
357 TAILQ_REMOVE(&c->ignoreq, wn, entry);
358 free(wn->name);
359 free(wn);
360 }
361 while ((mb = TAILQ_FIRST(&c->mousebindq)) != NULL) {
362 TAILQ_REMOVE(&c->mousebindq, mb, entry);
363 free(mb);
364 }
365 for (i = 0; i < CWM_COLOR_NITEMS; i++)
366 free(c->color[i]);
367
368 free(c->conf_file);
369 free(c->known_hosts);
370 free(c->font);
371 free(c->wmname);
372 }
373
374 void
375 conf_cmd_add(struct conf *c, const char *name, const char *path)
376 {
377 struct cmd_ctx *cmd, *cmdtmp = NULL, *cmdnxt;
378
379 cmd = xmalloc(sizeof(*cmd));
380 cmd->name = xstrdup(name);
381 cmd->path = xstrdup(path);
382
383 TAILQ_FOREACH_SAFE(cmdtmp, &c->cmdq, entry, cmdnxt) {
384 if (strcmp(cmdtmp->name, name) == 0) {
385 TAILQ_REMOVE(&c->cmdq, cmdtmp, entry);
386 free(cmdtmp->name);
387 free(cmdtmp->path);
388 free(cmdtmp);
389 }
390 }
391 TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry);
392 }
393
394 void
395 conf_wm_add(struct conf *c, const char *name, const char *path)
396 {
397 struct cmd_ctx *wm, *wmtmp = NULL, *wmnxt;
398
399 wm = xmalloc(sizeof(*wm));
400 wm->name = xstrdup(name);
401 wm->path = xstrdup(path);
402
403 TAILQ_FOREACH_SAFE(wmtmp, &c->cmdq, entry, wmnxt) {
404 if (strcmp(wmtmp->name, name) == 0) {
405 TAILQ_REMOVE(&c->wmq, wmtmp, entry);
406 free(wmtmp->name);
407 free(wmtmp->path);
408 free(wmtmp);
409 }
410 }
411 TAILQ_INSERT_TAIL(&c->wmq, wm, entry);
412 }
413
414 void
415 conf_autogroup(struct conf *c, int num, const char *name, const char *class)
416 {
417 struct autogroup *ag;
418 char *p;
419
420 ag = xmalloc(sizeof(*ag));
421 if ((p = strchr(class, ',')) == NULL) {
422 if (name == NULL)
423 ag->name = NULL;
424 else
425 ag->name = xstrdup(name);
426
427 ag->class = xstrdup(class);
428 } else {
429 *(p++) = '\0';
430 if (name == NULL)
431 ag->name = xstrdup(class);
432 else
433 ag->name = xstrdup(name);
434
435 ag->class = xstrdup(p);
436 }
437 ag->num = num;
438 TAILQ_INSERT_TAIL(&c->autogroupq, ag, entry);
439 }
440
441 void
442 conf_ignore(struct conf *c, const char *name)
443 {
444 struct winname *wn;
445
446 wn = xmalloc(sizeof(*wn));
447 wn->name = xstrdup(name);
448 TAILQ_INSERT_TAIL(&c->ignoreq, wn, entry);
449 }
450
451 void
452 conf_cursor(struct conf *c)
453 {
454 unsigned int i;
455
456 for (i = 0; i < nitems(cursor_binds); i++)
457 c->cursor[i] = XCreateFontCursor(X_Dpy, cursor_binds[i]);
458 }
459
460 void
461 conf_client(struct client_ctx *cc)
462 {
463 struct winname *wn;
464
465 TAILQ_FOREACH(wn, &Conf.ignoreq, entry) {
466 if (strncasecmp(wn->name, cc->name, strlen(wn->name)) == 0) {
467 cc->flags |= CLIENT_IGNORE;
468 break;
469 }
470 }
471 }
472
473 void
474 conf_screen(struct screen_ctx *sc)
475 {
476 unsigned int i;
477 XftColor xc;
478
479 sc->gap = Conf.gap;
480 sc->snapdist = Conf.snapdist;
481
482 sc->xftfont = XftFontOpenXlfd(X_Dpy, sc->which, Conf.font);
483 if (sc->xftfont == NULL) {
484 sc->xftfont = XftFontOpenName(X_Dpy, sc->which, Conf.font);
485 if (sc->xftfont == NULL)
486 errx(1, "%s: XftFontOpenName: %s", __func__, Conf.font);
487 }
488
489 for (i = 0; i < nitems(color_binds); i++) {
490 if (i == CWM_COLOR_MENU_FONT_SEL && *Conf.color[i] == '\0') {
491 xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_BG],
492 sc->xftcolor[CWM_COLOR_MENU_FG], &xc);
493 xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_FONT], xc, &xc);
494 if (!XftColorAllocValue(X_Dpy, sc->visual, sc->colormap,
495 &xc.color, &sc->xftcolor[CWM_COLOR_MENU_FONT_SEL]))
496 warnx("XftColorAllocValue: %s", Conf.color[i]);
497 break;
498 }
499 if (!XftColorAllocName(X_Dpy, sc->visual, sc->colormap,
500 Conf.color[i], &sc->xftcolor[i])) {
501 warnx("XftColorAllocName: %s", Conf.color[i]);
502 XftColorAllocName(X_Dpy, sc->visual, sc->colormap,
503 color_binds[i], &sc->xftcolor[i]);
504 }
505 }
506
507 conf_grab_kbd(sc->rootwin);
508 }
509
510 void
511 conf_group(struct screen_ctx *sc)
512 {
513 unsigned int i;
514
515 for (i = 0; i < nitems(group_binds); i++) {
516 group_init(sc, group_binds[i].num, group_binds[i].name);
517 Conf.ngroups++;
518 }
519 }
520
521 static const char *
522 conf_bind_mask(const char *name, unsigned int *mask)
523 {
524 char *dash;
525 const char *ch;
526 unsigned int i;
527
528 *mask = 0;
529 if ((dash = strchr(name, '-')) == NULL)
530 return name;
531 for (i = 0; i < nitems(bind_mods); i++) {
532 if ((ch = strchr(name, bind_mods[i].ch)) != NULL && ch < dash)
533 *mask |= bind_mods[i].mask;
534 }
535 /* Skip past modifiers. */
536 return (dash + 1);
537 }
538
539 int
540 conf_bind_key(struct conf *c, const char *bind, const char *cmd)
541 {
542 struct bind_ctx *kb;
543 struct cargs *cargs;
544 const char *key;
545 unsigned int i;
546
547 if ((strcmp(bind, "all") == 0) && (cmd == NULL)) {
548 conf_unbind_key(c, NULL);
549 return 1;
550 }
551 kb = xmalloc(sizeof(*kb));
552 key = conf_bind_mask(bind, &kb->modmask);
553 kb->press.keysym = XStringToKeysym(key);
554 if (kb->press.keysym == NoSymbol) {
555 warnx("unknown symbol: %s", key);
556 free(kb);
557 return 0;
558 }
559 conf_unbind_key(c, kb);
560 if (cmd == NULL) {
561 free(kb);
562 return 1;
563 }
564 cargs = xcalloc(1, sizeof(*cargs));
565 for (i = 0; i < nitems(name_to_func); i++) {
566 if (strcmp(name_to_func[i].tag, cmd) != 0)
567 continue;
568 kb->callback = name_to_func[i].handler;
569 kb->context = name_to_func[i].context;
570 cargs->flag = name_to_func[i].flag;
571 goto out;
572 }
573 kb->callback = kbfunc_exec_cmd;
574 kb->context = CWM_CONTEXT_NONE;
575 cargs->flag = 0;
576 cargs->cmd = xstrdup(cmd);
577 out:
578 kb->cargs = cargs;
579 TAILQ_INSERT_TAIL(&c->keybindq, kb, entry);
580 return 1;
581 }
582
583 static void
584 conf_unbind_key(struct conf *c, struct bind_ctx *unbind)
585 {
586 struct bind_ctx *key = NULL, *keynxt;
587
588 TAILQ_FOREACH_SAFE(key, &c->keybindq, entry, keynxt) {
589 if ((unbind == NULL) ||
590 ((key->modmask == unbind->modmask) &&
591 (key->press.keysym == unbind->press.keysym))) {
592 TAILQ_REMOVE(&c->keybindq, key, entry);
593 free(key->cargs->cmd);
594 free(key->cargs);
595 free(key);
596 }
597 }
598 }
599
600 int
601 conf_bind_mouse(struct conf *c, const char *bind, const char *cmd)
602 {
603 struct bind_ctx *mb;
604 struct cargs *cargs;
605 const char *button, *errstr;
606 unsigned int i;
607
608 if ((strcmp(bind, "all") == 0) && (cmd == NULL)) {
609 conf_unbind_mouse(c, NULL);
610 return 1;
611 }
612 mb = xmalloc(sizeof(*mb));
613 button = conf_bind_mask(bind, &mb->modmask);
614 mb->press.button = strtonum(button, Button1, Button5, &errstr);
615 if (errstr) {
616 warnx("button number is %s: %s", errstr, button);
617 free(mb);
618 return 0;
619 }
620 conf_unbind_mouse(c, mb);
621 if (cmd == NULL) {
622 free(mb);
623 return 1;
624 }
625 cargs = xcalloc(1, sizeof(*cargs));
626 for (i = 0; i < nitems(name_to_func); i++) {
627 if (strcmp(name_to_func[i].tag, cmd) != 0)
628 continue;
629 mb->callback = name_to_func[i].handler;
630 mb->context = name_to_func[i].context;
631 cargs->flag = name_to_func[i].flag;
632 goto out;
633 }
634 mb->callback = kbfunc_exec_cmd;
635 mb->context = CWM_CONTEXT_NONE;
636 cargs->flag = 0;
637 cargs->cmd = xstrdup(cmd);
638 out:
639 mb->cargs = cargs;
640 TAILQ_INSERT_TAIL(&c->mousebindq, mb, entry);
641 return 1;
642 }
643
644 static void
645 conf_unbind_mouse(struct conf *c, struct bind_ctx *unbind)
646 {
647 struct bind_ctx *mb = NULL, *mbnxt;
648
649 TAILQ_FOREACH_SAFE(mb, &c->mousebindq, entry, mbnxt) {
650 if ((unbind == NULL) ||
651 ((mb->modmask == unbind->modmask) &&
652 (mb->press.button == unbind->press.button))) {
653 TAILQ_REMOVE(&c->mousebindq, mb, entry);
654 free(mb->cargs->cmd);
655 free(mb->cargs);
656 free(mb);
657 }
658 }
659 }
660
661 void
662 conf_grab_kbd(Window win)
663 {
664 struct bind_ctx *kb;
665 KeyCode kc;
666 unsigned int i;
667
668 XUngrabKey(X_Dpy, AnyKey, AnyModifier, win);
669
670 TAILQ_FOREACH(kb, &Conf.keybindq, entry) {
671 kc = XKeysymToKeycode(X_Dpy, kb->press.keysym);
672 if (kc == 0)
673 continue;
674 if ((XkbKeycodeToKeysym(X_Dpy, kc, 0, 0) != kb->press.keysym) &&
675 (XkbKeycodeToKeysym(X_Dpy, kc, 0, 1) == kb->press.keysym))
676 kb->modmask |= ShiftMask;
677
678 for (i = 0; i < nitems(ignore_mods); i++)
679 XGrabKey(X_Dpy, kc, (kb->modmask | ignore_mods[i]), win,
680 True, GrabModeAsync, GrabModeAsync);
681 }
682 }
683
684 void
685 conf_grab_mouse(Window win)
686 {
687 struct bind_ctx *mb;
688 unsigned int i;
689
690 XUngrabButton(X_Dpy, AnyButton, AnyModifier, win);
691
692 TAILQ_FOREACH(mb, &Conf.mousebindq, entry) {
693 if (mb->context != CWM_CONTEXT_CC)
694 continue;
695 for (i = 0; i < nitems(ignore_mods); i++) {
696 XGrabButton(X_Dpy, mb->press.button,
697 (mb->modmask | ignore_mods[i]), win, False,
698 BUTTONMASK, GrabModeAsync, GrabModeSync,
699 None, None);
700 }
701 }
702 }
703