Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

/src/actions.cc

Go to the documentation of this file.
00001 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
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   // rm'd the last one, shift them all down one
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) { // found one, remove it and shift the rest up one
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   // run the PRESS python hook
00077   WidgetBase *w = dynamic_cast<WidgetBase*>
00078     (openbox->findHandler(e.window));
00079   if (!w) return;
00080 
00081   // kill off the Button1Mask etc, only want the modifiers
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; // won't count toward CLICK events
00095 
00096   _button = e.button;
00097 
00098   if (w->mcontext() == MouseContext::Window) {
00099     /*
00100       Because of how events are grabbed on the client window, we can't get
00101       ButtonRelease events, so instead we simply manufacture them here, so that
00102       clicks/doubleclicks etc still work.
00103     */
00104     //XButtonEvent ev = e;
00105     //ev.type = ButtonRelease;
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   // run the RELEASE python hook
00121   // kill off the Button1Mask etc, only want the modifiers
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   // not for the button we're watching?
00135   if (_button != e.button) return;
00136 
00137   _button = 0;
00138   _dragging = false;
00139 
00140   // find the area of the window
00141   XWindowAttributes attr;
00142   if (!XGetWindowAttributes(**otk::display, e.window, &attr)) return;
00143 
00144   // if not on the window any more, it isnt a CLICK
00145   if (!(e.same_screen && e.x >= 0 && e.y >= 0 &&
00146         e.x < attr.width && e.y < attr.height))
00147     return;
00148 
00149   // run the CLICK python hook
00150   data.action = MouseAction::Click;
00151   openbox->bindings()->fireButton(&data);
00152     
00153 
00154   // XXX: dont load this every time!!@*
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     // run the DOUBLECLICK python hook
00163     data.action = MouseAction::DoubleClick;
00164     openbox->bindings()->fireButton(&data);
00165     
00166     // reset so you cant triple click for 2 doubleclicks
00167     _release.win = 0;
00168     _release.button = 0;
00169     _release.time = 0;
00170   } else {
00171     // save the button release, might be part of a double click
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   // run the ENTER python hook
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   // run the LEAVE python hook
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   // kill off the Button1Mask etc, only want the modifiers
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   // kill off the Button1Mask etc, only want the modifiers
00229   unsigned int state = e.state & (ControlMask | ShiftMask | Mod1Mask |
00230                                   Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
00231 
00232   // remove from the state the mask of the modifier being released, if it is
00233   // a modifier key being released (this is a little ugly..)
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) { // found the keycode
00243         state &= ~mask_table[i]; // remove the mask for it
00244         i = n; // cause the first loop to break;
00245         break; // get outta here!
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; // this just gets stupid
00262 
00263   int x_root = e.x_root, y_root = e.y_root;
00264   
00265   // compress changes to a window into a single change
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     // XXX: dont get this from python every time!
00286     if (!python_get_long("DRAG_THRESHOLD", &threshold))
00287       threshold = 0;
00288     if (!(std::abs(dx) >= threshold || std::abs(dy) >= threshold))
00289       return; // not at the threshold yet
00290   }
00291   _dragging = true; // in a drag now
00292   
00293   // check if the movement is more than the threshold
00294 
00295   // run the MOTION python hook
00296   // kill off the Button1Mask etc, only want the modifiers
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 

Generated on Tue Feb 4 22:58:57 2003 for Openbox by doxygen1.3-rc2