// main.cc for Fluxbox Window manager // Copyright (c) 2001 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org) // and 2003-2005 Simon Bowden (rathnor at users.sourceforge.net) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "fluxbox.hh" #include "version.h" #include "defaults.hh" #include "Debug.hh" #include "FbTk/Theme.hh" #include "FbTk/I18n.hh" #include "FbTk/CommandParser.hh" #include "FbTk/FileUtil.hh" #include "FbTk/StringUtil.hh" //use GNU extensions #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif // _GNU_SOURCE #ifdef HAVE_CSTDLIB #include #else #include #endif #ifdef HAVE_CSTRING #include #else #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_STAT_H #include #include #endif // HAVE_SYS_STAT_H #include #include #include using std::cout; using std::cerr; using std::endl; using std::string; using std::ostream; using std::ofstream; using std::streambuf; using std::auto_ptr; using std::out_of_range; using std::runtime_error; using std::bad_cast; using std::bad_alloc; using std::exception; static void showInfo(ostream &ostr) { _FB_USES_NLS; ostr << _FB_CONSOLETEXT(Common, FluxboxVersion, "Fluxbox version", "Fluxbox version heading") << ": " << __fluxbox_version < 0) ostr << _FB_CONSOLETEXT(Common, SvnRevision, "GIT Revision", "Revision number in GIT repositary") << ": " << gitrevision() << endl; #if defined(__DATE__) && defined(__TIME__) ostr << _FB_CONSOLETEXT(Common, Compiled, "Compiled", "Time fluxbox was compiled") << ": " << __DATE__ << " " << __TIME__ << endl; #endif #ifdef __fluxbox_compiler ostr << _FB_CONSOLETEXT(Common, Compiler, "Compiler", "Compiler used to build fluxbox") << ": " << __fluxbox_compiler << endl; #endif // __fluxbox_compiler #ifdef __fluxbox_compiler_version ostr << _FB_CONSOLETEXT(Common, CompilerVersion, "Compiler version", "Compiler version used to build fluxbox") << ": " << __fluxbox_compiler_version << endl; #endif // __fluxbox_compiler_version ostr << endl <<_FB_CONSOLETEXT(Common, Defaults, "Defaults", "Default values compiled in") << ": " << endl; ostr <<_FB_CONSOLETEXT(Common, DefaultMenuFile, " menu", "default menu file (right aligned - make sure same width as other default values)") << ": " << FbTk::StringUtil::expandFilename(DEFAULTMENU) << endl; ostr << _FB_CONSOLETEXT(Common, DefaultStyle, " style", "default style (right aligned - make sure same width as other default values)") << ": " << FbTk::StringUtil::expandFilename(DEFAULTSTYLE) << endl; ostr << _FB_CONSOLETEXT(Common, DefaultKeyFile, " keys", "default key file (right aligned - make sure same width as other default values)") << ": " << FbTk::StringUtil::expandFilename(DEFAULTKEYSFILE) << endl; ostr << _FB_CONSOLETEXT(Common, DefaultInitFile, " init", "default init file (right aligned - make sure same width as other default values)") << ": " << FbTk::StringUtil::expandFilename(DEFAULT_INITFILE) << endl; #ifdef NLS ostr << _FB_CONSOLETEXT(Common, DefaultLocalePath, " nls", "location for localization files (right aligned - make sure same width as other default values)") << ": " << FbTk::StringUtil::expandFilename(LOCALEPATH) << endl; #endif const char NOT[] = "-"; ostr << endl << _FB_CONSOLETEXT(Common, CompiledOptions, "Compiled options", "Options used when compiled") << " (" << NOT << " => " << _FB_CONSOLETEXT(Common, Disabled, "disabled", "option is turned off") << "): " << endl << /**** NOTE: This list is in alphabetical order! ****/ #ifndef HAVE_FRIBIDI NOT << #endif "BIDI" << endl << #ifndef DEBUG NOT << #endif // DEBUG "DEBUG" << endl << #ifndef USE_EWMH NOT << #endif // USE_EWMH "EWMH" << endl << #ifndef HAVE_IMLIB2 NOT<< #endif // HAVE_IMLIB2 "IMLIB2" << endl << #ifndef NLS NOT<< #endif // NLS "NLS" << endl << #ifndef REMEMBER NOT << #endif // REMEMBER "REMEMBER" << endl << #ifndef HAVE_XRENDER NOT << #endif // HAVE_XRENDER "RENDER" << endl << #ifndef SHAPE NOT << #endif // SHAPE "SHAPE" << endl << #ifndef USE_SLIT NOT << #endif // SLIT "SLIT" << endl << #ifndef USE_TOOLBAR NOT << #endif // USE_TOOLBAR "TOOLBAR" << endl << #ifndef USE_XFT NOT << #endif // USE_XFT "XFT" << endl << #ifndef XINERAMA NOT << #endif // XINERAMA "XINERAMA" << endl << #ifndef USE_XMB NOT << #endif // USE_XMB "XMB" << endl << #ifndef HAVE_XPM NOT << #endif // HAVE_XPM "XPM" << endl << endl; } struct Options { Options() : xsync(false) { const char* env; env = getenv("DISPLAY"); if (env && strlen(env) > 0) { session_display.assign(env); } #ifdef _WIN32 env = getenv("USERPROFILE"); #else env = getenv("HOME"); #endif if (env && strlen(env) > 0) { rc_path.assign(std::string(env) + "/." + realProgramName("fluxbox")); rc_file = rc_path + "/init"; } } std::string session_display; std::string rc_path; std::string rc_file; std::string log_filename; bool xsync; }; static void parseOptions(int argc, char** argv, Options& opts) { _FB_USES_NLS; int i; for (i = 1; i < argc; ++i) { string arg(argv[i]); if (arg == "-rc" || arg == "--rc") { // look for alternative rc file to use if ((++i) >= argc) { cerr<<_FB_CONSOLETEXT(main, RCRequiresArg, "error: '-rc' requires an argument", "the -rc option requires a file argument")<= argc) { cerr<<_FB_CONSOLETEXT(main, DISPLAYRequiresArg, "error: '-display' requires an argument", "")<= argc) { cerr<<_FB_CONSOLETEXT(main, LOGRequiresArg, "error: '-log' needs an argument", "")<\t\tuse display connection.\n" "-screen \trun on specified screens only.\n" "-rc \t\t\tuse alternate resource file.\n" "-version\t\t\tdisplay version and exit.\n" "-info\t\t\t\tdisplay some useful information.\n" "-list-commands\t\t\tlist all valid key commands.\n" "-sync\t\t\t\tsynchronize with X server for debugging.\n" "-log \t\t\tlog output to file.\n" "-help\t\t\t\tdisplay this help text and exit.\n\n", "Main usage string. Please lay it out nicely. There is one %s that is given the version").c_str(), __fluxbox_version, "2001-2011"); exit(EXIT_SUCCESS); } else if (arg == "-info" || arg == "-i" || arg == "--info") { showInfo(cout); exit(EXIT_SUCCESS); } else if (arg == "-list-commands" || arg == "--list-commands") { FbTk::CommandParser::CreatorMap cmap = FbTk::CommandParser::instance().creatorMap(); FbTk::CommandParser::CreatorMap::const_iterator it = cmap.begin(); const FbTk::CommandParser::CreatorMap::const_iterator it_end = cmap.end(); for (; it != it_end; ++it) cout << it->first << endl; exit(EXIT_SUCCESS); } else if (arg == "-verbose" || arg == "--verbose") { FbTk::ThemeManager::instance().setVerbose(true); } } } #ifdef _WIN32 /** Wrapper function for Windows builds - mkdir takes only one param. */ static int mkdir(const char *dirname, int /*permissions*/) { return mkdir(dirname); } #endif /** setup the configutation files in home directory */ void setupConfigFiles(const std::string& dirname, const std::string& rc) { _FB_USES_NLS; const bool has_dir = FbTk::FileUtil::isDirectory(dirname.c_str()); struct CFInfo { bool create_file; const char* default_name; const std::string filename; } cfiles[] = { { !has_dir, DEFAULT_INITFILE, rc }, { !has_dir, DEFAULTKEYSFILE, dirname + "/keys" }, { !has_dir, DEFAULTMENU, dirname + "/menu" }, { !has_dir, DEFAULT_APPSFILE, dirname + "/apps" }, { !has_dir, DEFAULT_OVERLAY, dirname + "/overlay" }, { !has_dir, DEFAULT_WINDOWMENU, dirname + "/windowmenu" } }; const size_t nr_of_cfiles = sizeof(cfiles)/sizeof(CFInfo); if (has_dir) { // check if anything with these names exists, if not create new for (size_t i = 0; i < nr_of_cfiles; ++i) { cfiles[i].create_file = access(cfiles[i].filename.c_str(), F_OK); } } else { fbdbg << "Creating dir: " << dirname << endl; if (mkdir(dirname.c_str(), 0700)) { fprintf(stderr, _FB_CONSOLETEXT(Fluxbox, ErrorCreatingDirectory, "Can't create %s directory", "Can't create a directory, one %s for directory name").c_str(), dirname.c_str()); cerr << endl; return; } } bool sync_fs = false; // copy default files if needed for (size_t i = 0; i < nr_of_cfiles; ++i) { if (cfiles[i].create_file) { FbTk::FileUtil::copyFile(FbTk::StringUtil::expandFilename(cfiles[i].default_name).c_str(), cfiles[i].filename.c_str()); sync_fs = true; } } #ifdef HAVE_SYNC if (sync_fs) { sync(); } #endif } // configs might be out of date, so run fluxbox-update_configs // if necassary. void updateConfigFilesIfNeeded(const std::string& rc_file) { const int CONFIG_VERSION = 13; // TODO: move this to 'defaults.hh' or 'config.h' FbTk::ResourceManager r_mgr(rc_file.c_str(), false); FbTk::Resource c_version(r_mgr, 0, "session.configVersion", "Session.ConfigVersion"); if (!r_mgr.load(rc_file.c_str())) { _FB_USES_NLS; cerr << _FB_CONSOLETEXT(Fluxbox, CantLoadRCFile, "Failed to load database", "") << ": " << rc_file << endl; return; } if (*c_version < CONFIG_VERSION) { fbdbg << "updating config files from version " << *c_version << " to " << CONFIG_VERSION << endl; string commandargs = realProgramName("fluxbox-update_configs"); commandargs += " -rc " + rc_file; if (system(commandargs.c_str())) { fbdbg << "running '" << commandargs << "' failed." << endl; } #ifdef HAVE_SYNC sync(); #endif // HAVE_SYNC } } int main(int argc, char **argv) { FbTk::NLSInit("fluxbox.cat"); Options opts; parseOptions(argc, argv, opts); #ifdef __EMX__ _chdir2(getenv("X11ROOT")); #endif // __EMX__ streambuf *outbuf = 0; streambuf *errbuf = 0; ofstream log_file(opts.log_filename.c_str()); _FB_USES_NLS; // setup log file if (log_file.is_open()) { cerr << _FB_CONSOLETEXT(main, LoggingTo, "Logging to", "Logging to a file") << ": " << opts.log_filename << endl; log_file <<"------------------------------------------" << endl; log_file << _FB_CONSOLETEXT(main, LogFile, "Log File", "") << ": " << opts.log_filename < fluxbox; try { fluxbox.reset(new Fluxbox(argc, argv, opts.session_display, opts.rc_path, opts.rc_file, opts.xsync)); fluxbox->eventLoop(); exitcode = EXIT_SUCCESS; } catch (out_of_range &oor) { cerr <<"Fluxbox: " << _FB_CONSOLETEXT(main, ErrorOutOfRange, "Out of range", "Error message") << ": " << oor.what() << endl; } catch (runtime_error &re) { cerr << "Fluxbox: " << _FB_CONSOLETEXT(main, ErrorRuntime, "Runtime error", "Error message") << ": " << re.what() << endl; } catch (bad_cast &bc) { cerr << "Fluxbox: " << _FB_CONSOLETEXT(main, ErrorBadCast, "Bad cast", "Error message") << ": " << bc.what() << endl; } catch (bad_alloc &ba) { cerr << "Fluxbox: " << _FB_CONSOLETEXT(main, ErrorBadAlloc, "Bad Alloc", "Error message") << ": " << ba.what() << endl; } catch (exception &e) { cerr << "Fluxbox: " << _FB_CONSOLETEXT(main, ErrorStandardException, "Standard Exception", "Error message") << ": " << e.what() << endl; } catch (string & error_str) { cerr << _FB_CONSOLETEXT(Common, Error, "Error", "Error message header") << ": " << error_str << endl; } catch (...) { cerr << "Fluxbox: " << _FB_CONSOLETEXT(main, ErrorUnknown, "Unknown error", "Error message") << "." << endl; abort(); } bool restarting = false; string restart_argument; if (fluxbox.get()) { restarting = fluxbox->isRestarting(); restart_argument = fluxbox->getRestartArgument(); } // destroy fluxbox fluxbox.reset(0); // restore cout and cin streams if (outbuf != 0) cout.rdbuf(outbuf); if (errbuf != 0) cerr.rdbuf(errbuf); FbTk::FbStringUtil::shutdown(); if (restarting) { if (!restart_argument.empty()) { const char *shell = getenv("SHELL"); if (!shell) shell = "/bin/sh"; execlp(shell, shell, "-c", restart_argument.c_str(), (const char *) NULL); perror(restart_argument.c_str()); } // fall back in case the above execlp doesn't work execvp(argv[0], argv); perror(argv[0]); const char *basename = FbTk::StringUtil::basename(argv[0]).c_str(); execvp(basename, argv); perror(basename); } return exitcode; }