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 bool remap
= false; // remap the window when we're done?
178 Window window
= client
->window();
180 // XXX: pass around focus if this window was focused
182 // remove the window from our save set
183 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeDelete
);
185 // we dont want events no more
186 XSelectInput(otk::OBDisplay::display
, window
, NoEventMask
);
188 // XXX: XUnmapWindow(otk::OBDisplay::display, FRAME);
189 XUnmapWindow(otk::OBDisplay::display
, window
);
191 // we dont want a border on the client
192 XSetWindowBorderWidth(otk::OBDisplay::display
, window
,client
->borderWidth());
194 // remove the client class from the search list
195 Openbox::instance
->removeClient(window
);
197 // check if the app has already reparented its window to the root window
199 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, window
, ReparentNotify
,
201 remap
= true; // XXX: why do we remap the window if they already
202 // reparented to root?
204 // according to the ICCCM - if the client doesn't reparent to
205 // root, then we have to do it for them
206 XReparentWindow(otk::OBDisplay::display
, window
,
207 RootWindow(otk::OBDisplay::display
,
208 DefaultScreen(otk::OBDisplay::display
)),
209 // XXX: screen->getRootWindow(),
210 client
->area().x(), client
->area().y());
213 // if we want to remap the window, do so now
215 XMapWindow(otk::OBDisplay::display
, window
);
220 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
223 printf("MapRequest for 0x%lx\n", e
.window
);
226 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
229 // XXX: uniconify and/or unshade the window
231 manageWindow(e
.window
);
235 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
239 if (win->isIconic()) {
243 if (win->isShaded()) {
248 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
250 win->setInputFocus();
252 BScreen *screen = searchScreen(e->xmaprequest.parent);
257 we got a map request for a window who's parent isn't root. this
258 can happen in only one circumstance:
260 a client window unmapped a managed window, and then remapped it
261 somewhere between unmapping the client window and reparenting it
264 regardless of how it happens, we need to find the screen that
268 XWindowAttributes wattrib;
269 if (! XGetWindowAttributes(otk::OBDisplay::display,
270 e->xmaprequest.window,
272 // failed to get the window attributes, perhaps the window has
273 // now been destroyed?
277 screen = searchScreen(wattrib.root);
278 assert(screen != 0); // this should never happen
280 screen->manageWindow(e->xmaprequest.window);
286 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
288 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
291 unmanageWindow(client
);
295 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
297 // XXX: window group leaders can come through here too!
299 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
302 unmanageWindow(client
);
306 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
309 this event is quite rare and is usually handled in unmapNotify
310 however, if the window is unmapped when the reparent event occurs
311 the window manager never sees it because an unmap event is not sent
312 to an already unmapped window.
314 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
318 BlackboxWindow *win = searchWindow(e->xreparent.window);
320 win->reparentNotifyEvent(&e->xreparent);
325 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
329 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
336 void OBXEventHandler::expose(const XExposeEvent
&first
)
338 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
341 // compress expose events
342 XEvent e
; e
.xexpose
= first
;
344 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
346 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
347 e
.xexpose
.window
, Expose
, &e
)) {
350 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
354 // use the merged area
355 e
.xexpose
.x
= area
.x();
356 e
.xexpose
.y
= area
.y();
357 e
.xexpose
.width
= area
.width();
358 e
.xexpose
.height
= area
.height();
361 // XXX: make the decorations redraw!
365 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
369 BScreen *screen = searchScreen(e->xcolormap.window);
371 screen->setRootColormapInstalled((e->xcolormap.state ==
372 ColormapInstalled) ? True : False);
377 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
379 if (e
.detail
!= NotifyNonlinear
&&
380 e
.detail
!= NotifyAncestor
) {
382 don't process FocusIns when:
383 1. the new focus window isn't an ancestor or inferior of the old
384 focus window (NotifyNonlinear)
385 make sure to allow the FocusIn when the old focus window was an
386 ancestor but didn't have a parent, such as root (NotifyAncestor)
391 BlackboxWindow *win = searchWindow(e.window);
393 if (! win->isFocused())
394 win->setFocusFlag(True);
397 set the event window to None. when the FocusOut event handler calls
398 this function recursively, it uses this as an indication that focus
399 has moved to a known window.
402 e->xfocus.window = None;
404 no_focus = False; // focusing is back on
410 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
412 if (e
.detail
!= NotifyNonlinear
) {
414 don't process FocusOuts when:
415 2. the new focus window isn't an ancestor or inferior of the old
416 focus window (NotifyNonlinear)
422 BlackboxWindow *win = searchWindow(e->xfocus.window);
423 if (win && win->isFocused()) {
426 before we mark "win" as unfocused, we need to verify that focus is
427 going to a known location, is in a known location, or set focus
432 // don't check the current focus if FocusOut was generated during a grab
433 bool check_focus = (e->xfocus.mode == NotifyNormal);
436 First, check if there is a pending FocusIn event waiting. if there
437 is, process it and determine if focus has moved to another window
438 (the FocusIn event handler sets the window in the event
439 structure to None to indicate this).
442 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
444 process_event(&event);
445 if (event.xfocus.window == None) {
454 Second, we query the X server for the current input focus.
455 to make sure that we keep a consistent state.
458 BlackboxWindow *focus;
461 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
462 focus = searchWindow(w);
466 focus got from "win" to "focus" under some very strange
467 circumstances, and we need to make sure that the focus indication
471 setFocusedWindow(focus);
473 // we have no idea where focus went... so we set it to somewhere
483 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
485 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
486 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
488 if (win
&& shape_event
->kind
== ShapeBounding
)
489 win
->shapeEvent(shape_event
);
494 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
499 } else if (e->xclient.message_type ==
500 xatom->getAtom(XAtom::blackbox_change_workspace) ||
501 e->xclient.message_type ==
502 xatom->getAtom(XAtom::net_current_desktop)) {
503 // NET_CURRENT_DESKTOP message
504 BScreen *screen = searchScreen(e->xclient.window);
506 unsigned int workspace = e->xclient.data.l[0];
507 if (screen && workspace < screen->getWorkspaceCount())
508 screen->changeWorkspaceID(workspace);
509 } else if (e->xclient.message_type ==
510 xatom->getAtom(XAtom::net_active_window)) {
512 BlackboxWindow *win = searchWindow(e->xclient.window);
515 BScreen *screen = win->getScreen();
518 win->deiconify(False, False);
519 if (! win->isStuck() &&
520 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
522 screen->changeWorkspaceID(win->getWorkspaceNumber());
524 if (win->isVisible() && win->setInputFocus()) {
525 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
527 win->installColormap(True);
530 } else if (e->xclient.message_type ==
531 xatom->getAtom(XAtom::net_number_of_desktops)) {
532 // NET_NUMBER_OF_DESKTOPS
533 BScreen *screen = searchScreen(e->xclient.window);
535 if (e->xclient.data.l[0] > 0)
536 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
537 } else if (e->xclient.message_type ==
538 xatom->getAtom(XAtom::net_close_window)) {
540 BlackboxWindow *win = searchWindow(e->xclient.window);
541 if (win && win->validateClient())
542 win->close(); // could this be smarter?
543 } else if (e->xclient.message_type ==
544 xatom->getAtom(XAtom::net_wm_moveresize)) {
546 BlackboxWindow *win = searchWindow(e->xclient.window);
547 if (win && win->validateClient()) {
548 int x_root = e->xclient.data.l[0],
549 y_root = e->xclient.data.l[1];
550 if ((Atom) e->xclient.data.l[2] ==
551 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
552 win->beginMove(x_root, y_root);
554 if ((Atom) e->xclient.data.l[2] ==
555 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
556 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
557 else if ((Atom) e->xclient.data.l[2] ==
558 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
559 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
560 else if ((Atom) e->xclient.data.l[2] ==
561 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
562 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
563 else if ((Atom) e->xclient.data.l[2] ==
564 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
565 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
573 void OBXEventHandler::handle(const XEvent
&e
)
575 /* mouse button events can get translated into:
576 press - button was pressed down
577 release - buttons was released
578 click - button was pressed and released on the same window
579 double click - clicked twice on the same widget in a given time and area
581 key events are only bindable to presses. key releases are ignored.
583 mouse enter/leave can be bound to for the entire window
588 // These types of XEvent's can be bound to actions by the user, and so end
589 // up getting passed off to the OBBindingMapper class at some point
591 buttonPress(e
.xbutton
);
594 buttonRelease(e
.xbutton
);
603 enterNotify(e
.xcrossing
);
606 leaveNotify(e
.xcrossing
);
610 // These types of XEvent's can not be bound to actions by the user and so
611 // will simply be handled in this class
612 case ConfigureRequest
:
613 configureRequest(e
.xconfigurerequest
);
617 mapRequest(e
.xmaprequest
);
621 unmapNotify(e
.xunmap
);
625 destroyNotify(e
.xdestroywindow
);
629 reparentNotify(e
.xreparent
);
633 propertyNotify(e
.xproperty
);
641 colormapNotify(e
.xcolormap
);
653 clientMessage(e
.xclient
);
657 if (e
.type
== otk::OBDisplay::shapeEventBase())
663 case ClientMessage: {