news download themes documentation links










fluxbox.cc

00001 // fluxbox.cc for Fluxbox Window Manager
00002 // Copyright (c) 2001 - 2004 Henrik Kinnunen (fluxgen at users.sourceforge.net)
00003 //
00004 // blackbox.cc for blackbox - an X11 Window manager
00005 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
00006 //
00007 // Permission is hereby granted, free of charge, to any person obtaining a
00008 // copy of this software and associated documentation files (the "Software"),
00009 // to deal in the Software without restriction, including without limitation
00010 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 // and/or sell copies of the Software, and to permit persons to whom the
00012 // Software is furnished to do so, subject to the following conditions:
00013 //
00014 // The above copyright notice and this permission notice shall be included in
00015 // all copies or substantial portions of the Software.
00016 //
00017 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 // DEALINGS IN THE SOFTWARE.
00024 
00025 // $Id: fluxbox.cc,v 1.221 2004/01/13 12:55:25 rathnor Exp $
00026 
00027 #include "fluxbox.hh"
00028 
00029 #include "I18n.hh"
00030 #include "Screen.hh"
00031 #include "Window.hh"
00032 #include "Workspace.hh"
00033 #include "AtomHandler.hh"
00034 #include "FbCommands.hh"
00035 #include "WinClient.hh"
00036 #include "Keys.hh"
00037 #include "FbAtoms.hh"
00038 #include "defaults.hh"
00039 
00040 #include "FbTk/Image.hh"
00041 #include "FbTk/KeyUtil.hh"
00042 #include "FbTk/ImageControl.hh"
00043 #include "FbTk/EventManager.hh"
00044 #include "FbTk/StringUtil.hh"
00045 #include "FbTk/Resource.hh"
00046 #include "FbTk/SimpleCommand.hh"
00047 #include "FbTk/XrmDatabaseHelper.hh"
00048 #include "FbTk/Command.hh"
00049 #include "FbTk/RefCount.hh"
00050 #include "FbTk/SimpleCommand.hh"
00051 
00052 //Use GNU extensions
00053 #ifndef  _GNU_SOURCE
00054 #define  _GNU_SOURCE
00055 #endif // _GNU_SOURCE
00056 
00057 #ifdef HAVE_CONFIG_H
00058 #include "config.h"
00059 #endif // HAVE_CONFIG_H
00060 
00061 #ifdef SLIT
00062 #include "Slit.hh"
00063 #endif // SLIT
00064 #ifdef USE_GNOME
00065 #include "Gnome.hh"
00066 #endif // USE_GNOME
00067 #ifdef USE_NEWWMSPEC
00068 #include "Ewmh.hh"
00069 #endif // USE_NEWWMSPEC
00070 #ifdef REMEMBER
00071 #include "Remember.hh"
00072 #endif // REMEMBER
00073 #ifdef USE_TOOLBAR
00074 #include "Toolbar.hh"
00075 #else
00076 class Toolbar { };
00077 #endif // USE_TOOLBAR
00078 
00079 // X headers
00080 #include <X11/Xlib.h>
00081 #include <X11/Xutil.h>
00082 #include <X11/Xresource.h>
00083 #include <X11/Xatom.h>
00084 #include <X11/keysym.h>
00085 
00086 // X extensions
00087 #ifdef SHAPE
00088 #include <X11/extensions/shape.h>
00089 #endif // SHAPE
00090 #ifdef HAVE_RANDR
00091 #include <X11/extensions/Xrandr.h>
00092 #endif // HAVE_RANDR
00093 
00094 // system headers
00095 
00096 #include <cstdio>
00097 #include <cstdlib>
00098 #include <cstring>
00099 
00100 #ifdef HAVE_UNISTD_H
00101 #include <sys/types.h>
00102 #include <unistd.h>
00103 #endif // HAVE_UNISTD_H
00104 
00105 #ifdef HAVE_SYS_PARAM_H
00106 #include <sys/param.h>
00107 #endif // HAVE_SYS_PARAM_H
00108 
00109 #ifdef HAVE_SYS_SELECT_H
00110 #include <sys/select.h>
00111 #endif // HAVE_SYS_SELECT_H
00112 
00113 #ifdef HAVE_SYS_STAT_H
00114 #include <sys/types.h>
00115 #include <sys/stat.h>
00116 #endif // HAVE_SYS_STAT_H
00117 
00118 #ifdef  TIME_WITH_SYS_TIME
00119 #include <sys/time.h>
00120 #include <time.h>
00121 #else // !TIME_WITH_SYS_TIME
00122 #ifdef HAVE_SYS_TIME_H
00123 #include <sys/time.h>
00124 #else // !HAVE_SYS_TIME_H
00125 #include <time.h>
00126 #endif // HAVE_SYS_TIME_H
00127 #endif // TIME_WITH_SYS_TIME
00128 
00129 #include <sys/wait.h>
00130 
00131 #include <iostream>
00132 #include <string>
00133 #include <memory>
00134 #include <algorithm>
00135 #include <typeinfo>
00136 
00137 using namespace std;
00138 using namespace FbTk;
00139 
00140 //-----------------------------------------------------------------
00141 //---- accessors for int, bool, and some enums with Resource ------
00142 //-----------------------------------------------------------------
00143 
00144 template<>
00145 void FbTk::Resource<int>::
00146 setFromString(const char* strval) {
00147     int val;
00148     if (sscanf(strval, "%d", &val)==1)
00149         *this = val;
00150 }
00151 
00152 template<>
00153 void FbTk::Resource<std::string>::
00154 setFromString(const char *strval) {
00155     *this = strval;
00156 }
00157 
00158 template<>
00159 void FbTk::Resource<bool>::
00160 setFromString(char const *strval) {
00161     if (strcasecmp(strval, "true")==0)
00162         *this = true;
00163     else
00164         *this = false;
00165 }
00166 
00167 
00168 
00169 template<>
00170 void FbTk::Resource<Fluxbox::TitlebarList>::
00171 setFromString(char const *strval) {
00172     vector<std::string> val;
00173     StringUtil::stringtok(val, strval);
00174     int size=val.size();
00175     //clear old values
00176     m_value.clear();
00177         
00178     for (int i=0; i<size; i++) {
00179         if (strcasecmp(val[i].c_str(), "Maximize")==0)
00180             m_value.push_back(Fluxbox::MAXIMIZE);
00181         else if (strcasecmp(val[i].c_str(), "Minimize")==0)
00182             m_value.push_back(Fluxbox::MINIMIZE);
00183         else if (strcasecmp(val[i].c_str(), "Shade")==0)
00184             m_value.push_back(Fluxbox::SHADE);
00185         else if (strcasecmp(val[i].c_str(), "Stick")==0)
00186             m_value.push_back(Fluxbox::STICK);
00187         else if (strcasecmp(val[i].c_str(), "Menu")==0)
00188             m_value.push_back(Fluxbox::MENU);
00189         else if (strcasecmp(val[i].c_str(), "Close")==0)
00190             m_value.push_back(Fluxbox::CLOSE);
00191     }
00192 }
00193 
00194 template<>
00195 void FbTk::Resource<unsigned int>::
00196 setFromString(const char *strval) { 
00197     if (sscanf(strval, "%ul", &m_value) != 1)
00198         setDefaultValue();
00199 }
00200 
00201 //-----------------------------------------------------------------
00202 //---- manipulators for int, bool, and some enums with Resource ---
00203 //-----------------------------------------------------------------
00204 template<>
00205 std::string FbTk::Resource<bool>::
00206 getString() {               
00207     return std::string(**this == true ? "true" : "false");
00208 }
00209 
00210 template<>
00211 std::string FbTk::Resource<int>::
00212 getString() {
00213     char strval[256];
00214     sprintf(strval, "%d", **this);
00215     return std::string(strval);
00216 }
00217 
00218 template<>
00219 std::string FbTk::Resource<std::string>::
00220 getString() { return **this; }
00221 
00222 
00223 template<>
00224 std::string FbTk::Resource<Fluxbox::TitlebarList>::
00225 getString() {
00226     string retval;
00227     int size=m_value.size();
00228     for (int i=0; i<size; i++) {
00229         switch (m_value[i]) {
00230         case Fluxbox::SHADE:
00231             retval.append("Shade");
00232             break;
00233         case Fluxbox::MINIMIZE:
00234             retval.append("Minimize");
00235             break;
00236         case Fluxbox::MAXIMIZE:
00237             retval.append("Maximize");
00238             break;
00239         case Fluxbox::CLOSE:
00240             retval.append("Close");
00241             break;
00242         case Fluxbox::STICK:
00243             retval.append("Stick");
00244             break;
00245         case Fluxbox::MENU:
00246             retval.append("Menu");
00247             break;
00248         default:
00249             break;
00250         }
00251         retval.append(" ");
00252     }
00253 
00254     return retval;
00255 }
00256 
00257 template<>
00258 string FbTk::Resource<unsigned int>::
00259 getString() {
00260     char tmpstr[128];
00261     sprintf(tmpstr, "%ul", m_value);
00262     return string(tmpstr);
00263 }
00264 
00265 template<>
00266 void FbTk::Resource<Fluxbox::Layer>::
00267 setFromString(const char *strval) {
00268     int tempnum = 0;
00269     if (sscanf(strval, "%d", &tempnum) == 1)
00270         m_value = tempnum;
00271     else if (strcasecmp(strval, "Menu") == 0)
00272         m_value = Fluxbox::instance()->getMenuLayer();
00273     else if (strcasecmp(strval, "AboveDock") == 0)
00274         m_value = Fluxbox::instance()->getAboveDockLayer();
00275     else if (strcasecmp(strval, "Dock") == 0)
00276         m_value = Fluxbox::instance()->getDockLayer();
00277     else if (strcasecmp(strval, "Top") == 0)
00278         m_value = Fluxbox::instance()->getTopLayer();
00279     else if (strcasecmp(strval, "Normal") == 0)
00280         m_value = Fluxbox::instance()->getNormalLayer();
00281     else if (strcasecmp(strval, "Bottom") == 0)
00282         m_value = Fluxbox::instance()->getBottomLayer();
00283     else if (strcasecmp(strval, "Desktop") == 0)
00284         m_value = Fluxbox::instance()->getDesktopLayer();
00285     else 
00286         setDefaultValue();
00287 }
00288 
00289 
00290 template<>
00291 string FbTk::Resource<Fluxbox::Layer>::
00292 getString() {
00293 
00294     if (m_value.getNum() == Fluxbox::instance()->getMenuLayer()) 
00295         return string("Menu");
00296     else if (m_value.getNum() == Fluxbox::instance()->getAboveDockLayer()) 
00297         return string("AboveDock");
00298     else if (m_value.getNum() == Fluxbox::instance()->getDockLayer()) 
00299         return string("Dock");
00300     else if (m_value.getNum() == Fluxbox::instance()->getTopLayer()) 
00301         return string("Top");
00302     else if (m_value.getNum() == Fluxbox::instance()->getNormalLayer()) 
00303         return string("Normal");
00304     else if (m_value.getNum() == Fluxbox::instance()->getBottomLayer()) 
00305         return string("Bottom");
00306     else if (m_value.getNum() == Fluxbox::instance()->getDesktopLayer()) 
00307         return string("Desktop");
00308     else {
00309         char tmpstr[128];
00310         sprintf(tmpstr, "%d", m_value.getNum());
00311         return string(tmpstr);
00312     }
00313 }
00314 template<>
00315 void FbTk::Resource<long>::
00316 setFromString(const char *strval) {   
00317     if (sscanf(strval, "%ld", &m_value) != 1)
00318         setDefaultValue();
00319 }
00320  
00321 
00322 string FbTk::Resource<long>::
00323 getString() {
00324     char tmpstr[128];
00325     sprintf(tmpstr, "%ld", m_value);
00326     return string(tmpstr);
00327 }
00328 
00329 static Window last_bad_window = None;
00330 namespace {
00331 void copyFile(const std::string &from, const std::string &to) {
00332         ifstream from_file(from.c_str());
00333         ofstream to_file(to.c_str());
00334 
00335         if (! to_file.good()) {
00336             cerr<<"Can't write file: "<<to<<endl;           
00337         } else if (from_file.good()) {
00338             to_file<<from_file.rdbuf(); //copy file
00339         } else {
00340             cerr<<"Can't copy from "<<from<<" to "<<to<<endl;
00341         }       
00342 }
00343 
00344 } // end anonymous
00345 
00346 static int handleXErrors(Display *d, XErrorEvent *e) {
00347 #ifdef DEBUG
00348     /*    
00349     char errtxt[128];
00350     
00351     XGetErrorText(d, e->error_code, errtxt, 128);
00352     cerr<<"Fluxbox: X Error: "<<errtxt<<"("<<(int)e->error_code<<") opcodes "<<
00353         (int)e->request_code<<"/"<<(int)e->minor_code<<" resource 0x"<<hex<<(int)e->resourceid<<dec<<endl;
00354     */
00355 #endif // !DEBUG
00356 
00357     if (e->error_code == BadWindow)
00358         last_bad_window = e->resourceid;
00359 
00360     return False;
00361 }
00362 
00363 
00364 //static singleton var
00365 Fluxbox *Fluxbox::s_singleton=0;
00366 
00367 //default values for titlebar left and right
00368 //don't forget to change last value in m_rc_titlebar_* if you add more to these
00369 Fluxbox::Titlebar Fluxbox::s_titlebar_left[] = {STICK};
00370 Fluxbox::Titlebar Fluxbox::s_titlebar_right[] = {MINIMIZE, MAXIMIZE, CLOSE};
00371 
00372 Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfilename)
00373     : FbTk::App(dpy_name),
00374       m_fbatoms(new FbAtoms()),
00375       m_resourcemanager(rcfilename, true), 
00376       // TODO: shouldn't need a separate one for screen
00377       m_screen_rm(m_resourcemanager),
00378       m_rc_tabs(m_resourcemanager, true, "session.tabs", "Session.Tabs"),
00379       m_rc_ignoreborder(m_resourcemanager, false, "session.ignoreBorder", "Session.IgnoreBorder"),
00380       m_rc_colors_per_channel(m_resourcemanager, 4, 
00381                               "session.colorsPerChannel", "Session.ColorsPerChannel"),
00382       m_rc_numlayers(m_resourcemanager, 13, "session.numLayers", "Session.NumLayers"),
00383       m_rc_double_click_interval(m_resourcemanager, 250, "session.doubleClickInterval", "Session.DoubleClickInterval"),
00384       m_rc_update_delay_time(m_resourcemanager, 0, "session.updateDelayTime", "Session.UpdateDelayTime"),
00385       m_rc_stylefile(m_resourcemanager, "", "session.styleFile", "Session.StyleFile"),
00386       m_rc_menufile(m_resourcemanager, DEFAULTMENU, "session.menuFile", "Session.MenuFile"),
00387       m_rc_keyfile(m_resourcemanager, DEFAULTKEYSFILE, "session.keyFile", "Session.KeyFile"),
00388       m_rc_slitlistfile(m_resourcemanager, "", "session.slitlistFile", "Session.SlitlistFile"),
00389       m_rc_groupfile(m_resourcemanager, "", "session.groupFile", "Session.GroupFile"),
00390       m_rc_titlebar_left(m_resourcemanager, 
00391                          TitlebarList(&s_titlebar_left[0], &s_titlebar_left[1]), 
00392                          "session.titlebar.left", "Session.Titlebar.Left"),
00393       m_rc_titlebar_right(m_resourcemanager, 
00394                           TitlebarList(&s_titlebar_right[0], &s_titlebar_right[3]), 
00395                           "session.titlebar.right", "Session.Titlebar.Right"),
00396       m_rc_cache_life(m_resourcemanager, 5, "session.cacheLife", "Session.CacheLife"),
00397       m_rc_cache_max(m_resourcemanager, 200, "session.cacheMax", "Session.CacheMax"),
00398       m_rc_auto_raise_delay(m_resourcemanager, 250, "session.autoRaiseDelay", "Session.AutoRaiseDelay"),
00399       m_rc_use_mod1(m_resourcemanager, true, "session.useMod1", "Session.UseMod1"),
00400       m_focused_window(0), m_masked_window(0),
00401       m_mousescreen(0),
00402       m_keyscreen(0),
00403       m_watching_screen(0), m_watch_keyrelease(0),
00404       m_last_time(0),
00405       m_masked(0),
00406       m_rc_file(rcfilename ? rcfilename : ""),
00407       m_argv(argv), m_argc(argc),
00408       m_starting(true),
00409       m_shutdown(false),
00410       m_server_grabs(0),
00411       m_randr_event_type(0),
00412       m_RC_PATH("fluxbox"),
00413       m_RC_INIT_FILE("init") {
00414       
00415     
00416     if (s_singleton != 0)
00417         throw string("Fatal! There can only one instance of fluxbox class.");
00418 
00419     if (display() == 0) {
00421         throw string("Can not connect to X server.\n"
00422                      "Make sure you started X before you start Fluxbox.");
00423     }
00424     // For KDE dock applets
00425     // KDE v1.x
00426     m_kwm1_dockwindow = XInternAtom(FbTk::App::instance()->display(), 
00427                                     "KWM_DOCKWINDOW", False);
00428     // KDE v2.x
00429     m_kwm2_dockwindow = XInternAtom(FbTk::App::instance()->display(), 
00430                                     "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
00431     // setup X error handler
00432     XSetErrorHandler((XErrorHandler) handleXErrors);
00433 
00434     //catch system signals
00435     SignalHandler &sigh = SignalHandler::instance();    
00436     sigh.registerHandler(SIGSEGV, this);
00437     sigh.registerHandler(SIGFPE, this);
00438     sigh.registerHandler(SIGTERM, this);
00439     sigh.registerHandler(SIGINT, this);
00440     sigh.registerHandler(SIGCHLD, this);
00441     sigh.registerHandler(SIGHUP, this);
00442     sigh.registerHandler(SIGUSR1, this);    
00443     sigh.registerHandler(SIGUSR2, this);
00444     //
00445     // setup timer
00446     // This timer is used to we can issue a safe reconfig command.
00447     // Because when the command is executed we shouldn't do reconfig directly
00448     // because it could affect ongoing menu stuff so we need to reconfig in
00449     // the next event "round".
00450     FbTk::RefCount<FbTk::Command> reconfig_cmd(new FbTk::SimpleCommand<Fluxbox>(*this, &Fluxbox::timed_reconfigure));
00451     timeval to;
00452     to.tv_sec = 0;
00453     to.tv_usec = 1;
00454     m_reconfig_timer.setTimeout(to);
00455     m_reconfig_timer.setCommand(reconfig_cmd);
00456     m_reconfig_timer.fireOnce(true);
00457 
00458     Display *disp = FbTk::App::instance()->display();
00459 
00460     s_singleton = this;
00461     m_have_shape = false;
00462     m_shape_eventbase = 0;
00463 #ifdef SHAPE
00464     int shape_err; 
00465     m_have_shape = XShapeQueryExtension(disp, &m_shape_eventbase, &shape_err);
00466 #endif // SHAPE
00467 
00468 #ifdef HAVE_RANDR
00469     // get randr event type
00470     int randr_error_base;
00471     XRRQueryExtension(disp, &m_randr_event_type, &randr_error_base);
00472 #endif // HAVE_RANDR
00473 
00474     load_rc();
00475     // setup theme manager to have our style file ready to be scanned
00476     FbTk::ThemeManager::instance().load(getStyleFilename());
00477 
00478     // setup atom handlers before we create any windows
00479 #ifdef USE_GNOME
00480     addAtomHandler(new Gnome()); // for gnome 1 atom support
00481 #endif //USE_GNOME
00482 
00483 #ifdef USE_NEWWMSPEC
00484     addAtomHandler(new Ewmh()); // for Extended window manager atom support
00485 #endif // USE_NEWWMSPEC
00486 
00487 #ifdef REMEMBER
00488     addAtomHandler(new Remember()); // for remembering window attribs
00489 #endif // REMEMBER
00490 
00491     grab();
00492     
00493     setupConfigFiles();
00494     
00495     if (! XSupportsLocale())
00496         cerr<<"Warning: X server does not support locale"<<endl;
00497 
00498     if (XSetLocaleModifiers("") == 0)
00499         cerr<<"Warning: cannot set locale modifiers"<<endl;
00500 
00501 
00502 #ifdef HAVE_GETPID
00503     m_fluxbox_pid = XInternAtom(disp, "_BLACKBOX_PID", False);
00504 #endif // HAVE_GETPID
00505 
00506     // Allocate screens
00507     for (int i = 0; i < ScreenCount(display()); i++) {
00508         char scrname[128], altscrname[128];
00509         sprintf(scrname, "session.screen%d", i);
00510         sprintf(altscrname, "session.Screen%d", i);
00511         BScreen *screen = new BScreen(m_screen_rm.lock(), 
00512 
00513                                       scrname, altscrname,
00514                                       i, getNumberOfLayers());
00515         if (! screen->isScreenManaged()) {
00516             delete screen;          
00517             continue;
00518         }
00519 
00520 #ifdef HAVE_GETPID
00521         pid_t bpid = getpid();
00522 
00523         screen->rootWindow().changeProperty(getFluxboxPidAtom(), XA_CARDINAL,
00524                                             sizeof(pid_t) * 8, PropModeReplace,
00525                                             (unsigned char *) &bpid, 1);
00526 #endif // HAVE_GETPID
00527 
00528 #ifdef HAVE_RANDR
00529         // setup RANDR for this screens root window
00530         // we need to determine if we should use old randr select input function or not
00531 #ifdef X_RRScreenChangeSelectInput
00532         // use old set randr event
00533         XRRScreenChangeSelectInput(disp, screen->rootWindow().window(), True);
00534 #else
00535         XRRSelectInput(disp, screen->rootWindow().window(),
00536                        RRScreenChangeNotifyMask);
00537 #endif // X_RRScreenChangeSelectInput        
00538 
00539 #endif // HAVE_RANDR
00540 
00541         m_screen_list.push_back(screen);
00542 #ifdef USE_TOOLBAR
00543         m_toolbars.push_back(new Toolbar(*screen, 
00544                                          *screen->layerManager().getLayer(Fluxbox::instance()->getNormalLayer())));
00545 #endif // USE_TOOLBAR
00546 
00547         // attach screen signals to this
00548         screen->currentWorkspaceSig().attach(this);
00549         screen->workspaceCountSig().attach(this);
00550         screen->workspaceNamesSig().attach(this);
00551         screen->clientListSig().attach(this);
00552 
00553         // initiate atomhandler for screen specific stuff
00554         for (size_t atomh=0; atomh<m_atomhandler.size(); ++atomh) {
00555             m_atomhandler[atomh]->initForScreen(*screen);
00556         }
00557 
00558         revertFocus(*screen); // make sure focus style is correct
00559 
00560     } // end init screens
00561 
00562 
00563     m_keyscreen = m_mousescreen = m_screen_list.front();
00564 
00565     if (m_screen_list.size() == 0) {
00567         throw string("Couldn't find screens to manage.\n"
00568                      "Make sure you don't have another window manager running.");
00569     }
00570 
00571     // setup theme manager to have our style file ready to be scanned
00572     FbTk::ThemeManager::instance().load(getStyleFilename());
00573 
00574     XSynchronize(disp, False);
00575     sync(false);
00576 
00577     m_reconfigure_wait = m_reread_menu_wait = false;
00578     
00579     // Create keybindings handler and load keys file    
00580     m_key.reset(new Keys(StringUtil::expandFilename(*m_rc_keyfile).c_str()));
00581 
00582     m_resourcemanager.unlock();
00583     ungrab();
00584 
00585 #ifdef DEBUG
00586     if (m_resourcemanager.lockDepth() != 0) 
00587         cerr<<"--- resource manager lockdepth = "<<m_resourcemanager.lockDepth()<<endl;
00588 #endif //DEBUG
00589     m_starting = false;
00590     // 
00591     // For dumping theme items
00592     // FbTk::ThemeManager::instance().listItems();
00593     //
00594     //    m_resourcemanager.dump();
00595 }
00596 
00597 
00598 Fluxbox::~Fluxbox() {
00599     // destroy toolbars
00600     while (!m_toolbars.empty()) {
00601         delete m_toolbars.back();
00602         m_toolbars.pop_back();
00603     }
00604 
00605     // destroy atomhandlers
00606     while (!m_atomhandler.empty()) {
00607         delete m_atomhandler.back();
00608         m_atomhandler.pop_back();
00609     }
00610 
00611     while (!m_screen_list.empty()) {
00612         delete m_screen_list.back();
00613         m_screen_list.pop_back();
00614     }
00615 
00616     clearMenuFilenames();   
00617 }
00618 
00619 void Fluxbox::eventLoop() {
00620     Display *disp = display();
00621     while (!m_shutdown) {
00622         if (XPending(disp)) {
00623             XEvent e;
00624             XNextEvent(disp, &e);
00625 
00626             if (last_bad_window != None && e.xany.window == last_bad_window && 
00627                 e.type != DestroyNotify) { // we must let the actual destroys through
00628 #ifdef DEBUG
00629                 cerr<<"Fluxbox::eventLoop(): removing bad window from event queue"<<endl;
00630 #endif // DEBUG
00631             } else {
00632                 last_bad_window = None;
00633                 handleEvent(&e);
00634             }
00635         } else {
00636             FbTk::Timer::updateTimers(ConnectionNumber(disp)); //handle all timers
00637         }
00638     }
00639 }
00640 
00641 bool Fluxbox::validateWindow(Window window) const {
00642     XEvent event;
00643     if (XCheckTypedWindowEvent(display(), window, DestroyNotify, &event)) {
00644         XPutBackEvent(display(), &event);
00645         return false;
00646     }
00647 
00648     return true;
00649 }
00650 
00651 void Fluxbox::grab() {
00652     if (! m_server_grabs++)
00653        XGrabServer(display());
00654 }
00655 
00656 void Fluxbox::ungrab() {
00657     if (! --m_server_grabs)
00658         XUngrabServer(display());
00659     if (m_server_grabs < 0)
00660         m_server_grabs = 0;
00661 }
00662 
00667 void Fluxbox::setupConfigFiles() {
00668 
00669     bool create_init = false, create_keys = false, create_menu = false;
00670 
00671     string dirname = getenv("HOME") + string("/.") + string(m_RC_PATH) + "/";
00672     string init_file, keys_file, menu_file, slitlist_file;
00673     init_file = dirname + m_RC_INIT_FILE;
00674     keys_file = dirname + "keys";
00675     menu_file = dirname + "menu";
00676 
00677     struct stat buf;
00678 
00679     // is file/dir already there?
00680     if (! stat(dirname.c_str(), &buf)) {
00681         
00682         // check if anything with those name exists, if not create new
00683         if (stat(init_file.c_str(), &buf))
00684             create_init = true;
00685         if (stat(keys_file.c_str(), &buf))
00686             create_keys = true;
00687         if (stat(menu_file.c_str(), &buf))
00688             create_menu = true;
00689 
00690     } else {
00691 #ifdef DEBUG
00692         cerr <<__FILE__<<"("<<__LINE__<<"): Creating dir: " << dirname.c_str() << endl;
00693 #endif // DEBUG
00694 
00695         // create directory with perm 700
00696         if (mkdir(dirname.c_str(), 0700)) {
00697             cerr << "Can't create " << dirname << " directory!" << endl;
00698             return; 
00699         }
00700         
00701         //mark creation of files
00702         create_init = create_keys = create_menu = true;
00703     }
00704 
00705 
00706     // copy key configuration
00707     if (create_keys)
00708         copyFile(DEFAULTKEYSFILE, keys_file);
00709 
00710     // copy menu configuration
00711     if (create_menu)
00712         copyFile(DEFAULTMENU, menu_file);
00713 
00714     // copy init file
00715     if (create_init)
00716         copyFile(DEFAULT_INITFILE, init_file);
00717 
00718 }
00719 
00720 void Fluxbox::handleEvent(XEvent * const e) {
00721     m_last_event = *e;
00722 
00723     // it is possible (e.g. during moving) for a window
00724     // to mask all events to go to it 
00725     if ((m_masked == e->xany.window) && m_masked_window) {
00726         if (e->type == MotionNotify) {
00727             m_last_time = e->xmotion.time;
00728             m_masked_window->motionNotifyEvent(e->xmotion);
00729             return;
00730         } else if (e->type == ButtonRelease) {
00731             e->xbutton.window = m_masked_window->fbWindow().window();
00732         }
00733   
00734     }
00735 
00736     // update key/mouse screen and last time before we enter other eventhandlers
00737     if (e->type == KeyPress ||
00738         e->type == KeyRelease) {
00739         m_keyscreen = searchScreen(e->xkey.root);
00740     } else if (e->type == ButtonPress ||
00741                e->type == ButtonRelease ||
00742                e->type == MotionNotify ) {
00743         if (e->type == MotionNotify)
00744             m_last_time = e->xmotion.time;
00745         else
00746             m_last_time = e->xbutton.time;
00747 
00748         m_mousescreen = searchScreen(e->xbutton.root);
00749     } else if (e->type == EnterNotify ||
00750                e->type == LeaveNotify) {
00751         m_last_time = e->xcrossing.time;
00752         m_mousescreen = searchScreen(e->xcrossing.root);
00753     } else if (e->type == PropertyNotify)
00754         m_last_time = e->xproperty.time;
00755 
00756     
00757     // try FbTk::EventHandler first
00758     FbTk::EventManager::instance()->handleEvent(*e);
00759 
00760     switch (e->type) {
00761     case ButtonRelease:
00762     case ButtonPress:
00763         handleButtonEvent(e->xbutton);
00764     break;  
00765     case ConfigureRequest: {
00766         WinClient *winclient = (WinClient *) 0;
00767 
00768         if ((winclient = searchWindow(e->xconfigurerequest.window))) {
00769             // already handled in FluxboxWindow::handleEvent
00770         } else { 
00771             grab();
00772 
00773             if (validateWindow(e->xconfigurerequest.window)) {
00774                 XWindowChanges xwc;
00775 
00776                 xwc.x = e->xconfigurerequest.x;
00777                 xwc.y = e->xconfigurerequest.y;
00778                 xwc.width = e->xconfigurerequest.width;
00779                 xwc.height = e->xconfigurerequest.height;
00780                 xwc.border_width = e->xconfigurerequest.border_width;
00781                 xwc.sibling = e->xconfigurerequest.above;
00782                 xwc.stack_mode = e->xconfigurerequest.detail;
00783 
00784                 XConfigureWindow(FbTk::App::instance()->display(),
00785                                  e->xconfigurerequest.window,
00786                                  e->xconfigurerequest.value_mask, &xwc);
00787             }
00788 
00789             ungrab();
00790         }
00791 
00792     }
00793         break;
00794     case MapRequest: {
00795 
00796 #ifdef DEBUG
00797         cerr<<"MapRequest for 0x"<<hex<<e->xmaprequest.window<<dec<<endl;
00798 #endif // DEBUG
00799 
00800         WinClient *winclient = searchWindow(e->xmaprequest.window);
00801         FluxboxWindow *win = 0;
00802 
00803         if (! winclient) {
00805             BScreen *scr = searchScreen(e->xmaprequest.parent);
00806             if (scr != 0)
00807                 win = scr->createWindow(e->xmaprequest.window);
00808             else
00809                 cerr<<"Fluxbox Warning! Could not find screen to map window on!"<<endl;
00810 
00811         } else {
00812             win = winclient->fbwindow();
00813         }
00814 
00815         // we don't handle MapRequest in FluxboxWindow::handleEvent
00816         if (win)
00817             win->mapRequestEvent(e->xmaprequest);
00818     }
00819         break;
00820     case MapNotify: {
00821         // handled directly in FluxboxWindow::handleEvent
00822     } break;
00823     case UnmapNotify:
00824         handleUnmapNotify(e->xunmap);
00825     break;  
00826     case MappingNotify:
00827         // Update stored modifier mapping
00828 #ifdef DEBUG
00829         cerr<<__FILE__<<"("<<__FUNCTION__<<"): MappingNotify"<<endl;
00830 #endif // DEBUG        
00831 
00832         FbTk::KeyUtil::instance().init(); // reinitialise the key utils
00833 
00834         break;
00835     case CreateNotify:
00836     break;
00837     case DestroyNotify: {
00838         WinClient *winclient = searchWindow(e->xdestroywindow.window);        
00839         if (winclient != 0) {
00840             FluxboxWindow *win = winclient->fbwindow();
00841             if (win)
00842                 win->destroyNotifyEvent(e->xdestroywindow);
00843 
00844             delete winclient;
00845                 
00846             if (win && win->numClients() == 0)
00847                 delete win;
00848         } 
00849 
00850     }
00851         break;
00852     case MotionNotify: 
00853         m_last_time = e->xmotion.time;
00854         break;
00855     case PropertyNotify: {
00856         m_last_time = e->xproperty.time;
00857         WinClient *winclient = searchWindow(e->xproperty.window);
00858         if (winclient == 0)
00859             break;
00860         // most of them are handled in FluxboxWindow::handleEvent
00861         // but some special cases like ewmh propertys needs to be checked 
00862         for (size_t i=0; i<m_atomhandler.size(); ++i) {
00863             if (m_atomhandler[i]->propertyNotify(*winclient, e->xproperty.atom))
00864                 break;
00865         }
00866     } break;
00867     case EnterNotify: {
00868         m_last_time = e->xcrossing.time;
00869         BScreen *screen = 0;
00870 
00871         if (e->xcrossing.mode == NotifyGrab)
00872             break;
00873 
00874         if ((e->xcrossing.window == e->xcrossing.root) &&
00875             (screen = searchScreen(e->xcrossing.window))) {
00876             screen->imageControl().installRootColormap();
00877 
00878         }
00879             
00880     } break;
00881     case LeaveNotify:
00882         m_last_time = e->xcrossing.time;
00883         break;
00884     case Expose:
00885         break;
00886     case KeyRelease:
00887     case KeyPress:
00888         handleKeyEvent(e->xkey);
00889     break;
00890     case ColormapNotify: {
00891         BScreen *screen = searchScreen(e->xcolormap.window);
00892 
00893         if (screen != 0) {
00894             screen->setRootColormapInstalled((e->xcolormap.state ==
00895                                               ColormapInstalled) ? true : false);
00896         }
00897     } break;
00898     case FocusIn: {
00899 
00900         // a grab is something of a pseudo-focus event, so we ignore
00901         // them, here we ignore some window receiving it
00902         if (e->xfocus.mode == NotifyGrab ||
00903             e->xfocus.detail == NotifyPointer ||
00904             e->xfocus.detail == NotifyInferior)
00905             break;
00906 
00907         WinClient *winclient = searchWindow(e->xfocus.window);
00908         if (winclient && m_focused_window != winclient)
00909             setFocusedWindow(winclient);
00910 
00911     } break;
00912     case FocusOut:{
00913 
00914         // and here we ignore some window losing the special grab focus
00915         if (e->xfocus.mode == NotifyGrab ||
00916             e->xfocus.detail == NotifyPointer ||
00917             e->xfocus.detail == NotifyInferior)
00918             break;
00919 
00920         WinClient *winclient = searchWindow(e->xfocus.window);
00921         if (winclient == 0 && FbTk::Menu::focused() == 0) {
00922 #ifdef DEBUG
00923             cerr<<__FILE__<<"("<<__FUNCTION__<<") Focus out is not a FluxboxWindow !!"<<endl;
00924 #endif // DEBUG
00925         } else if (winclient && winclient == m_focused_window)
00926             setFocusedWindow(0);
00927     }
00928     break;
00929     case ClientMessage:
00930         handleClientMessage(e->xclient);
00931     break;
00932     default: {
00933 #ifdef HAVE_RANDR
00934         if (e->type == m_randr_event_type) {
00935             // update root window size in screen
00936             BScreen *scr = searchScreen(e->xany.window);
00937             if (scr != 0)
00938                 scr->updateSize(); 
00939         }
00940 #endif // HAVE_RANDR
00941 
00942     }
00943 
00944     }
00945 }
00946 
00947 void Fluxbox::handleButtonEvent(XButtonEvent &be) {
00948 
00949     switch (be.type) {
00950     case ButtonPress: {
00951         m_last_time = be.time;
00952 
00953         BScreen *screen = searchScreen(be.window);
00954         if (screen == 0)
00955             break; // end case
00956 
00957         screen->hideMenus();
00958 
00959         // strip num/caps/scroll-lock and 
00960         // see if we're using any other modifier,
00961         // if we're we shouldn't show the root menu
00962         // this could happen if we're resizing aterm for instance
00963         if (FbTk::KeyUtil::instance().cleanMods(be.state) != 0)
00964             return;
00965 
00966         if (be.button == 1) {
00967             if (! screen->isRootColormapInstalled())
00968                 screen->imageControl().installRootColormap();
00969 
00970             if (screen->getWorkspacemenu().isVisible())
00971                 screen->getWorkspacemenu().hide();
00972             if (screen->getRootmenu().isVisible())
00973                 screen->getRootmenu().hide();
00974 
00975         } else if (be.button == 2) {
00976             int mx = be.x_root -
00977                 (screen->getWorkspacemenu().width() / 2);
00978             int my = be.y_root -
00979                 (screen->getWorkspacemenu().titleHeight() / 2);
00980     
00981             if (mx < 0) mx = 0;
00982             if (my < 0) my = 0;
00983 
00984             if (mx + screen->getWorkspacemenu().width() >
00985                 screen->width()) {
00986                 mx = screen->width()-1 -
00987                     screen->getWorkspacemenu().width() -
00988                     2*screen->getWorkspacemenu().fbwindow().borderWidth();
00989             }
00990 
00991             if (my + screen->getWorkspacemenu().height() >
00992                 screen->height()) {
00993                 my = screen->height()-1 -
00994                     screen->getWorkspacemenu().height() -
00995                     2*screen->getWorkspacemenu().fbwindow().borderWidth();
00996             }
00997             screen->getWorkspacemenu().move(mx, my);
00998 
00999             if (! screen->getWorkspacemenu().isVisible()) {
01000                 screen->getWorkspacemenu().removeParent();
01001                 screen->getWorkspacemenu().show();
01002             }
01003         } else if (be.button == 3) { 
01004             //calculate placement of root menu
01005             //and show/hide it              
01006             int mx = be.x_root -
01007                 (screen->getRootmenu().width() / 2);
01008             int my = be.y_root -
01009                 (screen->getRootmenu().titleHeight() / 2);
01010             int borderw = screen->getRootmenu().fbwindow().borderWidth();
01011 
01012             if (mx < 0) mx = 0;
01013             if (my < 0) my = 0;
01014             
01015             if (mx + screen->getRootmenu().width() + 2*borderw > screen->width()) {
01016                 mx = screen->width() -
01017                     screen->getRootmenu().width() -
01018                     2*borderw;
01019             }
01020 
01021             if (my + screen->getRootmenu().height() + 2*borderw >
01022                 screen->height()) {
01023                 my = screen->height() -
01024                     screen->getRootmenu().height() -
01025                     2*borderw;
01026             }
01027             screen->getRootmenu().move(mx, my);
01028 
01029             if (! screen->getRootmenu().isVisible()) {
01030                 checkMenu();
01031                 screen->getRootmenu().show();
01032             }
01033         } else if (screen->isDesktopWheeling() && be.button == 4) {
01034             screen->nextWorkspace(1);
01035         } else if (screen->isDesktopWheeling() && be.button == 5) {
01036             screen->prevWorkspace(1);
01037         }
01038         
01039     } break;
01040     case ButtonRelease:
01041         m_last_time = be.time;
01042         break;  
01043     default:
01044         break;
01045     }
01046 }
01047 
01048 void Fluxbox::handleUnmapNotify(XUnmapEvent &ue) {
01049 
01050         
01051     WinClient *winclient = 0;
01052     
01053     BScreen *screen = searchScreen(ue.event);
01054     
01055     if ( ue.event != ue.window && (screen != 0 || !ue.send_event))
01056         return;
01057 
01058     if ((winclient = searchWindow(ue.window)) != 0) {
01059 
01060         if (winclient != 0) {
01061             FluxboxWindow *win = winclient->fbwindow();
01062 
01063             if (!win) {
01064                 delete winclient;
01065                 return;
01066             }
01067 
01068             // this should delete client and adjust m_focused_window if necessary
01069             win->unmapNotifyEvent(ue); 
01070 
01071             winclient = 0; // it's invalid now when win destroyed the client
01072 
01073             // finally destroy window if empty
01074             if (win->numClients() == 0) {
01075                 delete win;
01076                 win = 0;
01077             }
01078         }  
01079     }
01080 
01081 }
01082 
01086 void Fluxbox::handleClientMessage(XClientMessageEvent &ce) {
01087 #ifdef DEBUG
01088     char * atom = 0;
01089     if (ce.message_type)
01090         atom = XGetAtomName(FbTk::App::instance()->display(), ce.message_type);
01091 
01092     cerr<<__FILE__<<"("<<__LINE__<<"): ClientMessage. data.l[0]=0x"<<hex<<ce.data.l[0]<<
01093     "  message_type=0x"<<ce.message_type<<dec<<" = \""<<atom<<"\""<<endl;
01094 
01095     if (ce.message_type && atom) XFree((char *) atom);
01096 
01097 #endif // DEBUG
01098 
01099     if (ce.format != 32)
01100         return;
01101     
01102     if (ce.message_type == m_fbatoms->getWMChangeStateAtom()) {
01103         WinClient *winclient = searchWindow(ce.window);
01104         if (! winclient || !winclient->fbwindow() || ! winclient->validateClient())
01105             return;
01106 
01107         if (ce.data.l[0] == IconicState)
01108             winclient->fbwindow()->iconify();
01109         if (ce.data.l[0] == NormalState)
01110             winclient->fbwindow()->deiconify();
01111     } else if (ce.message_type == m_fbatoms->getFluxboxChangeWorkspaceAtom()) {
01112         BScreen *screen = searchScreen(ce.window);
01113 
01114         if (screen && ce.data.l[0] >= 0 &&
01115             ce.data.l[0] < (signed)screen->getCount())
01116             screen->changeWorkspaceID(ce.data.l[0]);
01117                 
01118     } else if (ce.message_type == m_fbatoms->getFluxboxChangeWindowFocusAtom()) {
01119         WinClient *winclient = searchWindow(ce.window);
01120         if (winclient) {
01121             FluxboxWindow *win = winclient->fbwindow();
01122             if (win && win->isVisible())
01123                 win->setCurrentClient(*winclient, true);
01124         }
01125     } else if (ce.message_type == m_fbatoms->getFluxboxCycleWindowFocusAtom()) {
01126         BScreen *screen = searchScreen(ce.window);
01127 
01128         if (screen) {
01129             if (! ce.data.l[0])
01130                 screen->prevFocus();
01131             else
01132                 screen->nextFocus();
01133         }
01134     } else if (ce.message_type == m_fbatoms->getFluxboxChangeAttributesAtom()) {
01135         WinClient *winclient = searchWindow(ce.window);
01136         FluxboxWindow *win = 0;
01137         if (winclient && (win = winclient->fbwindow()) && winclient->validateClient()) {
01138             FluxboxWindow::BlackboxHints net;
01139             net.flags = ce.data.l[0];
01140             net.attrib = ce.data.l[1];
01141             net.workspace = ce.data.l[2];
01142             net.stack = ce.data.l[3];
01143             net.decoration = static_cast<int>(ce.data.l[4]);
01144             win->changeBlackboxHints(net);
01145         }
01146     } else {
01147         WinClient *winclient = searchWindow(ce.window);
01148         BScreen *screen = searchScreen(ce.window);
01149         // note: we dont need screen nor winclient to be non-null, 
01150         // it's up to the atomhandler to check that
01151         for (size_t i=0; i<m_atomhandler.size(); ++i) {
01152             m_atomhandler[i]->checkClientMessage(ce, screen, winclient);
01153         }
01154 
01155     }
01156 }
01157 
01161 void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
01162     
01163     if (keyScreen() == 0 || mouseScreen() == 0)
01164         return;
01165 
01166     
01167     switch (ke.type) {
01168     case KeyPress:
01169         m_key->doAction(ke);
01170     break;
01171     case KeyRelease: {
01172         // we ignore most key releases unless we need to use
01173         // a release to stop something (e.g. window cycling).
01174 
01175         // we notify if _all_ of the watched modifiers are released
01176         if (m_watching_screen && m_watch_keyrelease) {
01177             // mask the mod of the released key out
01178             // won't mask anything if it isn't a mod
01179             ke.state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode);
01180             
01181             if ((m_watch_keyrelease & ke.state) == 0) {
01182                 
01183                 m_watching_screen->notifyReleasedKeys(ke);
01184                 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
01185                 
01186                 // once they are released, we drop the watch
01187                 m_watching_screen = 0;
01188                 m_watch_keyrelease = 0;
01189             }
01190         }
01191 
01192         break;
01193     }   
01194     default:
01195         break;
01196     }
01197     
01198     
01199 }
01200 
01202 void Fluxbox::handleSignal(int signum) {
01203     I18n *i18n = I18n::instance();
01204     static int re_enter = 0;
01205 
01206     switch (signum) {
01207     case SIGCHLD: // we don't want the child process to kill us
01208         waitpid(-1, 0, WNOHANG | WUNTRACED);
01209         break;
01210     case SIGHUP:
01211         load_rc();
01212         break;
01213     case SIGUSR1:
01214         reload_rc();
01215         break;
01216     case SIGUSR2:
01217         rereadMenu();
01218         break;
01219     case SIGSEGV:
01220         abort();
01221         break;
01222     case SIGFPE:
01223     case SIGINT:
01224     case SIGTERM:
01225         shutdown();
01226         break;
01227     default:
01228         fprintf(stderr,
01229                 i18n->getMessage(
01230                     FBNLS::BaseDisplaySet, FBNLS::BaseDisplaySignalCaught,
01231                     "%s:    signal %d caught\n"),
01232                 m_argv[0], signum);
01233 
01234         if (! m_starting && ! re_enter) {
01235             re_enter = 1;
01236             fprintf(stderr,
01237                     i18n->getMessage(
01238                         FBNLS::BaseDisplaySet, FBNLS::BaseDisplayShuttingDown,
01239                         "shutting down\n"));
01240             shutdown();
01241         }
01242 
01243             
01244         fprintf(stderr,
01245                 i18n->getMessage(
01246                     FBNLS::BaseDisplaySet, FBNLS::BaseDisplayAborting,
01247                     "aborting... dumping core\n"));
01248         abort();
01249         break;
01250     }
01251 }
01252 
01253 
01254 void Fluxbox::update(FbTk::Subject *changedsub) {
01255     //TODO: fix signaling, this does not look good
01256     if (typeid(*changedsub) == typeid(FluxboxWindow::WinSubject)) {
01257         FluxboxWindow::WinSubject *winsub = dynamic_cast<FluxboxWindow::WinSubject *>(changedsub);
01258         FluxboxWindow &win = winsub->win();
01259         if ((&(win.hintSig())) == changedsub) { // hint signal
01260             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01261                 if (m_atomhandler[i]->update())
01262                     m_atomhandler[i]->updateHints(win);
01263             }
01264         } else if ((&(win.stateSig())) == changedsub) { // state signal
01265             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01266                 if (m_atomhandler[i]->update())
01267                     m_atomhandler[i]->updateState(win);
01268             }
01269             // if window changed to iconic state
01270             // add to icon list
01271             if (win.isIconic()) {
01272                 Workspace *space = win.screen().getWorkspace(win.workspaceNumber());
01273                 if (space != 0)
01274                     space->removeWindow(&win);
01275                 win.screen().addIcon(&win);
01276             }
01277 
01278             if (win.isStuck()) {
01279                 // if we're sticky then reassociate window
01280                 // to all workspaces
01281                 BScreen &scr = win.screen();
01282                 if (scr.currentWorkspaceID() != win.workspaceNumber()) {
01283                     scr.reassociateWindow(&win, 
01284                                           scr.currentWorkspaceID(),
01285                                           true);
01286                 }
01287             }
01288         } else if ((&(win.layerSig())) == changedsub) { // layer signal
01289 
01290             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01291                 if (m_atomhandler[i]->update())
01292                     m_atomhandler[i]->updateLayer(win);
01293             }
01294         } else if ((&(win.dieSig())) == changedsub) { // window death signal
01295             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01296                 if (m_atomhandler[i]->update())
01297                     m_atomhandler[i]->updateFrameClose(win);
01298             }
01299             // make sure each workspace get this 
01300             BScreen &scr = win.screen();
01301             scr.removeWindow(&win);
01302             if (m_focused_window == &win.winClient())
01303                 m_focused_window = 0;
01304 
01305         } else if ((&(win.workspaceSig())) == changedsub) {  // workspace signal
01306             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01307                 if (m_atomhandler[i]->update())
01308                     m_atomhandler[i]->updateWorkspace(win);
01309             }            
01310         } else {
01311 #ifdef DEBUG
01312             cerr<<__FILE__<<"("<<__LINE__<<"): WINDOW uncought signal from "<<&win<<endl;
01313 #endif // DEBUG
01314         }
01315         
01316     } else if (typeid(*changedsub) == typeid(BScreen::ScreenSubject)) {
01317         BScreen::ScreenSubject *subj = dynamic_cast<BScreen::ScreenSubject *>(changedsub);
01318         BScreen &screen = subj->screen();
01319         if ((&(screen.workspaceCountSig())) == changedsub) {
01320             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01321                 if (m_atomhandler[i]->update())
01322                     m_atomhandler[i]->updateWorkspaceCount(screen);
01323             }
01324         } else if ((&(screen.workspaceNamesSig())) == changedsub) {
01325             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01326                 if (m_atomhandler[i]->update())
01327                     m_atomhandler[i]->updateWorkspaceNames(screen);
01328             }
01329         } else if ((&(screen.currentWorkspaceSig())) == changedsub) {
01330             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01331                 if (m_atomhandler[i]->update())
01332                     m_atomhandler[i]->updateCurrentWorkspace(screen);
01333             }
01334         } else if ((&(screen.clientListSig())) == changedsub) {
01335             for (size_t i=0; i<m_atomhandler.size(); ++i) {
01336                 if (m_atomhandler[i]->update())
01337                     m_atomhandler[i]->updateClientList(screen);
01338             }
01339         }
01340     } else if (typeid(*changedsub) == typeid(WinClient::WinClientSubj)) {
01341 
01342         WinClient::WinClientSubj *subj = dynamic_cast<WinClient::WinClientSubj *>(changedsub);
01343         WinClient &client = subj->winClient();
01344 
01345         // TODO: don't assume it is diesig (need to fix as soon as another signal appears)
01346         for (size_t i=0; i<m_atomhandler.size(); ++i) {
01347             if (m_atomhandler[i]->update())
01348                 m_atomhandler[i]->updateClientClose(client);
01349         }
01350 
01351         BScreen &screen = client.screen();
01352         
01353         screen.removeClient(client);
01354         // finaly send notify signal
01355         screen.updateNetizenWindowDel(client.window());
01356 
01357         if (m_focused_window == &client) 
01358             revertFocus(screen);
01359 
01360         // failed to revert focus?
01361         if (m_focused_window == &client)
01362             m_focused_window = 0;
01363     }
01364 }
01365 
01366 void Fluxbox::attachSignals(FluxboxWindow &win) {
01367     win.hintSig().attach(this);
01368     win.stateSig().attach(this);
01369     win.workspaceSig().attach(this);
01370     win.layerSig().attach(this);
01371     win.dieSig().attach(this);
01372     for (size_t i=0; i<m_atomhandler.size(); ++i) {
01373         m_atomhandler[i]->setupFrame(win);
01374     }
01375 }
01376 
01377 void Fluxbox::attachSignals(WinClient &winclient) {
01378     winclient.dieSig().attach(this);
01379 
01380     for (size_t i=0; i<m_atomhandler.size(); ++i) {
01381         m_atomhandler[i]->setupClient(winclient);
01382     }
01383 }
01384 
01385 BScreen *Fluxbox::searchScreen(Window window) {
01386     ScreenList::iterator it = m_screen_list.begin();
01387     ScreenList::iterator it_end = m_screen_list.end();
01388     for (; it != it_end; ++it) {
01389         if (*it && (*it)->rootWindow() == window)
01390             return (*it);
01391     }
01392 
01393     return 0;
01394 }
01395 
01396 void Fluxbox::addAtomHandler(AtomHandler *atomh) {
01397     for (unsigned int handler = 0; handler < m_atomhandler.size(); handler++) {
01398         if (m_atomhandler[handler] == atomh) 
01399             return;
01400     }
01401     m_atomhandler.push_back(atomh);
01402 }
01403 
01404 void Fluxbox::removeAtomHandler(AtomHandler *atomh) {
01405     std::vector<AtomHandler *>::iterator it = m_atomhandler.begin();        
01406     for (; it != m_atomhandler.end(); ++it) {
01407         if (*it == atomh) {
01408             m_atomhandler.erase(it);
01409             return;
01410         }
01411     }
01412 }
01413 
01414 WinClient *Fluxbox::searchWindow(Window window) {
01415     std::map<Window, WinClient *>::iterator it = m_window_search.find(window);
01416     if (it != m_window_search.end())
01417         return it->second;
01418 
01419     std::map<Window, FluxboxWindow *>::iterator git = m_window_search_group.find(window);
01420     return git == m_window_search_group.end() ? 0 : &git->second->winClient();
01421 }
01422 
01423 
01424 /* Not implemented until we know how it'll be used
01425  * Recall that this refers to ICCCM groups, not fluxbox tabgroups
01426  * See ICCCM 4.1.11 for details
01427  */
01428 /*
01429 WinClient *Fluxbox::searchGroup(Window window) {
01430 }
01431 */
01432 
01433 void Fluxbox::saveWindowSearch(Window window, WinClient *data) {
01434     m_window_search[window] = data;
01435 }
01436 
01437 /* some windows relate to the whole group */
01438 void Fluxbox::saveWindowSearchGroup(Window window, FluxboxWindow *data) {
01439     m_window_search_group[window] = data;
01440 }
01441 
01442 void Fluxbox::saveGroupSearch(Window window, WinClient *data) {
01443     m_group_search.insert(pair<Window, WinClient *>(window, data));
01444 }
01445 
01446 
01447 void Fluxbox::removeWindowSearch(Window window) {
01448     m_window_search.erase(window);
01449 }
01450 
01451 void Fluxbox::removeWindowSearchGroup(Window window) {
01452     m_window_search_group.erase(window);
01453 }
01454 
01455 void Fluxbox::removeGroupSearch(Window window) {
01456     m_group_search.erase(window);
01457 }
01458 
01460 void Fluxbox::restart(const char *prog) {
01461     shutdown();
01462 
01463     if (prog) {
01464         execlp(prog, prog, 0);
01465         perror(prog);
01466     }
01467 
01468     // fall back in case the above execlp doesn't work
01469     execvp(m_argv[0], m_argv);
01470     execvp(StringUtil::basename(m_argv[0]).c_str(), m_argv);
01471 }
01472 
01474 void Fluxbox::shutdown() {
01475 
01476     XSetInputFocus(FbTk::App::instance()->display(), PointerRoot, None, CurrentTime);
01477 
01478     //send shutdown to all screens
01479     for_each(m_screen_list.begin(), m_screen_list.end(), mem_fun(&BScreen::shutdown));
01480 
01481     m_shutdown = true;
01482     sync(false);
01483 
01484 }
01485 
01487 void Fluxbox::save_rc() {
01488 
01489     XrmDatabase new_blackboxrc = 0;
01490     
01491     char rc_string[1024];
01492 
01493     string dbfile(getRcFilename());
01494     
01495     if (dbfile.size() != 0) {
01496         m_resourcemanager.save(dbfile.c_str(), dbfile.c_str());
01497         m_screen_rm.save(dbfile.c_str(), dbfile.c_str());
01498     } else
01499         cerr<<"database filename is invalid!"<<endl;
01500     
01501     ScreenList::iterator it = m_screen_list.begin();
01502     ScreenList::iterator it_end = m_screen_list.end();
01503 
01504     //Save screen resources
01505 
01506     for (; it != it_end; ++it) {
01507         BScreen *screen = *it;
01508         int screen_number = screen->screenNumber();
01509 
01510         // these are static, but may not be saved in the users resource file,
01511         // writing these resources will allow the user to edit them at a later
01512         // time... but loading the defaults before saving allows us to rewrite the
01513         // users changes...
01514 
01515         // write out the users workspace names
01516         sprintf(rc_string, "session.screen%d.workspaceNames: ", screen_number);
01517         string workspaces_string(rc_string);
01518 
01519         for (unsigned int workspace=0; workspace < screen->getCount(); workspace++) {
01520             if (screen->getWorkspace(workspace)->name().size()!=0)
01521                 workspaces_string.append(screen->getWorkspace(workspace)->name());
01522             else
01523                 workspaces_string.append("Null");
01524             workspaces_string.append(",");
01525         }
01526 
01527         XrmPutLineResource(&new_blackboxrc, workspaces_string.c_str());
01528     
01529     }
01530 
01531     XrmDatabase old_blackboxrc = XrmGetFileDatabase(dbfile.c_str());
01532 
01533     XrmMergeDatabases(new_blackboxrc, &old_blackboxrc); //merge database together
01534     XrmPutFileDatabase(old_blackboxrc, dbfile.c_str());
01535     XrmDestroyDatabase(old_blackboxrc);
01536 #ifdef DEBUG
01537     cerr<<__FILE__<<"("<<__LINE__<<"): ------------ SAVING DONE"<<endl; 
01538 #endif // DEBUG
01539 }
01540 
01542 string Fluxbox::getRcFilename() {
01543  
01544     if (m_rc_file.size() == 0) { // set default filename
01545         string defaultfile(getenv("HOME") + string("/.") + m_RC_PATH + string("/") + m_RC_INIT_FILE);
01546         return defaultfile;
01547     }
01548 
01549     return m_rc_file;
01550 }
01551 
01553 void Fluxbox::getDefaultDataFilename(char *name, string &filename) {
01554     filename = string(getenv("HOME") + string("/.") + m_RC_PATH + string("/") + name);
01555 }
01556 
01558 void Fluxbox::load_rc() {
01559     
01560     //get resource filename
01561     string dbfile(getRcFilename());
01562 
01563     if (dbfile.size() != 0) {
01564         if (!m_resourcemanager.load(dbfile.c_str())) {
01565             cerr<<"Failed to load database:"<<dbfile<<endl;
01566             cerr<<"Trying with: "<<DEFAULT_INITFILE<<endl;
01567             if (!m_resourcemanager.load(DEFAULT_INITFILE))
01568                 cerr<<"Failed to load database: "<<DEFAULT_INITFILE<<endl;
01569         }
01570     } else {
01571         if (!m_resourcemanager.load(DEFAULT_INITFILE))
01572             cerr<<"Failed to load database: "<<DEFAULT_INITFILE<<endl;
01573     }
01574     
01575     if (m_rc_menufile->size() == 0)
01576         m_rc_menufile.setDefaultValue();
01577  
01578     if (m_rc_slitlistfile->size() != 0) {
01579         *m_rc_slitlistfile = StringUtil::expandFilename(*m_rc_slitlistfile);
01580     } else {
01581         string filename;
01582         getDefaultDataFilename("slitlist", filename);
01583         m_rc_slitlistfile.setFromString(filename.c_str());
01584     }
01585 
01586     if (*m_rc_colors_per_channel < 2)
01587         *m_rc_colors_per_channel = 2;
01588     else if (*m_rc_colors_per_channel > 6)
01589         *m_rc_colors_per_channel = 6;
01590 
01591     if (m_rc_stylefile->size() == 0)
01592         *m_rc_stylefile = DEFAULTSTYLE;
01593     else // expand tilde
01594         *m_rc_stylefile = StringUtil::expandFilename(*m_rc_stylefile);
01595 
01596 
01597     // expand tilde
01598     *m_rc_groupfile = StringUtil::expandFilename(*m_rc_groupfile);
01599 
01600 #ifdef DEBUG
01601     cerr<<__FILE__<<": Loading groups ("<<*m_rc_groupfile<<")"<<endl;
01602 #endif // DEBUG
01603     if (!Workspace::loadGroups(*m_rc_groupfile)) {
01604         cerr<<"Failed to load groupfile: "<<*m_rc_groupfile<<endl;
01605     }
01606 }
01607 
01608 void Fluxbox::load_rc(BScreen &screen) {
01609     //get resource filename
01610     string dbfile(getRcFilename());
01611     
01612     XrmDatabaseHelper database;
01613 
01614     database = XrmGetFileDatabase(dbfile.c_str());
01615     if (database==0)
01616         database = XrmGetFileDatabase(DEFAULT_INITFILE);
01617         
01618     XrmValue value;
01619     char *value_type, name_lookup[1024], class_lookup[1024];
01620     int screen_number = screen.screenNumber();
01621 
01622 
01623     screen.removeWorkspaceNames();
01624     
01625     sprintf(name_lookup, "session.screen%d.workspaceNames", screen_number);
01626     sprintf(class_lookup, "Session.Screen%d.WorkspaceNames", screen_number);
01627     if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
01628                        &value)) {
01629 #ifdef DEBUG
01630         cerr<<__FILE__<<"("<<__FUNCTION__<<"): Workspaces="<<
01631             screen.getNumberOfWorkspaces()<<endl;
01632 #endif // DEBUG
01633         char *search = StringUtil::strdup(value.addr);
01634 
01635         int i;
01636         for (i = 0; i < screen.getNumberOfWorkspaces(); i++) {
01637             char *nn;
01638 
01639             if (! i) nn = strtok(search, ",");
01640             else nn = strtok(0, ",");
01641 
01642             if (nn)
01643                 screen.addWorkspaceName(nn);    
01644             else break;
01645             
01646         }
01647 
01648         delete [] search;
01649     }
01650 
01651     FbTk::Image::removeAllSearchPaths();
01652     sprintf(name_lookup, "session.screen%d.imageSearchPath", screen_number);
01653     sprintf(class_lookup, "Session.Screen%d.imageSearchPath", screen_number);
01654     if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
01655                        &value) && value.addr) {
01656         std::vector<std::string> paths;        
01657         StringUtil::stringtok(paths, value.addr, ", ");
01658         for (unsigned int i=0; i<paths.size(); ++i)
01659             FbTk::Image::addSearchPath(paths[i]);
01660     }
01661     
01662     if (dbfile.size() != 0) {
01663         if (!m_screen_rm.load(dbfile.c_str())) {
01664             cerr<<"Failed to load database:"<<dbfile<<endl;
01665             cerr<<"Trying with: "<<DEFAULT_INITFILE<<endl;
01666             if (!m_screen_rm.load(DEFAULT_INITFILE))
01667                 cerr<<"Failed to load database: "<<DEFAULT_INITFILE<<endl;
01668         }
01669     } else {
01670         if (!m_screen_rm.load(DEFAULT_INITFILE))
01671             cerr<<"Failed to load database: "<<DEFAULT_INITFILE<<endl;
01672     }
01673 
01674 }
01675 
01676 void Fluxbox::loadRootCommand(BScreen &screen)  {
01677  
01678     string dbfile(getRcFilename());
01679 
01680     XrmDatabaseHelper database(dbfile.c_str());
01681     if (!*database) 
01682         database = XrmGetFileDatabase(DEFAULT_INITFILE);
01683 
01684     XrmValue value;
01685     char *value_type, name_lookup[1024], class_lookup[1024];
01686     sprintf(name_lookup, "session.screen%d.rootCommand", screen.screenNumber());
01687     sprintf(class_lookup, "Session.Screen%d.RootCommand", screen.screenNumber());
01688     if (XrmGetResource(*database, name_lookup, class_lookup, &value_type,
01689                        &value)) {                                        
01690         screen.saveRootCommand(value.addr==0 ?