1 // -*- mode: C++; indent-tabs-mode: nil; -*-
3 #include "xeventhandler.hh"
6 #include "otk/display.hh"
11 #include <X11/Xutil.h>
17 OBXEventHandler::OBXEventHandler()
19 _lasttime
= 1; // 0 is CurrentTime, so set to minimum
22 void OBXEventHandler::buttonPress(const XButtonEvent
&e
)
29 void OBXEventHandler::buttonRelease(const XButtonEvent
&e
)
36 void OBXEventHandler::keyPress(const XKeyEvent
&e
)
42 void OBXEventHandler::motion(const XMotionEvent
&e
)
46 // the pointer is on the wrong screen
47 if (! e
.same_screen
) return;
52 void OBXEventHandler::enterNotify(const XCrossingEvent
&e
)
56 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
60 BScreen *screen = (BScreen *) 0;
61 BlackboxWindow *win = (BlackboxWindow *) 0;
63 if (e->xcrossing.mode == NotifyGrab) break;
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))) {
70 win->enterNotifyEvent(&e->xcrossing);
76 void OBXEventHandler::leaveNotify(const XCrossingEvent
&e
)
80 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
84 BlackboxWindow *win = (BlackboxWindow *) 0;
86 if ((win = searchWindow(e->xcrossing.window)))
87 win->leaveNotifyEvent(&e->xcrossing);
92 void OBXEventHandler::configureRequest(const XConfigureRequestEvent
&e
)
94 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
97 /* BlackboxWindow *win = (BlackboxWindow *) 0;
99 if ((win = searchWindow(e->xconfigurerequest.window))) {
100 win->configureRequestEvent(&e->xconfigurerequest);
102 if (validateWindow(e->xconfigurerequest.window)) {
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;
113 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
114 e->xconfigurerequest.value_mask, &xwc);
121 // XXX: put this into the OBScreen class!
122 static void manageWindow(Window window
)
125 XSetWindowAttributes attrib_set
;
127 // XXX: manage the window, i.e. grab events n shit
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!
140 // choose the events we want to receive on the CLIENT window
141 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
143 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
145 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
146 CWEventMask
|CWDontPropagate
, &attrib_set
);
148 // create the OBClient class, which gets all of the hints on the window
149 Openbox::instance
->addClient(window
, new OBClient(window
));
152 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
155 printf("MapRequest for 0x%lx\n", e
.window
);
158 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
161 // XXX: uniconify and/or unshade the window
163 manageWindow(e
.window
);
167 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
171 if (win->isIconic()) {
175 if (win->isShaded()) {
180 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
182 win->setInputFocus();
184 BScreen *screen = searchScreen(e->xmaprequest.parent);
189 we got a map request for a window who's parent isn't root. this
190 can happen in only one circumstance:
192 a client window unmapped a managed window, and then remapped it
193 somewhere between unmapping the client window and reparenting it
196 regardless of how it happens, we need to find the screen that
200 XWindowAttributes wattrib;
201 if (! XGetWindowAttributes(otk::OBDisplay::display,
202 e->xmaprequest.window,
204 // failed to get the window attributes, perhaps the window has
205 // now been destroyed?
209 screen = searchScreen(wattrib.root);
210 assert(screen != 0); // this should never happen
212 screen->manageWindow(e->xmaprequest.window);
218 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
220 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
223 // XXX: unmanage the window, i.e. ungrab events n reparent n shit
224 Openbox::instance
->removeClient(e
.window
);
228 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
230 // XXX: window group leaders can come through here too!
232 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
235 // XXX: unmanage the window, i.e. ungrab events n reparent n shit
236 Openbox::instance
->removeClient(e
.window
);
240 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
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.
248 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
252 BlackboxWindow *win = searchWindow(e->xreparent.window);
254 win->reparentNotifyEvent(&e->xreparent);
259 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
263 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
270 void OBXEventHandler::expose(const XExposeEvent
&first
)
272 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
275 // compress expose events
276 XEvent e
; e
.xexpose
= first
;
278 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
280 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
281 e
.xexpose
.window
, Expose
, &e
)) {
284 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
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();
295 // XXX: make the decorations redraw!
299 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
303 BScreen *screen = searchScreen(e->xcolormap.window);
305 screen->setRootColormapInstalled((e->xcolormap.state ==
306 ColormapInstalled) ? True : False);
311 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
313 if (e
.detail
!= NotifyNonlinear
&&
314 e
.detail
!= NotifyAncestor
) {
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)
325 BlackboxWindow *win = searchWindow(e.window);
327 if (! win->isFocused())
328 win->setFocusFlag(True);
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.
336 e->xfocus.window = None;
338 no_focus = False; // focusing is back on
344 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
346 if (e
.detail
!= NotifyNonlinear
) {
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)
356 BlackboxWindow *win = searchWindow(e->xfocus.window);
357 if (win && win->isFocused()) {
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
366 // don't check the current focus if FocusOut was generated during a grab
367 bool check_focus = (e->xfocus.mode == NotifyNormal);
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).
376 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
378 process_event(&event);
379 if (event.xfocus.window == None) {
388 Second, we query the X server for the current input focus.
389 to make sure that we keep a consistent state.
392 BlackboxWindow *focus;
395 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
396 focus = searchWindow(w);
400 focus got from "win" to "focus" under some very strange
401 circumstances, and we need to make sure that the focus indication
405 setFocusedWindow(focus);
407 // we have no idea where focus went... so we set it to somewhere
417 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
419 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
420 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
422 if (win
&& shape_event
->kind
== ShapeBounding
)
423 win
->shapeEvent(shape_event
);
428 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
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);
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)) {
446 BlackboxWindow *win = searchWindow(e->xclient.window);
449 BScreen *screen = win->getScreen();
452 win->deiconify(False, False);
453 if (! win->isStuck() &&
454 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
456 screen->changeWorkspaceID(win->getWorkspaceNumber());
458 if (win->isVisible() && win->setInputFocus()) {
459 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
461 win->installColormap(True);
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);
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)) {
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)) {
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);
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);
507 void OBXEventHandler::handle(const XEvent
&e
)
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
515 key events are only bindable to presses. key releases are ignored.
517 mouse enter/leave can be bound to for the entire window
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
525 buttonPress(e
.xbutton
);
528 buttonRelease(e
.xbutton
);
537 enterNotify(e
.xcrossing
);
540 leaveNotify(e
.xcrossing
);
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
);
551 mapRequest(e
.xmaprequest
);
555 unmapNotify(e
.xunmap
);
559 destroyNotify(e
.xdestroywindow
);
563 reparentNotify(e
.xreparent
);
567 propertyNotify(e
.xproperty
);
575 colormapNotify(e
.xcolormap
);
587 clientMessage(e
.xclient
);
591 if (e
.type
== otk::OBDisplay::shapeEventBase())
597 case ClientMessage: {