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

/src/openbox.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 "openbox.hh"
00008 #include "client.hh"
00009 #include "screen.hh"
00010 #include "actions.hh"
00011 #include "bindings.hh"
00012 #include "python.hh"
00013 #include "otk/property.hh"
00014 #include "otk/assassin.hh"
00015 #include "otk/property.hh"
00016 #include "otk/util.hh"
00017 #include "otk/rendercolor.hh"
00018 
00019 extern "C" {
00020 #include <X11/cursorfont.h>
00021 
00022 #ifdef    HAVE_STDIO_H
00023 #  include <stdio.h>
00024 #endif // HAVE_STDIO_H
00025 
00026 #ifdef    HAVE_STDLIB_H
00027 #  include <stdlib.h>
00028 #endif // HAVE_STDLIB_H
00029 
00030 #ifdef    HAVE_SIGNAL_H
00031 #  include <signal.h>
00032 #endif // HAVE_SIGNAL_H
00033 
00034 #ifdef    HAVE_FCNTL_H
00035 #  include <fcntl.h>
00036 #endif // HAVE_FCNTL_H
00037 
00038 #ifdef    HAVE_SYS_WAIT_H
00039 #  include <sys/wait.h>
00040 #endif // HAVE_SYS_WAIT_H
00041 
00042 #include "gettext.h"
00043 #define _(str) gettext(str)
00044 }
00045 
00046 #include <algorithm>
00047 
00048 namespace ob {
00049 
00050 Openbox *openbox = (Openbox *) 0;
00051 
00052 
00053 void Openbox::signalHandler(int signal)
00054 {
00055   switch (signal) {
00056   case SIGUSR1:
00057     printf("Caught SIGUSR1 signal. Restarting.\n");
00058     openbox->restart();
00059     break;
00060 
00061   case SIGCHLD:
00062     wait(NULL);
00063     break;
00064 
00065   case SIGHUP:
00066   case SIGINT:
00067   case SIGTERM:
00068   case SIGPIPE:
00069     printf("Caught signal %d. Exiting.\n", signal);
00070     openbox->shutdown();
00071     break;
00072 
00073   case SIGFPE:
00074   case SIGSEGV:
00075     printf("Caught signal %d. Aborting and dumping core.\n", signal);
00076     abort();
00077   }
00078 }
00079 
00080 
00081 Openbox::Openbox(int argc, char **argv)
00082   : otk::EventDispatcher(),
00083     otk::EventHandler(),
00084     _display()
00085 {
00086   struct sigaction action;
00087 
00088   _state = State_Starting; // initializing everything
00089 
00090   openbox = this;
00091 
00092   _displayreq = (char*) 0;
00093   _argv = argv;
00094   _shutdown = false;
00095   _restart = false;
00096   _rcfilepath = otk::expandTilde("~/.openbox/rc3");
00097   _scriptfilepath = otk::expandTilde("~/.openbox/user.py");
00098   _focused_client = 0;
00099   _sync = false;
00100   _single = false;
00101 
00102   parseCommandLine(argc, argv);
00103 
00104   XSynchronize(**otk::display, _sync);
00105   
00106   // set up the signal handler
00107   action.sa_handler = Openbox::signalHandler;
00108   action.sa_mask = sigset_t();
00109   action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
00110   sigaction(SIGUSR1, &action, (struct sigaction *) 0);
00111   sigaction(SIGPIPE, &action, (struct sigaction *) 0);
00112   sigaction(SIGSEGV, &action, (struct sigaction *) 0);
00113   sigaction(SIGFPE, &action, (struct sigaction *) 0);
00114   sigaction(SIGTERM, &action, (struct sigaction *) 0);
00115   sigaction(SIGINT, &action, (struct sigaction *) 0);
00116   sigaction(SIGHUP, &action, (struct sigaction *) 0);
00117   sigaction(SIGCHLD, &action, (struct sigaction *) 0);
00118 
00119   // anything that died while we were restarting won't give us a SIGCHLD
00120   while (waitpid(-1, NULL, WNOHANG) > 0);
00121 
00122   otk::RenderColor::initialize();
00123   otk::Timer::initialize();
00124   otk::Property::initialize();
00125   _actions = new Actions();
00126   _bindings = new Bindings();
00127 
00128   setMasterHandler(_actions); // set as the master event handler
00129 
00130   // create the mouse cursors we'll use
00131   _cursors.session = XCreateFontCursor(**otk::display, XC_left_ptr);
00132   _cursors.move = XCreateFontCursor(**otk::display, XC_fleur);
00133   _cursors.ll_angle = XCreateFontCursor(**otk::display, XC_ll_angle);
00134   _cursors.lr_angle = XCreateFontCursor(**otk::display, XC_lr_angle);
00135   _cursors.ul_angle = XCreateFontCursor(**otk::display, XC_ul_angle);
00136   _cursors.ur_angle = XCreateFontCursor(**otk::display, XC_ur_angle);
00137 
00138   // initialize scripting
00139   python_init(argv[0]);
00140   
00141   // load config values
00142   //python_exec(SCRIPTDIR"/config.py"); // load openbox config values
00143   // run all of the python scripts
00144   //python_exec(SCRIPTDIR"/builtins.py"); // builtin callbacks
00145   //python_exec(SCRIPTDIR"/focus.py"); // focus helpers
00146   // run the user's script or the system defaults if that fails
00147   if (!python_exec(_scriptfilepath.c_str()))
00148     python_exec(SCRIPTDIR"/defaults.py"); // system default bahaviors
00149 
00150   // initialize all the screens
00151   _focused_screen = 0;
00152 
00153   for (int i = 0, max = ScreenCount(**otk::display); i < max; ++i) {
00154     Screen *screen;
00155     // in single mode skip the screens we don't want to manage
00156     if (_single && i != DefaultScreen(**otk::display)) {
00157       _screens.push_back(0);
00158       continue;
00159     }
00160     // try manage the screen
00161     screen = new Screen(i);
00162     if (screen->managed()) {
00163       _screens.push_back(screen);
00164       if (!_focused_screen) // set this to the first screen managed
00165         _focused_screen = screen;
00166     } else {
00167       delete screen;
00168       _screens.push_back(0);
00169     }
00170   }
00171 
00172   assert(_focused_screen);
00173 
00174   if (_screens.empty()) {
00175     printf(_("No screens were found without a window manager. Exiting.\n"));
00176     ::exit(1);
00177   }
00178 
00179   ScreenList::iterator it, end = _screens.end();
00180   for (it = _screens.begin(); it != end; ++it) {
00181     (*it)->manageExisting();
00182   }
00183  
00184   // grab any keys set up before the screens existed
00185   _bindings->grabKeys(true);
00186 
00187   // set up input focus
00188   setFocusedClient(0);
00189   
00190   _state = State_Normal; // done starting
00191 }
00192 
00193 
00194 Openbox::~Openbox()
00195 {
00196   _state = State_Exiting; // time to kill everything
00197 
00198   std::for_each(_screens.begin(), _screens.end(), otk::PointerAssassin());
00199 
00200   delete _bindings;
00201   delete _actions;
00202 
00203   python_destroy();
00204 
00205   XSetInputFocus(**otk::display, PointerRoot, RevertToNone,
00206                  CurrentTime);
00207   XSync(**otk::display, false);
00208 
00209   // this tends to block.. i honestly am not sure why. causing an x error in
00210   // the shutdown process unblocks it. blackbox simply did a ::exit(0), so
00211   // all im gunna do is the same.
00212   //delete _display;
00213 
00214   otk::Timer::destroy();
00215   otk::RenderColor::destroy();
00216 }
00217 
00218 
00219 void Openbox::parseCommandLine(int argc, char **argv)
00220 {
00221   bool err = false;
00222 
00223   for (int i = 1; i < argc; ++i) {
00224     std::string arg(argv[i]);
00225 
00226     if (arg == "-display") {
00227       if (++i >= argc)
00228         err = true;
00229       else
00230         _displayreq = argv[i];
00231     } else if (arg == "-rc") {
00232       if (++i >= argc)
00233         err = true;
00234       else
00235         _rcfilepath = argv[i];
00236     } else if (arg == "-menu") {
00237       if (++i >= argc)
00238         err = true;
00239       else
00240         _menufilepath = argv[i];
00241     } else if (arg == "-script") {
00242       if (++i >= argc)
00243         err = true;
00244       else
00245         _scriptfilepath = argv[i];
00246     } else if (arg == "-sync") {
00247       _sync = true;
00248     } else if (arg == "-single") {
00249       _single = true;
00250     } else if (arg == "-version") {
00251       showVersion();
00252       ::exit(0);
00253     } else if (arg == "-help") {
00254       showHelp();
00255       ::exit(0);
00256     } else
00257       err = true;
00258 
00259     if (err) {
00260       showHelp();
00261       exit(1);
00262     }
00263   }
00264 }
00265 
00266 
00267 void Openbox::showVersion()
00268 {
00269   printf(_("Openbox - version %s\n"), VERSION);
00270   printf("    (c) 2002 - 2002 Ben Jansens\n\n");
00271 }
00272 
00273 
00274 void Openbox::showHelp()
00275 {
00276   showVersion(); // show the version string and copyright
00277 
00278   // print program usage and command line options
00279   printf(_("Usage: %s [OPTIONS...]\n\
00280   Options:\n\
00281   -display <string>  use display connection.\n\
00282   -single            run on a single screen (default is to run every one).\n\
00283   -rc <string>       use alternate resource file.\n\
00284   -menu <string>     use alternate menu file.\n\
00285   -script <string>   use alternate startup script file.\n\
00286   -sync              run in synchronous mode (for debugging X errors).\n\
00287   -version           display version and exit.\n\
00288   -help              display this help text and exit.\n\n"), _argv[0]);
00289 
00290   printf(_("Compile time options:\n\
00291   Debugging: %s\n\
00292   Shape:     %s\n\
00293   Xinerama:  %s\n\
00294   Xkb:       %s\n"),
00295 #ifdef    DEBUG
00296          _("yes"),
00297 #else // !DEBUG
00298          _("no"),
00299 #endif // DEBUG
00300 
00301 #ifdef    SHAPE
00302          _("yes"),
00303 #else // !SHAPE
00304          _("no"),
00305 #endif // SHAPE
00306 
00307 #ifdef    XINERAMA
00308          _("yes"),
00309 #else // !XINERAMA
00310          _("no"),
00311 #endif // XINERAMA
00312 
00313 #ifdef    XKB
00314          _("yes")
00315 #else // !XKB
00316          _("no")
00317 #endif // XKB
00318     );
00319 }
00320 
00321 
00322 void Openbox::eventLoop()
00323 {
00324   while (true) {
00325     dispatchEvents(); // from otk::EventDispatcher
00326     XFlush(**otk::display); // flush here before we go wait for timers
00327     // don't wait if we're to shutdown
00328     if (_shutdown) break;
00329     otk::Timer::dispatchTimers(!_sync); // wait if not in sync mode
00330   }
00331 }
00332 
00333 
00334 void Openbox::addClient(Window window, Client *client)
00335 {
00336   _clients[window] = client;
00337 }
00338 
00339 
00340 void Openbox::removeClient(Window window)
00341 {
00342   _clients.erase(window);
00343 }
00344 
00345 
00346 Client *Openbox::findClient(Window window)
00347 {
00348   /*
00349     NOTE: we dont use _clients[] to find the value because that will insert
00350     a new null into the hash, which really sucks when we want to clean up the
00351     hash at shutdown!
00352   */
00353   ClientMap::iterator it = _clients.find(window);
00354   if (it != _clients.end())
00355     return it->second;
00356   else
00357     return (Client*) 0;
00358 }
00359 
00360 
00361 void Openbox::setFocusedClient(Client *c)
00362 {
00363   // sometimes this is called with the already-focused window, this is
00364   // important for the python scripts to work (eg, c = 0 twice). don't just
00365   // return if _focused_client == c
00366   
00367   assert(_focused_screen);
00368 
00369   // uninstall the old colormap
00370   if (_focused_client)
00371     _focused_client->installColormap(false);
00372   else
00373     _focused_screen->installColormap(false);
00374   
00375   _focused_client = c;
00376   if (c) {
00377     _focused_screen = _screens[c->screen()];
00378 
00379     // install the client's colormap
00380     c->installColormap(true);
00381   } else {
00382     XSetInputFocus(**otk::display, _focused_screen->focuswindow(),
00383                    RevertToNone, CurrentTime);
00384 
00385     // install the root window colormap
00386     _focused_screen->installColormap(true);
00387   }
00388   // set the NET_ACTIVE_WINDOW hint for all screens
00389   ScreenList::iterator it, end = _screens.end();
00390   for (it = _screens.begin(); it != end; ++it) {
00391     int num = (*it)->number();
00392     Window root = otk::display->screenInfo(num)->rootWindow();
00393     otk::Property::set(root, otk::Property::atoms.net_active_window,
00394                        otk::Property::atoms.window,
00395                        (c && _focused_screen == *it) ? c->window() : None);
00396   }
00397 
00398   // call the python Focus callbacks
00399   EventData data(_focused_screen->number(), c, EventAction::Focus, 0);
00400   _bindings->fireEvent(&data);
00401 }
00402 
00403 }
00404 

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