Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Awesome/Monad style automatic layouts to Sway #1024

Merged
merged 36 commits into from
Jan 14, 2017
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
97f7d47
Added Awesome/Monad type "auto" layouts
willakat Dec 10, 2016
5425d04
Handle resize in auto layouts
willakat Dec 19, 2016
8b0073b
Added "layout incnmaster|incncol" commands
willakat Dec 21, 2016
ed71e67
[fix] handle cases where nb_master > children->length in auto layout
willakat Dec 21, 2016
bc3dc97
[fix] Handle auto layout resize with multiple slave groups
willakat Dec 21, 2016
0ff9fe9
introduce next/prev as a direction for focus/move commands.
willakat Dec 22, 2016
2b0e3c2
[fix] move next/prev behavior for vert/horiz layout
willakat Dec 22, 2016
a0aa8d9
cleanup in auto layouts
willakat Dec 29, 2016
1b87193
Added "layout promote" command.
willakat Dec 29, 2016
4b1d9b0
Added a word in the Readme about the purpose of the fork.
willakat Dec 30, 2016
15745ab
[fix] cycle auto layouts backwards
willakat Dec 31, 2016
c01b898
Fix inline is_auto_layout
ddevault Jan 1, 2017
0412e95
Document new layout command syntax
ddevault Jan 1, 2017
a62048f
changed "layout promote" command to "move first"
willakat Jan 1, 2017
97f7098
[fix] cleanups suggested by Sway community
willakat Jan 1, 2017
704b2db
Merge branch 'master' of https://github.com/willakat/sway
willakat Jan 1, 2017
bd41502
Moved auto_* layout functions from resize.c to layout.c
willakat Jan 7, 2017
d99efb5
[fix] corner cases win nb_children < nb_master|nb_col
willakat Jan 7, 2017
f726968
[fix] scale check to prevent un-necessary layouts was in the wrong pl…
willakat Jan 7, 2017
3c84250
[fix] resize should now preserve surrounding container's dimensions
willakat Jan 7, 2017
1f47c58
simplification of apply_auto_layout
willakat Jan 7, 2017
f24ebd7
Added mouse resize for auto layouts
willakat Jan 7, 2017
653e96f
Merge branch 'master' into master
willakat Jan 7, 2017
2040c62
Merge branch 'master' of https://github.com/SirCmpwn/sway
willakat Jan 7, 2017
d822150
[fix] Keep Clang happy
willakat Jan 8, 2017
063c798
Indent cleanups
willakat Jan 8, 2017
07474a4
reworked "layout auto*" star commands
willakat Jan 8, 2017
52f3a8d
fixed up space-after-cast style issues
willakat Jan 8, 2017
32430d3
Merge branch 'master' of https://github.com/willakat/sway
willakat Jan 8, 2017
dc361fd
Merge branch 'master' into master
willakat Jan 8, 2017
4c06a10
Merge branch 'master' into master
willakat Jan 14, 2017
b74870f
Improved behavior of insert/remove child in auto layouts
willakat Jan 14, 2017
71b3869
replaced "bot" with "bottom" in auto layout commands
willakat Jan 14, 2017
5c40cc4
Added a sample config for Awesome-like behavior
willakat Jan 14, 2017
a90ddde
[fix] handle auto layout of empty container
willakat Jan 14, 2017
a2cf3be
Move awesome config to contrib/
ddevault Jan 14, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ int list_seq_find(list_t *list, int compare(const void *item, const void *data),
return -1;
}

static void list_swap(list_t *list, int src, int dest) {
void list_swap(list_t *list, int src, int dest) {
void *tmp = list->items[src];
list->items[src] = list->items[dest];
list->items[dest] = tmp;
Expand Down
2 changes: 2 additions & 0 deletions include/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ void list_qsort(list_t *list, int compare(const void *left, const void *right));
int list_seq_find(list_t *list, int compare(const void *item, const void *cmp_to), const void *cmp_to);
// stable sort since qsort is not guaranteed to be stable
void list_stable_sort(list_t *list, int compare(const void *a, const void *b));
// swap two elements in a list
void list_swap(list_t *list, int src, int dest);
#endif
20 changes: 20 additions & 0 deletions include/sway/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ enum swayc_layouts {
L_STACKED,
L_TABBED,
L_FLOATING, /**< A psuedo-container, removed from the tree, to hold floating windows */

/* Awesome/Monad style auto layouts */
L_AUTO_LEFT,
L_AUTO_RIGHT,
L_AUTO_TOP,
L_AUTO_BOTTOM,

L_AUTO_FIRST = L_AUTO_LEFT,
L_AUTO_LAST = L_AUTO_BOTTOM,

// Keep last
L_LAYOUTS,
};
Expand Down Expand Up @@ -144,6 +154,16 @@ struct sway_container {
struct wlc_geometry title_bar_geometry;
struct wlc_geometry actual_geometry;
int border_thickness;

/**
* Number of master views in auto layouts.
*/
size_t nb_master;

/**
* Number of slave groups (e.g. columns) in auto layouts.
*/
size_t nb_slave_groups;
};

enum visibility_mask {
Expand Down
6 changes: 4 additions & 2 deletions include/sway/focus.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ enum movement_direction {
MOVE_UP,
MOVE_DOWN,
MOVE_PARENT,
MOVE_CHILD
MOVE_CHILD,
MOVE_NEXT,
MOVE_PREV,
MOVE_FIRST
};

#include "container.h"
Expand Down Expand Up @@ -40,4 +43,3 @@ extern bool suspend_workspace_cleanup;
bool move_focus(enum movement_direction direction);

#endif

7 changes: 7 additions & 0 deletions include/sway/layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,11 @@ void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ..
*/
enum swayc_layouts default_layout(swayc_t *output);

bool is_auto_layout(enum swayc_layouts layout);
int auto_group_start_index(const swayc_t *container, int index);
int auto_group_end_index(const swayc_t *container, int index);
size_t auto_group_count(const swayc_t *container);
size_t auto_group_index(const swayc_t *container, int index);
bool auto_group_bounds(const swayc_t *container, size_t group_index, int *start, int *end);

#endif
63 changes: 63 additions & 0 deletions samples/awesome-like.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#
# Replicate some of Awesome's default layout manipulation configuration for Sway
#
# Differences:
# - Layout switching doesn't use the spacebar (i.e. i3/Sway behavior to switch to/from floating windows)
# and uses the 'A' key instead (as in auto)
# - Resizing windows uses i3/Sway's more versatile Mod4+r
# - no tags
# - no Maximize/Minize, alternatives to Maximize would be to switch to Stacked/Tabbed layouts
# via Mod4+w or Mod4+s.
# - kill focused client is available on Mod4+Shift+q (instead of Mod4+Shift+c, which maps to Sway's
# config reload)
# - probably many more ...

# Awesome-style container traversal using Vim-like binding
set $next j
set $prev k

#
# Moving around:
#
# Move your focus around
bindsym $mod+$next focus next
bindsym $mod+$prev focus prev

# _move_ the focused window with the same, but add Shift
bindsym $mod+Shift+$next move next
bindsym $mod+Shift+$prev move prev

#
# Layout:
#
workspace_layout auto left

# This is usually bound to $mod+space, but this works well in practice by keeping
# all the layout switching keys grouped together.
bindsym $mod+a layout auto next
bindsym $mod+Shift+a layout auto prev

# Promote a child to master position in an auto layout
bindsym $mod+Control+Return move first

# Increase/decrease number of master elements in auto layout
bindsym $mod+Shift+h layout auto master inc 1
bindsym $mod+Shift+l layout auto master inc -1

# Increase/decrease number of slave element groups in auto layout
bindsym $mod+Control+h layout auto ncol inc 1
bindsym $mod+Control+l layout auto ncol inc -1

#
# Resizing containers:
# Again, not really the way Awesome works well, but in spirit with i3/Sway and it works well.
#
mode "resize" {
bindsym Left resize shrink width 20 px
bindsym Down resize grow height 20 px
bindsym Up resize shrink height 20 px
bindsym Right resize grow width 20 px
}
bindsym $mod+r mode "resize"

new_window pixel 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put this into a directory called contrib instead?

4 changes: 4 additions & 0 deletions sway/commands/focus.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
move_focus(MOVE_PARENT);
} else if (strcasecmp(argv[0], "child") == 0) {
move_focus(MOVE_CHILD);
} else if (strcasecmp(argv[0], "next") == 0) {
move_focus(MOVE_NEXT);
} else if (strcasecmp(argv[0], "prev") == 0) {
move_focus(MOVE_PREV);
} else if (strcasecmp(argv[0], "mode_toggle") == 0) {
int i;
swayc_t *workspace = swayc_active_workspace();
Expand Down
127 changes: 126 additions & 1 deletion sway/commands/layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
#include "sway/container.h"
#include "sway/layout.h"

/**
* handle "layout auto" command group
*/
static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv);

struct cmd_results *cmd_layout(int argc, char **argv) {
struct cmd_results *error = NULL;
if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file.");
Expand Down Expand Up @@ -49,11 +54,14 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
} else if (strcasecmp(argv[0], "splitv") == 0) {
swayc_change_layout(parent, L_VERT);
} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE || parent->workspace_layout == L_HORIZ)) {
if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE
|| parent->workspace_layout == L_HORIZ)) {
swayc_change_layout(parent, L_VERT);
} else {
swayc_change_layout(parent, L_HORIZ);
}
} else if (strcasecmp(argv[0], "auto") == 0) {
return cmd_layout_auto(parent, argc, argv);
}
}

Expand All @@ -64,3 +72,120 @@ struct cmd_results *cmd_layout(int argc, char **argv) {

return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv) {
// called after checking that argv[0] is auto, so just continue parsing from there
struct cmd_results *error = NULL;
const char *cmd_name = "layout auto";
const char *set_inc_cmd_name = "layout auto [master|ncol] [set|inc]";
const char *err_msg = "Allowed arguments are <right|left|top|bottom|next|prev|master|ncol>";

bool need_layout_update = false;
enum swayc_layouts old_layout = container->layout;
enum swayc_layouts layout = old_layout;

if (strcasecmp(argv[1], "left") == 0) {
layout = L_AUTO_LEFT;
} else if (strcasecmp(argv[1], "right") == 0) {
layout = L_AUTO_RIGHT;
} else if (strcasecmp(argv[1], "top") == 0) {
layout = L_AUTO_TOP;
} else if (strcasecmp(argv[1], "bottom") == 0) {
layout = L_AUTO_BOTTOM;
} else if (strcasecmp(argv[1], "next") == 0) {
if (is_auto_layout(container->layout) && container->layout < L_AUTO_LAST) {
layout = container->layout + 1;
} else {
layout = L_AUTO_FIRST;
}
} else if (strcasecmp(argv[1], "prev") == 0) {
if (is_auto_layout(container->layout) && container->layout > L_AUTO_FIRST) {
layout = container->layout - 1;
} else {
layout = L_AUTO_LAST;
}
} else {
bool is_nmaster;
bool is_set;
if (strcasecmp(argv[1], "master") == 0) {
is_nmaster = true;
} else if (strcasecmp(argv[1], "ncol") == 0) {
is_nmaster = false;
} else {
return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command. %s",
cmd_name, err_msg);
}
if ((error = checkarg(argc, "auto <master|ncol>", EXPECTED_EQUAL_TO, 4))) {
return error;
}
if (strcasecmp(argv[2], "set") == 0) {
is_set = true;
} else if (strcasecmp(argv[2], "inc") == 0) {
is_set = false;
} else {
return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command. %s, "
"Argument must be on of <set|inc>",
set_inc_cmd_name);
}
char *end;
int n = (int)strtol(argv[3], &end, 10);
if (*end) {
return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command "
"(argument must be an integer)", set_inc_cmd_name);
}
if (is_auto_layout(container->layout)) {
int inc = 0; /* difference between current master/ncol and requested value */
if (is_nmaster) {
if (is_set) {
if (n < 0) {
return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command "
"(master must be >= 0)", set_inc_cmd_name);
}
inc = n - (int)container->nb_master;
} else { /* inc command */
if ((int)container->nb_master + n >= 0) {
inc = n;
}
}
if (inc) {
for (int i = container->nb_master;
i >= 0 && i < container->children->length
&& i != (int)container->nb_master + inc;) {
((swayc_t *)container->children->items[i])->height = -1;
((swayc_t *)container->children->items[i])->width = -1;
i += inc > 0 ? 1 : -1;
}
container->nb_master += inc;
need_layout_update = true;
}
} else { /* ncol modification */
if (is_set) {
if (n <= 0) {
return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command "
"(ncol must be > 0)", set_inc_cmd_name);
}
inc = n - (int)container->nb_slave_groups;
} else { /* inc command */
if ((int)container->nb_slave_groups + n > 0) {
inc = n;
}
}
if (inc) {
container->nb_slave_groups += inc;
need_layout_update = true;
}
}
}
}

if (layout != old_layout) {
swayc_change_layout(container, layout);
update_layout_geometry(container, old_layout);
need_layout_update = true;
}
if (need_layout_update) {
update_geometry(container);
arrange_windows(container, container->width, container->height);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
8 changes: 7 additions & 1 deletion sway/commands/move.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct cmd_results *cmd_move(int argc, char **argv) {
if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
return error;
}
const char* expected_syntax = "Expected 'move <left|right|up|down>' or "
const char* expected_syntax = "Expected 'move <left|right|up|down|next|prev|first>' or "
"'move <container|window> to workspace <name>' or "
"'move <container|window|workspace> to output <name|direction>' or "
"'move position mouse'";
Expand All @@ -27,6 +27,12 @@ struct cmd_results *cmd_move(int argc, char **argv) {
move_container(view, MOVE_UP);
} else if (strcasecmp(argv[0], "down") == 0) {
move_container(view, MOVE_DOWN);
} else if (strcasecmp(argv[0], "next") == 0) {
move_container(view, MOVE_NEXT);
} else if (strcasecmp(argv[0], "prev") == 0) {
move_container(view, MOVE_PREV);
} else if (strcasecmp(argv[0], "first") == 0) {
move_container(view, MOVE_FIRST);
} else if (strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) {
// "move container ...
if ((error = checkarg(argc, "move container/window", EXPECTED_AT_LEAST, 4))) {
Expand Down
Loading