From 1ec69a741f1e800514f27a83ad8c0628ed57adc9 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Mon, 27 Jun 2011 19:34:51 +0200 Subject: A veeeery rough implementation of lua menu parsers --- src/FbTk/Menu.cc | 2 +- src/FbTk/Menu.hh | 2 +- src/FbTk/MenuItem.hh | 4 +- src/MenuCreator.cc | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/MenuCreator.hh | 15 +++-- src/Screen.cc | 7 ++- 6 files changed, 172 insertions(+), 9 deletions(-) diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc index a66b6c0..b6b4ec6 100644 --- a/src/FbTk/Menu.cc +++ b/src/FbTk/Menu.cc @@ -219,7 +219,7 @@ Menu::~Menu() { s_focused = 0; } -int Menu::insert(const FbString &label, RefCount > &cmd, int pos) { +int Menu::insert(const FbString &label, const RefCount > &cmd, int pos) { return insert(new MenuItem(label, cmd, this), pos); } diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh index bd830b4..4096295 100644 --- a/src/FbTk/Menu.hh +++ b/src/FbTk/Menu.hh @@ -61,7 +61,7 @@ public: */ //@{ /// add a menu item with a label and a command - int insert(const FbString &label, RefCount > &cmd, int pos=-1); + int insert(const FbString &label, const RefCount > &cmd, int pos=-1); /// add empty menu item int insert(const FbString &label, int pos=-1); /// add submenu diff --git a/src/FbTk/MenuItem.hh b/src/FbTk/MenuItem.hh index 2149559..cc24228 100644 --- a/src/FbTk/MenuItem.hh +++ b/src/FbTk/MenuItem.hh @@ -69,7 +69,7 @@ public: m_toggle_item(false) { } /// create a menu item with a specific command to be executed on click - MenuItem(const BiDiString &label, RefCount > &cmd, Menu *menu = 0) + MenuItem(const BiDiString &label, const RefCount > &cmd, Menu *menu = 0) : m_label(label), m_menu(menu), m_submenu(0), @@ -91,7 +91,7 @@ public: { } virtual ~MenuItem() { } - void setCommand(RefCount > &cmd) { m_command = cmd; } + void setCommand(const RefCount > &cmd) { m_command = cmd; } virtual void setSelected(bool selected) { m_selected = selected; } virtual void setEnabled(bool enabled) { m_enabled = enabled; } virtual void setLabel(const BiDiString &label) { m_label = label; } diff --git a/src/MenuCreator.cc b/src/MenuCreator.cc index 41dcf73..b944bcb 100644 --- a/src/MenuCreator.cc +++ b/src/MenuCreator.cc @@ -433,8 +433,159 @@ bool getStart(FbMenuParser &parser, string &label, FbTk::StringConvertor &labelc return true; } +string getField(lua::state &l, int pos, const char *field, FbTk::StringConvertor *conv = NULL) { + lua::stack_sentry s(l); + l.checkstack(1); + _FB_USES_NLS; + + string val; + l.rawgetfield(pos, field); { + if(l.isstring(-1)) + val = l.tostring(-1); + else if(! l.isnil(-1)) { + fprintf(stderr, _FB_CONSOLETEXT(Menu, FieldNotString, + "Warning: Menu field %s is not a string", "One %s for field name.").c_str(), + field); + fputs("\n", stderr); + } + } l.pop(); + return conv ? conv->recode(val) : val; +} + +std::auto_ptr +createMenu_(lua::state &l, int screen_number, FbTk::StringConvertor &conv, + FbTk::AutoReloadHelper *reloader); + +void +insertMenuItem(lua::state &l, FbMenu &menu, FbTk::StringConvertor &parent_conv, + FbTk::AutoReloadHelper *reloader) { + lua::stack_sentry s(l, -1); + l.checkstack(1); + + if(l.type(-1) != lua::TTABLE) + throw std::runtime_error(_FB_CONSOLETEXT(Menu, MenuNotTable, "Warning: Menu is not a lua table", "Menu is not a lua table")); + + // if menu specifies an encoding, create a convertor for it + std::auto_ptr my_conv; + + FbTk::StringConvertor *conv = &parent_conv; + const string &encoding = getField(l, -1, "encoding"); + if(! encoding.empty()) { + my_conv.reset(new FbTk::StringConvertor(FbTk::StringConvertor::ToFbString)); + conv = my_conv.get(); + conv->setSource(encoding); + } + + const string &str_label = getField(l, -1, "label", conv); + const string &str_key = getField(l, -1, "type"); + const FbTk::CommandParser &parser = FbTk::CommandParser::instance(); + BScreen *screen = Fluxbox::instance()->findScreen(menu.screenNumber()); + size_t old_size = menu.numberOfItems(); + + // first items that don't need additional parameters + if(str_key == "separator") + menu.insert(new FbTk::MenuSeparator()); + else if(str_key == "nop") { + int size = menu.insert(str_label); + menu.setItemEnabled(size-1, false); + } else if(str_key == "icons") { + FbTk::Menu *submenu = MenuCreator::createMenuType("iconmenu", menu.screenNumber()); + if (submenu == 0) + return; + if (str_label.empty()) + menu.insert(_FB_XTEXT(Menu, Icons, "Icons", "Iconic windows menu title"), submenu); + else + menu.insert(str_label, submenu); + } else if (str_key == "exit") { // exit + FbTk::RefCount > exit_cmd(FbTk::CommandParser::instance().parse("exit")); + if (str_label.empty()) + menu.insert(_FB_XTEXT(Menu, Exit, "Exit", "Exit Command"), exit_cmd); + else + menu.insert(str_label, exit_cmd); + } else if (str_key == "config") { + menu.insert(str_label, &screen->configMenu()); + } else if(str_key == "menu") { + l.pushvalue(-1); + menu.insert(str_label, createMenu_(l, menu.screenNumber(), *conv, reloader).release()); + } else { + // items that have a parameter + const string &str_cmd = getField(l, -1, "param"); + + if(str_key == "command") { + menu.insert(str_label, FbTk::RefCount >( + parser.parse(str_cmd)) ); + } else if(str_key == "exec") { + menu.insert(str_label, FbTk::RefCount >( + parser.parse("exec", str_cmd)) ); + } else if(str_key == "style") + menu.insert(new StyleMenuItem(str_label, str_cmd)); + else if (str_key == "stylesdir") + createStyleMenu(menu, str_label, reloader, str_cmd); + else if (str_key == "wallpapers") { + const string &program = getField(l, -1, "program"); + createRootCmdMenu(menu, str_label, str_cmd, reloader, + program.empty() ? realProgramName("fbsetbg") : program); + } else if (str_key == "workspaces") { +/* screen->workspaceMenu().setInternalMenu(); + menu.insert(str_label, &screen->workspaceMenu());*/ + } + } + + const string &icon = getField(l, -1, "icon"); + if(! icon.empty()) { + while(old_size < menu.numberOfItems()) + menu.find(old_size++)->setIcon(icon, menu.screenNumber()); + } +} + +std::auto_ptr +createMenu_(lua::state &l, int screen_number, FbTk::StringConvertor &conv, + FbTk::AutoReloadHelper *reloader) { + + lua::stack_sentry s(l, -1); + l.checkstack(1); + + std::auto_ptr menu( MenuCreator::createMenu(getField(l, -1, "label", &conv), + screen_number) ); + + for(int i = 1; l.rawgeti(-1, i), !l.isnil(-1); ++i) { + try { + insertMenuItem(l, *menu, conv, reloader); + } + catch(std::runtime_error &e) { + cerr << e.what() << endl; + } + } l.pop(); + + l.pop(); + return menu; +} + } // end of anonymous namespace +std::auto_ptr +MenuCreator::createMenu(lua::state &l, int screen_number, FbTk::AutoReloadHelper *reloader) { + lua::stack_sentry s(l, -1); + l.checkstack(1); + + if(l.type(-1) != lua::TTABLE) { + cerr << _FB_CONSOLETEXT(Menu, MenuNotTable, "Warning: Menu is not a lua table", + "Menu is not a lua table") << endl; + return std::auto_ptr(); + } + + std::auto_ptr conv(new FbTk::StringConvertor(FbTk::StringConvertor::ToFbString)); + + // if menu specifies an encoding, create a convertor for it + l.rawgetfield(-1, "encoding"); { + if(l.isstring(-1)) + conv->setSource(l.tostring(-1)); + } l.pop(); + + return createMenu_(l, screen_number, *conv, reloader); +} + + FbMenu *MenuCreator::createMenu(const string &label, int screen_number) { BScreen *screen = Fluxbox::instance()->findScreen(screen_number); if (screen == 0) diff --git a/src/MenuCreator.hh b/src/MenuCreator.hh index 91add47..4329639 100644 --- a/src/MenuCreator.hh +++ b/src/MenuCreator.hh @@ -26,6 +26,11 @@ #include "FbTk/FbString.hh" #include +#include + +namespace lua { +class state; +} namespace FbTk { class AutoReloadHelper; @@ -37,14 +42,16 @@ class FluxboxWindow; namespace MenuCreator { + std::auto_ptr + createMenu(lua::state &l, int screen_number, FbTk::AutoReloadHelper *reloader = NULL); FbMenu *createMenu(const std::string &label, int screen_num); FbMenu *createMenuType(const std::string &label, int screen_num); bool createFromFile(const std::string &filename, - FbTk::Menu &inject_into, - FbTk::AutoReloadHelper *reloader = NULL, - bool begin = true); + FbTk::Menu &inject_into, + FbTk::AutoReloadHelper *reloader = NULL, + bool begin = true); bool createWindowMenuItem(const std::string &type, const std::string &label, FbTk::Menu &inject_into); -}; +} #endif // MENUCREATOR_HH diff --git a/src/Screen.cc b/src/Screen.cc index 52d7f8e..64512eb 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -1384,8 +1384,13 @@ void BScreen::reassociateWindow(FluxboxWindow *w, unsigned int wkspc_id, } void BScreen::initMenus() { + lua::state &l = Fluxbox::instance()->lua(); m_workspacemenu.reset(MenuCreator::createMenuType("workspacemenu", screenNumber())); - m_rootmenu->reloadHelper()->setMainFile(Fluxbox::instance()->getMenuFilename()); + l.loadfile(FbTk::StringUtil::expandFilename(Fluxbox::instance()->getMenuFilename()).c_str()); + l.call(0, 0); + l.getglobal("menu"); + m_rootmenu = MenuCreator::createMenu(l, 0); +// m_rootmenu->reloadHelper()->setMainFile(Fluxbox::instance()->getMenuFilename()); m_windowmenu->reloadHelper()->setMainFile(windowMenuFilename()); } -- cgit v0.11.2