From 1c05af4329e62b8bfaf3c0f032c52ace4eaa5975 Mon Sep 17 00:00:00 2001 From: markt Date: Tue, 23 Oct 2007 17:34:30 +0000 Subject: allow remembering minimized, maximized, and fullscreen state --- ChangeLog | 7 +++ nls/fluxbox-nls.hh | 3 ++ src/CurrentWindowCmd.cc | 2 +- src/Ewmh.cc | 10 ++-- src/Remember.cc | 99 ++++++++++++++++++++++++++++++++++- src/Remember.hh | 23 ++++++++- src/Screen.cc | 14 ----- src/Screen.hh | 3 -- src/Window.cc | 135 +++++++++++++++++++++++++++++------------------- src/Window.hh | 6 +++ 10 files changed, 222 insertions(+), 80 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2b9d305..c1c6a20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ (Format: Year/Month/Day) Changes for 1.0.1: *07/10/23: + * Support remembering maximized, minimized, and fullscreen state (Mark) + - [Maximized] {yes|no|horz|vert} + - [Minimized] {yes|no} + - [Fullscreen] {yes|no} + - also fixed window placement when remembering head but not position + Window.cc/hh Remember.cc/hh Screen.cc/hh Ewmh.cc fluxbox-nls.hh + CurrentWindowCmd.cc * Allow negated patterns, e.g. (name!=xterm) (Mark) ClientPattern.cc/hh *07/10/22: diff --git a/nls/fluxbox-nls.hh b/nls/fluxbox-nls.hh index 3aa4480..e337125 100644 --- a/nls/fluxbox-nls.hh +++ b/nls/fluxbox-nls.hh @@ -153,6 +153,9 @@ enum { RememberWorkspace = 11, RememberHead = 12, RememberAlpha = 13, + RememberMinimized = 14, + RememberMaximized = 15, + RememberFullscreen = 16, ScreenSet = 12, ScreenAnotherWMRunning = 1, diff --git a/src/CurrentWindowCmd.cc b/src/CurrentWindowCmd.cc index 885f4b0..929be5d 100644 --- a/src/CurrentWindowCmd.cc +++ b/src/CurrentWindowCmd.cc @@ -57,7 +57,7 @@ void CurrentWindowCmd::real_execute() { } void SetHeadCmd::real_execute() { - fbwindow().screen().setOnHead(fbwindow(), m_head); + fbwindow().setOnHead(m_head); } void SendToWorkspaceCmd::real_execute() { diff --git a/src/Ewmh.cc b/src/Ewmh.cc index 7266496..11da267 100644 --- a/src/Ewmh.cc +++ b/src/Ewmh.cc @@ -1044,13 +1044,11 @@ void Ewmh::setState(FluxboxWindow &win, Atom state, bool value, (!value && win.isShaded())) win.shade(); } else if (state == m_net_wm_state_maximized_horz ) { // maximized Horizontal - if ((value && !win.isMaximized()) || - (!value && win.isMaximized())) - win.maximizeHorizontal(); + if (value ^ win.isMaximizedHorz()) + win.maximizeHorizontal(); } else if (state == m_net_wm_state_maximized_vert) { // maximized Vertical - if ((value && !win.isMaximized()) || - (!value && win.isMaximized())) - win.maximizeVertical(); + if (value ^ win.isMaximizedVert()) + win.maximizeVertical(); } else if (state == m_net_wm_state_fullscreen) { // fullscreen if ((value && !win.isFullscreen()) || (!value && win.isFullscreen())) diff --git a/src/Remember.cc b/src/Remember.cc index d8f1d83..41f91c4 100644 --- a/src/Remember.cc +++ b/src/Remember.cc @@ -173,6 +173,12 @@ FbTk::Menu *createRememberMenu(BScreen &screen) { Remember::REM_DECOSTATE)); menu->insert(new RememberMenuItem(_FB_XTEXT(Remember, Shaded, "Shaded", "Remember shaded"), Remember::REM_SHADEDSTATE)); + menu->insert(new RememberMenuItem(_FB_XTEXT(Remember, Minimized, "Minimized", "Remember minimized"), + Remember::REM_MINIMIZEDSTATE)); + menu->insert(new RememberMenuItem(_FB_XTEXT(Remember, Maximized, "Maximized", "Remember maximized"), + Remember::REM_MAXIMIZEDSTATE)); + menu->insert(new RememberMenuItem(_FB_XTEXT(Remember, Fullscreen, "Fullscreen", "Remember fullscreen"), + Remember::REM_FULLSCREENSTATE)); if (FbTk::Transparent::haveComposite() || FbTk::Transparent::haveRender()) menu->insert(new RememberMenuItem(_FB_XTEXT(Remember, Alpha, "Transparency", "Remember window tranparency settings"), @@ -250,6 +256,10 @@ bool handleStartupItem(const string &line, int offset) { Application::Application(bool grouped, ClientPattern *pat) : is_grouped(grouped), group_pattern(pat) { + reset(); +} + +void Application::reset() { decostate_remember = dimensions_remember = focushiddenstate_remember = @@ -263,6 +273,9 @@ Application::Application(bool grouped, ClientPattern *pat) workspace_remember = head_remember = alpha_remember = + minimizedstate_remember = + maximizedstate_remember = + fullscreenstate_remember = save_on_close_remember = false; } @@ -496,6 +509,19 @@ int Remember::parseApp(ifstream &file, Application &app, string *first_line) { had_error = 1; } else if (strcasecmp(str_key.c_str(), "Sticky") == 0) { app.rememberStuckstate((strcasecmp(str_label.c_str(), "yes") == 0)); + } else if (strcasecmp(str_key.c_str(), "Minimized") == 0) { + app.rememberMinimizedstate((strcasecmp(str_label.c_str(), "yes") == 0)); + } else if (strcasecmp(str_key.c_str(), "Maximized") == 0) { + if (strcasecmp(str_label.c_str(), "yes") == 0) + app.rememberMaximizedstate(FluxboxWindow::MAX_FULL); + else if (strcasecmp(str_label.c_str(), "horz") == 0) + app.rememberMaximizedstate(FluxboxWindow::MAX_HORZ); + else if (strcasecmp(str_label.c_str(), "vert") == 0) + app.rememberMaximizedstate(FluxboxWindow::MAX_VERT); + else + app.rememberMaximizedstate(FluxboxWindow::MAX_NONE); + } else if (strcasecmp(str_key.c_str(), "Fullscreen") == 0) { + app.rememberFullscreenstate((strcasecmp(str_label.c_str(), "yes") == 0)); } else if (strcasecmp(str_key.c_str(), "Jump") == 0) { app.rememberJumpworkspace((strcasecmp(str_label.c_str(), "yes") == 0)); } else if (strcasecmp(str_key.c_str(), "Close") == 0) { @@ -599,7 +625,9 @@ void Remember::reconfigure() { if (!in_group) { if ((err = pat->error()) == 0) { Application *app = findMatchingPatterns(pat, old_pats, false); - if (!app) + if (app) + app->reset(); + else app = new Application(false); m_pats->push_back(make_pair(pat, app)); @@ -824,6 +852,30 @@ void Remember::save() { if (a.stuckstate_remember) { apps_file << " [Sticky]\t{" << ((a.stuckstate)?"yes":"no") << "}" << endl; } + if (a.minimizedstate_remember) { + apps_file << " [Minimized]\t{" << ((a.minimizedstate)?"yes":"no") << "}" << endl; + } + if (a.maximizedstate_remember) { + apps_file << " [Maximized]\t{"; + switch (a.maximizedstate) { + case FluxboxWindow::MAX_FULL: + apps_file << "yes" << "}" << endl; + break; + case FluxboxWindow::MAX_HORZ: + apps_file << "horz" << "}" << endl; + break; + case FluxboxWindow::MAX_VERT: + apps_file << "vert" << "}" << endl; + break; + case FluxboxWindow::MAX_NONE: + default: + apps_file << "no" << "}" << endl; + break; + } + } + if (a.fullscreenstate_remember) { + apps_file << " [Fullscreen]\t{" << ((a.fullscreenstate)?"yes":"no") << "}" << endl; + } if (a.jumpworkspace_remember) { apps_file << " [Jump]\t{" << ((a.jumpworkspace)?"yes":"no") << "}" << endl; } @@ -874,6 +926,15 @@ bool Remember::isRemembered(WinClient &winclient, Attribute attrib) { case REM_STUCKSTATE: return app->stuckstate_remember; break; + case REM_MINIMIZEDSTATE: + return app->minimizedstate_remember; + break; + case REM_MAXIMIZEDSTATE: + return app->maximizedstate_remember; + break; + case REM_FULLSCREENSTATE: + return app->fullscreenstate_remember; + break; case REM_DECOSTATE: return app->decostate_remember; break; @@ -941,6 +1002,15 @@ void Remember::rememberAttrib(WinClient &winclient, Attribute attrib) { case REM_STUCKSTATE: app->rememberStuckstate(win->isStuck()); break; + case REM_MINIMIZEDSTATE: + app->rememberMinimizedstate(win->isIconic()); + break; + case REM_MAXIMIZEDSTATE: + app->rememberMaximizedstate(win->maximizedState()); + break; + case REM_FULLSCREENSTATE: + app->rememberFullscreenstate(win->isFullscreen()); + break; case REM_ALPHA: app->rememberAlpha(win->frame().getAlpha(true), win->frame().getAlpha(false)); break; @@ -992,6 +1062,15 @@ void Remember::forgetAttrib(WinClient &winclient, Attribute attrib) { case REM_STUCKSTATE: app->forgetStuckstate(); break; + case REM_MINIMIZEDSTATE: + app->forgetMinimizedstate(); + break; + case REM_MAXIMIZEDSTATE: + app->forgetMaximizedstate(); + break; + case REM_FULLSCREENSTATE: + app->forgetFullscreenstate(); + break; case REM_DECOSTATE: app->forgetDecostate(); break; @@ -1058,7 +1137,7 @@ void Remember::setupFrame(FluxboxWindow &win) { } if (app->head_remember) { - win.screen().setOnHead(win, app->head); + win.setOnHead(app->head); } if (app->dimensions_remember) @@ -1112,6 +1191,22 @@ void Remember::setupFrame(FluxboxWindow &win) { !win.isStuck() && app->stuckstate) win.stick(); // toggles + if (app->minimizedstate_remember) { + // if inconsistent... + // this one doesn't actually work, but I can't imagine needing it + if (win.isIconic() && !app->minimizedstate) + win.deiconify(); + else if (!win.isIconic() && app->minimizedstate) + win.iconify(); + } + + // I can't really test the "no" case of this + if (app->maximizedstate_remember) + win.setMaximizedState(app->maximizedstate); + + // I can't really test the "no" case of this + if (app->fullscreenstate_remember) + win.setFullscreen(app->fullscreenstate); } void Remember::setupClient(WinClient &winclient) { diff --git a/src/Remember.hh b/src/Remember.hh index 7ecf8c2..f34c551 100644 --- a/src/Remember.hh +++ b/src/Remember.hh @@ -47,6 +47,7 @@ class WinClient; class Application { public: Application(bool grouped, ClientPattern *pat = 0); + void reset(); inline void forgetWorkspace() { workspace_remember = false; } inline void forgetHead() { head_remember = false; } inline void forgetDimensions() { dimensions_remember = false; } @@ -61,6 +62,9 @@ public: inline void forgetLayer() { layer_remember = false; } inline void forgetSaveOnClose() { save_on_close_remember = false; } inline void forgetAlpha() { alpha_remember = false; } + inline void forgetMinimizedstate() { minimizedstate_remember = false; } + inline void forgetMaximizedstate() { maximizedstate_remember = false; } + inline void forgetFullscreenstate() { fullscreenstate_remember = false; } inline void rememberWorkspace(int ws) { workspace = ws; workspace_remember = true; } @@ -90,7 +94,12 @@ public: { save_on_close = state; save_on_close_remember = true; } inline void rememberAlpha(int focused_a, int unfocused_a) { focused_alpha = focused_a; unfocused_alpha = unfocused_a; alpha_remember = true; } - + inline void rememberMinimizedstate(bool state) + { minimizedstate = state; minimizedstate_remember = true; } + inline void rememberMaximizedstate(int state) + { maximizedstate = state; maximizedstate_remember = true; } + inline void rememberFullscreenstate(bool state) + { fullscreenstate = state; fullscreenstate_remember = true; } bool workspace_remember; unsigned int workspace; @@ -139,6 +148,15 @@ public: bool save_on_close_remember; bool save_on_close; + bool minimizedstate_remember; + bool minimizedstate; + + bool maximizedstate_remember; + int maximizedstate; + + bool fullscreenstate_remember; + bool fullscreenstate; + bool is_grouped; FbTk::RefCount group_pattern; @@ -171,6 +189,9 @@ public: REM_WORKSPACE, REM_HEAD, REM_ALPHA, + REM_MINIMIZEDSTATE, + REM_MAXIMIZEDSTATE, + REM_FULLSCREENSTATE, REM_LASTATTRIB // not actually used }; diff --git a/src/Screen.cc b/src/Screen.cc index e6681e6..0589d2f 100644 --- a/src/Screen.cc +++ b/src/Screen.cc @@ -2325,17 +2325,3 @@ pair BScreen::clampToHead(int head, int x, int y, int w, int h) const { return make_pair(x,y); } - -// TODO: when toolbar gets its resources moved into Toolbar.hh/cc, then -// this can be gone and a consistent interface for the two used -// on the actual objects - -template<> -void BScreen::setOnHead(FluxboxWindow& win, int head) { - if (head > 0 && head <= numHeads()) { - int current_head = getHead(win.fbWindow()); - win.move(getHeadX(head) + win.frame().x() - getHeadX(current_head), - getHeadY(head) + win.frame().y() - getHeadY(current_head)); - } -} - diff --git a/src/Screen.hh b/src/Screen.hh index 09865e6..37edaa7 100644 --- a/src/Screen.hh +++ b/src/Screen.hh @@ -441,9 +441,6 @@ public: template int getOnHead(OnHeadObject &obj) const; - template - void setOnHead(OnHeadObject &obj, int head); - // grouping - we want ordering, so we can either search for a // group to the left, or to the right (they'll be different if // they exist). diff --git a/src/Window.cc b/src/Window.cc index 133ccd2..767aff5 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -267,6 +267,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client, FbWinFrameTheme &tm, m_old_width(1), m_old_height(1), m_last_button_x(0), m_last_button_y(0), m_frame(client.screen(), tm, client.screen().imageControl(), layer, 0, 0, 100, 100), + m_placed(false), m_layernum(layer.getLayerNum()), m_old_layernum(0), m_parent(client.screen().rootWindow()), @@ -354,10 +355,6 @@ FluxboxWindow::~FluxboxWindow() { void FluxboxWindow::init() { m_attaching_tab = 0; - // magic to detect if moved by hints - // don't use 0, since setting maximized or fullscreen on the window will set - // this to 0 - m_old_pos_x = m_screen.width(); assert(m_client); m_client->setFluxboxWindow(this); @@ -469,10 +466,8 @@ void FluxboxWindow::init() { if (m_workspace_number >= screen().numberOfWorkspaces()) m_workspace_number = screen().currentWorkspaceID(); - bool place_window = (m_old_pos_x == static_cast(m_screen.width())); - if (fluxbox.isStartup()) - place_window = false; + m_placed = true; else if (m_client->isTransient() || m_client->normal_hint_flags & (PPosition|USPosition)) { @@ -483,7 +478,7 @@ void FluxboxWindow::init() { real_y >= 0 && real_x <= (signed) screen().width() && real_y <= (signed) screen().height()) - place_window = false; + m_placed = true; } /* @@ -514,18 +509,10 @@ void FluxboxWindow::init() { m_client->applySizeHints(real_width, real_height); real_height += frame().titlebarHeight() + frame().handleHeight(); - if (!place_window) + if (m_placed) moveResize(frame().x(), frame().y(), real_width, real_height); - screen().getWorkspace(m_workspace_number)->addWindow(*this, place_window); - - if (maximized && functions.maximize) { // start maximized - // This will set it to the appropriate style of maximisation - int req_maximized = maximized; - // NOTE: don't manually change maximized ANYWHERE else, it isn't safe - maximized = MAX_NONE; // it is not maximized now - maximize(req_maximized); - } + screen().getWorkspace(m_workspace_number)->addWindow(*this, !m_placed); setFocusFlag(false); // update graphics before mapping @@ -550,6 +537,19 @@ void FluxboxWindow::init() { m_focused = false; } + // maximization won't work if we think the window is fullscreen + bool tmp_fullscreen = fullscreen; + fullscreen = false; + if (maximized) { + int tmp = maximized; + maximized = MAX_NONE; + setMaximizedState(tmp); + } + + if (tmp_fullscreen) + setFullscreen(true); + + struct timeval now; gettimeofday(&now, NULL); m_creation_time = now.tv_sec; @@ -1185,14 +1185,10 @@ void FluxboxWindow::move(int x, int y) { } void FluxboxWindow::resize(unsigned int width, unsigned int height) { - int old_x = m_old_pos_x; - + // don't set window as placed, since we're only resizing + bool placed = m_placed; moveResize(frame().x(), frame().y(), width, height); - - // magic to detect if moved during initialisation - // we restore the old state, because we were a resize, not a moveResize! - if (!m_initialized) - m_old_pos_x = old_x; + m_placed = placed; } // send_event is just an override @@ -1200,10 +1196,7 @@ void FluxboxWindow::moveResize(int new_x, int new_y, unsigned int new_width, unsigned int new_height, bool send_event) { - // magic to detect if moved during initialisation - if (!m_initialized) - m_old_pos_x = 1; - + m_placed = true; send_event = send_event || frame().x() != new_x || frame().y() != new_y; if ((new_width != frame().width() || new_height != frame().height()) && @@ -1236,9 +1229,7 @@ void FluxboxWindow::moveResize(int new_x, int new_y, void FluxboxWindow::moveResizeForClient(int new_x, int new_y, unsigned int new_width, unsigned int new_height, int gravity, unsigned int client_bw) { - // magic to detect if moved during initialisation - if (!m_initialized) - m_old_pos_x = 1; + m_placed = true; frame().moveResizeForClient(new_x, new_y, new_width, new_height, gravity, client_bw); setFocusFlag(m_focused); shaded = false; @@ -1517,13 +1508,16 @@ void FluxboxWindow::deiconify(bool reassoc, bool do_raise) { */ void FluxboxWindow::setFullscreen(bool flag) { + if (!m_initialized) { + // this will interfere with window placement, so we delay it + fullscreen = flag; + return; + } + const int head = screen().getHead(fbWindow()); if (flag && !isFullscreen()) { - if (isIconic()) - deiconify(); - if (isShaded()) shade(); @@ -1533,10 +1527,12 @@ void FluxboxWindow::setFullscreen(bool flag) { m_old_decoration_mask = decorationMask(); m_old_layernum = layerNum(); - m_old_pos_x = frame().x(); - m_old_pos_y = frame().y(); - m_old_width = frame().width(); - m_old_height = frame().height(); + if (!maximized) { + m_old_pos_x = frame().x(); + m_old_pos_y = frame().y(); + m_old_width = frame().width(); + m_old_height = frame().height(); + } // clear decorations setDecorationMask(0); @@ -1586,7 +1582,12 @@ void FluxboxWindow::setFullscreen(bool flag) { m_old_layernum = ::Layer::NORMAL; - stateSig().notify(); + if (maximized) { + int tmp = maximized; + maximized = MAX_NONE; + setMaximizedState(tmp); + } else + stateSig().notify(); } } @@ -1599,8 +1600,32 @@ void FluxboxWindow::maximize(int type) { if (isFullscreen() || type == MAX_NONE) return; - if (isIconic()) - deiconify(); + int new_max = maximized; + + // toggle maximize vertically? + // when _don't_ we want to toggle? + // - type is horizontal maximise, or + // - type is full and we are not maximised horz but already vertically + if (type != MAX_HORZ && !(type == MAX_FULL && maximized == MAX_VERT)) + new_max ^= MAX_VERT; + + // maximize horizontally? + if (type != MAX_VERT && !(type == MAX_FULL && maximized == MAX_HORZ)) + new_max ^= MAX_HORZ; + + setMaximizedState(new_max); +} + +void FluxboxWindow::setMaximizedState(int type) { + + if (!m_initialized) { + // this will interfere with the window getting placed, so we delay it + maximized = type; + return; + } + + if (isFullscreen() || type == maximized) + return; if (isShaded()) shade(); @@ -1614,8 +1639,6 @@ void FluxboxWindow::maximize(int type) { new_w = frame().width(), new_h = frame().height(); - int orig_max = maximized; - // These evaluate whether we need to TOGGLE the value for that field // Why? If maximize is only set to zero outside this, // and we only EVER toggle them, then: @@ -1626,12 +1649,9 @@ void FluxboxWindow::maximize(int type) { // we still won't lose the state in that case. // toggle maximize vertically? - // when _don't_ we want to toggle? - // - type is horizontal maximise, or - // - type is full and we are not maximised horz but already vertically - if (type != MAX_HORZ && !(type == MAX_FULL && orig_max == MAX_VERT)) { + if ((maximized ^ type) & MAX_VERT) { // already maximized in that direction? - if (orig_max & MAX_VERT) { + if (maximized & MAX_VERT) { new_y = m_old_pos_y; new_h = m_old_height; } else { @@ -1647,10 +1667,10 @@ void FluxboxWindow::maximize(int type) { maximized ^= MAX_VERT; } - // maximize horizontally? - if (type != MAX_VERT && !(type == MAX_FULL && orig_max == MAX_HORZ)) { + // toggle maximize horizontally? + if ((maximized ^ type) & MAX_HORZ) { // already maximized in that direction? - if (orig_max & MAX_HORZ) { + if (maximized & MAX_HORZ) { new_x = m_old_pos_x; new_w = m_old_width; } else { @@ -1711,7 +1731,6 @@ void FluxboxWindow::maximizeFull() { maximize(MAX_FULL); } - void FluxboxWindow::setWorkspace(int n) { unsigned int old_wkspc = m_workspace_number; @@ -4080,3 +4099,13 @@ int FluxboxWindow::getDecoMaskFromString(const string &str_label) { mask = strtol(str_label.c_str(), NULL, 0); return mask; } + +void FluxboxWindow::setOnHead(int head) { + if (head > 0 && head <= screen().numHeads()) { + int cur = screen().getHead(fbWindow()); + bool placed = m_placed; + move(screen().getHeadX(head) + frame().x() - screen().getHeadX(cur), + screen().getHeadY(head) + frame().y() - screen().getHeadY(cur)); + m_placed = placed; + } +} diff --git a/src/Window.hh b/src/Window.hh index 6fb258a..cf0077e 100644 --- a/src/Window.hh +++ b/src/Window.hh @@ -281,6 +281,8 @@ public: void setFullscreen(bool flag); /// toggle maximize void maximize(int type = MAX_FULL); + /// sets the maximized state + void setMaximizedState(int type); /// maximizes the window horizontal void maximizeHorizontal(); /// maximizes the window vertical @@ -304,6 +306,7 @@ public: void lowerLayer(); /// moves the window to a new layer void moveToLayer(int layernum, bool force = false); + void setOnHead(int head); /// sets the window focus hidden state void setFocusHidden(bool value); /// sets the window icon hidden state @@ -414,6 +417,7 @@ public: inline bool isMaximized() const { return maximized == MAX_FULL; } inline bool isMaximizedVert() const { return (bool)(maximized & MAX_VERT); } inline bool isMaximizedHorz() const { return (bool)(maximized & MAX_HORZ); } + inline int maximizedState() const { return maximized; } inline bool isIconifiable() const { return functions.iconify; } inline bool isMaximizable() const { return functions.maximize; } inline bool isResizable() const { return functions.resize; } @@ -627,6 +631,8 @@ private: m_last_button_y; ///< last known y position of the mouse button FbWinFrame m_frame; ///< the actuall window frame + bool m_placed; ///< determine whether or not we should place the window + int m_layernum; int m_old_layernum; -- cgit v0.11.2