From c27c3533f72e0721354c82e16472aa3ef7839bf7 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Thu, 8 Dec 2011 19:42:59 -0800 Subject: [PATCH] make the position math steps more visible to the outside. when next position is going to be filling the screen, just maximize the window. --- src/grid.cpp | 22 +- src/position.cpp | 785 +++++++++++++++++++++++------------------------ src/position.h | 27 +- src/window.cpp | 40 ++- src/window.h | 1 + 5 files changed, 457 insertions(+), 418 deletions(-) diff --git a/src/grid.cpp b/src/grid.cpp index d408049..445b932 100644 --- a/src/grid.cpp +++ b/src/grid.cpp @@ -21,6 +21,8 @@ #include "position.h" #include "window.h" +#include "config.h" + bool grid::set_position(POS pos) { //initializes to the currently active window ActiveWindow win; @@ -34,7 +36,23 @@ bool grid::set_position(POS pos) { //using the requested position and current dimensions, //calculate and set new dimensions PositionCalc calc(viewport, cur_dim); - + + State cur_state, next_state; + if (!calc.CurState(cur_state) || + !calc.NextState(cur_state, pos, next_state)) { + return false; + } + + //if we're going to be filling the screen anyway, just maximize + if (next_state.pos == grid::POS_CENTER && + next_state.mode == grid::MODE_THREE_COL_L) { + if (win.Maximize()) { + return true; + } + ERROR_DIR("Maximizing window failed, falling back to filling screen."); + } + Dimensions next_dim; - return calc.NextPos(pos, next_dim) && win.MoveResize(next_dim); + return calc.StateToDim(next_state, next_dim) && + win.MoveResize(next_dim); } diff --git a/src/position.cpp b/src/position.cpp index e38f3cf..afcd917 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -20,21 +20,15 @@ #include "config.h" namespace { - enum MODE { - MODE_UNKNOWN, - MODE_TWO_COL,// 2x2 (not applicable for center col positions) - MODE_THREE_COL_S,// 3x2 small: each position filling 1 column - MODE_THREE_COL_L// 3x2 large: sides filling 2 columns and center filling full width - }; - inline const char* mode_str(MODE mode) { + inline const char* mode_str(grid::MODE mode) { switch (mode) { - case MODE_UNKNOWN: + case grid::MODE_UNKNOWN: return "UNKNOWN"; - case MODE_TWO_COL: + case grid::MODE_TWO_COL: return "TWO_COL"; - case MODE_THREE_COL_S: + case grid::MODE_THREE_COL_S: return "THREE_COL_S"; - case MODE_THREE_COL_L: + case grid::MODE_THREE_COL_L: return "THREE_COL_L"; default: break; @@ -42,205 +36,6 @@ namespace { return "???"; } - struct State { - grid::POS pos; - MODE mode; - }; - - // given window's state, calculate its dimensions. - // could have some kind of fancy autogeneration here, - // but there's a very finite number of possible positions (for now?) - bool calculate_state(const Dimensions& viewport, - const State& state, Dimensions& window_out) { - bool ret = true; - long rel_x = 0, rel_y = 0;//coordinates relative to viewport - switch (state.mode) { - case MODE_TWO_COL: - switch (state.pos) { - case grid::POS_TOP_LEFT:// top left quadrant - rel_x = 0; - rel_y = 0; - window_out.width = viewport.width / 2.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_TOP_CENTER:// invalid, use mode THREE_COL_S/L - return false; - case grid::POS_TOP_RIGHT:// top right quadrant - rel_x = viewport.width / 2.; - rel_y = 0; - window_out.width = viewport.width / 2.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_LEFT:// left half - rel_x = 0; - rel_y = 0; - window_out.width = viewport.width / 2.; - window_out.height = viewport.height; - break; - case grid::POS_CENTER:// invalid, use mode THREE_COL_S/L - return false; - case grid::POS_RIGHT:// right half - rel_x = viewport.width / 2.; - rel_y = 0; - window_out.width = viewport.width / 2.; - window_out.height = viewport.height; - break; - case grid::POS_BOT_LEFT:// bottom left quadrant - rel_x = 0; - rel_y = viewport.height / 2.; - window_out.width = viewport.width / 2.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_BOT_CENTER:// invalid, use mode THREE_COL_S/L - return false; - case grid::POS_BOT_RIGHT:// bottom right quadrant - rel_x = viewport.width / 2.; - rel_y = viewport.height / 2.; - window_out.width = viewport.width / 2.; - window_out.height = viewport.height / 2.; - break; - default: - ret = false; - break; - } - break; - case MODE_THREE_COL_S: - switch (state.pos) { - case grid::POS_TOP_LEFT:// top left col - rel_x = 0; - rel_y = 0; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_TOP_CENTER:// top center col - rel_x = viewport.width / 3.; - rel_y = 0; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_TOP_RIGHT:// top right col - rel_x = 2 * viewport.width / 3.; - rel_y = 0; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_LEFT:// left third - rel_x = 0; - rel_y = 0; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height; - break; - case grid::POS_CENTER:// center col - rel_x = viewport.width / 3.; - rel_y = 0; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height; - break; - case grid::POS_RIGHT:// right third - rel_x = 2 * viewport.width / 3.; - rel_y = 0; - window_out.width = viewport.width / 3; - window_out.height = viewport.height; - break; - case grid::POS_BOT_LEFT:// bottom left col - rel_x = 0; - rel_y = viewport.height / 2.; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_BOT_CENTER:// bottom center col - rel_x = viewport.width / 3.; - rel_y = viewport.height / 2.; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_BOT_RIGHT:// bottom right col - rel_x = 2 * viewport.width / 3.; - rel_y = viewport.height / 2.; - window_out.width = viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - default: - ret = false; - } - break; - case MODE_THREE_COL_L: - switch (state.pos) { - case grid::POS_TOP_LEFT:// top left two cols - rel_x = 0; - rel_y = 0; - window_out.width = 2 * viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_TOP_CENTER:// top half - rel_x = 0; - rel_y = 0; - window_out.width = viewport.width; - window_out.height = viewport.height / 2.; - break; - case grid::POS_TOP_RIGHT:// top right two cols - rel_x = viewport.width / 3.; - rel_y = 0; - window_out.width = 2 * viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_LEFT:// left two thirds - rel_x = 0; - rel_y = 0; - window_out.width = 2 * viewport.width / 3.; - window_out.height = viewport.height; - break; - case grid::POS_CENTER:// full screen - rel_x = 0; - rel_y = 0; - window_out.width = viewport.width; - window_out.height = viewport.height; - break; - case grid::POS_RIGHT:// right two thirds - rel_x = viewport.width / 3.; - rel_y = 0; - window_out.width = 2 * viewport.width / 3.; - window_out.height = viewport.height; - break; - case grid::POS_BOT_LEFT:// bottom left two cols - rel_x = 0; - rel_y = viewport.height / 2.; - window_out.width = 2 * viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - case grid::POS_BOT_CENTER:// bottom half - rel_x = 0; - rel_y = viewport.height / 2.; - window_out.width = viewport.width; - window_out.height = viewport.height / 2.; - break; - case grid::POS_BOT_RIGHT:// bottom right two cols - rel_x = viewport.width / 3.; - rel_y = viewport.height / 2.; - window_out.width = 2 * viewport.width / 3.; - window_out.height = viewport.height / 2.; - break; - default: - ret = false; - } - break; - default: - ret = false; - } - if (ret) { - //convert relative pos to absolute: - window_out.x = rel_x + viewport.x; - window_out.y = rel_y + viewport.y; - DEBUG("pos=%s mode=%s -> %ldx %ldy %luw %luh", - pos_str(state.pos), mode_str(state.mode), - window_out.x, window_out.y, - window_out.width, window_out.height); - } else { - ERROR("Bad pos=%s + mode=%s", pos_str(state.pos), mode_str(state.mode)); - } - return ret; - } - #define MAX(a,b) (((a) > (b)) ? (a) : (b)) // whether two numbers are 'near' one another, according to a fudge factor. template @@ -254,223 +49,407 @@ namespace { return ret; } #define NEAR(a,b) _near(a, b, #a, #b) +} - // given window's dimensions, estimate its state (or unknown+unknown) - // (inverse of calculate_state) - bool get_current_state(const Dimensions& window, - const Dimensions& viewport, State& out) { - //get window x/y relative to viewport x/y - int rel_x = window.x - viewport.x, - rel_y = window.y - viewport.y; - out.pos = grid::POS_UNKNOWN; - out.mode = MODE_UNKNOWN; - if (NEAR(window.width, viewport.width / 2.)) { - if (NEAR(window.height, viewport.height / 2.)) { - if (NEAR(rel_x, 0)) { - if (NEAR(rel_y, 0)) { - // top left quadrant - out.pos = grid::POS_TOP_LEFT; - out.mode = MODE_TWO_COL; - } else if (NEAR(rel_y, viewport.height / 2.)) { - // bottom left quadrant - out.pos = grid::POS_BOT_LEFT; - out.mode = MODE_TWO_COL; - } - } else if (NEAR(rel_x, viewport.width / 2.)) { - if (NEAR(rel_y, 0)) { - // top right quadrant - out.pos = grid::POS_TOP_RIGHT; - out.mode = MODE_TWO_COL; - } else if (NEAR(rel_y, viewport.height / 2.)) { - // bottom right quadrant - out.pos = grid::POS_BOT_RIGHT; - out.mode = MODE_TWO_COL; - } +/* given window's dimensions, estimate its state (or unknown+unknown) + (inverse of StateToDim) */ +bool PositionCalc::CurState(State& out) { + //get window x/y relative to viewport x/y + int rel_x = window.x - viewport.x, + rel_y = window.y - viewport.y; + out.pos = grid::POS_UNKNOWN; + out.mode = grid::MODE_UNKNOWN; + if (NEAR(window.width, viewport.width / 2.)) { + if (NEAR(window.height, viewport.height / 2.)) { + if (NEAR(rel_x, 0)) { + if (NEAR(rel_y, 0)) { + // top left quadrant + out.pos = grid::POS_TOP_LEFT; + out.mode = grid::MODE_TWO_COL; + } else if (NEAR(rel_y, viewport.height / 2.)) { + // bottom left quadrant + out.pos = grid::POS_BOT_LEFT; + out.mode = grid::MODE_TWO_COL; } - } else if (NEAR(window.height, viewport.height) && - NEAR(rel_y, 0)) { - if (NEAR(rel_x, 0)) { - // left half - out.pos = grid::POS_LEFT; - out.mode = MODE_TWO_COL; - } else if (NEAR(rel_x, viewport.width / 2.)) { - // right half - out.pos = grid::POS_RIGHT; - out.mode = MODE_TWO_COL; + } else if (NEAR(rel_x, viewport.width / 2.)) { + if (NEAR(rel_y, 0)) { + // top right quadrant + out.pos = grid::POS_TOP_RIGHT; + out.mode = grid::MODE_TWO_COL; + } else if (NEAR(rel_y, viewport.height / 2.)) { + // bottom right quadrant + out.pos = grid::POS_BOT_RIGHT; + out.mode = grid::MODE_TWO_COL; } } - } else if (NEAR(window.width, viewport.width / 3.)) { - if (NEAR(window.height, viewport.height / 2.)) { - if (NEAR(rel_x, 0)) { - if (NEAR(rel_y, 0)) { - // top left col - out.pos = grid::POS_TOP_LEFT; - out.mode = MODE_THREE_COL_S; - } if (NEAR(rel_y, viewport.height / 2.)) { - // bottom left col - out.pos = grid::POS_BOT_LEFT; - out.mode = MODE_THREE_COL_S; - } - } else if (NEAR(rel_x, viewport.width / 3.)) { - if (NEAR(rel_y, 0)) { - // top center col - out.pos = grid::POS_TOP_CENTER; - out.mode = MODE_THREE_COL_S; - } else if (NEAR(rel_y, viewport.height / 2.)) { - // bottom center col - out.pos = grid::POS_BOT_CENTER; - out.mode = MODE_THREE_COL_S; - } - } else if (NEAR(rel_x, 2 * viewport.width / 3.)) { - if (NEAR(rel_y, 0)) { - // top right col - out.pos = grid::POS_TOP_RIGHT; - out.mode = MODE_THREE_COL_S; - } else if (NEAR(rel_y, viewport.height / 2.)) { - // bottom right col - out.pos = grid::POS_BOT_RIGHT; - out.mode = MODE_THREE_COL_S; - } - } - } else if (NEAR(window.height, viewport.height) && - NEAR(rel_y, 0)) { - if (NEAR(rel_x, 0)) { - // left col - out.pos = grid::POS_LEFT; - out.mode = MODE_THREE_COL_S; - } else if (NEAR(rel_x, viewport.width / 3.)) { - // center col - out.pos = grid::POS_CENTER; - out.mode = MODE_THREE_COL_S; - } else if (NEAR(rel_x, 2 * viewport.width / 3.)) { - // right col - out.pos = grid::POS_RIGHT; - out.mode = MODE_THREE_COL_S; - } + } else if (NEAR(window.height, viewport.height) && + NEAR(rel_y, 0)) { + if (NEAR(rel_x, 0)) { + // left half + out.pos = grid::POS_LEFT; + out.mode = grid::MODE_TWO_COL; + } else if (NEAR(rel_x, viewport.width / 2.)) { + // right half + out.pos = grid::POS_RIGHT; + out.mode = grid::MODE_TWO_COL; } - } else if (NEAR(window.width, 2 * viewport.width / 3.)) { - if (NEAR(window.height, viewport.height / 2.)) { - if (NEAR(rel_x, 0)) { - if (NEAR(rel_y, 0)) { - // top left two cols - out.pos = grid::POS_TOP_LEFT; - out.mode = MODE_THREE_COL_L; - } else if (NEAR(rel_y, viewport.height / 2.)) { - // bottom left two cols - out.pos = grid::POS_BOT_LEFT; - out.mode = MODE_THREE_COL_L; - } - } else if (NEAR(rel_x, viewport.width / 3.)) { - if (NEAR(rel_y, 0)) { - // top right two cols - out.pos = grid::POS_TOP_RIGHT; - out.mode = MODE_THREE_COL_L; - } else if (NEAR(rel_y, viewport.height / 2.)) { - // bottom right two cols - out.pos = grid::POS_BOT_RIGHT; - out.mode = MODE_THREE_COL_L; - } - } - } else if (NEAR(window.height, viewport.height) && - NEAR(rel_y, 0)) { - if (NEAR(rel_x, 0)) { - // left two cols - out.pos = grid::POS_LEFT; - out.mode = MODE_THREE_COL_L; - } else if (NEAR(rel_x, viewport.width / 3.)) { - // right two cols - out.pos = grid::POS_RIGHT; - out.mode = MODE_THREE_COL_L; + } + } else if (NEAR(window.width, viewport.width / 3.)) { + if (NEAR(window.height, viewport.height / 2.)) { + if (NEAR(rel_x, 0)) { + if (NEAR(rel_y, 0)) { + // top left col + out.pos = grid::POS_TOP_LEFT; + out.mode = grid::MODE_THREE_COL_S; + } if (NEAR(rel_y, viewport.height / 2.)) { + // bottom left col + out.pos = grid::POS_BOT_LEFT; + out.mode = grid::MODE_THREE_COL_S; } - } - } else if (NEAR(window.width, viewport.width) && - NEAR(rel_x, 0)) { - if (NEAR(window.height, viewport.height / 2.)) { + } else if (NEAR(rel_x, viewport.width / 3.)) { if (NEAR(rel_y, 0)) { - // top half + // top center col out.pos = grid::POS_TOP_CENTER; - out.mode = MODE_THREE_COL_L; + out.mode = grid::MODE_THREE_COL_S; } else if (NEAR(rel_y, viewport.height / 2.)) { - // bottom half + // bottom center col out.pos = grid::POS_BOT_CENTER; - out.mode = MODE_THREE_COL_L; + out.mode = grid::MODE_THREE_COL_S; + } + } else if (NEAR(rel_x, 2 * viewport.width / 3.)) { + if (NEAR(rel_y, 0)) { + // top right col + out.pos = grid::POS_TOP_RIGHT; + out.mode = grid::MODE_THREE_COL_S; + } else if (NEAR(rel_y, viewport.height / 2.)) { + // bottom right col + out.pos = grid::POS_BOT_RIGHT; + out.mode = grid::MODE_THREE_COL_S; } - } else if (NEAR(window.height, viewport.height) && - NEAR(rel_y, 0)) { - // full screen + } + } else if (NEAR(window.height, viewport.height) && + NEAR(rel_y, 0)) { + if (NEAR(rel_x, 0)) { + // left col + out.pos = grid::POS_LEFT; + out.mode = grid::MODE_THREE_COL_S; + } else if (NEAR(rel_x, viewport.width / 3.)) { + // center col out.pos = grid::POS_CENTER; - out.mode = MODE_THREE_COL_L; + out.mode = grid::MODE_THREE_COL_S; + } else if (NEAR(rel_x, 2 * viewport.width / 3.)) { + // right col + out.pos = grid::POS_RIGHT; + out.mode = grid::MODE_THREE_COL_S; } } - - DEBUG("%ldx %ldy %luw %luh -> pos=%s mode=%s", - rel_x, rel_y, window.width, window.height, - pos_str(out.pos), mode_str(out.mode)); - return true; + } else if (NEAR(window.width, 2 * viewport.width / 3.)) { + if (NEAR(window.height, viewport.height / 2.)) { + if (NEAR(rel_x, 0)) { + if (NEAR(rel_y, 0)) { + // top left two cols + out.pos = grid::POS_TOP_LEFT; + out.mode = grid::MODE_THREE_COL_L; + } else if (NEAR(rel_y, viewport.height / 2.)) { + // bottom left two cols + out.pos = grid::POS_BOT_LEFT; + out.mode = grid::MODE_THREE_COL_L; + } + } else if (NEAR(rel_x, viewport.width / 3.)) { + if (NEAR(rel_y, 0)) { + // top right two cols + out.pos = grid::POS_TOP_RIGHT; + out.mode = grid::MODE_THREE_COL_L; + } else if (NEAR(rel_y, viewport.height / 2.)) { + // bottom right two cols + out.pos = grid::POS_BOT_RIGHT; + out.mode = grid::MODE_THREE_COL_L; + } + } + } else if (NEAR(window.height, viewport.height) && + NEAR(rel_y, 0)) { + if (NEAR(rel_x, 0)) { + // left two cols + out.pos = grid::POS_LEFT; + out.mode = grid::MODE_THREE_COL_L; + } else if (NEAR(rel_x, viewport.width / 3.)) { + // right two cols + out.pos = grid::POS_RIGHT; + out.mode = grid::MODE_THREE_COL_L; + } + } + } else if (NEAR(window.width, viewport.width) && + NEAR(rel_x, 0)) { + if (NEAR(window.height, viewport.height / 2.)) { + if (NEAR(rel_y, 0)) { + // top half + out.pos = grid::POS_TOP_CENTER; + out.mode = grid::MODE_THREE_COL_L; + } else if (NEAR(rel_y, viewport.height / 2.)) { + // bottom half + out.pos = grid::POS_BOT_CENTER; + out.mode = grid::MODE_THREE_COL_L; + } + } else if (NEAR(window.height, viewport.height) && + NEAR(rel_y, 0)) { + // full screen + out.pos = grid::POS_CENTER; + out.mode = grid::MODE_THREE_COL_L; + } } - bool get_next_state(const State& cur, grid::POS req_pos, State& out) { - if (req_pos == grid::POS_UNKNOWN) { - ERROR("Position '%s' was requested. Internal error?", pos_str(req_pos)); - return false;// nice to have - } - if (cur.pos == req_pos) { - // position is same, so rotate mode - out.pos = cur.pos; - switch (cur.pos) { - case grid::POS_TOP_CENTER: - case grid::POS_CENTER: - case grid::POS_BOT_CENTER: - // for center col: 3x2L -> 3x2S (-> 3x2L) (no 2x2) - switch (cur.mode) { - case MODE_THREE_COL_L: - out.mode = MODE_THREE_COL_S; - break; - case MODE_THREE_COL_S: - default: - out.mode = MODE_THREE_COL_L; - } + DEBUG("%ldx %ldy %luw %luh -> pos=%s mode=%s", + rel_x, rel_y, window.width, window.height, + pos_str(out.pos), mode_str(out.mode)); + return true; +} + +bool PositionCalc::NextState(const State& cur, grid::POS req_pos, State& out) { + if (req_pos == grid::POS_UNKNOWN) { + ERROR("Position '%s' was requested. Internal error?", pos_str(req_pos)); + return false;// nice to have + } + if (cur.pos == req_pos) { + // position is same, so rotate mode + out.pos = cur.pos; + switch (cur.pos) { + case grid::POS_TOP_CENTER: + case grid::POS_CENTER: + case grid::POS_BOT_CENTER: + // for center col: 3x2L -> 3x2S (-> 3x2L) (no 2x2) + switch (cur.mode) { + case grid::MODE_THREE_COL_L: + out.mode = grid::MODE_THREE_COL_S; break; + case grid::MODE_THREE_COL_S: default: - // for everything else: 2x2 -> 3x2L -> 3x2S (-> 2x2) - switch (cur.mode) { - case MODE_UNKNOWN: - case MODE_THREE_COL_L: - out.mode = MODE_THREE_COL_S; - break; - case MODE_TWO_COL: - out.mode = MODE_THREE_COL_L; - break; - case MODE_THREE_COL_S: - default: - out.mode = MODE_TWO_COL; - } + out.mode = grid::MODE_THREE_COL_L; } - } else { - // new position, so start with initial mode - out.pos = req_pos; - switch (req_pos) { - case grid::POS_TOP_CENTER: - case grid::POS_CENTER: - case grid::POS_BOT_CENTER: - // for center col: start with 3x2L - out.mode = MODE_THREE_COL_L; + break; + default: + // for everything else: 2x2 -> 3x2L -> 3x2S (-> 2x2) + switch (cur.mode) { + case grid::MODE_UNKNOWN: + case grid::MODE_THREE_COL_L: + out.mode = grid::MODE_THREE_COL_S; + break; + case grid::MODE_TWO_COL: + out.mode = grid::MODE_THREE_COL_L; break; + case grid::MODE_THREE_COL_S: default: - // for everything else: start with 2x2 - out.mode = MODE_TWO_COL; + out.mode = grid::MODE_TWO_COL; } } - DEBUG("curpos=%s curmode=%s + reqpos=%s -> pos=%s mode=%s", - pos_str(cur.pos), mode_str(cur.mode), pos_str(req_pos), - pos_str(out.pos), mode_str(out.mode)); - return true; + } else { + // new position, so start with initial mode + out.pos = req_pos; + switch (req_pos) { + case grid::POS_TOP_CENTER: + case grid::POS_CENTER: + case grid::POS_BOT_CENTER: + // for center col: start with 3x2L + out.mode = grid::MODE_THREE_COL_L; + break; + default: + // for everything else: start with 2x2 + out.mode = grid::MODE_TWO_COL; + } } + DEBUG("curpos=%s curmode=%s + reqpos=%s -> pos=%s mode=%s", + pos_str(cur.pos), mode_str(cur.mode), pos_str(req_pos), + pos_str(out.pos), mode_str(out.mode)); + return true; } -bool PositionCalc::NextPos(grid::POS request, Dimensions& out) { - State cur_state, next_state; - return get_current_state(window, viewport, cur_state) &&// window + viewport -> cur_state - get_next_state(cur_state, request, next_state) &&// cur_state + request -> next_state - calculate_state(viewport, next_state, out);// next_state + viewport -> next_dim +/* given window's state, calculate its dimensions. + could have some kind of fancy autogeneration here, + but there's a very finite number of possible positions (for now?) */ +bool PositionCalc::StateToDim(const State& state, Dimensions& out) { + bool ret = true; + long rel_x = 0, rel_y = 0;//coordinates relative to viewport + switch (state.mode) { + case grid::MODE_TWO_COL: + switch (state.pos) { + case grid::POS_TOP_LEFT:// top left quadrant + rel_x = 0; + rel_y = 0; + out.width = viewport.width / 2.; + out.height = viewport.height / 2.; + break; + case grid::POS_TOP_CENTER:// invalid, use mode THREE_COL_S/L + return false; + case grid::POS_TOP_RIGHT:// top right quadrant + rel_x = viewport.width / 2.; + rel_y = 0; + out.width = viewport.width / 2.; + out.height = viewport.height / 2.; + break; + case grid::POS_LEFT:// left half + rel_x = 0; + rel_y = 0; + out.width = viewport.width / 2.; + out.height = viewport.height; + break; + case grid::POS_CENTER:// invalid, use mode THREE_COL_S/L + return false; + case grid::POS_RIGHT:// right half + rel_x = viewport.width / 2.; + rel_y = 0; + out.width = viewport.width / 2.; + out.height = viewport.height; + break; + case grid::POS_BOT_LEFT:// bottom left quadrant + rel_x = 0; + rel_y = viewport.height / 2.; + out.width = viewport.width / 2.; + out.height = viewport.height / 2.; + break; + case grid::POS_BOT_CENTER:// invalid, use mode THREE_COL_S/L + return false; + case grid::POS_BOT_RIGHT:// bottom right quadrant + rel_x = viewport.width / 2.; + rel_y = viewport.height / 2.; + out.width = viewport.width / 2.; + out.height = viewport.height / 2.; + break; + default: + ret = false; + break; + } + break; + case grid::MODE_THREE_COL_S: + switch (state.pos) { + case grid::POS_TOP_LEFT:// top left col + rel_x = 0; + rel_y = 0; + out.width = viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_TOP_CENTER:// top center col + rel_x = viewport.width / 3.; + rel_y = 0; + out.width = viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_TOP_RIGHT:// top right col + rel_x = 2 * viewport.width / 3.; + rel_y = 0; + out.width = viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_LEFT:// left third + rel_x = 0; + rel_y = 0; + out.width = viewport.width / 3.; + out.height = viewport.height; + break; + case grid::POS_CENTER:// center col + rel_x = viewport.width / 3.; + rel_y = 0; + out.width = viewport.width / 3.; + out.height = viewport.height; + break; + case grid::POS_RIGHT:// right third + rel_x = 2 * viewport.width / 3.; + rel_y = 0; + out.width = viewport.width / 3; + out.height = viewport.height; + break; + case grid::POS_BOT_LEFT:// bottom left col + rel_x = 0; + rel_y = viewport.height / 2.; + out.width = viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_BOT_CENTER:// bottom center col + rel_x = viewport.width / 3.; + rel_y = viewport.height / 2.; + out.width = viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_BOT_RIGHT:// bottom right col + rel_x = 2 * viewport.width / 3.; + rel_y = viewport.height / 2.; + out.width = viewport.width / 3.; + out.height = viewport.height / 2.; + break; + default: + ret = false; + } + break; + case grid::MODE_THREE_COL_L: + switch (state.pos) { + case grid::POS_TOP_LEFT:// top left two cols + rel_x = 0; + rel_y = 0; + out.width = 2 * viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_TOP_CENTER:// top half + rel_x = 0; + rel_y = 0; + out.width = viewport.width; + out.height = viewport.height / 2.; + break; + case grid::POS_TOP_RIGHT:// top right two cols + rel_x = viewport.width / 3.; + rel_y = 0; + out.width = 2 * viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_LEFT:// left two thirds + rel_x = 0; + rel_y = 0; + out.width = 2 * viewport.width / 3.; + out.height = viewport.height; + break; + case grid::POS_CENTER:// full screen + rel_x = 0; + rel_y = 0; + out.width = viewport.width; + out.height = viewport.height; + break; + case grid::POS_RIGHT:// right two thirds + rel_x = viewport.width / 3.; + rel_y = 0; + out.width = 2 * viewport.width / 3.; + out.height = viewport.height; + break; + case grid::POS_BOT_LEFT:// bottom left two cols + rel_x = 0; + rel_y = viewport.height / 2.; + out.width = 2 * viewport.width / 3.; + out.height = viewport.height / 2.; + break; + case grid::POS_BOT_CENTER:// bottom half + rel_x = 0; + rel_y = viewport.height / 2.; + out.width = viewport.width; + out.height = viewport.height / 2.; + break; + case grid::POS_BOT_RIGHT:// bottom right two cols + rel_x = viewport.width / 3.; + rel_y = viewport.height / 2.; + out.width = 2 * viewport.width / 3.; + out.height = viewport.height / 2.; + break; + default: + ret = false; + } + break; + default: + ret = false; + } + if (ret) { + //convert relative pos to absolute: + out.x = rel_x + viewport.x; + out.y = rel_y + viewport.y; + DEBUG("pos=%s mode=%s -> %ldx %ldy %luw %luh", + pos_str(state.pos), mode_str(state.mode), + out.x, out.y, out.width, out.height); + } else { + ERROR("Bad pos=%s + mode=%s", pos_str(state.pos), mode_str(state.mode)); + } + return ret; } diff --git a/src/position.h b/src/position.h index b5965bc..309c055 100644 --- a/src/position.h +++ b/src/position.h @@ -22,13 +22,38 @@ #include "pos.h" #include "dimensions.h" +namespace grid { + enum MODE { + MODE_UNKNOWN, + MODE_TWO_COL,// 2x2 (not applicable for center col positions) + MODE_THREE_COL_S,// 3x2 small: each position filling 1 column + MODE_THREE_COL_L// 3x2 large: sides filling 2 columns and center filling full width + }; +} + +struct State { + grid::POS pos; + grid::MODE mode; +}; + class PositionCalc { public: PositionCalc(const Dimensions& viewport, const Dimensions& window) : viewport(viewport), window(window) { } - bool NextPos(grid::POS request, Dimensions& out); + /* Produces an autodetected state of this window using its current + * coordinates. Returns true on success, else false. */ + bool CurState(State& cur_state); + + /* Given a current state and requested position for the window, calculates + * its next state. Returns true on success, else false. */ + bool NextState(const State& cur_state, grid::POS req_pos, + State& next_state); + + /* Given a state for the window, calculates the dimensions of that position. + * Returns true on success, else false. */ + bool StateToDim(const State& state, Dimensions& out); private: const Dimensions viewport, window; diff --git a/src/window.cpp b/src/window.cpp index 0694390..2ebf747 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -81,7 +81,7 @@ namespace { if (!(types = (Atom*)x11_util::get_property(disp, win, XA_ATOM, "_NET_WM_WINDOW_TYPE", &count))) { - ERROR_DIR("couldnt get window types"); + ERROR_DIR("couldn't get window types"); //assume window types are allowed, keep going } else { for (size_t i = 0; i < count; ++i) { @@ -110,7 +110,7 @@ namespace { if (!(states = (Atom*)x11_util::get_property(disp, win, XA_ATOM, "_NET_WM_STATE", &count))) { - ERROR_DIR("couldnt get window states"); + ERROR_DIR("couldn't get window states"); //assume window states are allowed, keep going } else { bool has_skip_pager = false, has_skip_taskbar = false; @@ -228,25 +228,30 @@ namespace { XInternAtom(disp, "_NET_WM_STATE_SHADED", False), XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False), SOURCE_INDICATION, 0)) { - ERROR_DIR("couldnt unshade/defullscreen"); + ERROR_DIR("couldn't unshade/defullscreen"); return false; } return true; } - bool demaximize_window(Display* disp, Window win) { + bool maximize_window(Display* disp, Window win, bool maximize) { /* this disagrees with docs, which say that we should be using a - _NET_WM_STATE_DISABLE atom in data[0]. but that apparently doesn't - work in practice, but '0' does. (and '1' works for ENABLE) + _NET_WM_STATE_DISABLE/_ENABLE atom in data[0]. That apparently doesn't + work in practice, but '0'/'1' do. */ + int val = (maximize) ? 1 : 0;//just to be explicit if (!client_msg(disp, win, "_NET_WM_STATE", - 0,//1 = enable state(s), 0 = disable state(s) + val,//1 = enable state(s), 0 = disable state(s) XInternAtom(disp, "_NET_WM_STATE_MAXIMIZED_VERT", False), XInternAtom(disp, "_NET_WM_STATE_MAXIMIZED_HORZ", False), SOURCE_INDICATION, 0)) { - ERROR_DIR("couldnt demaximize"); + if (maximize) { + ERROR_DIR("couldn't maximize"); + } else { + ERROR_DIR("couldn't demaximize"); + } return false; } @@ -300,7 +305,7 @@ bool ActiveWindow::Sizes(Dimensions& viewport, Dimensions& activewin) const { } if (!get_window_size(disp, *win, &activewin, NULL, NULL)) { - ERROR_DIR("couldnt get window size"); + ERROR_DIR("couldn't get window size"); return false; } @@ -333,7 +338,7 @@ bool ActiveWindow::MoveResize(const Dimensions& activewin) { } //demaximize the window before attempting to move it - demaximize_window(disp, *win);//disregard failure + maximize_window(disp, *win, false);//disregard failure unsigned long new_interior_width = activewin.width - margin_width, new_interior_height = activewin.height - margin_height; @@ -344,6 +349,17 @@ bool ActiveWindow::MoveResize(const Dimensions& activewin) { margin_width, margin_height, activewin.x, activewin.y, new_interior_width, new_interior_height); - return XMoveResizeWindow(disp, *win, activewin.x, activewin.y, - new_interior_width, new_interior_height) == 0; + if (XMoveResizeWindow(disp, *win, activewin.x, activewin.y, + new_interior_width, new_interior_height) == 0) { + ERROR("MoveResize to %ldx %ldy %luw %luh failed.", + activewin.x, activewin.y, new_interior_width, new_interior_height); + return false; + } + return true; +} + +bool ActiveWindow::Maximize() { + CHECK_STATE(); + + return maximize_window(disp, *win, true); } diff --git a/src/window.h b/src/window.h index f6da330..dcb679b 100644 --- a/src/window.h +++ b/src/window.h @@ -36,6 +36,7 @@ class ActiveWindow { bool Sizes(Dimensions& viewport, Dimensions& activewin) const; bool MoveResize(const Dimensions& activewin); + bool Maximize(); private: Display* disp; -- 2.45.2