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"
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
));
159 // add all the client's decoration windows as event handlers for the client
160 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
161 Openbox::instance
->addClient(client
->frame
->buttonIconify(), client
);
162 Openbox::instance
->addClient(client
->frame
->buttonMax(), client
);
163 Openbox::instance
->addClient(client
->frame
->buttonStick(), client
);
164 Openbox::instance
->addClient(client
->frame
->buttonClose(), client
);
165 Openbox::instance
->addClient(client
->frame
->label(), client
);
166 Openbox::instance
->addClient(client
->frame
->handle(), client
);
167 Openbox::instance
->addClient(client
->frame
->gripLeft(), client
);
168 Openbox::instance
->addClient(client
->frame
->gripRight(), client
);
170 // we dont want a border on the client
171 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
173 // specify that if we exit, the window should not be destroyed and should be
174 // reparented back to root automatically
175 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
177 if (!client
->positionRequested()) {
178 // XXX: position the window intelligenty
181 // XXX: store a style somewheres cooler!!
182 otk::Style
*style
= ((Blackbox
*)Openbox::instance
)->
183 searchScreen(RootWindow(otk::OBDisplay::display
, screen
))->
185 client
->frame
= new OBFrame(client
, style
);
187 // XXX: if on the current desktop..
188 XMapWindow(otk::OBDisplay::display
, client
->frame
->window());
190 // XXX: handle any requested states such as shaded/maximized
193 // XXX: move this to the OBScreen or OBClient class!
194 void OBXEventHandler::unmanageWindow(OBClient
*client
)
196 OBFrame
*frame
= client
->frame
;
198 // XXX: pass around focus if this window was focused
200 // remove the window from our save set
201 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
203 // we dont want events no more
204 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
206 XUnmapWindow(otk::OBDisplay::display
, frame
->window());
208 // we dont want a border on the client
209 XSetWindowBorderWidth(otk::OBDisplay::display
, client
->window(),
210 client
->borderWidth());
212 // remove the client class from the search list
213 Openbox::instance
->removeClient(client
->window());
214 // remove the frame's decor elements as event handlers for the client
215 Openbox::instance
->removeClient(frame
->titlebar());
216 Openbox::instance
->removeClient(frame
->buttonIconify());
217 Openbox::instance
->removeClient(frame
->buttonMax());
218 Openbox::instance
->removeClient(frame
->buttonStick());
219 Openbox::instance
->removeClient(frame
->buttonClose());
220 Openbox::instance
->removeClient(frame
->label());
221 Openbox::instance
->removeClient(frame
->handle());
222 Openbox::instance
->removeClient(frame
->gripLeft());
223 Openbox::instance
->removeClient(frame
->gripRight());
225 delete client
->frame
;
231 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
234 printf("MapRequest for 0x%lx\n", e
.window
);
237 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
240 // XXX: uniconify and/or unshade the window
242 int screen
= INT_MAX
;
244 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
245 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == e
.parent
) {
250 if (screen
>= ScreenCount(otk::OBDisplay::display
)) {
252 we got a map request for a window who's parent isn't root. this
253 can happen in only one circumstance:
255 a client window unmapped a managed window, and then remapped it
256 somewhere between unmapping the client window and reparenting it
259 regardless of how it happens, we need to find the screen that
262 XWindowAttributes wattrib
;
263 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
.window
,
265 // failed to get the window attributes, perhaps the window has
266 // now been destroyed?
270 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
271 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == wattrib
.root
) {
277 assert(screen
< ScreenCount(otk::OBDisplay::display
));
279 manageWindow(screen
, e
.window
);
283 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
287 if (win->isIconic()) {
291 if (win->isShaded()) {
296 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
298 win->setInputFocus();
300 BScreen *screen = searchScreen(e->xmaprequest.parent);
305 we got a map request for a window who's parent isn't root. this
306 can happen in only one circumstance:
308 a client window unmapped a managed window, and then remapped it
309 somewhere between unmapping the client window and reparenting it
312 regardless of how it happens, we need to find the screen that
316 XWindowAttributes wattrib;
317 if (! XGetWindowAttributes(otk::OBDisplay::display,
318 e->xmaprequest.window,
320 // failed to get the window attributes, perhaps the window has
321 // now been destroyed?
325 screen = searchScreen(wattrib.root);
326 assert(screen != 0); // this should never happen
328 screen->manageWindow(e->xmaprequest.window);
334 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
336 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
339 unmanageWindow(client
);
343 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
345 // XXX: window group leaders can come through here too!
347 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
350 unmanageWindow(client
);
354 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
357 this event is quite rare and is usually handled in unmapNotify
358 however, if the window is unmapped when the reparent event occurs
359 the window manager never sees it because an unmap event is not sent
360 to an already unmapped window.
362 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
366 BlackboxWindow *win = searchWindow(e->xreparent.window);
368 win->reparentNotifyEvent(&e->xreparent);
373 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
377 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
384 void OBXEventHandler::expose(const XExposeEvent
&first
)
386 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
389 // compress expose events
390 XEvent e
; e
.xexpose
= first
;
392 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
394 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
395 e
.xexpose
.window
, Expose
, &e
)) {
398 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
402 // use the merged area
403 e
.xexpose
.x
= area
.x();
404 e
.xexpose
.y
= area
.y();
405 e
.xexpose
.width
= area
.width();
406 e
.xexpose
.height
= area
.height();
409 // XXX: make the decorations redraw!
413 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
417 BScreen *screen = searchScreen(e->xcolormap.window);
419 screen->setRootColormapInstalled((e->xcolormap.state ==
420 ColormapInstalled) ? True : False);
425 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
427 if (e
.detail
!= NotifyNonlinear
&&
428 e
.detail
!= NotifyAncestor
) {
430 don't process FocusIns when:
431 1. the new focus window isn't an ancestor or inferior of the old
432 focus window (NotifyNonlinear)
433 make sure to allow the FocusIn when the old focus window was an
434 ancestor but didn't have a parent, such as root (NotifyAncestor)
439 BlackboxWindow *win = searchWindow(e.window);
441 if (! win->isFocused())
442 win->setFocusFlag(True);
445 set the event window to None. when the FocusOut event handler calls
446 this function recursively, it uses this as an indication that focus
447 has moved to a known window.
450 e->xfocus.window = None;
452 no_focus = False; // focusing is back on
458 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
460 if (e
.detail
!= NotifyNonlinear
) {
462 don't process FocusOuts when:
463 2. the new focus window isn't an ancestor or inferior of the old
464 focus window (NotifyNonlinear)
470 BlackboxWindow *win = searchWindow(e->xfocus.window);
471 if (win && win->isFocused()) {
474 before we mark "win" as unfocused, we need to verify that focus is
475 going to a known location, is in a known location, or set focus
480 // don't check the current focus if FocusOut was generated during a grab
481 bool check_focus = (e->xfocus.mode == NotifyNormal);
484 First, check if there is a pending FocusIn event waiting. if there
485 is, process it and determine if focus has moved to another window
486 (the FocusIn event handler sets the window in the event
487 structure to None to indicate this).
490 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
492 process_event(&event);
493 if (event.xfocus.window == None) {
502 Second, we query the X server for the current input focus.
503 to make sure that we keep a consistent state.
506 BlackboxWindow *focus;
509 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
510 focus = searchWindow(w);
514 focus got from "win" to "focus" under some very strange
515 circumstances, and we need to make sure that the focus indication
519 setFocusedWindow(focus);
521 // we have no idea where focus went... so we set it to somewhere
531 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
533 printf("ShapeEvent\n");
534 if (e
.kind
!= ShapeBounding
) return;
536 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
540 client
->frame
->update();
545 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
550 } else if (e->xclient.message_type ==
551 xatom->getAtom(XAtom::blackbox_change_workspace) ||
552 e->xclient.message_type ==
553 xatom->getAtom(XAtom::net_current_desktop)) {
554 // NET_CURRENT_DESKTOP message
555 BScreen *screen = searchScreen(e->xclient.window);
557 unsigned int workspace = e->xclient.data.l[0];
558 if (screen && workspace < screen->getWorkspaceCount())
559 screen->changeWorkspaceID(workspace);
560 } else if (e->xclient.message_type ==
561 xatom->getAtom(XAtom::net_active_window)) {
563 BlackboxWindow *win = searchWindow(e->xclient.window);
566 BScreen *screen = win->getScreen();
569 win->deiconify(False, False);
570 if (! win->isStuck() &&
571 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
573 screen->changeWorkspaceID(win->getWorkspaceNumber());
575 if (win->isVisible() && win->setInputFocus()) {
576 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
578 win->installColormap(True);
581 } else if (e->xclient.message_type ==
582 xatom->getAtom(XAtom::net_number_of_desktops)) {
583 // NET_NUMBER_OF_DESKTOPS
584 BScreen *screen = searchScreen(e->xclient.window);
586 if (e->xclient.data.l[0] > 0)
587 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
588 } else if (e->xclient.message_type ==
589 xatom->getAtom(XAtom::net_close_window)) {
591 BlackboxWindow *win = searchWindow(e->xclient.window);
592 if (win && win->validateClient())
593 win->close(); // could this be smarter?
594 } else if (e->xclient.message_type ==
595 xatom->getAtom(XAtom::net_wm_moveresize)) {
597 BlackboxWindow *win = searchWindow(e->xclient.window);
598 if (win && win->validateClient()) {
599 int x_root = e->xclient.data.l[0],
600 y_root = e->xclient.data.l[1];
601 if ((Atom) e->xclient.data.l[2] ==
602 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
603 win->beginMove(x_root, y_root);
605 if ((Atom) e->xclient.data.l[2] ==
606 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
607 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
608 else if ((Atom) e->xclient.data.l[2] ==
609 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
610 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
611 else if ((Atom) e->xclient.data.l[2] ==
612 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
613 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
614 else if ((Atom) e->xclient.data.l[2] ==
615 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
616 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
624 void OBXEventHandler::handle(const XEvent
&e
)
626 /* mouse button events can get translated into:
627 press - button was pressed down
628 release - buttons was released
629 click - button was pressed and released on the same window
630 double click - clicked twice on the same widget in a given time and area
632 key events are only bindable to presses. key releases are ignored.
634 mouse enter/leave can be bound to for the entire window
639 // These types of XEvent's can be bound to actions by the user, and so end
640 // up getting passed off to the OBBindingMapper class at some point
641 // IOW: THESE WILL HAVE GUILE HOOKS
643 buttonPress(e
.xbutton
);
646 buttonRelease(e
.xbutton
);
655 enterNotify(e
.xcrossing
);
658 leaveNotify(e
.xcrossing
);
662 // These types of XEvent's can not be bound to actions by the user and so
663 // will simply be handled in this class
664 case ConfigureRequest
:
665 configureRequest(e
.xconfigurerequest
);
669 mapRequest(e
.xmaprequest
);
673 unmapNotify(e
.xunmap
);
677 destroyNotify(e
.xdestroywindow
);
681 reparentNotify(e
.xreparent
);
685 propertyNotify(e
.xproperty
);
693 colormapNotify(e
.xcolormap
);
705 clientMessage(e
.xclient
);
709 if (e
.type
== otk::OBDisplay::shapeEventBase())
710 shapeEvent((*(XShapeEvent
*)&e
));
715 case ClientMessage: {