]> Dogcows Code - chaz/openbox/blob - src/xeventhandler.cc
read protocols too in OBClient
[chaz/openbox] / src / xeventhandler.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2
3 #include "xeventhandler.hh"
4 #include "client.hh"
5 #include "openbox.hh"
6 #include "otk/display.hh"
7 #include "otk/rect.hh"
8
9 extern "C" {
10 #include <X11/Xlib.h>
11 #include <X11/Xutil.h>
12 }
13
14 namespace ob {
15
16
17 OBXEventHandler::OBXEventHandler()
18 {
19 _lasttime = 1; // 0 is CurrentTime, so set to minimum
20 }
21
22 void OBXEventHandler::buttonPress(const XButtonEvent &e)
23 {
24 _lasttime = e.time;
25
26 }
27
28
29 void OBXEventHandler::buttonRelease(const XButtonEvent &e)
30 {
31 _lasttime = e.time;
32
33 }
34
35
36 void OBXEventHandler::keyPress(const XKeyEvent &e)
37 {
38 _lasttime = e.time;
39 }
40
41
42 void OBXEventHandler::motion(const XMotionEvent &e)
43 {
44 _lasttime = e.time;
45
46 // the pointer is on the wrong screen
47 if (! e.same_screen) return;
48
49 }
50
51
52 void OBXEventHandler::enterNotify(const XCrossingEvent &e)
53 {
54 _lasttime = e.time;
55
56 OBClient *client = Openbox::instance->findClient(e.window);
57 if (!client) return;
58
59 /*
60 BScreen *screen = (BScreen *) 0;
61 BlackboxWindow *win = (BlackboxWindow *) 0;
62
63 if (e->xcrossing.mode == NotifyGrab) break;
64
65 if ((e->xcrossing.window == e->xcrossing.root) &&
66 (screen = searchScreen(e->xcrossing.window))) {
67 screen->getImageControl()->installRootColormap();
68 } else if ((win = searchWindow(e->xcrossing.window))) {
69 if (! no_focus)
70 win->enterNotifyEvent(&e->xcrossing);
71 }
72 */
73 }
74
75
76 void OBXEventHandler::leaveNotify(const XCrossingEvent &e)
77 {
78 _lasttime = e.time;
79
80 OBClient *client = Openbox::instance->findClient(e.window);
81 if (!client) return;
82
83 /*
84 BlackboxWindow *win = (BlackboxWindow *) 0;
85
86 if ((win = searchWindow(e->xcrossing.window)))
87 win->leaveNotifyEvent(&e->xcrossing);
88 */
89 }
90
91
92 void OBXEventHandler::configureRequest(const XConfigureRequestEvent &e)
93 {
94 OBClient *client = Openbox::instance->findClient(e.window);
95 if (!client) return;
96
97 /* BlackboxWindow *win = (BlackboxWindow *) 0;
98
99 if ((win = searchWindow(e->xconfigurerequest.window))) {
100 win->configureRequestEvent(&e->xconfigurerequest);
101 } else {
102 if (validateWindow(e->xconfigurerequest.window)) {
103 XWindowChanges xwc;
104
105 xwc.x = e->xconfigurerequest.x;
106 xwc.y = e->xconfigurerequest.y;
107 xwc.width = e->xconfigurerequest.width;
108 xwc.height = e->xconfigurerequest.height;
109 xwc.border_width = e->xconfigurerequest.border_width;
110 xwc.sibling = e->xconfigurerequest.above;
111 xwc.stack_mode = e->xconfigurerequest.detail;
112
113 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
114 e->xconfigurerequest.value_mask, &xwc);
115 }
116 }
117 */
118 }
119
120
121 // XXX: put this into the OBScreen class!
122 static void manageWindow(Window window)
123 {
124 XWMHints *wmhint;
125 XSetWindowAttributes attrib_set;
126
127 // XXX: manage the window, i.e. grab events n shit
128
129 // is the window a docking app
130 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
131 if ((wmhint->flags & StateHint) &&
132 wmhint->initial_state == WithdrawnState) {
133 //slit->addClient(w); // XXX: make dock apps work!
134 XFree(wmhint);
135 return;
136 }
137 XFree(wmhint);
138 }
139
140 // choose the events we want to receive on the CLIENT window
141 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
142 StructureNotifyMask;
143 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
144 ButtonMotionMask;
145 XChangeWindowAttributes(otk::OBDisplay::display, window,
146 CWEventMask|CWDontPropagate, &attrib_set);
147
148 // create the OBClient class, which gets all of the hints on the window
149 Openbox::instance->addClient(window, new OBClient(window));
150 }
151
152 void OBXEventHandler::mapRequest(const XMapRequestEvent &e)
153 {
154 #ifdef DEBUG
155 printf("MapRequest for 0x%lx\n", e.window);
156 #endif // DEBUG
157
158 OBClient *client = Openbox::instance->findClient(e.window);
159
160 if (client) {
161 // XXX: uniconify and/or unshade the window
162 } else {
163 manageWindow(e.window);
164 }
165
166 /*
167 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
168
169 if (win) {
170 bool focus = False;
171 if (win->isIconic()) {
172 win->deiconify();
173 focus = True;
174 }
175 if (win->isShaded()) {
176 win->shade();
177 focus = True;
178 }
179
180 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
181 win->isVisible())
182 win->setInputFocus();
183 } else {
184 BScreen *screen = searchScreen(e->xmaprequest.parent);
185
186 if (! screen) {
187 */
188 /*
189 we got a map request for a window who's parent isn't root. this
190 can happen in only one circumstance:
191
192 a client window unmapped a managed window, and then remapped it
193 somewhere between unmapping the client window and reparenting it
194 to root.
195
196 regardless of how it happens, we need to find the screen that
197 the window is on
198 */
199 /*
200 XWindowAttributes wattrib;
201 if (! XGetWindowAttributes(otk::OBDisplay::display,
202 e->xmaprequest.window,
203 &wattrib)) {
204 // failed to get the window attributes, perhaps the window has
205 // now been destroyed?
206 break;
207 }
208
209 screen = searchScreen(wattrib.root);
210 assert(screen != 0); // this should never happen
211 }
212 screen->manageWindow(e->xmaprequest.window);
213 }
214 */
215 }
216
217
218 void OBXEventHandler::unmapNotify(const XUnmapEvent &e)
219 {
220 OBClient *client = Openbox::instance->findClient(e.window);
221 if (!client) return;
222
223 // XXX: unmanage the window, i.e. ungrab events n reparent n shit
224 Openbox::instance->removeClient(e.window);
225 }
226
227
228 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent &e)
229 {
230 // XXX: window group leaders can come through here too!
231
232 OBClient *client = Openbox::instance->findClient(e.window);
233 if (!client) return;
234
235 // XXX: unmanage the window, i.e. ungrab events n reparent n shit
236 Openbox::instance->removeClient(e.window);
237 }
238
239
240 void OBXEventHandler::reparentNotify(const XReparentEvent &e)
241 {
242 /*
243 this event is quite rare and is usually handled in unmapNotify
244 however, if the window is unmapped when the reparent event occurs
245 the window manager never sees it because an unmap event is not sent
246 to an already unmapped window.
247 */
248 OBClient *client = Openbox::instance->findClient(e.window);
249 if (!client) return;
250
251 /*
252 BlackboxWindow *win = searchWindow(e->xreparent.window);
253 if (win)
254 win->reparentNotifyEvent(&e->xreparent);
255 */
256 }
257
258
259 void OBXEventHandler::propertyNotify(const XPropertyEvent &e)
260 {
261 _lasttime = e.time;
262
263 OBClient *client = Openbox::instance->findClient(e.window);
264 if (!client) return;
265
266 client->update(e);
267 }
268
269
270 void OBXEventHandler::expose(const XExposeEvent &first)
271 {
272 OBClient *client = Openbox::instance->findClient(first.window);
273 if (!client) return;
274
275 // compress expose events
276 XEvent e; e.xexpose = first;
277 unsigned int i = 0;
278 otk::Rect area(e.xexpose.x, e.xexpose.y, e.xexpose.width,
279 e.xexpose.height);
280 while (XCheckTypedWindowEvent(otk::OBDisplay::display,
281 e.xexpose.window, Expose, &e)) {
282 i++;
283 // merge expose area
284 area |= otk::Rect(e.xexpose.x, e.xexpose.y, e.xexpose.width,
285 e.xexpose.height);
286 }
287 if ( i > 0 ) {
288 // use the merged area
289 e.xexpose.x = area.x();
290 e.xexpose.y = area.y();
291 e.xexpose.width = area.width();
292 e.xexpose.height = area.height();
293 }
294
295 // XXX: make the decorations redraw!
296 }
297
298
299 void OBXEventHandler::colormapNotify(const XColormapEvent &e)
300 {
301 (void)e;
302 /*
303 BScreen *screen = searchScreen(e->xcolormap.window);
304 if (screen)
305 screen->setRootColormapInstalled((e->xcolormap.state ==
306 ColormapInstalled) ? True : False);
307 */
308 }
309
310
311 void OBXEventHandler::focusIn(const XFocusChangeEvent &e)
312 {
313 if (e.detail != NotifyNonlinear &&
314 e.detail != NotifyAncestor) {
315 /*
316 don't process FocusIns when:
317 1. the new focus window isn't an ancestor or inferior of the old
318 focus window (NotifyNonlinear)
319 make sure to allow the FocusIn when the old focus window was an
320 ancestor but didn't have a parent, such as root (NotifyAncestor)
321 */
322 return;
323 }
324 /*
325 BlackboxWindow *win = searchWindow(e.window);
326 if (win) {
327 if (! win->isFocused())
328 win->setFocusFlag(True);
329 */
330 /*
331 set the event window to None. when the FocusOut event handler calls
332 this function recursively, it uses this as an indication that focus
333 has moved to a known window.
334 */
335 /*
336 e->xfocus.window = None;
337
338 no_focus = False; // focusing is back on
339 }
340 */
341 }
342
343
344 void OBXEventHandler::focusOut(const XFocusChangeEvent &e)
345 {
346 if (e.detail != NotifyNonlinear) {
347 /*
348 don't process FocusOuts when:
349 2. the new focus window isn't an ancestor or inferior of the old
350 focus window (NotifyNonlinear)
351 */
352 return;
353 }
354
355 /*
356 BlackboxWindow *win = searchWindow(e->xfocus.window);
357 if (win && win->isFocused()) {
358 */
359 /*
360 before we mark "win" as unfocused, we need to verify that focus is
361 going to a known location, is in a known location, or set focus
362 to a known location.
363 */
364 /*
365 XEvent event;
366 // don't check the current focus if FocusOut was generated during a grab
367 bool check_focus = (e->xfocus.mode == NotifyNormal);
368 */
369 /*
370 First, check if there is a pending FocusIn event waiting. if there
371 is, process it and determine if focus has moved to another window
372 (the FocusIn event handler sets the window in the event
373 structure to None to indicate this).
374 */
375 /*
376 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
377
378 process_event(&event);
379 if (event.xfocus.window == None) {
380 // focus has moved
381 check_focus = False;
382 }
383 }
384
385 if (check_focus) {
386 */
387 /*
388 Second, we query the X server for the current input focus.
389 to make sure that we keep a consistent state.
390 */
391 /*
392 BlackboxWindow *focus;
393 Window w;
394 int revert;
395 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
396 focus = searchWindow(w);
397 if (focus) {
398 */
399 /*
400 focus got from "win" to "focus" under some very strange
401 circumstances, and we need to make sure that the focus indication
402 is correct.
403 */
404 /*
405 setFocusedWindow(focus);
406 } else {
407 // we have no idea where focus went... so we set it to somewhere
408 setFocusedWindow(0);
409 }
410 }
411 }
412 */
413 }
414
415
416 #ifdef SHAPE
417 void OBXEventHandler::shapeEvent(const XShapeEvent &e)
418 {
419 XShapeEvent *shape_event = (XShapeEvent *) e;
420 BlackboxWindow *win = searchWindow(e->xany.window);
421
422 if (win && shape_event->kind == ShapeBounding)
423 win->shapeEvent(shape_event);
424 }
425 #endif // SHAPE
426
427
428 void OBXEventHandler::clientMessage(const XClientMessageEvent &e)
429 {
430 if (e.format != 32)
431 return;
432 /*
433 } else if (e->xclient.message_type ==
434 xatom->getAtom(XAtom::blackbox_change_workspace) ||
435 e->xclient.message_type ==
436 xatom->getAtom(XAtom::net_current_desktop)) {
437 // NET_CURRENT_DESKTOP message
438 BScreen *screen = searchScreen(e->xclient.window);
439
440 unsigned int workspace = e->xclient.data.l[0];
441 if (screen && workspace < screen->getWorkspaceCount())
442 screen->changeWorkspaceID(workspace);
443 } else if (e->xclient.message_type ==
444 xatom->getAtom(XAtom::net_active_window)) {
445 // NET_ACTIVE_WINDOW
446 BlackboxWindow *win = searchWindow(e->xclient.window);
447
448 if (win) {
449 BScreen *screen = win->getScreen();
450
451 if (win->isIconic())
452 win->deiconify(False, False);
453 if (! win->isStuck() &&
454 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
455 no_focus = True;
456 screen->changeWorkspaceID(win->getWorkspaceNumber());
457 }
458 if (win->isVisible() && win->setInputFocus()) {
459 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
460 raiseWindow(win);
461 win->installColormap(True);
462 }
463 }
464 } else if (e->xclient.message_type ==
465 xatom->getAtom(XAtom::net_number_of_desktops)) {
466 // NET_NUMBER_OF_DESKTOPS
467 BScreen *screen = searchScreen(e->xclient.window);
468
469 if (e->xclient.data.l[0] > 0)
470 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
471 } else if (e->xclient.message_type ==
472 xatom->getAtom(XAtom::net_close_window)) {
473 // NET_CLOSE_WINDOW
474 BlackboxWindow *win = searchWindow(e->xclient.window);
475 if (win && win->validateClient())
476 win->close(); // could this be smarter?
477 } else if (e->xclient.message_type ==
478 xatom->getAtom(XAtom::net_wm_moveresize)) {
479 // NET_WM_MOVERESIZE
480 BlackboxWindow *win = searchWindow(e->xclient.window);
481 if (win && win->validateClient()) {
482 int x_root = e->xclient.data.l[0],
483 y_root = e->xclient.data.l[1];
484 if ((Atom) e->xclient.data.l[2] ==
485 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
486 win->beginMove(x_root, y_root);
487 } else {
488 if ((Atom) e->xclient.data.l[2] ==
489 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
490 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
491 else if ((Atom) e->xclient.data.l[2] ==
492 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
493 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
494 else if ((Atom) e->xclient.data.l[2] ==
495 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
496 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
497 else if ((Atom) e->xclient.data.l[2] ==
498 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
499 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
500 }
501 }
502 }
503 */
504 }
505
506
507 void OBXEventHandler::handle(const XEvent &e)
508 {
509 /* mouse button events can get translated into:
510 press - button was pressed down
511 release - buttons was released
512 click - button was pressed and released on the same window
513 double click - clicked twice on the same widget in a given time and area
514
515 key events are only bindable to presses. key releases are ignored.
516
517 mouse enter/leave can be bound to for the entire window
518 */
519
520 switch (e.type) {
521
522 // These types of XEvent's can be bound to actions by the user, and so end
523 // up getting passed off to the OBBindingMapper class at some point
524 case ButtonPress:
525 buttonPress(e.xbutton);
526 break;
527 case ButtonRelease:
528 buttonRelease(e.xbutton);
529 break;
530 case KeyPress:
531 keyPress(e.xkey);
532 break;
533 case MotionNotify:
534 motion(e.xmotion);
535 break;
536 case EnterNotify:
537 enterNotify(e.xcrossing);
538 break;
539 case LeaveNotify:
540 leaveNotify(e.xcrossing);
541 break;
542
543
544 // These types of XEvent's can not be bound to actions by the user and so
545 // will simply be handled in this class
546 case ConfigureRequest:
547 configureRequest(e.xconfigurerequest);
548 break;
549
550 case MapRequest:
551 mapRequest(e.xmaprequest);
552 break;
553
554 case UnmapNotify:
555 unmapNotify(e.xunmap);
556 break;
557
558 case DestroyNotify:
559 destroyNotify(e.xdestroywindow);
560 break;
561
562 case ReparentNotify:
563 reparentNotify(e.xreparent);
564 break;
565
566 case PropertyNotify:
567 propertyNotify(e.xproperty);
568 break;
569
570 case Expose:
571 expose(e.xexpose);
572 break;
573
574 case ColormapNotify:
575 colormapNotify(e.xcolormap);
576 break;
577
578 case FocusIn:
579 focusIn(e.xfocus);
580 break;
581
582 case FocusOut:
583 focusOut(e.xfocus);
584 break;
585
586 case ClientMessage:
587 clientMessage(e.xclient);
588
589 default:
590 #ifdef SHAPE
591 if (e.type == otk::OBDisplay::shapeEventBase())
592 shapeEvent(e);
593 #endif // SHAPE
594 break;
595
596 /*
597 case ClientMessage: {
598 break;
599 }
600
601 */
602 } // switch
603 }
604
605
606 }
This page took 0.064412 seconds and 5 git commands to generate.