1 // -*- mode: C++; indent-tabs-mode: nil; -*-
4 # include "../config.h"
7 #include "xeventhandler.hh"
12 #include "otk/display.hh"
13 #include "otk/rect.hh"
17 #include <X11/Xutil.h>
23 OBXEventHandler::OBXEventHandler()
25 _lasttime
= 1; // 0 is CurrentTime, so set to minimum
28 void OBXEventHandler::buttonPress(const XButtonEvent
&e
)
35 void OBXEventHandler::buttonRelease(const XButtonEvent
&e
)
42 void OBXEventHandler::keyPress(const XKeyEvent
&e
)
48 void OBXEventHandler::motion(const XMotionEvent
&e
)
52 // the pointer is on the wrong screen
53 if (! e
.same_screen
) return;
58 void OBXEventHandler::enterNotify(const XCrossingEvent
&e
)
62 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
66 BScreen *screen = (BScreen *) 0;
67 BlackboxWindow *win = (BlackboxWindow *) 0;
69 if (e->xcrossing.mode == NotifyGrab) break;
71 if ((e->xcrossing.window == e->xcrossing.root) &&
72 (screen = searchScreen(e->xcrossing.window))) {
73 screen->getImageControl()->installRootColormap();
74 } else if ((win = searchWindow(e->xcrossing.window))) {
76 win->enterNotifyEvent(&e->xcrossing);
82 void OBXEventHandler::leaveNotify(const XCrossingEvent
&e
)
86 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
90 BlackboxWindow *win = (BlackboxWindow *) 0;
92 if ((win = searchWindow(e->xcrossing.window)))
93 win->leaveNotifyEvent(&e->xcrossing);
98 void OBXEventHandler::configureRequest(const XConfigureRequestEvent
&e
)
100 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
103 /* BlackboxWindow *win = (BlackboxWindow *) 0;
105 if ((win = searchWindow(e->xconfigurerequest.window))) {
106 win->configureRequestEvent(&e->xconfigurerequest);
108 if (validateWindow(e->xconfigurerequest.window)) {
111 xwc.x = e->xconfigurerequest.x;
112 xwc.y = e->xconfigurerequest.y;
113 xwc.width = e->xconfigurerequest.width;
114 xwc.height = e->xconfigurerequest.height;
115 xwc.border_width = e->xconfigurerequest.border_width;
116 xwc.sibling = e->xconfigurerequest.above;
117 xwc.stack_mode = e->xconfigurerequest.detail;
119 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
120 e->xconfigurerequest.value_mask, &xwc);
127 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
130 printf("MapRequest for 0x%lx\n", e
.window
);
133 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
136 // XXX: uniconify and/or unshade the window
138 int screen
= INT_MAX
;
140 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
141 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == e
.parent
) {
146 if (screen
>= ScreenCount(otk::OBDisplay::display
)) {
148 we got a map request for a window who's parent isn't root. this
149 can happen in only one circumstance:
151 a client window unmapped a managed window, and then remapped it
152 somewhere between unmapping the client window and reparenting it
155 regardless of how it happens, we need to find the screen that
158 XWindowAttributes wattrib
;
159 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
.window
,
161 // failed to get the window attributes, perhaps the window has
162 // now been destroyed?
166 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
167 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == wattrib
.root
) {
173 assert(screen
< ScreenCount(otk::OBDisplay::display
));
175 Openbox::instance
->screen(screen
)->manageWindow(e
.window
);
179 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
183 if (win->isIconic()) {
187 if (win->isShaded()) {
192 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
194 win->setInputFocus();
196 BScreen *screen = searchScreen(e->xmaprequest.parent);
201 we got a map request for a window who's parent isn't root. this
202 can happen in only one circumstance:
204 a client window unmapped a managed window, and then remapped it
205 somewhere between unmapping the client window and reparenting it
208 regardless of how it happens, we need to find the screen that
212 XWindowAttributes wattrib;
213 if (! XGetWindowAttributes(otk::OBDisplay::display,
214 e->xmaprequest.window,
216 // failed to get the window attributes, perhaps the window has
217 // now been destroyed?
221 screen = searchScreen(wattrib.root);
222 assert(screen != 0); // this should never happen
224 screen->manageWindow(e->xmaprequest.window);
230 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
232 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
235 Openbox::instance
->screen(client
->screen())->unmanageWindow(client
);
239 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
241 // XXX: window group leaders can come through here too!
243 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
246 Openbox::instance
->screen(client
->screen())->unmanageWindow(client
);
250 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
253 this event is quite rare and is usually handled in unmapNotify
254 however, if the window is unmapped when the reparent event occurs
255 the window manager never sees it because an unmap event is not sent
256 to an already unmapped window.
258 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
262 BlackboxWindow *win = searchWindow(e->xreparent.window);
264 win->reparentNotifyEvent(&e->xreparent);
269 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
273 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
280 void OBXEventHandler::expose(const XExposeEvent
&first
)
282 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
285 // compress expose events
286 XEvent e
; e
.xexpose
= first
;
288 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
290 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
291 e
.xexpose
.window
, Expose
, &e
)) {
294 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
298 // use the merged area
299 e
.xexpose
.x
= area
.x();
300 e
.xexpose
.y
= area
.y();
301 e
.xexpose
.width
= area
.width();
302 e
.xexpose
.height
= area
.height();
305 // XXX: make the decorations redraw!
309 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
313 BScreen *screen = searchScreen(e->xcolormap.window);
315 screen->setRootColormapInstalled((e->xcolormap.state ==
316 ColormapInstalled) ? True : False);
321 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
323 if (e
.detail
!= NotifyNonlinear
&&
324 e
.detail
!= NotifyAncestor
) {
326 don't process FocusIns when:
327 1. the new focus window isn't an ancestor or inferior of the old
328 focus window (NotifyNonlinear)
329 make sure to allow the FocusIn when the old focus window was an
330 ancestor but didn't have a parent, such as root (NotifyAncestor)
335 BlackboxWindow *win = searchWindow(e.window);
337 if (! win->isFocused())
338 win->setFocusFlag(True);
341 set the event window to None. when the FocusOut event handler calls
342 this function recursively, it uses this as an indication that focus
343 has moved to a known window.
346 e->xfocus.window = None;
348 no_focus = False; // focusing is back on
354 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
356 if (e
.detail
!= NotifyNonlinear
) {
358 don't process FocusOuts when:
359 2. the new focus window isn't an ancestor or inferior of the old
360 focus window (NotifyNonlinear)
366 BlackboxWindow *win = searchWindow(e->xfocus.window);
367 if (win && win->isFocused()) {
370 before we mark "win" as unfocused, we need to verify that focus is
371 going to a known location, is in a known location, or set focus
376 // don't check the current focus if FocusOut was generated during a grab
377 bool check_focus = (e->xfocus.mode == NotifyNormal);
380 First, check if there is a pending FocusIn event waiting. if there
381 is, process it and determine if focus has moved to another window
382 (the FocusIn event handler sets the window in the event
383 structure to None to indicate this).
386 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
388 process_event(&event);
389 if (event.xfocus.window == None) {
398 Second, we query the X server for the current input focus.
399 to make sure that we keep a consistent state.
402 BlackboxWindow *focus;
405 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
406 focus = searchWindow(w);
410 focus got from "win" to "focus" under some very strange
411 circumstances, and we need to make sure that the focus indication
415 setFocusedWindow(focus);
417 // we have no idea where focus went... so we set it to somewhere
427 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
429 printf("ShapeEvent\n");
430 if (e
.kind
!= ShapeBounding
) return;
432 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
436 client
->frame
->update();
441 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
446 } else if (e->xclient.message_type ==
447 xatom->getAtom(XAtom::blackbox_change_workspace) ||
448 e->xclient.message_type ==
449 xatom->getAtom(XAtom::net_current_desktop)) {
450 // NET_CURRENT_DESKTOP message
451 BScreen *screen = searchScreen(e->xclient.window);
453 unsigned int workspace = e->xclient.data.l[0];
454 if (screen && workspace < screen->getWorkspaceCount())
455 screen->changeWorkspaceID(workspace);
456 } else if (e->xclient.message_type ==
457 xatom->getAtom(XAtom::net_active_window)) {
459 BlackboxWindow *win = searchWindow(e->xclient.window);
462 BScreen *screen = win->getScreen();
465 win->deiconify(False, False);
466 if (! win->isStuck() &&
467 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
469 screen->changeWorkspaceID(win->getWorkspaceNumber());
471 if (win->isVisible() && win->setInputFocus()) {
472 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
474 win->installColormap(True);
477 } else if (e->xclient.message_type ==
478 xatom->getAtom(XAtom::net_number_of_desktops)) {
479 // NET_NUMBER_OF_DESKTOPS
480 BScreen *screen = searchScreen(e->xclient.window);
482 if (e->xclient.data.l[0] > 0)
483 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
484 } else if (e->xclient.message_type ==
485 xatom->getAtom(XAtom::net_close_window)) {
487 BlackboxWindow *win = searchWindow(e->xclient.window);
488 if (win && win->validateClient())
489 win->close(); // could this be smarter?
490 } else if (e->xclient.message_type ==
491 xatom->getAtom(XAtom::net_wm_moveresize)) {
493 BlackboxWindow *win = searchWindow(e->xclient.window);
494 if (win && win->validateClient()) {
495 int x_root = e->xclient.data.l[0],
496 y_root = e->xclient.data.l[1];
497 if ((Atom) e->xclient.data.l[2] ==
498 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
499 win->beginMove(x_root, y_root);
501 if ((Atom) e->xclient.data.l[2] ==
502 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
503 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
504 else if ((Atom) e->xclient.data.l[2] ==
505 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
506 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
507 else if ((Atom) e->xclient.data.l[2] ==
508 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
509 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
510 else if ((Atom) e->xclient.data.l[2] ==
511 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
512 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
520 void OBXEventHandler::handle(const XEvent
&e
)
522 /* mouse button events can get translated into:
523 press - button was pressed down
524 release - buttons was released
525 click - button was pressed and released on the same window
526 double click - clicked twice on the same widget in a given time and area
528 key events are only bindable to presses. key releases are ignored.
530 mouse enter/leave can be bound to for the entire window
535 // These types of XEvent's can be bound to actions by the user, and so end
536 // up getting passed off to the OBBindingMapper class at some point
537 // IOW: THESE WILL HAVE GUILE HOOKS
539 buttonPress(e
.xbutton
);
542 buttonRelease(e
.xbutton
);
551 enterNotify(e
.xcrossing
);
554 leaveNotify(e
.xcrossing
);
558 // These types of XEvent's can not be bound to actions by the user and so
559 // will simply be handled in this class
560 case ConfigureRequest
:
561 configureRequest(e
.xconfigurerequest
);
565 mapRequest(e
.xmaprequest
);
569 unmapNotify(e
.xunmap
);
573 destroyNotify(e
.xdestroywindow
);
577 reparentNotify(e
.xreparent
);
581 propertyNotify(e
.xproperty
);
589 colormapNotify(e
.xcolormap
);
601 clientMessage(e
.xclient
);
605 if (e
.type
== otk::OBDisplay::shapeEventBase())
606 shapeEvent((*(XShapeEvent
*)&e
));
611 case ClientMessage: {