From f2d3fff4d4db7677814379139dcec3e31fc68047 Mon Sep 17 00:00:00 2001 From: simonb Date: Mon, 20 Mar 2006 11:31:24 +0000 Subject: external tabs --- ChangeLog | 13 ++ nls/fluxbox-nls.hh | 1 + src/ColSmartPlacement.cc | 19 +-- src/Container.cc | 76 +++++++++- src/Container.hh | 11 +- src/FbTk/XLayer.cc | 20 +++ src/FbTk/XLayer.hh | 2 + src/FbTk/XLayerItem.cc | 10 +- src/FbWinFrame.cc | 349 +++++++++++++++++++++++++++++++++++---------- src/FbWinFrame.hh | 62 ++++++-- src/Remember.cc | 7 + src/RowSmartPlacement.cc | 19 +-- src/Screen.cc | 6 +- src/Screen.hh | 2 + src/ScreenPlacement.cc | 9 +- src/UnderMousePlacement.cc | 1 + src/WinButton.cc | 2 +- src/Window.cc | 61 ++++++-- src/Window.hh | 10 +- src/fluxbox.cc | 12 +- 20 files changed, 547 insertions(+), 145 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5b338c0..a9f1a82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,17 @@ (Format: Year/Month/Day) +Changes for 0.9.16: +*06/03/20: + * External tabs (Simon) + - option in Configure menu to enable + - restart require at present when toggling this option + - New apps pnemonic for "Deco" option: TAB, which is like NONE, + but with an external tab + Notes: + - tab width currently hardcoded + - only alignment is topleft + fluxbox.cc Screen.hh/cc Window.hh/cc FbWinFrame.hh/cc Remember.cc + Container.hh/cc FbTk/XLayer.hh/cc XLayerItem.cc fluxbox-nls.hh + RowSmart/ColSmart/UnderMousePlacement.cc WinButton.cc Changes for 0.9.15: *06/03/19: * Fixed some wrong fbsetroot nls (Thanks Semushin Slava ) diff --git a/nls/fluxbox-nls.hh b/nls/fluxbox-nls.hh index ed0f177..21fbd88 100644 --- a/nls/fluxbox-nls.hh +++ b/nls/fluxbox-nls.hh @@ -72,6 +72,7 @@ enum { ConfigmenuTransparency = 18, ConfigmenuFocusedAlpha = 19, ConfigmenuUnfocusedAlpha = 20, + ConfigmenuExternalTabs = 21, EwmhSet = 5, EwmhOutOfMemoryClientList = 1, diff --git a/src/ColSmartPlacement.cc b/src/ColSmartPlacement.cc index abb74d7..5b84168 100644 --- a/src/ColSmartPlacement.cc +++ b/src/ColSmartPlacement.cc @@ -48,8 +48,11 @@ bool ColSmartPlacement::placeWindow(const std::vector &windowli int test_x; - int win_w = win.width() + win.fbWindow().borderWidth()*2; - int win_h = win.height() + win.fbWindow().borderWidth()*2; + int win_w = win.width() + win.fbWindow().borderWidth()*2 + win.widthOffset(); + int win_h = win.height() + win.fbWindow().borderWidth()*2 + win.heightOffset(); + + int x_off = win.xOffset(); + int y_off = win.yOffset(); if (left_right) test_x = head_left; @@ -87,10 +90,10 @@ bool ColSmartPlacement::placeWindow(const std::vector &windowli std::vector::const_iterator it_end = windowlist.end(); for (; it != it_end && placed; ++it) { - int curr_x = (*it)->x(); - int curr_y = (*it)->y(); - int curr_w = (*it)->width() + (*it)->fbWindow().borderWidth()*2; - int curr_h = (*it)->height() + (*it)->fbWindow().borderWidth()*2; + int curr_x = (*it)->x() + (*it)->xOffset(); + int curr_y = (*it)->y() + (*it)->yOffset(); + int curr_w = (*it)->width() + (*it)->fbWindow().borderWidth()*2 + (*it)->widthOffset(); + int curr_h = (*it)->height() + (*it)->fbWindow().borderWidth()*2 + (*it)->heightOffset(); if (curr_x < test_x + win_w && curr_x + curr_w > test_x && @@ -122,8 +125,8 @@ bool ColSmartPlacement::placeWindow(const std::vector &windowli } if (placed) { - place_x = test_x; - place_y = test_y; + place_x = test_x + x_off; + place_y = test_y + y_off; } test_y = next_y; diff --git a/src/Container.cc b/src/Container.cc index df745d0..9cef92c 100644 --- a/src/Container.cc +++ b/src/Container.cc @@ -34,6 +34,7 @@ Container::Container(const FbTk::FbWindow &parent): FbTk::FbWindow(parent, 0, 0, 1, 1, ExposureMask), m_align(RELATIVE), m_max_size_per_client(60), + m_max_total_size(0), m_selected(0), m_update_lock(false) { FbTk::EventManager::instance()->add(*this, *this); @@ -59,6 +60,13 @@ void Container::moveResize(int x, int y, repositionItems(); } +/* +void Container::move(int x, int y) { + FbTk::FbWindow::move(x, y); + // no need to reposition +} +*/ + void Container::insertItems(ItemList &item_list, int pos) { // make sure all items have parent == this @@ -255,6 +263,33 @@ void Container::setMaxSizePerClient(unsigned int size) { m_max_size_per_client = size; } +void Container::setMaxTotalSize(unsigned int size) { + m_max_total_size = size; + + if (m_max_total_size && width() > m_max_total_size) { + resize(m_max_total_size, height()); + } else { + // this is a bit of duplication from repositionItems + // for when we are allowed to grow ourself + Alignment align = alignment(); + unsigned int num_items = m_item_list.size(); + if (m_max_total_size && (align == RIGHT || align == LEFT) && + num_items) { + unsigned int max_width_per_client = maxWidthPerClient(); + unsigned int borderW = m_item_list.front()->borderWidth(); + + unsigned int preferred_width = (max_width_per_client + borderW) * num_items - borderW; + + if (preferred_width > m_max_total_size) + preferred_width = m_max_total_size; + + if (preferred_width != width()) + repositionItems(); + } + + } +} + void Container::setAlignment(Container::Alignment a) { m_align = a; } @@ -325,25 +360,48 @@ void Container::repositionItems() { //!! TODO vertical position - const int max_width_per_client = maxWidthPerClient(); + unsigned int max_width_per_client = maxWidthPerClient(); + unsigned int borderW = m_item_list.front()->borderWidth(); + unsigned int num_items = m_item_list.size(); + + unsigned int total_width = width(); + + // if we have a max total size, then we must also resize ourself + // within that bound + Alignment align = alignment(); + if (m_max_total_size && (align == RIGHT || align == LEFT)) { + total_width = (max_width_per_client + borderW) * num_items - borderW; + if (total_width > m_max_total_size) { + total_width = m_max_total_size; + if (m_max_total_size > ((num_items - 1)*borderW)) { // don't go negative with unsigned nums + max_width_per_client = ( m_max_total_size - (num_items - 1)*borderW ) / num_items; + total_width = (max_width_per_client + borderW) * num_items - borderW; + } else + max_width_per_client = 1; + } + if (total_width != width()) { + // calling Container::resize here risks infinite loops + FbTk::FbWindow::resize(total_width, height()); + } + } + ItemList::iterator it = m_item_list.begin(); const ItemList::iterator it_end = m_item_list.end(); - int borderW = m_item_list.front()->borderWidth(); - int rounding_error = width() - ((maxWidthPerClient() + borderW)* m_item_list.size() - borderW); + int rounding_error = total_width - ((max_width_per_client + borderW)* num_items - borderW); int next_x = -borderW; // zero so the border of the first shows int extra = 0; int direction = 1; - if (alignment() == RIGHT) { + if (align == RIGHT) { direction = -1; - next_x = 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)) { // we only need to do error stuff with alignment RELATIVE - if (rounding_error != 0 && alignment() == RELATIVE) { + if (rounding_error != 0 && align == RELATIVE) { --rounding_error; extra = 1; } else { @@ -374,7 +432,11 @@ unsigned int Container::maxWidthPerClient() const { int borderW = m_item_list.front()->borderWidth(); // there're count-1 borders to fit in with the windows // -> 1 per window plus end - return (width() - (count - 1) * borderW) / count; + unsigned int w = width(); + if (w < (count-1)*borderW) + return 1; + else + return (w - (count - 1) * borderW) / count; } break; } diff --git a/src/Container.hh b/src/Container.hh index b4226a3..4014131 100644 --- a/src/Container.hh +++ b/src/Container.hh @@ -25,15 +25,21 @@ #ifndef CONTAINER_HH #define CONTAINER_HH -#include "FbTk/Button.hh" +#include "FbTk/FbWindow.hh" #include "FbTk/EventHandler.hh" #include "FbTk/NotCopyable.hh" +namespace FbTk { + class Button; +} + #include #include class Container:public FbTk::FbWindow, public FbTk::EventHandler, private FbTk::NotCopyable { public: + // LEFT, RIGHT => fixed total width, fixed icon size + // RELATIVE => fixed total width, relative/variable icon size enum Alignment { LEFT, RELATIVE, RIGHT }; typedef FbTk::Button * Item; typedef const FbTk::Button * ConstItem; @@ -58,6 +64,7 @@ public: int find(ConstItem item); void setSelected(int index); void setMaxSizePerClient(unsigned int size); + void setMaxTotalSize(unsigned int size); void setAlignment(Alignment a); Item back() { return m_item_list.back(); } @@ -81,6 +88,7 @@ public: inline const Item& selected() const { return m_selected; } inline Item selected() { return m_selected; } unsigned int maxWidthPerClient() const; + unsigned int maxTotalSize() const { return m_max_total_size; } inline unsigned int maxHeightPerClient() const { return (empty() ? height() : height()/size()); } inline bool updateLock() const { return m_update_lock; } @@ -97,6 +105,7 @@ private: Alignment m_align; unsigned int m_max_size_per_client; + unsigned int m_max_total_size; ItemList m_item_list; Item m_selected; bool m_update_lock; diff --git a/src/FbTk/XLayer.cc b/src/FbTk/XLayer.cc index ae92e97..63881d3 100644 --- a/src/FbTk/XLayer.cc +++ b/src/FbTk/XLayer.cc @@ -131,6 +131,26 @@ void XLayer::stackBelowItem(XLayerItem *item, XLayerItem *above) { } +void XLayer::alignItem(XLayerItem &item) { + // Note: some other things effectively assume that the window list is + // sorted from highest to lowest + size_t winnum = 0, + num = item.numWindows(); + Window *winlist = new Window[num]; + + // fill the rest of the array + XLayerItem::Windows::iterator it = item.getWindows().begin(); + XLayerItem::Windows::iterator it_end = item.getWindows().end(); + for (; it != it_end; ++it) { + if ((*it)->window()) { + winlist[winnum++] = (*it)->window(); + } + } + + XRestackWindows(FbTk::App::instance()->display(), winlist, winnum); + delete [] winlist; +} + XLayer::iterator XLayer::insert(XLayerItem &item, unsigned int pos) { #ifdef DEBUG // at this point we don't support insertions into a layer other than at the top diff --git a/src/FbTk/XLayer.hh b/src/FbTk/XLayer.hh index d01094e..bed93cc 100644 --- a/src/FbTk/XLayer.hh +++ b/src/FbTk/XLayer.hh @@ -48,6 +48,8 @@ public: void setLayerNum(int layernum) { m_layernum = layernum; }; int getLayerNum() { return m_layernum; }; void restack(); + // Put all items on the same layer (called when layer item added to) + void alignItem(XLayerItem &item); int countWindows(); void stackBelowItem(XLayerItem *item, XLayerItem *above); XLayerItem *getLowestItem(); diff --git a/src/FbTk/XLayerItem.cc b/src/FbTk/XLayerItem.cc index eb88aa8..95befe7 100644 --- a/src/FbTk/XLayerItem.cc +++ b/src/FbTk/XLayerItem.cc @@ -81,9 +81,10 @@ void XLayerItem::moveToLayer(int layernum) { } void XLayerItem::addWindow(FbWindow &win) { - // I'd like to think we can trust ourselves that it won't be added twice... - // Otherwise we're always scanning through the list. - m_windows.push_back(&win); + // I'd like to think we can trust ourselves that it won't be added twice... + // Otherwise we're always scanning through the list. + m_windows.push_back(&win); + m_layer->alignItem(*this); } void XLayerItem::removeWindow(FbWindow &win) { @@ -91,7 +92,8 @@ void XLayerItem::removeWindow(FbWindow &win) { // Otherwise we're always scanning through the list. XLayerItem::Windows::iterator it = std::find(m_windows.begin(), m_windows.end(), &win); - m_windows.erase(it); + if (it != m_windows.end()) + m_windows.erase(it); } void XLayerItem::bringToTop(FbWindow &win) { diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc index 8e7c455..ec74f4b 100644 --- a/src/FbWinFrame.cc +++ b/src/FbWinFrame.cc @@ -25,13 +25,13 @@ #include "FbTk/ImageControl.hh" #include "FbTk/EventManager.hh" -#include "FbTk/TextButton.hh" #include "FbTk/App.hh" #include "FbTk/SimpleCommand.hh" #include "FbTk/Compose.hh" #include "FbTk/Transparent.hh" #include "CompareWindow.hh" #include "FbWinFrameTheme.hh" +#include "Screen.hh" #include "Container.hh" @@ -46,24 +46,22 @@ using namespace std; -FbWinFrame::FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, +FbWinFrame::FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, + FbTk::XLayer &layer, int x, int y, unsigned int width, unsigned int height): + m_screen(screen), m_theme(theme), m_imagectrl(imgctrl), m_window(theme.screenNum(), x, y, width, height, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask, true), + m_layeritem(window(), layer), m_titlebar(m_window, 0, 0, 100, 16, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask | EnterWindowMask | LeaveWindowMask), m_tab_container(m_titlebar), -/* - m_label(m_titlebar, 0, 0, 100, 16, - ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask | - EnterWindowMask | LeaveWindowMask), -*/ + m_label(m_titlebar, m_theme.font(), ""), m_handle(m_window, 0, 0, 100, 5, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask | @@ -82,11 +80,12 @@ FbWinFrame::FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, EnterWindowMask | LeaveWindowMask), m_bevel(1), m_use_titlebar(true), + m_use_tabs(true), m_use_handle(true), m_focused(false), m_visible(false), m_button_pm(0), - m_tabmode(INTERNAL), // TODO: configurable default (on compile, for backwards compat) + m_tabmode(NOTSET), m_need_render(true), m_themelistener(*this), m_shape(new Shape(m_window, theme.shapePlace())) { @@ -116,8 +115,78 @@ bool FbWinFrame::setOnClickTitlebar(FbTk::RefCount &ref, int mous return true; } +bool FbWinFrame::setTabMode(TabMode tabmode) { + if (m_tabmode == tabmode) + return false; + + bool ret = true; + + // setting tabmode to notset forces it through when + // something is likely to change + if (tabmode == NOTSET) + tabmode = m_tabmode; + + // reparent tab container + if (tabmode == EXTERNAL) { + + m_tab_container.setBorderWidth(m_window.borderWidth()); + m_tab_container.setBorderColor(theme().border().color()); + m_tab_container.setEventMask( + ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | ExposureMask | + EnterWindowMask | LeaveWindowMask); + + XGrabButton(m_tab_container.display(), Button1, AnyModifier, + m_tab_container.window(), True, ButtonPressMask, + GrabModeSync, GrabModeSync, None, None); + XUngrabButton(m_tab_container.display(), Button1, Mod1Mask|Mod2Mask|Mod3Mask, m_tab_container.window()); + + 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()); + + // TODO: tab position + if (m_use_tabs && m_visible) + m_tab_container.show(); + else { + ret = false; + m_tab_container.hide(); + } + + } else { + 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.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; +// reconfigure(); + } + + m_tabmode = tabmode; + return true; +} + void FbWinFrame::hide() { m_window.hide(); + if (m_tabmode == EXTERNAL && m_use_tabs) + m_tab_container.hide(); + m_visible = false; } @@ -130,6 +199,9 @@ void FbWinFrame::show() { clearAll(); } + if (m_tabmode == EXTERNAL && m_use_tabs) + m_tab_container.show(); + m_window.showSubwindows(); m_window.show(); } @@ -214,8 +286,28 @@ void FbWinFrame::moveResize(int x, int y, unsigned int width, unsigned int heigh m_window.resize(width, height); } - if (resize) + if (move) + alignTabs(); + + if (resize) { + if (m_tabmode == EXTERNAL) + m_tab_container.setMaxTotalSize(width); reconfigure(); + } +} + +void FbWinFrame::quietMoveResize(int x, int y, + unsigned int width, unsigned int height) { + m_window.moveResize(x, y, width, height); + if (m_tabmode == EXTERNAL) { + m_tab_container.setMaxTotalSize(width); + alignTabs(); + } +} + +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()); } void FbWinFrame::notifyMoved(bool clear) { @@ -224,10 +316,16 @@ void FbWinFrame::notifyMoved(bool clear) { if (alpha == 255) return; + if (m_tabmode == EXTERNAL && m_use_tabs || m_use_titlebar) { + m_tab_container.parentMoved(); + m_tab_container.for_each(mem_fun(&FbTk::Button::parentMoved)); + } + if (m_use_titlebar) { + if (m_tabmode == INTERNAL) + m_label.parentMoved(); + m_titlebar.parentMoved(); - //m_label.parentMoved(); - m_tab_container.parentMoved(); for_each(m_buttons_left.begin(), m_buttons_left.end(), @@ -235,7 +333,6 @@ void FbWinFrame::notifyMoved(bool clear) { for_each(m_buttons_right.begin(), m_buttons_right.end(), mem_fun(&FbTk::Button::parentMoved)); - m_tab_container.for_each(mem_fun(&FbTk::Button::parentMoved)); } if (m_use_handle) { @@ -246,7 +343,8 @@ void FbWinFrame::notifyMoved(bool clear) { if (clear && (m_use_handle || m_use_titlebar)) { clearAll(); - } + } else if (clear && m_tabmode == EXTERNAL && m_use_tabs) + m_tab_container.clear(); } void FbWinFrame::clearAll() { @@ -260,7 +358,8 @@ void FbWinFrame::clearAll() { for_each(m_buttons_right.begin(), m_buttons_right.end(), mem_fun(&FbTk::Button::clear)); - } + } else if (m_tabmode == EXTERNAL && m_use_tabs) + m_tab_container.clear(); if (m_use_handle) { m_handle.clear(); @@ -293,6 +392,7 @@ void FbWinFrame::setFocus(bool newvalue) { applyTitlebar(); applyHandles(); + applyTabContainer(); clearAll(); } @@ -416,6 +516,7 @@ void FbWinFrame::setLabelButtonFocus(FbTk::TextButton &btn) { applyUnfocusLabel(*m_current_label); m_current_label = &btn; // current focused button + m_label.setText(btn.text()); if (m_focused) applyFocusLabel(*m_current_label); @@ -451,11 +552,35 @@ void FbWinFrame::setClientWindow(FbTk::FbWindow &win) { XChangeWindowAttributes(win.display(), win.window(), CWEventMask|CWDontPropagate, &attrib_set); m_clientarea.raise(); + win.show(); win.raise(); m_window.showSubwindows(); } +bool FbWinFrame::hideTabs() { + if (m_tabmode == INTERNAL || !m_use_tabs) { + m_use_tabs = false; + return false; + } + + m_use_tabs = false; + m_tab_container.hide(); + return true; +} + +bool FbWinFrame::showTabs() { + if (m_tabmode == INTERNAL || m_use_tabs) { + m_use_tabs = true; + return false; // nothing changed + } + + m_use_tabs = true; + if (m_visible) + m_tab_container.show(); + return true; +} + bool FbWinFrame::hideTitlebar() { if (!m_use_titlebar) return false; @@ -484,6 +609,7 @@ bool FbWinFrame::showTitlebar() { // only add one borderwidth (as the other border is still the "top" border) m_window.resize(m_window.width(), m_window.height() + m_titlebar.height() + m_titlebar.borderWidth()); + return true; } @@ -555,6 +681,7 @@ void FbWinFrame::setEventHandler(FbTk::EventHandler &evh) { FbTk::EventManager &evm = *FbTk::EventManager::instance(); evm.add(evh, m_tab_container); + evm.add(evh, m_label); evm.add(evh, m_titlebar); evm.add(evh, m_handle); evm.add(evh, m_grip_right); @@ -569,6 +696,7 @@ void FbWinFrame::setEventHandler(FbTk::EventHandler &evh) { void FbWinFrame::removeEventHandler() { FbTk::EventManager &evm = *FbTk::EventManager::instance(); evm.remove(m_tab_container); + evm.remove(m_label); evm.remove(m_titlebar); evm.remove(m_handle); evm.remove(m_grip_right); @@ -579,6 +707,9 @@ void FbWinFrame::removeEventHandler() { void FbWinFrame::buttonPressEvent(XButtonEvent &event) { // we can ignore which window the event was generated for + if (event.window == m_label.window() && m_current_label) + event.window = m_current_label->window(); + m_tab_container.tryButtonPressEvent(event); if (event.window == m_grip_right.window() || event.window == m_grip_left.window() || @@ -595,6 +726,8 @@ void FbWinFrame::buttonPressEvent(XButtonEvent &event) { void FbWinFrame::buttonReleaseEvent(XButtonEvent &event) { // we can ignore which window the event was generated for + if (event.window == m_label.window() && m_current_label) + event.window = m_current_label->window(); // we continue even if a button got the event m_tab_container.tryButtonReleaseEvent(event); @@ -626,6 +759,8 @@ void FbWinFrame::exposeEvent(XExposeEvent &event) { m_titlebar.clearArea(event.x, event.y, event.width, event.height); } else if (m_tab_container == event.window) { m_tab_container.clearArea(event.x, event.y, event.width, event.height); + } else if (m_label == event.window) { + m_label.clearArea(event.x, event.y, event.width, event.height); } else if (m_handle == event.window) { m_handle.clearArea(event.x, event.y, event.width, event.height); } else if (m_grip_left == event.window) { @@ -696,6 +831,8 @@ void FbWinFrame::reconfigure() { } else m_titlebar.lower(); + if (m_tabmode == EXTERNAL) + m_tab_container.resize(m_tab_container.width(), buttonHeight()); // leave client+grips alone if we're shaded (it'll get fixed when we unshade) if (!m_shaded) { @@ -788,7 +925,7 @@ void FbWinFrame::redrawTitlebar() { if (isVisible()) { m_tab_container.clear(); - //m_label.clear(); + m_label.clear(); m_titlebar.clear(); } } @@ -825,16 +962,23 @@ void FbWinFrame::reconfigureTitlebar() { next_x += m_bevel; // space left on titlebar between left and right buttons - unsigned int space_left = m_titlebar.width() - next_x; + int space_left = m_titlebar.width() - next_x; + if (!m_buttons_right.empty()) space_left -= m_buttons_right.size() * (button_size + m_bevel); space_left -= m_bevel; - - m_tab_container.moveResize(next_x, m_bevel, - space_left, button_size); - next_x += m_tab_container.width() + m_bevel;; + if (space_left <= 0) + space_left = 1; + + m_label.moveResize(next_x, m_bevel, space_left, button_size); + + if (m_tabmode == INTERNAL) + m_tab_container.moveResize(next_x, m_bevel, + space_left, button_size); + + next_x += m_label.width() + m_bevel; // finaly set new buttons to the right for (size_t i=0; i < m_buttons_right.size(); @@ -851,13 +995,13 @@ void FbWinFrame::renderAll() { renderTitlebar(); renderHandles(); - renderLabelButtons(); + renderTabContainer(); } void FbWinFrame::applyAll() { applyTitlebar(); applyHandles(); - applyLabelButtons(); + applyTabContainer(); } void FbWinFrame::renderTitlebar() { @@ -878,18 +1022,47 @@ void FbWinFrame::renderTitlebar() { m_title_unfocused_pm, m_titlebar.width(), m_titlebar.height()); + //!! TODO: don't render label if internal tabs + render(m_theme.labelFocusTexture(), m_label_focused_color, m_label_focused_pm, - m_tab_container.width(), m_tab_container.height()); - + m_label.width(), m_label.height()); render(m_theme.labelUnfocusTexture(), m_label_unfocused_color, m_label_unfocused_pm, - m_tab_container.width(), m_tab_container.height()); + m_label.width(), m_label.height()); renderButtons(); } +void FbWinFrame::renderTabContainer() { + if (!isVisible()) { + m_need_render = true; + return; + } + + render(m_theme.labelFocusTexture(), m_tabcontainer_focused_color, + m_tabcontainer_focused_pm, + m_tab_container.width(), m_tab_container.height()); + + render(m_theme.labelUnfocusTexture(), m_tabcontainer_unfocused_color, + m_tabcontainer_unfocused_pm, + m_tab_container.width(), m_tab_container.height()); + + render(m_theme.labelFocusTexture(), m_labelbutton_focused_color, + m_labelbutton_focused_pm, + m_tab_container.width(), m_tab_container.height()); + + render(m_theme.labelUnfocusTexture(), m_labelbutton_unfocused_color, + m_labelbutton_unfocused_pm, + m_tab_container.width(), m_tab_container.height()); + + render(m_theme.labelActiveTexture(), m_labelbutton_active_color, + m_labelbutton_active_pm, + m_tab_container.width(), m_tab_container.height()); + +} + void FbWinFrame::applyTitlebar() { // set up pixmaps for titlebar windows @@ -902,13 +1075,13 @@ void FbWinFrame::applyTitlebar() { unsigned char alpha = (m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); m_titlebar.setAlpha(alpha); - m_tab_container.setAlpha(alpha); + m_label.setAlpha(alpha); if (label_pm != 0) - m_tab_container.setBackgroundPixmap(label_pm); - else - m_tab_container.setBackgroundColor(label_color); - + m_label.setBackgroundPixmap(label_pm); + else + m_label.setBackgroundColor(label_color); + if (title_pm != 0) m_titlebar.setBackgroundPixmap(title_pm); else @@ -1036,6 +1209,7 @@ void FbWinFrame::init() { // clear pixmaps m_title_focused_pm = m_title_unfocused_pm = 0; m_label_focused_pm = m_label_unfocused_pm = 0; + m_tabcontainer_focused_pm = m_tabcontainer_unfocused_pm = 0; m_labelbutton_focused_pm = m_labelbutton_unfocused_pm = m_labelbutton_active_pm = 0; m_handle_focused_pm = m_handle_unfocused_pm = 0; m_button_pm = m_button_unfocused_pm = m_button_pressed_pm = 0; @@ -1045,8 +1219,20 @@ void FbWinFrame::init() { m_button_size = 26; m_clientarea.setBorderWidth(0); + m_label.setBorderWidth(0); m_shaded = false; + + // TODO: configurable default (on compile, for backwards compat) +// setTabMode(EXTERNAL); + setTabMode(INTERNAL); + + m_label.setEventMask(ExposureMask | ButtonPressMask | + ButtonReleaseMask | ButtonMotionMask | + EnterWindowMask); + m_label.show(); + m_tab_container.show(); + m_tab_container.raise(); showHandle(); showTitlebar(); @@ -1104,62 +1290,52 @@ void FbWinFrame::render(const FbTk::Texture &tex, FbTk::Color &col, Pixmap &pm, void FbWinFrame::getCurrentFocusPixmap(Pixmap &label_pm, Pixmap &title_pm, FbTk::Color &label_color, FbTk::Color &title_color) { if (m_focused) { - if (m_labelbutton_focused_pm != 0) - label_pm = m_labelbutton_focused_pm; + if (m_label_focused_pm != 0) + label_pm = m_label_focused_pm; else - label_color = m_labelbutton_focused_color; + label_color = m_label_focused_color; if (m_title_focused_pm != 0) title_pm = m_title_focused_pm; else title_color = m_title_focused_color; - } else { - getActiveLabelPixmap(label_pm, title_pm, - label_color, title_color); - } - + if (m_label_unfocused_pm != 0) + label_pm = m_label_unfocused_pm; + else + label_color = m_label_unfocused_color; + + if (m_title_unfocused_pm != 0) + title_pm = m_title_unfocused_pm; + else + title_color = m_title_unfocused_color; + } } -// only called if not focused -void FbWinFrame::getActiveLabelPixmap(Pixmap &label_pm, Pixmap &title_pm, - FbTk::Color &label_color, - FbTk::Color &title_color) { - - if (m_labelbutton_active_pm != 0) - label_pm = m_labelbutton_active_pm; - else - label_color = m_labelbutton_active_color; - - if (m_title_unfocused_pm != 0) - title_pm = m_title_unfocused_pm; - else - title_color = m_title_unfocused_color; -} +void FbWinFrame::applyTabContainer() { + m_tab_container.setAlpha(m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); -void FbWinFrame::renderLabelButtons() { - if (!isVisible()) { - m_need_render = true; - return; + // do the parent container + Pixmap tabcontainer_pm = None; + FbTk::Color *tabcontainer_color = NULL; + if (m_focused) { + if (m_tabcontainer_focused_pm != 0) + tabcontainer_pm = m_tabcontainer_focused_pm; + else + tabcontainer_color = &m_tabcontainer_focused_color; + } else { + if (m_tabcontainer_unfocused_pm != 0) + tabcontainer_pm = m_tabcontainer_unfocused_pm; + else + tabcontainer_color = &m_tabcontainer_unfocused_color; } - render(m_theme.labelFocusTexture(), m_labelbutton_focused_color, - m_labelbutton_focused_pm, - m_tab_container.width(), m_tab_container.height()); - - - render(m_theme.labelUnfocusTexture(), m_labelbutton_unfocused_color, - m_labelbutton_unfocused_pm, - m_tab_container.width(), m_tab_container.height()); - - render(m_theme.labelActiveTexture(), m_labelbutton_active_color, - m_labelbutton_active_pm, - m_tab_container.width(), m_tab_container.height()); - -} - -void FbWinFrame::applyLabelButtons() { + if (tabcontainer_pm != 0) + m_tab_container.setBackgroundPixmap(tabcontainer_pm); + else + m_tab_container.setBackgroundColor(*tabcontainer_color); + // and the labelbuttons in it Container::ItemList::iterator btn_it = m_tab_container.begin(); Container::ItemList::iterator btn_it_end = m_tab_container.end(); for (; btn_it != btn_it_end; ++btn_it) { @@ -1186,6 +1362,8 @@ void FbWinFrame::setBorderWidth(unsigned int border_width) { window().setBorderWidth(border_width); window().setBorderColor(theme().border().color()); + setTabMode(NOTSET); + titlebar().setBorderWidth(border_width); titlebar().setBorderColor(theme().border().color()); @@ -1200,13 +1378,16 @@ void FbWinFrame::setBorderWidth(unsigned int border_width) { if (bw_changes != 0) resize(width(), height() + bw_changes); + + if (m_tabmode == EXTERNAL) + alignTabs(); } void FbWinFrame::applyFocusLabel(FbTk::TextButton &button) { + button.setBorderWidth(1); button.setGC(theme().labelTextFocusGC()); button.setJustify(theme().justify()); - button.setBorderWidth(1); button.setAlpha(m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); if (m_labelbutton_focused_pm != 0) { @@ -1217,10 +1398,9 @@ void FbWinFrame::applyFocusLabel(FbTk::TextButton &button) { } void FbWinFrame::applyActiveLabel(FbTk::TextButton &button) { - + button.setBorderWidth(1); button.setGC(theme().labelTextActiveGC()); button.setJustify(theme().justify()); - button.setBorderWidth(1); button.setAlpha(m_focused?theme().focusedAlpha():theme().unfocusedAlpha()); if (m_labelbutton_active_pm != 0) { @@ -1362,3 +1542,18 @@ void FbWinFrame::gravityTranslate(int &x, int &y, unsigned int width, unsigned i move(x, y); } } + +int FbWinFrame::heightOffset() const { + if (m_tabmode == EXTERNAL && m_use_tabs) + return m_tab_container.height() + m_window.borderWidth(); + else + return 0; +} + +int FbWinFrame::yOffset() const { + if (m_tabmode == EXTERNAL && m_use_tabs) + return m_tab_container.height() + m_window.borderWidth(); + else + return 0; +} + diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh index bc4c1be..5b6b287 100644 --- a/src/FbWinFrame.hh +++ b/src/FbWinFrame.hh @@ -30,6 +30,8 @@ #include "FbTk/Observer.hh" #include "FbTk/Color.hh" #include "FbTk/FbPixmap.hh" +#include "FbTk/XLayerItem.hh" +#include "FbTk/TextButton.hh" #include "Container.hh" #include @@ -39,6 +41,7 @@ class Shape; class FbWinFrameTheme; +class BScreen; namespace FbTk { class TextButton; @@ -46,27 +49,30 @@ class ImageControl; class Command; class Button; class Texture; +class XLayer; } /// holds a window frame with a client window /// (see: image) class FbWinFrame:public FbTk::EventHandler { public: - enum TabMode { INTERNAL = 1, EXTERNAL }; + // STRICTINTERNAL means it doesn't go external automatically when no titlebar + enum TabMode { NOTSET = 0, INTERNAL = 1, EXTERNAL }; typedef FbTk::TextButton *ButtonId; ///< defines a button id /// create a top level window - FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, + FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, + FbTk::XLayer &layer, int x, int y, unsigned int width, unsigned int height); - /// create a frame window inside another FbWindow, NOT IMPLEMENTED! - FbWinFrame(FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, +/* /// create a frame window inside another FbWindow, NOT IMPLEMENTED! + FbWinFrame(BScreen &screen, FbWinFrameTheme &theme, FbTk::ImageControl &imgctrl, const FbTk::FbWindow &parent, int x, int y, unsigned int width, unsigned int height); - +*/ /// destroy frame ~FbWinFrame(); @@ -94,6 +100,10 @@ public: unsigned int width, unsigned int height, bool move = true, bool resize = true, int win_gravity=ForgetGravity); + // move without transparency or special effects (generally when dragging) + void quietMoveResize(int x, int y, + unsigned int width, unsigned int height); + /// some outside move/resize happened, and we need to notify all of our windows /// in case of transparency void notifyMoved(bool clear); @@ -101,7 +111,9 @@ public: /// set focus/unfocus style void setFocus(bool newvalue); + inline void setFocusTitle(const std::string &str) { m_label.setText(str); } void setDoubleClickTime(unsigned int time); + bool setTabMode(TabMode tabmode); /// add a button to the left of the label void addLeftButton(FbTk::Button *btn); @@ -138,6 +150,8 @@ public: // these return true/false for if something changed bool hideTitlebar(); bool showTitlebar(); + bool hideTabs(); + bool showTabs(); bool hideHandle(); bool showHandle(); bool hideAllDecorations(); @@ -172,6 +186,13 @@ public: inline int y() const { return m_window.y(); } inline unsigned int width() const { return m_window.width(); } inline unsigned int height() const { return m_window.height(); } + + // extra bits for tabs + inline int xOffset() const { return 0; } + int yOffset() const; + inline int widthOffset() const { return 0; } + int heightOffset() const; + inline const FbTk::FbWindow &window() const { return m_window; } inline FbTk::FbWindow &window() { return m_window; } /// @return titlebar window @@ -201,6 +222,10 @@ public: unsigned int titlebarHeight() const { return m_titlebar.height(); } /// @return size of button unsigned int buttonHeight() const; + bool externalTabMode() const { return m_tabmode == EXTERNAL; } + + inline const FbTk::XLayerItem &layerItem() const { return m_layeritem; } + inline FbTk::XLayerItem &layerItem() { return m_layeritem; } //@} @@ -216,7 +241,7 @@ private: void renderAll(); void renderTitlebar(); void renderHandles(); - void renderLabelButtons(); + void renderTabContainer(); // and labelbuttons void renderButtons(); // subset of renderTitlebar - don't call directly @@ -233,7 +258,7 @@ private: void applyAll(); void applyTitlebar(); void applyHandles(); - void applyLabelButtons(); + void applyTabContainer(); // and label buttons void applyFocusLabel(FbTk::TextButton &button); void applyUnfocusLabel(FbTk::TextButton &button); void applyActiveLabel(FbTk::TextButton &button); @@ -246,11 +271,15 @@ private: /// initiate inserted button for current theme void applyButton(FbTk::Button &btn); + + void alignTabs(); //@} /// initiate some commont variables void init(); + BScreen &m_screen; + FbWinFrameTheme &m_theme; ///< theme to be used FbTk::ImageControl &m_imagectrl; ///< Image control for rendering /** @@ -258,9 +287,12 @@ private: */ //@{ FbTk::FbWindow m_window; ///< base window that holds each decorations (ie titlebar, handles) + // want this deleted before the windows in it + FbTk::XLayerItem m_layeritem; + FbTk::FbWindow m_titlebar; ///< titlebar window Container m_tab_container; ///< Holds tabs - FbTk::FbWindow m_label; ///< holds title + FbTk::TextButton m_label; ///< holds title FbTk::FbWindow m_handle; ///< handle between grips FbTk::FbWindow m_grip_right, ///< rightgrip m_grip_left; ///< left grip @@ -274,6 +306,7 @@ private: std::string m_titletext; ///< text to be displayed int m_label int m_bevel; ///< bevel between titlebar items and titlebar bool m_use_titlebar; ///< if we should use titlebar + bool m_use_tabs; ///< if we should use tabs (turns them off in external mode only) bool m_use_handle; ///< if we should use handle bool m_focused; ///< focused/unfocused mode bool m_visible; ///< if we are currently showing @@ -285,17 +318,22 @@ private: Pixmap m_title_focused_pm; ///< pixmap for focused title FbTk::Color m_title_focused_color; ///< color for focused title Pixmap m_title_unfocused_pm; ///< pixmap for unfocused title - FbTk::Color m_title_unfocused_color; ///< color for unfocued title + FbTk::Color m_title_unfocused_color; ///< color for unfocused title - Pixmap m_label_focused_pm; ///< pixmap for focused label + Pixmap m_label_focused_pm; ///< pixmap for focused label (only visible with external tabs) FbTk::Color m_label_focused_color; ///< color for focused label Pixmap m_label_unfocused_pm; ///< pixmap for unfocused label - FbTk::Color m_label_unfocused_color; ///< color for unfocued label + FbTk::Color m_label_unfocused_color; ///< color for unfocused label + + Pixmap m_tabcontainer_focused_pm; ///< pixmap for focused tab container + FbTk::Color m_tabcontainer_focused_color; ///< color for focused tab container + Pixmap m_tabcontainer_unfocused_pm; ///< pixmap for unfocused tab container + FbTk::Color m_tabcontainer_unfocused_color; ///< color for unfocused tab container Pixmap m_labelbutton_focused_pm; ///< pixmap for focused label FbTk::Color m_labelbutton_focused_color; ///< color for focused label Pixmap m_labelbutton_unfocused_pm; ///< pixmap for unfocused label - FbTk::Color m_labelbutton_unfocused_color; ///< color for unfocued label + FbTk::Color m_labelbutton_unfocused_color; ///< color for unfocused label Pixmap m_labelbutton_active_pm; ///< pixmap for active label FbTk::Color m_labelbutton_active_color; ///< color for active label diff --git a/src/Remember.cc b/src/Remember.cc index 273bd2a..07487fb 100644 --- a/src/Remember.cc +++ b/src/Remember.cc @@ -416,6 +416,7 @@ int Remember::parseApp(ifstream &file, Application &app, string *first_line) { FluxboxWindow::DECORM_TITLEBAR | FluxboxWindow::DECORM_ICONIFY | FluxboxWindow::DECORM_MENU + | FluxboxWindow::DECORM_TAB ); } else if (str_label == "TOOL") { app.rememberDecostate((unsigned int) @@ -427,6 +428,12 @@ int Remember::parseApp(ifstream &file, Application &app, string *first_line) { FluxboxWindow::DECORM_BORDER | FluxboxWindow::DECORM_MENU ); + } else if (str_label == "TAB") { + app.rememberDecostate((unsigned int) + FluxboxWindow::DECORM_BORDER + | FluxboxWindow::DECORM_MENU + | FluxboxWindow::DECORM_TAB + ); } else { unsigned int mask; const char * str = str_label.c_str(); diff --git a/src/RowSmartPlacement.cc b/src/RowSmartPlacement.cc index eb2956b..1c66a18 100644 --- a/src/RowSmartPlacement.cc +++ b/src/RowSmartPlacement.cc @@ -57,11 +57,12 @@ bool RowSmartPlacement::placeWindow(const std::vector &windowli if (screen_placement.rowDirection() == ScreenPlacement::RIGHTLEFT) change_x = -1; + int win_w = win.width() + win.fbWindow().borderWidth()*2 + win.widthOffset(); + int win_h = win.height() + win.fbWindow().borderWidth()*2 + win.heightOffset(); + int x_off = win.xOffset(); + int y_off = win.yOffset(); - - int win_h = win.height() + win.fbWindow().borderWidth()*2; - int win_w = win.width() + win.fbWindow().borderWidth()*2; int test_y; if (top_bot) test_y = head_top; @@ -102,10 +103,10 @@ bool RowSmartPlacement::placeWindow(const std::vector &windowli for (; win_it != win_it_end && placed; ++win_it) { FluxboxWindow &window = **win_it; - int curr_x = window.x(); - int curr_y = window.y(); - int curr_w = window.width() + window.fbWindow().borderWidth()*2; - int curr_h = window.height() + window.fbWindow().borderWidth()*2; + int curr_x = window.x() + window.xOffset(); + int curr_y = window.y() + window.yOffset(); + int curr_w = window.width() + window.fbWindow().borderWidth()*2 + window.widthOffset(); + int curr_h = window.height() + window.fbWindow().borderWidth()*2 + window.heightOffset(); if (curr_x < test_x + win_w && curr_x + curr_w > test_x && @@ -138,8 +139,8 @@ bool RowSmartPlacement::placeWindow(const std::vector &windowli if (placed) { - place_x = test_x; - place_y = test_y; + place_x = test_x + x_off; + place_y = test_y + y_off; break; } diff --git a/src/Screen.cc b/src/Screen.cc index 805d19d..464b41f 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -201,7 +201,8 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm, scrname+".overlay.capStyle", altscrname+".overlay.CapStyle"), scroll_action(rm, "", scrname+".windowScrollAction", altscrname+".WindowScrollAction"), - scroll_reverse(rm, false, scrname+".windowScrollReverse", altscrname+".WindowScrollReverse") { + scroll_reverse(rm, false, scrname+".windowScrollReverse", altscrname+".WindowScrollReverse"), + default_external_tabs(rm, false /* TODO: autoconf option? */ , scrname+".externalTabs", altscrname+".ExternalTabs") { } @@ -1549,6 +1550,9 @@ void BScreen::setupConfigmenu(FbTk::Menu &menu) { _BOOLITEM(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, "Click Raises", "Click Raises", *resource.click_raises, saverc_cmd); diff --git a/src/Screen.hh b/src/Screen.hh index 1858829..9fcff11 100644 --- a/src/Screen.hh +++ b/src/Screen.hh @@ -138,6 +138,7 @@ public: 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 Slit *slit() { return m_slit.get(); } inline const Slit *slit() const { return m_slit.get(); } @@ -446,6 +447,7 @@ private: FbTk::Resource gc_cap_style; FbTk::Resource scroll_action; FbTk::Resource scroll_reverse; + FbTk::Resource default_external_tabs; } resource; diff --git a/src/ScreenPlacement.cc b/src/ScreenPlacement.cc index 51ade90..ef1f243 100644 --- a/src/ScreenPlacement.cc +++ b/src/ScreenPlacement.cc @@ -113,15 +113,14 @@ bool ScreenPlacement::placeWindow(const std::vector &windowlist - int win_w = win.width() + win.fbWindow().borderWidth()*2, - win_h = win.height() + win.fbWindow().borderWidth()*2; - + int win_w = win.width() + win.fbWindow().borderWidth()*2 + win.widthOffset(), + win_h = win.height() + win.fbWindow().borderWidth()*2 + win.heightOffset(); // make sure the window is inside our screen(head) area if (place_x + win_w > head_right) - place_x = (head_right - win_w) / 2; + place_x = (head_right - win_w) / 2 + win.xOffset(); if (place_y + win_h > head_bot) - place_y = (head_bot - win_h) / 2; + place_y = (head_bot - win_h) / 2 + win.yOffset(); return true; } diff --git a/src/UnderMousePlacement.cc b/src/UnderMousePlacement.cc index 3e2bc41..3af2975 100644 --- a/src/UnderMousePlacement.cc +++ b/src/UnderMousePlacement.cc @@ -43,6 +43,7 @@ bool UnderMousePlacement::placeWindow(const std::vector &list, &ignore_i, &ignore_i, &ignore_ui); // 2*border = border on each side of the screen + // not using offset ones because we won't let tabs influence the "centre" int win_w = win.width() + win.fbWindow().borderWidth()*2, win_h = win.height() + win.fbWindow().borderWidth()*2; diff --git a/src/WinButton.cc b/src/WinButton.cc index 871992d..6c51a6d 100644 --- a/src/WinButton.cc +++ b/src/WinButton.cc @@ -298,7 +298,7 @@ void WinButton::drawType() { if (m_icon_mask.drawable()) XSetClipMask(m_listen_to.fbWindow().display(), gc(), None); } else { - for (int y = height()/3; y <= height() - height()/3; y+=3) { + for (unsigned int y = height()/3; y <= height() - height()/3; y+=3) { drawLine(gc(), width()/4, y, width() - width()/4 - oddW - 1, y); } drawRectangle(gc(), diff --git a/src/Window.cc b/src/Window.cc index b03ee6f..f28f6ab 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -311,8 +311,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm, m_old_pos_x(0), m_old_pos_y(0), m_old_width(1), m_old_height(1), m_last_button_x(0), m_last_button_y(0), - m_frame(tm, client.screen().imageControl(), 0, 0, 100, 100), - m_layeritem(m_frame.window(), layer), + m_frame(client.screen(), tm, client.screen().imageControl(), layer, 0, 0, 100, 100), m_layernum(layer.getLayerNum()), m_old_layernum(0), m_parent(client.screen().rootWindow()), @@ -344,6 +343,7 @@ FluxboxWindow::~FluxboxWindow() { // no longer a valid window to do stuff with Fluxbox::instance()->removeWindowSearchGroup(frame().window().window()); + Fluxbox::instance()->removeWindowSearchGroup(frame().tabcontainer().window()); Client2ButtonMap::iterator it = m_labelbuttons.begin(); Client2ButtonMap::iterator it_end = m_labelbuttons.end(); @@ -394,6 +394,12 @@ void FluxboxWindow::init() { frame().setUseShape(!m_shaped); + if (screen().getDefaultExternalTabs()) { + frame().setTabMode(FbWinFrame::EXTERNAL); + } else { + frame().setTabMode(FbWinFrame::INTERNAL); + } + //!! TODO init of client should be better // we don't want to duplicate code here and in attachClient m_clientlist.push_back(m_client); @@ -467,6 +473,7 @@ void FluxboxWindow::init() { m_timer.fireOnce(true); Fluxbox::instance()->saveWindowSearchGroup(frame().window().window(), this); + Fluxbox::instance()->saveWindowSearchGroup(frame().tabcontainer().window(), this); /**************************************************/ /* Read state above here, apply state below here. */ @@ -1146,8 +1153,11 @@ void FluxboxWindow::updateTitleFromClient(WinClient &client) { client.updateTitle(); // compare old title with new and see if we need to update // graphics - if (m_labelbuttons[&client]->text() != client.title()) + if (m_labelbuttons[&client]->text() != client.title()) { m_labelbuttons[&client]->setText(client.title()); + if (&client == m_client) + frame().setFocusTitle(client.title()); + } } /// update icon title from client @@ -2648,7 +2658,7 @@ void FluxboxWindow::buttonPressEvent(XButtonEvent &be) { setInputFocus(); } - if (frame().window().window() == be.window) { + if (frame().window().window() == be.window || frame().tabcontainer().window() == be.window) { if (screen().clickRaises()) raise(); #ifdef DEBUG @@ -2694,17 +2704,28 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) { if (isMoving() && me.window == parent()) { me.window = frame().window().window(); } - bool inside_titlebar = (frame().titlebar() == me.window || frame().label() == me.window || - frame().handle() == me.window || frame().window() == me.window); + + bool inside_titlebar = (frame().titlebar() == me.window + || frame().label() == me.window + || frame().tabcontainer() == me.window + || frame().handle() == me.window + || frame().window() == me.window); if (Fluxbox::instance()->getIgnoreBorder() && !(me.state & Mod1Mask) // really should check for exact matches && !(isMoving() || isResizing() || m_attaching_tab != 0)) { int borderw = frame().window().borderWidth(); - if (me.x_root < (frame().x() + borderw) || + //!! TODO(tabs): the below test ought to be in FbWinFrame + if ((me.x_root < (frame().x() + borderw) || me.y_root < (frame().y() + borderw) || me.x_root > (frame().x() + (int)frame().width() + borderw) || - me.y_root > (frame().y() + (int)frame().height() + borderw)) + me.y_root > (frame().y() + (int)frame().height() + borderw)) && + ( !frame().externalTabMode() || + (me.x_root < (frame().tabcontainer().x() + borderw) || + me.y_root < (frame().tabcontainer().y() + borderw) || + me.x_root > (frame().tabcontainer().x() + (int)frame().tabcontainer().width() + borderw) || + me.y_root > (frame().tabcontainer().y() + (int)frame().tabcontainer().height() + borderw) + ))) return; } @@ -2794,7 +2815,7 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) { } else { //moveResize(dx, dy, frame().width(), frame().height()); // need to move the base window without interfering with transparency - frame().window().moveResize(dx, dy, frame().width(), frame().height()); + frame().quietMoveResize(dx, dy, frame().width(), frame().height()); } screen().showPosition(dx, dy); @@ -3077,11 +3098,26 @@ void FluxboxWindow::applyDecorations(bool initial) { frame().setBorderWidth(border_width); } - // we rely on frame not doing anything if it is already shown/hidden - if (decorations.titlebar) - client_move |= frame().showTitlebar(); + // tab deocration only affects if we're external + // must do before the setTabMode in case it goes + // to external and is meant to be hidden + if (decorations.tab) + client_move |= frame().showTabs(); else + client_move |= frame().hideTabs(); + + // 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()) { + client_move |= frame().setTabMode(FbWinFrame::INTERNAL); + } + } else { client_move |= frame().hideTitlebar(); + if (decorations.tab) + client_move |= frame().setTabMode(FbWinFrame::EXTERNAL); + } if (decorations.handle) { client_move |= frame().showHandle(); @@ -4048,6 +4084,7 @@ void FluxboxWindow::associateClient(WinClient &client) { Fluxbox::instance()->getTabsPadding()); m_labelbuttons[&client] = btn; + FbTk::EventManager &evm = *FbTk::EventManager::instance(); diff --git a/src/Window.hh b/src/Window.hh index 7c59371..9ad9594 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -316,8 +316,8 @@ public: inline const BScreen &screen() const { return m_screen; } inline BScreen &screen() { return m_screen; } - inline const FbTk::XLayerItem &layerItem() const { return m_layeritem; } - inline FbTk::XLayerItem &layerItem() { return m_layeritem; } + inline const FbTk::XLayerItem &layerItem() const { return m_frame.layerItem(); } + inline FbTk::XLayerItem &layerItem() { return m_frame.layerItem(); } Window clientWindow() const; @@ -337,6 +337,11 @@ public: inline unsigned int width() const { return frame().width(); } inline unsigned int height() const { return frame().height(); } + inline int xOffset() const { return frame().xOffset(); } + inline int yOffset() const { return frame().yOffset(); } + inline int widthOffset() const { return frame().widthOffset(); } + inline int heightOffset() const { return frame().heightOffset(); } + unsigned int workspaceNumber() const { return m_workspace_number; } int layerNum() const { return m_layernum; } @@ -504,7 +509,6 @@ private: m_last_button_y; ///< last known y position of the mouse button FbWinFrame m_frame; - FbTk::XLayerItem m_layeritem; int m_layernum; int m_old_layernum; diff --git a/src/fluxbox.cc b/src/fluxbox.cc index 2ae8110..061bf1f 100644 --- a/src/fluxbox.cc +++ b/src/fluxbox.cc @@ -175,6 +175,8 @@ int handleXErrors(Display *d, XErrorEvent *e) { XGetErrorText(d, e->error_code, errtxt, 128); cerr<<"Fluxbox: X Error: "<error_code<<") opcodes "<< (int)e->request_code<<"/"<<(int)e->minor_code<<" resource 0x"<resourceid<error_code != 9 && e->error_code != 183) +// kill(0, 2); } #endif // !DEBUG @@ -193,15 +195,15 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile // TODO: shouldn't need a separate one for screen m_screen_rm(m_resourcemanager), m_rc_tabs(m_resourcemanager, true, "session.tabs", "Session.Tabs"), - m_rc_tabs_padding(m_resourcemanager, 0, "session.tabPadding", "Session.TabPadding"), - m_rc_focused_tab_min_width(m_resourcemanager, 0, "session.focusTabMinWidth", - "Session.FocusTabMinWidth"), m_rc_ignoreborder(m_resourcemanager, false, "session.ignoreBorder", "Session.IgnoreBorder"), m_rc_pseudotrans(m_resourcemanager, false, "session.forcePseudoTransparency", "Session.forcePseudoTransparency"), m_rc_colors_per_channel(m_resourcemanager, 4, "session.colorsPerChannel", "Session.ColorsPerChannel"), m_rc_numlayers(m_resourcemanager, 13, "session.numLayers", "Session.NumLayers"), m_rc_double_click_interval(m_resourcemanager, 250, "session.doubleClickInterval", "Session.DoubleClickInterval"), + m_rc_tabs_padding(m_resourcemanager, 0, "session.tabPadding", "Session.TabPadding"), + m_rc_focused_tab_min_width(m_resourcemanager, 0, "session.focusTabMinWidth", + "Session.FocusTabMinWidth"), m_rc_stylefile(m_resourcemanager, DEFAULTSTYLE, "session.styleFile", "Session.StyleFile"), m_rc_styleoverlayfile(m_resourcemanager, "~/.fluxbox/overlay", "session.styleOverlay", "Session.StyleOverlay"), m_rc_menufile(m_resourcemanager, DEFAULTMENU, "session.menuFile", "Session.MenuFile"), @@ -358,8 +360,8 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile } // init all "screens" - for(i = 0; i < screens.size(); i++) - initScreen(screens[i]); + for(unsigned int s = 0; s < screens.size(); s++) + initScreen(screens[s]); XAllowEvents(disp, ReplayPointer, CurrentTime); -- cgit v0.11.2