00001
00002
00003 #ifdef HAVE_CONFIG_H
00004 # include "../config.h"
00005 #endif
00006
00007 #include "actions.hh"
00008 #include "widgetbase.hh"
00009 #include "openbox.hh"
00010 #include "client.hh"
00011 #include "screen.hh"
00012 #include "python.hh"
00013 #include "bindings.hh"
00014 #include "otk/display.hh"
00015
00016 #include <stdio.h>
00017 #include <algorithm>
00018
00019 namespace ob {
00020
00021 const int Actions::BUTTONS;
00022
00023 Actions::Actions()
00024 : _button(0),
00025 _dragging(false)
00026 {
00027 for (int i=0; i<BUTTONS; ++i)
00028 _posqueue[i] = new ButtonPressAction();
00029 }
00030
00031
00032 Actions::~Actions()
00033 {
00034 for (int i=0; i<BUTTONS; ++i)
00035 delete _posqueue[i];
00036 }
00037
00038
00039 void Actions::insertPress(const XButtonEvent &e)
00040 {
00041 ButtonPressAction *a = _posqueue[BUTTONS - 1];
00042
00043 for (int i = BUTTONS-1; i > 0; --i) {
00044 _posqueue[i] = _posqueue[i-1];
00045 }
00046 _posqueue[0] = a;
00047 a->button = e.button;
00048 a->pos.setPoint(e.x_root, e.y_root);
00049
00050 Client *c = openbox->findClient(e.window);
00051 if (c) a->clientarea = c->area();
00052 }
00053
00054 void Actions::removePress(const XButtonEvent &e)
00055 {
00056 int i;
00057 ButtonPressAction *a = 0;
00058 for (i=0; i<BUTTONS-1; ++i)
00059 if (_posqueue[i]->button == e.button) {
00060 a = _posqueue[i];
00061 break;
00062 }
00063 if (a) {
00064 for (; i < BUTTONS-1; ++i)
00065 _posqueue[i] = _posqueue[i+1];
00066 _posqueue[BUTTONS-1] = a;
00067 }
00068 _posqueue[BUTTONS-1]->button = 0;
00069 }
00070
00071 void Actions::buttonPressHandler(const XButtonEvent &e)
00072 {
00073 otk::EventHandler::buttonPressHandler(e);
00074 insertPress(e);
00075
00076
00077 WidgetBase *w = dynamic_cast<WidgetBase*>
00078 (openbox->findHandler(e.window));
00079 if (!w) return;
00080
00081
00082 unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
00083 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
00084 int screen;
00085 Client *c = openbox->findClient(e.window);
00086 if (c)
00087 screen = c->screen();
00088 else
00089 screen = otk::display->findScreen(e.root)->screen();
00090 MouseData data(screen, c, e.time, state, e.button, w->mcontext(),
00091 MouseAction::Press);
00092 openbox->bindings()->fireButton(&data);
00093
00094 if (_button) return;
00095
00096 _button = e.button;
00097
00098 if (w->mcontext() == MouseContext::Window) {
00099
00100
00101
00102
00103
00104
00105
00106 buttonReleaseHandler(e);
00107 }
00108 }
00109
00110
00111 void Actions::buttonReleaseHandler(const XButtonEvent &e)
00112 {
00113 otk::EventHandler::buttonReleaseHandler(e);
00114 removePress(e);
00115
00116 WidgetBase *w = dynamic_cast<WidgetBase*>
00117 (openbox->findHandler(e.window));
00118 if (!w) return;
00119
00120
00121
00122 unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
00123 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
00124 int screen;
00125 Client *c = openbox->findClient(e.window);
00126 if (c)
00127 screen = c->screen();
00128 else
00129 screen = otk::display->findScreen(e.root)->screen();
00130 MouseData data(screen, c, e.time, state, e.button, w->mcontext(),
00131 MouseAction::Release);
00132 openbox->bindings()->fireButton(&data);
00133
00134
00135 if (_button != e.button) return;
00136
00137 _button = 0;
00138 _dragging = false;
00139
00140
00141 XWindowAttributes attr;
00142 if (!XGetWindowAttributes(**otk::display, e.window, &attr)) return;
00143
00144
00145 if (!(e.same_screen && e.x >= 0 && e.y >= 0 &&
00146 e.x < attr.width && e.y < attr.height))
00147 return;
00148
00149
00150 data.action = MouseAction::Click;
00151 openbox->bindings()->fireButton(&data);
00152
00153
00154
00155 long dblclick;
00156 if (!python_get_long("DOUBLE_CLICK_DELAY", &dblclick))
00157 dblclick = 300;
00158
00159 if (e.time - _release.time < (unsigned)dblclick &&
00160 _release.win == e.window && _release.button == e.button) {
00161
00162
00163 data.action = MouseAction::DoubleClick;
00164 openbox->bindings()->fireButton(&data);
00165
00166
00167 _release.win = 0;
00168 _release.button = 0;
00169 _release.time = 0;
00170 } else {
00171
00172 _release.win = e.window;
00173 _release.button = e.button;
00174 _release.time = e.time;
00175 }
00176 }
00177
00178
00179 void Actions::enterHandler(const XCrossingEvent &e)
00180 {
00181 otk::EventHandler::enterHandler(e);
00182
00183
00184 int screen;
00185 Client *c = openbox->findClient(e.window);
00186 if (c)
00187 screen = c->screen();
00188 else
00189 screen = otk::display->findScreen(e.root)->screen();
00190 EventData data(screen, c, EventAction::EnterWindow, e.state);
00191 openbox->bindings()->fireEvent(&data);
00192 }
00193
00194
00195 void Actions::leaveHandler(const XCrossingEvent &e)
00196 {
00197 otk::EventHandler::leaveHandler(e);
00198
00199
00200 int screen;
00201 Client *c = openbox->findClient(e.window);
00202 if (c)
00203 screen = c->screen();
00204 else
00205 screen = otk::display->findScreen(e.root)->screen();
00206 EventData data(screen, c, EventAction::LeaveWindow, e.state);
00207 openbox->bindings()->fireEvent(&data);
00208 }
00209
00210
00211 void Actions::keyPressHandler(const XKeyEvent &e)
00212 {
00213 otk::EventHandler::keyPressHandler(e);
00214
00215
00216 unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
00217 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
00218 openbox->bindings()->
00219 fireKey(otk::display->findScreen(e.root)->screen(),
00220 state, e.keycode, e.time, KeyAction::Press);
00221 }
00222
00223
00224 void Actions::keyReleaseHandler(const XKeyEvent &e)
00225 {
00226 otk::EventHandler::keyReleaseHandler(e);
00227
00228
00229 unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
00230 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
00231
00232
00233
00234 const XModifierKeymap *map = otk::display->modifierMap();
00235 const int mask_table[] = {
00236 ShiftMask, LockMask, ControlMask, Mod1Mask,
00237 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
00238 };
00239 KeyCode *kp = map->modifiermap;
00240 for (int i = 0, n = sizeof(mask_table)/sizeof(mask_table[0]); i < n; ++i) {
00241 for (int k = 0; k < map->max_keypermod; ++k) {
00242 if (*kp == e.keycode) {
00243 state &= ~mask_table[i];
00244 i = n;
00245 break;
00246 }
00247 ++kp;
00248 }
00249 }
00250
00251 openbox->bindings()->
00252 fireKey(otk::display->findScreen(e.root)->screen(),
00253 state, e.keycode, e.time, KeyAction::Release);
00254 }
00255
00256
00257 void Actions::motionHandler(const XMotionEvent &e)
00258 {
00259 otk::EventHandler::motionHandler(e);
00260
00261 if (!e.same_screen) return;
00262
00263 int x_root = e.x_root, y_root = e.y_root;
00264
00265
00266 XEvent ce;
00267 while (XCheckTypedEvent(**otk::display, e.type, &ce)) {
00268 if (ce.xmotion.window != e.window) {
00269 XPutBackEvent(**otk::display, &ce);
00270 break;
00271 } else {
00272 x_root = e.x_root;
00273 y_root = e.y_root;
00274 }
00275 }
00276
00277 WidgetBase *w = dynamic_cast<WidgetBase*>
00278 (openbox->findHandler(e.window));
00279 if (!w) return;
00280
00281 if (!_dragging) {
00282 long threshold;
00283 int dx = x_root - _posqueue[0]->pos.x();
00284 int dy = y_root - _posqueue[0]->pos.y();
00285
00286 if (!python_get_long("DRAG_THRESHOLD", &threshold))
00287 threshold = 0;
00288 if (!(std::abs(dx) >= threshold || std::abs(dy) >= threshold))
00289 return;
00290 }
00291 _dragging = true;
00292
00293
00294
00295
00296
00297 unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
00298 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
00299 unsigned int button = _posqueue[0]->button;
00300 int screen;
00301 Client *c = openbox->findClient(e.window);
00302 if (c)
00303 screen = c->screen();
00304 else
00305 screen = otk::display->findScreen(e.root)->screen();
00306 MouseData data(screen, c, e.time, state, button, w->mcontext(),
00307 MouseAction::Motion, x_root, y_root,
00308 _posqueue[0]->pos, _posqueue[0]->clientarea);
00309 openbox->bindings()->fireButton(&data);
00310 }
00311
00312 #ifdef XKB
00313 void Actions::xkbHandler(const XkbEvent &e)
00314 {
00315 Window w;
00316 int screen;
00317
00318 otk::EventHandler::xkbHandler(e);
00319
00320 switch (((XkbAnyEvent*)&e)->xkb_type) {
00321 case XkbBellNotify:
00322 w = ((XkbBellNotifyEvent*)&e)->window;
00323 Client *c = openbox->findClient(w);
00324 if (c)
00325 screen = c->screen();
00326 else
00327 screen = openbox->focusedScreen()->number();
00328 EventData data(screen, c, EventAction::Bell, 0);
00329 openbox->bindings()->fireEvent(&data);
00330 break;
00331 }
00332 }
00333 #endif // XKB
00334
00335 }
00336