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 // XXX: put this into the OBScreen or OBClient class!
128 void OBXEventHandler::manageWindow(int screen
, Window window
)
130 OBClient
*client
= 0;
132 XSetWindowAttributes attrib_set
;
134 // XXX: manage the window, i.e. grab events n shit
136 // is the window a docking app
137 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
138 if ((wmhint
->flags
& StateHint
) &&
139 wmhint
->initial_state
== WithdrawnState
) {
140 //slit->addClient(w); // XXX: make dock apps work!
147 // choose the events we want to receive on the CLIENT window
148 attrib_set
.event_mask
= OBClient::event_mask
;
149 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
151 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
152 CWEventMask
|CWDontPropagate
, &attrib_set
);
154 // create the OBClient class, which gets all of the hints on the window
155 Openbox::instance
->addClient(window
, client
= new OBClient(screen
, window
));
157 // we dont want a border on the client
158 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
160 // specify that if we exit, the window should not be destroyed and should be
161 // reparented back to root automatically
162 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
164 if (!client
->positionRequested()) {
165 // XXX: position the window intelligenty
168 // create the decoration frame for the client window
169 client
->frame
= new OBFrame(client
,
170 Openbox::instance
->screen(screen
)->style());
172 // add all the client's decoration windows as event handlers for the client
173 Openbox::instance
->addClient(client
->frame
->window(), client
);
174 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
175 Openbox::instance
->addClient(client
->frame
->buttonIconify(), client
);
176 Openbox::instance
->addClient(client
->frame
->buttonMax(), client
);
177 Openbox::instance
->addClient(client
->frame
->buttonStick(), client
);
178 Openbox::instance
->addClient(client
->frame
->buttonClose(), client
);
179 Openbox::instance
->addClient(client
->frame
->label(), client
);
180 Openbox::instance
->addClient(client
->frame
->handle(), client
);
181 Openbox::instance
->addClient(client
->frame
->gripLeft(), client
);
182 Openbox::instance
->addClient(client
->frame
->gripRight(), client
);
184 // XXX: if on the current desktop..
185 XMapWindow(otk::OBDisplay::display
, client
->frame
->window());
187 // XXX: handle any requested states such as shaded/maximized
190 // XXX: move this to the OBScreen or OBClient class!
191 void OBXEventHandler::unmanageWindow(OBClient
*client
)
193 OBFrame
*frame
= client
->frame
;
195 // XXX: pass around focus if this window was focused
197 // remove the window from our save set
198 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
200 // we dont want events no more
201 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
203 XUnmapWindow(otk::OBDisplay::display
, frame
->window());
205 // we dont want a border on the client
206 XSetWindowBorderWidth(otk::OBDisplay::display
, client
->window(),
207 client
->borderWidth());
209 // remove the client class from the search list
210 Openbox::instance
->removeClient(client
->window());
211 // remove the frame's decor elements as event handlers for the client
212 Openbox::instance
->removeClient(frame
->window());
213 Openbox::instance
->removeClient(frame
->titlebar());
214 Openbox::instance
->removeClient(frame
->buttonIconify());
215 Openbox::instance
->removeClient(frame
->buttonMax());
216 Openbox::instance
->removeClient(frame
->buttonStick());
217 Openbox::instance
->removeClient(frame
->buttonClose());
218 Openbox::instance
->removeClient(frame
->label());
219 Openbox::instance
->removeClient(frame
->handle());
220 Openbox::instance
->removeClient(frame
->gripLeft());
221 Openbox::instance
->removeClient(frame
->gripRight());
223 delete client
->frame
;
229 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
232 printf("MapRequest for 0x%lx\n", e
.window
);
235 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
238 // XXX: uniconify and/or unshade the window
240 int screen
= INT_MAX
;
242 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
243 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == e
.parent
) {
248 if (screen
>= ScreenCount(otk::OBDisplay::display
)) {
250 we got a map request for a window who's parent isn't root. this
251 can happen in only one circumstance:
253 a client window unmapped a managed window, and then remapped it
254 somewhere between unmapping the client window and reparenting it
257 regardless of how it happens, we need to find the screen that
260 XWindowAttributes wattrib
;
261 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
.window
,
263 // failed to get the window attributes, perhaps the window has
264 // now been destroyed?
268 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
269 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == wattrib
.root
) {
275 assert(screen
< ScreenCount(otk::OBDisplay::display
));
277 manageWindow(screen
, e
.window
);
281 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
285 if (win->isIconic()) {
289 if (win->isShaded()) {
294 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
296 win->setInputFocus();
298 BScreen *screen = searchScreen(e->xmaprequest.parent);
303 we got a map request for a window who's parent isn't root. this
304 can happen in only one circumstance:
306 a client window unmapped a managed window, and then remapped it
307 somewhere between unmapping the client window and reparenting it
310 regardless of how it happens, we need to find the screen that
314 XWindowAttributes wattrib;
315 if (! XGetWindowAttributes(otk::OBDisplay::display,
316 e->xmaprequest.window,
318 // failed to get the window attributes, perhaps the window has
319 // now been destroyed?
323 screen = searchScreen(wattrib.root);
324 assert(screen != 0); // this should never happen
326 screen->manageWindow(e->xmaprequest.window);
332 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
334 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
337 unmanageWindow(client
);
341 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
343 // XXX: window group leaders can come through here too!
345 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
348 unmanageWindow(client
);
352 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
355 this event is quite rare and is usually handled in unmapNotify
356 however, if the window is unmapped when the reparent event occurs
357 the window manager never sees it because an unmap event is not sent
358 to an already unmapped window.
360 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
364 BlackboxWindow *win = searchWindow(e->xreparent.window);
366 win->reparentNotifyEvent(&e->xreparent);
371 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
375 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
382 void OBXEventHandler::expose(const XExposeEvent
&first
)
384 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
387 // compress expose events
388 XEvent e
; e
.xexpose
= first
;
390 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
392 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
393 e
.xexpose
.window
, Expose
, &e
)) {
396 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
400 // use the merged area
401 e
.xexpose
.x
= area
.x();
402 e
.xexpose
.y
= area
.y();
403 e
.xexpose
.width
= area
.width();
404 e
.xexpose
.height
= area
.height();
407 // XXX: make the decorations redraw!
411 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
415 BScreen *screen = searchScreen(e->xcolormap.window);
417 screen->setRootColormapInstalled((e->xcolormap.state ==
418 ColormapInstalled) ? True : False);
423 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
425 if (e
.detail
!= NotifyNonlinear
&&
426 e
.detail
!= NotifyAncestor
) {
428 don't process FocusIns when:
429 1. the new focus window isn't an ancestor or inferior of the old
430 focus window (NotifyNonlinear)
431 make sure to allow the FocusIn when the old focus window was an
432 ancestor but didn't have a parent, such as root (NotifyAncestor)
437 BlackboxWindow *win = searchWindow(e.window);
439 if (! win->isFocused())
440 win->setFocusFlag(True);
443 set the event window to None. when the FocusOut event handler calls
444 this function recursively, it uses this as an indication that focus
445 has moved to a known window.
448 e->xfocus.window = None;
450 no_focus = False; // focusing is back on
456 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
458 if (e
.detail
!= NotifyNonlinear
) {
460 don't process FocusOuts when:
461 2. the new focus window isn't an ancestor or inferior of the old
462 focus window (NotifyNonlinear)
468 BlackboxWindow *win = searchWindow(e->xfocus.window);
469 if (win && win->isFocused()) {
472 before we mark "win" as unfocused, we need to verify that focus is
473 going to a known location, is in a known location, or set focus
478 // don't check the current focus if FocusOut was generated during a grab
479 bool check_focus = (e->xfocus.mode == NotifyNormal);
482 First, check if there is a pending FocusIn event waiting. if there
483 is, process it and determine if focus has moved to another window
484 (the FocusIn event handler sets the window in the event
485 structure to None to indicate this).
488 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
490 process_event(&event);
491 if (event.xfocus.window == None) {
500 Second, we query the X server for the current input focus.
501 to make sure that we keep a consistent state.
504 BlackboxWindow *focus;
507 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
508 focus = searchWindow(w);
512 focus got from "win" to "focus" under some very strange
513 circumstances, and we need to make sure that the focus indication
517 setFocusedWindow(focus);
519 // we have no idea where focus went... so we set it to somewhere
529 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
531 printf("ShapeEvent\n");
532 if (e
.kind
!= ShapeBounding
) return;
534 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
538 client
->frame
->update();
543 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
548 } else if (e->xclient.message_type ==
549 xatom->getAtom(XAtom::blackbox_change_workspace) ||
550 e->xclient.message_type ==
551 xatom->getAtom(XAtom::net_current_desktop)) {
552 // NET_CURRENT_DESKTOP message
553 BScreen *screen = searchScreen(e->xclient.window);
555 unsigned int workspace = e->xclient.data.l[0];
556 if (screen && workspace < screen->getWorkspaceCount())
557 screen->changeWorkspaceID(workspace);
558 } else if (e->xclient.message_type ==
559 xatom->getAtom(XAtom::net_active_window)) {
561 BlackboxWindow *win = searchWindow(e->xclient.window);
564 BScreen *screen = win->getScreen();
567 win->deiconify(False, False);
568 if (! win->isStuck() &&
569 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
571 screen->changeWorkspaceID(win->getWorkspaceNumber());
573 if (win->isVisible() && win->setInputFocus()) {
574 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
576 win->installColormap(True);
579 } else if (e->xclient.message_type ==
580 xatom->getAtom(XAtom::net_number_of_desktops)) {
581 // NET_NUMBER_OF_DESKTOPS
582 BScreen *screen = searchScreen(e->xclient.window);
584 if (e->xclient.data.l[0] > 0)
585 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
586 } else if (e->xclient.message_type ==
587 xatom->getAtom(XAtom::net_close_window)) {
589 BlackboxWindow *win = searchWindow(e->xclient.window);
590 if (win && win->validateClient())
591 win->close(); // could this be smarter?
592 } else if (e->xclient.message_type ==
593 xatom->getAtom(XAtom::net_wm_moveresize)) {
595 BlackboxWindow *win = searchWindow(e->xclient.window);
596 if (win && win->validateClient()) {
597 int x_root = e->xclient.data.l[0],
598 y_root = e->xclient.data.l[1];
599 if ((Atom) e->xclient.data.l[2] ==
600 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
601 win->beginMove(x_root, y_root);
603 if ((Atom) e->xclient.data.l[2] ==
604 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
605 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
606 else if ((Atom) e->xclient.data.l[2] ==
607 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
608 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
609 else if ((Atom) e->xclient.data.l[2] ==
610 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
611 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
612 else if ((Atom) e->xclient.data.l[2] ==
613 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
614 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
622 void OBXEventHandler::handle(const XEvent
&e
)
624 /* mouse button events can get translated into:
625 press - button was pressed down
626 release - buttons was released
627 click - button was pressed and released on the same window
628 double click - clicked twice on the same widget in a given time and area
630 key events are only bindable to presses. key releases are ignored.
632 mouse enter/leave can be bound to for the entire window
637 // These types of XEvent's can be bound to actions by the user, and so end
638 // up getting passed off to the OBBindingMapper class at some point
639 // IOW: THESE WILL HAVE GUILE HOOKS
641 buttonPress(e
.xbutton
);
644 buttonRelease(e
.xbutton
);
653 enterNotify(e
.xcrossing
);
656 leaveNotify(e
.xcrossing
);
660 // These types of XEvent's can not be bound to actions by the user and so
661 // will simply be handled in this class
662 case ConfigureRequest
:
663 configureRequest(e
.xconfigurerequest
);
667 mapRequest(e
.xmaprequest
);
671 unmapNotify(e
.xunmap
);
675 destroyNotify(e
.xdestroywindow
);
679 reparentNotify(e
.xreparent
);
683 propertyNotify(e
.xproperty
);
691 colormapNotify(e
.xcolormap
);
703 clientMessage(e
.xclient
);
707 if (e
.type
== otk::OBDisplay::shapeEventBase())
708 shapeEvent((*(XShapeEvent
*)&e
));
713 case ClientMessage: {