diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..a1c73fe4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# For the full list of code style requirements, see CONTRIBUTING.md + +root = true + +[*] +charset = utf-8 +end_of_line = lf + +[*.{c,h,cmake,txt}] +indent_style = tab +indent_size = 4 + +[*.{xml,yml}] +indent_style = space +indent_size = 2 + +[config] +indent_style = space +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false diff --git a/include/focus.h b/include/focus.h index 10d5182b..4abd6080 100644 --- a/include/focus.h +++ b/include/focus.h @@ -21,6 +21,10 @@ swayc_t *get_focused_container(swayc_t *parent); swayc_t *get_focused_view(swayc_t *parent); swayc_t *get_focused_float(swayc_t *ws); +// a special-case function to get the focused view, regardless +// of whether it's tiled or floating +swayc_t *get_focused_view_include_floating(swayc_t *parent); + bool set_focused_container(swayc_t *container); bool set_focused_container_for(swayc_t *ancestor, swayc_t *container); diff --git a/include/resize.h b/include/resize.h index d49cc74a..0d382994 100644 --- a/include/resize.h +++ b/include/resize.h @@ -2,7 +2,13 @@ #define _SWAY_RESIZE_H #include -bool set_size_tiled(int amount, bool use_width); -bool resize_tiled(int amount, bool use_width); +enum resize_dim_types { + RESIZE_DIM_PX, + RESIZE_DIM_PPT, + RESIZE_DIM_DEFAULT, +}; + +bool set_size(int dimension, bool use_width); +bool resize(int dimension, bool use_width, enum resize_dim_types dim_type); #endif diff --git a/sway/commands.c b/sway/commands.c index 55f46f79..2248e1c7 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -83,6 +83,7 @@ static sway_cmd cmd_orientation; static sway_cmd cmd_output; static sway_cmd cmd_reload; static sway_cmd cmd_resize; +static sway_cmd cmd_resize_set; static sway_cmd cmd_scratchpad; static sway_cmd cmd_set; static sway_cmd cmd_smart_gaps; @@ -2000,36 +2001,112 @@ static struct cmd_results *cmd_resize(int argc, char **argv) { struct cmd_results *error = NULL; if (config->reading) return cmd_results_new(CMD_FAILURE, "resize", "Can't be used in config file."); if (!config->active) return cmd_results_new(CMD_FAILURE, "resize", "Can only be used when sway is running."); + + if (strcasecmp(argv[0], "set") == 0) { + return cmd_resize_set(argc - 1, &argv[1]); + } + if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { return error; } - int amount = (int)strtol(argv[argc - 1], NULL, 10); + int dim_arg = argc - 1; + + enum resize_dim_types dim_type = RESIZE_DIM_DEFAULT; + if (strcasecmp(argv[dim_arg], "ppt") == 0) { + dim_type = RESIZE_DIM_PPT; + dim_arg--; + } else if (strcasecmp(argv[dim_arg], "px") == 0) { + dim_type = RESIZE_DIM_PX; + dim_arg--; + } + + int amount = (int)strtol(argv[dim_arg], NULL, 10); if (errno == ERANGE || amount == 0) { errno = 0; - return cmd_results_new(CMD_INVALID, "resize", "Number is out of range."); + amount = 10; // this is the default resize dimension used by i3 for both px and ppt + sway_log(L_DEBUG, "Tried to get resize dimension out of '%s' but failed; setting dimension to default %d", + argv[dim_arg], amount); } - if (strcmp(argv[0], "shrink") == 0 || strcmp(argv[0], "grow") == 0) { - if (strcmp(argv[0], "shrink") == 0) { - amount *= -1; - } + bool use_width = false; + if (strcasecmp(argv[1], "width") == 0) { + use_width = true; + } else if (strcasecmp(argv[1], "height") != 0) { + return cmd_results_new(CMD_INVALID, "resize", + "Expected 'resize [] [px|ppt]'"); + } - if (strcmp(argv[1], "width") == 0) { - resize_tiled(amount, true); - } else if (strcmp(argv[1], "height") == 0) { - resize_tiled(amount, false); - } else { - return cmd_results_new(CMD_INVALID, "resize", - "Expected 'resize ' or 'resize '"); + if (strcasecmp(argv[0], "shrink") == 0) { + amount *= -1; + } else if (strcasecmp(argv[0], "grow") != 0) { + return cmd_results_new(CMD_INVALID, "resize", + "Expected 'resize [] [px|ppt]'"); + } + + resize(amount, use_width, dim_type); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +static struct cmd_results *cmd_resize_set(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "resize set", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (strcasecmp(argv[0], "width") == 0 || strcasecmp(argv[0], "height") == 0) { + // handle `reset set width 100 px height 100 px` syntax, also allows + // specifying only one dimension for a `resize set` + int cmd_num = 0; + int dim; + + while ((cmd_num + 1) < argc) { + dim = (int)strtol(argv[cmd_num + 1], NULL, 10); + if (errno == ERANGE || dim == 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [ [px]]'"); + } + + if (strcasecmp(argv[cmd_num], "width") == 0) { + set_size(dim, true); + } else if (strcasecmp(argv[cmd_num], "height") == 0) { + set_size(dim, false); + } else { + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [ [px]]'"); + } + + cmd_num += 2; + + if (cmd_num < argc && strcasecmp(argv[cmd_num], "px") == 0) { + // if this was `resize set width 400 px height 300 px`, disregard the `px` arg + cmd_num++; + } } - } else if (strcmp(argv[0], "width") == 0) { - set_size_tiled(amount, true); - } else if (strcmp(argv[0], "height") == 0) { - set_size_tiled(amount, false); } else { - return cmd_results_new(CMD_INVALID, "resize", - "Expected 'resize ' or 'resize '"); + // handle `reset set 100 px 100 px` syntax + int width = (int)strtol(argv[0], NULL, 10); + if (errno == ERANGE || width == 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [px]'"); + } + + int height_arg = 1; + if (strcasecmp(argv[1], "px") == 0) { + height_arg = 2; + } + + int height = (int)strtol(argv[height_arg], NULL, 10); + if (errno == ERANGE || height == 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "resize set", + "Expected 'resize set [px] [px]'"); + } + + set_size(width, true); + set_size(height, false); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/focus.c b/sway/focus.c index 2219ab4a..1d21ac35 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -243,3 +243,22 @@ swayc_t *get_focused_float(swayc_t *ws) { } return NULL; } + +swayc_t *get_focused_view_include_floating(swayc_t *parent) { + swayc_t *c = parent; + swayc_t *f = NULL; + + while (c && c->type != C_VIEW) { + if (c->type == C_WORKSPACE && c->focused == NULL) { + return ((f = get_focused_float(c))) ? f : c; + } + + c = c->focused; + } + + if (c == NULL) { + c = swayc_active_workspace_for(parent); + } + + return c; +} diff --git a/sway/resize.c b/sway/resize.c index 9411cfd8..18bb86bb 100644 --- a/sway/resize.c +++ b/sway/resize.c @@ -7,20 +7,52 @@ #include "handlers.h" #include "resize.h" -bool set_size_tiled(int amount, bool use_width) { - int desired; - swayc_t *focused = get_focused_view(swayc_active_workspace()); +static bool set_size_floating(int new_dimension, bool use_width) { + swayc_t *view = get_focused_float(swayc_active_workspace()); + if (view) { + if (use_width) { + int current_width = view->width; + view->desired_width = new_dimension; + floating_view_sane_size(view); - if (use_width) { - desired = amount - focused->width; - } else { - desired = amount - focused->height; + int new_x = view->x + (int)(((view->desired_width - current_width) / 2) * -1); + view->width = view->desired_width; + view->x = new_x; + + update_geometry(view); + } else { + int current_height = view->height; + view->desired_height = new_dimension; + floating_view_sane_size(view); + + int new_y = view->y + (int)(((view->desired_height - current_height) / 2) * -1); + view->height = view->desired_height; + view->y = new_y; + + update_geometry(view); + } + + return true; } - return resize_tiled(desired, use_width); + return false; } -bool resize_tiled(int amount, bool use_width) { +static bool resize_floating(int amount, bool use_width) { + swayc_t *view = get_focused_float(swayc_active_workspace()); + + if (view) { + if (use_width) { + return set_size_floating(view->width + amount, true); + } else { + return set_size_floating(view->height + amount, false); + } + } + + return false; +} + +static bool resize_tiled(int amount, bool use_width) { swayc_t *parent = get_focused_view(swayc_active_workspace()); swayc_t *focused = parent; swayc_t *sibling; @@ -242,3 +274,65 @@ bool resize_tiled(int amount, bool use_width) { } return true; } + +static bool set_size_tiled(int amount, bool use_width) { + int desired; + swayc_t *focused = get_focused_view(swayc_active_workspace()); + + if (use_width) { + desired = amount - focused->width; + } else { + desired = amount - focused->height; + } + + return resize_tiled(desired, use_width); +} + +bool set_size(int dimension, bool use_width) { + swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace()); + + if (focused) { + if (focused->is_floating) { + return set_size_floating(dimension, use_width); + } else { + return set_size_tiled(dimension, use_width); + } + } + + return false; +} + +bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { + swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace()); + + // translate "10 ppt" (10%) to appropriate # of pixels in case we need it + float ppt_dim = (float)dimension / 100; + + if (use_width) { + ppt_dim = focused->width * ppt_dim; + } else { + ppt_dim = focused->height * ppt_dim; + } + + if (focused) { + if (focused->is_floating) { + // floating view resize dimensions should default to px, so only + // use ppt if specified + if (dim_type == RESIZE_DIM_PPT) { + dimension = (int)ppt_dim; + } + + return resize_floating(dimension, use_width); + } else { + // tiled view resize dimensions should default to ppt, so only use + // px if specified + if (dim_type != RESIZE_DIM_PX) { + dimension = (int)ppt_dim; + } + + return resize_tiled(dimension, use_width); + } + } + + return false; +} diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 76d09edb..18b693f8 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -94,13 +94,24 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**( **reload**:: Reloads the sway config file without restarting sway. -**resize** :: - Resizes the currently focused container or view by _amount_. _amount_ can be - specified as "n px" or "n ppt" or "n px or n ppt". - -**resize** :: - Sets the _width_ or _height_ of the currently focused container to _amount_. - _amount_ can be specified as "n px" or "n ppt" or "n px or n ppt". +**resize** [] [px|ppt]:: + Resizes the currently focused container or view by _amount_. _amount_ is + optional: the default value is 10 (either px or ppt depending on the view + type). The [px|ppt] parameter is optional. _px_ specifies that _amount_ refers + to pixels; _ppt_ specifies that _amount_ refers to percentage points of the + current dimension. Floating views use px dimensions by default (but can use + ppt if specified); tiled views use ppt dimensions by default (but can use px + if specified). + +**resize set** [px] [px]:: + Sets the width and height of the currently focused container to _width_ pixels + and _height_ pixels. The [px] parameters are optional and have no effect. This + command only accepts pixel dimensions. + +**resize set** [px] [ [px]]:: + Sets the _width_ and/or _height_ of the currently focused container to + _amount_. The [px] parameters are optional and have no effect. This command + only accepts pixel dimensions. **split** :: Splits the current container, vertically or horizontally. If toggled then the @@ -200,7 +211,7 @@ The default colors are: **floating_maximum_size** x :: Specifies the maximum dimensions of floating windows. Uses the container dimensions as default. - -1 x -1 will remove any restriction on dimentions. + -1 x -1 will remove any restriction on dimensions. 0 x 0 has the same behavior as not setting any value. If in conflict this option has precedence over floating_minimum_size. @@ -214,7 +225,7 @@ The default colors are: windows, and right click to resize them. Unlike i3, this modifier may also be used to resize and move windows that are tiled. With the _inverse_ mode enabled, left click is used for resizing and right click for dragging. The - mode paramenter is optional and defaults to _normal_ if it isn't defined. + mode parameter is optional and defaults to _normal_ if it isn't defined. **floating_scroll** [command]:: Sets a command to be executed when the mouse wheel is scrolled in the @@ -263,7 +274,7 @@ The default colors are: than one child container. **mode** :: - Switches to the given mode_name. the default mode is simply _default_. To + Switches to the given mode_name. The default mode is simply _default_. To create a new mode in config append _{_ to this command, the following lines will be keybinds for that mode, and _}_ on its own line to close the block.