💾 Archived View for gemini.rmf-dev.com › repo › Vaati › cwm › files › 230a2c57182ca854f660145213707f… captured on 2023-03-20 at 18:15:15. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

🚧 View Differences

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

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 <stdio.h>

27 #include <stdlib.h>

28 #include <string.h>

29 #include <unistd.h>

30

31 #include "calmwm.h"

32

33 void

34 xu_ptr_get(Window win, int *x, int *y)

35 {

36 Window w0, w1;

37 int tmp0, tmp1;

38 unsigned int tmp2;

39

40 XQueryPointer(X_Dpy, win, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);

41 }

42

43 void

44 xu_ptr_set(Window win, int x, int y)

45 {

46 XWarpPointer(X_Dpy, None, win, 0, 0, 0, 0, x, y);

47 }

48

49 int

50 xu_get_prop(Window win, Atom atm, Atom type, long len, unsigned char **p)

51 {

52 Atom realtype;

53 unsigned long n, extra;

54 int format;

55

56 if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,

57 &realtype, &format, &n, &extra, p) != Success || *p == NULL)

58 return -1;

59

60 if (n == 0)

61 XFree(*p);

62

63 return n;

64 }

65

66 int

67 xu_get_strprop(Window win, Atom atm, char **text) {

68 XTextProperty prop;

69 char **list;

70 int nitems = 0;

71

72 *text = NULL;

73

74 XGetTextProperty(X_Dpy, win, &prop, atm);

75 if (!prop.nitems) {

76 XFree(prop.value);

77 return 0;

78 }

79

80 if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,

81 &nitems) == Success && nitems > 0 && *list) {

82 if (nitems > 1) {

83 XTextProperty prop2;

84 if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,

85 XUTF8StringStyle, &prop2) == Success) {

86 *text = xstrdup((const char *)prop2.value);

87 XFree(prop2.value);

88 }

89 } else {

90 *text = xstrdup(*list);

91 }

92 XFreeStringList(list);

93 }

94 XFree(prop.value);

95

96 return nitems;

97 }

98

99 void

100 xu_send_clientmsg(Window win, Atom proto, Time ts)

101 {

102 XClientMessageEvent cm;

103

104 (void)memset(&cm, 0, sizeof(cm));

105 cm.type = ClientMessage;

106 cm.window = win;

107 cm.message_type = cwmh[WM_PROTOCOLS];

108 cm.format = 32;

109 cm.data.l[0] = proto;

110 cm.data.l[1] = ts;

111

112 XSendEvent(X_Dpy, win, False, NoEventMask, (XEvent *)&cm);

113 }

114

115 void

116 xu_get_wm_state(Window win, long *state)

117 {

118 long *p;

119

120 *state = -1;

121 if (xu_get_prop(win, cwmh[WM_STATE], cwmh[WM_STATE], 2L,

122 (unsigned char **)&p) > 0) {

123 *state = *p;

124 XFree(p);

125 }

126 }

127

128 void

129 xu_set_wm_state(Window win, long state)

130 {

131 long data[] = { state, None };

132

133 XChangeProperty(X_Dpy, win, cwmh[WM_STATE], cwmh[WM_STATE], 32,

134 PropModeReplace, (unsigned char *)data, 2);

135 }

136 void

137 xu_xorcolor(XftColor a, XftColor b, XftColor *r)

138 {

139 r->pixel = a.pixel ^ b.pixel;

140 r->color.red = a.color.red ^ b.color.red;

141 r->color.green = a.color.green ^ b.color.green;

142 r->color.blue = a.color.blue ^ b.color.blue;

143 r->color.alpha = 0xffff;

144 }

145

146 void

147 xu_atom_init(void)

148 {

149 char *cwmhints[] = {

150 "WM_STATE",

151 "WM_DELETE_WINDOW",

152 "WM_TAKE_FOCUS",

153 "WM_PROTOCOLS",

154 "_MOTIF_WM_HINTS",

155 "UTF8_STRING",

156 "WM_CHANGE_STATE",

157 };

158 char *ewmhints[] = {

159 "_NET_SUPPORTED",

160 "_NET_SUPPORTING_WM_CHECK",

161 "_NET_ACTIVE_WINDOW",

162 "_NET_CLIENT_LIST",

163 "_NET_CLIENT_LIST_STACKING",

164 "_NET_NUMBER_OF_DESKTOPS",

165 "_NET_CURRENT_DESKTOP",

166 "_NET_DESKTOP_VIEWPORT",

167 "_NET_DESKTOP_GEOMETRY",

168 "_NET_VIRTUAL_ROOTS",

169 "_NET_SHOWING_DESKTOP",

170 "_NET_DESKTOP_NAMES",

171 "_NET_WORKAREA",

172 "_NET_WM_NAME",

173 "_NET_WM_DESKTOP",

174 "_NET_CLOSE_WINDOW",

175 "_NET_WM_STATE",

176 "_NET_WM_STATE_STICKY",

177 "_NET_WM_STATE_MAXIMIZED_VERT",

178 "_NET_WM_STATE_MAXIMIZED_HORZ",

179 "_NET_WM_STATE_HIDDEN",

180 "_NET_WM_STATE_FULLSCREEN",

181 "_NET_WM_STATE_DEMANDS_ATTENTION",

182 "_NET_WM_STATE_SKIP_PAGER",

183 "_NET_WM_STATE_SKIP_TASKBAR",

184 "_CWM_WM_STATE_FREEZE",

185 };

186

187 XInternAtoms(X_Dpy, cwmhints, nitems(cwmhints), False, cwmh);

188 XInternAtoms(X_Dpy, ewmhints, nitems(ewmhints), False, ewmh);

189 }

190

191 /* Root Window Properties */

192 void

193 xu_ewmh_net_supported(struct screen_ctx *sc)

194 {

195 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTED],

196 XA_ATOM, 32, PropModeReplace, (unsigned char *)ewmh, EWMH_NITEMS);

197 }

198

199 void

200 xu_ewmh_net_supported_wm_check(struct screen_ctx *sc)

201 {

202 Window w;

203

204 w = XCreateSimpleWindow(X_Dpy, sc->rootwin, -1, -1, 1, 1, 0, 0, 0);

205 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTING_WM_CHECK],

206 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);

207 XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK],

208 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);

209 XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME],

210 cwmh[UTF8_STRING], 8, PropModeReplace,

211 (unsigned char *)Conf.wmname, strlen(Conf.wmname));

212 }

213

214 void

215 xu_ewmh_net_desktop_geometry(struct screen_ctx *sc)

216 {

217 long geom[2] = { sc->view.w, sc->view.h };

218

219 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_GEOMETRY],

220 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);

221 }

222

223 void

224 xu_ewmh_net_desktop_viewport(struct screen_ctx *sc)

225 {

226 long viewports[2] = {0, 0};

227

228 /* We don't support large desktops, so this is (0, 0). */

229 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_VIEWPORT],

230 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);

231 }

232

233 void

234 xu_ewmh_net_workarea(struct screen_ctx *sc)

235 {

236 unsigned long *workarea;

237 int i, ngroups = Conf.ngroups;

238

239 workarea = xreallocarray(NULL, ngroups * 4, sizeof(unsigned long));

240 for (i = 0; i < ngroups; i++) {

241 workarea[4 * i + 0] = sc->work.x;

242 workarea[4 * i + 1] = sc->work.y;

243 workarea[4 * i + 2] = sc->work.w;

244 workarea[4 * i + 3] = sc->work.h;

245 }

246 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_WORKAREA],

247 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)workarea,

248 ngroups * 4);

249 free(workarea);

250 }

251

252 void

253 xu_ewmh_net_client_list(struct screen_ctx *sc)

254 {

255 struct client_ctx *cc;

256 Window *winlist;

257 int i = 0, j = 0;

258

259 TAILQ_FOREACH(cc, &sc->clientq, entry)

260 i++;

261 if (i == 0)

262 return;

263

264 winlist = xreallocarray(NULL, i, sizeof(*winlist));

265 TAILQ_FOREACH(cc, &sc->clientq, entry)

266 winlist[j++] = cc->win;

267 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST],

268 XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);

269 free(winlist);

270 }

271

272 void

273 xu_ewmh_net_client_list_stacking(struct screen_ctx *sc)

274 {

275 struct client_ctx *cc;

276 Window *winlist;

277 int i = 0, j;

278

279 TAILQ_FOREACH(cc, &sc->clientq, entry)

280 i++;

281 if (i == 0)

282 return;

283

284 j = i;

285 winlist = xreallocarray(NULL, i, sizeof(*winlist));

286 TAILQ_FOREACH(cc, &sc->clientq, entry)

287 winlist[--j] = cc->win;

288 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST_STACKING],

289 XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);

290 free(winlist);

291 }

292

293 void

294 xu_ewmh_net_active_window(struct screen_ctx *sc, Window w)

295 {

296 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_ACTIVE_WINDOW],

297 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);

298 }

299

300 void

301 xu_ewmh_net_number_of_desktops(struct screen_ctx *sc)

302 {

303 long ndesks = Conf.ngroups;

304

305 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_NUMBER_OF_DESKTOPS],

306 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);

307 }

308

309 void

310 xu_ewmh_net_showing_desktop(struct screen_ctx *sc)

311 {

312 long zero = 0;

313

314 /* We don't support `showing desktop' mode, so this is zero.

315 * Note that when we hide all groups, or when all groups are

316 * hidden we could technically set this later on.

317 */

318 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SHOWING_DESKTOP],

319 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);

320 }

321

322 void

323 xu_ewmh_net_virtual_roots(struct screen_ctx *sc)

324 {

325 /* We don't support virtual roots, so delete if set by previous wm. */

326 XDeleteProperty(X_Dpy, sc->rootwin, ewmh[_NET_VIRTUAL_ROOTS]);

327 }

328

329 void

330 xu_ewmh_net_current_desktop(struct screen_ctx *sc)

331 {

332 long num = sc->group_active->num;

333

334 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CURRENT_DESKTOP],

335 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&num, 1);

336 }

337

338 void

339 xu_ewmh_net_desktop_names(struct screen_ctx *sc)

340 {

341 struct group_ctx *gc;

342 char *p, *q;

343 unsigned char *prop_ret;

344 int i = 0, j = 0, nstrings = 0, n = 0;

345 size_t len = 0, tlen, slen;

346

347 /* Let group names be overwritten if _NET_DESKTOP_NAMES is set. */

348

349 if ((j = xu_get_prop(sc->rootwin, ewmh[_NET_DESKTOP_NAMES],

350 cwmh[UTF8_STRING], 0xffffff, (unsigned char **)&prop_ret)) > 0) {

351 prop_ret[j - 1] = '\0'; /* paranoia */

352 while (i < j) {

353 if (prop_ret[i++] == '\0')

354 nstrings++;

355 }

356 }

357

358 p = (char *)prop_ret;

359 while (n < nstrings) {

360 TAILQ_FOREACH(gc, &sc->groupq, entry) {

361 if (gc->num == n) {

362 free(gc->name);

363 gc->name = xstrdup(p);

364 p += strlen(p) + 1;

365 break;

366 }

367 }

368 n++;

369 }

370 if (prop_ret != NULL)

371 XFree(prop_ret);

372

373 TAILQ_FOREACH(gc, &sc->groupq, entry)

374 len += strlen(gc->name) + 1;

375 q = p = xreallocarray(NULL, len, sizeof(*p));

376

377 tlen = len;

378 TAILQ_FOREACH(gc, &sc->groupq, entry) {

379 slen = strlen(gc->name) + 1;

380 (void)strlcpy(q, gc->name, tlen);

381 tlen -= slen;

382 q += slen;

383 }

384

385 XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES],

386 cwmh[UTF8_STRING], 8, PropModeReplace, (unsigned char *)p, len);

387 free(p);

388 }

389

390 /* Application Window Properties */

391 int

392 xu_ewmh_get_net_wm_desktop(struct client_ctx *cc, long *n)

393 {

394 long *p;

395

396 if (xu_get_prop(cc->win, ewmh[_NET_WM_DESKTOP], XA_CARDINAL, 1L,

397 (unsigned char **)&p) <= 0)

398 return 0;

399 *n = *p;

400 XFree(p);

401 return 1;

402 }

403

404 void

405 xu_ewmh_set_net_wm_desktop(struct client_ctx *cc)

406 {

407 long num = 0xffffffff;

408

409 if (cc->gc)

410 num = cc->gc->num;

411

412 XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_DESKTOP],

413 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&num, 1);

414 }

415

416 Atom *

417 xu_ewmh_get_net_wm_state(struct client_ctx *cc, int *n)

418 {

419 Atom *state, *p = NULL;

420

421 if ((*n = xu_get_prop(cc->win, ewmh[_NET_WM_STATE], XA_ATOM, 64L,

422 (unsigned char **)&p)) <= 0)

423 return NULL;

424

425 state = xreallocarray(NULL, *n, sizeof(Atom));

426 (void)memcpy(state, p, *n * sizeof(Atom));

427 XFree((char *)p);

428

429 return state;

430 }

431

432 void

433 xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,

434 Atom first, Atom second)

435 {

436 unsigned int i;

437 struct handlers {

438 Atom atom;

439 int flag;

440 void (*toggle)(struct client_ctx *);

441 } handlers[] = {

442 { _NET_WM_STATE_STICKY,

443 CLIENT_STICKY,

444 client_toggle_sticky },

445 { _NET_WM_STATE_MAXIMIZED_VERT,

446 CLIENT_VMAXIMIZED,

447 client_toggle_vmaximize },

448 { _NET_WM_STATE_MAXIMIZED_HORZ,

449 CLIENT_HMAXIMIZED,

450 client_toggle_hmaximize },

451 { _NET_WM_STATE_HIDDEN,

452 CLIENT_HIDDEN,

453 client_toggle_hidden },

454 { _NET_WM_STATE_FULLSCREEN,

455 CLIENT_FULLSCREEN,

456 client_toggle_fullscreen },

457 { _NET_WM_STATE_DEMANDS_ATTENTION,

458 CLIENT_URGENCY,

459 client_urgency },

460 { _NET_WM_STATE_SKIP_PAGER,

461 CLIENT_SKIP_PAGER,

462 client_toggle_skip_pager},

463 { _NET_WM_STATE_SKIP_TASKBAR,

464 CLIENT_SKIP_TASKBAR,

465 client_toggle_skip_taskbar},

466 { _CWM_WM_STATE_FREEZE,

467 CLIENT_FREEZE,

468 client_toggle_freeze },

469 };

470

471 for (i = 0; i < nitems(handlers); i++) {

472 if (first != ewmh[handlers[i].atom] &&

473 second != ewmh[handlers[i].atom])

474 continue;

475 switch (action) {

476 case _NET_WM_STATE_ADD:

477 if (!(cc->flags & handlers[i].flag))

478 handlers[i].toggle(cc);

479 break;

480 case _NET_WM_STATE_REMOVE:

481 if (cc->flags & handlers[i].flag)

482 handlers[i].toggle(cc);

483 break;

484 case _NET_WM_STATE_TOGGLE:

485 handlers[i].toggle(cc);

486 }

487 }

488 }

489

490 void

491 xu_ewmh_restore_net_wm_state(struct client_ctx *cc)

492 {

493 Atom *atoms;

494 int i, n;

495

496 atoms = xu_ewmh_get_net_wm_state(cc, &n);

497 for (i = 0; i < n; i++) {

498 if (atoms[i] == ewmh[_NET_WM_STATE_STICKY])

499 client_toggle_sticky(cc);

500 if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_VERT])

501 client_toggle_vmaximize(cc);

502 if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ])

503 client_toggle_hmaximize(cc);

504 if (atoms[i] == ewmh[_NET_WM_STATE_HIDDEN])

505 client_toggle_hidden(cc);

506 if (atoms[i] == ewmh[_NET_WM_STATE_FULLSCREEN])

507 client_toggle_fullscreen(cc);

508 if (atoms[i] == ewmh[_NET_WM_STATE_DEMANDS_ATTENTION])

509 client_urgency(cc);

510 if (atoms[i] == ewmh[_NET_WM_STATE_SKIP_PAGER])

511 client_toggle_skip_pager(cc);

512 if (atoms[i] == ewmh[_NET_WM_STATE_SKIP_TASKBAR])

513 client_toggle_skip_taskbar(cc);

514 if (atoms[i] == ewmh[_CWM_WM_STATE_FREEZE])

515 client_toggle_freeze(cc);

516 }

517 free(atoms);

518 }

519

520 void

521 xu_ewmh_set_net_wm_state(struct client_ctx *cc)

522 {

523 Atom *atoms, *oatoms;

524 int n, i, j;

525

526 oatoms = xu_ewmh_get_net_wm_state(cc, &n);

527 atoms = xreallocarray(NULL, (n + _NET_WM_STATES_NITEMS), sizeof(Atom));

528 for (i = j = 0; i < n; i++) {

529 if (oatoms[i] != ewmh[_NET_WM_STATE_STICKY] &&

530 oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_VERT] &&

531 oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] &&

532 oatoms[i] != ewmh[_NET_WM_STATE_HIDDEN] &&

533 oatoms[i] != ewmh[_NET_WM_STATE_FULLSCREEN] &&

534 oatoms[i] != ewmh[_NET_WM_STATE_DEMANDS_ATTENTION] &&

535 oatoms[i] != ewmh[_NET_WM_STATE_SKIP_PAGER] &&

536 oatoms[i] != ewmh[_NET_WM_STATE_SKIP_TASKBAR] &&

537 oatoms[i] != ewmh[_CWM_WM_STATE_FREEZE])

538 atoms[j++] = oatoms[i];

539 }

540 free(oatoms);

541 if (cc->flags & CLIENT_STICKY)

542 atoms[j++] = ewmh[_NET_WM_STATE_STICKY];

543 if (cc->flags & CLIENT_HIDDEN)

544 atoms[j++] = ewmh[_NET_WM_STATE_HIDDEN];

545 if (cc->flags & CLIENT_FULLSCREEN)

546 atoms[j++] = ewmh[_NET_WM_STATE_FULLSCREEN];

547 else {

548 if (cc->flags & CLIENT_VMAXIMIZED)

549 atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_VERT];

550 if (cc->flags & CLIENT_HMAXIMIZED)

551 atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ];

552 }

553 if (cc->flags & CLIENT_URGENCY)

554 atoms[j++] = ewmh[_NET_WM_STATE_DEMANDS_ATTENTION];

555 if (cc->flags & CLIENT_SKIP_PAGER)

556 atoms[j++] = ewmh[_NET_WM_STATE_SKIP_PAGER];

557 if (cc->flags & CLIENT_SKIP_TASKBAR)

558 atoms[j++] = ewmh[_NET_WM_STATE_SKIP_TASKBAR];

559 if (cc->flags & CLIENT_FREEZE)

560 atoms[j++] = ewmh[_CWM_WM_STATE_FREEZE];

561 if (j > 0)

562 XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE],

563 XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, j);

564 else

565 XDeleteProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE]);

566 free(atoms);

567 }

568