include the all otk stuff into the openbox python module. rename widget.hh to stop...
[mikachu/openbox.git] / src / actions.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 #include "actions.hh"
8 #include "widgetbase.hh"
9 #include "openbox.hh"
10 #include "client.hh"
11 #include "screen.hh"
12 #include "python.hh"
13 #include "bindings.hh"
14 #include "otk/display.hh"
15
16 #include <stdio.h>
17
18 namespace ob {
19
20 const int OBActions::BUTTONS;
21
22 OBActions::OBActions()
23   : _button(0)
24 {
25   for (int i=0; i<BUTTONS; ++i)
26     _posqueue[i] = new ButtonPressAction();
27 }
28
29
30 OBActions::~OBActions()
31 {
32   for (int i=0; i<BUTTONS; ++i)
33     delete _posqueue[i];
34 }
35
36
37 void OBActions::insertPress(const XButtonEvent &e)
38 {
39   ButtonPressAction *a = _posqueue[BUTTONS - 1];
40   for (int i=BUTTONS-1; i>0;)
41     _posqueue[i] = _posqueue[--i];
42   _posqueue[0] = a;
43   a->button = e.button;
44   a->pos.setPoint(e.x_root, e.y_root);
45
46   OBClient *c = Openbox::instance->findClient(e.window);
47   if (c) a->clientarea = c->area();
48 }
49
50 void OBActions::removePress(const XButtonEvent &e)
51 {
52   ButtonPressAction *a = 0;
53   for (int i=0; i<BUTTONS; ++i) {
54     if (_posqueue[i]->button == e.button)
55       a = _posqueue[i];
56     if (a) // found one and removed it
57       _posqueue[i] = _posqueue[i+1];
58   }
59   if (a) { // found one
60     _posqueue[BUTTONS-1] = a;
61     a->button = 0;
62   }
63 }
64
65 void OBActions::buttonPressHandler(const XButtonEvent &e)
66 {
67   OtkEventHandler::buttonPressHandler(e);
68   insertPress(e);
69   
70   // run the PRESS python hook
71   OBWidget *w = dynamic_cast<OBWidget*>
72     (Openbox::instance->findHandler(e.window));
73   assert(w); // everything should be a widget
74
75   // kill off the Button1Mask etc, only want the modifiers
76   unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
77                                   Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
78   int screen;
79   OBClient *c = Openbox::instance->findClient(e.window);
80   if (c)
81     screen = c->screen();
82   else
83     screen = otk::OBDisplay::findScreen(e.root)->screen();
84   MouseData data(screen, c, e.time, state, e.button, w->mcontext(),
85                  MousePress);
86   Openbox::instance->bindings()->fireButton(&data);
87     
88   if (_button) return; // won't count toward CLICK events
89
90   _button = e.button;
91 }
92   
93
94 void OBActions::buttonReleaseHandler(const XButtonEvent &e)
95 {
96   OtkEventHandler::buttonReleaseHandler(e);
97   removePress(e);
98   
99   OBWidget *w = dynamic_cast<OBWidget*>
100     (Openbox::instance->findHandler(e.window));
101   assert(w); // everything should be a widget
102
103   // not for the button we're watching?
104   if (_button != e.button) return;
105
106   _button = 0;
107
108   // find the area of the window
109   XWindowAttributes attr;
110   if (!XGetWindowAttributes(otk::OBDisplay::display, e.window, &attr)) return;
111
112   // if not on the window any more, it isnt a CLICK
113   if (!(e.same_screen && e.x >= 0 && e.y >= 0 &&
114         e.x < attr.width && e.y < attr.height))
115     return;
116
117   // run the CLICK python hook
118   // kill off the Button1Mask etc, only want the modifiers
119   unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
120                                   Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
121   int screen;
122   OBClient *c = Openbox::instance->findClient(e.window);
123   if (c)
124     screen = c->screen();
125   else
126     screen = otk::OBDisplay::findScreen(e.root)->screen();
127   MouseData data(screen, c, e.time, state, e.button, w->mcontext(),
128                  MouseClick);
129   Openbox::instance->bindings()->fireButton(&data);
130     
131
132   // XXX: dont load this every time!!@*
133   long dblclick;
134   if (!python_get_long("double_click_delay", &dblclick))
135     dblclick = 300;
136
137   if (e.time - _release.time < (unsigned)dblclick &&
138       _release.win == e.window && _release.button == e.button) {
139
140     // run the DOUBLECLICK python hook
141     data.action = MouseDoubleClick;
142     Openbox::instance->bindings()->fireButton(&data);
143     
144     // reset so you cant triple click for 2 doubleclicks
145     _release.win = 0;
146     _release.button = 0;
147     _release.time = 0;
148   } else {
149     // save the button release, might be part of a double click
150     _release.win = e.window;
151     _release.button = e.button;
152     _release.time = e.time;
153   }
154 }
155
156
157 void OBActions::enterHandler(const XCrossingEvent &e)
158 {
159   OtkEventHandler::enterHandler(e);
160   
161   // run the ENTER python hook
162   int screen;
163   OBClient *c = Openbox::instance->findClient(e.window);
164   if (c)
165     screen = c->screen();
166   else
167     screen = otk::OBDisplay::findScreen(e.root)->screen();
168   EventData data(screen, c, EventEnterWindow, e.state);
169   Openbox::instance->bindings()->fireEvent(&data);
170 }
171
172
173 void OBActions::leaveHandler(const XCrossingEvent &e)
174 {
175   OtkEventHandler::leaveHandler(e);
176
177   // run the LEAVE python hook
178   int screen;
179   OBClient *c = Openbox::instance->findClient(e.window);
180   if (c)
181     screen = c->screen();
182   else
183     screen = otk::OBDisplay::findScreen(e.root)->screen();
184   EventData data(screen, c, EventLeaveWindow, e.state);
185   Openbox::instance->bindings()->fireEvent(&data);
186 }
187
188
189 void OBActions::keyPressHandler(const XKeyEvent &e)
190 {
191   OtkEventHandler::keyPressHandler(e);
192
193   // kill off the Button1Mask etc, only want the modifiers
194   unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
195                                   Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
196   Openbox::instance->bindings()->
197     fireKey(otk::OBDisplay::findScreen(e.root)->screen(),
198             state, e.keycode, e.time);
199 }
200
201
202 void OBActions::motionHandler(const XMotionEvent &e)
203 {
204   OtkEventHandler::motionHandler(e);
205
206   if (!e.same_screen) return; // this just gets stupid
207
208   int x_root = e.x_root, y_root = e.y_root;
209   
210   // compress changes to a window into a single change
211   XEvent ce;
212   while (XCheckTypedEvent(otk::OBDisplay::display, e.type, &ce)) {
213     if (ce.xmotion.window != e.window) {
214       XPutBackEvent(otk::OBDisplay::display, &ce);
215       break;
216     } else {
217       x_root = e.x_root;
218       y_root = e.y_root;
219     }
220   }
221
222   OBWidget *w = dynamic_cast<OBWidget*>
223     (Openbox::instance->findHandler(e.window));
224   assert(w); // everything should be a widget
225
226   // run the MOTION python hook
227   // kill off the Button1Mask etc, only want the modifiers
228   unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
229                                   Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
230   unsigned int button = _posqueue[0]->button;
231   int screen;
232   OBClient *c = Openbox::instance->findClient(e.window);
233   if (c)
234     screen = c->screen();
235   else
236     screen = otk::OBDisplay::findScreen(e.root)->screen();
237   MouseData data(screen, c, e.time, state, button, w->mcontext(), MouseMotion,
238                  x_root, y_root, _posqueue[0]->pos, _posqueue[0]->clientarea);
239   Openbox::instance->bindings()->fireButton(&data);
240 }
241
242 void OBActions::mapRequestHandler(const XMapRequestEvent &e)
243 {
244   OtkEventHandler::mapRequestHandler(e);
245   // do this in OBScreen::manageWindow
246 }
247
248 void OBActions::unmapHandler(const XUnmapEvent &e)
249 {
250   OtkEventHandler::unmapHandler(e);
251   // do this in OBScreen::unmanageWindow
252 }
253
254 void OBActions::destroyHandler(const XDestroyWindowEvent &e)
255 {
256   OtkEventHandler::destroyHandler(e);
257   // do this in OBScreen::unmanageWindow
258 }
259
260 #ifdef    XKB
261 void OBActions::xkbHandler(const XkbEvent &e)
262 {
263   Window w;
264   int screen;
265   
266   OtkEventHandler::xkbHandler(e);
267
268   switch (((XkbAnyEvent*)&e)->xkb_type) {
269   case XkbBellNotify:
270     w = ((XkbBellNotifyEvent*)&e)->window;
271     OBClient *c = Openbox::instance->findClient(w);
272     if (c)
273       screen = c->screen();
274     else
275       screen = Openbox::instance->focusedScreen()->number();
276     EventData data(screen, c, EventBell, 0);
277     Openbox::instance->bindings()->fireEvent(&data);
278     break;
279   }
280 }
281 #endif // XKB
282
283 }
284