Implement per side and per direction outer gaps
This introduces the following command extensions from `i3-gaps`: * `gaps horizontal|vertical|top|right|bottom|left <amount>` * `gaps horizontal|vertical|top|right|bottom|left all|current set|plus|minus <amount>` * `workspace <ws> gaps horizontal|vertical|top|right|bottom|left <amount>` `inner` and `outer` are also still available as options for all three of the above commands. `outer` now acts as a shorthand to set/alter all sides. Additionally, this fixes two bugs with the prevention of invalid gap configurations for workspace configs: 1. If outer gaps were not set and inner gaps were, the outer gaps would be snapped to the negation of the inner gaps due to `INT_MIN` being less than the negation. This took precedence over the default outer gaps. 2. Similarly, if inner gaps were not set and outer gaps were, inner gaps would be set to zero, which would take precedence over the default inner gaps. Fixing both of the above items also requires checking the gaps again when creating a workspace since the default outer gaps can be smaller than the negation of the workspace specific inner gaps.
This commit is contained in:
parent
4a21981855
commit
9e8aa39530
|
@ -167,6 +167,16 @@ struct output_config {
|
||||||
enum config_dpms dpms_state;
|
enum config_dpms dpms_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores size of gaps for each side
|
||||||
|
*/
|
||||||
|
struct side_gaps {
|
||||||
|
int top;
|
||||||
|
int right;
|
||||||
|
int bottom;
|
||||||
|
int left;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores configuration for a workspace, regardless of whether the workspace
|
* Stores configuration for a workspace, regardless of whether the workspace
|
||||||
* exists.
|
* exists.
|
||||||
|
@ -175,7 +185,7 @@ struct workspace_config {
|
||||||
char *workspace;
|
char *workspace;
|
||||||
char *output;
|
char *output;
|
||||||
int gaps_inner;
|
int gaps_inner;
|
||||||
int gaps_outer;
|
struct side_gaps gaps_outer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bar_config {
|
struct bar_config {
|
||||||
|
@ -398,7 +408,7 @@ struct sway_config {
|
||||||
|
|
||||||
bool smart_gaps;
|
bool smart_gaps;
|
||||||
int gaps_inner;
|
int gaps_inner;
|
||||||
int gaps_outer;
|
struct side_gaps gaps_outer;
|
||||||
|
|
||||||
list_t *config_chain;
|
list_t *config_chain;
|
||||||
const char *current_config_path;
|
const char *current_config_path;
|
||||||
|
|
|
@ -32,9 +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;
|
||||||
|
|
||||||
int current_gaps;
|
struct side_gaps current_gaps;
|
||||||
int gaps_inner;
|
int gaps_inner;
|
||||||
int gaps_outer;
|
struct side_gaps 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
|
||||||
|
|
|
@ -16,73 +16,128 @@ enum gaps_op {
|
||||||
|
|
||||||
struct gaps_data {
|
struct gaps_data {
|
||||||
bool inner;
|
bool inner;
|
||||||
|
struct {
|
||||||
|
bool top;
|
||||||
|
bool right;
|
||||||
|
bool bottom;
|
||||||
|
bool left;
|
||||||
|
} outer;
|
||||||
enum gaps_op operation;
|
enum gaps_op operation;
|
||||||
int amount;
|
int amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
// gaps inner|outer <px>
|
// Prevent negative outer gaps from moving windows out of the workspace.
|
||||||
|
static void prevent_invalid_outer_gaps(void) {
|
||||||
|
if (config->gaps_outer.top < -config->gaps_inner) {
|
||||||
|
config->gaps_outer.top = -config->gaps_inner;
|
||||||
|
}
|
||||||
|
if (config->gaps_outer.right < -config->gaps_inner) {
|
||||||
|
config->gaps_outer.right = -config->gaps_inner;
|
||||||
|
}
|
||||||
|
if (config->gaps_outer.bottom < -config->gaps_inner) {
|
||||||
|
config->gaps_outer.bottom = -config->gaps_inner;
|
||||||
|
}
|
||||||
|
if (config->gaps_outer.left < -config->gaps_inner) {
|
||||||
|
config->gaps_outer.left = -config->gaps_inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gaps inner|outer|horizontal|vertical|top|right|bottom|left <px>
|
||||||
|
static const char *expected_defaults =
|
||||||
|
"'gaps inner|outer|horizontal|vertical|top|right|bottom|left <px>'";
|
||||||
static struct cmd_results *gaps_set_defaults(int argc, char **argv) {
|
static struct cmd_results *gaps_set_defaults(int argc, char **argv) {
|
||||||
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
|
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
|
||||||
if (error) {
|
if (error) {
|
||||||
return 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;
|
char *end;
|
||||||
int amount = strtol(argv[1], &end, 10);
|
int amount = strtol(argv[1], &end, 10);
|
||||||
if (strlen(end) && strcasecmp(end, "px") != 0) {
|
if (strlen(end) && strcasecmp(end, "px") != 0) {
|
||||||
return cmd_results_new(CMD_INVALID, "gaps",
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
"Expected 'gaps inner|outer <px>'");
|
"Expected %s", expected_defaults);
|
||||||
}
|
}
|
||||||
if (inner) {
|
|
||||||
|
bool valid = false;
|
||||||
|
if (!strcasecmp(argv[0], "inner")) {
|
||||||
|
valid = true;
|
||||||
config->gaps_inner = (amount >= 0) ? amount : 0;
|
config->gaps_inner = (amount >= 0) ? amount : 0;
|
||||||
} else {
|
} else {
|
||||||
config->gaps_outer = amount;
|
if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "vertical")
|
||||||
}
|
|| !strcasecmp(argv[0], "top")) {
|
||||||
|
valid = true;
|
||||||
// Prevent negative outer gaps from moving windows out of the workspace.
|
config->gaps_outer.top = amount;
|
||||||
if (config->gaps_outer < -config->gaps_inner) {
|
}
|
||||||
config->gaps_outer = -config->gaps_inner;
|
if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "horizontal")
|
||||||
|
|| !strcasecmp(argv[0], "right")) {
|
||||||
|
valid = true;
|
||||||
|
config->gaps_outer.right = amount;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "vertical")
|
||||||
|
|| !strcasecmp(argv[0], "bottom")) {
|
||||||
|
valid = true;
|
||||||
|
config->gaps_outer.bottom = amount;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "horizontal")
|
||||||
|
|| !strcasecmp(argv[0], "left")) {
|
||||||
|
valid = true;
|
||||||
|
config->gaps_outer.left = amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!valid) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
|
"Expected %s", expected_defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prevent_invalid_outer_gaps();
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void configure_gaps(struct sway_workspace *ws, void *_data) {
|
static void apply_gaps_op(int *prop, enum gaps_op op, int amount) {
|
||||||
struct gaps_data *data = _data;
|
switch (op) {
|
||||||
int *prop = data->inner ? &ws->gaps_inner : &ws->gaps_outer;
|
|
||||||
|
|
||||||
switch (data->operation) {
|
|
||||||
case GAPS_OP_SET:
|
case GAPS_OP_SET:
|
||||||
*prop = data->amount;
|
*prop = amount;
|
||||||
break;
|
break;
|
||||||
case GAPS_OP_ADD:
|
case GAPS_OP_ADD:
|
||||||
*prop += data->amount;
|
*prop += amount;
|
||||||
break;
|
break;
|
||||||
case GAPS_OP_SUBTRACT:
|
case GAPS_OP_SUBTRACT:
|
||||||
*prop -= data->amount;
|
*prop -= amount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configure_gaps(struct sway_workspace *ws, void *_data) {
|
||||||
|
// Apply operation to gaps
|
||||||
|
struct gaps_data *data = _data;
|
||||||
|
if (data->inner) {
|
||||||
|
apply_gaps_op(&ws->gaps_inner, data->operation, data->amount);
|
||||||
|
}
|
||||||
|
if (data->outer.top) {
|
||||||
|
apply_gaps_op(&(ws->gaps_outer.top), data->operation, data->amount);
|
||||||
|
}
|
||||||
|
if (data->outer.right) {
|
||||||
|
apply_gaps_op(&(ws->gaps_outer.right), data->operation, data->amount);
|
||||||
|
}
|
||||||
|
if (data->outer.bottom) {
|
||||||
|
apply_gaps_op(&(ws->gaps_outer.bottom), data->operation, data->amount);
|
||||||
|
}
|
||||||
|
if (data->outer.left) {
|
||||||
|
apply_gaps_op(&(ws->gaps_outer.left), data->operation, data->amount);
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent invalid gaps configurations.
|
// Prevent invalid gaps configurations.
|
||||||
if (ws->gaps_inner < 0) {
|
if (ws->gaps_inner < 0) {
|
||||||
ws->gaps_inner = 0;
|
ws->gaps_inner = 0;
|
||||||
}
|
}
|
||||||
if (ws->gaps_outer < -ws->gaps_inner) {
|
prevent_invalid_outer_gaps();
|
||||||
ws->gaps_outer = -ws->gaps_inner;
|
|
||||||
}
|
|
||||||
arrange_workspace(ws);
|
arrange_workspace(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
// gaps inner|outer current|all set|plus|minus <px>
|
// gaps inner|outer|horizontal|vertical|top|right|bottom|left current|all
|
||||||
|
// set|plus|minus <px>
|
||||||
|
static const char *expected_runtime = "'gaps inner|outer|horizontal|vertical|"
|
||||||
|
"top|right|bottom|left current|all set|plus|minus <px>'";
|
||||||
static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
|
static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
|
||||||
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
|
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -93,15 +148,24 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
|
||||||
"Can't run this command while there's no outputs connected.");
|
"Can't run this command while there's no outputs connected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct gaps_data data;
|
struct gaps_data data = {0};
|
||||||
|
|
||||||
if (strcasecmp(argv[0], "inner") == 0) {
|
if (strcasecmp(argv[0], "inner") == 0) {
|
||||||
data.inner = true;
|
data.inner = true;
|
||||||
} else if (strcasecmp(argv[0], "outer") == 0) {
|
|
||||||
data.inner = false;
|
|
||||||
} else {
|
} else {
|
||||||
|
data.outer.top = !strcasecmp(argv[0], "outer") ||
|
||||||
|
!strcasecmp(argv[0], "vertical") || !strcasecmp(argv[0], "top");
|
||||||
|
data.outer.right = !strcasecmp(argv[0], "outer") ||
|
||||||
|
!strcasecmp(argv[0], "horizontal") || !strcasecmp(argv[0], "right");
|
||||||
|
data.outer.bottom = !strcasecmp(argv[0], "outer") ||
|
||||||
|
!strcasecmp(argv[0], "vertical") || !strcasecmp(argv[0], "bottom");
|
||||||
|
data.outer.left = !strcasecmp(argv[0], "outer") ||
|
||||||
|
!strcasecmp(argv[0], "horizontal") || !strcasecmp(argv[0], "left");
|
||||||
|
}
|
||||||
|
if (!data.inner && !data.outer.top && !data.outer.right &&
|
||||||
|
!data.outer.bottom && !data.outer.left) {
|
||||||
return cmd_results_new(CMD_INVALID, "gaps",
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
|
"Expected %s", expected_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool all;
|
bool all;
|
||||||
|
@ -111,7 +175,7 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
|
||||||
all = true;
|
all = true;
|
||||||
} else {
|
} else {
|
||||||
return cmd_results_new(CMD_INVALID, "gaps",
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
|
"Expected %s", expected_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(argv[2], "set") == 0) {
|
if (strcasecmp(argv[2], "set") == 0) {
|
||||||
|
@ -122,14 +186,14 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
|
||||||
data.operation = GAPS_OP_SUBTRACT;
|
data.operation = GAPS_OP_SUBTRACT;
|
||||||
} else {
|
} else {
|
||||||
return cmd_results_new(CMD_INVALID, "gaps",
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
|
"Expected %s", expected_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
data.amount = strtol(argv[3], &end, 10);
|
data.amount = strtol(argv[3], &end, 10);
|
||||||
if (strlen(end) && strcasecmp(end, "px") != 0) {
|
if (strlen(end) && strcasecmp(end, "px") != 0) {
|
||||||
return cmd_results_new(CMD_INVALID, "gaps",
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
"Expected 'gaps inner|outer current|all set|plus|minus <px>'");
|
"Expected %s", expected_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all) {
|
if (all) {
|
||||||
|
@ -141,8 +205,10 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// gaps inner|outer <px> - sets defaults for workspaces
|
// gaps inner|outer|<dir>|<side> <px> - sets defaults for workspaces
|
||||||
// gaps inner|outer current|all set|plus|minus <px> - runtime only
|
// gaps inner|outer|<dir>|<side> current|all set|plus|minus <px> - runtime only
|
||||||
|
// <dir> = horizontal|vertical
|
||||||
|
// <side> = top|right|bottom|left
|
||||||
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, 2);
|
struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -159,9 +225,8 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
if (config_loading) {
|
if (config_loading) {
|
||||||
return cmd_results_new(CMD_INVALID, "gaps",
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
"Expected 'gaps inner|outer <px>'");
|
"Expected %s", expected_defaults);
|
||||||
}
|
}
|
||||||
return cmd_results_new(CMD_INVALID, "gaps",
|
return cmd_results_new(CMD_INVALID, "gaps",
|
||||||
"Expected 'gaps inner|outer <px>' or "
|
"Expected %s or %s", expected_runtime, expected_defaults);
|
||||||
"'gaps inner|outer current|all set|plus|minus <px>'");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,10 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
|
||||||
}
|
}
|
||||||
wsc->workspace = strdup(ws_name);
|
wsc->workspace = strdup(ws_name);
|
||||||
wsc->gaps_inner = INT_MIN;
|
wsc->gaps_inner = INT_MIN;
|
||||||
wsc->gaps_outer = INT_MIN;
|
wsc->gaps_outer.top = INT_MIN;
|
||||||
|
wsc->gaps_outer.right = INT_MIN;
|
||||||
|
wsc->gaps_outer.bottom = INT_MIN;
|
||||||
|
wsc->gaps_outer.left = INT_MIN;
|
||||||
list_add(config->workspace_configs, wsc);
|
list_add(config->workspace_configs, wsc);
|
||||||
return wsc;
|
return wsc;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +36,89 @@ void free_workspace_config(struct workspace_config *wsc) {
|
||||||
free(wsc);
|
free(wsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prevent_invalid_outer_gaps(struct workspace_config *wsc) {
|
||||||
|
if (wsc->gaps_outer.top != INT_MIN &&
|
||||||
|
wsc->gaps_outer.top < -wsc->gaps_inner) {
|
||||||
|
wsc->gaps_outer.top = -wsc->gaps_inner;
|
||||||
|
}
|
||||||
|
if (wsc->gaps_outer.right != INT_MIN &&
|
||||||
|
wsc->gaps_outer.right < -wsc->gaps_inner) {
|
||||||
|
wsc->gaps_outer.right = -wsc->gaps_inner;
|
||||||
|
}
|
||||||
|
if (wsc->gaps_outer.bottom != INT_MIN &&
|
||||||
|
wsc->gaps_outer.bottom < -wsc->gaps_inner) {
|
||||||
|
wsc->gaps_outer.bottom = -wsc->gaps_inner;
|
||||||
|
}
|
||||||
|
if (wsc->gaps_outer.left != INT_MIN &&
|
||||||
|
wsc->gaps_outer.left < -wsc->gaps_inner) {
|
||||||
|
wsc->gaps_outer.left = -wsc->gaps_inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
|
||||||
|
int gaps_location) {
|
||||||
|
const char *expected = "Expected 'workspace <name> gaps "
|
||||||
|
"inner|outer|horizontal|vertical|top|right|bottom|left <px>'";
|
||||||
|
struct cmd_results *error = NULL;
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
int amount = strtol(argv[gaps_location + 2], &end, 10);
|
||||||
|
if (strlen(end)) {
|
||||||
|
free(end);
|
||||||
|
return cmd_results_new(CMD_FAILURE, "workspace gaps", expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
char *type = argv[gaps_location + 1];
|
||||||
|
if (!strcasecmp(type, "inner")) {
|
||||||
|
valid = true;
|
||||||
|
wsc->gaps_inner = (amount >= 0) ? amount : 0;
|
||||||
|
} else {
|
||||||
|
if (!strcasecmp(type, "outer") || !strcasecmp(type, "vertical")
|
||||||
|
|| !strcasecmp(type, "top")) {
|
||||||
|
valid = true;
|
||||||
|
wsc->gaps_outer.top = amount;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(type, "outer") || !strcasecmp(type, "horizontal")
|
||||||
|
|| !strcasecmp(type, "right")) {
|
||||||
|
valid = true;
|
||||||
|
wsc->gaps_outer.right = amount;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(type, "outer") || !strcasecmp(type, "vertical")
|
||||||
|
|| !strcasecmp(type, "bottom")) {
|
||||||
|
valid = true;
|
||||||
|
wsc->gaps_outer.bottom = amount;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(type, "outer") || !strcasecmp(type, "horizontal")
|
||||||
|
|| !strcasecmp(type, "left")) {
|
||||||
|
valid = true;
|
||||||
|
wsc->gaps_outer.left = amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!valid) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "workspace gaps", expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent invalid gaps configurations.
|
||||||
|
if (wsc->gaps_inner != INT_MIN && wsc->gaps_inner < 0) {
|
||||||
|
wsc->gaps_inner = 0;
|
||||||
|
}
|
||||||
|
prevent_invalid_outer_gaps(wsc);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
struct cmd_results *cmd_workspace(int argc, char **argv) {
|
struct cmd_results *cmd_workspace(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) {
|
if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) {
|
||||||
|
@ -68,43 +154,9 @@ 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) {
|
} else if (gaps_location >= 0) {
|
||||||
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, gaps_location + 3))) {
|
if ((error = cmd_workspace_gaps(argc, argv, gaps_location))) {
|
||||||
return error;
|
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;
|
|
||||||
|
|
||||||
// Prevent invalid gaps configurations.
|
|
||||||
if (wsc->gaps_inner < 0) {
|
|
||||||
wsc->gaps_inner = 0;
|
|
||||||
}
|
|
||||||
if (wsc->gaps_outer < -wsc->gaps_inner) {
|
|
||||||
wsc->gaps_outer = -wsc->gaps_inner;
|
|
||||||
}
|
|
||||||
|
|
||||||
} 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);
|
||||||
|
|
|
@ -234,7 +234,10 @@ static void config_defaults(struct sway_config *config) {
|
||||||
|
|
||||||
config->smart_gaps = false;
|
config->smart_gaps = false;
|
||||||
config->gaps_inner = 0;
|
config->gaps_inner = 0;
|
||||||
config->gaps_outer = 0;
|
config->gaps_outer.top = 0;
|
||||||
|
config->gaps_outer.right = 0;
|
||||||
|
config->gaps_outer.bottom = 0;
|
||||||
|
config->gaps_outer.left = 0;
|
||||||
|
|
||||||
if (!(config->active_bar_modifiers = create_list())) goto cleanup;
|
if (!(config->active_bar_modifiers = create_list())) goto cleanup;
|
||||||
|
|
||||||
|
|
|
@ -133,9 +133,12 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
|
||||||
*fullscreen*
|
*fullscreen*
|
||||||
Toggles fullscreen for the focused view.
|
Toggles fullscreen for the focused view.
|
||||||
|
|
||||||
*gaps* inner|outer all|current set|plus|minus <amount>
|
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current
|
||||||
|
set|plus|minus <amount>
|
||||||
Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the
|
Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the
|
||||||
_current_ workspace.
|
_current_ workspace. _outer_ gaps can be altered per side with _top_,
|
||||||
|
_right_, _bottom_, and _left_ or per direction with _horizontal_ and
|
||||||
|
_vertical_.
|
||||||
|
|
||||||
*layout* default|splith|splitv|stacking|tabbed
|
*layout* default|splith|splitv|stacking|tabbed
|
||||||
Sets the layout mode of the focused container.
|
Sets the layout mode of the focused container.
|
||||||
|
@ -429,14 +432,16 @@ The default colors are:
|
||||||
_focus\_wrapping force_. This is only available for convenience. Please
|
_focus\_wrapping force_. This is only available for convenience. Please
|
||||||
use _focus\_wrapping_ instead when possible.
|
use _focus\_wrapping_ instead when possible.
|
||||||
|
|
||||||
*gaps* inner|outer <amount>
|
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left <amount>
|
||||||
Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
|
Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
|
||||||
affects spacing around each view and outer affects the spacing around each
|
affects spacing around each view and outer affects the spacing around each
|
||||||
workspace. Outer gaps are in addition to inner gaps. To reduce or remove
|
workspace. Outer gaps are in addition to inner gaps. To reduce or remove
|
||||||
outer gaps, outer gaps can be set to a negative value.
|
outer gaps, outer gaps can be set to a negative value. _outer_ gaps can
|
||||||
|
also be specified per side with _top_, _right_, _bottom_, and _left_ or
|
||||||
|
per direction with _horizontal_ and _vertical_.
|
||||||
|
|
||||||
This affects new workspaces only, and is used when the workspace doesn't
|
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>).
|
have its own gaps settings (see: workspace <ws> gaps ...).
|
||||||
|
|
||||||
*hide\_edge\_borders* none|vertical|horizontal|both|smart|smart\_no\_gaps
|
*hide\_edge\_borders* none|vertical|horizontal|both|smart|smart\_no\_gaps
|
||||||
Hides window borders adjacent to the screen edges. Default is _none_.
|
Hides window borders adjacent to the screen edges. Default is _none_.
|
||||||
|
@ -549,7 +554,8 @@ The default colors are:
|
||||||
*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>
|
*workspace* <name> gaps inner|outer|horizontal|vertical|top|right|bottom|left
|
||||||
|
<amount>
|
||||||
Specifies that workspace _name_ should have the given gaps settings when it
|
Specifies that workspace _name_ should have the given gaps settings when it
|
||||||
is created.
|
is created.
|
||||||
|
|
||||||
|
|
|
@ -190,7 +190,8 @@ static bool gaps_to_edge(struct sway_view *view) {
|
||||||
}
|
}
|
||||||
con = con->parent;
|
con = con->parent;
|
||||||
}
|
}
|
||||||
return view->container->workspace->current_gaps > 0;
|
struct side_gaps gaps = view->container->workspace->current_gaps;
|
||||||
|
return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void view_autoconfigure(struct sway_view *view) {
|
void view_autoconfigure(struct sway_view *view) {
|
||||||
|
|
|
@ -49,6 +49,21 @@ struct sway_output *workspace_get_initial_output(const char *name) {
|
||||||
return focus->output;
|
return focus->output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prevent_invalid_outer_gaps(struct sway_workspace *ws) {
|
||||||
|
if (ws->gaps_outer.top < -ws->gaps_inner) {
|
||||||
|
ws->gaps_outer.top = -ws->gaps_inner;
|
||||||
|
}
|
||||||
|
if (ws->gaps_outer.right < -ws->gaps_inner) {
|
||||||
|
ws->gaps_outer.right = -ws->gaps_inner;
|
||||||
|
}
|
||||||
|
if (ws->gaps_outer.bottom < -ws->gaps_inner) {
|
||||||
|
ws->gaps_outer.bottom = -ws->gaps_inner;
|
||||||
|
}
|
||||||
|
if (ws->gaps_outer.left < -ws->gaps_inner) {
|
||||||
|
ws->gaps_outer.left = -ws->gaps_inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct sway_workspace *workspace_create(struct sway_output *output,
|
struct sway_workspace *workspace_create(struct sway_output *output,
|
||||||
const char *name) {
|
const char *name) {
|
||||||
if (output == NULL) {
|
if (output == NULL) {
|
||||||
|
@ -77,12 +92,24 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
||||||
if (name) {
|
if (name) {
|
||||||
struct workspace_config *wsc = workspace_find_config(name);
|
struct workspace_config *wsc = workspace_find_config(name);
|
||||||
if (wsc) {
|
if (wsc) {
|
||||||
if (wsc->gaps_outer != INT_MIN) {
|
if (wsc->gaps_outer.top != INT_MIN) {
|
||||||
ws->gaps_outer = wsc->gaps_outer;
|
ws->gaps_outer.top = wsc->gaps_outer.top;
|
||||||
|
}
|
||||||
|
if (wsc->gaps_outer.right != INT_MIN) {
|
||||||
|
ws->gaps_outer.right = wsc->gaps_outer.right;
|
||||||
|
}
|
||||||
|
if (wsc->gaps_outer.bottom != INT_MIN) {
|
||||||
|
ws->gaps_outer.bottom = wsc->gaps_outer.bottom;
|
||||||
|
}
|
||||||
|
if (wsc->gaps_outer.left != INT_MIN) {
|
||||||
|
ws->gaps_outer.left = wsc->gaps_outer.left;
|
||||||
}
|
}
|
||||||
if (wsc->gaps_inner != INT_MIN) {
|
if (wsc->gaps_inner != INT_MIN) {
|
||||||
ws->gaps_inner = wsc->gaps_inner;
|
ws->gaps_inner = wsc->gaps_inner;
|
||||||
}
|
}
|
||||||
|
// Since default outer gaps can be smaller than the negation of
|
||||||
|
// workspace specific inner gaps, check outer gaps again
|
||||||
|
prevent_invalid_outer_gaps(ws);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,19 +642,25 @@ void workspace_insert_tiling(struct sway_workspace *workspace,
|
||||||
}
|
}
|
||||||
|
|
||||||
void workspace_remove_gaps(struct sway_workspace *ws) {
|
void workspace_remove_gaps(struct sway_workspace *ws) {
|
||||||
if (ws->current_gaps == 0) {
|
if (ws->current_gaps.top == 0 && ws->current_gaps.right == 0 &&
|
||||||
|
ws->current_gaps.bottom == 0 && ws->current_gaps.left == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws->width += ws->current_gaps * 2;
|
ws->width += ws->current_gaps.left + ws->current_gaps.right;
|
||||||
ws->height += ws->current_gaps * 2;
|
ws->height += ws->current_gaps.top + ws->current_gaps.bottom;
|
||||||
ws->x -= ws->current_gaps;
|
ws->x -= ws->current_gaps.left;
|
||||||
ws->y -= ws->current_gaps;
|
ws->y -= ws->current_gaps.top;
|
||||||
ws->current_gaps = 0;
|
|
||||||
|
ws->current_gaps.top = 0;
|
||||||
|
ws->current_gaps.right = 0;
|
||||||
|
ws->current_gaps.bottom = 0;
|
||||||
|
ws->current_gaps.left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void workspace_add_gaps(struct sway_workspace *ws) {
|
void workspace_add_gaps(struct sway_workspace *ws) {
|
||||||
if (ws->current_gaps > 0) {
|
if (ws->current_gaps.top > 0 || ws->current_gaps.right > 0 ||
|
||||||
|
ws->current_gaps.bottom > 0 || ws->current_gaps.left > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (config->smart_gaps) {
|
if (config->smart_gaps) {
|
||||||
|
@ -643,18 +676,20 @@ void workspace_add_gaps(struct sway_workspace *ws) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ws->current_gaps = ws->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->gaps_inner;
|
ws->current_gaps.top += ws->gaps_inner;
|
||||||
|
ws->current_gaps.right += ws->gaps_inner;
|
||||||
|
ws->current_gaps.bottom += ws->gaps_inner;
|
||||||
|
ws->current_gaps.left += ws->gaps_inner;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws->x += ws->current_gaps;
|
ws->x += ws->current_gaps.left;
|
||||||
ws->y += ws->current_gaps;
|
ws->y += ws->current_gaps.top;
|
||||||
ws->width -= 2 * ws->current_gaps;
|
ws->width -= ws->current_gaps.left + ws->current_gaps.right;
|
||||||
ws->height -= 2 * ws->current_gaps;
|
ws->height -= ws->current_gaps.top + ws->current_gaps.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sway_container *workspace_split(struct sway_workspace *workspace,
|
struct sway_container *workspace_split(struct sway_workspace *workspace,
|
||||||
|
|
Loading…
Reference in a new issue