1 // -*- mode: C++; indent-tabs-mode: nil; -*-
4 # include "../config.h"
7 #include "xeventhandler.hh"
11 #include "otk/display.hh"
12 #include "otk/rect.hh"
14 // XXX: REMOVE THIS SOON!!#!
15 #include "blackbox.hh"
16 #include "bbscreen.hh"
20 #include <X11/Xutil.h>
26 OBXEventHandler::OBXEventHandler()
28 _lasttime
= 1; // 0 is CurrentTime, so set to minimum
31 void OBXEventHandler::buttonPress(const XButtonEvent
&e
)
38 void OBXEventHandler::buttonRelease(const XButtonEvent
&e
)
45 void OBXEventHandler::keyPress(const XKeyEvent
&e
)
51 void OBXEventHandler::motion(const XMotionEvent
&e
)
55 // the pointer is on the wrong screen
56 if (! e
.same_screen
) return;
61 void OBXEventHandler::enterNotify(const XCrossingEvent
&e
)
65 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
69 BScreen *screen = (BScreen *) 0;
70 BlackboxWindow *win = (BlackboxWindow *) 0;
72 if (e->xcrossing.mode == NotifyGrab) break;
74 if ((e->xcrossing.window == e->xcrossing.root) &&
75 (screen = searchScreen(e->xcrossing.window))) {
76 screen->getImageControl()->installRootColormap();
77 } else if ((win = searchWindow(e->xcrossing.window))) {
79 win->enterNotifyEvent(&e->xcrossing);
85 void OBXEventHandler::leaveNotify(const XCrossingEvent
&e
)
89 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
93 BlackboxWindow *win = (BlackboxWindow *) 0;
95 if ((win = searchWindow(e->xcrossing.window)))
96 win->leaveNotifyEvent(&e->xcrossing);
101 void OBXEventHandler::configureRequest(const XConfigureRequestEvent
&e
)
103 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
106 /* BlackboxWindow *win = (BlackboxWindow *) 0;
108 if ((win = searchWindow(e->xconfigurerequest.window))) {
109 win->configureRequestEvent(&e->xconfigurerequest);
111 if (validateWindow(e->xconfigurerequest.window)) {
114 xwc.x = e->xconfigurerequest.x;
115 xwc.y = e->xconfigurerequest.y;
116 xwc.width = e->xconfigurerequest.width;
117 xwc.height = e->xconfigurerequest.height;
118 xwc.border_width = e->xconfigurerequest.border_width;
119 xwc.sibling = e->xconfigurerequest.above;
120 xwc.stack_mode = e->xconfigurerequest.detail;
122 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
123 e->xconfigurerequest.value_mask, &xwc);
130 // XXX: put this into the OBScreen or OBClient class!
131 void OBXEventHandler::manageWindow(int screen
, Window window
)
133 OBClient
*client
= 0;
135 XSetWindowAttributes attrib_set
;
137 // XXX: manage the window, i.e. grab events n shit
139 // is the window a docking app
140 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
141 if ((wmhint
->flags
& StateHint
) &&
142 wmhint
->initial_state
== WithdrawnState
) {
143 //slit->addClient(w); // XXX: make dock apps work!
150 // choose the events we want to receive on the CLIENT window
151 attrib_set
.event_mask
= OBClient::event_mask
;
152 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
154 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
155 CWEventMask
|CWDontPropagate
, &attrib_set
);
157 // create the OBClient class, which gets all of the hints on the window
158 Openbox::instance
->addClient(window
, client
= new OBClient(screen
, window
));
160 // we dont want a border on the client
161 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
163 // specify that if we exit, the window should not be destroyed and should be
164 // reparented back to root automatically
165 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
167 if (!client
->positionRequested()) {
168 // XXX: position the window intelligenty
171 // XXX: store a style somewheres cooler!!
172 otk::Style
*style
= ((Blackbox
*)Openbox::instance
)->
173 searchScreen(RootWindow(otk::OBDisplay::display
, screen
))->
175 // create the decoration frame for the client window
176 client
->frame
= new OBFrame(client
, style
);
178 // add all the client's decoration windows as event handlers for the client
179 Openbox::instance
->addClient(client
->frame
->window(), client
);
180 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
181 Openbox::instance
->addClient(client
->frame
->buttonIconify(), client
);
182 Openbox::instance
->addClient(client
->frame
->buttonMax(), client
);
183 Openbox::instance
->addClient(client
->frame
->buttonStick(), client
);
184 Openbox::instance
->addClient(client
->frame
->buttonClose(), client
);
185 Openbox::instance
->addClient(client
->frame
->label(), client
);
186 Openbox::instance
->addClient(client
->frame
->handle(), client
);
187 Openbox::instance
->addClient(client
->frame
->gripLeft(), client
);
188 Openbox::instance
->addClient(client
->frame
->gripRight(), client
);
190 // XXX: if on the current desktop..
191 XMapWindow(otk::OBDisplay::display
, client
->frame
->window());
193 // XXX: handle any requested states such as shaded/maximized
196 // XXX: move this to the OBScreen or OBClient class!
197 void OBXEventHandler::unmanageWindow(OBClient
*client
)
199 OBFrame
*frame
= client
->frame
;
201 // XXX: pass around focus if this window was focused
203 // remove the window from our save set
204 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
206 // we dont want events no more
207 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
209 XUnmapWindow(otk::OBDisplay::display
, frame
->window());
211 // we dont want a border on the client
212 XSetWindowBorderWidth(otk::OBDisplay::display
, client
->window(),
213 client
->borderWidth());
215 // remove the client class from the search list
216 Openbox::instance
->removeClient(client
->window());
217 // remove the frame's decor elements as event handlers for the client
218 Openbox::instance
->removeClient(frame
->window());
219 Openbox::instance
->removeClient(frame
->titlebar());
220 Openbox::instance
->removeClient(frame
->buttonIconify());
221 Openbox::instance
->removeClient(frame
->buttonMax());
222 Openbox::instance
->removeClient(frame
->buttonStick());
223 Openbox::instance
->removeClient(frame
->buttonClose());
224 Openbox::instance
->removeClient(frame
->label());
225 Openbox::instance
->removeClient(frame
->handle());
226 Openbox::instance
->removeClient(frame
->gripLeft());
227 Openbox::instance
->removeClient(frame
->gripRight());
229 delete client
->frame
;
235 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
238 printf("MapRequest for 0x%lx\n", e
.window
);
241 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
244 // XXX: uniconify and/or unshade the window
246 int screen
= INT_MAX
;
248 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
249 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == e
.parent
) {
254 if (screen
>= ScreenCount(otk::OBDisplay::display
)) {
256 we got a map request for a window who's parent isn't root. this
257 can happen in only one circumstance:
259 a client window unmapped a managed window, and then remapped it
260 somewhere between unmapping the client window and reparenting it
263 regardless of how it happens, we need to find the screen that
266 XWindowAttributes wattrib
;
267 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
.window
,
269 // failed to get the window attributes, perhaps the window has
270 // now been destroyed?
274 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
275 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == wattrib
.root
) {
281 assert(screen
< ScreenCount(otk::OBDisplay::display
));
283 manageWindow(screen
, e
.window
);
287 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
291 if (win->isIconic()) {
295 if (win->isShaded()) {
300 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
302 win->setInputFocus();
304 BScreen *screen = searchScreen(e->xmaprequest.parent);
309 we got a map request for a window who's parent isn't root. this
310 can happen in only one circumstance:
312 a client window unmapped a managed window, and then remapped it
313 somewhere between unmapping the client window and reparenting it
316 regardless of how it happens, we need to find the screen that
320 XWindowAttributes wattrib;
321 if (! XGetWindowAttributes(otk::OBDisplay::display,
322 e->xmaprequest.window,
324 // failed to get the window attributes, perhaps the window has
325 // now been destroyed?
329 screen = searchScreen(wattrib.root);
330 assert(screen != 0); // this should never happen
332 screen->manageWindow(e->xmaprequest.window);
338 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
340 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
343 unmanageWindow(client
);
347 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
349 // XXX: window group leaders can come through here too!
351 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
354 unmanageWindow(client
);
358 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
361 this event is quite rare and is usually handled in unmapNotify
362 however, if the window is unmapped when the reparent event occurs
363 the window manager never sees it because an unmap event is not sent
364 to an already unmapped window.
366 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
370 BlackboxWindow *win = searchWindow(e->xreparent.window);
372 win->reparentNotifyEvent(&e->xreparent);
377 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
381 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
388 void OBXEventHandler::expose(const XExposeEvent
&first
)
390 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
393 // compress expose events
394 XEvent e
; e
.xexpose
= first
;
396 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
398 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
399 e
.xexpose
.window
, Expose
, &e
)) {
402 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
406 // use the merged area
407 e
.xexpose
.x
= area
.x();
408 e
.xexpose
.y
= area
.y();
409 e
.xexpose
.width
= area
.width();
410 e
.xexpose
.height
= area
.height();
413 // XXX: make the decorations redraw!
417 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
421 BScreen *screen = searchScreen(e->xcolormap.window);
423 screen->setRootColormapInstalled((e->xcolormap.state ==
424 ColormapInstalled) ? True : False);
429 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
431 if (e
.detail
!= NotifyNonlinear
&&
432 e
.detail
!= NotifyAncestor
) {
434 don't process FocusIns when:
435 1. the new focus window isn't an ancestor or inferior of the old
436 focus window (NotifyNonlinear)
437 make sure to allow the FocusIn when the old focus window was an
438 ancestor but didn't have a parent, such as root (NotifyAncestor)
443 BlackboxWindow *win = searchWindow(e.window);
445 if (! win->isFocused())
446 win->setFocusFlag(True);
449 set the event window to None. when the FocusOut event handler calls
450 this function recursively, it uses this as an indication that focus
451 has moved to a known window.
454 e->xfocus.window = None;
456 no_focus = False; // focusing is back on
462 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
464 if (e
.detail
!= NotifyNonlinear
) {
466 don't process FocusOuts when:
467 2. the new focus window isn't an ancestor or inferior of the old
468 focus window (NotifyNonlinear)
474 BlackboxWindow *win = searchWindow(e->xfocus.window);
475 if (win && win->isFocused()) {
478 before we mark "win" as unfocused, we need to verify that focus is
479 going to a known location, is in a known location, or set focus
484 // don't check the current focus if FocusOut was generated during a grab
485 bool check_focus = (e->xfocus.mode == NotifyNormal);
488 First, check if there is a pending FocusIn event waiting. if there
489 is, process it and determine if focus has moved to another window
490 (the FocusIn event handler sets the window in the event
491 structure to None to indicate this).
494 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
496 process_event(&event);
497 if (event.xfocus.window == None) {
506 Second, we query the X server for the current input focus.
507 to make sure that we keep a consistent state.
510 BlackboxWindow *focus;
513 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
514 focus = searchWindow(w);
518 focus got from "win" to "focus" under some very strange
519 circumstances, and we need to make sure that the focus indication
523 setFocusedWindow(focus);
525 // we have no idea where focus went... so we set it to somewhere
535 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
537 printf("ShapeEvent\n");
538 if (e
.kind
!= ShapeBounding
) return;
540 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
544 client
->frame
->update();
549 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
554 } else if (e->xclient.message_type ==
555 xatom->getAtom(XAtom::blackbox_change_workspace) ||
556 e->xclient.message_type ==
557 xatom->getAtom(XAtom::net_current_desktop)) {
558 // NET_CURRENT_DESKTOP message
559 BScreen *screen = searchScreen(e->xclient.window);
561 unsigned int workspace = e->xclient.data.l[0];
562 if (screen && workspace < screen->getWorkspaceCount())
563 screen->changeWorkspaceID(workspace);
564 } else if (e->xclient.message_type ==
565 xatom->getAtom(XAtom::net_active_window)) {
567 BlackboxWindow *win = searchWindow(e->xclient.window);
570 BScreen *screen = win->getScreen();
573 win->deiconify(False, False);
574 if (! win->isStuck() &&
575 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
577 screen->changeWorkspaceID(win->getWorkspaceNumber());
579 if (win->isVisible() && win->setInputFocus()) {
580 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
582 win->installColormap(True);
585 } else if (e->xclient.message_type ==
586 xatom->getAtom(XAtom::net_number_of_desktops)) {
587 // NET_NUMBER_OF_DESKTOPS
588 BScreen *screen = searchScreen(e->xclient.window);
590 if (e->xclient.data.l[0] > 0)
591 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
592 } else if (e->xclient.message_type ==
593 xatom->getAtom(XAtom::net_close_window)) {
595 BlackboxWindow *win = searchWindow(e->xclient.window);
596 if (win && win->validateClient())
597 win->close(); // could this be smarter?
598 } else if (e->xclient.message_type ==
599 xatom->getAtom(XAtom::net_wm_moveresize)) {
601 BlackboxWindow *win = searchWindow(e->xclient.window);
602 if (win && win->validateClient()) {
603 int x_root = e->xclient.data.l[0],
604 y_root = e->xclient.data.l[1];
605 if ((Atom) e->xclient.data.l[2] ==
606 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
607 win->beginMove(x_root, y_root);
609 if ((Atom) e->xclient.data.l[2] ==
610 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
611 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
612 else if ((Atom) e->xclient.data.l[2] ==
613 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
614 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
615 else if ((Atom) e->xclient.data.l[2] ==
616 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
617 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
618 else if ((Atom) e->xclient.data.l[2] ==
619 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
620 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
628 void OBXEventHandler::handle(const XEvent
&e
)
630 /* mouse button events can get translated into:
631 press - button was pressed down
632 release - buttons was released
633 click - button was pressed and released on the same window
634 double click - clicked twice on the same widget in a given time and area
636 key events are only bindable to presses. key releases are ignored.
638 mouse enter/leave can be bound to for the entire window
643 // These types of XEvent's can be bound to actions by the user, and so end
644 // up getting passed off to the OBBindingMapper class at some point
645 // IOW: THESE WILL HAVE GUILE HOOKS
647 buttonPress(e
.xbutton
);
650 buttonRelease(e
.xbutton
);
659 enterNotify(e
.xcrossing
);
662 leaveNotify(e
.xcrossing
);
666 // These types of XEvent's can not be bound to actions by the user and so
667 // will simply be handled in this class
668 case ConfigureRequest
:
669 configureRequest(e
.xconfigurerequest
);
673 mapRequest(e
.xmaprequest
);
677 unmapNotify(e
.xunmap
);
681 destroyNotify(e
.xdestroywindow
);
685 reparentNotify(e
.xreparent
);
689 propertyNotify(e
.xproperty
);
697 colormapNotify(e
.xcolormap
);
709 clientMessage(e
.xclient
);
713 if (e
.type
== otk::OBDisplay::shapeEventBase())
714 shapeEvent((*(XShapeEvent
*)&e
));
719 case ClientMessage: {