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 ? "": value.addr);
01691     } else
01692         screen.saveRootCommand("");     
01693     
01694 }
01695 
01696 void Fluxbox::reload_rc() {
01697     load_rc();
01698     reconfigure();
01699 }
01700 
01701 
01702 void Fluxbox::reconfigure() {
01703     m_reconfigure_wait = true;
01704     m_reconfig_timer.start();
01705 }
01706 
01707 
01708 void Fluxbox::real_reconfigure() {
01709 
01710     XrmDatabase new_blackboxrc = (XrmDatabase) 0;
01711 
01712     string dbfile(getRcFilename());
01713     XrmDatabase old_blackboxrc = XrmGetFileDatabase(dbfile.c_str());
01714 
01715     XrmMergeDatabases(new_blackboxrc, &old_blackboxrc);
01716     XrmPutFileDatabase(old_blackboxrc, dbfile.c_str());
01717     
01718     if (old_blackboxrc)
01719         XrmDestroyDatabase(old_blackboxrc);
01720 
01721     // reconfigure all screens
01722     for_each(m_screen_list.begin(), m_screen_list.end(), mem_fun(&BScreen::reconfigure));
01723 
01724     //reconfigure keys
01725     m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());
01726 
01727 
01728 }
01729 
01730 
01731 bool Fluxbox::menuTimestampsChanged() const {
01732     std::list<MenuTimestamp *>::const_iterator it = m_menu_timestamps.begin();
01733     std::list<MenuTimestamp *>::const_iterator it_end = m_menu_timestamps.end();
01734     for (; it != it_end; ++it) {
01735         struct stat buf;
01736 
01737         if (! stat((*it)->filename.c_str(), &buf)) {
01738             if ((*it)->timestamp != buf.st_ctime)
01739                 return true;
01740         } else
01741             return true;
01742     }
01743 
01744     // no timestamp changed
01745     return false;
01746 }
01747 
01748 void Fluxbox::checkMenu() {
01749     if (menuTimestampsChanged())
01750         rereadMenu();
01751 }
01752 
01753 void Fluxbox::hideExtraMenus(BScreen &screen) {
01754 
01755 #ifdef USE_TOOLBAR
01756         // hide toolbar that matches screen
01757         for (size_t toolbar = 0; toolbar < m_toolbars.size(); ++toolbar) {
01758             if (&(m_toolbars[toolbar]->screen()) == &screen)
01759                 m_toolbars[toolbar]->menu().hide();
01760         }
01761 
01762 #endif // USE_TOOLBAR
01763 
01764 }
01765 
01766 void Fluxbox::rereadMenu() {
01767     m_reread_menu_wait = true;
01768     m_reconfig_timer.start();
01769 }
01770 
01771 
01772 void Fluxbox::real_rereadMenu() {
01773     std::list<MenuTimestamp *>::iterator it = m_menu_timestamps.begin();
01774     std::list<MenuTimestamp *>::iterator it_end = m_menu_timestamps.end();
01775     for (; it != it_end; ++it)
01776         delete *it;
01777 
01778     m_menu_timestamps.erase(m_menu_timestamps.begin(), m_menu_timestamps.end());
01779     for_each(m_screen_list.begin(), m_screen_list.end(), mem_fun(&BScreen::rereadMenu));
01780 }
01781 
01782 void Fluxbox::saveMenuFilename(const char *filename) {
01783     if (filename == 0)
01784         return;
01785 
01786     bool found = false;
01787 
01788     std::list<MenuTimestamp *>::iterator it = m_menu_timestamps.begin();
01789     std::list<MenuTimestamp *>::iterator it_end = m_menu_timestamps.end();
01790     for (; it != it_end; ++it) {
01791         if ((*it)->filename == filename) {
01792             found = true; 
01793             break; 
01794         }
01795     }
01796 
01797     if (! found) {
01798         struct stat buf;
01799 
01800         if (! stat(filename, &buf)) {
01801             MenuTimestamp *ts = new MenuTimestamp;
01802 
01803             ts->filename = filename;
01804             ts->timestamp = buf.st_ctime;
01805 
01806             m_menu_timestamps.push_back(ts);
01807         }
01808     }
01809 }
01810 
01811 void Fluxbox::clearMenuFilenames() {
01812     std::list<MenuTimestamp *>::iterator it = m_menu_timestamps.begin();
01813     std::list<MenuTimestamp *>::iterator it_end = m_menu_timestamps.end();
01814     for (; it != it_end; ++it)
01815          delete *it;
01816 
01817     m_menu_timestamps.erase(m_menu_timestamps.begin(), m_menu_timestamps.end());
01818 }
01819 
01820 void Fluxbox::timed_reconfigure() {
01821     if (m_reconfigure_wait)
01822         real_reconfigure();
01823 
01824     if (m_reread_menu_wait)
01825         real_rereadMenu();
01826 
01827     m_reconfigure_wait = m_reread_menu_wait = false;
01828 }
01829 
01830 // set focused window
01831 void Fluxbox::setFocusedWindow(WinClient *client) {
01832     // already focused
01833     if (m_focused_window == client) {
01834 #ifdef DEBUG
01835         cerr<<"Focused window already win"<<endl;
01836 #endif // DEBUG
01837         return;
01838     }
01839 #ifdef DEBUG
01840     cerr<<"Setting Focused window = "<<client<<endl;
01841     cerr<<"Current Focused window = "<<m_focused_window<<endl;
01842     cerr<<"------------------"<<endl;
01843 #endif // DEBUG    
01844     BScreen *old_screen = 0, *screen = 0;
01845     WinClient *old_client = 0;
01846     Workspace *old_wkspc = 0;
01847     
01848     if (m_focused_window != 0) {
01849         // check if m_focused_window is valid
01850         bool found = false;
01851         std::map<Window, WinClient *>::iterator it = m_window_search.begin();
01852         std::map<Window, WinClient *>::iterator it_end = m_window_search.end();
01853         for (; it != it_end; ++it) {
01854             if (it->second == m_focused_window) {
01855                 // we found it, end loop
01856                 found = true;
01857                 break;
01858             }
01859         }
01860 
01861         if (!found) {
01862             m_focused_window = 0;
01863         } else {
01864             old_client = m_focused_window;
01865             old_screen = &old_client->screen();
01866 
01867             if (old_client->fbwindow()) {
01868                 FluxboxWindow *old_win = old_client->fbwindow();
01869                 old_wkspc = old_screen->getWorkspace(old_win->workspaceNumber());
01870 
01871                 if (!client || client->fbwindow() != old_win)
01872                     old_win->setFocusFlag(false);
01873             }
01874         }
01875     }
01876 
01877     if (client && client->fbwindow() && !client->fbwindow()->isIconic()) {
01878         FluxboxWindow *win = client->fbwindow();
01879         // make sure we have a valid win pointer with a valid screen
01880         ScreenList::iterator winscreen = 
01881             std::find(m_screen_list.begin(), m_screen_list.end(),
01882                       &client->screen());
01883         if (winscreen == m_screen_list.end()) {
01884             m_focused_window = 0; // the window pointer wasn't valid, mark no window focused
01885         } else {
01886             screen = *winscreen;
01887             m_focused_window = client;     // update focused window
01888             win->setCurrentClient(*client, false); // don't setinputfocus
01889             win->setFocusFlag(true); // set focus flag
01890         }
01891 
01892     } else
01893         m_focused_window = 0;
01894 
01895 
01896 
01897     if (screen != 0)
01898         screen->updateNetizenWindowFocus();
01899 
01900     if (old_screen && old_screen != screen)
01901         old_screen->updateNetizenWindowFocus();
01902 
01903 }
01904 
01915 void Fluxbox::revertFocus(BScreen &screen) {
01916     // Relevant resources:
01917     // resource.focus_last = whether we focus last focused when changing workspace
01918     // BScreen::FocusModel = sloppy, click, whatever
01919     WinClient *next_focus = screen.getLastFocusedWindow(screen.currentWorkspaceID());
01920 
01921     // if setting focus fails, or isn't possible, fallback correctly
01922     if (!(next_focus && next_focus->fbwindow() &&
01923           next_focus->fbwindow()->setCurrentClient(*next_focus, true))) {
01924         setFocusedWindow(0); // so we don't get dangling m_focused_window pointer
01925         switch (screen.getFocusModel()) {
01926         case BScreen::SLOPPYFOCUS:
01927         case BScreen::SEMISLOPPYFOCUS:
01928             XSetInputFocus(FbTk::App::instance()->display(), 
01929                            PointerRoot, None, CurrentTime);
01930             break;
01931         case BScreen::CLICKTOFOCUS:
01932             screen.rootWindow().setInputFocus(RevertToPointerRoot, CurrentTime);
01933             break;
01934         }
01935     }
01936 }
01937 
01938 
01939 
01940 void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) {
01941     if (mods == 0) {
01942         cerr<<"WARNING: attempt to grab without modifiers!"<<endl;
01943         return;
01944     }
01945     m_watching_screen = &screen;
01946     m_watch_keyrelease = mods;
01947     XGrabKeyboard(FbTk::App::instance()->display(),
01948                   screen.rootWindow().window(), True, 
01949                   GrabModeAsync, GrabModeAsync, CurrentTime);
01950 }

Fluxbox CVS-Jan-2003




      



Got comments about the page? Send them to webmaster.
If you have general Fluxbox related questions ask them on our irc channel or mailing lists.

Show Source








Designed by aLEczapKA