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 if (client
->ignore_unmaps
== 0)
236 Openbox::instance
->screen(client
->screen())->unmanageWindow(client
);
238 client
->ignore_unmaps
--;
242 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
244 // XXX: window group leaders can come through here too!
246 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
249 Openbox::instance
->screen(client
->screen())->unmanageWindow(client
);
253 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
256 this event is quite rare and is usually handled in unmapNotify
257 however, if the window is unmapped when the reparent event occurs
258 the window manager never sees it because an unmap event is not sent
259 to an already unmapped window.
261 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
265 BlackboxWindow *win = searchWindow(e->xreparent.window);
267 win->reparentNotifyEvent(&e->xreparent);
272 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
276 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
283 void OBXEventHandler::expose(const XExposeEvent
&first
)
285 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
288 // compress expose events
289 XEvent e
; e
.xexpose
= first
;
291 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
293 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
294 e
.xexpose
.window
, Expose
, &e
)) {
297 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
301 // use the merged area
302 e
.xexpose
.x
= area
.x();
303 e
.xexpose
.y
= area
.y();
304 e
.xexpose
.width
= area
.width();
305 e
.xexpose
.height
= area
.height();
308 // XXX: make the decorations redraw!
312 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
316 BScreen *screen = searchScreen(e->xcolormap.window);
318 screen->setRootColormapInstalled((e->xcolormap.state ==
319 ColormapInstalled) ? True : False);
324 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
326 if (e
.detail
!= NotifyNonlinear
&&
327 e
.detail
!= NotifyAncestor
) {
329 don't process FocusIns when:
330 1. the new focus window isn't an ancestor or inferior of the old
331 focus window (NotifyNonlinear)
332 make sure to allow the FocusIn when the old focus window was an
333 ancestor but didn't have a parent, such as root (NotifyAncestor)
338 BlackboxWindow *win = searchWindow(e.window);
340 if (! win->isFocused())
341 win->setFocusFlag(True);
344 set the event window to None. when the FocusOut event handler calls
345 this function recursively, it uses this as an indication that focus
346 has moved to a known window.
349 e->xfocus.window = None;
351 no_focus = False; // focusing is back on
357 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
359 if (e
.detail
!= NotifyNonlinear
) {
361 don't process FocusOuts when:
362 2. the new focus window isn't an ancestor or inferior of the old
363 focus window (NotifyNonlinear)
369 BlackboxWindow *win = searchWindow(e->xfocus.window);
370 if (win && win->isFocused()) {
373 before we mark "win" as unfocused, we need to verify that focus is
374 going to a known location, is in a known location, or set focus
379 // don't check the current focus if FocusOut was generated during a grab
380 bool check_focus = (e->xfocus.mode == NotifyNormal);
383 First, check if there is a pending FocusIn event waiting. if there
384 is, process it and determine if focus has moved to another window
385 (the FocusIn event handler sets the window in the event
386 structure to None to indicate this).
389 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
391 process_event(&event);
392 if (event.xfocus.window == None) {
401 Second, we query the X server for the current input focus.
402 to make sure that we keep a consistent state.
405 BlackboxWindow *focus;
408 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
409 focus = searchWindow(w);
413 focus got from "win" to "focus" under some very strange
414 circumstances, and we need to make sure that the focus indication
418 setFocusedWindow(focus);
420 // we have no idea where focus went... so we set it to somewhere
430 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
432 printf("ShapeEvent\n");
433 if (e
.kind
!= ShapeBounding
) return;
435 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
439 client
->frame
->update();
444 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
449 } else if (e->xclient.message_type ==
450 xatom->getAtom(XAtom::blackbox_change_workspace) ||
451 e->xclient.message_type ==
452 xatom->getAtom(XAtom::net_current_desktop)) {
453 // NET_CURRENT_DESKTOP message
454 BScreen *screen = searchScreen(e->xclient.window);
456 unsigned int workspace = e->xclient.data.l[0];
457 if (screen && workspace < screen->getWorkspaceCount())
458 screen->changeWorkspaceID(workspace);
459 } else if (e->xclient.message_type ==
460 xatom->getAtom(XAtom::net_active_window)) {
462 BlackboxWindow *win = searchWindow(e->xclient.window);
465 BScreen *screen = win->getScreen();
468 win->deiconify(False, False);
469 if (! win->isStuck() &&
470 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
472 screen->changeWorkspaceID(win->getWorkspaceNumber());
474 if (win->isVisible() && win->setInputFocus()) {
475 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
477 win->installColormap(True);
480 } else if (e->xclient.message_type ==
481 xatom->getAtom(XAtom::net_number_of_desktops)) {
482 // NET_NUMBER_OF_DESKTOPS
483 BScreen *screen = searchScreen(e->xclient.window);
485 if (e->xclient.data.l[0] > 0)
486 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
487 } else if (e->xclient.message_type ==
488 xatom->getAtom(XAtom::net_close_window)) {
490 BlackboxWindow *win = searchWindow(e->xclient.window);
491 if (win && win->validateClient())
492 win->close(); // could this be smarter?
493 } else if (e->xclient.message_type ==
494 xatom->getAtom(XAtom::net_wm_moveresize)) {
496 BlackboxWindow *win = searchWindow(e->xclient.window);
497 if (win && win->validateClient()) {
498 int x_root = e->xclient.data.l[0],
499 y_root = e->xclient.data.l[1];
500 if ((Atom) e->xclient.data.l[2] ==
501 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
502 win->beginMove(x_root, y_root);
504 if ((Atom) e->xclient.data.l[2] ==
505 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
506 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
507 else if ((Atom) e->xclient.data.l[2] ==
508 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
509 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
510 else if ((Atom) e->xclient.data.l[2] ==
511 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
512 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
513 else if ((Atom) e->xclient.data.l[2] ==
514 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
515 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
523 void OBXEventHandler::handle(const XEvent
&e
)
525 /* mouse button events can get translated into:
526 press - button was pressed down
527 release - buttons was released
528 click - button was pressed and released on the same window
529 double click - clicked twice on the same widget in a given time and area
531 key events are only bindable to presses. key releases are ignored.
533 mouse enter/leave can be bound to for the entire window
538 // These types of XEvent's can be bound to actions by the user, and so end
539 // up getting passed off to the OBBindingMapper class at some point
540 // IOW: THESE WILL HAVE GUILE HOOKS
542 buttonPress(e
.xbutton
);
545 buttonRelease(e
.xbutton
);
554 enterNotify(e
.xcrossing
);
557 leaveNotify(e
.xcrossing
);
561 // These types of XEvent's can not be bound to actions by the user and so
562 // will simply be handled in this class
563 case ConfigureRequest
:
564 configureRequest(e
.xconfigurerequest
);
568 mapRequest(e
.xmaprequest
);
572 unmapNotify(e
.xunmap
);
576 destroyNotify(e
.xdestroywindow
);
580 reparentNotify(e
.xreparent
);
584 propertyNotify(e
.xproperty
);
592 colormapNotify(e
.xcolormap
);
604 clientMessage(e
.xclient
);
608 if (e
.type
== otk::OBDisplay::shapeEventBase())
609 shapeEvent((*(XShapeEvent
*)&e
));
614 case ClientMessage: {