allow remembering minimized, maximized, and fullscreen state

This commit is contained in:
markt 2007-10-23 17:34:30 +00:00
parent c849d3c7ff
commit 1c05af4329
10 changed files with 222 additions and 80 deletions

View file

@ -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:

View file

@ -153,6 +153,9 @@ enum {
RememberWorkspace = 11,
RememberHead = 12,
RememberAlpha = 13,
RememberMinimized = 14,
RememberMaximized = 15,
RememberFullscreen = 16,
ScreenSet = 12,
ScreenAnotherWMRunning = 1,

View file

@ -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() {

View file

@ -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()))

View file

@ -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<FluxboxWindow>(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) {

View file

@ -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<ClientPattern> group_pattern;
@ -171,6 +189,9 @@ public:
REM_WORKSPACE,
REM_HEAD,
REM_ALPHA,
REM_MINIMIZEDSTATE,
REM_MAXIMIZEDSTATE,
REM_FULLSCREENSTATE,
REM_LASTATTRIB // not actually used
};

View file

@ -2325,17 +2325,3 @@ pair<int,int> 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>(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));
}
}

View file

@ -441,9 +441,6 @@ public:
template <typename OnHeadObject>
int getOnHead(OnHeadObject &obj) const;
template <typename OnHeadObject>
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).

View file

@ -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<signed>(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;
}
}

View file

@ -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;