1 // -*- mode: C++; indent-tabs-mode: nil; -*-
3 #include "xeventhandler.hh"
7 #include "otk/display.hh"
10 // XXX: REMOVE THIS SOON!!#!
11 #include "blackbox.hh"
16 #include <X11/Xutil.h>
22 OBXEventHandler::OBXEventHandler()
24 _lasttime
= 1; // 0 is CurrentTime, so set to minimum
27 void OBXEventHandler::buttonPress(const XButtonEvent
&e
)
34 void OBXEventHandler::buttonRelease(const XButtonEvent
&e
)
41 void OBXEventHandler::keyPress(const XKeyEvent
&e
)
47 void OBXEventHandler::motion(const XMotionEvent
&e
)
51 // the pointer is on the wrong screen
52 if (! e
.same_screen
) return;
57 void OBXEventHandler::enterNotify(const XCrossingEvent
&e
)
61 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
65 BScreen *screen = (BScreen *) 0;
66 BlackboxWindow *win = (BlackboxWindow *) 0;
68 if (e->xcrossing.mode == NotifyGrab) break;
70 if ((e->xcrossing.window == e->xcrossing.root) &&
71 (screen = searchScreen(e->xcrossing.window))) {
72 screen->getImageControl()->installRootColormap();
73 } else if ((win = searchWindow(e->xcrossing.window))) {
75 win->enterNotifyEvent(&e->xcrossing);
81 void OBXEventHandler::leaveNotify(const XCrossingEvent
&e
)
85 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
89 BlackboxWindow *win = (BlackboxWindow *) 0;
91 if ((win = searchWindow(e->xcrossing.window)))
92 win->leaveNotifyEvent(&e->xcrossing);
97 void OBXEventHandler::configureRequest(const XConfigureRequestEvent
&e
)
99 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
102 /* BlackboxWindow *win = (BlackboxWindow *) 0;
104 if ((win = searchWindow(e->xconfigurerequest.window))) {
105 win->configureRequestEvent(&e->xconfigurerequest);
107 if (validateWindow(e->xconfigurerequest.window)) {
110 xwc.x = e->xconfigurerequest.x;
111 xwc.y = e->xconfigurerequest.y;
112 xwc.width = e->xconfigurerequest.width;
113 xwc.height = e->xconfigurerequest.height;
114 xwc.border_width = e->xconfigurerequest.border_width;
115 xwc.sibling = e->xconfigurerequest.above;
116 xwc.stack_mode = e->xconfigurerequest.detail;
118 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
119 e->xconfigurerequest.value_mask, &xwc);
126 // XXX: put this into the OBScreen or OBClient class!
127 static void manageWindow(int screen
, Window window
)
129 OBClient
*client
= 0;
131 XSetWindowAttributes attrib_set
;
133 // XXX: manage the window, i.e. grab events n shit
135 // is the window a docking app
136 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
137 if ((wmhint
->flags
& StateHint
) &&
138 wmhint
->initial_state
== WithdrawnState
) {
139 //slit->addClient(w); // XXX: make dock apps work!
146 // choose the events we want to receive on the CLIENT window
147 attrib_set
.event_mask
= OBClient::event_mask
;
148 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
150 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
151 CWEventMask
|CWDontPropagate
, &attrib_set
);
153 // create the OBClient class, which gets all of the hints on the window
154 Openbox::instance
->addClient(window
, client
= new OBClient(screen
, window
));
156 // we dont want a border on the client
157 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
159 // specify that if we exit, the window should not be destroyed and should be
160 // reparented back to root automatically
161 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
163 if (!client
->positionRequested()) {
164 // XXX: position the window intelligenty
167 // XXX: store a style somewheres cooler!!
168 otk::Style
*style
= ((Blackbox
*)Openbox::instance
)->
169 searchScreen(RootWindow(otk::OBDisplay::display
, screen
))->
171 client
->frame
= new OBFrame(client
, style
);
173 // XXX: if on the current desktop..
174 XMapWindow(otk::OBDisplay::display
, client
->frame
->window());
176 // XXX: handle any requested states such as shaded/maximized
179 // XXX: move this to the OBScreen or OBClient class!
180 static void unmanageWindow(OBClient
*client
)
182 OBFrame
*frame
= client
->frame
;
184 // XXX: pass around focus if this window was focused
186 // remove the window from our save set
187 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
189 // we dont want events no more
190 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
192 XUnmapWindow(otk::OBDisplay::display
, frame
->window());
194 // we dont want a border on the client
195 XSetWindowBorderWidth(otk::OBDisplay::display
, client
->window(),
196 client
->borderWidth());
198 // remove the client class from the search list
199 Openbox::instance
->removeClient(client
->window());
201 delete client
->frame
;
207 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
210 printf("MapRequest for 0x%lx\n", e
.window
);
213 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
216 // XXX: uniconify and/or unshade the window
218 int screen
= INT_MAX
;
220 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
221 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == e
.parent
) {
226 if (screen
>= ScreenCount(otk::OBDisplay::display
)) {
228 we got a map request for a window who's parent isn't root. this
229 can happen in only one circumstance:
231 a client window unmapped a managed window, and then remapped it
232 somewhere between unmapping the client window and reparenting it
235 regardless of how it happens, we need to find the screen that
238 XWindowAttributes wattrib
;
239 if (! XGetWindowAttributes(otk::OBDisplay::display
, e
.window
,
241 // failed to get the window attributes, perhaps the window has
242 // now been destroyed?
246 for (int i
= 0; i
< ScreenCount(otk::OBDisplay::display
); ++i
)
247 if (otk::OBDisplay::screenInfo(i
)->getRootWindow() == wattrib
.root
) {
253 assert(screen
< ScreenCount(otk::OBDisplay::display
));
255 manageWindow(screen
, e
.window
);
259 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
263 if (win->isIconic()) {
267 if (win->isShaded()) {
272 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
274 win->setInputFocus();
276 BScreen *screen = searchScreen(e->xmaprequest.parent);
281 we got a map request for a window who's parent isn't root. this
282 can happen in only one circumstance:
284 a client window unmapped a managed window, and then remapped it
285 somewhere between unmapping the client window and reparenting it
288 regardless of how it happens, we need to find the screen that
292 XWindowAttributes wattrib;
293 if (! XGetWindowAttributes(otk::OBDisplay::display,
294 e->xmaprequest.window,
296 // failed to get the window attributes, perhaps the window has
297 // now been destroyed?
301 screen = searchScreen(wattrib.root);
302 assert(screen != 0); // this should never happen
304 screen->manageWindow(e->xmaprequest.window);
310 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
312 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
315 unmanageWindow(client
);
319 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
321 // XXX: window group leaders can come through here too!
323 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
326 unmanageWindow(client
);
330 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
333 this event is quite rare and is usually handled in unmapNotify
334 however, if the window is unmapped when the reparent event occurs
335 the window manager never sees it because an unmap event is not sent
336 to an already unmapped window.
338 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
342 BlackboxWindow *win = searchWindow(e->xreparent.window);
344 win->reparentNotifyEvent(&e->xreparent);
349 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
353 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
360 void OBXEventHandler::expose(const XExposeEvent
&first
)
362 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
365 // compress expose events
366 XEvent e
; e
.xexpose
= first
;
368 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
370 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
371 e
.xexpose
.window
, Expose
, &e
)) {
374 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
378 // use the merged area
379 e
.xexpose
.x
= area
.x();
380 e
.xexpose
.y
= area
.y();
381 e
.xexpose
.width
= area
.width();
382 e
.xexpose
.height
= area
.height();
385 // XXX: make the decorations redraw!
389 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
393 BScreen *screen = searchScreen(e->xcolormap.window);
395 screen->setRootColormapInstalled((e->xcolormap.state ==
396 ColormapInstalled) ? True : False);
401 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
403 if (e
.detail
!= NotifyNonlinear
&&
404 e
.detail
!= NotifyAncestor
) {
406 don't process FocusIns when:
407 1. the new focus window isn't an ancestor or inferior of the old
408 focus window (NotifyNonlinear)
409 make sure to allow the FocusIn when the old focus window was an
410 ancestor but didn't have a parent, such as root (NotifyAncestor)
415 BlackboxWindow *win = searchWindow(e.window);
417 if (! win->isFocused())
418 win->setFocusFlag(True);
421 set the event window to None. when the FocusOut event handler calls
422 this function recursively, it uses this as an indication that focus
423 has moved to a known window.
426 e->xfocus.window = None;
428 no_focus = False; // focusing is back on
434 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
436 if (e
.detail
!= NotifyNonlinear
) {
438 don't process FocusOuts when:
439 2. the new focus window isn't an ancestor or inferior of the old
440 focus window (NotifyNonlinear)
446 BlackboxWindow *win = searchWindow(e->xfocus.window);
447 if (win && win->isFocused()) {
450 before we mark "win" as unfocused, we need to verify that focus is
451 going to a known location, is in a known location, or set focus
456 // don't check the current focus if FocusOut was generated during a grab
457 bool check_focus = (e->xfocus.mode == NotifyNormal);
460 First, check if there is a pending FocusIn event waiting. if there
461 is, process it and determine if focus has moved to another window
462 (the FocusIn event handler sets the window in the event
463 structure to None to indicate this).
466 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
468 process_event(&event);
469 if (event.xfocus.window == None) {
478 Second, we query the X server for the current input focus.
479 to make sure that we keep a consistent state.
482 BlackboxWindow *focus;
485 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
486 focus = searchWindow(w);
490 focus got from "win" to "focus" under some very strange
491 circumstances, and we need to make sure that the focus indication
495 setFocusedWindow(focus);
497 // we have no idea where focus went... so we set it to somewhere
507 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
509 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
510 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
512 if (win
&& shape_event
->kind
== ShapeBounding
)
513 win
->shapeEvent(shape_event
);
518 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
523 } else if (e->xclient.message_type ==
524 xatom->getAtom(XAtom::blackbox_change_workspace) ||
525 e->xclient.message_type ==
526 xatom->getAtom(XAtom::net_current_desktop)) {
527 // NET_CURRENT_DESKTOP message
528 BScreen *screen = searchScreen(e->xclient.window);
530 unsigned int workspace = e->xclient.data.l[0];
531 if (screen && workspace < screen->getWorkspaceCount())
532 screen->changeWorkspaceID(workspace);
533 } else if (e->xclient.message_type ==
534 xatom->getAtom(XAtom::net_active_window)) {
536 BlackboxWindow *win = searchWindow(e->xclient.window);
539 BScreen *screen = win->getScreen();
542 win->deiconify(False, False);
543 if (! win->isStuck() &&
544 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
546 screen->changeWorkspaceID(win->getWorkspaceNumber());
548 if (win->isVisible() && win->setInputFocus()) {
549 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
551 win->installColormap(True);
554 } else if (e->xclient.message_type ==
555 xatom->getAtom(XAtom::net_number_of_desktops)) {
556 // NET_NUMBER_OF_DESKTOPS
557 BScreen *screen = searchScreen(e->xclient.window);
559 if (e->xclient.data.l[0] > 0)
560 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
561 } else if (e->xclient.message_type ==
562 xatom->getAtom(XAtom::net_close_window)) {
564 BlackboxWindow *win = searchWindow(e->xclient.window);
565 if (win && win->validateClient())
566 win->close(); // could this be smarter?
567 } else if (e->xclient.message_type ==
568 xatom->getAtom(XAtom::net_wm_moveresize)) {
570 BlackboxWindow *win = searchWindow(e->xclient.window);
571 if (win && win->validateClient()) {
572 int x_root = e->xclient.data.l[0],
573 y_root = e->xclient.data.l[1];
574 if ((Atom) e->xclient.data.l[2] ==
575 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
576 win->beginMove(x_root, y_root);
578 if ((Atom) e->xclient.data.l[2] ==
579 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
580 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
581 else if ((Atom) e->xclient.data.l[2] ==
582 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
583 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
584 else if ((Atom) e->xclient.data.l[2] ==
585 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
586 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
587 else if ((Atom) e->xclient.data.l[2] ==
588 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
589 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
597 void OBXEventHandler::handle(const XEvent
&e
)
599 /* mouse button events can get translated into:
600 press - button was pressed down
601 release - buttons was released
602 click - button was pressed and released on the same window
603 double click - clicked twice on the same widget in a given time and area
605 key events are only bindable to presses. key releases are ignored.
607 mouse enter/leave can be bound to for the entire window
612 // These types of XEvent's can be bound to actions by the user, and so end
613 // up getting passed off to the OBBindingMapper class at some point
615 buttonPress(e
.xbutton
);
618 buttonRelease(e
.xbutton
);
627 enterNotify(e
.xcrossing
);
630 leaveNotify(e
.xcrossing
);
634 // These types of XEvent's can not be bound to actions by the user and so
635 // will simply be handled in this class
636 case ConfigureRequest
:
637 configureRequest(e
.xconfigurerequest
);
641 mapRequest(e
.xmaprequest
);
645 unmapNotify(e
.xunmap
);
649 destroyNotify(e
.xdestroywindow
);
653 reparentNotify(e
.xreparent
);
657 propertyNotify(e
.xproperty
);
665 colormapNotify(e
.xcolormap
);
677 clientMessage(e
.xclient
);
681 if (e
.type
== otk::OBDisplay::shapeEventBase())
687 case ClientMessage: {