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
));
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 client
->frame
= new OBFrame(client
, style
);
177 // XXX: if on the current desktop..
178 XMapWindow(otk::OBDisplay::display
, client
->frame
->window());
180 // XXX: handle any requested states such as shaded/maximized
183 // XXX: move this to the OBScreen or OBClient class!
184 void OBXEventHandler::unmanageWindow(OBClient
*client
)
186 OBFrame
*frame
= client
->frame
;
188 // XXX: pass around focus if this window was focused
190 // remove the window from our save set
191 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
193 // we dont want events no more
194 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
196 XUnmapWindow(otk::OBDisplay::display
, frame
->window());
198 // we dont want a border on the client
199 XSetWindowBorderWidth(otk::OBDisplay::display
, client
->window(),
200 client
->borderWidth());
202 // remove the client class from the search list
203 Openbox::instance
->removeClient(client
->window());
205 delete client
->frame
;
211 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
214 printf("MapRequest for 0x%lx\n", e
.window
);
217 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
220 // XXX: uniconify and/or unshade the window
222 int screen
= INT_MAX
;
224 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
225 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == e
.parent
) {
230 if (screen
>= ScreenCount(otk::OBDisplay::display
)) {
232 we got a map request for a window who's parent isn't root. this
233 can happen in only one circumstance:
235 a client window unmapped a managed window, and then remapped it
236 somewhere between unmapping the client window and reparenting it
239 regardless of how it happens, we need to find the screen that
242 XWindowAttributes wattrib
;
243 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
.window
,
245 // failed to get the window attributes, perhaps the window has
246 // now been destroyed?
250 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
251 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == wattrib
.root
) {
257 assert(screen
< ScreenCount(otk::OBDisplay::display
));
259 manageWindow(screen
, e
.window
);
263 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
267 if (win->isIconic()) {
271 if (win->isShaded()) {
276 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
278 win->setInputFocus();
280 BScreen *screen = searchScreen(e->xmaprequest.parent);
285 we got a map request for a window who's parent isn't root. this
286 can happen in only one circumstance:
288 a client window unmapped a managed window, and then remapped it
289 somewhere between unmapping the client window and reparenting it
292 regardless of how it happens, we need to find the screen that
296 XWindowAttributes wattrib;
297 if (! XGetWindowAttributes(otk::OBDisplay::display,
298 e->xmaprequest.window,
300 // failed to get the window attributes, perhaps the window has
301 // now been destroyed?
305 screen = searchScreen(wattrib.root);
306 assert(screen != 0); // this should never happen
308 screen->manageWindow(e->xmaprequest.window);
314 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
316 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
319 unmanageWindow(client
);
323 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
325 // XXX: window group leaders can come through here too!
327 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
330 unmanageWindow(client
);
334 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
337 this event is quite rare and is usually handled in unmapNotify
338 however, if the window is unmapped when the reparent event occurs
339 the window manager never sees it because an unmap event is not sent
340 to an already unmapped window.
342 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
346 BlackboxWindow *win = searchWindow(e->xreparent.window);
348 win->reparentNotifyEvent(&e->xreparent);
353 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
357 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
364 void OBXEventHandler::expose(const XExposeEvent
&first
)
366 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
369 // compress expose events
370 XEvent e
; e
.xexpose
= first
;
372 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
374 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
375 e
.xexpose
.window
, Expose
, &e
)) {
378 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
382 // use the merged area
383 e
.xexpose
.x
= area
.x();
384 e
.xexpose
.y
= area
.y();
385 e
.xexpose
.width
= area
.width();
386 e
.xexpose
.height
= area
.height();
389 // XXX: make the decorations redraw!
393 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
397 BScreen *screen = searchScreen(e->xcolormap.window);
399 screen->setRootColormapInstalled((e->xcolormap.state ==
400 ColormapInstalled) ? True : False);
405 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
407 if (e
.detail
!= NotifyNonlinear
&&
408 e
.detail
!= NotifyAncestor
) {
410 don't process FocusIns when:
411 1. the new focus window isn't an ancestor or inferior of the old
412 focus window (NotifyNonlinear)
413 make sure to allow the FocusIn when the old focus window was an
414 ancestor but didn't have a parent, such as root (NotifyAncestor)
419 BlackboxWindow *win = searchWindow(e.window);
421 if (! win->isFocused())
422 win->setFocusFlag(True);
425 set the event window to None. when the FocusOut event handler calls
426 this function recursively, it uses this as an indication that focus
427 has moved to a known window.
430 e->xfocus.window = None;
432 no_focus = False; // focusing is back on
438 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
440 if (e
.detail
!= NotifyNonlinear
) {
442 don't process FocusOuts when:
443 2. the new focus window isn't an ancestor or inferior of the old
444 focus window (NotifyNonlinear)
450 BlackboxWindow *win = searchWindow(e->xfocus.window);
451 if (win && win->isFocused()) {
454 before we mark "win" as unfocused, we need to verify that focus is
455 going to a known location, is in a known location, or set focus
460 // don't check the current focus if FocusOut was generated during a grab
461 bool check_focus = (e->xfocus.mode == NotifyNormal);
464 First, check if there is a pending FocusIn event waiting. if there
465 is, process it and determine if focus has moved to another window
466 (the FocusIn event handler sets the window in the event
467 structure to None to indicate this).
470 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
472 process_event(&event);
473 if (event.xfocus.window == None) {
482 Second, we query the X server for the current input focus.
483 to make sure that we keep a consistent state.
486 BlackboxWindow *focus;
489 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
490 focus = searchWindow(w);
494 focus got from "win" to "focus" under some very strange
495 circumstances, and we need to make sure that the focus indication
499 setFocusedWindow(focus);
501 // we have no idea where focus went... so we set it to somewhere
511 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
513 printf("ShapeEvent\n");
514 if (e
.kind
!= ShapeBounding
) return;
516 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
520 client
->frame
->update();
525 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
530 } else if (e->xclient.message_type ==
531 xatom->getAtom(XAtom::blackbox_change_workspace) ||
532 e->xclient.message_type ==
533 xatom->getAtom(XAtom::net_current_desktop)) {
534 // NET_CURRENT_DESKTOP message
535 BScreen *screen = searchScreen(e->xclient.window);
537 unsigned int workspace = e->xclient.data.l[0];
538 if (screen && workspace < screen->getWorkspaceCount())
539 screen->changeWorkspaceID(workspace);
540 } else if (e->xclient.message_type ==
541 xatom->getAtom(XAtom::net_active_window)) {
543 BlackboxWindow *win = searchWindow(e->xclient.window);
546 BScreen *screen = win->getScreen();
549 win->deiconify(False, False);
550 if (! win->isStuck() &&
551 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
553 screen->changeWorkspaceID(win->getWorkspaceNumber());
555 if (win->isVisible() && win->setInputFocus()) {
556 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
558 win->installColormap(True);
561 } else if (e->xclient.message_type ==
562 xatom->getAtom(XAtom::net_number_of_desktops)) {
563 // NET_NUMBER_OF_DESKTOPS
564 BScreen *screen = searchScreen(e->xclient.window);
566 if (e->xclient.data.l[0] > 0)
567 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
568 } else if (e->xclient.message_type ==
569 xatom->getAtom(XAtom::net_close_window)) {
571 BlackboxWindow *win = searchWindow(e->xclient.window);
572 if (win && win->validateClient())
573 win->close(); // could this be smarter?
574 } else if (e->xclient.message_type ==
575 xatom->getAtom(XAtom::net_wm_moveresize)) {
577 BlackboxWindow *win = searchWindow(e->xclient.window);
578 if (win && win->validateClient()) {
579 int x_root = e->xclient.data.l[0],
580 y_root = e->xclient.data.l[1];
581 if ((Atom) e->xclient.data.l[2] ==
582 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
583 win->beginMove(x_root, y_root);
585 if ((Atom) e->xclient.data.l[2] ==
586 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
587 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
588 else if ((Atom) e->xclient.data.l[2] ==
589 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
590 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
591 else if ((Atom) e->xclient.data.l[2] ==
592 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
593 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
594 else if ((Atom) e->xclient.data.l[2] ==
595 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
596 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
604 void OBXEventHandler::handle(const XEvent
&e
)
606 /* mouse button events can get translated into:
607 press - button was pressed down
608 release - buttons was released
609 click - button was pressed and released on the same window
610 double click - clicked twice on the same widget in a given time and area
612 key events are only bindable to presses. key releases are ignored.
614 mouse enter/leave can be bound to for the entire window
619 // These types of XEvent's can be bound to actions by the user, and so end
620 // up getting passed off to the OBBindingMapper class at some point
621 // IOW: THESE WILL HAVE GUILE HOOKS
623 buttonPress(e
.xbutton
);
626 buttonRelease(e
.xbutton
);
635 enterNotify(e
.xcrossing
);
638 leaveNotify(e
.xcrossing
);
642 // These types of XEvent's can not be bound to actions by the user and so
643 // will simply be handled in this class
644 case ConfigureRequest
:
645 configureRequest(e
.xconfigurerequest
);
649 mapRequest(e
.xmaprequest
);
653 unmapNotify(e
.xunmap
);
657 destroyNotify(e
.xdestroywindow
);
661 reparentNotify(e
.xreparent
);
665 propertyNotify(e
.xproperty
);
673 colormapNotify(e
.xcolormap
);
685 clientMessage(e
.xclient
);
689 if (e
.type
== otk::OBDisplay::shapeEventBase())
690 shapeEvent((*(XShapeEvent
*)&e
));
695 case ClientMessage: {