Merge pull request #2726 from RyanDwyer/overhaul-gaps

Make gaps implementation consistent with i3-gaps
master
Drew DeVault 6 years ago committed by GitHub
commit f1dbdce0b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -174,6 +174,8 @@ struct output_config {
struct workspace_config {
char *workspace;
char *output;
int gaps_inner;
int gaps_outer;
};
struct bar_config {

@ -94,9 +94,6 @@ struct sway_container {
// The gaps currently applied to the container.
double current_gaps;
bool has_gaps;
double gaps_inner;
double gaps_outer;
struct sway_workspace *workspace; // NULL when hidden in the scratchpad
struct sway_container *parent; // NULL if container in root of workspace

@ -32,10 +32,9 @@ struct sway_workspace {
enum sway_container_layout layout;
enum sway_container_layout prev_split_layout;
double current_gaps;
bool has_gaps;
double gaps_inner;
double gaps_outer;
int current_gaps;
int gaps_inner;
int gaps_outer;
struct sway_output *output; // NULL if no outputs are connected
list_t *floating; // struct sway_container

@ -1,4 +1,5 @@
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/tree/arrange.h"
@ -13,172 +14,173 @@ enum gaps_op {
GAPS_OP_SUBTRACT
};
enum gaps_scope {
GAPS_SCOPE_ALL,
GAPS_SCOPE_WORKSPACE,
GAPS_SCOPE_CURRENT
struct gaps_data {
bool inner;
enum gaps_op operation;
int amount;
};
struct cmd_results *cmd_gaps(int argc, char **argv) {
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1);
if (error) {
// gaps edge_gaps on|off|toggle
static struct cmd_results *gaps_edge_gaps(int argc, char **argv) {
struct cmd_results *error;
if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) {
return error;
}
if (strcmp(argv[0], "edge_gaps") == 0) {
if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) {
return error;
}
if (strcmp(argv[1], "on") == 0) {
config->edge_gaps = true;
} else if (strcmp(argv[1], "off") == 0) {
config->edge_gaps = false;
} else if (strcmp(argv[1], "toggle") == 0) {
if (!config->active) {
return cmd_results_new(CMD_INVALID, "gaps",
"Cannot toggle gaps while not running.");
}
config->edge_gaps = !config->edge_gaps;
} else {
if (strcmp(argv[1], "on") == 0) {
config->edge_gaps = true;
} else if (strcmp(argv[1], "off") == 0) {
config->edge_gaps = false;
} else if (strcmp(argv[1], "toggle") == 0) {
if (!config->active) {
return cmd_results_new(CMD_INVALID, "gaps",
"gaps edge_gaps on|off|toggle");
"Cannot toggle gaps while not running.");
}
arrange_root();
config->edge_gaps = !config->edge_gaps;
} else {
int amount_idx = 0; // the current index in argv
enum gaps_op op = GAPS_OP_SET;
enum gaps_scope scope = GAPS_SCOPE_ALL;
bool inner = true;
if (strcmp(argv[0], "inner") == 0) {
amount_idx++;
inner = true;
} else if (strcmp(argv[0], "outer") == 0) {
amount_idx++;
inner = false;
}
return cmd_results_new(CMD_INVALID, "gaps",
"gaps edge_gaps on|off|toggle");
}
arrange_root();
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
// If one of the long variants of the gaps command is used
// (which starts with inner|outer) check the number of args
if (amount_idx > 0) { // if we've seen inner|outer
if (argc > 2) { // check the longest variant
error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
if (error) {
return error;
}
} else { // check the next longest format
error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
if (error) {
return error;
}
}
} else {
error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 1);
if (error) {
return error;
}
}
// gaps inner|outer <px>
static struct cmd_results *gaps_set_defaults(int argc, char **argv) {
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
if (error) {
return error;
}
if (argc == 4) {
// Long format: all|workspace|current.
if (strcmp(argv[amount_idx], "all") == 0) {
amount_idx++;
scope = GAPS_SCOPE_ALL;
} else if (strcmp(argv[amount_idx], "workspace") == 0) {
amount_idx++;
scope = GAPS_SCOPE_WORKSPACE;
} else if (strcmp(argv[amount_idx], "current") == 0) {
amount_idx++;
scope = GAPS_SCOPE_CURRENT;
}
// Long format: set|plus|minus
if (strcmp(argv[amount_idx], "set") == 0) {
amount_idx++;
op = GAPS_OP_SET;
} else if (strcmp(argv[amount_idx], "plus") == 0) {
amount_idx++;
op = GAPS_OP_ADD;
} else if (strcmp(argv[amount_idx], "minus") == 0) {
amount_idx++;
op = GAPS_OP_SUBTRACT;
}
}
bool inner;
if (strcasecmp(argv[0], "inner") == 0) {
inner = true;
} else if (strcasecmp(argv[0], "outer") == 0) {
inner = false;
} else {
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer <px>'");
}
char *end;
double val = strtod(argv[amount_idx], &end);
if (strlen(end) && val == 0.0) { // invalid <amount>
// guess which variant of the command was attempted
if (argc == 1) {
return cmd_results_new(CMD_INVALID, "gaps", "gaps <amount>");
}
if (argc == 2) {
return cmd_results_new(CMD_INVALID, "gaps",
"gaps inner|outer <amount>");
}
return cmd_results_new(CMD_INVALID, "gaps",
"gaps inner|outer all|workspace|current set|plus|minus <amount>");
}
char *end;
int amount = strtol(argv[1], &end, 10);
if (strlen(end) && strcasecmp(end, "px") != 0) {
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer <px>'");
}
if (amount < 0) {
amount = 0;
}
if (amount_idx == 0) { // gaps <amount>
config->gaps_inner = val;
config->gaps_outer = val;
arrange_root();
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
// Other variants. The middle-length variant (gaps inner|outer <amount>)
// just defaults the scope to "all" and defaults the op to "set".
double total;
switch (op) {
case GAPS_OP_SUBTRACT: {
total = (inner ? config->gaps_inner : config->gaps_outer) - val;
if (total < 0) {
total = 0;
}
break;
}
case GAPS_OP_ADD: {
total = (inner ? config->gaps_inner : config->gaps_outer) + val;
break;
}
case GAPS_OP_SET: {
total = val;
break;
}
}
if (inner) {
config->gaps_inner = amount;
} else {
config->gaps_outer = amount;
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
if (scope == GAPS_SCOPE_ALL) {
if (inner) {
config->gaps_inner = total;
} else {
config->gaps_outer = total;
}
arrange_root();
} else {
if (scope == GAPS_SCOPE_WORKSPACE) {
struct sway_workspace *ws = config->handler_context.workspace;
ws->has_gaps = true;
if (inner) {
ws->gaps_inner = total;
} else {
ws->gaps_outer = total;
}
arrange_workspace(ws);
} else {
struct sway_container *c = config->handler_context.container;
c->has_gaps = true;
if (inner) {
c->gaps_inner = total;
} else {
c->gaps_outer = total;
}
arrange_workspace(c->workspace);
}
}
static void configure_gaps(struct sway_workspace *ws, void *_data) {
struct gaps_data *data = _data;
int *prop = data->inner ? &ws->gaps_inner : &ws->gaps_outer;
switch (data->operation) {
case GAPS_OP_SET:
*prop = data->amount;
break;
case GAPS_OP_ADD:
*prop += data->amount;
break;
case GAPS_OP_SUBTRACT:
*prop -= data->amount;
break;
}
if (*prop < 0) {
*prop = 0;
}
arrange_workspace(ws);
}
// gaps inner|outer current|all set|plus|minus <px>
static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
if (error) {
return error;
}
struct gaps_data data;
if (strcasecmp(argv[0], "inner") == 0) {
data.inner = true;
} else if (strcasecmp(argv[0], "outer") == 0) {
data.inner = false;
} else {
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
}
bool all;
if (strcasecmp(argv[1], "current") == 0) {
all = false;
} else if (strcasecmp(argv[1], "all") == 0) {
all = true;
} else {
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
}
if (strcasecmp(argv[2], "set") == 0) {
data.operation = GAPS_OP_SET;
} else if (strcasecmp(argv[2], "plus") == 0) {
data.operation = GAPS_OP_ADD;
} else if (strcasecmp(argv[2], "minus") == 0) {
data.operation = GAPS_OP_SUBTRACT;
} else {
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
}
char *end;
data.amount = strtol(argv[3], &end, 10);
if (strlen(end) && strcasecmp(end, "px") != 0) {
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
}
if (all) {
root_for_each_workspace(configure_gaps, &data);
} else {
configure_gaps(config->handler_context.workspace, &data);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
// gaps edge_gaps on|off|toggle
// gaps inner|outer <px> - sets defaults for workspaces
// gaps inner|outer current|all set|plus|minus <px> - runtime only
struct cmd_results *cmd_gaps(int argc, char **argv) {
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2);
if (error) {
return error;
}
if (strcmp(argv[0], "edge_gaps") == 0) {
return gaps_edge_gaps(argc, argv);
}
if (argc == 2) {
return gaps_set_defaults(argc, argv);
}
if (argc == 4) {
if (config->active) {
return gaps_set_runtime(argc, argv);
} else {
return cmd_results_new(CMD_INVALID, "gaps",
"This syntax can only be used when sway is running");
}
}
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer <px>' or "
"'gaps inner|outer current|all set|plus|minus <px>'");
}

@ -138,15 +138,14 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
}
container->layout = new_layout;
container_update_representation(container);
arrange_container(container);
} else {
if (old_layout != L_TABBED && old_layout != L_STACKED) {
workspace->prev_split_layout = old_layout;
}
workspace->layout = new_layout;
workspace_update_representation(workspace);
arrange_workspace(workspace);
}
arrange_workspace(workspace);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);

@ -20,6 +20,8 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
return NULL;
}
wsc->workspace = strdup(ws_name);
wsc->gaps_inner = -1;
wsc->gaps_outer = -1;
list_add(config->workspace_configs, wsc);
return wsc;
}
@ -37,6 +39,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
int output_location = -1;
int gaps_location = -1;
for (int i = 0; i < argc; ++i) {
if (strcasecmp(argv[i], "output") == 0) {
@ -44,6 +47,12 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
break;
}
}
for (int i = 0; i < argc; ++i) {
if (strcasecmp(argv[i], "gaps") == 0) {
gaps_location = i;
break;
}
}
if (output_location >= 0) {
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) {
return error;
@ -57,6 +66,35 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
free(wsc->output);
wsc->output = strdup(argv[output_location + 1]);
} else if (gaps_location >= 0) {
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, gaps_location + 3))) {
return error;
}
char *ws_name = join_args(argv, argc - 3);
struct workspace_config *wsc = workspace_config_find_or_create(ws_name);
free(ws_name);
if (!wsc) {
return cmd_results_new(CMD_FAILURE, "workspace gaps",
"Unable to allocate workspace output");
}
int *prop = NULL;
if (strcasecmp(argv[gaps_location + 1], "inner") == 0) {
prop = &wsc->gaps_inner;
} else if (strcasecmp(argv[gaps_location + 1], "outer") == 0) {
prop = &wsc->gaps_outer;
} else {
return cmd_results_new(CMD_FAILURE, "workspace gaps",
"Expected 'workspace <ws> gaps inner|outer <px>'");
}
char *end;
int val = strtol(argv[gaps_location + 2], &end, 10);
if (strlen(end)) {
free(end);
return cmd_results_new(CMD_FAILURE, "workspace gaps",
"Expected 'workspace <ws> gaps inner|outer <px>'");
}
*prop = val >= 0 ? val : 0;
} else {
if (config->reading || !config->active) {
return cmd_results_new(CMD_DEFER, "workspace", NULL);

@ -419,19 +419,17 @@ The default colors are:
inner gap is nonzero. When _off_, gaps will only be added between views.
_toggle_ cannot be used in the configuration file.
*gaps* <amount>
Sets _amount_ pixels of gap between windows and around each workspace.
*gaps* inner|outer <amount>
Sets default _amount_ pixels of _inner_ or _outer_ gap, where the former
affects spacing between views and the latter affects the space around each
workspace.
Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
affects spacing around each view and outer affects the spacing around each
workspace. Outer gaps are in addition to inner gaps.
This affects new workspaces only, and is used when the workspace doesn't
have its own gaps settings (see: workspace <ws> gaps inner|outer <amount>).
*gaps* inner|outer all|workspace|current set|plus|minus <amount>
Changes the gaps for the _inner_ or _outer_ gap. _all_ changes the gaps for
all views or workspace, _workspace_ changes gaps for all views in current
workspace (or current workspace), and _current_ changes gaps for the current
view or workspace.
*gaps* inner|outer all|current set|plus|minus <amount>
Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the
_current_ workspace.
*hide\_edge\_borders* none|vertical|horizontal|both|smart
Hides window borders adjacent to the screen edges. Default is _none_.
@ -580,6 +578,10 @@ match any output by using the output name "\*".
*workspace* back_and_forth
Switches to the previously focused workspace.
*workspace* <name> gaps inner|outer <amount>
Specifies that workspace _name_ should have the given gaps settings when it
is created.
*workspace* <name> output <output>
Specifies that workspace _name_ should be shown on the specified _output_.

@ -1029,7 +1029,7 @@ void container_add_gaps(struct sway_container *c) {
struct sway_workspace *ws = c->workspace;
c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner;
c->current_gaps = ws->gaps_inner;
c->x += c->current_gaps;
c->y += c->current_gaps;
c->width -= 2 * c->current_gaps;

@ -68,6 +68,20 @@ struct sway_workspace *workspace_create(struct sway_output *output,
ws->output_priority = create_list();
workspace_output_add_priority(ws, output);
ws->gaps_outer = config->gaps_outer;
ws->gaps_inner = config->gaps_inner;
if (name) {
struct workspace_config *wsc = workspace_find_config(name);
if (wsc) {
if (wsc->gaps_outer != -1) {
ws->gaps_outer = wsc->gaps_outer;
}
if (wsc->gaps_inner != -1) {
ws->gaps_inner = wsc->gaps_inner;
}
}
}
output_add_workspace(output, ws);
output_sort_workspaces(output);
@ -632,13 +646,13 @@ void workspace_add_gaps(struct sway_workspace *ws) {
return;
}
ws->current_gaps = ws->has_gaps ? ws->gaps_outer : config->gaps_outer;
ws->current_gaps = ws->gaps_outer;
if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
// We have to add inner gaps for this, because children of tabbed and
// stacked containers don't apply their own gaps - they assume the
// tabbed/stacked container is using gaps.
ws->current_gaps += ws->has_gaps ? ws->gaps_inner : config->gaps_inner;
ws->current_gaps += ws->gaps_inner;
}
ws->x += ws->current_gaps;

Loading…
Cancel
Save