kbfunc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /*
  2. * calmwm - the calm window manager
  3. *
  4. * Copyright (c) 2004 Martin Murray <mmurray@monkey.org>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. *
  18. * $OpenBSD: kbfunc.c,v 1.113 2015/07/12 14:31:47 okan Exp $
  19. */
  20. #include <sys/types.h>
  21. #include <sys/queue.h>
  22. #include <dirent.h>
  23. #include <err.h>
  24. #include <errno.h>
  25. #include <limits.h>
  26. #include <paths.h>
  27. #include <signal.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32. #include "calmwm.h"
  33. #define HASH_MARKER "|1|"
  34. extern sig_atomic_t cwm_status;
  35. void
  36. kbfunc_client_lower(struct client_ctx *cc, union arg *arg)
  37. {
  38. client_ptrsave(cc);
  39. client_lower(cc);
  40. }
  41. void
  42. kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
  43. {
  44. client_raise(cc);
  45. }
  46. #define TYPEMASK (CWM_MOVE | CWM_RESIZE | CWM_PTRMOVE)
  47. #define MOVEMASK (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
  48. void
  49. kbfunc_client_moveresize(struct client_ctx *cc, union arg *arg)
  50. {
  51. struct screen_ctx *sc = cc->sc;
  52. struct geom area;
  53. int x, y, flags, amt;
  54. unsigned int mx, my;
  55. if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY))
  56. return;
  57. mx = my = 0;
  58. flags = arg->i;
  59. amt = Conf.mamount;
  60. if (flags & CWM_BIGMOVE) {
  61. flags -= CWM_BIGMOVE;
  62. amt = amt * 10;
  63. }
  64. switch (flags & MOVEMASK) {
  65. case CWM_UP:
  66. my -= amt;
  67. break;
  68. case CWM_DOWN:
  69. my += amt;
  70. break;
  71. case CWM_RIGHT:
  72. mx += amt;
  73. break;
  74. case CWM_LEFT:
  75. mx -= amt;
  76. break;
  77. }
  78. switch (flags & TYPEMASK) {
  79. case CWM_MOVE:
  80. cc->geom.x += mx;
  81. if (cc->geom.x + cc->geom.w < 0)
  82. cc->geom.x = -cc->geom.w;
  83. if (cc->geom.x > sc->view.w - 1)
  84. cc->geom.x = sc->view.w - 1;
  85. cc->geom.y += my;
  86. if (cc->geom.y + cc->geom.h < 0)
  87. cc->geom.y = -cc->geom.h;
  88. if (cc->geom.y > sc->view.h - 1)
  89. cc->geom.y = sc->view.h - 1;
  90. area = screen_area(sc,
  91. cc->geom.x + cc->geom.w / 2,
  92. cc->geom.y + cc->geom.h / 2, CWM_GAP);
  93. cc->geom.x += client_snapcalc(cc->geom.x,
  94. cc->geom.x + cc->geom.w + (cc->bwidth * 2),
  95. area.x, area.x + area.w, sc->snapdist);
  96. cc->geom.y += client_snapcalc(cc->geom.y,
  97. cc->geom.y + cc->geom.h + (cc->bwidth * 2),
  98. area.y, area.y + area.h, sc->snapdist);
  99. client_move(cc);
  100. xu_ptr_getpos(cc->win, &x, &y);
  101. cc->ptr.x = x + mx;
  102. cc->ptr.y = y + my;
  103. client_ptrwarp(cc);
  104. break;
  105. case CWM_RESIZE:
  106. if ((cc->geom.w += mx) < 1)
  107. cc->geom.w = 1;
  108. if ((cc->geom.h += my) < 1)
  109. cc->geom.h = 1;
  110. client_resize(cc, 1);
  111. /* Make sure the pointer stays within the window. */
  112. xu_ptr_getpos(cc->win, &cc->ptr.x, &cc->ptr.y);
  113. if (cc->ptr.x > cc->geom.w)
  114. cc->ptr.x = cc->geom.w - cc->bwidth;
  115. if (cc->ptr.y > cc->geom.h)
  116. cc->ptr.y = cc->geom.h - cc->bwidth;
  117. client_ptrwarp(cc);
  118. break;
  119. case CWM_PTRMOVE:
  120. xu_ptr_getpos(sc->rootwin, &x, &y);
  121. xu_ptr_setpos(sc->rootwin, x + mx, y + my);
  122. break;
  123. default:
  124. warnx("invalid flags passed to kbfunc_client_moveresize");
  125. }
  126. }
  127. void
  128. kbfunc_client_search(struct client_ctx *cc, union arg *arg)
  129. {
  130. struct screen_ctx *sc = cc->sc;
  131. struct client_ctx *old_cc;
  132. struct menu *mi;
  133. struct menu_q menuq;
  134. old_cc = client_current();
  135. TAILQ_INIT(&menuq);
  136. TAILQ_FOREACH(cc, &sc->clientq, entry)
  137. menuq_add(&menuq, cc, NULL);
  138. if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
  139. search_match_client, search_print_client)) != NULL) {
  140. cc = (struct client_ctx *)mi->ctx;
  141. if (cc->flags & CLIENT_HIDDEN)
  142. client_unhide(cc);
  143. if (old_cc)
  144. client_ptrsave(old_cc);
  145. client_ptrwarp(cc);
  146. }
  147. menuq_clear(&menuq);
  148. }
  149. void
  150. kbfunc_menu_cmd(struct client_ctx *cc, union arg *arg)
  151. {
  152. struct screen_ctx *sc = cc->sc;
  153. struct cmd *cmd;
  154. struct menu *mi;
  155. struct menu_q menuq;
  156. TAILQ_INIT(&menuq);
  157. TAILQ_FOREACH(cmd, &Conf.cmdq, entry)
  158. menuq_add(&menuq, cmd, "%s", cmd->name);
  159. if ((mi = menu_filter(sc, &menuq, "application", NULL, 0,
  160. search_match_text, search_print_cmd)) != NULL)
  161. u_spawn(((struct cmd *)mi->ctx)->path);
  162. menuq_clear(&menuq);
  163. }
  164. void
  165. kbfunc_menu_group(struct client_ctx *cc, union arg *arg)
  166. {
  167. struct screen_ctx *sc = cc->sc;
  168. struct group_ctx *gc;
  169. struct menu *mi;
  170. struct menu_q menuq;
  171. TAILQ_INIT(&menuq);
  172. TAILQ_FOREACH(gc, &sc->groupq, entry) {
  173. if (group_holds_only_sticky(gc))
  174. continue;
  175. menuq_add(&menuq, gc, "%d %s", gc->num, gc->name);
  176. }
  177. if ((mi = menu_filter(sc, &menuq, "group", NULL, CWM_MENU_LIST,
  178. search_match_text, search_print_group)) != NULL) {
  179. gc = (struct group_ctx *)mi->ctx;
  180. (group_holds_only_hidden(gc)) ?
  181. group_show(gc) : group_hide(gc);
  182. }
  183. menuq_clear(&menuq);
  184. }
  185. void
  186. kbfunc_client_cycle(struct client_ctx *cc, union arg *arg)
  187. {
  188. struct screen_ctx *sc = cc->sc;
  189. /* XXX for X apps that ignore events */
  190. XGrabKeyboard(X_Dpy, sc->rootwin, True,
  191. GrabModeAsync, GrabModeAsync, CurrentTime);
  192. client_cycle(sc, arg->i);
  193. }
  194. void
  195. kbfunc_client_hide(struct client_ctx *cc, union arg *arg)
  196. {
  197. client_hide(cc);
  198. }
  199. void
  200. kbfunc_cmdexec(struct client_ctx *cc, union arg *arg)
  201. {
  202. u_spawn(arg->c);
  203. }
  204. void
  205. kbfunc_term(struct client_ctx *cc, union arg *arg)
  206. {
  207. struct cmd *cmd;
  208. TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
  209. if (strcmp(cmd->name, "term") == 0)
  210. u_spawn(cmd->path);
  211. }
  212. }
  213. void
  214. kbfunc_lock(struct client_ctx *cc, union arg *arg)
  215. {
  216. struct cmd *cmd;
  217. TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
  218. if (strcmp(cmd->name, "lock") == 0)
  219. u_spawn(cmd->path);
  220. }
  221. }
  222. void
  223. kbfunc_exec(struct client_ctx *cc, union arg *arg)
  224. {
  225. #define NPATHS 256
  226. struct screen_ctx *sc = cc->sc;
  227. char **ap, *paths[NPATHS], *path, *pathcpy;
  228. char tpath[PATH_MAX];
  229. const char *label;
  230. DIR *dirp;
  231. struct dirent *dp;
  232. struct menu *mi;
  233. struct menu_q menuq;
  234. int l, i, cmd = arg->i;
  235. switch (cmd) {
  236. case CWM_EXEC_PROGRAM:
  237. label = "exec";
  238. break;
  239. case CWM_EXEC_WM:
  240. label = "wm";
  241. break;
  242. default:
  243. errx(1, "kbfunc_exec: invalid cmd %d", cmd);
  244. /*NOTREACHED*/
  245. }
  246. TAILQ_INIT(&menuq);
  247. if ((path = getenv("PATH")) == NULL)
  248. path = _PATH_DEFPATH;
  249. pathcpy = path = xstrdup(path);
  250. for (ap = paths; ap < &paths[NPATHS - 1] &&
  251. (*ap = strsep(&pathcpy, ":")) != NULL;) {
  252. if (**ap != '\0')
  253. ap++;
  254. }
  255. *ap = NULL;
  256. for (i = 0; i < NPATHS && paths[i] != NULL; i++) {
  257. if ((dirp = opendir(paths[i])) == NULL)
  258. continue;
  259. while ((dp = readdir(dirp)) != NULL) {
  260. /* skip everything but regular files and symlinks */
  261. if (dp->d_type != DT_REG && dp->d_type != DT_LNK)
  262. continue;
  263. (void)memset(tpath, '\0', sizeof(tpath));
  264. l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
  265. dp->d_name);
  266. if (l == -1 || l >= sizeof(tpath))
  267. continue;
  268. if (access(tpath, X_OK) == 0)
  269. menuq_add(&menuq, NULL, "%s", dp->d_name);
  270. }
  271. (void)closedir(dirp);
  272. }
  273. free(path);
  274. if ((mi = menu_filter(sc, &menuq, label, NULL,
  275. CWM_MENU_DUMMY | CWM_MENU_FILE,
  276. search_match_exec_path, NULL)) != NULL) {
  277. if (mi->text[0] == '\0')
  278. goto out;
  279. switch (cmd) {
  280. case CWM_EXEC_PROGRAM:
  281. u_spawn(mi->text);
  282. break;
  283. case CWM_EXEC_WM:
  284. u_exec(mi->text);
  285. warn("%s", mi->text);
  286. break;
  287. default:
  288. errx(1, "kb_func: egad, cmd changed value!");
  289. break;
  290. }
  291. }
  292. out:
  293. if (mi != NULL && mi->dummy)
  294. free(mi);
  295. menuq_clear(&menuq);
  296. }
  297. void
  298. kbfunc_ssh(struct client_ctx *cc, union arg *arg)
  299. {
  300. struct screen_ctx *sc = cc->sc;
  301. struct cmd *cmd;
  302. struct menu *mi;
  303. struct menu_q menuq;
  304. FILE *fp;
  305. char *buf, *lbuf, *p;
  306. char hostbuf[HOST_NAME_MAX+1];
  307. char path[PATH_MAX];
  308. int l;
  309. size_t len;
  310. TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
  311. if (strcmp(cmd->name, "term") == 0)
  312. break;
  313. }
  314. TAILQ_INIT(&menuq);
  315. if ((fp = fopen(Conf.known_hosts, "r")) == NULL) {
  316. warn("kbfunc_ssh: %s", Conf.known_hosts);
  317. goto menu;
  318. }
  319. lbuf = NULL;
  320. while ((buf = fgetln(fp, &len))) {
  321. if (buf[len - 1] == '\n')
  322. buf[len - 1] = '\0';
  323. else {
  324. /* EOF without EOL, copy and add the NUL */
  325. lbuf = xmalloc(len + 1);
  326. (void)memcpy(lbuf, buf, len);
  327. lbuf[len] = '\0';
  328. buf = lbuf;
  329. }
  330. /* skip hashed hosts */
  331. if (strncmp(buf, HASH_MARKER, strlen(HASH_MARKER)) == 0)
  332. continue;
  333. for (p = buf; *p != ',' && *p != ' ' && p != buf + len; p++) {
  334. /* do nothing */
  335. }
  336. /* ignore badness */
  337. if (p - buf + 1 > sizeof(hostbuf))
  338. continue;
  339. (void)strlcpy(hostbuf, buf, p - buf + 1);
  340. menuq_add(&menuq, NULL, hostbuf);
  341. }
  342. free(lbuf);
  343. (void)fclose(fp);
  344. menu:
  345. if ((mi = menu_filter(sc, &menuq, "ssh", NULL, CWM_MENU_DUMMY,
  346. search_match_exec, NULL)) != NULL) {
  347. if (mi->text[0] == '\0')
  348. goto out;
  349. l = snprintf(path, sizeof(path), "%s -T '[ssh] %s' -e ssh %s",
  350. cmd->path, mi->text, mi->text);
  351. if (l == -1 || l >= sizeof(path))
  352. goto out;
  353. u_spawn(path);
  354. }
  355. out:
  356. if (mi != NULL && mi->dummy)
  357. free(mi);
  358. menuq_clear(&menuq);
  359. }
  360. void
  361. kbfunc_client_label(struct client_ctx *cc, union arg *arg)
  362. {
  363. struct menu *mi;
  364. struct menu_q menuq;
  365. TAILQ_INIT(&menuq);
  366. /* dummy is set, so this will always return */
  367. mi = menu_filter(cc->sc, &menuq, "label", cc->label, CWM_MENU_DUMMY,
  368. search_match_text, NULL);
  369. if (!mi->abort) {
  370. free(cc->label);
  371. cc->label = xstrdup(mi->text);
  372. }
  373. free(mi);
  374. }
  375. void
  376. kbfunc_client_delete(struct client_ctx *cc, union arg *arg)
  377. {
  378. client_send_delete(cc);
  379. }
  380. void
  381. kbfunc_client_group(struct client_ctx *cc, union arg *arg)
  382. {
  383. group_hidetoggle(cc->sc, arg->i);
  384. }
  385. void
  386. kbfunc_client_grouponly(struct client_ctx *cc, union arg *arg)
  387. {
  388. group_only(cc->sc, arg->i);
  389. }
  390. void
  391. kbfunc_client_cyclegroup(struct client_ctx *cc, union arg *arg)
  392. {
  393. group_cycle(cc->sc, arg->i);
  394. }
  395. void
  396. kbfunc_client_nogroup(struct client_ctx *cc, union arg *arg)
  397. {
  398. group_alltoggle(cc->sc);
  399. }
  400. void
  401. kbfunc_client_grouptoggle(struct client_ctx *cc, union arg *arg)
  402. {
  403. if (arg->i == 0) {
  404. /* XXX for stupid X apps like xpdf and gvim */
  405. XGrabKeyboard(X_Dpy, cc->win, True,
  406. GrabModeAsync, GrabModeAsync, CurrentTime);
  407. }
  408. group_toggle_membership_enter(cc);
  409. }
  410. void
  411. kbfunc_client_movetogroup(struct client_ctx *cc, union arg *arg)
  412. {
  413. group_movetogroup(cc, arg->i);
  414. }
  415. void
  416. kbfunc_client_toggle_sticky(struct client_ctx *cc, union arg *arg)
  417. {
  418. client_toggle_sticky(cc);
  419. }
  420. void
  421. kbfunc_client_toggle_fullscreen(struct client_ctx *cc, union arg *arg)
  422. {
  423. client_toggle_fullscreen(cc);
  424. }
  425. void
  426. kbfunc_client_toggle_maximize(struct client_ctx *cc, union arg *arg)
  427. {
  428. client_toggle_maximize(cc);
  429. }
  430. void
  431. kbfunc_client_toggle_vmaximize(struct client_ctx *cc, union arg *arg)
  432. {
  433. client_toggle_vmaximize(cc);
  434. }
  435. void
  436. kbfunc_client_toggle_hmaximize(struct client_ctx *cc, union arg *arg)
  437. {
  438. client_toggle_hmaximize(cc);
  439. }
  440. void
  441. kbfunc_client_toggle_freeze(struct client_ctx *cc, union arg *arg)
  442. {
  443. client_toggle_freeze(cc);
  444. }
  445. void
  446. kbfunc_cwm_status(struct client_ctx *cc, union arg *arg)
  447. {
  448. cwm_status = arg->i;
  449. }
  450. void
  451. kbfunc_tile(struct client_ctx *cc, union arg *arg)
  452. {
  453. switch (arg->i) {
  454. case CWM_TILE_HORIZ:
  455. client_htile(cc);
  456. break;
  457. case CWM_TILE_VERT:
  458. client_vtile(cc);
  459. break;
  460. }
  461. }