]> icculus.org git repositories - dana/openbox.git/blob - otk/eventdispatcher.cc
rm the python api docs
[dana/openbox.git] / otk / eventdispatcher.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #include "config.h"
4
5 #include "eventdispatcher.hh"
6 #include "display.hh"
7
8 #include <cstdio>
9 #include <iostream>
10
11 namespace otk {
12
13 EventDispatcher::EventDispatcher()
14   : _fallback(0), _master(0)
15 {
16 }
17
18 EventDispatcher::~EventDispatcher()
19 {
20 }
21
22 void EventDispatcher::clearAllHandlers(void)
23 {
24   _map.clear();
25 }
26
27 void EventDispatcher::registerHandler(Window id, EventHandler *handler)
28 {
29   _map.insert(std::pair<Window, EventHandler*>(id, handler));
30 }
31
32 void EventDispatcher::clearHandler(Window id)
33 {
34   _map.erase(id);
35 }
36
37 void EventDispatcher::dispatchEvents(bool remote)
38 {
39   XEvent e;
40
41   while (true) {
42     /*
43       There are slightly different event retrieval semantics here for local (or
44       high bandwidth) versus remote (or low bandwidth) connections to the
45       display/Xserver.
46     */
47     if (remote) {
48       if (!XPending(**display))
49         return;
50     } else {
51       /*
52         This XSync allows for far more compression of events, which makes
53         things like Motion events perform far far better. Since it also means
54         network traffic for every event instead of every X events (where X is
55         the number retrieved at a time), it probably should not be used for
56         setups where Openbox is running on a remote/low bandwidth
57         display/Xserver.
58       */
59       XSync(**display, false);
60       if (!XEventsQueued(**display, QueuedAlready))
61         return;
62     }
63     XNextEvent(**display, &e);
64
65 #if 0//defined(DEBUG)
66     printf("Event %d window %lx\n", e.type, e.xany.window);
67 #endif
68
69     if (e.type == FocusIn || e.type == FocusOut) {
70       // focus events are a beast all their own.. yuk, hate, etc.
71       dispatchFocus(e);
72     } else {    
73       Window win;
74
75       // pick a window
76       switch (e.type) {
77       case UnmapNotify:
78         win = e.xunmap.window;
79         break;
80       case DestroyNotify:
81         win = e.xdestroywindow.window;
82         break;
83       case ConfigureRequest:
84         win = e.xconfigurerequest.window;
85         break;
86       default:
87         win = e.xany.window;
88       }
89     
90       // grab the lasttime and hack up the modifiers
91       switch (e.type) {
92       case ButtonPress:
93       case ButtonRelease:
94         _lasttime = e.xbutton.time;
95         e.xbutton.state &= ~(LockMask | display->numLockMask() |
96                              display->scrollLockMask());
97         break;
98       case KeyPress:
99         e.xkey.state &= ~(LockMask | display->numLockMask() |
100                           display->scrollLockMask());
101         break;
102       case MotionNotify:
103         _lasttime = e.xmotion.time;
104         e.xmotion.state &= ~(LockMask | display->numLockMask() |
105                              display->scrollLockMask());
106         break;
107       case PropertyNotify:
108         _lasttime = e.xproperty.time;
109         break;
110       case EnterNotify:
111       case LeaveNotify:
112         _lasttime = e.xcrossing.time;
113         if (e.xcrossing.mode != NotifyNormal)
114           continue; // skip me!
115         break;
116       }
117
118       dispatch(win, e);
119     }
120   }
121 }
122
123 void EventDispatcher::dispatchFocus(const XEvent &e)
124 {
125 //  printf("focus %s detail %d -> 0x%lx\n",
126 //         (e.xfocus.type == FocusIn ? "IN" : "OUT"),
127 //         e.xfocus.detail, e.xfocus.window);
128   // ignore focus changes from grabs
129   if (e.xfocus.mode == NotifyGrab) //|| e.xfocus.mode == NotifyUngrab ||
130       // From Metacity, from WindowMaker, ignore all funky pointer root events
131       // its commented out cuz I don't think we need this at all. If problems
132       // arise we can look into it
133       //e.xfocus.detail > NotifyNonlinearVirtual)
134     return;
135   
136   if (e.type == FocusIn) {
137     //printf("Got FocusIn!\n");
138
139     // send a FocusIn to whatever was just focused
140     dispatch(e.xfocus.window, e);
141     //printf("Sent FocusIn 0x%lx\n", e.xfocus.window);
142
143   } else if (e.type == FocusOut) {
144     //printf("Got FocusOut!\n");
145
146     // FocusOut events just make us look for FocusIn events. They are ignored
147     // otherwise.
148     XEvent fi;
149     if (XCheckTypedEvent(**display, FocusIn, &fi)) {
150       //printf("Found FocusIn\n");
151       dispatchFocus(fi);
152       // dont unfocus the window we just focused!
153       if (fi.xfocus.window == e.xfocus.window)
154         return;
155     }
156
157     dispatch(e.xfocus.window, e);
158     //printf("Sent FocusOut 0x%lx\n", e.xfocus.window);
159   }
160 }
161
162 void EventDispatcher::dispatch(Window win, const XEvent &e)
163 {
164   EventHandler *handler = 0;
165   EventMap::iterator it;
166
167   // master gets everything first
168   if (_master)
169     _master->handle(e);
170
171   // find handler for the chosen window
172   it = _map.find(win);
173
174   if (it != _map.end()) {
175     // if we found a handler
176     handler = it->second;
177   } else if (e.type == ConfigureRequest) {
178     // unhandled configure requests must be used to configure the window
179     // directly
180     XWindowChanges xwc;
181       
182     xwc.x = e.xconfigurerequest.x;
183     xwc.y = e.xconfigurerequest.y;
184     xwc.width = e.xconfigurerequest.width;
185     xwc.height = e.xconfigurerequest.height;
186     xwc.border_width = e.xconfigurerequest.border_width;
187     xwc.sibling = e.xconfigurerequest.above;
188     xwc.stack_mode = e.xconfigurerequest.detail;
189     
190 #ifdef DEBUG
191     printf("Proxying configure event for 0x%lx\n", e.xconfigurerequest.window);
192 #endif
193     
194     // we are not to be held responsible if someone sends us an invalid
195     // request!
196     display->setIgnoreErrors(true); 
197     XConfigureWindow(**display, e.xconfigurerequest.window,
198                      e.xconfigurerequest.value_mask, &xwc);
199     display->setIgnoreErrors(false);
200   } else {
201     // grab a falback if it exists
202     handler = _fallback;
203   }
204
205   if (handler)
206     handler->handle(e);
207 }
208
209 EventHandler *EventDispatcher::findHandler(Window win)
210 {
211   EventMap::iterator it = _map.find(win);
212   if (it != _map.end())
213     return it->second;
214   return 0;
215 }
216
217 }