Skip to content

Commit

Permalink
Add support for stacked tiling via ArrangeWindows*
Browse files Browse the repository at this point in the history
  • Loading branch information
jnse authored and Mathias Gumz committed Aug 2, 2013
1 parent 58e09b7 commit 57ec44e
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 17 deletions.
17 changes: 17 additions & 0 deletions doc/asciidoc/fluxbox-keys.txt
Expand Up @@ -417,6 +417,23 @@ doing so.
splits (windows on top of eachother). See *CLIENT PATTERNS* for more about the
'pattern' arguments.

*ArrangeWindowsStackLeft* 'pattern' / *ArrangeWindowsStackRight* 'pattern'::
Similar to *ArrangeWindows*, these commands arrange windows on the current
workspace. The currently focussed window is used as the 'main' window, and
will fill half the screen, while the other windows are tiled on the
other half of the screen as if they were tiled with ArrangeWindows.
*ArrangeWindowsStackLeft* puts the main window on the RIGHT hand side of the
screen, and the tiled windows are on the LEFT hand side of the screen.
*ArrangeWindowsStackRight* puts the main window on the LEFT hand side of the
screen, and the tiled windows are on the RIGHT hand side of the screen.

*ArrangeWindowsStackTop* 'pattern' / *ArrangeWindowsStackBottom 'pattern'::
Behaves just like *ArrangeWindowsStackLeft* and *ArrangeWindowsStackRight*.
*ArrangeWindowsStackBottom* places the main window on the TOP half of the
screen, and the tiled windows on the bottom half of the screen.
*ArrangeWindowsStackTop* places the main window on the BOTTOM half of the
screen and the tiled windows on the top half of the screen.

*ShowDesktop*::
Minimizes all windows on the current workspace. If they are already all
minimized, then it restores them.
Expand Down
116 changes: 101 additions & 15 deletions src/WorkspaceCmd.cc
Expand Up @@ -186,7 +186,20 @@ FbTk::Command<void> *parseWindowList(const string &command,
} else if (command == "arrangewindowshorizontal") {
int method = ArrangeWindowsCmd::HORIZONTAL;
return new ArrangeWindowsCmd(method,pat);
} else if (command == "arrangewindowsstackleft") {
int method = ArrangeWindowsCmd::STACKLEFT;
return new ArrangeWindowsCmd(method,pat);
} else if (command == "arrangewindowsstackright") {
int method = ArrangeWindowsCmd::STACKRIGHT;
return new ArrangeWindowsCmd(method,pat);
} else if (command == "arrangewindowsstacktop") {
int method = ArrangeWindowsCmd::STACKTOP;
return new ArrangeWindowsCmd(method,pat);
} else if (command == "arrangewindowsstackbottom") {
int method = ArrangeWindowsCmd::STACKBOTTOM;
return new ArrangeWindowsCmd(method,pat);
}

return 0;
}

Expand All @@ -198,6 +211,10 @@ REGISTER_COMMAND_PARSER(prevgroup, parseWindowList, void);
REGISTER_COMMAND_PARSER(arrangewindows, parseWindowList, void);
REGISTER_COMMAND_PARSER(arrangewindowsvertical, parseWindowList, void);
REGISTER_COMMAND_PARSER(arrangewindowshorizontal, parseWindowList, void);
REGISTER_COMMAND_PARSER(arrangewindowsstackleft, parseWindowList, void);
REGISTER_COMMAND_PARSER(arrangewindowsstackright, parseWindowList, void);
REGISTER_COMMAND_PARSER(arrangewindowsstacktop, parseWindowList, void);
REGISTER_COMMAND_PARSER(arrangewindowsstackbottom, parseWindowList, void);

} // end anonymous namespace

Expand All @@ -217,7 +234,7 @@ void AttachCmd::execute() {
first->attachClient((*it)->fbwindow()->winClient());
}
}

}
}

Expand Down Expand Up @@ -393,13 +410,33 @@ void ArrangeWindowsCmd::execute() {

Workspace::Windows normal_windows;
Workspace::Windows shaded_windows;
FluxboxWindow* main_window = NULL; // Main (big) window for stacked modes
for(win = space->windowList().begin(); win != space->windowList().end(); ++win) {
int winhead = screen->getHead((*win)->fbWindow());
if ((winhead == head || winhead == 0) && m_pat.match(**win)) {
if ((*win)->isShaded())
shaded_windows.push_back(*win);
else
normal_windows.push_back(*win);
// If using stacked tiling, and this window is focused, set it as main window
if (((m_tile_method == STACKLEFT) || (m_tile_method == STACKRIGHT)
|| (m_tile_method == STACKBOTTOM) || (m_tile_method == STACKTOP))
&& (*win)->isFocused()){
main_window = (*win);
}
else{
if ((*win)->isShaded())
shaded_windows.push_back(*win);
else
normal_windows.push_back(*win);
}
}
}
// if using stacked-left/right/top/bottom and we don't have a main window yet
// (no focused window?), we'll fall back on using the last window in the
// window list.
if (main_window == NULL)
{
if ((m_tile_method == STACKLEFT) || (m_tile_method == STACKRIGHT)
|| (m_tile_method == STACKTOP) || (m_tile_method == STACKBOTTOM)) {
main_window = normal_windows.back();
normal_windows.pop_back();
}
}

Expand All @@ -408,8 +445,16 @@ void ArrangeWindowsCmd::execute() {
if (win_count == 0)
return;

const unsigned int max_width = screen->maxRight(head) - screen->maxLeft(head);
unsigned int max_width = screen->maxRight(head) - screen->maxLeft(head);
// If stacked left or right, max width is divided in 2
if ((m_tile_method == STACKLEFT) || (m_tile_method == STACKRIGHT)){
max_width = max_width / 2;
}
unsigned int max_height = screen->maxBottom(head) - screen->maxTop(head);
// If stacked top or bottom, max height is divided in 2
if ((m_tile_method == STACKTOP) || (m_tile_method == STACKBOTTOM)){
max_height = max_height / 2;
}

// try to get the same number of rows as columns.
unsigned int cols = int(sqrt((float)win_count)); // truncate to lower
Expand All @@ -421,7 +466,26 @@ void ArrangeWindowsCmd::execute() {

unsigned int x_offs = screen->maxLeft(head); // window position offset in x
unsigned int y_offs = screen->maxTop(head); // window position offset in y
// unsigned int window = 0; // current window
// Stacked mode only uses half the screen for tiled windows, so adjust offset to half the screen
// (horizontal or vertical depending on stacking mode)
switch(m_tile_method)
{
case STACKRIGHT:
x_offs = int(abs((screen->maxLeft(head)-screen->maxRight(head)))/2);
break;
case STACKBOTTOM:
y_offs = int(abs(screen->maxBottom(head) - screen->maxTop(head))/2);
break;
default:
// no change needed for STACKLEFT/STACKTOP
break;
}
// Since the placing algorithm loop below modifies the offsets, but we still need them to
// position the main window, we save the calculated values.
const unsigned int orig_x_offs = x_offs;
const unsigned int orig_y_offs = y_offs;

// unsigned int window = 0; // current window
const unsigned int cal_width = max_width/cols; // calculated width ratio (width of every window)
unsigned int i;
unsigned int j;
Expand All @@ -448,7 +512,7 @@ void ArrangeWindowsCmd::execute() {
const unsigned int cal_height = max_height/rows; // height ratio (height of every window)
// Resizes and sets windows positions in columns and rows.
for (i = 0; i < rows; ++i) {
x_offs = screen->maxLeft(head);
x_offs = orig_x_offs;
for (j = 0; j < cols && !normal_windows.empty(); ++j) {


Expand All @@ -461,7 +525,7 @@ void ArrangeWindowsCmd::execute() {

int win_center_x = (*win)->frame().x() + ((*win)->frame().x() + (*win)->frame().width() / 2);
int win_center_y = (*win)->frame().y() + ((*win)->frame().y() + (*win)->frame().height() / 2);
unsigned int dist = (win_center_x - cell_center_x) * (win_center_x - cell_center_x) +
unsigned int dist = (win_center_x - cell_center_x) * (win_center_x - cell_center_x) +
(win_center_y - cell_center_y) * (win_center_y - cell_center_y);

if (dist < closest_dist) {
Expand All @@ -472,14 +536,14 @@ void ArrangeWindowsCmd::execute() {

if (normal_windows.size() > 1) {
(*closest)->moveResize(x_offs + (*closest)->xOffset(),
y_offs + (*closest)->yOffset(),
cal_width - (*closest)->widthOffset(),
cal_height - (*closest)->heightOffset());
y_offs + (*closest)->yOffset(),
cal_width - (*closest)->widthOffset(),
cal_height - (*closest)->heightOffset());
} else { // the last window gets everything that is left.
(*closest)->moveResize(x_offs + (*closest)->xOffset(),
y_offs + (*closest)->yOffset(),
screen->maxRight(head) - x_offs - (*closest)->widthOffset(),
cal_height - (*closest)->heightOffset());
y_offs + (*closest)->yOffset(),
max_width - x_offs - (*closest)->widthOffset(),
cal_height - (*closest)->heightOffset());
}

normal_windows.erase(closest);
Expand All @@ -490,6 +554,28 @@ void ArrangeWindowsCmd::execute() {
// next y offset
y_offs += cal_height;
}

// If using a stacked mechanism we now need to place the main window.
if (main_window != NULL){
switch (m_tile_method){
case STACKLEFT:
main_window->moveResize(max_width,orig_y_offs,max_width,max_height);
break;
case STACKRIGHT:
main_window->moveResize(screen->maxLeft(head),screen->maxTop(head),max_width,max_height);
break;
case STACKTOP:
main_window->moveResize(screen->maxLeft(head),max_height,max_width,max_height);
break;
case STACKBOTTOM:
main_window->moveResize(screen->maxLeft(head),screen->maxTop(head),max_width,max_height);
break;
default:
// Shouldn't happen.
break;
}
}

}

REGISTER_COMMAND(showdesktop, ShowDesktopCmd, void);
Expand Down
8 changes: 6 additions & 2 deletions src/WorkspaceCmd.hh
Expand Up @@ -86,7 +86,7 @@ private:

class PrevWindowCmd: public FbTk::Command<void> {
public:
explicit PrevWindowCmd(int option, std::string &pat):
explicit PrevWindowCmd(int option, std::string &pat):
m_option(option), m_pat(pat.c_str()) { }
void execute();
private:
Expand Down Expand Up @@ -173,7 +173,11 @@ public:
enum {
UNSPECIFIED,
VERTICAL,
HORIZONTAL
HORIZONTAL,
STACKLEFT,
STACKRIGHT,
STACKTOP,
STACKBOTTOM
};
explicit ArrangeWindowsCmd(int tile_method, std::string &pat):
m_tile_method( tile_method ), m_pat(pat.c_str()) { }
Expand Down

0 comments on commit 57ec44e

Please sign in to comment.