all repos — fluxbox @ fe4a7db228d69bc9a66ed948f218ef489b2cedaf

custom fork of the fluxbox windowmanager

external tabs features and bugfixes
simonb simonb
commit

fe4a7db228d69bc9a66ed948f218ef489b2cedaf

parent

da365bb4c99edf1a18e1f8db285f8c2dcee2c5e3

M ChangeLogChangeLog

@@ -1,5 +1,14 @@

(Format: Year/Month/Day) Changes for 0.9.16: +*06/03/22: + * More external tabs work (Simon) + - Can now be placed TopLeft/TopRight/BottomLeft/BottomRight + - New "Tab Options" config menu, with (efficient) runtime updating + - edge snapping includes tabs + - decoration fixes where some missed the tab option + - label text color was not updated + Screen.hh/cc Window.hh/cc FbWinFrame.hh/cc Container.cc + fluxbox-nls.hh *06/03/20: * Fix placement config (some compilers resulted in ignoring of placement policy setting), and a minor ext. tabs placement bug
M nls/fluxbox-nls.hhnls/fluxbox-nls.hh

@@ -72,7 +72,8 @@ ConfigmenuMenuAlpha = 17,

ConfigmenuTransparency = 18, ConfigmenuFocusedAlpha = 19, ConfigmenuUnfocusedAlpha = 20, - ConfigmenuExternalTabs = 21, + ConfigmenuTabMenu = 21, + ConfigmenuTabsInTitlebar = 22, EwmhSet = 5, EwmhOutOfMemoryClientList = 1,
M src/Container.ccsrc/Container.cc

@@ -264,10 +264,16 @@ m_max_size_per_client = size;

} void Container::setMaxTotalSize(unsigned int size) { + if (m_max_total_size == size) + return; + + unsigned int old = m_max_total_size; m_max_total_size = size; if (m_max_total_size && width() > m_max_total_size) { resize(m_max_total_size, height()); + } else if (!m_max_total_size && old) { // going from restricted to unrestricted + repositionItems(); } else { // this is a bit of duplication from repositionItems // for when we are allowed to grow ourself

@@ -286,7 +292,6 @@

if (preferred_width != width()) repositionItems(); } - } }

@@ -381,7 +386,10 @@ max_width_per_client = 1;

} if (total_width != width()) { // calling Container::resize here risks infinite loops - FbTk::FbWindow::resize(total_width, height()); + if (align == RIGHT) + FbTk::FbWindow::moveResize(x() - (total_width - width()), y(), total_width, height()); + else + FbTk::FbWindow::resize(total_width, height()); } }

@@ -396,7 +404,7 @@ int extra = 0;

int direction = 1; if (align == RIGHT) { direction = -1; - next_x = total_width - max_width_per_client + borderW; + next_x = total_width - max_width_per_client - borderW; } for (; it != it_end; ++it, next_x += direction*(max_width_per_client + borderW + extra)) {
M src/FbWinFrame.ccsrc/FbWinFrame.cc

@@ -80,6 +80,7 @@ ButtonMotionMask | ExposureMask |

EnterWindowMask | LeaveWindowMask), m_bevel(1), m_use_titlebar(true), + m_tabplacement(BOTTOMRIGHT), m_use_tabs(true), m_use_handle(true), m_focused(false),

@@ -126,9 +127,11 @@ // something is likely to change

if (tabmode == NOTSET) tabmode = m_tabmode; + m_tabmode = tabmode; + // reparent tab container if (tabmode == EXTERNAL) { - + m_label.show(); m_tab_container.setBorderWidth(m_window.borderWidth()); m_tab_container.setBorderColor(theme().border().color()); m_tab_container.setEventMask(

@@ -141,15 +144,35 @@ m_tab_container.window(), True, ButtonPressMask,

GrabModeSync, GrabModeSync, None, None); XUngrabButton(m_tab_container.display(), Button1, Mod1Mask|Mod2Mask|Mod3Mask, m_tab_container.window()); + int tabx, taby; + switch (m_tabplacement) { + case TOPLEFT: + m_tab_container.setAlignment(Container::LEFT); + tabx = x(); + taby = y() - yOffset(); + break; + case TOPRIGHT: + m_tab_container.setAlignment(Container::RIGHT); + tabx = x() + width() - m_tab_container.width(); + taby = y() - yOffset(); + break; + case BOTTOMLEFT: + m_tab_container.setAlignment(Container::LEFT); + tabx = x(); + taby = y() + height() + m_window.borderWidth(); + break; + case BOTTOMRIGHT: + m_tab_container.setAlignment(Container::RIGHT); + tabx = x() + width() - m_tab_container.width(); + taby = y() + height() + m_window.borderWidth(); + break; + } + if (m_tab_container.parent()->window() != m_screen.rootWindow().window()) { - int tabx = x(); - // one borderwidth only, so the adjacent borders overlab - int taby = y() - m_tab_container.height() - m_tab_container.borderWidth(); m_tab_container.reparent(m_screen.rootWindow(), tabx, taby); m_layeritem.addWindow(m_tab_container); } - m_tab_container.setAlignment(Container::LEFT); m_tab_container.setMaxSizePerClient(64); //!!TODO make this a setting m_tab_container.setMaxTotalSize(window().width());

@@ -162,23 +185,24 @@ m_tab_container.hide();

} } else { + m_tab_container.setAlignment(Container::RELATIVE); if (m_tab_container.parent()->window() == m_screen.rootWindow().window()) { m_layeritem.removeWindow(m_tab_container); m_tab_container.reparent(m_titlebar, m_label.x(), m_label.y()); + m_tab_container.resize(m_label.width(), m_label.height()); m_tab_container.raise(); } m_tab_container.setBorderWidth(0); m_tab_container.setMaxTotalSize(0); m_tab_container.setMaxSizePerClient(0); - m_tab_container.setAlignment(Container::RELATIVE); if (!m_use_tabs) m_tab_container.show(); else ret = false; + m_label.hide(); // reconfigure(); } - m_tabmode = tabmode; return true; }

@@ -286,7 +310,7 @@ } else {

m_window.resize(width, height); } - if (move) + if (move || resize && m_tabplacement != TOPLEFT) alignTabs(); if (resize) {

@@ -306,8 +330,30 @@ }

} void FbWinFrame::alignTabs() { - if (m_tabmode == EXTERNAL) - m_tab_container.move(m_window.x(), m_window.y() - m_tab_container.height() - m_tab_container.borderWidth()); + if (m_tabmode != EXTERNAL) + return; + + int tabx = 0, taby = 0; + switch (m_tabplacement) { + case TOPLEFT: + tabx = x(); + taby = y() - yOffset(); + break; + case TOPRIGHT: + tabx = x() + width() - m_tab_container.width(); + taby = y() - yOffset(); + break; + case BOTTOMLEFT: + tabx = x(); + taby = y() + height() + m_window.borderWidth(); + break; + case BOTTOMRIGHT: + tabx = x() + width() - m_tab_container.width(); + taby = y() + height() + m_window.borderWidth(); + break; + } + + m_tab_container.move(tabx, taby); } void FbWinFrame::notifyMoved(bool clear) {

@@ -1077,6 +1123,9 @@ unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha());

m_titlebar.setAlpha(alpha); m_label.setAlpha(alpha); + if (externalTabMode()) + m_label.setGC(m_focused?theme().labelTextFocusGC():theme().labelTextUnfocusGC()); + if (label_pm != 0) m_label.setBackgroundPixmap(label_pm); else

@@ -1398,6 +1447,7 @@

} void FbWinFrame::applyActiveLabel(FbTk::TextButton &button) { + button.setBorderWidth(1); button.setGC(theme().labelTextActiveGC()); button.setJustify(theme().justify());

@@ -1544,16 +1594,26 @@ }

} int FbWinFrame::heightOffset() const { - if (m_tabmode == EXTERNAL && m_use_tabs) - return m_tab_container.height() + m_window.borderWidth(); - else + if (m_tabmode != EXTERNAL || !m_use_tabs) return 0; + + // same height offset for top and bottom tabs + return m_tab_container.height() + m_window.borderWidth(); } int FbWinFrame::yOffset() const { - if (m_tabmode == EXTERNAL && m_use_tabs) + if (m_tabmode != EXTERNAL || !m_use_tabs) + return 0; + + switch (m_tabplacement) { + case TOPLEFT: + case TOPRIGHT: return m_tab_container.height() + m_window.borderWidth(); - else + break; + case BOTTOMLEFT: + case BOTTOMRIGHT: return 0; + break; + } }
M src/FbWinFrame.hhsrc/FbWinFrame.hh

@@ -59,6 +59,17 @@ public:

// STRICTINTERNAL means it doesn't go external automatically when no titlebar enum TabMode { NOTSET = 0, INTERNAL = 1, EXTERNAL }; + /// Toolbar placement on the screen + enum TabPlacement{ + // top and bottom placement + TOPLEFT = 1, BOTTOMLEFT, + TOPRIGHT, BOTTOMRIGHT + // left and right placement +// LEFTBOTTOM, LEFTTOP, +// RIGHTBOTTOM, RIGHTTOP + }; + + typedef FbTk::TextButton *ButtonId; ///< defines a button id /// create a top level window

@@ -114,6 +125,7 @@ void setFocus(bool newvalue);

inline void setFocusTitle(const std::string &str) { m_label.setText(str); } void setDoubleClickTime(unsigned int time); bool setTabMode(TabMode tabmode); + inline void setTabPlacement(TabPlacement tabplacement) { m_tabplacement = tabplacement; alignTabs(); } /// add a button to the left of the label void addLeftButton(FbTk::Button *btn);

@@ -222,7 +234,7 @@ /// @return titlebar height

unsigned int titlebarHeight() const { return m_titlebar.height(); } /// @return size of button unsigned int buttonHeight() const; - bool externalTabMode() const { return m_tabmode == EXTERNAL; } + bool externalTabMode() const { return m_tabmode == EXTERNAL && m_use_tabs; } inline const FbTk::XLayerItem &layerItem() const { return m_layeritem; } inline FbTk::XLayerItem &layerItem() { return m_layeritem; }

@@ -355,6 +367,7 @@ FbTk::Color m_grip_unfocused_color; ///< unfocused color for grip if no pixmap is given

//@} TabMode m_tabmode; + TabPlacement m_tabplacement; bool m_need_render; int m_button_size; ///< size for all titlebar buttons
M src/Screen.ccsrc/Screen.cc

@@ -156,9 +156,93 @@ return -1;

} +class TabPlacementMenuItem: public FbTk::MenuItem { +public: + TabPlacementMenuItem(const char * label, BScreen &screen, FbWinFrame::TabPlacement place, FbTk::RefCount<FbTk::Command> &cmd): + FbTk::MenuItem(label, cmd), + m_screen(screen), + m_place(place) { } + + bool isEnabled() const { return m_screen.getTabPlacement() != m_place; } + void click(int button, int time) { + m_screen.saveTabPlacement(m_place); + FbTk::MenuItem::click(button, time); + } + + +private: + BScreen &m_screen; + FbWinFrame::TabPlacement m_place; +}; } // end anonymous namespace + + +namespace FbTk { + +template<> +void FbTk::Resource<FbWinFrame::TabPlacement>:: +setFromString(const char *strval) { + if (strcasecmp(strval, "TopLeft")==0) + m_value = FbWinFrame::TOPLEFT; + else if (strcasecmp(strval, "BottomLeft")==0) + m_value = FbWinFrame::BOTTOMLEFT; + else if (strcasecmp(strval, "TopRight")==0) + m_value = FbWinFrame::TOPRIGHT; + else if (strcasecmp(strval, "BottomRight")==0) + m_value = FbWinFrame::BOTTOMRIGHT; + /* + else if (strcasecmp(strval, "LeftTop") == 0) + m_value = FbWinFrame::LEFTTOP; + else if (strcasecmp(strval, "LeftBottom") == 0) + m_value = FbWinFrame::LEFTBOTTOM; + else if (strcasecmp(strval, "RightTop") == 0) + m_value = FbWinFrame::RIGHTTOP; + else if (strcasecmp(strval, "RightBottom") == 0) + m_value = FbWinFrame::RIGHTBOTTOM; + */ + else + setDefaultValue(); +} + +template<> +string FbTk::Resource<FbWinFrame::TabPlacement>:: +getString() const { + switch (m_value) { + case FbWinFrame::TOPLEFT: + return string("TopLeft"); + break; + case FbWinFrame::BOTTOMLEFT: + return string("BottomLeft"); + break; + case FbWinFrame::TOPRIGHT: + return string("TopRight"); + break; + case FbWinFrame::BOTTOMRIGHT: + return string("BottomRight"); + break; +/* + case FbWinFrame::LEFTTOP: + return string("LeftTop"); + break; + case FbWinFrame::LEFTBOTTOM: + return string("LeftBottom"); + break; + case FbWinFrame::RIGHTTOP: + return string("RightTop"); + break; + case FbWinFrame::RIGHTBOTTOM: + return string("RightBottom"); + break; +*/ + } + //default string + return string("TopLeft"); +} +} // end namespace FbTk + + BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm, const std::string &scrname, const std::string &altscrname):

@@ -176,6 +260,7 @@ click_raises(rm, true, scrname+".clickRaises", altscrname+".ClickRaises"),

decorate_transient(rm, false, scrname+".decorateTransient", altscrname+".DecorateTransient"), rootcommand(rm, "", scrname+".rootCommand", altscrname+".RootCommand"), resize_model(rm, BOTTOMRESIZE, scrname+".resizeMode", altscrname+".ResizeMode"), + tab_placement(rm, FbWinFrame::TOPLEFT, scrname+".tab.placement", altscrname+".Tab.Placement"), windowmenufile(rm, "", scrname+".windowMenu", altscrname+".WindowMenu"), follow_model(rm, IGNORE_OTHER_WORKSPACES, scrname+".followModel", altscrname+".followModel"), workspaces(rm, 1, scrname+".workspaces", altscrname+".Workspaces"),

@@ -202,7 +287,7 @@ scrname+".overlay.capStyle",

altscrname+".overlay.CapStyle"), scroll_action(rm, "", scrname+".windowScrollAction", altscrname+".WindowScrollAction"), scroll_reverse(rm, false, scrname+".windowScrollReverse", altscrname+".WindowScrollReverse"), - default_external_tabs(rm, false /* TODO: autoconf option? */ , scrname+".externalTabs", altscrname+".ExternalTabs") { + default_internal_tabs(rm, false /* TODO: autoconf option? */ , scrname+".tabs.intitlebar", altscrname+".Tabs.InTitlebar") { }

@@ -330,7 +415,7 @@ addWorkspace();

} m_current_workspace = m_workspaces_list.front(); - + //!! TODO: we shouldn't do this more than once, but since slit handles their // own resources we must do this.

@@ -626,6 +711,15 @@ menu->setLabel(label.c_str());

return menu; } +FbTk::Menu *BScreen::createToggleMenu(const std::string &label) { + FbTk::Menu *menu = new ToggleMenu(menuTheme(), + imageControl(), + *layerManager().getLayer(Layer::MENU)); + if (!label.empty()) + menu->setLabel(label.c_str()); + + return menu; +} void BScreen::addExtraWindowMenu(const char *label, FbTk::Menu *menu) { menu->setInternalMenu();

@@ -794,6 +888,26 @@ // Reload style

FbTk::ThemeManager::instance().load(fluxbox->getStyleFilename(), fluxbox->getStyleOverlayFilename(), m_root_theme->screenNum()); + + reconfigureTabs(); +} + +void BScreen::reconfigureTabs() { + Workspaces::iterator w_it = getWorkspacesList().begin(); + const Workspaces::iterator w_it_end = getWorkspacesList().end(); + for (; w_it != w_it_end; ++w_it) { + if ((*w_it)->windowList().size()) { + Workspace::Windows::iterator win_it = (*w_it)->windowList().begin(); + const Workspace::Windows::iterator win_it_end = (*w_it)->windowList().end(); + for (; win_it != win_it_end; ++win_it) { + (*win_it)->frame().setTabPlacement(*resource.tab_placement); + if (*resource.default_internal_tabs) + (*win_it)->frame().setTabMode(FbWinFrame::INTERNAL); + else + (*win_it)->frame().setTabMode(FbWinFrame::EXTERNAL); + } + } + } }

@@ -1454,12 +1568,21 @@

menu.removeAll(); FbTk::MacroCommand *s_a_reconf_macro = new FbTk::MacroCommand(); - FbTk::RefCount<FbTk::Command> saverc_cmd(new FbTk::SimpleCommand<Fluxbox>(*Fluxbox::instance(), - &Fluxbox::save_rc)); + FbTk::MacroCommand *s_a_reconftabs_macro = new FbTk::MacroCommand(); + FbTk::RefCount<FbTk::Command> saverc_cmd(new FbTk::SimpleCommand<Fluxbox>( + *Fluxbox::instance(), + &Fluxbox::save_rc)); FbTk::RefCount<FbTk::Command> reconf_cmd(CommandParser::instance().parseLine("reconfigure")); + + FbTk::RefCount<FbTk::Command> reconftabs_cmd(new FbTk::SimpleCommand<BScreen>( + *this, + &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); FbTk::RefCount<FbTk::Command> save_and_reconfigure(s_a_reconf_macro); + FbTk::RefCount<FbTk::Command> save_and_reconftabs(s_a_reconftabs_macro); // create focus menu // we don't set this to internal menu so will // be deleted toghether with the parent

@@ -1468,6 +1591,9 @@ "Focus Model",

"Method used to give focus to windows"); FbTk::Menu *focus_menu = createMenu(focusmenu_label ? focusmenu_label : ""); +#define _BOOLITEM(m,a, b, c, d, e, f) (m).insert(new BoolMenuItem(_FBTEXT(a, b, c, d), e, f)) + + #define _FOCUSITEM(a, b, c, d, e) \ focus_menu->insert(new FocusModelMenuItem(_FBTEXT(a, b, c, d), focusControl(), \ e, save_and_reconfigure))

@@ -1498,6 +1624,84 @@

focus_menu->updateMenu(); menu.insert(focusmenu_label, focus_menu); + + // END focus menu + + // BEGIN tab menu + + const char *tabmenu_label = _FBTEXT(Configmenu, TabMenu, + "Tab Options", + "heading for tab-related options"); + FbTk::Menu *tab_menu = createMenu(tabmenu_label ? tabmenu_label : ""); + const char *tabplacement_label = _FBTEXT(Menu, Placement, "Placement", "Title of Placement menu"); + FbTk::Menu *tabplacement_menu = createToggleMenu(tabplacement_label); + + tab_menu->insert(tabplacement_label, tabplacement_menu); + + _BOOLITEM(*tab_menu,Configmenu, TabsInTitlebar, + "Tabs in Titlebar", "Tabs in Titlebar", + *resource.default_internal_tabs, save_and_reconftabs); + + typedef pair<const char*, FbWinFrame::TabPlacement> PlacementP; + typedef list<PlacementP> Placements; + Placements place_menu; + + // menu is 3 wide, 5 down + place_menu.push_back(PlacementP(_FBTEXT(Align, TopLeft, "Top Left", "Top Left"), FbWinFrame::TOPLEFT)); + place_menu.push_back(PlacementP(_FBTEXT(Align, BottomLeft, "Bottom Left", "Bottom Left"), FbWinFrame::BOTTOMLEFT)); + place_menu.push_back(PlacementP(_FBTEXT(Align, TopRight, "Top Right", "Top Right"), FbWinFrame::TOPRIGHT)); + place_menu.push_back(PlacementP(_FBTEXT(Align, BottomRight, "Bottom Right", "Bottom Right"), FbWinFrame::BOTTOMRIGHT)); + +/* + place_menu.push_back(PlacementP(_FBTEXT(Align, LeftTop, "Left Top", "Left Top"), FbWinFrame::LEFTTOP)); + place_menu.push_back(PlacementP(_FBTEXT(Align, LeftBottom, "Left Bottom", "Left Bottom"), FbWinFrame::LEFTBOTTOM)); + place_menu.push_back(PlacementP(_FBTEXT(Align, RightTop, "Right Top", "Right Top"), FbWinFrame::RIGHTTOP)); + place_menu.push_back(PlacementP(_FBTEXT(Align, RightBottom, "Right Bottom", "Right Bottom"), FbWinFrame::RIGHTBOTTOM)); +*/ + + tabplacement_menu->setMinimumSublevels(2); + // create items in sub menu + size_t i=0; + while (!place_menu.empty()) { + i++; + const char *str = place_menu.front().first; + FbWinFrame::TabPlacement placement = place_menu.front().second; + + if (str == 0) { + tabplacement_menu->insert(""); + tabplacement_menu->setItemEnabled(i, false); + } else { + tabplacement_menu->insert(new TabPlacementMenuItem(str, *this, placement, save_and_reconftabs)); + } + place_menu.pop_front(); + } + tabplacement_menu->updateMenu(); + + menu.insert(tabmenu_label, tab_menu); + +#undef _FOCUSITEM + + focus_menu->insert(new TabFocusModelMenuItem("ClickTabFocus", focusControl(), + FocusControl::CLICKTABFOCUS, + save_and_reconfigure)); + focus_menu->insert(new TabFocusModelMenuItem("MouseTabFocus", focusControl(), + FocusControl::MOUSETABFOCUS, + save_and_reconfigure)); + + + focus_menu->insert(new BoolMenuItem(_FBTEXT(Configmenu, + AutoRaise, + "Auto Raise", + "Auto Raise windows on sloppy"), + *resource.auto_raise, + save_and_reconfigure)); + + focus_menu->updateMenu(); + + menu.insert(focusmenu_label, focus_menu); + + // end tab menu + #ifdef SLIT if (slit() != 0) { slit()->menu().setInternalMenu();

@@ -1510,20 +1714,18 @@ Configmenus::iterator it_end = m_configmenu_list.end();

for (; it != it_end; ++it) menu.insert(it->first, it->second); -#define _BOOLITEM(a, b, c, d, e, f) menu.insert(new BoolMenuItem(_FBTEXT(a, b, c, d), e, f)) - - _BOOLITEM(Configmenu, ImageDithering, + _BOOLITEM(menu, Configmenu, ImageDithering, "Image Dithering", "Image Dithering", *resource.image_dither, save_and_reconfigure); - _BOOLITEM(Configmenu, OpaqueMove, + _BOOLITEM(menu, Configmenu, OpaqueMove, "Opaque Window Moving", "Window Moving with whole window visible (as opposed to outline moving)", *resource.opaque_move, saverc_cmd); - _BOOLITEM(Configmenu, FullMax, + _BOOLITEM(menu, Configmenu, FullMax, "Full Maximization", "Maximise over slit, toolbar, etc", *resource.full_max, saverc_cmd); try { - _BOOLITEM(Configmenu, FocusNew, + _BOOLITEM(menu, Configmenu, FocusNew, "Focus New Windows", "Focus newly created windows", *m_resource_manager.getResource<bool>(name() + ".focusNewWindows"), saverc_cmd);

@@ -1532,7 +1734,7 @@ cerr<<e.what()<<endl;

} try { - _BOOLITEM(Configmenu, FocusLast, + _BOOLITEM(menu, Configmenu, FocusLast, "Focus Last Window on Workspace", "Focus Last Window on Workspace", *resourceManager().getResource<bool>(name() + ".focusLastWindow"), saverc_cmd);

@@ -1540,20 +1742,17 @@ } catch (FbTk::ResourceException e) {

cerr<<e.what()<<endl; } - _BOOLITEM(Configmenu, WorkspaceWarping, + _BOOLITEM(menu, Configmenu, WorkspaceWarping, "Workspace Warping", "Workspace Warping - dragging windows to the edge and onto the next workspace", *resource.workspace_warping, saverc_cmd); - _BOOLITEM(Configmenu, DesktopWheeling, + _BOOLITEM(menu, Configmenu, DesktopWheeling, "Desktop MouseWheel Switching", "Workspace switching using mouse wheel", *resource.desktop_wheeling, saverc_cmd); - _BOOLITEM(Configmenu, DecorateTransient, + _BOOLITEM(menu, Configmenu, DecorateTransient, "Decorate Transient Windows", "Decorate Transient Windows", *resource.decorate_transient, saverc_cmd); - _BOOLITEM(Configmenu, ExternalTabs, - "Use External Tabs (experimental)", "Use External Tabs (experimental)", - *resource.default_external_tabs, saverc_cmd); - _BOOLITEM(Configmenu, ClickRaises, + _BOOLITEM(menu, Configmenu, ClickRaises, "Click Raises", "Click Raises", *resource.click_raises, saverc_cmd);
M src/Screen.hhsrc/Screen.hh

@@ -27,7 +27,7 @@

#ifndef SCREEN_HH #define SCREEN_HH - +#include "FbWinFrame.hh" #include "FbRootWindow.hh" #include "MenuTheme.hh" #include "PlacementStrategy.hh"

@@ -132,13 +132,15 @@ FbTk::Menu &windowMenu() { return *m_windowmenu.get(); }

ExtraMenus &extraWindowMenus() { return m_extramenus; } const ExtraMenus &extraWindowMenus() const { return m_extramenus; } + FbWinFrame::TabPlacement getTabPlacement() const { return *resource.tab_placement; } + ResizeModel getResizeModel() const { return *resource.resize_model; } inline FollowModel getFollowModel() const { return *resource.follow_model; } inline const std::string &getScrollAction() const { return *resource.scroll_action; } inline const bool getScrollReverse() const { return *resource.scroll_reverse; } - inline const bool getDefaultExternalTabs() const { return *resource.default_external_tabs; } + inline const bool getDefaultInternalTabs() const { return *resource.default_internal_tabs; } inline Slit *slit() { return m_slit.get(); } inline const Slit *slit() const { return m_slit.get(); }

@@ -203,6 +205,7 @@

void update(FbTk::Subject *subj); FbTk::Menu *createMenu(const std::string &label); + FbTk::Menu *createToggleMenu(const std::string &label); void hideMenus(); // for extras to add menus. // These menus will be marked internal,

@@ -218,6 +221,8 @@

void setRootColormapInstalled(bool r) { root_colormap_installed = r; } void saveRootCommand(std::string rootcmd) { *resource.rootcommand = rootcmd; } + 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); }

@@ -275,6 +280,7 @@ bool ignore_sticky);

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

@@ -434,6 +440,7 @@ desktop_wheeling, show_window_pos,

antialias, auto_raise, click_raises, decorate_transient; FbTk::Resource<std::string> rootcommand; FbTk::Resource<ResizeModel> resize_model; + FbTk::Resource<FbWinFrame::TabPlacement> tab_placement; FbTk::Resource<std::string> windowmenufile; FbTk::Resource<FollowModel> follow_model; bool ordered_dither;

@@ -447,7 +454,7 @@ FbTk::Resource<FbTk::GContext::JoinStyle> gc_join_style;

FbTk::Resource<FbTk::GContext::CapStyle> gc_cap_style; FbTk::Resource<std::string> scroll_action; FbTk::Resource<bool> scroll_reverse; - FbTk::Resource<bool> default_external_tabs; + FbTk::Resource<bool> default_internal_tabs; } resource;
M src/Window.ccsrc/Window.cc

@@ -394,10 +394,11 @@ }

frame().setUseShape(!m_shaped); - if (screen().getDefaultExternalTabs()) { + frame().setTabPlacement(screen().getTabPlacement()); + if (screen().getDefaultInternalTabs()) { + frame().setTabMode(FbWinFrame::INTERNAL); + } else { frame().setTabMode(FbWinFrame::EXTERNAL); - } else { - frame().setTabMode(FbWinFrame::INTERNAL); } //!! TODO init of client should be better

@@ -3049,20 +3050,28 @@ default:

case DECOR_NORMAL: decorations.titlebar = decorations.border = decorations.handle = decorations.iconify = decorations.maximize = - decorations.menu = true; + decorations.menu = decorations.tab = true; + functions.resize = functions.move = functions.iconify = + functions.maximize = true; + break; + + case DECOR_TAB: + decorations.border = decorations.iconify = decorations.maximize = + decorations.menu = decorations.tab = true; + decorations.titlebar = decorations.handle = false; functions.resize = functions.move = functions.iconify = functions.maximize = true; break; case DECOR_TINY: decorations.titlebar = decorations.iconify = decorations.menu = - functions.move = functions.iconify = true; + functions.move = functions.iconify = decorations.tab = true; decorations.border = decorations.handle = decorations.maximize = functions.resize = functions.maximize = false; break; case DECOR_TOOL: - decorations.titlebar = decorations.menu = functions.move = true; + decorations.titlebar = decorations.tab = decorations.menu = functions.move = true; decorations.iconify = decorations.border = decorations.handle = decorations.maximize = functions.resize = functions.maximize = functions.iconify = false;

@@ -3110,7 +3119,7 @@ // we rely on frame not doing anything if it is already shown/hidden

if (decorations.titlebar) { bool change = frame().showTitlebar(); client_move |= change; - if (change && !screen().getDefaultExternalTabs()) { + if (change && screen().getDefaultInternalTabs()) { client_move |= frame().setTabMode(FbWinFrame::INTERNAL); } } else {

@@ -3357,41 +3366,55 @@

int right = orig_left + width() + 2 * borderW; int bottom = orig_top + height() + 2 * borderW; + // test against tabs too + bool i_have_tabs = frame().externalTabMode(); + int xoff,yoff,woff,hoff; + if (i_have_tabs) { + xoff = xOffset(); + yoff = yOffset(); + woff = widthOffset(); + hoff = heightOffset(); + } + + ///////////////////////////////////// // begin by checking the screen (or Xinerama head) edges - int h; - if (screen().numHeads() > 0) { - // head "0" == whole screen width + height, which we skip since the - // sum of all the heads covers those edges - for (h = 1; h <= screen().numHeads(); h++) { - snapToWindow(dx, dy, left, right, top, bottom, + int starth = 0; + + // head "0" == whole screen width + height, which we skip since the + // sum of all the heads covers those edges, if >1 head + if (screen().numHeads() > 0) + starth=1; + + for (int h=starth; h <= screen().numHeads(); h++) { + snapToWindow(dx, dy, left, right, top, bottom, + screen().maxLeft(h), + screen().maxRight(h), + screen().maxTop(h), + screen().maxBottom(h)); + + if (i_have_tabs) + snapToWindow(dx, dy, left - xoff, right - xoff + woff, top - yoff, bottom - yoff + hoff, screen().maxLeft(h), screen().maxRight(h), screen().maxTop(h), screen().maxBottom(h)); - } - for (h = 1; h <= screen().numHeads(); h++) { - snapToWindow(dx, dy, left, right, top, bottom, + } + for (int h=starth; h <= screen().numHeads(); h++) { + snapToWindow(dx, dy, left, right, top, bottom, + screen().getHeadX(h), + screen().getHeadX(h) + screen().getHeadWidth(h), + screen().getHeadY(h), + screen().getHeadY(h) + screen().getHeadHeight(h)); + + if (i_have_tabs) + snapToWindow(dx, dy, left - xoff, right - xoff + woff, top - yoff, bottom - yoff + hoff, screen().getHeadX(h), screen().getHeadX(h) + screen().getHeadWidth(h), screen().getHeadY(h), screen().getHeadY(h) + screen().getHeadHeight(h)); - } - } else { - snapToWindow(dx, dy, left, right, top, bottom, - screen().maxLeft(0), - screen().maxRight(0), - screen().maxTop(0), - screen().maxBottom(0)); - - snapToWindow(dx, dy, left, right, top, bottom, - screen().getHeadX(0), - screen().getHeadX(0) + screen().getHeadWidth(0), - screen().getHeadY(0), - screen().getHeadY(0) + screen().getHeadHeight(0)); } - ///////////////////////////////////// // now check window edges

@@ -3415,6 +3438,30 @@ (*it)->x(),

(*it)->x() + (*it)->width() + 2 * bw, (*it)->y(), (*it)->y() + (*it)->height() + 2 * bw); + + if (i_have_tabs) + snapToWindow(dx, dy, left - xoff, right - xoff + woff, top - yoff, bottom - yoff + hoff, + (*it)->x(), + (*it)->x() + (*it)->width() + 2 * bw, + (*it)->y(), + (*it)->y() + (*it)->height() + 2 * bw); + + // also snap to the box containing the tabs (don't bother with actual + // tab edges, since they're dynamic + if ((*it)->frame().externalTabMode()) + snapToWindow(dx, dy, left, right, top, bottom, + (*it)->x() - (*it)->xOffset(), + (*it)->x() - (*it)->xOffset() + (*it)->width() + 2 * bw + (*it)->widthOffset(), + (*it)->y() - (*it)->yOffset(), + (*it)->y() - (*it)->yOffset() + (*it)->height() + 2 * bw + (*it)->heightOffset()); + + if (i_have_tabs) + snapToWindow(dx, dy, left - xoff, right - xoff + woff, top - yoff, bottom - yoff + hoff, + (*it)->x() - (*it)->xOffset(), + (*it)->x() - (*it)->xOffset() + (*it)->width() + 2 * bw + (*it)->widthOffset(), + (*it)->y() - (*it)->yOffset(), + (*it)->y() - (*it)->yOffset() + (*it)->height() + 2 * bw + (*it)->heightOffset()); + } // commit
M src/Window.hhsrc/Window.hh

@@ -62,7 +62,8 @@ enum Decoration {

DECOR_NONE=0, ///< no decor at all DECOR_NORMAL, ///< normal normal DECOR_TINY, ///< tiny decoration - DECOR_TOOL ///< decor tool + DECOR_TOOL, ///< decor tool + DECOR_TAB ///< decor tab (border + tab) }; /// Motif wm Hints