// ConfigMenu.cc for Fluxbox Window Manager // Copyright (c) 2015 - Mathias Gumz <akira@fluxbox.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 "ConfigMenu.hh" #include "MenuCreator.hh" #include "Screen.hh" #include "fluxbox.hh" #include "FocusModelMenuItem.hh" #include "ScreenPlacement.hh" #include "FbMenu.hh" #include "ToggleMenu.hh" #include "FbTk/Menu.hh" #include "FbTk/BoolMenuItem.hh" #include "FbTk/IntMenuItem.hh" #include "FbTk/MenuSeparator.hh" #include "FbTk/RadioMenuItem.hh" #include "FbTk/MacroCommand.hh" #include "FbTk/CommandParser.hh" #include "FbTk/SimpleCommand.hh" #include "FbTk/Transparent.hh" #include "FbTk/Resource.hh" #include "FbTk/I18n.hh" namespace { class TabPlacementMenuItem: public FbTk::RadioMenuItem { public: TabPlacementMenuItem(const FbTk::FbString & label, BScreen &screen, FbWinFrame::TabPlacement place, FbTk::RefCount<FbTk::Command<void> > &cmd): FbTk::RadioMenuItem(label, cmd), m_screen(screen), m_place(place) { setCloseOnClick(false); } bool isSelected() const { return m_screen.getTabPlacement() == m_place; } void click(int button, int time, unsigned int mods) { m_screen.saveTabPlacement(m_place); FbTk::RadioMenuItem::click(button, time, mods); } private: BScreen &m_screen; FbWinFrame::TabPlacement m_place; }; typedef FbTk::RefCount<FbTk::Command<void> > _Cmd; // NOTE: might also be placed into MenuCreator; for now it ends up here // because it's just used here FbMenu *createToggleMenu(const std::string &label, BScreen& screen) { FbTk::Layer* layer = screen.layerManager().getLayer(ResourceLayer::MENU); FbMenu *menu = new ToggleMenu(screen.menuTheme(), screen.imageControl(), *layer); if (!label.empty()) menu->setLabel(label); return menu; } void setupAlphaMenu(FbTk::Menu& parent, ConfigMenu::SetupHelper& sh, _Cmd& save_reconf) { #ifdef HAVE_XRENDER _FB_USES_NLS; enum { L_ALPHA = 0, L_PSEUDO_TRANS, L_FOCUS_ALPHA, L_UNFOCUS_ALPHA, L_MENU_ALPHA, }; static const FbTk::FbString _labels[] = { _FB_XTEXT(Configmenu, Transparency, "Transparency", "Menu containing various transparency options"), _FB_XTEXT(Configmenu, ForcePseudoTrans, "Force Pseudo-Transparency", "When composite is available, still use old pseudo-transparency"), _FB_XTEXT(Configmenu, FocusedAlpha, "Focused Window Alpha", "Transparency level of the focused window"), _FB_XTEXT(Configmenu, UnfocusedAlpha, "Unfocused Window Alpha", "Transparency level of unfocused windows"), _FB_XTEXT(Configmenu, MenuAlpha, "Menu Alpha", "Transparency level of menu") }; FbTk::FbString label = _labels[L_ALPHA]; FbTk::Menu* menu = MenuCreator::createMenu(label, sh.screen); if (FbTk::Transparent::haveComposite(true)) { static FbTk::SimpleAccessor<bool> s_pseudo = Fluxbox::instance()->getPseudoTrans(); menu->insertItem(new FbTk::BoolMenuItem(_labels[L_PSEUDO_TRANS], s_pseudo, save_reconf)); } // in order to save system resources, don't save or reconfigure alpha // settings until after the user is done changing them _Cmd delayed_save_and_reconf(new FbTk::DelayedCmd(save_reconf)); FbTk::MenuItem *focused_alpha_item = new FbTk::IntMenuItem(_labels[L_FOCUS_ALPHA], sh.resource.focused_alpha, 0, 255, *menu); focused_alpha_item->setCommand(delayed_save_and_reconf); menu->insertItem(focused_alpha_item); FbTk::MenuItem *unfocused_alpha_item = new FbTk::IntMenuItem(_labels[L_UNFOCUS_ALPHA], sh.resource.unfocused_alpha, 0, 255, *menu); unfocused_alpha_item->setCommand(delayed_save_and_reconf); menu->insertItem(unfocused_alpha_item); FbTk::MenuItem *menu_alpha_item = new FbTk::IntMenuItem(_labels[L_MENU_ALPHA], sh.resource.menu_alpha, 0, 255, *menu); menu_alpha_item->setCommand(delayed_save_and_reconf); menu->insertItem(menu_alpha_item); menu->updateMenu(); parent.insertSubmenu(label, menu); #endif } #define _BOOLITEM(m,a, b, c, d, e, f) (m).insertItem(new FbTk::BoolMenuItem(_FB_XTEXT(a, b, c, d), e, f)) void setupFocusMenu(FbTk::Menu& menu, ConfigMenu::SetupHelper& sh, _Cmd& save_rc, _Cmd& save_reconf) { _FB_USES_NLS; // we don't set this to internal menu so will // be deleted toghether with the parent FbTk::FbString label = _FB_XTEXT(Configmenu, FocusModel, "Focus Model", "Method used to give focus to windows"); FbMenu* fm = MenuCreator::createMenu(label, sh.screen); #define _FOCUSITEM(a, b, c, d, e) \ fm->insertItem(new FocusModelMenuItem(_FB_XTEXT(a, b, c, d), sh.screen.focusControl(), \ e, save_reconf)) _FOCUSITEM(Configmenu, ClickFocus, "Click To Focus", "Click to focus", FocusControl::CLICKFOCUS); _FOCUSITEM(Configmenu, MouseFocus, "Mouse Focus (Keyboard Friendly)", "Mouse Focus (Keyboard Friendly)", FocusControl::MOUSEFOCUS); _FOCUSITEM(Configmenu, StrictMouseFocus, "Mouse Focus (Strict)", "Mouse Focus (Strict)", FocusControl::STRICTMOUSEFOCUS); #undef _FOCUSITEM fm->insertItem(new FbTk::MenuSeparator()); fm->insertItem(new TabFocusModelMenuItem(_FB_XTEXT(Configmenu, ClickTabFocus, "ClickTabFocus", "Click tab to focus windows"), sh.screen.focusControl(), FocusControl::CLICKTABFOCUS, save_reconf)); fm->insertItem(new TabFocusModelMenuItem(_FB_XTEXT(Configmenu, MouseTabFocus, "MouseTabFocus", "Hover over tab to focus windows"), sh.screen.focusControl(), FocusControl::MOUSETABFOCUS, save_reconf)); fm->insertItem(new FbTk::MenuSeparator()); try { fm->insertItem(new FbTk::BoolMenuItem(_FB_XTEXT(Configmenu, FocusNew, "Focus New Windows", "Focus newly created windows"), sh.rm.getResource<bool>(sh.screen.name() + ".focusNewWindows"), save_rc)); } catch (FbTk::ResourceException & e) { std::cerr<<e.what()<<std::endl; } #ifdef XINERAMA try { fm->insertItem(new FbTk::BoolMenuItem(_FB_XTEXT(Configmenu, FocusSameHead, "Keep Head", "Only revert focus on same head"), sh.rm.getResource<bool>(sh.screen.name() + ".focusSameHead"), save_rc)); } catch (FbTk::ResourceException e) { std::cerr << e.what() << std::endl; } #endif // XINERAMA _BOOLITEM(*fm, Configmenu, AutoRaise, "Auto Raise", "Auto Raise windows on sloppy", sh.resource.auto_raise, save_rc); _BOOLITEM(*fm, Configmenu, ClickRaises, "Click Raises", "Click Raises", sh.resource.click_raises, save_rc); fm->updateMenu(); menu.insertSubmenu(label, fm); } void setupMaximizeMenu(FbTk::Menu& menu, ConfigMenu::SetupHelper& sh, _Cmd& save_rc) { _FB_USES_NLS; FbTk::FbString label = _FB_XTEXT(Configmenu, MaxMenu, "Maximize Options", "heading for maximization options"); FbTk::Menu* mm = MenuCreator::createMenu(label, sh.screen); _BOOLITEM(*mm, Configmenu, FullMax, "Full Maximization", "Maximise over slit, toolbar, etc", sh.resource.full_max, save_rc); _BOOLITEM(*mm, Configmenu, MaxIgnoreInc, "Ignore Resize Increment", "Maximizing Ignores Resize Increment (e.g. xterm)", sh.resource.max_ignore_inc, save_rc); _BOOLITEM(*mm, Configmenu, MaxDisableMove, "Disable Moving", "Don't Allow Moving While Maximized", sh.resource.max_disable_move, save_rc); _BOOLITEM(*mm, Configmenu, MaxDisableResize, "Disable Resizing", "Don't Allow Resizing While Maximized", sh.resource.max_disable_resize, save_rc); mm->updateMenu(); menu.insertSubmenu(label, mm); } void setupTabMenu(FbTk::Menu& parent, ConfigMenu::SetupHelper& sh, _Cmd& save_reconf, _Cmd& save_reconftabs) { _FB_USES_NLS; FbTk::FbString label = _FB_XTEXT(Configmenu, TabMenu, "Tab Options", "heading for tab-related options"); // TODO: main-category is 'Menu'?? should be 'ConfigMenu'??? FbTk::FbString p_label = _FB_XTEXT(Menu, Placement, "Placement", "Title of Placement menu"); FbTk::Menu* menu = MenuCreator::createMenu(label, sh.screen); FbTk::Menu* p_menu = createToggleMenu(p_label, sh.screen); menu->insertSubmenu(p_label, p_menu); menu->insertItem(new FbTk::BoolMenuItem(_FB_XTEXT(Configmenu, TabsInTitlebar, "Tabs in Titlebar", "Tabs in Titlebar"), sh.resource.default_internal_tabs, save_reconftabs)); menu->insertItem(new FbTk::BoolMenuItem(_FB_XTEXT(Common, MaximizeOver, "Maximize Over", "Maximize over this thing when maximizing"), sh.resource.max_over_tabs, save_reconf)); menu->insertItem(new FbTk::BoolMenuItem(_FB_XTEXT(Toolbar, ShowIcons, "Show Pictures", "chooses if little icons are shown next to title in the iconbar"), sh.resource.tabs_use_pixmap, save_reconf)); FbTk::MenuItem *tab_width_item = new FbTk::IntMenuItem(_FB_XTEXT(Configmenu, ExternalTabWidth, "External Tab Width", "Width of external-style tabs"), sh.resource.tab_width, 10, 3000, /* silly number */ *menu); tab_width_item->setCommand(save_reconftabs); menu->insertItem(tab_width_item); // menu is 3 wide, 5 down struct PlacementP { const FbTk::FbString label; FbWinFrame::TabPlacement placement; }; static const PlacementP place_menu[] = { { _FB_XTEXT(Align, TopLeft, "Top Left", "Top Left"), FbWinFrame::TOPLEFT}, { _FB_XTEXT(Align, LeftTop, "Left Top", "Left Top"), FbWinFrame::LEFTTOP}, { _FB_XTEXT(Align, LeftCenter, "Left Center", "Left Center"), FbWinFrame::LEFT}, { _FB_XTEXT(Align, LeftBottom, "Left Bottom", "Left Bottom"), FbWinFrame::LEFTBOTTOM}, { _FB_XTEXT(Align, BottomLeft, "Bottom Left", "Bottom Left"), FbWinFrame::BOTTOMLEFT}, { _FB_XTEXT(Align, TopCenter, "Top Center", "Top Center"), FbWinFrame::TOP}, { "", FbWinFrame::TOPLEFT}, { "", FbWinFrame::TOPLEFT}, { "", FbWinFrame::TOPLEFT}, { _FB_XTEXT(Align, BottomCenter, "Bottom Center", "Bottom Center"), FbWinFrame::BOTTOM}, { _FB_XTEXT(Align, TopRight, "Top Right", "Top Right"), FbWinFrame::TOPRIGHT}, { _FB_XTEXT(Align, RightTop, "Right Top", "Right Top"), FbWinFrame::RIGHTTOP}, { _FB_XTEXT(Align, RightCenter, "Right Center", "Right Center"), FbWinFrame::RIGHT}, { _FB_XTEXT(Align, RightBottom, "Right Bottom", "Right Bottom"), FbWinFrame::RIGHTBOTTOM}, { _FB_XTEXT(Align, BottomRight, "Bottom Right", "Bottom Right"), FbWinFrame::BOTTOMRIGHT} }; p_menu->setMinimumColumns(3); // create items in sub menu for (size_t i=0; i< sizeof(place_menu)/sizeof(PlacementP); ++i) { const PlacementP& p = place_menu[i]; if (p.label == "") { p_menu->insert(p.label); p_menu->setItemEnabled(i, false); } else p_menu->insertItem(new TabPlacementMenuItem(p.label, sh.screen, p.placement, save_reconftabs)); } p_menu->updateMenu(); menu->updateMenu(); parent.insertSubmenu(label, menu); } } void ConfigMenu::setup(FbTk::Menu& menu, ConfigMenu::SetupHelper& sh) { _FB_USES_NLS; FbTk::MacroCommand *s_a_reconf_macro = new FbTk::MacroCommand(); FbTk::MacroCommand *s_a_reconftabs_macro = new FbTk::MacroCommand(); _Cmd saverc_cmd(new FbTk::SimpleCommand<Fluxbox>( *Fluxbox::instance(), &Fluxbox::save_rc)); _Cmd reconf_cmd(FbTk::CommandParser<void>::instance().parse("reconfigure")); _Cmd reconftabs_cmd(new FbTk::SimpleCommand<BScreen>(sh.screen, &BScreen::reconfigureTabs)); s_a_reconf_macro->add(saverc_cmd); s_a_reconf_macro->add(reconf_cmd); s_a_reconftabs_macro->add(saverc_cmd); s_a_reconftabs_macro->add(reconftabs_cmd); _Cmd save_and_reconfigure(s_a_reconf_macro); _Cmd save_and_reconftabs(s_a_reconftabs_macro); setupFocusMenu(menu, sh, saverc_cmd, save_and_reconfigure); setupMaximizeMenu(menu, sh, saverc_cmd); setupTabMenu(menu, sh, save_and_reconfigure, save_and_reconftabs); #ifdef HAVE_XRENDER if (FbTk::Transparent::haveRender() || FbTk::Transparent::haveComposite()) { setupAlphaMenu(menu, sh, save_and_reconfigure); } #endif // HAVE_XRENDER _BOOLITEM(menu, Configmenu, OpaqueMove, "Opaque Window Moving", "Window Moving with whole window visible (as opposed to outline moving)", sh.resource.opaque_move, saverc_cmd); _BOOLITEM(menu, Configmenu, WorkspaceWarping, "Workspace Warping", "Workspace Warping - dragging windows to the edge and onto the next workspace", sh.resource.workspace_warping, saverc_cmd); #undef _BOOLITEM menu.updateMenu(); }