Merge pull request #2726 from RyanDwyer/overhaul-gaps

Make gaps implementation consistent with i3-gaps
This commit is contained in:
Drew DeVault 2018-09-30 13:47:35 +02:00 committed by GitHub
commit f1dbdce0b2
Failed to generate hash of commit
9 changed files with 234 additions and 181 deletions

View file

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

View file

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

View file

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

View file

@ -1,4 +1,5 @@
#include <string.h> #include <string.h>
#include <strings.h>
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/tree/arrange.h" #include "sway/tree/arrange.h"
@ -13,172 +14,173 @@ enum gaps_op {
GAPS_OP_SUBTRACT GAPS_OP_SUBTRACT
}; };
enum gaps_scope { struct gaps_data {
GAPS_SCOPE_ALL, bool inner;
GAPS_SCOPE_WORKSPACE, enum gaps_op operation;
GAPS_SCOPE_CURRENT int amount;
}; };
// 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[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 {
return cmd_results_new(CMD_INVALID, "gaps",
"gaps edge_gaps on|off|toggle");
}
arrange_root();
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
// 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;
}
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;
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 (inner) {
config->gaps_inner = amount;
} else {
config->gaps_outer = amount;
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
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 *cmd_gaps(int argc, char **argv) {
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1); struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2);
if (error) { if (error) {
return error; return error;
} }
if (strcmp(argv[0], "edge_gaps") == 0) { if (strcmp(argv[0], "edge_gaps") == 0) {
if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) { return gaps_edge_gaps(argc, argv);
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 {
return cmd_results_new(CMD_INVALID, "gaps",
"gaps edge_gaps on|off|toggle");
}
arrange_root();
} 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;
}
// 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;
}
}
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;
}
}
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>");
}
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 (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);
}
}
} }
return cmd_results_new(CMD_SUCCESS, NULL, NULL); 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>'");
} }

View file

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

View file

@ -20,6 +20,8 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
return NULL; return NULL;
} }
wsc->workspace = strdup(ws_name); wsc->workspace = strdup(ws_name);
wsc->gaps_inner = -1;
wsc->gaps_outer = -1;
list_add(config->workspace_configs, wsc); list_add(config->workspace_configs, wsc);
return wsc; return wsc;
} }
@ -37,6 +39,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
} }
int output_location = -1; int output_location = -1;
int gaps_location = -1;
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
if (strcasecmp(argv[i], "output") == 0) { if (strcasecmp(argv[i], "output") == 0) {
@ -44,6 +47,12 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
break; break;
} }
} }
for (int i = 0; i < argc; ++i) {
if (strcasecmp(argv[i], "gaps") == 0) {
gaps_location = i;
break;
}
}
if (output_location >= 0) { if (output_location >= 0) {
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) { if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) {
return error; return error;
@ -57,6 +66,35 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
} }
free(wsc->output); free(wsc->output);
wsc->output = strdup(argv[output_location + 1]); 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 { } else {
if (config->reading || !config->active) { if (config->reading || !config->active) {
return cmd_results_new(CMD_DEFER, "workspace", NULL); return cmd_results_new(CMD_DEFER, "workspace", NULL);

View file

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

View file

@ -1029,7 +1029,7 @@ void container_add_gaps(struct sway_container *c) {
struct sway_workspace *ws = c->workspace; 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->x += c->current_gaps;
c->y += c->current_gaps; c->y += c->current_gaps;
c->width -= 2 * c->current_gaps; c->width -= 2 * c->current_gaps;

View file

@ -68,6 +68,20 @@ struct sway_workspace *workspace_create(struct sway_output *output,
ws->output_priority = create_list(); ws->output_priority = create_list();
workspace_output_add_priority(ws, output); 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_add_workspace(output, ws);
output_sort_workspaces(output); output_sort_workspaces(output);
@ -632,13 +646,13 @@ void workspace_add_gaps(struct sway_workspace *ws) {
return; 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) { if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
// We have to add inner gaps for this, because children of tabbed and // We have to add inner gaps for this, because children of tabbed and
// stacked containers don't apply their own gaps - they assume the // stacked containers don't apply their own gaps - they assume the
// tabbed/stacked container is using gaps. // 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; ws->x += ws->current_gaps;