1 // -*- mode: C++; indent-tabs-mode: nil; -*-
3 #include "xeventhandler.hh"
6 #include "otk/display.hh"
11 #include <X11/Xutil.h>
17 OBXEventHandler::OBXEventHandler()
19 _lasttime
= 1; // 0 is CurrentTime, so set to minimum
22 void OBXEventHandler::buttonPress(const XButtonEvent
&e
)
29 void OBXEventHandler::buttonRelease(const XButtonEvent
&e
)
36 void OBXEventHandler::keyPress(const XKeyEvent
&e
)
42 void OBXEventHandler::motion(const XMotionEvent
&e
)
46 // the pointer is on the wrong screen
47 if (! e
.same_screen
) return;
52 void OBXEventHandler::enterNotify(const XCrossingEvent
&e
)
56 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
60 BScreen *screen = (BScreen *) 0;
61 BlackboxWindow *win = (BlackboxWindow *) 0;
63 if (e->xcrossing.mode == NotifyGrab) break;
65 if ((e->xcrossing.window == e->xcrossing.root) &&
66 (screen = searchScreen(e->xcrossing.window))) {
67 screen->getImageControl()->installRootColormap();
68 } else if ((win = searchWindow(e->xcrossing.window))) {
70 win->enterNotifyEvent(&e->xcrossing);
76 void OBXEventHandler::leaveNotify(const XCrossingEvent
&e
)
80 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
84 BlackboxWindow *win = (BlackboxWindow *) 0;
86 if ((win = searchWindow(e->xcrossing.window)))
87 win->leaveNotifyEvent(&e->xcrossing);
92 void OBXEventHandler::configureRequest(const XConfigureRequestEvent
&e
)
94 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
97 /* BlackboxWindow *win = (BlackboxWindow *) 0;
99 if ((win = searchWindow(e->xconfigurerequest.window))) {
100 win->configureRequestEvent(&e->xconfigurerequest);
102 if (validateWindow(e->xconfigurerequest.window)) {
105 xwc.x = e->xconfigurerequest.x;
106 xwc.y = e->xconfigurerequest.y;
107 xwc.width = e->xconfigurerequest.width;
108 xwc.height = e->xconfigurerequest.height;
109 xwc.border_width = e->xconfigurerequest.border_width;
110 xwc.sibling = e->xconfigurerequest.above;
111 xwc.stack_mode = e->xconfigurerequest.detail;
113 XConfigureWindow(otk::OBDisplay::display, e->xconfigurerequest.window,
114 e->xconfigurerequest.value_mask, &xwc);
121 // XXX: put this into the OBScreen or OBClient class!
122 static void manageWindow(Window window
)
124 OBClient
*client
= 0;
126 XSetWindowAttributes attrib_set
;
128 // XXX: manage the window, i.e. grab events n shit
130 // is the window a docking app
131 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
132 if ((wmhint
->flags
& StateHint
) &&
133 wmhint
->initial_state
== WithdrawnState
) {
134 //slit->addClient(w); // XXX: make dock apps work!
141 // choose the events we want to receive on the CLIENT window
142 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
144 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
146 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
147 CWEventMask
|CWDontPropagate
, &attrib_set
);
149 // create the OBClient class, which gets all of the hints on the window
150 Openbox::instance
->addClient(window
, client
= new OBClient(window
));
152 // we dont want a border on the client
153 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
155 // specify that if we exit, the window should not be destroyed and should be
156 // reparented back to root automatically
157 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
159 if (!client
->positionRequested()) {
160 // XXX: position the window intelligenty
163 // XXX: grab server, reparent client to the frame, ungrab server
165 // XXX: if shaped, shape the frame..
167 // XXX: if on the current desktop..
168 /// XMapSubwindows(otk::OBDisplay::display, FRAMEWINDOW);
169 XMapWindow(otk::OBDisplay::display
, window
);
171 // XXX: handle any requested states such as shaded/maximized
174 // XXX: move this to the OBScreen or OBClient class!
175 static void unmanageWindow(OBClient
*client
)
177 bool remap
= false; // remap the window when we're done?
179 Window window
= client
->window();
181 // XXX: pass around focus if this window was focused
183 // remove the window from our save set
184 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeDelete
);
186 // we dont want events no more
187 XSelectInput(otk::OBDisplay::display
, window
, NoEventMask
);
189 // XXX: XUnmapWindow(otk::OBDisplay::display, FRAME);
190 XUnmapWindow(otk::OBDisplay::display
, window
);
192 // we dont want a border on the client
193 XSetWindowBorderWidth(otk::OBDisplay::display
, window
,client
->borderWidth());
195 // remove the client class from the search list
196 Openbox::instance
->removeClient(window
);
198 // check if the app has already reparented its window to the root window
200 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, window
, ReparentNotify
,
202 remap
= true; // XXX: why do we remap the window if they already
203 // reparented to root?
205 // according to the ICCCM - if the client doesn't reparent to
206 // root, then we have to do it for them
207 XReparentWindow(otk::OBDisplay::display
, window
,
208 RootWindow(otk::OBDisplay::display
,
209 DefaultScreen(otk::OBDisplay::display
)),
210 // XXX: screen->getRootWindow(),
211 client
->area().x(), client
->area().y());
214 // if we want to remap the window, do so now
216 XMapWindow(otk::OBDisplay::display
, window
);
221 void OBXEventHandler::mapRequest(const XMapRequestEvent
&e
)
224 printf("MapRequest for 0x%lx\n", e
.window
);
227 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
230 // XXX: uniconify and/or unshade the window
232 manageWindow(e
.window
);
236 BlackboxWindow *win = searchWindow(e->xmaprequest.window);
240 if (win->isIconic()) {
244 if (win->isShaded()) {
249 if (focus && (win->isTransient() || win->getScreen()->doFocusNew()) &&
251 win->setInputFocus();
253 BScreen *screen = searchScreen(e->xmaprequest.parent);
258 we got a map request for a window who's parent isn't root. this
259 can happen in only one circumstance:
261 a client window unmapped a managed window, and then remapped it
262 somewhere between unmapping the client window and reparenting it
265 regardless of how it happens, we need to find the screen that
269 XWindowAttributes wattrib;
270 if (! XGetWindowAttributes(otk::OBDisplay::display,
271 e->xmaprequest.window,
273 // failed to get the window attributes, perhaps the window has
274 // now been destroyed?
278 screen = searchScreen(wattrib.root);
279 assert(screen != 0); // this should never happen
281 screen->manageWindow(e->xmaprequest.window);
287 void OBXEventHandler::unmapNotify(const XUnmapEvent
&e
)
289 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
292 unmanageWindow(client
);
296 void OBXEventHandler::destroyNotify(const XDestroyWindowEvent
&e
)
298 // XXX: window group leaders can come through here too!
300 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
303 unmanageWindow(client
);
307 void OBXEventHandler::reparentNotify(const XReparentEvent
&e
)
310 this event is quite rare and is usually handled in unmapNotify
311 however, if the window is unmapped when the reparent event occurs
312 the window manager never sees it because an unmap event is not sent
313 to an already unmapped window.
315 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
319 BlackboxWindow *win = searchWindow(e->xreparent.window);
321 win->reparentNotifyEvent(&e->xreparent);
326 void OBXEventHandler::propertyNotify(const XPropertyEvent
&e
)
330 OBClient
*client
= Openbox::instance
->findClient(e
.window
);
337 void OBXEventHandler::expose(const XExposeEvent
&first
)
339 OBClient
*client
= Openbox::instance
->findClient(first
.window
);
342 // compress expose events
343 XEvent e
; e
.xexpose
= first
;
345 otk::Rect
area(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
347 while (XCheckTypedWindowEvent(otk::OBDisplay::display
,
348 e
.xexpose
.window
, Expose
, &e
)) {
351 area
|= otk::Rect(e
.xexpose
.x
, e
.xexpose
.y
, e
.xexpose
.width
,
355 // use the merged area
356 e
.xexpose
.x
= area
.x();
357 e
.xexpose
.y
= area
.y();
358 e
.xexpose
.width
= area
.width();
359 e
.xexpose
.height
= area
.height();
362 // XXX: make the decorations redraw!
366 void OBXEventHandler::colormapNotify(const XColormapEvent
&e
)
370 BScreen *screen = searchScreen(e->xcolormap.window);
372 screen->setRootColormapInstalled((e->xcolormap.state ==
373 ColormapInstalled) ? True : False);
378 void OBXEventHandler::focusIn(const XFocusChangeEvent
&e
)
380 if (e
.detail
!= NotifyNonlinear
&&
381 e
.detail
!= NotifyAncestor
) {
383 don't process FocusIns when:
384 1. the new focus window isn't an ancestor or inferior of the old
385 focus window (NotifyNonlinear)
386 make sure to allow the FocusIn when the old focus window was an
387 ancestor but didn't have a parent, such as root (NotifyAncestor)
392 BlackboxWindow *win = searchWindow(e.window);
394 if (! win->isFocused())
395 win->setFocusFlag(True);
398 set the event window to None. when the FocusOut event handler calls
399 this function recursively, it uses this as an indication that focus
400 has moved to a known window.
403 e->xfocus.window = None;
405 no_focus = False; // focusing is back on
411 void OBXEventHandler::focusOut(const XFocusChangeEvent
&e
)
413 if (e
.detail
!= NotifyNonlinear
) {
415 don't process FocusOuts when:
416 2. the new focus window isn't an ancestor or inferior of the old
417 focus window (NotifyNonlinear)
423 BlackboxWindow *win = searchWindow(e->xfocus.window);
424 if (win && win->isFocused()) {
427 before we mark "win" as unfocused, we need to verify that focus is
428 going to a known location, is in a known location, or set focus
433 // don't check the current focus if FocusOut was generated during a grab
434 bool check_focus = (e->xfocus.mode == NotifyNormal);
437 First, check if there is a pending FocusIn event waiting. if there
438 is, process it and determine if focus has moved to another window
439 (the FocusIn event handler sets the window in the event
440 structure to None to indicate this).
443 if (XCheckTypedEvent(otk::OBDisplay::display, FocusIn, &event)) {
445 process_event(&event);
446 if (event.xfocus.window == None) {
455 Second, we query the X server for the current input focus.
456 to make sure that we keep a consistent state.
459 BlackboxWindow *focus;
462 XGetInputFocus(otk::OBDisplay::display, &w, &revert);
463 focus = searchWindow(w);
467 focus got from "win" to "focus" under some very strange
468 circumstances, and we need to make sure that the focus indication
472 setFocusedWindow(focus);
474 // we have no idea where focus went... so we set it to somewhere
484 void OBXEventHandler::shapeEvent(const XShapeEvent
&e
)
486 XShapeEvent
*shape_event
= (XShapeEvent
*) e
;
487 BlackboxWindow
*win
= searchWindow(e
->xany
.window
);
489 if (win
&& shape_event
->kind
== ShapeBounding
)
490 win
->shapeEvent(shape_event
);
495 void OBXEventHandler::clientMessage(const XClientMessageEvent
&e
)
500 } else if (e->xclient.message_type ==
501 xatom->getAtom(XAtom::blackbox_change_workspace) ||
502 e->xclient.message_type ==
503 xatom->getAtom(XAtom::net_current_desktop)) {
504 // NET_CURRENT_DESKTOP message
505 BScreen *screen = searchScreen(e->xclient.window);
507 unsigned int workspace = e->xclient.data.l[0];
508 if (screen && workspace < screen->getWorkspaceCount())
509 screen->changeWorkspaceID(workspace);
510 } else if (e->xclient.message_type ==
511 xatom->getAtom(XAtom::net_active_window)) {
513 BlackboxWindow *win = searchWindow(e->xclient.window);
516 BScreen *screen = win->getScreen();
519 win->deiconify(False, False);
520 if (! win->isStuck() &&
521 (win->getWorkspaceNumber() != screen->getCurrentWorkspaceID())) {
523 screen->changeWorkspaceID(win->getWorkspaceNumber());
525 if (win->isVisible() && win->setInputFocus()) {
526 win->getScreen()->getWorkspace(win->getWorkspaceNumber())->
528 win->installColormap(True);
531 } else if (e->xclient.message_type ==
532 xatom->getAtom(XAtom::net_number_of_desktops)) {
533 // NET_NUMBER_OF_DESKTOPS
534 BScreen *screen = searchScreen(e->xclient.window);
536 if (e->xclient.data.l[0] > 0)
537 screen->changeWorkspaceCount((unsigned) e->xclient.data.l[0]);
538 } else if (e->xclient.message_type ==
539 xatom->getAtom(XAtom::net_close_window)) {
541 BlackboxWindow *win = searchWindow(e->xclient.window);
542 if (win && win->validateClient())
543 win->close(); // could this be smarter?
544 } else if (e->xclient.message_type ==
545 xatom->getAtom(XAtom::net_wm_moveresize)) {
547 BlackboxWindow *win = searchWindow(e->xclient.window);
548 if (win && win->validateClient()) {
549 int x_root = e->xclient.data.l[0],
550 y_root = e->xclient.data.l[1];
551 if ((Atom) e->xclient.data.l[2] ==
552 xatom->getAtom(XAtom::net_wm_moveresize_move)) {
553 win->beginMove(x_root, y_root);
555 if ((Atom) e->xclient.data.l[2] ==
556 xatom->getAtom(XAtom::net_wm_moveresize_size_topleft))
557 win->beginResize(x_root, y_root, BlackboxWindow::TopLeft);
558 else if ((Atom) e->xclient.data.l[2] ==
559 xatom->getAtom(XAtom::net_wm_moveresize_size_topright))
560 win->beginResize(x_root, y_root, BlackboxWindow::TopRight);
561 else if ((Atom) e->xclient.data.l[2] ==
562 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomleft))
563 win->beginResize(x_root, y_root, BlackboxWindow::BottomLeft);
564 else if ((Atom) e->xclient.data.l[2] ==
565 xatom->getAtom(XAtom::net_wm_moveresize_size_bottomright))
566 win->beginResize(x_root, y_root, BlackboxWindow::BottomRight);
574 void OBXEventHandler::handle(const XEvent
&e
)
576 /* mouse button events can get translated into:
577 press - button was pressed down
578 release - buttons was released
579 click - button was pressed and released on the same window
580 double click - clicked twice on the same widget in a given time and area
582 key events are only bindable to presses. key releases are ignored.
584 mouse enter/leave can be bound to for the entire window
589 // These types of XEvent's can be bound to actions by the user, and so end
590 // up getting passed off to the OBBindingMapper class at some point
592 buttonPress(e
.xbutton
);
595 buttonRelease(e
.xbutton
);
604 enterNotify(e
.xcrossing
);
607 leaveNotify(e
.xcrossing
);
611 // These types of XEvent's can not be bound to actions by the user and so
612 // will simply be handled in this class
613 case ConfigureRequest
:
614 configureRequest(e
.xconfigurerequest
);
618 mapRequest(e
.xmaprequest
);
622 unmapNotify(e
.xunmap
);
626 destroyNotify(e
.xdestroywindow
);
630 reparentNotify(e
.xreparent
);
634 propertyNotify(e
.xproperty
);
642 colormapNotify(e
.xcolormap
);
654 clientMessage(e
.xclient
);
658 if (e
.type
== otk::OBDisplay::shapeEventBase())
664 case ClientMessage: {