openbox/otk/eventdispatcher.cc

217 lines
5.7 KiB
C++

// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#include "config.h"
#include "eventdispatcher.hh"
#include "display.hh"
#include <cstdio>
#include <iostream>
namespace otk {
EventDispatcher::EventDispatcher()
: _fallback(0), _master(0)
{
}
EventDispatcher::~EventDispatcher()
{
}
void EventDispatcher::clearAllHandlers(void)
{
_map.clear();
}
void EventDispatcher::registerHandler(Window id, EventHandler *handler)
{
_map.insert(std::pair<Window, EventHandler*>(id, handler));
}
void EventDispatcher::clearHandler(Window id)
{
_map.erase(id);
}
void EventDispatcher::dispatchEvents(bool remote)
{
XEvent e;
while (true) {
/*
There are slightly different event retrieval semantics here for local (or
high bandwidth) versus remote (or low bandwidth) connections to the
display/Xserver.
*/
if (remote) {
if (!XPending(**display))
return;
} else {
/*
This XSync allows for far more compression of events, which makes
things like Motion events perform far far better. Since it also means
network traffic for every event instead of every X events (where X is
the number retrieved at a time), it probably should not be used for
setups where Openbox is running on a remote/low bandwidth
display/Xserver.
*/
XSync(**display, false);
if (!XEventsQueued(**display, QueuedAlready))
return;
}
XNextEvent(**display, &e);
#if 0//defined(DEBUG)
printf("Event %d window %lx\n", e.type, e.xany.window);
#endif
if (e.type == FocusIn || e.type == FocusOut) {
// focus events are a beast all their own.. yuk, hate, etc.
dispatchFocus(e);
} else {
Window win;
// pick a window
switch (e.type) {
case UnmapNotify:
win = e.xunmap.window;
break;
case DestroyNotify:
win = e.xdestroywindow.window;
break;
case ConfigureRequest:
win = e.xconfigurerequest.window;
break;
default:
win = e.xany.window;
}
// grab the lasttime and hack up the modifiers
switch (e.type) {
case ButtonPress:
case ButtonRelease:
_lasttime = e.xbutton.time;
e.xbutton.state &= ~(LockMask | display->numLockMask() |
display->scrollLockMask());
break;
case KeyPress:
e.xkey.state &= ~(LockMask | display->numLockMask() |
display->scrollLockMask());
break;
case MotionNotify:
_lasttime = e.xmotion.time;
e.xmotion.state &= ~(LockMask | display->numLockMask() |
display->scrollLockMask());
break;
case PropertyNotify:
_lasttime = e.xproperty.time;
break;
case EnterNotify:
case LeaveNotify:
_lasttime = e.xcrossing.time;
if (e.xcrossing.mode != NotifyNormal)
continue; // skip me!
break;
}
dispatch(win, e);
}
}
}
void EventDispatcher::dispatchFocus(const XEvent &e)
{
// printf("focus %s detail %d -> 0x%lx\n",
// (e.xfocus.type == FocusIn ? "IN" : "OUT"),
// e.xfocus.detail, e.xfocus.window);
// ignore focus changes from grabs
if (e.xfocus.mode == NotifyGrab) //|| e.xfocus.mode == NotifyUngrab ||
// From Metacity, from WindowMaker, ignore all funky pointer root events
// its commented out cuz I don't think we need this at all. If problems
// arise we can look into it
//e.xfocus.detail > NotifyNonlinearVirtual)
return;
if (e.type == FocusIn) {
//printf("Got FocusIn!\n");
// send a FocusIn to whatever was just focused
dispatch(e.xfocus.window, e);
//printf("Sent FocusIn 0x%lx\n", e.xfocus.window);
} else if (e.type == FocusOut) {
//printf("Got FocusOut!\n");
// FocusOut events just make us look for FocusIn events. They are ignored
// otherwise.
XEvent fi;
if (XCheckTypedEvent(**display, FocusIn, &fi)) {
//printf("Found FocusIn\n");
dispatchFocus(fi);
// dont unfocus the window we just focused!
if (fi.xfocus.window == e.xfocus.window)
return;
}
dispatch(e.xfocus.window, e);
//printf("Sent FocusOut 0x%lx\n", e.xfocus.window);
}
}
void EventDispatcher::dispatch(Window win, const XEvent &e)
{
EventHandler *handler = 0;
EventMap::iterator it;
// master gets everything first
if (_master)
_master->handle(e);
// find handler for the chosen window
it = _map.find(win);
if (it != _map.end()) {
// if we found a handler
handler = it->second;
} else if (e.type == ConfigureRequest) {
// unhandled configure requests must be used to configure the window
// directly
XWindowChanges xwc;
xwc.x = e.xconfigurerequest.x;
xwc.y = e.xconfigurerequest.y;
xwc.width = e.xconfigurerequest.width;
xwc.height = e.xconfigurerequest.height;
xwc.border_width = e.xconfigurerequest.border_width;
xwc.sibling = e.xconfigurerequest.above;
xwc.stack_mode = e.xconfigurerequest.detail;
#ifdef DEBUG
printf("Proxying configure event for 0x%lx\n", e.xconfigurerequest.window);
#endif
// we are not to be held responsible if someone sends us an invalid
// request!
display->setIgnoreErrors(true);
XConfigureWindow(**display, e.xconfigurerequest.window,
e.xconfigurerequest.value_mask, &xwc);
display->setIgnoreErrors(false);
} else {
// grab a falback if it exists
handler = _fallback;
}
if (handler)
handler->handle(e);
}
EventHandler *EventDispatcher::findHandler(Window win)
{
EventMap::iterator it = _map.find(win);
if (it != _map.end())
return it->second;
return 0;
}
}