"Fossies" - the Fresh Open Source Software Archive

Member "bbkeys-0.9.1/src/ScreenHandler.cpp" (22 Dec 2008, 30322 Bytes) of package /linux/privat/old/bbkeys-0.9.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ScreenHandler.cpp" see the Fossies "Dox" file reference documentation.

    1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
    2 // -- ScreenHandler.cpp --
    3 // Copyright (c) 2001 - 2003 Jason 'vanRijn' Kasper <vR at movingparts dot net>
    4 //
    5 // Permission is hereby granted, free of charge, to any person obtaining a
    6 // copy of this software and associated documentation files (the "Software"),
    7 // to deal in the Software without restriction, including without limitation
    8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
    9 // and/or sell copies of the Software, and to permit persons to whom the
   10 // Software is furnished to do so, subject to the following conditions:
   11 //
   12 // The above copyright notice and this permission notice shall be included in
   13 // all copies or substantial portions of the Software.
   14 //
   15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   21 // DEALINGS IN THE SOFTWARE.
   22 
   23 // E_O_H_VR
   24 
   25 #include "../config.h"
   26 
   27 extern "C" {
   28 #ifdef    HAVE_STDIO_H
   29 #  include <stdio.h>
   30 #endif // HAVE_STDIO_H
   31 
   32 #ifdef    HAVE_UNISTD_H
   33 #  include <sys/types.h>
   34 #  include <unistd.h>
   35 #endif // HAVE_UNISTD_H
   36 
   37 #include <X11/keysym.h>
   38 #include <stdlib.h>
   39 }
   40 
   41 #include "ScreenHandler.h"
   42 
   43 using std::cout;
   44 
   45 //--------------------------------------------------------
   46 // Constructor/Destructor
   47 //--------------------------------------------------------
   48 ScreenHandler::ScreenHandler (KeyClient * k, unsigned int number)
   49   : _managed(true), _screenNumber(number),
   50     _screenInfo(k->display().screenInfo(number)),
   51     _clients(k->clientsList()), _active(k->activeWindow())
   52 {
   53   _keyClient = k;
   54   _netclient = k->getNetclient();
   55   _config = k->getConfig();
   56   _display = k->XDisplay();
   57   _last_active = _clients.end();
   58   _keyGrabber = k->getKeyGrabber();
   59   _keybindings = k->getKeybindings();
   60   _root = _screenInfo.rootWindow();
   61 
   62   // get our lockmasks from bt::Application
   63   k->getLockModifiers(_numlockMask, _scrolllockMask);
   64 
   65   // find a window manager supporting NETWM, waiting for it to load if we must
   66   int count = 20;  // try 20 times
   67   _managed = false;
   68   while (! (_keyClient->shuttingDown() || _managed || count <= 0)) {
   69     if (! (_managed = findSupportingWM()))
   70       sleep(5);
   71     --count;
   72   }
   73 
   74   if (!_managed) {
   75     cout << BBTOOL << ": " << "ScreenHandler: Unable to find a "
   76          << "compatible window manager for screen: [" << number << "].\n";
   77     return;
   78   }
   79 
   80   bt::EWMH::AtomList atoms;
   81   if (_netclient->readSupported(_root, atoms)) {
   82     cout << BBTOOL << ": " << "ScreenHandler: Supported atoms: [" << atoms.size() << "].\n";
   83   } else {
   84     cout << BBTOOL << ": " << "ScreenHandler: No supported ewmh hints. Not able to be managed.\n";
   85     _managed = false;
   86     return;
   87   }
   88 
   89   XSelectInput(_display, _root,
   90                PropertyChangeMask | KeyPressMask | KeyReleaseMask);
   91 
   92   // add an event handler for our root window
   93   k->insertEventHandler(_root, this);
   94 
   95   // get configuration options
   96   _honor_modifiers   = _config->getBoolValue("honormodifiers", false);
   97   _raise_while_cycling = _config->getBoolValue("raisewhilecycling", true);
   98   _show_cycle_menu   = _config->getBoolValue("showcyclemenu", true);
   99   _menu_text_justify = _config->getStringValue("menutextjustify", "left");
  100   _workspace_columns = _config->getNumberValue("workspacecolumns", 0);
  101   _workspace_rows    = _config->getNumberValue("workspacerows", 0);
  102   _follow_window_on_send    = _config->getBoolValue("followwindowonsend", false);
  103   _include_iconified_windows_in_cycle    = _config->getBoolValue("includeiconifiedwindowsincycle", true);
  104   _debug             = _config->getBoolValue("debug", false);
  105 
  106   _cycling = false;
  107 
  108   // our popup window list menu
  109   _windowmenu = new WindowlistMenu(this);
  110 
  111 }
  112 ScreenHandler::~ScreenHandler ()
  113 {
  114   _keyClient->removeEventHandler( _root );
  115 
  116   _keyGrabber->ungrabAll(_root);
  117 
  118   if (_managed)
  119     XSelectInput(_display, _root, None);
  120 }
  121 
  122 void ScreenHandler::initialize()
  123 {
  124   _keybindings->grabDefaults(this);
  125 
  126   updateActiveDesktop();
  127   updateNumDesktops();
  128   updateDesktopNames();
  129   updateClientList();
  130   updateActiveWindow();
  131 
  132   // load graphics resource from config file
  133   std::string menuTextJustify =
  134     _config->getStringValue("menuTextJustify", "right");
  135   std::string menuTitleJustify =
  136     _config->getStringValue("menuTitleJustify", "right");
  137 
  138   bt::Resource res(_config->getStringValue("stylefile", DEFAULTSTYLE));
  139   res.write("menu.frame.alignment", menuTextJustify.c_str());
  140   res.write("menu.title.alignment", menuTitleJustify.c_str());
  141 
  142   bt::MenuStyle::get(_keyClient->getMainApplication(),
  143              _screenNumber)->load(res);
  144 
  145 
  146 }
  147 
  148 bool ScreenHandler::findSupportingWM() {
  149 
  150   if (_debug)
  151     cout << endl << BBTOOL << ": " << "ScreenHandler: in findSupportingWM."<< endl;
  152 
  153   Window client, tmp;
  154   bool res = false;
  155 
  156   res = _netclient->readSupportingWMCheck(_root, &client);
  157   if (!res) {
  158     if (_debug)
  159       cout << BBTOOL << ": " << "ScreenHandler: first readSupportingWMCheck failed." << endl;
  160     return false;
  161   }
  162 
  163   if (_debug)
  164     cout << BBTOOL << ": " << "ScreenHandler: first readSupportingWMCheck succeeded." << endl;
  165 
  166   res = _netclient->readSupportingWMCheck(client, &tmp);
  167   if (!res || client != tmp) {
  168     if (_debug)
  169       cout << BBTOOL << ": " << "ScreenHandler: second readSupportingWMCheck failed." << endl;
  170     return false;
  171   }
  172 
  173   if (_debug)
  174     cout << BBTOOL << ": " << "ScreenHandler: second readSupportingWMCheck worked." << endl;
  175 
  176   // now try to get the name of the window manager, using utf8 first
  177   // and falling back to ansi if that fails
  178 
  179 
  180   // try ewmh
  181   if (! _netclient->getValue(client, _netclient->wmName(),
  182                              Netclient::utf8, _wm_name)) {
  183     if (_debug)
  184       cout << BBTOOL << ": " << "ScreenHandler: first try at getting wmName failed." << endl;
  185     // try old x stuff
  186     _netclient->getValue(client, XA_WM_NAME, Netclient::ansi, _wm_name);
  187   }
  188 
  189   if (_wm_name.empty()) {
  190     if (_debug)
  191       cout << BBTOOL << ": " << "ScreenHandler: couldn't get wm's name.  letting it slide this time...." << endl;
  192     _wm_name = "beats the heck out of me";
  193   }
  194 
  195   cout << BBTOOL << ": " << "ScreenHandler: Found compatible "
  196        << "window manager: [" << _wm_name << "] for screen: ["
  197        << _screenNumber << "].\n";
  198 
  199   return true;
  200 
  201 }
  202 
  203 bool ScreenHandler::grabKey(const KeyCode keyCode,
  204                             const int modifierMask) const {
  205   return _keyGrabber->grab(keyCode, modifierMask, _root );
  206 }
  207 
  208 bool ScreenHandler::ungrabKey(const KeyCode keyCode,
  209                               const int modifierMask) const {
  210   return _keyGrabber->ungrab(keyCode, modifierMask, _root );
  211 }
  212 
  213 void ScreenHandler::keyPressEvent (const XKeyEvent * const e)
  214 {
  215     unsigned int state = e->state;
  216 
  217   // Mask out the lock modifiers unless our user doesn't want this
  218     if (! _honor_modifiers) {
  219         state= e->state & ~(LockMask|_scrolllockMask|_numlockMask);
  220     }
  221 
  222   // first, check to see if we're in the middle of a window cycling
  223   // loop-de-loop and we're getting a cancel....
  224     if (_cycling && e->keycode == XKeysymToKeycode(_display, XK_Escape)) {
  225 
  226     // we've been told to cancel out of a cycleWindow loop, so we turn
  227     // off cycling, ungrab the keyboard, then raise the last-active
  228     // window for our user
  229         _cycling = false;
  230         XUngrabKeyboard(_display, CurrentTime);
  231 
  232         const XWindow * la = lastActiveWindow();
  233 
  234         if (la) la->focus(true);
  235 
  236         return;
  237     }
  238 
  239   // if we've made it this far, handle the action....
  240     Action *it = _keybindings->getAction(e, state, this);
  241 
  242     if (!it)
  243         return;
  244 
  245     if (_debug)
  246         cout <<BBTOOL << ": " << "action fired: [" << it->toString() <<"]" <<endl;
  247 
  248 
  249     switch (it->type()) {
  250 
  251         case Action::chain:
  252     // if we're doing a chain, then keytree has done everything for us...
  253     // just return
  254             return;
  255 
  256         case Action::nextScreen:
  257             _keyClient->cycleScreen(_screenNumber, true);
  258             return;
  259 
  260         case Action::prevScreen:
  261             _keyClient->cycleScreen(_screenNumber, false);
  262             return;
  263 
  264         case Action::nextWorkspace:
  265             cycleWorkspace(true, it->number() != 0 ? it->number(): 1);
  266             return;
  267 
  268         case Action::prevWorkspace:
  269             cycleWorkspace(false, it->number() != 0 ? it->number(): 1);
  270             return;
  271 
  272         case Action::nextWindow:
  273             cycleWindow(state, true, it->number() != 0 ? it->number(): 1);
  274             return;
  275 
  276         case Action::prevWindow:
  277             cycleWindow(state, false, it->number() != 0 ? it->number(): 1);
  278             return;
  279 
  280         case Action::nextWindowOnAllWorkspaces:
  281             cycleWindow(state, true, it->number() != 0 ? it->number(): 1,  false, true);
  282             return;
  283 
  284         case Action::prevWindowOnAllWorkspaces:
  285             cycleWindow(state, false, it->number() != 0 ? it->number(): 1, false, true);
  286             return;
  287 
  288         case Action::nextWindowOnAllScreens:
  289             cycleWindow(state, true, it->number() != 0 ? it->number(): 1, true);
  290             return;
  291 
  292         case Action::prevWindowOnAllScreens:
  293             cycleWindow(state, false, it->number() != 0 ? it->number(): 1, true);
  294             return;
  295 
  296         case Action::nextWindowOfClass:
  297             cycleWindow(state, true, it->number() != 0 ? it->number(): 1,
  298                         false, false, true, it->string());
  299             return;
  300 
  301         case Action::prevWindowOfClass:
  302             cycleWindow(state, false, it->number() != 0 ? it->number(): 1,
  303                         false, false, true, it->string());
  304             return;
  305 
  306         case Action::nextWindowOfClassOnAllWorkspaces:
  307             cycleWindow(state, true, it->number() != 0 ? it->number(): 1,
  308                         false, true, true, it->string());
  309             return;
  310 
  311         case Action::prevWindowOfClassOnAllWorkspaces:
  312             cycleWindow(state, false, it->number() != 0 ? it->number(): 1,
  313                         false, true, true, it->string());
  314             return;
  315 
  316         case Action::changeWorkspace:
  317             changeWorkspace(it->number());
  318             return;
  319 
  320         case Action::upWorkspace:
  321             changeWorkspaceVert(-1);
  322             return;
  323 
  324         case Action::downWorkspace:
  325             changeWorkspaceVert(1);
  326             return;
  327 
  328         case Action::leftWorkspace:
  329             changeWorkspaceHorz(-1);
  330             return;
  331 
  332         case Action::rightWorkspace:
  333             changeWorkspaceHorz(1);
  334             return;
  335 
  336         case Action::execute:
  337             execCommand(it->string());
  338             return;
  339 
  340         case Action::showRootMenu:
  341             _netclient->sendClientMessage(_root, _netclient->xaOpenboxShowRootMenu(),
  342                                           None);
  343             return;
  344 
  345         case Action::showWorkspaceMenu:
  346             _netclient->sendClientMessage(_root, _netclient->xaOpenboxShowWorkspaceMenu(),
  347                                           None);
  348             return;
  349 
  350             case Action::toggleGrabs: {
  351                 if (_grabbed) {
  352                     _keybindings->ungrabDefaults(this);
  353                     _grabbed = false;
  354                 } else {
  355                     _keybindings->grabDefaults(this);
  356                     _grabbed = true;
  357                 }
  358                 return;
  359             }
  360 
  361         default:
  362             break;
  363     }
  364 
  365   // these actions require an active window
  366     if (_active != _clients.end()) {
  367         XWindow *window = *_active;
  368 
  369         switch (it->type()) {
  370             case Action::iconify:
  371                 window->iconify();
  372                 return;
  373 
  374             case Action::close:
  375                 window->close();
  376                 return;
  377 
  378             case Action::raise:
  379                 window->raise();
  380                 return;
  381 
  382             case Action::lower:
  383                 window->lower();
  384                 return;
  385 
  386             case Action::sendToWorkspace:
  387                 window->sendTo(it->number());
  388                 if (_follow_window_on_send ) {
  389                     window->focus(true);
  390                 }
  391                 return;
  392 
  393             case Action::sendToNextWorkspace:
  394                 if (_active_desktop == _num_desktops - 1) {
  395                     window->sendTo(0);
  396                 }  else {
  397                     window->sendTo(_active_desktop + 1);
  398                 }
  399                 if (_follow_window_on_send ) {
  400                     window->focus(true);
  401                 }
  402                 return;
  403 
  404             case Action::sendToPrevWorkspace:
  405                 if (_active_desktop == 0) {
  406                     window->sendTo(_num_desktops - 1);
  407                 } else {
  408                     window->sendTo(_active_desktop - 1);
  409                 }
  410                 if (_follow_window_on_send ) {
  411                     window->focus(true);
  412                 }
  413                 return;
  414 
  415             case Action::toggleOmnipresent:
  416                 if (window->desktop() == 0xffffffff)
  417                     window->sendTo(_active_desktop);
  418                 else
  419                     window->sendTo(0xffffffff);
  420                 return;
  421 
  422             case Action::moveWindowUp:
  423                 window->move(0, -(it->number() != 0 ? it->number(): 1));
  424                 return;
  425 
  426             case Action::moveWindowDown:
  427                 window->move(0, it->number() != 0 ? it->number(): 1);
  428                 return;
  429 
  430             case Action::moveWindowLeft:
  431                 window->move(-(it->number() != 0 ? it->number(): 1), 0);
  432                 return;
  433 
  434             case Action::moveWindowRight:
  435                 window->move(it->number() != 0 ? it->number(): 1,0);
  436                 return;
  437 
  438             case Action::resizeWindowWidth:
  439                 window->resizeRel(it->number(), 0);
  440                 return;
  441 
  442             case Action::resizeWindowHeight:
  443                 window->resizeRel(0, it->number());
  444                 return;
  445 
  446             case Action::toggleShade:
  447                 window->shade(! window->shaded());
  448                 return;
  449 
  450             case Action::toggleMaximizeHorizontal:
  451                 window->toggleMaximize(XWindow::Max_Horz);
  452                 return;
  453 
  454             case Action::toggleMaximizeVertical:
  455                 window->toggleMaximize(XWindow::Max_Vert);
  456                 return;
  457 
  458             case Action::toggleMaximizeFull:
  459                 window->toggleMaximize(XWindow::Max_Full);
  460                 return;
  461 
  462             case Action::toggleDecorations:
  463                 window->decorate(! window->decorated());
  464                 return;
  465 
  466             default:
  467                 assert(false);  // unhandled action type!
  468                 break;
  469         }
  470     }
  471 }
  472 
  473 void ScreenHandler::keyReleaseEvent (const XKeyEvent * const e)
  474 {
  475   // the only keyrelease event we care about (for now) is when we do window
  476   // cycling and the modifier is released
  477   if ( _cycling && nothingIsPressed()) {
  478     // all modifiers have been released. ungrab the keyboard, move the
  479     // focused window to the top of the Z-order and raise it
  480     XUngrabKeyboard(_display, CurrentTime);
  481 
  482     if (_active != _clients.end()) {
  483       XWindow *w = *_active;
  484       bool e = _last_active == _active;
  485       _clients.remove(w);
  486       _clients.push_front(w);
  487       _active = _clients.begin();
  488       if (!e) _last_active = _active;
  489       w->raise();
  490     }
  491 
  492     _cycling = false;
  493   }
  494 }
  495 
  496 void ScreenHandler::propertyNotifyEvent(const XPropertyEvent * const e)
  497 {
  498   if (e->atom == _netclient->numberOfDesktops()) {
  499     updateNumDesktops();
  500   } else if (e->atom == _netclient->desktopNames()) {
  501     updateDesktopNames();
  502   } else if (e->atom == _netclient->currentDesktop()) {
  503     updateActiveDesktop();
  504   } else if (e->atom == _netclient->activeWindow()) {
  505     updateActiveWindow();
  506   } else if (e->atom == _netclient->clientList()) {
  507     updateClientList();
  508   }
  509 }
  510 
  511 void ScreenHandler::updateNumDesktops()
  512 {
  513   assert(_managed);
  514 
  515   if (! _netclient->readNumberOfDesktops(_root, & _num_desktops))
  516     _num_desktops = 1;  // assume that there is at least 1 desktop!
  517 
  518 }
  519 
  520 void ScreenHandler::updateDesktopNames()
  521 {
  522   assert(_managed);
  523 
  524   if(! _netclient->readDesktopNames(_root, _desktop_names)) {
  525     _desktop_names.clear();
  526     return;
  527   }
  528 
  529 //  bt::EWMH::UTF8StringList::const_iterator it = _desktop_names.begin(),
  530 //    end = _desktop_names.end();
  531 
  532 //  for (; it != end; ++it) {
  533 //    std::cout << BBTOOL << ": " << "name: ->" << *it << "<-\n";
  534 //    char default_name[80];
  535 //    sprintf(default_name, "Workspace %u", _id + 1);
  536 //    the_name = default_name;
  537 //  }
  538 
  539 }
  540 
  541 bt::ustring ScreenHandler::getDesktopName(unsigned int desktopNbr) const {
  542 
  543   if (0xFFFFFFFF == desktopNbr)
  544     return bt::toUnicode("");
  545 
  546   if (desktopNbr > _desktop_names.size() )
  547     return bt::toUnicode("error");
  548 
  549   return _desktop_names[desktopNbr];
  550 
  551 }
  552 
  553 void ScreenHandler::updateActiveDesktop()
  554 {
  555   assert(_managed);
  556 
  557   if (! _netclient->readCurrentDesktop(_root, & _active_desktop))
  558     _active_desktop = 0;  // there must be at least one desktop, and it must
  559   // be the current one
  560 
  561 }
  562 
  563 void ScreenHandler::updateActiveWindow()
  564 {
  565   assert(_managed);
  566 
  567   Window a = None;
  568   _netclient->getValue(_root, _netclient->activeWindow(), XA_WINDOW, a);
  569 
  570   if ( None == a ) {
  571     return;
  572   }
  573 
  574   WindowList::iterator it, end = _clients.end();
  575   for (it = _clients.begin(); it != end; ++it) {
  576     if ( (*it)->window() == a) {
  577       if ( (*it)->getScreenNumber() != _screenNumber )
  578         return;
  579       break;
  580     }
  581   }
  582 
  583   _active = it;
  584 
  585   if (_active != end) {
  586     /* if we're not cycling and a window gets focus, add it to the top of the
  587      * cycle stack.
  588      */
  589 
  590     if ( !_cycling) {
  591       XWindow *win = *_active;
  592       _clients.remove(win);
  593       _clients.push_front(win);
  594       _active = _clients.begin();
  595 
  596       _last_active = _active;
  597 
  598       if ( _debug )
  599         cout <<BBTOOL << ": " << "active window now: [" << bt::toLocale((*_active)->title()) <<"]" <<endl;
  600     }
  601 
  602   }
  603 
  604 }
  605 
  606 void ScreenHandler::updateClientList()
  607 {
  608 
  609   assert(_managed);
  610 
  611   WindowList::iterator insert_point = _active;
  612   if (insert_point != _clients.end())
  613     ++insert_point; // get to the item client the focused client
  614 
  615   // get the client list from the root window
  616   Netclient::WindowList rootclients;
  617   unsigned long num = (unsigned) -1;
  618 
  619   if ( ! _netclient->readClientList(_root, rootclients) ) {
  620     cerr << BBTOOL << ": " << "couldn't get client list from WM.\n";
  621     num = 0;
  622   } else {
  623     num = rootclients.size();
  624   }
  625 
  626   WindowList::iterator it;
  627   const WindowList::iterator end = _clients.end();
  628   unsigned long i;
  629 
  630   for (i = 0; i < num; ++i) {
  631     for (it = _clients.begin(); it != end; ++it)
  632       if (**it == rootclients[i])
  633         break;
  634     if (it == end) {  // didn't already exist
  635       if (careAboutWindow(rootclients[i])) {
  636         XWindow * wTmp = new XWindow( rootclients[i], _netclient, _screenInfo , *_keyClient );
  637         _clients.insert(insert_point, wTmp);
  638       }
  639     }
  640   }
  641 
  642   // remove clients that no longer exist (that belong to this screen)
  643   for (it = _clients.begin(); it != end;) {
  644     WindowList::iterator it2 = it;
  645     ++it;
  646 
  647     // is on another screen?
  648     if ((*it2)->getScreenNumber() != _screenNumber)
  649       continue;
  650 
  651     for (i = 0; i < num; ++i)
  652       if (**it2 == rootclients[i])
  653         break;
  654     if (i == num)  { // no longer exists
  655       // watch for the active and last-active window
  656       if (it2 == _active)
  657         _active = _clients.end();
  658       if (it2 == _last_active)
  659         _last_active = _clients.end();
  660       delete *it2;
  661       _clients.erase(it2);
  662     }
  663   }
  664 
  665 }
  666 
  667 
  668 // do we care about this window as a client?
  669 bool ScreenHandler::careAboutWindow(Window window) const
  670 {
  671   assert(_managed);
  672 
  673   Atom type;
  674   if (! _netclient->getValue(window, _netclient->wmWindowType(), XA_ATOM,
  675                              type)) {
  676     return True;
  677   }
  678 
  679   if (type == _netclient->wmWindowTypeDock() ||
  680       type == _netclient->wmWindowTypeMenu() ) {
  681     return False;
  682   } else {
  683     return True;
  684   }
  685 }
  686 
  687 XWindow * ScreenHandler::findWindow(Window window) const {
  688   assert(_managed);
  689 
  690   WindowList::const_iterator it, end = _clients.end();
  691   for (it = _clients.begin(); it != end; ++it)
  692     if (**it == window)
  693       break;
  694   if(it == end)
  695     return 0;
  696   return *it;
  697 }
  698 
  699 void ScreenHandler::execCommand(const string &cmd) const {
  700   pid_t pid;
  701   if ((pid = fork()) == 0) {
  702     // disconnect the child from this session and the tty
  703     if (setsid() == -1) {
  704       cout << BBTOOL << ": " << "warning: could not start a new process group\n";
  705       perror("setsid");
  706     }
  707 
  708     // make the command run on the correct screen
  709     if (putenv(const_cast<char*>(_screenInfo.displayString().c_str()))) {
  710       cout << BBTOOL << ": " << "warning: couldn't set environment variable 'DISPLAY'\n";
  711       perror("putenv()");
  712     }
  713     execl("/bin/sh", "sh", "-c", cmd.c_str(), NULL);
  714     exit(-1);
  715   } else if (pid == -1) {
  716     cout << BBTOOL << ": " << ": Could not fork a process for executing a command\n";
  717   }
  718 }
  719 
  720 WindowList ScreenHandler::getCycleWindowList(unsigned int state, const bool forward,
  721                          const int increment, const bool allscreens,
  722                          const bool alldesktops, const bool sameclass,
  723                          const string &cn)
  724 {
  725   assert(_managed);
  726   assert(increment > 0);
  727 
  728   WindowList theList;
  729 
  730   if (_clients.empty()) return theList;
  731 
  732   string classname(cn);
  733   if (sameclass && classname.empty() && _active != _clients.end())
  734     classname = (*_active)->appClass();
  735 
  736 
  737   WindowList::const_iterator it = _clients.begin();
  738   const WindowList::const_iterator end = _clients.end();
  739 
  740   for (; it != end; ++it) {
  741     XWindow *t = *it;
  742 
  743     // determine if this window is invalid for cycling to
  744     if (t->iconic() && !_include_iconified_windows_in_cycle) continue;
  745     if (! allscreens && t->getScreenNumber() != _screenNumber) continue;
  746     if (! alldesktops && ! (t->desktop() == _active_desktop ||
  747                 t->desktop() == 0xffffffff)) continue;
  748     if (sameclass && ! classname.empty() &&
  749     t->appClass() != classname) continue;
  750     if (! t->canFocus()) continue;
  751     if (t->skipPager()) continue;
  752 
  753     // found a focusable window
  754     theList.push_back(t);
  755   }
  756 
  757   return theList;
  758 
  759 }
  760 
  761 void ScreenHandler::cycleWindow(unsigned int state, const bool forward,
  762                 const int increment, const bool allscreens,
  763                 const bool alldesktops, const bool sameclass,
  764                 const string &cn)
  765 {
  766   assert(_managed);
  767   assert(increment > 0);
  768 
  769   if (_clients.empty()) {
  770       if (_debug)
  771           std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: no clients list. can't do anything..." << std::endl;
  772       return;
  773   }
  774 
  775   // if our user wants the window cycling menu to show (who wouldn't!!
  776   //  =:) ) and if it's not already showing...
  777   if ( _show_cycle_menu && ! _windowmenu->isVisible() ) {
  778     if (_debug)
  779         std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: menu not visible. loading and showing..." << std::endl;
  780 
  781     _cycling = true;
  782     WindowList theList = getCycleWindowList(state, forward, increment,
  783                         allscreens, alldesktops,
  784                         sameclass, cn);
  785     // can't show the window list if there's not even one window  =:)
  786     if (theList.size() >= 1)
  787       _windowmenu->showCycleMenu(theList);
  788 
  789     return;
  790 
  791   }
  792 
  793   if (_debug)
  794       std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: doing non-menu-based cycling..." << std::endl;
  795 
  796   string classname(cn);
  797   if (sameclass && classname.empty() && _active != _clients.end())
  798     classname = (*_active)->appClass();
  799 
  800   WindowList::const_iterator target = _active,
  801     begin = _clients.begin(),
  802     end = _clients.end();
  803 
  804   XWindow *t = 0;
  805 
  806   for (int x = 0; x < increment; ++x) {
  807       while (1) {
  808           if (forward) {
  809               if (target == end)
  810                   target = begin;
  811               else
  812                   ++target;
  813           } else {
  814               if (target == begin)
  815                   target = end;
  816               else
  817                   --target;
  818           }
  819 
  820     // must be no window to focus
  821           if (target == _active) {
  822               if (_debug)
  823                   std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: target == _active..." << std::endl;
  824               return;
  825           }
  826 
  827     // start back at the beginning of the loop
  828           if (target == end)
  829               continue;
  830 
  831     // determine if this window is invalid for cycling to
  832           t = *target;
  833           if (t->iconic() && !_include_iconified_windows_in_cycle) continue;
  834           if (! allscreens && t->getScreenNumber() != _screenNumber) continue;
  835           if (! alldesktops && ! (t->desktop() == _active_desktop ||
  836                       t->desktop() == 0xffffffff)) continue;
  837           if (sameclass && ! classname.empty() &&
  838                     t->appClass() != classname) continue;
  839           if (! t->canFocus()) continue;
  840           if (t->skipPager()) continue;
  841 
  842     // found a good window so break out of the while, and perhaps continue
  843     // with the for loop
  844           break;
  845       }
  846   }
  847 
  848   if (_debug)
  849       std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: dealing  with window: ["  << bt::toLocale(t->title()) << "]..." << std::endl;
  850   // phew. we found the window, so focus it.
  851   if ( state) {
  852       if (!_cycling) {
  853           if (_debug)
  854               std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: not cycling. grabbing keyboard..." << std::endl;
  855       // grab keyboard so we can intercept KeyReleases from it
  856           XGrabKeyboard(_display, _root, True, GrabModeAsync,
  857                         GrabModeAsync, CurrentTime);
  858           _cycling = true;
  859       }
  860       if (_debug)
  861           std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: focusing window while cycling..." << std::endl;
  862       focusWindow(t);
  863 
  864   } else {
  865       if (_debug)
  866           std::cout << BBTOOL << ": " << "ScreenHandler: cycleWindow: done cycling, focusing window now" << std::endl;
  867       t->focus();
  868   }
  869 }
  870 
  871 void ScreenHandler::focusWindow(const XWindow * win) {
  872 
  873   // if the window our little user has selected is on a different
  874   // workspace, go there first
  875   if ( ! win->isSticky() && (_active_desktop != win->desktop() ) ) {
  876       // this turns out to be yucky.  if we're not on the same desktop as the
  877       // window we're told to focus, just return and don't do anything...
  878       // changeWorkspace(win->desktop() );
  879       return;
  880   }
  881 
  882   // if we're cycling and user wants to raise windows while cycling,
  883   // raise the window, else if we're cycling without raising windows,
  884   // just set focus on the window, else focus and raise the window
  885   if (_cycling) {
  886     if (_raise_while_cycling) {
  887       win->focus();
  888     } else {
  889       win->focus(false);
  890     }
  891   } else {
  892     win->focus();
  893   }
  894 
  895 }
  896 
  897 void ScreenHandler::cycleWorkspace(const bool forward, const int increment,
  898                    const bool loop) const {
  899   assert(_managed);
  900   assert(increment > 0);
  901 
  902   unsigned int destination = _active_desktop;
  903 
  904   for (int x = 0; x < increment; ++x) {
  905     if (forward) {
  906       if (destination < _num_desktops - 1)
  907     ++destination;
  908       else if (loop)
  909     destination = 0;
  910     } else {
  911       if (destination > 0)
  912     --destination;
  913       else if (loop)
  914     destination = _num_desktops - 1;
  915     }
  916   }
  917 
  918   if (destination != _active_desktop)
  919     changeWorkspace(destination);
  920 }
  921 
  922 
  923 void ScreenHandler::changeWorkspace(const int num) const {
  924   assert(_managed);
  925 
  926   _netclient->sendClientMessage(_root, _netclient->currentDesktop(), _root, num);
  927 }
  928 
  929 void ScreenHandler::changeWorkspaceVert(const int num) const {
  930   assert(_managed);
  931   int width  = _workspace_columns;
  932   int height = _workspace_rows;
  933   int total = (signed)_num_desktops; // starts at 1
  934   int n = (signed)_active_desktop;   // starts at 0
  935   int wnum = 0;
  936   bool moveUp = (num < 0);
  937 
  938 // to understand the mathemathics in here, consider the following arrangements:
  939 
  940 //      | 0 1 2 columns         | 0 1 2
  941 //  -------------------       ---------
  942 //   0  | 0 1 2                0| 0 3 6
  943 //   1  | 3 4 5                1| 1 4 7
  944 //   2  | 6 7                  2| 2 5
  945 //  rows
  946 
  947 // left: horizontal arrangement, right: vertical
  948 // last workspace missing, total number of workspaces = 8
  949 // n%width = current column
  950 // n%height = current row
  951 
  952 
  953   if ( width > 0 ) { // width is set -> assume horizontal arrangement
  954                    // (default if height is given as well)
  955 
  956     if ( moveUp ) { // we go up...
  957       if ( n < width ) { // we're in the first row and want to change to the last
  958         if ( (total-1)%width < n%width ) // last row is incomplete, our column isn't there
  959           wnum = total-1 - (total-1)%width + n%width - width; // go to last but one
  960               // I guess, there's a more elegant expression for this...
  961         else // our column exists in the last row
  962           wnum = total-1 - (total-1)%width + n%width; // go to same column in last row
  963       } else wnum = n-width; // else, just go up one row
  964 
  965   } else { // we go down...
  966 
  967       if ( n+width > total-1 ) // next row would be out of range -> we're in the last
  968         wnum = n%width; // current column in first row
  969       else
  970         wnum = n+width; // go down one row
  971 
  972     }
  973   } else if ( height > 0 ) { // height is set -> vertical arrangement
  974     if ( moveUp ) {
  975       if ( n%height==0 ) { // if in first row
  976         if ( n + height > total - 1 ) // we're in an incomplete column
  977           wnum = total-1;
  978         else
  979           wnum = n+height-1;
  980       }
  981       else  // current row>1
  982         wnum = n-1;
  983     } else { // we're on our way down
  984       if ( n==total-1 || n%height==height-1 ) // incomplete column or last row
  985         wnum = n - n%height ;
  986       else
  987         wnum = n+1 ;
  988   }
  989   } else {} // no arrangement given -> do nothing
  990   changeWorkspace(wnum);
  991 }
  992 
  993 void ScreenHandler::changeWorkspaceHorz(const int num) const {
  994   assert(_managed);
  995   int width = _workspace_columns;
  996   int height = _workspace_rows;
  997   int total = (signed)_num_desktops;
  998   int n = (signed)_active_desktop;
  999   int wnum = 0;
 1000   bool moveLeft = (num < 0);
 1001 
 1002   if ( width > 0 ) { // width is set -> assume horizontal arrangement
 1003                    // (default if height is given as well)
 1004 
 1005     if ( moveLeft ) {
 1006       if ( n%width == 0 ) { // if in first col
 1007         if ( n + width > total - 1 ) // we're in an incomplete row
 1008           wnum = total-1;
 1009         else
 1010           wnum = n+width-1;
 1011       } else wnum = n-1;
 1012 
 1013     } else { // move right
 1014       if ( n==total-1 || n%width==width-1 ) // incomplete row or last col
 1015         wnum = n - n%width ;
 1016       else
 1017         wnum = n+1 ;
 1018     }
 1019 
 1020     } else if ( height > 0 ) { // height is set -> vertical arrangement
 1021     if ( moveLeft ) {
 1022       if ( n < height ) { // move first col -> last
 1023         if ( (total-1)%height < n%height ) // last col is incomplete
 1024           wnum = total-1 - (total-1)%height + n%height - height; // go to last but one
 1025         else // our row exists
 1026           wnum = total-1 - (total-1)%height + n%height; // go to same row in last col
 1027       } else wnum = n-height; // else, just go left one col
 1028 
 1029     } else { // go right
 1030       if ( n+height > total-1 ) // we would be out of range
 1031         wnum = n%height; // current row in first col
 1032       else
 1033         wnum = n+height; // go down one row
 1034     }
 1035   }
 1036   changeWorkspace(wnum);
 1037 }
 1038 
 1039 bool ScreenHandler::nothingIsPressed(void) const
 1040 {
 1041   char keys[32];
 1042   XQueryKeymap(_display, keys);
 1043 
 1044   for (int i = 0; i < 32; ++i) {
 1045     if (keys[i] != 0)
 1046       return false;
 1047   }
 1048 
 1049   return true;
 1050 }
 1051 
 1052 const XWindow *ScreenHandler::lastActiveWindow() const {
 1053   if (_last_active != _clients.end())
 1054     return *_last_active;
 1055 
 1056   // find a window if one exists
 1057   WindowList::const_iterator it, end = _clients.end();
 1058   for (it = _clients.begin(); it != end; ++it)
 1059     if ((*it)->getScreenNumber() == _screenNumber && ! (*it)->iconic() &&
 1060         (*it)->canFocus() &&
 1061         ((*it)->desktop() == 0xffffffff ||
 1062          (*it)->desktop() == _active_desktop))
 1063       return *it;
 1064 
 1065   // no windows on this screen
 1066   return 0;
 1067 }
 1068 
 1069 void ScreenHandler::p()
 1070 {
 1071   cout << BBTOOL << ": " << "\nNOW LISTING CLIENTS!!!" << endl;
 1072 
 1073   WindowList::const_iterator it = _clients.begin();
 1074   const WindowList::const_iterator end = _clients.end();
 1075 
 1076   for (; it != end; ++it)
 1077     cout << BBTOOL << ": " << "desktop: ["
 1078          << (*it)->desktop()
 1079          << "], window: [" << bt::toLocale((*it)->title()) << "]" << endl;
 1080 
 1081 
 1082 }
 1083 
 1084