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

View Raw

More Information

➡️ Next capture (2023-04-19)

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

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 /*

21 * NOTE:

22 * It is the responsibility of the caller to deal with memory

23 * management of the xevent's.

24 */

25

26 #include <sys/types.h>

27 #include <sys/queue.h>

28

29 #include <err.h>

30 #include <errno.h>

31 #include <limits.h>

32 #include <stdio.h>

33 #include <stdlib.h>

34 #include <string.h>

35 #include <unistd.h>

36

37 #include "calmwm.h"

38

39 static void xev_handle_maprequest(XEvent *);

40 static void xev_handle_unmapnotify(XEvent *);

41 static void xev_handle_destroynotify(XEvent *);

42 static void xev_handle_configurerequest(XEvent *);

43 static void xev_handle_propertynotify(XEvent *);

44 static void xev_handle_enternotify(XEvent *);

45 static void xev_handle_buttonpress(XEvent *);

46 static void xev_handle_buttonrelease(XEvent *);

47 static void xev_handle_keypress(XEvent *);

48 static void xev_handle_keyrelease(XEvent *);

49 static void xev_handle_clientmessage(XEvent *);

50 static void xev_handle_randr(XEvent *);

51 static void xev_handle_mappingnotify(XEvent *);

52 static void xev_handle_expose(XEvent *);

53

54 void (*xev_handlers[LASTEvent])(XEvent *) = {

55 [MapRequest] = xev_handle_maprequest,

56 [UnmapNotify] = xev_handle_unmapnotify,

57 [DestroyNotify] = xev_handle_destroynotify,

58 [ConfigureRequest] = xev_handle_configurerequest,

59 [PropertyNotify] = xev_handle_propertynotify,

60 [EnterNotify] = xev_handle_enternotify,

61 [ButtonPress] = xev_handle_buttonpress,

62 [ButtonRelease] = xev_handle_buttonrelease,

63 [KeyPress] = xev_handle_keypress,

64 [KeyRelease] = xev_handle_keyrelease,

65 [ClientMessage] = xev_handle_clientmessage,

66 [MappingNotify] = xev_handle_mappingnotify,

67 [Expose] = xev_handle_expose,

68 };

69

70 static KeySym modkeys[] = { XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R,

71 XK_Control_L, XK_Control_R, XK_ISO_Level3_Shift };

72

73 static void

74 xev_handle_maprequest(XEvent *ee)

75 {

76 XMapRequestEvent *e = &ee->xmaprequest;

77 struct screen_ctx *sc;

78 struct client_ctx *cc, *old_cc;

79

80 LOG_DEBUG3("parent: 0x%lx window: 0x%lx", e->parent, e->window);

81

82 if ((sc = screen_find(e->parent)) == NULL)

83 return;

84

85 if ((old_cc = client_current(sc)) != NULL)

86 client_ptr_save(old_cc);

87

88 if ((cc = client_find(e->window)) == NULL)

89 cc = client_init(e->window, NULL);

90

91 if ((cc != NULL) && (!(cc->flags & CLIENT_IGNORE)))

92 client_ptr_warp(cc);

93 }

94

95 static void

96 xev_handle_unmapnotify(XEvent *ee)

97 {

98 XUnmapEvent *e = &ee->xunmap;

99 struct client_ctx *cc;

100

101 LOG_DEBUG3("window: 0x%lx", e->window);

102

103 if ((cc = client_find(e->window)) != NULL) {

104 if (e->send_event) {

105 xu_set_wm_state(cc->win, WithdrawnState);

106 } else {

107 if (!(cc->flags & CLIENT_HIDDEN))

108 client_remove(cc);

109 }

110 }

111 }

112

113 static void

114 xev_handle_destroynotify(XEvent *ee)

115 {

116 XDestroyWindowEvent *e = &ee->xdestroywindow;

117 struct client_ctx *cc;

118

119 LOG_DEBUG3("window: 0x%lx", e->window);

120

121 if ((cc = client_find(e->window)) != NULL)

122 client_remove(cc);

123 }

124

125 static void

126 xev_handle_configurerequest(XEvent *ee)

127 {

128 XConfigureRequestEvent *e = &ee->xconfigurerequest;

129 struct client_ctx *cc;

130 struct screen_ctx *sc;

131 XWindowChanges wc;

132

133 LOG_DEBUG3("window: 0x%lx", e->window);

134

135 if ((cc = client_find(e->window)) != NULL) {

136 sc = cc->sc;

137

138 if (e->value_mask & CWWidth)

139 cc->geom.w = e->width;

140 if (e->value_mask & CWHeight)

141 cc->geom.h = e->height;

142 if (e->value_mask & CWX)

143 cc->geom.x = e->x;

144 if (e->value_mask & CWY)

145 cc->geom.y = e->y;

146 if (e->value_mask & CWBorderWidth)

147 cc->bwidth = e->border_width;

148 if (e->value_mask & CWSibling)

149 wc.sibling = e->above;

150 if (e->value_mask & CWStackMode)

151 wc.stack_mode = e->detail;

152

153 if (cc->geom.x == 0 && cc->geom.w >= sc->view.w)

154 cc->geom.x -= cc->bwidth;

155

156 if (cc->geom.y == 0 && cc->geom.h >= sc->view.h)

157 cc->geom.y -= cc->bwidth;

158

159 wc.x = cc->geom.x;

160 wc.y = cc->geom.y;

161 wc.width = cc->geom.w;

162 wc.height = cc->geom.h;

163 wc.border_width = cc->bwidth;

164

165 XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);

166 client_config(cc);

167 } else {

168 /* let it do what it wants, it'll be ours when we map it. */

169 wc.x = e->x;

170 wc.y = e->y;

171 wc.width = e->width;

172 wc.height = e->height;

173 wc.border_width = e->border_width;

174 wc.stack_mode = Above;

175 e->value_mask &= ~CWStackMode;

176

177 XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);

178 }

179 }

180

181 static void

182 xev_handle_propertynotify(XEvent *ee)

183 {

184 XPropertyEvent *e = &ee->xproperty;

185 struct screen_ctx *sc;

186 struct client_ctx *cc;

187

188 LOG_DEBUG3("window: 0x%lx", e->window);

189

190 if ((cc = client_find(e->window)) != NULL) {

191 switch (e->atom) {

192 case XA_WM_NORMAL_HINTS:

193 client_get_sizehints(cc);

194 break;

195 case XA_WM_NAME:

196 client_set_name(cc);

197 break;

198 case XA_WM_HINTS:

199 client_wm_hints(cc);

200 client_draw_border(cc);

201 break;

202 case XA_WM_TRANSIENT_FOR:

203 client_transient(cc);

204 client_draw_border(cc);

205 if (cc->gc)

206 group_movetogroup(cc, cc->gc->num);

207 break;

208 default:

209 if (e->atom == ewmh[_NET_WM_NAME])

210 client_set_name(cc);

211 break;

212 }

213 } else {

214 if (e->atom == ewmh[_NET_DESKTOP_NAMES]) {

215 if ((sc = screen_find(e->window)) != NULL)

216 xu_ewmh_net_desktop_names(sc);

217 }

218 }

219 }

220

221 static void

222 xev_handle_enternotify(XEvent *ee)

223 {

224 XCrossingEvent *e = &ee->xcrossing;

225 struct client_ctx *cc;

226

227 LOG_DEBUG3("window: 0x%lx", e->window);

228

229 Last_Event_Time = e->time;

230

231 if ((cc = client_find(e->window)) != NULL)

232 client_set_active(cc);

233 }

234

235 static void

236 xev_handle_buttonpress(XEvent *ee)

237 {

238 XButtonEvent *e = &ee->xbutton;

239 struct client_ctx *cc;

240 struct screen_ctx *sc;

241 struct bind_ctx *mb;

242

243 LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",

244 e->root, e->window, e->subwindow);

245

246 if ((sc = screen_find(e->root)) == NULL)

247 return;

248

249 e->state &= ~IGNOREMODMASK;

250

251 TAILQ_FOREACH(mb, &Conf.mousebindq, entry) {

252 if (e->button == mb->press.button && e->state == mb->modmask)

253 break;

254 }

255 if (mb == NULL)

256 return;

257 mb->cargs->xev = CWM_XEV_BTN;

258 switch (mb->context) {

259 case CWM_CONTEXT_CC:

260 if (((cc = client_find(e->window)) == NULL) &&

261 ((cc = client_current(sc)) == NULL))

262 return;

263 (*mb->callback)(cc, mb->cargs);

264 break;

265 case CWM_CONTEXT_SC:

266 (*mb->callback)(sc, mb->cargs);

267 break;

268 case CWM_CONTEXT_NONE:

269 (*mb->callback)(NULL, mb->cargs);

270 break;

271 }

272 }

273

274 static void

275 xev_handle_buttonrelease(XEvent *ee)

276 {

277 XButtonEvent *e = &ee->xbutton;

278 struct client_ctx *cc;

279

280 LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",

281 e->root, e->window, e->subwindow);

282

283 if ((cc = client_find(e->window)) != NULL) {

284 if (cc->flags & (CLIENT_ACTIVE | CLIENT_HIGHLIGHT)) {

285 cc->flags &= ~CLIENT_HIGHLIGHT;

286 client_draw_border(cc);

287 }

288 }

289 }

290

291 static void

292 xev_handle_keypress(XEvent *ee)

293 {

294 XKeyEvent *e = &ee->xkey;

295 struct client_ctx *cc;

296 struct screen_ctx *sc;

297 struct bind_ctx *kb;

298 KeySym keysym, skeysym;

299 unsigned int modshift;

300

301 LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",

302 e->root, e->window, e->subwindow);

303

304 if ((sc = screen_find(e->root)) == NULL)

305 return;

306

307 keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);

308 skeysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 1);

309

310 e->state &= ~IGNOREMODMASK;

311

312 TAILQ_FOREACH(kb, &Conf.keybindq, entry) {

313 if (keysym != kb->press.keysym && skeysym == kb->press.keysym)

314 modshift = ShiftMask;

315 else

316 modshift = 0;

317

318 if ((kb->modmask | modshift) != e->state)

319 continue;

320

321 if (kb->press.keysym == ((modshift == 0) ? keysym : skeysym))

322 break;

323 }

324 if (kb == NULL)

325 return;

326 kb->cargs->xev = CWM_XEV_KEY;

327 switch (kb->context) {

328 case CWM_CONTEXT_CC:

329 if (((cc = client_find(e->subwindow)) == NULL) &&

330 ((cc = client_current(sc)) == NULL))

331 return;

332 (*kb->callback)(cc, kb->cargs);

333 break;

334 case CWM_CONTEXT_SC:

335 (*kb->callback)(sc, kb->cargs);

336 break;

337 case CWM_CONTEXT_NONE:

338 (*kb->callback)(NULL, kb->cargs);

339 break;

340 }

341 }

342

343 /*

344 * This is only used for the modifier suppression detection.

345 */

346 static void

347 xev_handle_keyrelease(XEvent *ee)

348 {

349 XKeyEvent *e = &ee->xkey;

350 struct screen_ctx *sc;

351 struct client_ctx *cc;

352 KeySym keysym;

353 unsigned int i;

354

355 LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",

356 e->root, e->window, e->subwindow);

357

358 if ((sc = screen_find(e->root)) == NULL)

359 return;

360

361 keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);

362 for (i = 0; i < nitems(modkeys); i++) {

363 if (keysym == modkeys[i]) {

364 if ((cc = client_current(sc)) != NULL) {

365 if (sc->cycling) {

366 sc->cycling = 0;

367 client_mtf(cc);

368 }

369 if (cc->flags & CLIENT_HIGHLIGHT) {

370 cc->flags &= ~CLIENT_HIGHLIGHT;

371 client_draw_border(cc);

372 }

373 }

374 XUngrabKeyboard(X_Dpy, CurrentTime);

375 break;

376 }

377 }

378 }

379

380 static void

381 xev_handle_clientmessage(XEvent *ee)

382 {

383 XClientMessageEvent *e = &ee->xclient;

384 struct client_ctx *cc, *old_cc;

385 struct screen_ctx *sc;

386

387 LOG_DEBUG3("window: 0x%lx", e->window);

388

389 if (e->message_type == cwmh[WM_CHANGE_STATE]) {

390 if ((cc = client_find(e->window)) != NULL) {

391 if (e->data.l[0] == IconicState)

392 client_hide(cc);

393 }

394 } else if (e->message_type == ewmh[_NET_CLOSE_WINDOW]) {

395 if ((cc = client_find(e->window)) != NULL) {

396 client_close(cc);

397 }

398 } else if (e->message_type == ewmh[_NET_ACTIVE_WINDOW]) {

399 if ((cc = client_find(e->window)) != NULL) {

400 if ((old_cc = client_current(NULL)) != NULL)

401 client_ptr_save(old_cc);

402 client_show(cc);

403 client_ptr_warp(cc);

404 }

405 } else if (e->message_type == ewmh[_NET_WM_DESKTOP]) {

406 if ((cc = client_find(e->window)) != NULL) {

407 /*

408 * The EWMH spec states that if the cardinal returned

409 * is 0xFFFFFFFF (-1) then the window should appear

410 * on all desktops, in our case, group 0.

411 */

412 if (e->data.l[0] == (unsigned long)-1)

413 group_movetogroup(cc, 0);

414 else

415 if (e->data.l[0] >= 0 &&

416 e->data.l[0] < Conf.ngroups)

417 group_movetogroup(cc, e->data.l[0]);

418 }

419 } else if (e->message_type == ewmh[_NET_WM_STATE]) {

420 if ((cc = client_find(e->window)) != NULL) {

421 xu_ewmh_handle_net_wm_state_msg(cc,

422 e->data.l[0], e->data.l[1], e->data.l[2]);

423 }

424 } else if (e->message_type == ewmh[_NET_CURRENT_DESKTOP]) {

425 if ((sc = screen_find(e->window)) != NULL) {

426 if (e->data.l[0] >= 0 &&

427 e->data.l[0] < Conf.ngroups)

428 group_only(sc, e->data.l[0]);

429 }

430 }

431 }

432

433 static void

434 xev_handle_randr(XEvent *ee)

435 {

436 XRRScreenChangeNotifyEvent *e = (XRRScreenChangeNotifyEvent *)ee;

437 struct screen_ctx *sc;

438

439 LOG_DEBUG3("size: %d/%d", e->width, e->height);

440

441 if ((sc = screen_find(e->root)) == NULL)

442 return;

443

444 XRRUpdateConfiguration(ee);

445 screen_update_geometry(sc);

446 screen_assert_clients_within(sc);

447 }

448

449 /*

450 * Called when the keymap has changed.

451 * Ungrab all keys, reload keymap and then regrab

452 */

453 static void

454 xev_handle_mappingnotify(XEvent *ee)

455 {

456 XMappingEvent *e = &ee->xmapping;

457 struct screen_ctx *sc;

458

459 LOG_DEBUG3("window: 0x%lx", e->window);

460

461 XRefreshKeyboardMapping(e);

462 if (e->request == MappingKeyboard) {

463 TAILQ_FOREACH(sc, &Screenq, entry)

464 conf_grab_kbd(sc->rootwin);

465 }

466 }

467

468 static void

469 xev_handle_expose(XEvent *ee)

470 {

471 XExposeEvent *e = &ee->xexpose;

472 struct client_ctx *cc;

473

474 LOG_DEBUG3("window: 0x%lx", e->window);

475

476 if ((cc = client_find(e->window)) != NULL && e->count == 0)

477 client_draw_border(cc);

478 }

479

480 void

481 xev_process(void)

482 {

483 XEvent e;

484

485 while (XPending(X_Dpy)) {

486 XNextEvent(X_Dpy, &e);

487 if ((e.type - Conf.xrandr_event_base) == RRScreenChangeNotify)

488 xev_handle_randr(&e);

489 else if ((e.type < LASTEvent) && (xev_handlers[e.type] != NULL))

490 (*xev_handlers[e.type])(&e);

491 }

492 }

493