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

Conversation

willakat
Copy link
Contributor

@willakat willakat commented Jan 1, 2017

Hi all,

I've been wanting to try out a Wayland setup and as an Awesome (and ex-i3) user, I gave Sway a spin. I quickly missed the (in my opinion) easy way with which Awesome just sorts out all the nitty-gritty of laying out your windows for you with a few simple pre-defined layouts that usually cover my limited needs. Anyway, long story short, I added the feature to Sway and find it quite pleasant to use. I took the opportunity to refactor some of the layout code. I'll probably add an includable config file to provide a setup that roughly matches Awesome's.

Enjoy!

@@ -75,4 +75,7 @@ void swayc_log(log_importance_t verbosity, swayc_t *cont, const char* format, ..
*/
enum swayc_layouts default_layout(swayc_t *output);

inline bool is_auto_layout(enum swayc_layouts layout) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Needs to be static inline (GNU semantics).

Copy link
Contributor

Choose a reason for hiding this comment

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

Needs to move out of the header and into a file (no code in headers, just don't make it inline)

@@ -10,6 +11,10 @@ irc.freenode.net).

[More screenshots](https://github.com/SirCmpwn/sway/wiki/Screenshots-of-Sway)

This fork attempts to add
Copy link
Contributor

Choose a reason for hiding this comment

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

This fork

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah just revert all of the readme changes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

EXPECTED_EQUAL_TO, 2))) {
return error;
}
int inc = (int) strtol(argv[1], NULL, 10);
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 add error handling for invalid ints here?

char *end;
int inc = (int)strtol(argv[1], &end, 10);
if (*end) {
    // error
}

Also note no space between (int) and strtol

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

enum swayc_layouts layout;
if (strcasecmp(argv[1], "next") == 0) {
if (is_auto_layout(parent->layout) && parent->layout < L_AUTO_LAST) {
layout = parent->layout + 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 add another function somewhere that uses a switch case or something, given a layout, to find the next auto layout? I'd rather not rely on the order of and value of the enum values.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nevermind, let's not

"Must be one of <prev|next>.");
}
swayc_change_layout(parent, layout);
} else if (strcasecmp(argv[0], "promote") == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would prefer this as move promote

Copy link
Contributor Author

Choose a reason for hiding this comment

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

renamed to "move first" (I actually had this change pending ... so I completely agree!)

*/
static int group_start_index(swayc_t *container, int index) {
if ((index < 0) || (! is_auto_layout(container->layout)) ||
((uint_fast32_t) index < container->nb_master)) {
Copy link
Contributor

@ddevault ddevault Jan 1, 2017

Choose a reason for hiding this comment

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

Weird indent here, also weird extra parenthesis

if (index < 0 || !is_auto_layout(container->layout)
	|| (size_t)index < container->nb_master)) {
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

trying out "spacemacs", haven't yet looked into having it format using tabs only. For now fixed it up manually.

return 0;
} else {
uint_fast32_t grp_sz = slave_count(container) / container->nb_slave_groups;
uint_fast32_t remainder = slave_count(container) % container->nb_slave_groups;
Copy link
Contributor

Choose a reason for hiding this comment

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

Use size_t instead of uint_fast32_t

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

return container->children->length;
} else {
int nxt_idx;
if ((uint_fast32_t)index < container->nb_master) {
Copy link
Contributor

Choose a reason for hiding this comment

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

That goes for everywhere, s/uint_fast32_t/size_t/g

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

* return the index of the Group containing <index>th child of <container>.
* The index is the order of the group along the container's major axis (starting at 0).
*/
static uint_fast32_t group_index(swayc_t *container, int index) {
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 prefix all of these auto related functions with auto_?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

parent = container->parent;
if ((parent->children && parent->children->length > 1) &&
(is_auto_layout(parent->layout) || (use_width ? parent->layout == L_HORIZ :
parent->layout == L_VERT))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

More weird indentation, use tabs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

return true;
// Recursive resize does not handle positions, let arrange_windows
// take care of that.
arrange_windows(swayc_active_workspace(), -1, -1);
Copy link
Contributor

Choose a reason for hiding this comment

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

This whole function has now become pretty complicated. Can you split it up into several?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

on todo list...

// if layout change modifies the auto layout's major axis, swap width and height
// to preserve current ratios.
if (is_auto_layout(layout) && is_auto_layout(container->layout)) {
enum swayc_layouts prev_major = (container->layout == L_AUTO_LEFT ||
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary parens

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -256,7 +260,7 @@ void move_container(swayc_t *container, enum movement_direction dir) {
layout = L_VERT;
} else if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
layout = L_HORIZ;
} else {
} else if (! (dir == MOVE_NEXT || dir == MOVE_PREV)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

No space after !

@@ -279,19 +283,53 @@ void move_container(swayc_t *container, enum movement_direction dir) {
sway_log(L_DEBUG, "container:%p, parent:%p, child %p,",
container,parent,child);
if (parent->layout == layout
|| layout == L_NONE /* accept any layout for next/prev direction */
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't accept any layout, right? It'll accept no layout, which isn't a thing that happens in practice (things like views have no layout)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

"layout == L_NONE" was to broad, replaced by "layout == L_NONE && parent->type == C_CONTAINER". This is intended to accept the MOVE_PREV/MOVE_NEXT directions regardless of the actual container layout.

static void apply_auto_layout(swayc_t *container, const double x, const double y,
const double width, const double height,
enum swayc_layouts group_layout,
bool master_first);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please make the indentation on these consistent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

attempted to make things more consistent (used tabs exclusively)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

grepped through the code for mixed tab/space indents and removed the ones I had put in.


switch(group_layout) {
default:
sway_log(L_ERROR, "Unknown layout type (%d) used in %s()",
Copy link
Contributor

Choose a reason for hiding this comment

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

Make this L_DEBUG. It's programmer error, right? Not user error? And is a recoverable condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

// height and width of next group to be laid out.
const double *group_h, *group_w;

switch(group_layout) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Space after switch

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

}

/* update position for next group */
pos += group_dim;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this function be split up a bit?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

definitely. on todo list.

@ddevault
Copy link
Contributor

ddevault commented Jan 1, 2017

Overall these changes look good. I like the refactored layout code. You should do a pass on this with the style guide in hand.

There's a lot of complexity I would like to see simplified if you can spare the time to go through everything and see if you can find ways to simplify it (optional).

These are some huge changes, so I'm not going to merge them right away. I'm going to start running them locally for a few days and see if they break any existing functionality. Would appreciate it if any Awesome users could try this and verify that it behaves appropriately as well.

Could you make a wiki page explaining how to configure sway to behave like Awesome?

willakat and others added 10 commits January 7, 2017 20:26
Achieved by introducing auto_group_bounds function that produces
the start/end indexes of a group inside an auto layot container.
- "layout auto_left|auto_xxx" are now "layout auto xxx"
- "layout incmaster <n>" is now "layout auto master [set|inc] <n>"
- "layout incncol <n>" is now "layout auto ncol [set|inc] <n>"
@willakat
Copy link
Contributor Author

willakat commented Jan 8, 2017

I've been playing around with swaygrab but haven't encountered any SEGVs. I'm stumped as to what caused the parent pointer to get mangled. I could poke around the core file (if you kept it) and it would be interesting if this is a/ reproducible and b/ what sequence of actions preceded the crash.

As for the rest of the comments on the patch, I think I'm only missing the simplification bit (a few have been made, but nothing significant).

Regarding reseting nb_master/nb_slave_groups when switching layouts, I would argue against since it's very convenient to switch back and forth to, say a tabbed layout, to use all the available space, and recover the child layout as it was prior to the switch.

I also still need to push a sample Awesome-style config.

@ddevault
Copy link
Contributor

ddevault commented Jan 8, 2017

Alright, I'll retest and rereview this when I have some time (probably today or tomorrow). I'll try to get some more info about the swaygrab issue as well (fwiw the failure was when trying to capture video).

@thejan2009
Copy link
Contributor

I'm not sure how Awesome does it, but you might have to look into container movements. The following was achieved by moving a container "up" into the bigger area and then moving it back "down". When additional views are invoked, their width is different from every other container. I suppose they should be equally wide?
2017-01-08-190758_swaygrab


**layout** auto <mode>::
Sets layout to one of the auto modes, i.e. one of _left_, right_, _top_,
or _bot_.
Copy link
Contributor

Choose a reason for hiding this comment

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

Just spell out "bottom" here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -360,7 +381,7 @@ The default colors are:
switch to workspace 2, then invoke the "workspace 2" command again, you
will be returned to workspace 1. Defaults to _no_.

**workspace_layout** <default|stacking|tabbed>::
**workspace_layout** <default|stacking|tabbed|auto_left|auto_right|auto_top|auto_bottom>::
Copy link
Contributor

Choose a reason for hiding this comment

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

workspace_layout auto left, not workspace_layout auto_left

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@Airblader
Copy link

(Random side comment: instead of making i3 jump through hoops for KDE integration KDE should just behave better to not require special casing. Specifications exist for good reasons. I'm not sure why people don't consider this and then blame i3 for it.)

@willakat
Copy link
Contributor Author

Regarding thejan2009's comment, the most recent batch of commits should address the issue. When inserting/removing a child in a container, the auto-layout will attempt to preserve sizes along the "major" axis. Along the "minor" axis, sizes are preserved for children that aren't promoted/demoted to a different group. In the latter case their size will match the spot vacated in the arrival group.

}
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?

@ddevault
Copy link
Contributor

I would also make your sample awesome config more awesome like instead of trying to keep sway's default keybindings intact. Your config doesn't actually even include sway's default keybindings anyway, the defaults are via your config (rather than being hardcoded into sway). Fix that in a seperate pull request if you like.

@ddevault ddevault merged commit 81102e8 into swaywm:master Jan 14, 2017
@ddevault
Copy link
Contributor

Thanks for all the hard work!

@willakat
Copy link
Contributor Author

You're welcome! Many thanks for yours on Sway and to the other contributors.

@ddevault ddevault mentioned this pull request Feb 21, 2017
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants