💾 Archived View for gemini.rmf-dev.com › repo › Vaati › cwm › files › 7610400b9dffa5c74eefefc778a88b… captured on 2023-01-29 at 04:31:28. Gemini links have been rewritten to link to archived content

View Raw

More Information

➡️ Next capture (2023-03-20)

-=-=-=-=-=-=-

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