all repos — fluxbox @ 7f45bae4629f345906e96c1fcb3a3d1e49c36382

custom fork of the fluxbox windowmanager

Merge branch 'master' of fluxbox@git.fluxbox.org:fluxbox
Henrik Kinnunen fluxgen@fluxbox.org
commit

7f45bae4629f345906e96c1fcb3a3d1e49c36382

parent

5ecebae4770cbe7e4feea46d2c074a818f1c9662

M ChangeLogChangeLog

@@ -1,5 +1,13 @@

(Format: Year/Month/Day) Changes for 1.1 +*08/05/13: + * Only reload custom menus when necessary (Mark) + FbCommands.cc/hh +*08/05/12: + * Only reload the keys file if the contents have changed (Mark) + Keys.cc/hh fluxbox.cc/hh + * Modifying the apps file no longer requires a reconfigure (Mark) + Remember.cc/hh *08/05/09: * Made tooltip in toolbar update when the title changes (Henrik) Tooltip.cc/hh, Screen.cc/cc, OSDWindow.hh
M src/FbCommands.ccsrc/FbCommands.cc

@@ -73,16 +73,11 @@ namespace {

void showMenu(const BScreen &screen, FbTk::Menu &menu) { - // special case for root menu - if (&menu == &screen.rootMenu()) { - Fluxbox* fb = Fluxbox::instance(); - if(fb->menuTimestampsChanged()) { - // we dont show the menu here because fluxbox - // will bring up the rootmenu after the timed - // reread of the menu - fb->rereadMenu(true); - return; - } + // check if menu has changed + if (typeid(menu) == typeid(FbMenu)) { + FbMenu *fbmenu = static_cast<FbMenu *>(&menu); + if (fbmenu->reloadHelper()) + fbmenu->reloadHelper()->checkReload(); } Window root_ret; // not used

@@ -335,8 +330,8 @@ if (typeid(**it) == typeid(FluxboxWindow) && m_pat.match(**it))

m_list.push_back(static_cast<FluxboxWindow *>(*it)); } - m_menu = new ClientMenu(*screen, m_list, 0); - ::showMenu(*screen, **m_menu); + m_menu.reset(new ClientMenu(*screen, m_list, 0)); + ::showMenu(*screen, *m_menu.get()); } REGISTER_COMMAND_WITH_ARGS(custommenu, FbCommands::ShowCustomMenuCmd, void);

@@ -347,11 +342,22 @@ void ShowCustomMenuCmd::execute() {

BScreen *screen = Fluxbox::instance()->mouseScreen(); if (screen == 0) return; - m_menu = MenuCreator::createFromFile(custom_menu_file, - screen->screenNumber()); - if (!m_menu.get()) - return; - ::showMenu(*screen, **m_menu); + + if (!m_menu.get() || screen->screenNumber() != m_menu->screenNumber()) { + m_menu.reset(screen->createMenu("")); + m_menu->setReloadHelper(new FbTk::AutoReloadHelper()); + m_menu->reloadHelper()->setReloadCmd(FbTk::RefCount<FbTk::Command<void> >(new FbTk::SimpleCommand<ShowCustomMenuCmd>(*this, &ShowCustomMenuCmd::reload))); + m_menu->reloadHelper()->setMainFile(custom_menu_file); + } else + m_menu->reloadHelper()->checkReload(); + + ::showMenu(*screen, *m_menu.get()); +} + +void ShowCustomMenuCmd::reload() { + m_menu->removeAll(); + m_menu->setLabel(""); + MenuCreator::createFromFile(custom_menu_file, *m_menu.get(), m_menu->reloadHelper()); } REGISTER_COMMAND(rootmenu, FbCommands::ShowRootMenuCmd, void);
M src/FbCommands.hhsrc/FbCommands.hh

@@ -25,7 +25,8 @@ #ifndef FBCOMMANDS_HH

#define FBCOMMANDS_HH #include "FbTk/Command.hh" -#include "FbTk/RefCount.hh" + +#include <memory> #include "ClientMenu.hh" #include "ClientPattern.hh"

@@ -124,16 +125,17 @@ private:

const int m_option; const ClientPattern m_pat; std::list<FluxboxWindow *> m_list; - FbTk::RefCount<ClientMenu> m_menu; + std::auto_ptr<ClientMenu> m_menu; }; class ShowCustomMenuCmd: public FbTk::Command<void> { public: explicit ShowCustomMenuCmd(const std::string &arguments); void execute(); + void reload(); private: std::string custom_menu_file; - FbTk::RefCount<FbTk::Menu> m_menu; + std::auto_ptr<FbMenu> m_menu; }; class ShowRootMenuCmd: public FbTk::Command<void> {
M src/FbMenu.hhsrc/FbMenu.hh

@@ -22,8 +22,11 @@

#ifndef FBMENU_HH #define FBMENU_HH +#include <memory> + #include "FbTk/Menu.hh" #include "FbTk/XLayerItem.hh" +#include "FbTk/AutoReloadHelper.hh" class FluxboxWindow;

@@ -44,11 +47,15 @@ void buttonPressEvent(XButtonEvent &be);

void buttonReleaseEvent(XButtonEvent &be); void keyPressEvent(XKeyEvent &ke); + void setReloadHelper(FbTk::AutoReloadHelper *helper) { m_reloader.reset(helper); } + FbTk::AutoReloadHelper *reloadHelper() { return m_reloader.get(); } + static void setWindow(FluxboxWindow *win) { s_window = win; } static FluxboxWindow *window() { return s_window; } private: FbTk::XLayerItem m_layeritem; + std::auto_ptr<FbTk::AutoReloadHelper> m_reloader; static FluxboxWindow *s_window; };
A src/FbTk/AutoReloadHelper.cc

@@ -0,0 +1,66 @@

+// AutoReloadHelper.cc +// Copyright (c) 2008 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#include "AutoReloadHelper.hh" + +#include "FileUtil.hh" +#include "StringUtil.hh" + +namespace FbTk { + +void AutoReloadHelper::checkReload() { + if (!m_reload_cmd.get()) + return; + TimestampMap::const_iterator it = m_timestamps.begin(); + TimestampMap::const_iterator it_end = m_timestamps.end(); + for (; it != it_end; ++it) { + if (FileUtil::getLastStatusChangeTimestamp(it->first.c_str()) != + it->second) { + reload(); + return; + } + } +} + +void AutoReloadHelper::setMainFile(std::string file) { + file = StringUtil::expandFilename(file); + if (file == m_main_file) + return; + m_main_file = file; + reload(); +} + +void AutoReloadHelper::addFile(std::string file) { + if (file.empty()) + return; + file = StringUtil::expandFilename(file); + m_timestamps[file] = FileUtil::getLastStatusChangeTimestamp(file.c_str()); +} + +void AutoReloadHelper::reload() { + if (!m_reload_cmd.get()) + return; + m_timestamps.clear(); + addFile(m_main_file); + m_reload_cmd->execute(); +} + +} // end namespace FbTk
A src/FbTk/AutoReloadHelper.hh

@@ -0,0 +1,54 @@

+// AutoReloadHelper.hh +// Copyright (c) 2008 Fluxbox Team (fluxgen at fluxbox dot org) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef AUTORELOADHELPER_HH +#define AUTORELOADHELPER_HH + +#include <map> +#include <string> +#include <sys/types.h> + +#include "Command.hh" +#include "RefCount.hh" + +namespace FbTk { + +class AutoReloadHelper { +public: + + void setMainFile(std::string filename); + void addFile(std::string filename); + void setReloadCmd(RefCount<Command<void> > cmd) { m_reload_cmd = cmd; } + + void checkReload(); + void reload(); + +private: + RefCount<Command<void> > m_reload_cmd; + std::string m_main_file; + + typedef std::map<std::string, time_t> TimestampMap; + TimestampMap m_timestamps; +}; + +} // end namespace FbTk + +#endif // AUTORELOADHELPER_HH
M src/FbTk/Makefile.amsrc/FbTk/Makefile.am

@@ -45,6 +45,7 @@ StringUtil.hh StringUtil.cc Parser.hh Parser.cc \

RegExp.hh RegExp.cc \ FbString.hh FbString.cc \ Subject.hh Subject.cc Observer.hh Observer.cc SimpleObserver.hh \ + AutoReloadHelper.hh AutoReloadHelper.cc \ Transparent.hh Transparent.cc \ FbPixmap.hh FbPixmap.cc \ FbDrawable.hh FbDrawable.cc \
M src/Keys.ccsrc/Keys.cc

@@ -170,7 +170,9 @@ }

-Keys::Keys() : next_key(0) { } +Keys::Keys(): next_key(0) { + m_reloader.setReloadCmd(FbTk::RefCount<FbTk::Command<void> >(new FbTk::SimpleCommand<Keys>(*this, &Keys::reload))); +} Keys::~Keys() { ungrabKeys();

@@ -255,27 +257,25 @@

/** Load and grab keys TODO: error checking - @return true on success else false */ -bool Keys::load(const char *filename) { +void Keys::reload() { // an intentionally empty file will still have one root mapping bool firstload = m_map.empty(); - if (!filename) { + if (m_filename.empty()) { if (firstload) loadDefaults(); - return false; + return; } FbTk::App::instance()->sync(false); // open the file - ifstream infile(filename); + ifstream infile(m_filename.c_str()); if (!infile) { if (firstload) loadDefaults(); - - return false; // failed to open file + return; // failed to open file } // free memory of previous grabs

@@ -301,9 +301,7 @@ current_line<<"): "<<linebuffer<<endl;

} } // end while eof - m_filename = filename; keyMode("default"); - return true; } /**

@@ -319,19 +317,6 @@ addBinding("OnDesktop Mouse1 :HideMenus");

addBinding("OnDesktop Mouse2 :WorkspaceMenu"); addBinding("OnDesktop Mouse3 :RootMenu"); keyMode("default"); -} - -bool Keys::save(const char *filename) const { - //!! - //!! TODO: fix keybinding saving - //!! (we probably need to save key actions - //!! as strings instead of creating new Commands) - - // open file for writing - // ofstream outfile(filename); - // if (!outfile) - return false; - // return true; } bool Keys::addBinding(const string &linebuffer) {

@@ -583,8 +568,10 @@ /**

deletes the tree and load configuration returns true on success else false */ -bool Keys::reconfigure(const char *filename) { - return load(filename); +void Keys::reconfigure() { + m_filename = FbTk::StringUtil::expandFilename(Fluxbox::instance()->getKeysFilename()); + m_reloader.setMainFile(m_filename); + m_reloader.checkReload(); } void Keys::keyMode(const string& keyMode) {
M src/Keys.hhsrc/Keys.hh

@@ -23,6 +23,7 @@ #ifndef KEYS_HH

#define KEYS_HH #include "FbTk/NotCopyable.hh" +#include "FbTk/AutoReloadHelper.hh" #include <X11/Xlib.h> #include <string>

@@ -57,17 +58,6 @@ explicit Keys();

/// destructor ~Keys(); - /** - Load configuration from file - @return true on success, else false - */ - bool load(const char *filename = 0); - /** - Save keybindings to a file - Note: the file will be overwritten - @return true on success, else false - */ - bool save(const char *filename = 0) const; /// bind a key action from a string /// @return false on failure bool addBinding(const std::string &binding);

@@ -83,12 +73,12 @@ void registerWindow(Window win, FbTk::EventHandler &handler, int context);

/// unregister window void unregisterWindow(Window win); + const std::string& filename() const { return m_filename; } /** Reload configuration from filename @return true on success, else false */ - bool reconfigure(const char *filename); - const std::string& filename() const { return m_filename; } + void reconfigure(); void keyMode(const std::string& keyMode); private: class t_key; // helper class to build a 'keytree'

@@ -104,13 +94,18 @@ void grabButton(unsigned int button, unsigned int mod, int context);

void ungrabButtons(); void grabWindow(Window win); - // Load default keybindings for when there are errors loading the initial one + /** + Load configuration from file + */ + void reload(); + // Load default keybindings for when there are errors loading the keys file void loadDefaults(); void setKeyMode(t_key *keyMode); // member variables std::string m_filename; + FbTk::AutoReloadHelper m_reloader; t_key *m_keylist; keyspace_t m_map;
M src/MenuCreator.ccsrc/MenuCreator.cc

@@ -59,6 +59,7 @@ using std::string;

using std::vector; using std::list; using std::less; +using FbTk::AutoReloadHelper; list<string> MenuCreator::encoding_stack; list<size_t> MenuCreator::stacksize_stack;

@@ -68,12 +69,15 @@

namespace { void createStyleMenu(FbTk::Menu &parent, const string &label, - const string &directory) { + AutoReloadHelper *reloader, const string &directory) { // perform shell style ~ home directory expansion string stylesdir(FbTk::StringUtil::expandFilename(directory)); if (!FbTk::FileUtil::isDirectory(stylesdir.c_str())) return; + + if (reloader) + reloader->addFile(stylesdir); FbTk::Directory dir(stylesdir.c_str());

@@ -99,18 +103,21 @@ parent.insert(new StyleMenuItem(filelist[file_index], style));

} // update menu graphics parent.updateMenu(); - Fluxbox::instance()->saveMenuFilename(stylesdir.c_str()); } void createRootCmdMenu(FbTk::Menu &parent, const string &label, - const string &directory, const string &cmd) { + const string &directory, AutoReloadHelper *reloader, + const string &cmd) { // perform shell style ~ home directory expansion string rootcmddir(FbTk::StringUtil::expandFilename(directory)); if (!FbTk::FileUtil::isDirectory(rootcmddir.c_str())) return; + if (reloader) + reloader->addFile(rootcmddir); + FbTk::Directory dir(rootcmddir.c_str()); // create a vector of all the filenames in the directory

@@ -134,7 +141,6 @@ parent.insert(new RootCmdMenuItem(filelist[file_index], rootcmd, cmd));

} // update menu graphics parent.updateMenu(); - Fluxbox::instance()->saveMenuFilename(rootcmddir.c_str()); }

@@ -172,20 +178,26 @@ }

}; -void translateMenuItem(FbTk::Parser &parse, ParseItem &item, FbTk::StringConvertor &labelconvertor); +void translateMenuItem(FbTk::Parser &parse, ParseItem &item, + FbTk::StringConvertor &labelconvertor, + AutoReloadHelper *reloader); -void parseMenu(FbTk::Parser &pars, FbTk::Menu &menu, FbTk::StringConvertor &label_convertor) { +void parseMenu(FbTk::Parser &pars, FbTk::Menu &menu, + FbTk::StringConvertor &label_convertor, + AutoReloadHelper *reloader) { ParseItem pitem(&menu); while (!pars.eof()) { pitem.load(pars, label_convertor); if (pitem.key() == "end") return; - translateMenuItem(pars, pitem, label_convertor); + translateMenuItem(pars, pitem, label_convertor, reloader); } } -void translateMenuItem(FbTk::Parser &parse, ParseItem &pitem, FbTk::StringConvertor &labelconvertor) { +void translateMenuItem(FbTk::Parser &parse, ParseItem &pitem, + FbTk::StringConvertor &labelconvertor, + AutoReloadHelper *reloader) { if (pitem.menu() == 0) throw string("translateMenuItem: We must have a menu in ParseItem!");

@@ -255,13 +267,13 @@

if (FbTk::FileUtil::isRegularFile(thisfile.c_str()) && (filelist[file_index][0] != '.') && (thisfile[thisfile.length() - 1] != '~')) { - MenuCreator::createFromFile(thisfile, menu); + MenuCreator::createFromFile(thisfile, menu, reloader, false); } } } else { // inject this file into the current menu - MenuCreator::createFromFile(newfile, menu); + MenuCreator::createFromFile(newfile, menu, reloader, false); } safe_counter--;

@@ -278,26 +290,22 @@ submenu->setLabel(str_cmd);

else submenu->setLabel(str_label); - parseMenu(parse, *submenu, labelconvertor); + parseMenu(parse, *submenu, labelconvertor, reloader); submenu->updateMenu(); menu.insert(str_label, submenu); - // save to screen list so we can delete it later - BScreen *screen = Fluxbox::instance()->findScreen(screen_number); - if (screen != 0) - screen->saveMenu(*submenu); } // end of submenu else if (str_key == "stylesdir" || str_key == "stylesmenu") { - createStyleMenu(menu, str_label, + createStyleMenu(menu, str_label, reloader, str_key == "stylesmenu" ? str_cmd : str_label); } // end of stylesdir else if (str_key == "themesdir" || str_key == "themesmenu") { - createStyleMenu(menu, str_label, + createStyleMenu(menu, str_label, reloader, str_key == "themesmenu" ? str_cmd : str_label); } // end of themesdir else if (str_key == "wallpapers" || str_key == "wallpapermenu" || str_key == "rootcommands") { - createRootCmdMenu(menu, str_label, str_label, + createRootCmdMenu(menu, str_label, str_label, reloader, str_cmd == "" ? realProgramName("fbsetbg") : str_cmd); } // end of wallpapers else if (str_key == "workspaces") {

@@ -339,7 +347,9 @@ }

} -void parseWindowMenu(FbTk::Parser &parse, FbTk::Menu &menu, FbTk::StringConvertor &labelconvertor) { +void parseWindowMenu(FbTk::Parser &parse, FbTk::Menu &menu, + FbTk::StringConvertor &labelconvertor, + AutoReloadHelper *reloader) { ParseItem pitem(&menu); while (!parse.eof()) {

@@ -347,16 +357,16 @@ pitem.load(parse, labelconvertor);

if (MenuCreator::createWindowMenuItem(pitem.key(), pitem.label(), menu)) continue; - if (pitem.key() == "end") { + if (pitem.key() == "end") return; - } else if (pitem.key() == "submenu") { + if (pitem.key() == "submenu") { FbTk::Menu *submenu = MenuCreator::createMenu(pitem.label(), menu.screenNumber()); - parseWindowMenu(parse, *submenu, labelconvertor); + parseWindowMenu(parse, *submenu, labelconvertor, reloader); submenu->updateMenu(); menu.insert(pitem.label(), submenu); } else { // try non window menu specific stuff - translateMenuItem(parse, pitem, labelconvertor); + translateMenuItem(parse, pitem, labelconvertor, reloader); } } }

@@ -380,12 +390,12 @@ }

}; // end of anonymous namespace -FbTk::Menu *MenuCreator::createMenu(const string &label, int screen_number) { +FbMenu *MenuCreator::createMenu(const string &label, int screen_number) { BScreen *screen = Fluxbox::instance()->findScreen(screen_number); if (screen == 0) return 0; - FbTk::Menu *menu = new FbMenu(screen->menuTheme(), + FbMenu *menu = new FbMenu(screen->menuTheme(), screen->imageControl(), *screen->layerManager().getLayer(Layer::MENU)); if (!label.empty())

@@ -394,33 +404,9 @@

return menu; } -FbTk::Menu *MenuCreator::createFromFile(const string &filename, int screen_number) { - string real_filename = FbTk::StringUtil::expandFilename(filename); - Fluxbox::instance()->saveMenuFilename(real_filename.c_str()); - - FbMenuParser parser(real_filename); - if (!parser.isLoaded()) - return 0; - - startFile(); - string label; - if (!getStart(parser, label, m_stringconvertor)) { - endFile(); - return 0; - } - - FbTk::Menu *menu = createMenu(label, screen_number); - if (menu != 0) - parseMenu(parser, *menu, m_stringconvertor); - - endFile(); - - return menu; -} - - bool MenuCreator::createFromFile(const string &filename, - FbTk::Menu &inject_into) { + FbTk::Menu &inject_into, + AutoReloadHelper *reloader, bool begin) { string real_filename = FbTk::StringUtil::expandFilename(filename); FbMenuParser parser(real_filename);

@@ -428,75 +414,59 @@ if (!parser.isLoaded())

return false; startFile(); + if (begin) { + string label; + if (!getStart(parser, label, m_stringconvertor)) { + endFile(); + return false; + } + inject_into.setLabel(label); + } // save menu filename, so we can check if it changes - Fluxbox::instance()->saveMenuFilename(real_filename.c_str()); + if (reloader) + reloader->addFile(real_filename); - parseMenu(parser, inject_into, m_stringconvertor); + parseMenu(parser, inject_into, m_stringconvertor, reloader); endFile(); return true; } -bool MenuCreator::createWindowMenuFromFile(const string &filename, - FbTk::Menu &inject_into) { +void MenuCreator::createWindowMenuFromFile(const string &filename, + FbTk::Menu &inject_into, + AutoReloadHelper *reloader) { string real_filename = FbTk::StringUtil::expandFilename(filename); FbMenuParser parser(real_filename); if (!parser.isLoaded()) - return false; + return; string label; startFile(); if (!getStart(parser, label, m_stringconvertor)) { endFile(); - return false; + return; } - parseWindowMenu(parser, inject_into, m_stringconvertor); + if (reloader) + reloader->addFile(real_filename); + + parseWindowMenu(parser, inject_into, m_stringconvertor, reloader); endFile(); - - return true; } -FbTk::Menu *MenuCreator::createMenuType(const string &type, int screen_num) { +FbMenu *MenuCreator::createMenuType(const string &type, int screen_num) { BScreen *screen = Fluxbox::instance()->findScreen(screen_num); if (screen == 0) return 0; - if (type == "iconmenu") { + if (type == "iconmenu") return new ClientMenu(*screen, screen->iconList(), &screen->iconListSig()); - } else if (type == "workspacemenu") { + else if (type == "workspacemenu") return new WorkspaceMenu(*screen); - } else if (type == "windowmenu") { - FbTk::Menu *menu = screen->createMenu(""); - - menu->disableTitle(); // not titlebar - if (screen->windowMenuFilename().empty() || - ! createWindowMenuFromFile(screen->windowMenuFilename(), *menu)) { - const char *default_menu[] = { - "shade", - "stick", - "maximize", - "iconify", - "raise", - "lower", - "sendto", - "layer", - "alpha", - "extramenus", - "separator", - "close", - 0 - }; - for (unsigned int i=0; default_menu[i]; ++i) - createWindowMenuItem(default_menu[i], "", *menu); - } - menu->reconfigure(); // update graphics - return menu; - } return 0; }
M src/MenuCreator.hhsrc/MenuCreator.hh

@@ -28,18 +28,24 @@

#include <list> namespace FbTk { +class AutoReloadHelper; class Menu; } +class FbMenu; class FluxboxWindow; class MenuCreator { public: - static FbTk::Menu *createMenu(const std::string &label, int screen_num); - static FbTk::Menu *createFromFile(const std::string &filename, int screen_num); - static FbTk::Menu *createMenuType(const std::string &label, int screen_num); - static bool createFromFile(const std::string &filename, FbTk::Menu &inject_into); - static bool createWindowMenuFromFile(const std::string &filename, FbTk::Menu &inject_into); + static FbMenu *createMenu(const std::string &label, int screen_num); + static FbMenu *createMenuType(const std::string &label, int screen_num); + static bool createFromFile(const std::string &filename, + FbTk::Menu &inject_into, + FbTk::AutoReloadHelper *reloader = NULL, + bool begin = true); + static void createWindowMenuFromFile(const std::string &filename, + FbTk::Menu &inject_into, + FbTk::AutoReloadHelper *reloader); static bool createWindowMenuItem(const std::string &type, const std::string &label, FbTk::Menu &inject_into);
M src/Remember.ccsrc/Remember.cc

@@ -120,7 +120,7 @@ }

void click(int button, int time, unsigned int mods) { // reconfigure only does stuff if the apps file has changed - Remember::instance().reconfigure(); + Remember::instance().checkReload(); if (WindowCmd<void>::window() != 0) { if (isSelected()) { Remember::instance().forgetAttrib(WindowCmd<void>::window()->winClient(), m_attrib);

@@ -281,14 +281,14 @@

Remember *Remember::s_instance = 0; Remember::Remember(): - m_pats(new Patterns()), - m_last_timestamp(0) -{ + m_pats(new Patterns()) { if (s_instance != 0) throw string("Can not create more than one instance of Remember"); s_instance = this; enableUpdate(); + + m_reloader.setReloadCmd(FbTk::RefCount<FbTk::Command<void> >(new FbTk::SimpleCommand<Remember>(*this, &Remember::reload))); reconfigure(); }

@@ -579,12 +579,16 @@ }

void Remember::reconfigure() { + m_reloader.setMainFile(Fluxbox::instance()->getAppsFilename()); +} + +void Remember::checkReload() { + m_reloader.checkReload(); +} + +void Remember::reload() { string apps_string = FbTk::StringUtil::expandFilename(Fluxbox::instance()->getAppsFilename()); - time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp(apps_string.c_str()); - if (m_last_timestamp > 0 && m_last_timestamp == timestamp) - return; - #ifdef DEBUG cerr<<__FILE__<<"("<<__FUNCTION__<<"): Loading apps file ["<<apps_string<<"]"<<endl; #endif // DEBUG

@@ -598,7 +602,6 @@ m_pats.reset(new Patterns());

m_startups.clear(); if (!apps_file.fail()) { - m_last_timestamp = timestamp; if (!apps_file.eof()) { string line; int row = 0;

@@ -687,7 +690,7 @@ cerr<<__FILE__<<"("<<__FUNCTION__<< ") Empty apps file" << endl;

#endif } } else { - cerr << "apps file failure" << endl; + cerr << "failed to open apps file" << endl; } // Clean up old state

@@ -895,11 +898,8 @@ }

apps_file << "[end]" << endl; } apps_file.close(); - - time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp(apps_string.c_str()); - if (timestamp > 0) - m_last_timestamp = timestamp; - + // update timestamp to avoid unnecessary reload + m_reloader.addFile(Fluxbox::instance()->getAppsFilename()); } bool Remember::isRemembered(WinClient &winclient, Attribute attrib) {

@@ -1216,6 +1216,9 @@ // leave windows alone on restart

if (winclient.screen().isRestart()) return; + // check if apps file has changed + checkReload(); + Application *app = find(winclient); if (app == 0) return; // nothing to do

@@ -1249,7 +1252,7 @@ return 0;

} void Remember::updateClientClose(WinClient &winclient) { - reconfigure(); // reload if it's changed + checkReload(); // reload if it's changed Application *app = find(winclient); if (app && (app->save_on_close_remember && app->save_on_close)) {
M src/Remember.hhsrc/Remember.hh

@@ -29,6 +29,7 @@

#include "AtomHandler.hh" #include "ClientPattern.hh" +#include "FbTk/AutoReloadHelper.hh" #include "FbTk/RefCount.hh" #include <fstream>

@@ -223,7 +224,9 @@ Application* find(WinClient &winclient);

Application* add(WinClient &winclient); FluxboxWindow* findGroup(Application *, BScreen &screen); - void reconfigure(); // was load + void reconfigure(); + void checkReload(); + void reload(); void save(); bool isRemembered(WinClient &win, Attribute attrib);

@@ -277,7 +280,7 @@

Startups m_startups; static Remember *s_instance; - time_t m_last_timestamp; + FbTk::AutoReloadHelper m_reloader; }; #endif // REMEMBER_HH
M src/Screen.ccsrc/Screen.cc

@@ -283,7 +283,7 @@ typing_delay(rm, 0, scrname+".noFocusWhileTypingDelay", altscrname+".NoFocusWhileTypingDelay"),

follow_model(rm, IGNORE_OTHER_WORKSPACES, scrname+".followModel", altscrname+".followModel"), user_follow_model(rm, FOLLOW_ACTIVE_WINDOW, scrname+".userFollowModel", altscrname+".UserFollowModel"), workspaces(rm, 1, scrname+".workspaces", altscrname+".Workspaces"), - edge_snap_threshold(rm, 0, scrname+".edgeSnapThreshold", altscrname+".EdgeSnapThreshold"), + edge_snap_threshold(rm, 10, scrname+".edgeSnapThreshold", altscrname+".EdgeSnapThreshold"), focused_alpha(rm, 255, scrname+".window.focus.alpha", altscrname+".Window.Focus.Alpha"), unfocused_alpha(rm, 255, scrname+".window.unfocus.alpha", altscrname+".Window.Unfocus.Alpha"), menu_alpha(rm, 255, scrname+".menu.alpha", altscrname+".Menu.Alpha"),

@@ -501,6 +501,15 @@

//!! TODO: we shouldn't do this more than once, but since slit handles their // own resources we must do this. fluxbox->load_rc(*this); + + m_windowmenu.reset(createMenu("")); + m_windowmenu->setInternalMenu(); + m_windowmenu->setReloadHelper(new FbTk::AutoReloadHelper()); + m_windowmenu->reloadHelper()->setReloadCmd(FbTk::RefCount<FbTk::Command<void> >(new FbTk::SimpleCommand<BScreen>(*this, &BScreen::rereadWindowMenu))); + + m_rootmenu.reset(createMenu("")); + m_rootmenu->setReloadHelper(new FbTk::AutoReloadHelper()); + m_rootmenu->reloadHelper()->setReloadCmd(FbTk::RefCount<FbTk::Command<void> >(new FbTk::SimpleCommand<BScreen>(*this, &BScreen::rereadMenu))); m_configmenu.reset(createMenu(_FB_XTEXT(Menu, Configuration, "Configuration", "Title of configuration menu")));

@@ -889,8 +898,8 @@ focusControl().cycleFocus(*win_list, pat, reverse);

} -FbTk::Menu *BScreen::createMenu(const string &label) { - FbTk::Menu *menu = new FbMenu(menuTheme(), +FbMenu *BScreen::createMenu(const string &label) { + FbMenu *menu = new FbMenu(menuTheme(), imageControl(), *layerManager().getLayer(Layer::MENU)); if (!label.empty())

@@ -898,8 +907,9 @@ menu->setLabel(label);

return menu; } -FbTk::Menu *BScreen::createToggleMenu(const string &label) { - FbTk::Menu *menu = new ToggleMenu(menuTheme(), + +FbMenu *BScreen::createToggleMenu(const string &label) { + FbMenu *menu = new ToggleMenu(menuTheme(), imageControl(), *layerManager().getLayer(Layer::MENU)); if (!label.empty())

@@ -912,9 +922,7 @@ void BScreen::addExtraWindowMenu(const FbTk::FbString &label, FbTk::Menu *menu) {

menu->setInternalMenu(); menu->disableTitle(); m_extramenus.push_back(make_pair(label, menu)); - // recreate window menu - m_windowmenu.reset(MenuCreator::createMenuType("windowmenu", screenNumber())); - m_windowmenu->setInternalMenu(); + rereadWindowMenu(); } void BScreen::reconfigure() {

@@ -956,21 +964,9 @@ removeLastWorkspace();

} } - // if timestamp hasn't changed, then just a reconfigure is fine - // and that seems to happen somewhere else, anyway - if (fluxbox->menuTimestampsChanged()) { - // all bets are off, so just hide the menu and reset the filenames - fluxbox->clearMenuFilenames(); - m_rootmenu->hide(); - rereadMenu(); - } - - //reconfigure menus - m_workspacemenu->reconfigure(); - m_configmenu->reconfigure(); - // recreate window menu - m_windowmenu.reset(MenuCreator::createMenuType("windowmenu", screenNumber())); - m_windowmenu->setInternalMenu(); + // update menu filenames + m_rootmenu->reloadHelper()->setMainFile(fluxbox->getMenuFilename()); + m_windowmenu->reloadHelper()->setMainFile(windowMenuFilename()); // reconfigure workspaces for_each(m_workspaces_list.begin(),

@@ -1001,12 +997,6 @@ std::list<Focusable *>::const_iterator it = winlist.begin(),

it_end = winlist.end(); for (; it != it_end; ++it) (*it)->fbwindow()->applyDecorations(); -} - - -void BScreen::rereadMenu() { - initMenu(); - m_rootmenu->reconfigure(); } void BScreen::updateWorkspaceName(unsigned int w) {

@@ -1500,34 +1490,24 @@ }

void BScreen::initMenus() { m_workspacemenu.reset(MenuCreator::createMenuType("workspacemenu", screenNumber())); - m_windowmenu.reset(MenuCreator::createMenuType("windowmenu", screenNumber())); - m_windowmenu->setInternalMenu(); - initMenu(); + m_rootmenu->reloadHelper()->setMainFile(Fluxbox::instance()->getMenuFilename()); + m_windowmenu->reloadHelper()->setMainFile(windowMenuFilename()); } -void BScreen::initMenu() { +void BScreen::rereadMenu() { - if (m_rootmenu.get()) { - // since all menus in root is submenus in m_rootmenu - // just remove every item in m_rootmenu and then clear m_rootmenu_list - while (m_rootmenu->numberOfItems()) - m_rootmenu->remove(0); - m_rootmenu_list.clear(); - - } else - m_rootmenu.reset(createMenu("")); + m_rootmenu->removeAll(); + m_rootmenu->setLabel(""); Fluxbox * const fb = Fluxbox::instance(); - if (!fb->getMenuFilename().empty()) { - m_rootmenu.reset(MenuCreator::createFromFile(fb->getMenuFilename(), - screenNumber())); - - } + if (!fb->getMenuFilename().empty()) + MenuCreator::createFromFile(fb->getMenuFilename(), *m_rootmenu, + m_rootmenu->reloadHelper()); - if (m_rootmenu.get() == 0 || m_rootmenu->numberOfItems() == 0) { + if (m_rootmenu->numberOfItems() == 0) { _FB_USES_NLS; - m_rootmenu.reset(createMenu(_FB_XTEXT(Menu, DefaultRootMenu, "Fluxbox default menu", "Title of fallback root menu"))); + m_rootmenu->setLabel(_FB_XTEXT(Menu, DefaultRootMenu, "Fluxbox default menu", "Title of fallback root menu")); FbTk::RefCount<FbTk::Command<void> > restart_fb(FbTk::CommandParser<void>::instance().parse("restart")); FbTk::RefCount<FbTk::Command<void> > exit_fb(FbTk::CommandParser<void>::instance().parse("exit")); FbTk::RefCount<FbTk::Command<void> > execute_xterm(FbTk::CommandParser<void>::instance().parse("exec xterm"));

@@ -1539,14 +1519,39 @@ m_rootmenu->insert(_FB_XTEXT(Menu, Restart, "Restart", "Restart command"),

restart_fb); m_rootmenu->insert(_FB_XTEXT(Menu, Exit, "Exit", "Exit command"), exit_fb); - // still save the menu filename, in case it becomes valid later - if (!fb->getMenuFilename().empty()) - fb->saveMenuFilename(fb->getMenuFilename().c_str()); } - m_rootmenu->updateMenu(); } +void BScreen::rereadWindowMenu() { + + m_windowmenu->removeAll(); + if (!windowMenuFilename().empty()) + MenuCreator::createWindowMenuFromFile(windowMenuFilename(), + *m_windowmenu, + m_windowmenu->reloadHelper()); + + if (m_windowmenu->numberOfItems() == 0) { + const char *defaults[] = { + "shade", + "stick", + "maximize", + "iconify", + "raise", + "lower", + "sendto", + "layer", + "alpha", + "extramenus", + "separator", + "close", + 0 + }; + for (unsigned int i=0; defaults[i]; ++i) + MenuCreator::createWindowMenuItem(defaults[i], "", *m_windowmenu); + } + +} void BScreen::addConfigMenu(const FbTk::FbString &label, FbTk::Menu &menu) { m_configmenu_list.push_back(make_pair(label, &menu));
M src/Screen.hhsrc/Screen.hh

@@ -54,6 +54,7 @@ #include <memory>

#include <map> class ClientPattern; +class FbMenu; class Focusable; class FluxboxWindow; class WinClient;

@@ -122,12 +123,12 @@ const std::string &defaultDeco() const { return *resource.default_deco; }

const std::string &windowMenuFilename() const { return *resource.windowmenufile; } FbTk::ImageControl &imageControl() { return *m_image_control.get(); } // menus - const FbTk::Menu &rootMenu() const { return *m_rootmenu.get(); } - FbTk::Menu &rootMenu() { return *m_rootmenu.get(); } - const FbTk::Menu &configMenu() const { return *m_configmenu.get(); } - FbTk::Menu &configMenu() { return *m_configmenu.get(); } - const FbTk::Menu &windowMenu() const { return *m_windowmenu.get(); } - FbTk::Menu &windowMenu() { return *m_windowmenu.get(); } + const FbMenu &rootMenu() const { return *m_rootmenu.get(); } + FbMenu &rootMenu() { return *m_rootmenu.get(); } + const FbMenu &configMenu() const { return *m_configmenu.get(); } + FbMenu &configMenu() { return *m_configmenu.get(); } + const FbMenu &windowMenu() const { return *m_windowmenu.get(); } + FbMenu &windowMenu() { return *m_windowmenu.get(); } ExtraMenus &extraWindowMenus() { return m_extramenus; } const ExtraMenus &extraWindowMenus() const { return m_extramenus; }

@@ -166,9 +167,9 @@ /// @return the current workspace

Workspace *currentWorkspace() { return m_current_workspace; } const Workspace *currentWorkspace() const { return m_current_workspace; } /// @return the workspace menu - const FbTk::Menu &workspaceMenu() const { return *m_workspacemenu.get(); } + const FbMenu &workspaceMenu() const { return *m_workspacemenu.get(); } /// @return the workspace menu - FbTk::Menu &workspaceMenu() { return *m_workspacemenu.get(); } + FbMenu &workspaceMenu() { return *m_workspacemenu.get(); } /// @return focus control handler const FocusControl &focusControl() const { return *m_focus_control; } /// @return focus control handler

@@ -251,15 +252,15 @@

/** * Creates an empty menu with specified label * @param label for the menu - * @return create menu + * @return created menu */ - FbTk::Menu *createMenu(const std::string &label); + FbMenu *createMenu(const std::string &label); /** * Creates an empty toggle menu with a specific label * @param label * @return created menu */ - FbTk::Menu *createToggleMenu(const std::string &label); + FbMenu *createToggleMenu(const std::string &label); /** * For extras to add menus.

@@ -276,8 +277,6 @@ void saveTabPlacement(FbWinFrame::TabPlacement place) { *resource.tab_placement = place; }

void saveWorkspaces(int w) { *resource.workspaces = w; } - void saveMenu(FbTk::Menu &menu) { m_rootmenu_list.push_back(&menu); } - FbTk::ThemeProxy<FbWinFrameTheme> &focusedWinFrameTheme() { return *m_focused_windowtheme.get(); } const FbTk::ThemeProxy<FbWinFrameTheme> &focusedWinFrameTheme() const { return *m_focused_windowtheme.get(); } FbTk::ThemeProxy<FbWinFrameTheme> &unfocusedWinFrameTheme() { return *m_unfocused_windowtheme.get(); }

@@ -385,6 +384,7 @@

void reconfigure(); void reconfigureTabs(); void rereadMenu(); + void rereadWindowMenu(); void shutdown(); /// show position window centered on the screen with "X x Y" text void showPosition(int x, int y);

@@ -491,7 +491,6 @@ };

private: void setupConfigmenu(FbTk::Menu &menu); - void initMenu(); void renderGeomWindow(); void renderPosWindow();

@@ -517,15 +516,13 @@ GC opGC;

std::auto_ptr<FbTk::ImageControl> m_image_control; - std::auto_ptr<FbTk::Menu> m_configmenu, m_rootmenu, m_workspacemenu, m_windowmenu; + std::auto_ptr<FbMenu> m_configmenu, m_rootmenu, m_workspacemenu, m_windowmenu; ExtraMenus m_extramenus; - typedef std::list<FbTk::Menu *> Rootmenus; typedef std::list<std::pair<FbTk::FbString, FbTk::Menu *> > Configmenus; - Rootmenus m_rootmenu_list; Configmenus m_configmenu_list; Icons m_icon_list;
M src/fluxbox.ccsrc/fluxbox.cc

@@ -307,7 +307,7 @@

// Create keybindings handler and load keys file // Note: this needs to be done before creating screens m_key.reset(new Keys); - m_key->load(StringUtil::expandFilename(*m_rc_keyfile).c_str()); + m_key->reconfigure(); vector<int> screens; int i;

@@ -399,7 +399,7 @@

//XSynchronize(disp, False); sync(false); - m_reconfigure_wait = m_reread_menu_wait = false; + m_reconfigure_wait = false; m_resourcemanager.unlock(); ungrab();

@@ -437,8 +437,6 @@ it++) {

delete (*it).first; } m_atomhandler.clear(); - - clearMenuFilenames(); }

@@ -753,7 +751,7 @@ || e->xmapping.request == MappingModifier) {

XRefreshKeyboardMapping(&e->xmapping); FbTk::KeyUtil::instance().init(); // reinitialise the key utils // reconfigure keys (if the mapping changes, they don't otherwise update - m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str()); + m_key->reconfigure(); } break; case CreateNotify:

@@ -1445,7 +1443,7 @@ // reconfigure all screens

for_each(m_screen_list.begin(), m_screen_list.end(), mem_fun(&BScreen::reconfigure)); //reconfigure keys - m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str()); + m_key->reconfigure(); // and atomhandlers for (AtomHandlerContainerIt it= m_atomhandler.begin();

@@ -1469,87 +1467,11 @@

return *it; } -bool Fluxbox::menuTimestampsChanged() const { - list<MenuTimestamp *>::const_iterator it = m_menu_timestamps.begin(); - list<MenuTimestamp *>::const_iterator it_end = m_menu_timestamps.end(); - for (; it != it_end; ++it) { - - time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp((*it)->filename.c_str()); - - if (timestamp != (*it)->timestamp) - return true; - } - - // no timestamp changed - return false; -} - -void Fluxbox::rereadMenu(bool show_after_reread) { - m_reread_menu_wait = true; - m_show_menu_after_reread = show_after_reread; - m_reconfig_timer.start(); -} - - -void Fluxbox::real_rereadMenu() { - - clearMenuFilenames(); - - for_each(m_screen_list.begin(), - m_screen_list.end(), - mem_fun(&BScreen::rereadMenu)); - - if(m_show_menu_after_reread) { - - FbCommands::ShowRootMenuCmd showcmd; - showcmd.execute(); - - m_show_menu_after_reread = false; - } -} - -void Fluxbox::saveMenuFilename(const char *filename) { - if (filename == 0) - return; - - bool found = false; - - list<MenuTimestamp *>::iterator it = m_menu_timestamps.begin(); - list<MenuTimestamp *>::iterator it_end = m_menu_timestamps.end(); - for (; it != it_end; ++it) { - if ((*it)->filename == filename) { - found = true; - break; - } - } - - if (! found) { - time_t timestamp = FbTk::FileUtil::getLastStatusChangeTimestamp(filename); - - MenuTimestamp *ts = new MenuTimestamp; - - ts->filename = filename; - ts->timestamp = timestamp; - - m_menu_timestamps.push_back(ts); - } -} - -void Fluxbox::clearMenuFilenames() { - while(!m_menu_timestamps.empty()) { - delete m_menu_timestamps.back(); - m_menu_timestamps.pop_back(); - } -} - void Fluxbox::timed_reconfigure() { if (m_reconfigure_wait) real_reconfigure(); - if (m_reread_menu_wait) - real_rereadMenu(); - - m_reconfigure_wait = m_reread_menu_wait = false; + m_reconfigure_wait = false; } void Fluxbox::revertFocus() {
M src/fluxbox.hhsrc/fluxbox.hh

@@ -120,6 +120,7 @@

const std::string &getMenuFilename() const { return *m_rc_menufile; } const std::string &getSlitlistFilename() const { return *m_rc_slitlistfile; } const std::string &getAppsFilename() const { return *m_rc_appsfile; } + const std::string &getKeysFilename() const { return *m_rc_keyfile; } int colorsPerChannel() const { return *m_rc_colors_per_channel; } int getTabsPadding() const { return *m_rc_tabs_padding; }

@@ -136,8 +137,6 @@

void shutdown(); void load_rc(BScreen &scr); void saveStyleFilename(const char *val) { m_rc_stylefile = (val == 0 ? "" : val); } - void saveMenuFilename(const char *); - void clearMenuFilenames(); void saveWindowSearch(Window win, WinClient *winclient); // some windows relate to the group, not the client, so we record separately // searchWindow on these windows will give the active client in the group

@@ -149,8 +148,6 @@ void removeWindowSearchGroup(Window win);

void removeGroupSearch(Window win); void restart(const char *command = 0); void reconfigure(); - void rereadMenu(bool show_after_reread = false); - /// reloads the menus if the timestamps changed /// handle any system signal sent to the application void handleSignal(int signum);

@@ -176,8 +173,6 @@

typedef std::list<BScreen *> ScreenList; const ScreenList screenList() const { return m_screen_list; } - /// @return whether the timestamps on the menu changed - bool menuTimestampsChanged() const; bool haveShape() const { return m_have_shape; } int shapeEventbase() const { return m_shape_eventbase; } void getDefaultDataFilename(const char *name, std::string &) const;

@@ -190,18 +185,9 @@

AttentionNoticeHandler &attentionHandler() { return m_attention_handler; } private: - - typedef struct MenuTimestamp { - std::string filename; - time_t timestamp; - } MenuTimestamp; - - - std::string getRcFilename(); void load_rc(); - void real_rereadMenu(); void real_reconfigure(); void handleEvent(XEvent *xe);

@@ -242,7 +228,6 @@ // The group leader (which may not be mapped, so may not have a WinClient)

// will have it's window being the group index std::multimap<Window, WinClient *> m_group_search; - std::list<MenuTimestamp *> m_menu_timestamps; ScreenList m_screen_list; FluxboxWindow *m_masked_window;

@@ -251,7 +236,7 @@ BScreen *m_mousescreen, *m_keyscreen;

Atom m_fluxbox_pid; - bool m_reconfigure_wait, m_reread_menu_wait; + bool m_reconfigure_wait; Time m_last_time; Window m_masked; std::string m_rc_file; ///< resource filename

@@ -279,7 +264,6 @@

bool m_starting; bool m_restarting; bool m_shutdown; - bool m_show_menu_after_reread; int m_server_grabs; int m_randr_event_type; ///< the type number of randr event int m_shape_eventbase; ///< event base for shape events