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
)
124 OBClient
*client
= 0;
126 XSetWindowAttributes attrib_set
;
128 // XXX: manage the window, i.e. grab events n shit
130 // is the window a docking app
131 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
132 if ((wmhint
->flags
& StateHint
) &&
133 wmhint
->initial_state
== WithdrawnState
) {
134 //slit->addClient(w); // XXX: make dock apps work!
141 // choose the events we want to receive on the CLIENT window
142 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
144 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
146 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
147 CWEventMask
|CWDontPropagate
, &attrib_set
);
149 // create the OBClient class, which gets all of the hints on the window
150 Openbox::instance
->addClient(window
, client
= new OBClient(window
));
152 // we dont want a border on the client
153 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
155 // specify that if we exit, the window should not be destroyed and should be
156 // reparented back to root automatically
157 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
159 if (!client
->positionRequested()) {
160 // XXX: position the window intelligenty
163 // XXX: grab server, reparent client to the frame, ungrab server
165 // XXX: if shaped, shape the frame..
167 // XXX: if on the current desktop..
168 /// XMapSubwindows(otk::OBDisplay::display, FRAMEWINDOW);
169 XMapWindow(otk::OBDisplay::display
, window
);
171 // handle any requested states such as shaded/maximized
174 static void unmanageWindow(OBClient
*client
)
176 Window window
= client
->window();
178 // we dont want a border on the client
179 XSetWindowBorderWidth(otk::OBDisplay::display
, window
,client
->borderWidth());
181 // remove the window from our save set
182 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeDelete
);
186 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
189 printf("MapRequest for 0x%lx\n", e
.window
);
192 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
195 // XXX: uniconify and/or unshade the window
197 manageWindow(e
.window
);
201 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
205 if (win->isIconic()) {
209 if (win->isShaded()) {
214 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
216 win->setInputFocus();
218 BScreen *screen = searchScreen(e->xmaprequest.parent);
223 we got a map request for a window who's parent isn't root. this
224 can happen in only one circumstance:
226 a client window unmapped a managed window, and then remapped it
227 somewhere between unmapping the client window and reparenting it
230 regardless of how it happens, we need to find the screen that
234 XWindowAttributes wattrib;
235 if (! XGetWindowAttributes(otk::OBDisplay::display,
236 e->xmaprequest.window,
238 // failed to get the window attributes, perhaps the window has
239 // now been destroyed?
243 screen = searchScreen(wattrib.root);
244 assert(screen != 0); // this should never happen
246 screen->manageWindow(e->xmaprequest.window);
252 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
254 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
257 // XXX: unmanage the window, i.e. ungrab events n reparent n shit
258 Openbox::instance
->removeClient(e
.window
);
262 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
264 // XXX: window group leaders can come through here too!
266 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
269 // XXX: unmanage the window, i.e. ungrab events n reparent n shit
270 Openbox::instance
->removeClient(e
.window
);
274 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
277 this event is quite rare and is usually handled in unmapNotify
278 however, if the window is unmapped when the reparent event occurs
279 the window manager never sees it because an unmap event is not sent
280 to an already unmapped window.
282 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
286 BlackboxWindow *win = searchWindow(e->xreparent.window);
288 win->reparentNotifyEvent(&e->xreparent);
293 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
297 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
304 void OBXEventHandler::expose(const XExposeEvent
&first
)
306 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
309 // compress expose events
310 XEvent e
; e
.xexpose
= first
;
312 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
314 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
315 e
.xexpose
.window
, Expose
, &e
)) {
318 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
322 // use the merged area
323 e
.xexpose
.x
= area
.x();
324 e
.xexpose
.y
= area
.y();
325 e
.xexpose
.width
= area
.width();
326 e
.xexpose
.height
= area
.height();
329 // XXX: make the decorations redraw!
333 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
337 BScreen *screen = searchScreen(e->xcolormap.window);
339 screen->setRootColormapInstalled((e->xcolormap.state ==
340 ColormapInstalled) ? True : False);
345 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
347 if (e
.detail
!= NotifyNonlinear
&&
348 e
.detail
!= NotifyAncestor
) {
350 don't process FocusIns when:
351 1. the new focus window isn't an ancestor or inferior of the old
352 focus window (NotifyNonlinear)
353 make sure to allow the FocusIn when the old focus window was an
354 ancestor but didn't have a parent, such as root (NotifyAncestor)
359 BlackboxWindow *win = searchWindow(e.window);
361 if (! win->isFocused())
362 win->setFocusFlag(True);
365 set the event window to None. when the FocusOut event handler calls
366 this function recursively, it uses this as an indication that focus
367 has moved to a known window.
370 e->xfocus.window = None;
372 no_focus = False; // focusing is back on
378 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
380 if (e
.detail
!= NotifyNonlinear
) {
382 don't process FocusOuts when:
383 2. the new focus window isn't an ancestor or inferior of the old
384 focus window (NotifyNonlinear)
390 BlackboxWindow *win = searchWindow(e->xfocus.window);
391 if (win && win->isFocused()) {
394 before we mark "win" as unfocused, we need to verify that focus is
395 going to a known location, is in a known location, or set focus
400 // don't check the current focus if FocusOut was generated during a grab
401 bool check_focus = (e->xfocus.mode == NotifyNormal);
404 First, check if there is a pending FocusIn event waiting. if there
405 is, process it and determine if focus has moved to another window
406 (the FocusIn event handler sets the window in the event
407 structure to None to indicate this).
410 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
412 process_event(&event);
413 if (event.xfocus.window == None) {
422 Second, we query the X server for the current input focus.
423 to make sure that we keep a consistent state.
426 BlackboxWindow *focus;
429 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
430 focus = searchWindow(w);
434 focus got from "win" to "focus" under some very strange
435 circumstances, and we need to make sure that the focus indication
439 setFocusedWindow(focus);
441 // we have no idea where focus went... so we set it to somewhere
451 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
453 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
454 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
456 if (win
&& shape_event
->kind
== ShapeBounding
)
457 win
->shapeEvent(shape_event
);
462 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
467 } else if (e->xclient.message_type ==
468 xatom->getAtom(XAtom::blackbox_change_workspace) ||
469 e->xclient.message_type ==
470 xatom->getAtom(XAtom::net_current_desktop)) {
471 // NET_CURRENT_DESKTOP message
472 BScreen *screen = searchScreen(e->xclient.window);
474 unsigned int workspace = e->xclient.data.l[0];
475 if (screen && workspace < screen->getWorkspaceCount())
476 screen->changeWorkspaceID(workspace);
477 } else if (e->xclient.message_type ==
478 xatom->getAtom(XAtom::net_active_window)) {
480 BlackboxWindow *win = searchWindow(e->xclient.window);
483 BScreen *screen = win->getScreen();
486 win->deiconify(False, False);
487 if (! win->isStuck() &&
488 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
490 screen->changeWorkspaceID(win->getWorkspaceNumber());
492 if (win->isVisible() && win->setInputFocus()) {
493 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
495 win->installColormap(True);
498 } else if (e->xclient.message_type ==
499 xatom->getAtom(XAtom::net_number_of_desktops)) {
500 // NET_NUMBER_OF_DESKTOPS
501 BScreen *screen = searchScreen(e->xclient.window);
503 if (e->xclient.data.l[0] > 0)
504 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
505 } else if (e->xclient.message_type ==
506 xatom->getAtom(XAtom::net_close_window)) {
508 BlackboxWindow *win = searchWindow(e->xclient.window);
509 if (win && win->validateClient())
510 win->close(); // could this be smarter?
511 } else if (e->xclient.message_type ==
512 xatom->getAtom(XAtom::net_wm_moveresize)) {
514 BlackboxWindow *win = searchWindow(e->xclient.window);
515 if (win && win->validateClient()) {
516 int x_root = e->xclient.data.l[0],
517 y_root = e->xclient.data.l[1];
518 if ((Atom) e->xclient.data.l[2] ==
519 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
520 win->beginMove(x_root, y_root);
522 if ((Atom) e->xclient.data.l[2] ==
523 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
524 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
525 else if ((Atom) e->xclient.data.l[2] ==
526 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
527 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
528 else if ((Atom) e->xclient.data.l[2] ==
529 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
530 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
531 else if ((Atom) e->xclient.data.l[2] ==
532 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
533 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
541 void OBXEventHandler::handle(const XEvent
&e
)
543 /* mouse button events can get translated into:
544 press - button was pressed down
545 release - buttons was released
546 click - button was pressed and released on the same window
547 double click - clicked twice on the same widget in a given time and area
549 key events are only bindable to presses. key releases are ignored.
551 mouse enter/leave can be bound to for the entire window
556 // These types of XEvent's can be bound to actions by the user, and so end
557 // up getting passed off to the OBBindingMapper class at some point
559 buttonPress(e
.xbutton
);
562 buttonRelease(e
.xbutton
);
571 enterNotify(e
.xcrossing
);
574 leaveNotify(e
.xcrossing
);
578 // These types of XEvent's can not be bound to actions by the user and so
579 // will simply be handled in this class
580 case ConfigureRequest
:
581 configureRequest(e
.xconfigurerequest
);
585 mapRequest(e
.xmaprequest
);
589 unmapNotify(e
.xunmap
);
593 destroyNotify(e
.xdestroywindow
);
597 reparentNotify(e
.xreparent
);
601 propertyNotify(e
.xproperty
);
609 colormapNotify(e
.xcolormap
);
621 clientMessage(e
.xclient
);
625 if (e
.type
== otk::OBDisplay::shapeEventBase())
631 case ClientMessage: {