mirror of
https://github.com/swaywm/sway.git
synced 2026-04-22 06:46:27 -04:00
commit
4660771f6a
77 changed files with 703 additions and 306 deletions
|
|
@ -51,6 +51,7 @@ static const struct cmd_handler handlers[] = {
|
|||
{ "client.background", cmd_client_noop },
|
||||
{ "client.focused", cmd_client_focused },
|
||||
{ "client.focused_inactive", cmd_client_focused_inactive },
|
||||
{ "client.focused_tab_title", cmd_client_focused_tab_title },
|
||||
{ "client.placeholder", cmd_client_noop },
|
||||
{ "client.unfocused", cmd_client_unfocused },
|
||||
{ "client.urgent", cmd_client_urgent },
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
|
|||
}
|
||||
|
||||
const char *state = argv[0];
|
||||
if (config->reading) {
|
||||
if (config->current_bar) {
|
||||
error = bar_set_hidden_state(config->current_bar, state);
|
||||
} else {
|
||||
const char *id = argc == 2 ? argv[1] : NULL;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) {
|
|||
}
|
||||
|
||||
const char *mode = argv[0];
|
||||
if (config->reading) {
|
||||
if (config->current_bar) {
|
||||
error = bar_set_mode(config->current_bar, mode);
|
||||
} else {
|
||||
const char *id = argc == 2 ? argv[1] : NULL;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
|
|||
return error;
|
||||
}
|
||||
|
||||
if (argc > 3 && strcmp(cmd_name, "client.focused_tab_title") == 0) {
|
||||
sway_log(SWAY_ERROR,
|
||||
"Warning: indicator and child_border colors have no effect for %s",
|
||||
cmd_name);
|
||||
}
|
||||
|
||||
struct border_colors colors = {0};
|
||||
const char *ind_hex = argc > 3 ? argv[3] : default_indicator;
|
||||
const char *child_hex = argc > 4 ? argv[4] : argv[1]; // def to background
|
||||
|
|
@ -80,3 +86,13 @@ struct cmd_results *cmd_client_noop(int argc, char **argv) {
|
|||
sway_log(SWAY_INFO, "Warning: %s is ignored by sway", argv[-1]);
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_client_focused_tab_title(int argc, char **argv) {
|
||||
struct cmd_results *result = handle_command(argc, argv,
|
||||
"client.focused_tab_title",
|
||||
&config->border_colors.focused_tab_title, "#2e9ef4ff");
|
||||
if (result && result->status == CMD_SUCCESS) {
|
||||
config->has_focused_tab_title = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <signal.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/root.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
|
|
@ -53,6 +54,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
|||
// Fork process
|
||||
if ((pid = fork()) == 0) {
|
||||
// Fork child process again
|
||||
restore_nofile_limit();
|
||||
setsid();
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
|
|
|
|||
|
|
@ -267,6 +267,11 @@ static struct cmd_results *focus_mode(struct sway_workspace *ws,
|
|||
new_focus = seat_get_focus_inactive_tiling(seat, ws);
|
||||
}
|
||||
if (new_focus) {
|
||||
struct sway_container *new_focus_view =
|
||||
seat_get_focus_inactive_view(seat, &new_focus->node);
|
||||
if (new_focus_view) {
|
||||
new_focus = new_focus_view;
|
||||
}
|
||||
seat_set_focus_container(seat, new_focus);
|
||||
|
||||
// If we're on the floating layer and the floating container area
|
||||
|
|
@ -446,7 +451,8 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
|
|||
return cmd_results_new(CMD_FAILURE, "");
|
||||
}
|
||||
struct sway_node *next_focus = NULL;
|
||||
if (container_is_floating(container)) {
|
||||
if (container_is_floating(container) &&
|
||||
container->pending.fullscreen_mode == FULLSCREEN_NONE) {
|
||||
next_focus = node_get_in_direction_floating(container, seat, direction);
|
||||
} else {
|
||||
next_focus = node_get_in_direction_tiling(container, seat, direction, descend);
|
||||
|
|
|
|||
|
|
@ -874,6 +874,10 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
|
|||
return cmd_results_new(CMD_INVALID, "Invalid x position specified");
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
return cmd_results_new(CMD_FAILURE, expected_position_syntax);
|
||||
}
|
||||
|
||||
struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
|
||||
// Y direction
|
||||
num_consumed_args = parse_movement_amount(argc, argv, &ly);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ static const struct cmd_handler output_handlers[] = {
|
|||
{ "modeline", output_cmd_modeline },
|
||||
{ "pos", output_cmd_position },
|
||||
{ "position", output_cmd_position },
|
||||
{ "render_bit_depth", output_cmd_render_bit_depth },
|
||||
{ "res", output_cmd_mode },
|
||||
{ "resolution", output_cmd_mode },
|
||||
{ "scale", output_cmd_scale },
|
||||
|
|
@ -33,9 +34,9 @@ struct cmd_results *cmd_output(int argc, char **argv) {
|
|||
return error;
|
||||
}
|
||||
|
||||
// The NOOP-1 output is a dummy output used when there's no outputs
|
||||
// The HEADLESS-1 output is a dummy output used when there's no outputs
|
||||
// connected. It should never be configured.
|
||||
if (strcasecmp(argv[0], root->noop_output->wlr_output->name) == 0) {
|
||||
if (strcasecmp(argv[0], root->fallback_output->wlr_output->name) == 0) {
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"Refusing to configure the no op output");
|
||||
}
|
||||
|
|
@ -52,7 +53,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
|
|||
if (!sway_output) {
|
||||
return cmd_results_new(CMD_FAILURE, "Unknown output");
|
||||
}
|
||||
if (sway_output == root->noop_output) {
|
||||
if (sway_output == root->fallback_output) {
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"Refusing to configure the no op output");
|
||||
}
|
||||
|
|
|
|||
29
sway/commands/output/render_bit_depth.c
Normal file
29
sway/commands/output/render_bit_depth.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include <drm_fourcc.h>
|
||||
#include <strings.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
|
||||
struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
|
||||
if (!config->handler_context.output_config) {
|
||||
return cmd_results_new(CMD_FAILURE, "Missing output config");
|
||||
}
|
||||
if (!argc) {
|
||||
return cmd_results_new(CMD_INVALID, "Missing bit depth argument.");
|
||||
}
|
||||
|
||||
if (strcmp(*argv, "8") == 0) {
|
||||
config->handler_context.output_config->render_bit_depth =
|
||||
RENDER_BIT_DEPTH_8;
|
||||
} else if (strcmp(*argv, "10") == 0) {
|
||||
config->handler_context.output_config->render_bit_depth =
|
||||
RENDER_BIT_DEPTH_10;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID,
|
||||
"Invalid bit depth. Must be a value in (8|10).");
|
||||
}
|
||||
|
||||
config->handler_context.leftovers.argc = argc - 1;
|
||||
config->handler_context.leftovers.argv = argv + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +15,12 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
|
|||
return error;
|
||||
}
|
||||
|
||||
config->smart_gaps = parse_boolean(argv[0], config->smart_gaps);
|
||||
if (strcmp(argv[0], "inverse_outer") == 0) {
|
||||
config->smart_gaps = SMART_GAPS_INVERSE_OUTER;
|
||||
} else {
|
||||
config->smart_gaps = parse_boolean(argv[0], config->smart_gaps)
|
||||
? SMART_GAPS_ON : SMART_GAPS_OFF;
|
||||
}
|
||||
|
||||
arrange_root();
|
||||
|
||||
|
|
|
|||
|
|
@ -126,10 +126,10 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
|
|||
}
|
||||
|
||||
enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode;
|
||||
enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
|
||||
if (fs1) {
|
||||
container_fullscreen_disable(con1);
|
||||
}
|
||||
enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
|
||||
if (fs2) {
|
||||
container_fullscreen_disable(con2);
|
||||
}
|
||||
|
|
@ -247,6 +247,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
|
|||
} else if (!current) {
|
||||
error = cmd_results_new(CMD_FAILURE,
|
||||
"Can only swap with containers and views");
|
||||
} else if (current == other) {
|
||||
error = cmd_results_new(CMD_FAILURE,
|
||||
"Cannot swap a container with itself");
|
||||
} else if (container_has_ancestor(current, other)
|
||||
|| container_has_ancestor(other, current)) {
|
||||
error = cmd_results_new(CMD_FAILURE,
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ static void config_defaults(struct sway_config *config) {
|
|||
config->tiling_drag = true;
|
||||
config->tiling_drag_threshold = 9;
|
||||
|
||||
config->smart_gaps = false;
|
||||
config->smart_gaps = SMART_GAPS_OFF;
|
||||
config->gaps_inner = 0;
|
||||
config->gaps_outer.top = 0;
|
||||
config->gaps_outer.right = 0;
|
||||
|
|
@ -290,6 +290,8 @@ static void config_defaults(struct sway_config *config) {
|
|||
config->hide_edge_borders_smart = ESMART_OFF;
|
||||
config->hide_lone_tab = false;
|
||||
|
||||
config->has_focused_tab_title = false;
|
||||
|
||||
// border colors
|
||||
color_to_rgba(config->border_colors.focused.border, 0x4C7899FF);
|
||||
color_to_rgba(config->border_colors.focused.background, 0x285577FF);
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ static void invoke_swaybar(struct bar_config *bar) {
|
|||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
|
||||
restore_nofile_limit();
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
sway_log_errno(SWAY_ERROR, "fork failed");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
|
@ -67,6 +68,7 @@ struct output_config *new_output_config(const char *name) {
|
|||
oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
oc->max_render_time = -1;
|
||||
oc->adaptive_sync = -1;
|
||||
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
|
||||
return oc;
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +115,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
|
|||
if (src->adaptive_sync != -1) {
|
||||
dst->adaptive_sync = src->adaptive_sync;
|
||||
}
|
||||
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
|
||||
dst->render_bit_depth = src->render_bit_depth;
|
||||
}
|
||||
if (src->background) {
|
||||
free(dst->background);
|
||||
dst->background = strdup(src->background);
|
||||
|
|
@ -351,9 +356,26 @@ static int compute_default_scale(struct wlr_output *output) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
/* Lists of formats to try, in order, when a specific render bit depth has
|
||||
* been asked for. The second to last format in each list should always
|
||||
* be XRGB8888, as a reliable backup in case the others are not available;
|
||||
* the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */
|
||||
static const uint32_t *bit_depth_preferences[] = {
|
||||
[RENDER_BIT_DEPTH_8] = (const uint32_t []){
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_INVALID,
|
||||
},
|
||||
[RENDER_BIT_DEPTH_10] = (const uint32_t []){
|
||||
DRM_FORMAT_XRGB2101010,
|
||||
DRM_FORMAT_XBGR2101010,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_INVALID,
|
||||
},
|
||||
};
|
||||
|
||||
static void queue_output_config(struct output_config *oc,
|
||||
struct sway_output *output) {
|
||||
if (output == root->noop_output) {
|
||||
if (output == root->fallback_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -437,10 +459,26 @@ static void queue_output_config(struct output_config *oc,
|
|||
oc->adaptive_sync);
|
||||
wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1);
|
||||
}
|
||||
|
||||
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
|
||||
const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth];
|
||||
assert(fmts);
|
||||
|
||||
for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
|
||||
wlr_output_set_render_format(wlr_output, fmts[i]);
|
||||
if (wlr_output_test(wlr_output)) {
|
||||
break;
|
||||
}
|
||||
|
||||
sway_log(SWAY_DEBUG, "Preferred output format 0x%08x "
|
||||
"failed to work, falling back to next in "
|
||||
"list, 0x%08x", fmts[i], fmts[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool apply_output_config(struct output_config *oc, struct sway_output *output) {
|
||||
if (output == root->noop_output) {
|
||||
if (output == root->fallback_output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -535,7 +573,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
|
|||
}
|
||||
|
||||
bool test_output_config(struct output_config *oc, struct sway_output *output) {
|
||||
if (output == root->noop_output) {
|
||||
if (output == root->fallback_output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -750,6 +788,8 @@ static bool _spawn_swaybg(char **command) {
|
|||
sway_log_errno(SWAY_ERROR, "fork failed");
|
||||
return false;
|
||||
} else if (pid == 0) {
|
||||
restore_nofile_limit();
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
sway_log_errno(SWAY_ERROR, "fork failed");
|
||||
|
|
|
|||
|
|
@ -352,6 +352,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
|
|||
sway_layer->layer_surface->surface, true);
|
||||
}
|
||||
|
||||
static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface);
|
||||
|
||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_layer_surface *sway_layer =
|
||||
wl_container_of(listener, sway_layer, destroy);
|
||||
|
|
@ -360,6 +362,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
|||
if (sway_layer->layer_surface->mapped) {
|
||||
unmap(sway_layer);
|
||||
}
|
||||
|
||||
struct sway_layer_subsurface *subsurface, *subsurface_tmp;
|
||||
wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) {
|
||||
layer_subsurface_destroy(subsurface);
|
||||
}
|
||||
|
||||
wl_list_remove(&sway_layer->link);
|
||||
wl_list_remove(&sway_layer->destroy.link);
|
||||
wl_list_remove(&sway_layer->map.link);
|
||||
|
|
@ -428,11 +436,8 @@ static void subsurface_handle_commit(struct wl_listener *listener, void *data) {
|
|||
subsurface_damage(subsurface, false);
|
||||
}
|
||||
|
||||
static void subsurface_handle_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, destroy);
|
||||
|
||||
static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) {
|
||||
wl_list_remove(&subsurface->link);
|
||||
wl_list_remove(&subsurface->map.link);
|
||||
wl_list_remove(&subsurface->unmap.link);
|
||||
wl_list_remove(&subsurface->destroy.link);
|
||||
|
|
@ -440,6 +445,13 @@ static void subsurface_handle_destroy(struct wl_listener *listener,
|
|||
free(subsurface);
|
||||
}
|
||||
|
||||
static void subsurface_handle_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct sway_layer_subsurface *subsurface =
|
||||
wl_container_of(listener, subsurface, destroy);
|
||||
layer_subsurface_destroy(subsurface);
|
||||
}
|
||||
|
||||
static struct sway_layer_subsurface *create_subsurface(
|
||||
struct wlr_subsurface *wlr_subsurface,
|
||||
struct sway_layer_surface *layer_surface) {
|
||||
|
|
@ -451,6 +463,7 @@ static struct sway_layer_subsurface *create_subsurface(
|
|||
|
||||
subsurface->wlr_subsurface = wlr_subsurface;
|
||||
subsurface->layer_surface = layer_surface;
|
||||
wl_list_insert(&layer_surface->subsurfaces, &subsurface->link);
|
||||
|
||||
subsurface->map.notify = subsurface_handle_map;
|
||||
wl_signal_add(&wlr_subsurface->events.map, &subsurface->map);
|
||||
|
|
@ -624,7 +637,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
|||
output = ws->output;
|
||||
}
|
||||
}
|
||||
if (!output || output == root->noop_output) {
|
||||
if (!output || output == root->fallback_output) {
|
||||
if (!root->outputs->length) {
|
||||
sway_log(SWAY_ERROR,
|
||||
"no output to auto-assign layer surface '%s' to",
|
||||
|
|
@ -643,6 +656,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
wl_list_init(&sway_layer->subsurfaces);
|
||||
|
||||
sway_layer->surface_commit.notify = handle_surface_commit;
|
||||
wl_signal_add(&layer_surface->surface->events.commit,
|
||||
&sway_layer->surface_commit);
|
||||
|
|
@ -664,7 +679,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct sway_output *output = layer_surface->output->data;
|
||||
sway_layer->output_destroy.notify = handle_output_destroy;
|
||||
wl_signal_add(&output->events.destroy, &sway_layer->output_destroy);
|
||||
wl_signal_add(&output->events.disable, &sway_layer->output_destroy);
|
||||
|
||||
wl_list_insert(&output->layers[layer_surface->pending.layer],
|
||||
&sway_layer->link);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <time.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend/drm.h>
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_drm_lease_v1.h>
|
||||
|
|
@ -633,21 +634,19 @@ static void damage_surface_iterator(struct sway_output *output,
|
|||
struct wlr_box box = *_box;
|
||||
scale_box(&box, output->wlr_output->scale);
|
||||
|
||||
if (pixman_region32_not_empty(&surface->buffer_damage)) {
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
wlr_surface_get_effective_damage(surface, &damage);
|
||||
wlr_region_scale(&damage, &damage, output->wlr_output->scale);
|
||||
if (ceil(output->wlr_output->scale) > surface->current.scale) {
|
||||
// When scaling up a surface, it'll become blurry so we need to
|
||||
// expand the damage region
|
||||
wlr_region_expand(&damage, &damage,
|
||||
ceil(output->wlr_output->scale) - surface->current.scale);
|
||||
}
|
||||
pixman_region32_translate(&damage, box.x, box.y);
|
||||
wlr_output_damage_add(output->damage, &damage);
|
||||
pixman_region32_fini(&damage);
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
wlr_surface_get_effective_damage(surface, &damage);
|
||||
wlr_region_scale(&damage, &damage, output->wlr_output->scale);
|
||||
if (ceil(output->wlr_output->scale) > surface->current.scale) {
|
||||
// When scaling up a surface, it'll become blurry so we need to
|
||||
// expand the damage region
|
||||
wlr_region_expand(&damage, &damage,
|
||||
ceil(output->wlr_output->scale) - surface->current.scale);
|
||||
}
|
||||
pixman_region32_translate(&damage, box.x, box.y);
|
||||
wlr_output_damage_add(output->damage, &damage);
|
||||
pixman_region32_fini(&damage);
|
||||
|
||||
if (whole) {
|
||||
wlr_output_damage_add_box(output->damage, &box);
|
||||
|
|
@ -733,7 +732,7 @@ static void update_output_manager_config(struct sway_server *server) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output == root->noop_output) {
|
||||
if (output == root->fallback_output) {
|
||||
continue;
|
||||
}
|
||||
struct wlr_output_configuration_head_v1 *config_head =
|
||||
|
|
@ -755,18 +754,22 @@ static void update_output_manager_config(struct sway_server *server) {
|
|||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct sway_output *output = wl_container_of(listener, output, destroy);
|
||||
struct sway_server *server = output->server;
|
||||
wl_signal_emit(&output->events.destroy, output);
|
||||
output_begin_destroy(output);
|
||||
|
||||
if (output->enabled) {
|
||||
output_disable(output);
|
||||
}
|
||||
output_begin_destroy(output);
|
||||
|
||||
wl_list_remove(&output->link);
|
||||
|
||||
wl_list_remove(&output->destroy.link);
|
||||
wl_list_remove(&output->commit.link);
|
||||
wl_list_remove(&output->mode.link);
|
||||
wl_list_remove(&output->present.link);
|
||||
|
||||
output->wlr_output->data = NULL;
|
||||
output->wlr_output = NULL;
|
||||
|
||||
transaction_commit_dirty();
|
||||
|
||||
update_output_manager_config(server);
|
||||
|
|
@ -835,9 +838,22 @@ static void handle_present(struct wl_listener *listener, void *data) {
|
|||
output->refresh_nsec = output_event->refresh;
|
||||
}
|
||||
|
||||
static unsigned int last_headless_num = 0;
|
||||
|
||||
void handle_new_output(struct wl_listener *listener, void *data) {
|
||||
struct sway_server *server = wl_container_of(listener, server, new_output);
|
||||
struct wlr_output *wlr_output = data;
|
||||
|
||||
if (wlr_output == root->fallback_output->wlr_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wlr_output_is_headless(wlr_output)) {
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "HEADLESS-%u", ++last_headless_num);
|
||||
wlr_output_set_name(wlr_output, name);
|
||||
}
|
||||
|
||||
sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)",
|
||||
wlr_output, wlr_output->name, wlr_output->non_desktop);
|
||||
|
||||
|
|
@ -850,6 +866,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!wlr_output_init_render(wlr_output, server->allocator,
|
||||
server->renderer)) {
|
||||
sway_log(SWAY_ERROR, "Failed to init output render");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sway_output *output = output_create(wlr_output);
|
||||
if (!output) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static int scale_length(int length, int offset, float scale) {
|
|||
|
||||
static void scissor_output(struct wlr_output *wlr_output,
|
||||
pixman_box32_t *rect) {
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
|
||||
struct wlr_renderer *renderer = wlr_output->renderer;
|
||||
assert(renderer);
|
||||
|
||||
struct wlr_box box = {
|
||||
|
|
@ -100,8 +100,7 @@ static void render_texture(struct wlr_output *wlr_output,
|
|||
pixman_region32_t *output_damage, struct wlr_texture *texture,
|
||||
const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
|
||||
const float matrix[static 9], float alpha) {
|
||||
struct wlr_renderer *renderer =
|
||||
wlr_backend_get_renderer(wlr_output->backend);
|
||||
struct wlr_renderer *renderer = wlr_output->renderer;
|
||||
struct sway_output *output = wlr_output->data;
|
||||
|
||||
pixman_region32_t damage;
|
||||
|
|
@ -218,8 +217,7 @@ void render_rect(struct sway_output *output,
|
|||
pixman_region32_t *output_damage, const struct wlr_box *_box,
|
||||
float color[static 4]) {
|
||||
struct wlr_output *wlr_output = output->wlr_output;
|
||||
struct wlr_renderer *renderer =
|
||||
wlr_backend_get_renderer(wlr_output->backend);
|
||||
struct wlr_renderer *renderer = wlr_output->renderer;
|
||||
|
||||
struct wlr_box box;
|
||||
memcpy(&box, _box, sizeof(struct wlr_box));
|
||||
|
|
@ -764,6 +762,14 @@ static void render_containers_linear(struct sway_output *output,
|
|||
}
|
||||
}
|
||||
|
||||
static bool container_is_focused(struct sway_container *con, void *data) {
|
||||
return con->current.focused;
|
||||
}
|
||||
|
||||
static bool container_has_focused_child(struct sway_container *con) {
|
||||
return container_find_child(con, container_is_focused, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a container's children using the L_TABBED layout.
|
||||
*/
|
||||
|
|
@ -795,6 +801,10 @@ static void render_containers_tabbed(struct sway_output *output,
|
|||
colors = &config->border_colors.focused;
|
||||
title_texture = child->title_focused;
|
||||
marks_texture = child->marks_focused;
|
||||
} else if (config->has_focused_tab_title && container_has_focused_child(child)) {
|
||||
colors = &config->border_colors.focused_tab_title;
|
||||
title_texture = child->title_focused_tab_title;
|
||||
marks_texture = child->marks_focused_tab_title;
|
||||
} else if (child == parent->active_child) {
|
||||
colors = &config->border_colors.focused_inactive;
|
||||
title_texture = child->title_focused_inactive;
|
||||
|
|
@ -860,7 +870,11 @@ static void render_containers_stacked(struct sway_output *output,
|
|||
colors = &config->border_colors.focused;
|
||||
title_texture = child->title_focused;
|
||||
marks_texture = child->marks_focused;
|
||||
} else if (child == parent->active_child) {
|
||||
} else if (config->has_focused_tab_title && container_has_focused_child(child)) {
|
||||
colors = &config->border_colors.focused_tab_title;
|
||||
title_texture = child->title_focused_tab_title;
|
||||
marks_texture = child->marks_focused_tab_title;
|
||||
} else if (child == parent->active_child) {
|
||||
colors = &config->border_colors.focused_inactive;
|
||||
title_texture = child->title_focused_inactive;
|
||||
marks_texture = child->marks_focused_inactive;
|
||||
|
|
@ -1013,13 +1027,7 @@ static void render_seatops(struct sway_output *output,
|
|||
void output_render(struct sway_output *output, struct timespec *when,
|
||||
pixman_region32_t *damage) {
|
||||
struct wlr_output *wlr_output = output->wlr_output;
|
||||
|
||||
struct wlr_renderer *renderer =
|
||||
wlr_backend_get_renderer(wlr_output->backend);
|
||||
if (!sway_assert(renderer != NULL,
|
||||
"expected the output backend to have a renderer")) {
|
||||
return;
|
||||
}
|
||||
struct wlr_renderer *renderer = output->server->renderer;
|
||||
|
||||
struct sway_workspace *workspace = output->current.active_workspace;
|
||||
if (workspace == NULL) {
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
|
|||
struct sway_transaction_instruction *instruction =
|
||||
transaction->instructions->items[i];
|
||||
struct sway_node *node = instruction->node;
|
||||
bool hidden = node_is_view(node) &&
|
||||
bool hidden = node_is_view(node) && !node->destroying &&
|
||||
!view_is_visible(node->sway_container->view);
|
||||
if (should_configure(node, instruction)) {
|
||||
instruction->serial = view_configure(node->sway_container->view,
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
|
|||
// the output box expressed in the coordinate system of the toplevel parent
|
||||
// of the popup
|
||||
struct wlr_box output_toplevel_sx_box = {
|
||||
.x = output->lx - view->container->pending.content_x,
|
||||
.y = output->ly - view->container->pending.content_y,
|
||||
.x = output->lx - view->container->pending.content_x + view->geometry.x,
|
||||
.y = output->ly - view->container->pending.content_y + view->geometry.y,
|
||||
.width = output->width,
|
||||
.height = output->height,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -436,6 +436,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
|||
wl_list_remove(&xwayland_view->commit.link);
|
||||
}
|
||||
|
||||
xwayland_view->view.wlr_xwayland_surface = NULL;
|
||||
|
||||
wl_list_remove(&xwayland_view->destroy.link);
|
||||
wl_list_remove(&xwayland_view->request_configure.link);
|
||||
wl_list_remove(&xwayland_view->request_fullscreen.link);
|
||||
|
|
|
|||
|
|
@ -83,7 +83,28 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
|
|||
struct sway_node *node_at_coords(
|
||||
struct sway_seat *seat, double lx, double ly,
|
||||
struct wlr_surface **surface, double *sx, double *sy) {
|
||||
// check for unmanaged views first
|
||||
// find the output the cursor is on
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
root->output_layout, lx, ly);
|
||||
if (wlr_output == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct sway_output *output = wlr_output->data;
|
||||
if (!output || !output->enabled) {
|
||||
// output is being destroyed or is being enabled
|
||||
return NULL;
|
||||
}
|
||||
double ox = lx, oy = ly;
|
||||
wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
|
||||
|
||||
// layer surfaces on the overlay layer are rendered on top
|
||||
if ((*surface = layer_surface_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check for unmanaged views
|
||||
#if HAVE_XWAYLAND
|
||||
struct wl_list *unmanaged = &root->xwayland_unmanaged;
|
||||
struct sway_xwayland_unmanaged *unmanaged_surface;
|
||||
|
|
@ -101,19 +122,6 @@ struct sway_node *node_at_coords(
|
|||
}
|
||||
}
|
||||
#endif
|
||||
// find the output the cursor is on
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
root->output_layout, lx, ly);
|
||||
if (wlr_output == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct sway_output *output = wlr_output->data;
|
||||
if (!output || !output->enabled) {
|
||||
// output is being destroyed or is being enabled
|
||||
return NULL;
|
||||
}
|
||||
double ox = lx, oy = ly;
|
||||
wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
|
||||
|
||||
if (root->fullscreen_global) {
|
||||
// Try fullscreen container
|
||||
|
|
@ -131,11 +139,6 @@ struct sway_node *node_at_coords(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if ((*surface = layer_surface_at(output,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
ox, oy, sx, sy))) {
|
||||
return NULL;
|
||||
}
|
||||
if (ws->fullscreen) {
|
||||
// Try transient containers
|
||||
for (int i = 0; i < ws->floating->length; ++i) {
|
||||
|
|
@ -924,6 +927,7 @@ static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data)
|
|||
struct sway_cursor *cursor = wl_container_of(
|
||||
listener, cursor, pinch_begin);
|
||||
struct wlr_event_pointer_pinch_begin *event = data;
|
||||
cursor_handle_activity_from_device(cursor, event->device);
|
||||
wlr_pointer_gestures_v1_send_pinch_begin(
|
||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||
event->time_msec, event->fingers);
|
||||
|
|
@ -933,6 +937,7 @@ static void handle_pointer_pinch_update(struct wl_listener *listener, void *data
|
|||
struct sway_cursor *cursor = wl_container_of(
|
||||
listener, cursor, pinch_update);
|
||||
struct wlr_event_pointer_pinch_update *event = data;
|
||||
cursor_handle_activity_from_device(cursor, event->device);
|
||||
wlr_pointer_gestures_v1_send_pinch_update(
|
||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||
event->time_msec, event->dx, event->dy,
|
||||
|
|
@ -943,6 +948,7 @@ static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) {
|
|||
struct sway_cursor *cursor = wl_container_of(
|
||||
listener, cursor, pinch_end);
|
||||
struct wlr_event_pointer_pinch_end *event = data;
|
||||
cursor_handle_activity_from_device(cursor, event->device);
|
||||
wlr_pointer_gestures_v1_send_pinch_end(
|
||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||
event->time_msec, event->cancelled);
|
||||
|
|
@ -952,6 +958,7 @@ static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data)
|
|||
struct sway_cursor *cursor = wl_container_of(
|
||||
listener, cursor, swipe_begin);
|
||||
struct wlr_event_pointer_swipe_begin *event = data;
|
||||
cursor_handle_activity_from_device(cursor, event->device);
|
||||
wlr_pointer_gestures_v1_send_swipe_begin(
|
||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||
event->time_msec, event->fingers);
|
||||
|
|
@ -961,6 +968,7 @@ static void handle_pointer_swipe_update(struct wl_listener *listener, void *data
|
|||
struct sway_cursor *cursor = wl_container_of(
|
||||
listener, cursor, swipe_update);
|
||||
struct wlr_event_pointer_swipe_update *event = data;
|
||||
cursor_handle_activity_from_device(cursor, event->device);
|
||||
wlr_pointer_gestures_v1_send_swipe_update(
|
||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||
event->time_msec, event->dx, event->dy);
|
||||
|
|
@ -970,6 +978,7 @@ static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) {
|
|||
struct sway_cursor *cursor = wl_container_of(
|
||||
listener, cursor, swipe_end);
|
||||
struct wlr_event_pointer_swipe_end *event = data;
|
||||
cursor_handle_activity_from_device(cursor, event->device);
|
||||
wlr_pointer_gestures_v1_send_swipe_end(
|
||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||
event->time_msec, event->cancelled);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,16 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
|
|||
static void seat_node_destroy(struct sway_seat_node *seat_node) {
|
||||
wl_list_remove(&seat_node->destroy.link);
|
||||
wl_list_remove(&seat_node->link);
|
||||
|
||||
/*
|
||||
* This is the only time we remove items from the focus stack without
|
||||
* immediately re-adding them. If we just removed the last thing,
|
||||
* mark that nothing has focus anymore.
|
||||
*/
|
||||
if (wl_list_empty(&seat_node->seat->focus_stack)) {
|
||||
seat_node->seat->has_focus = false;
|
||||
}
|
||||
|
||||
free(seat_node);
|
||||
}
|
||||
|
||||
|
|
@ -1415,9 +1425,8 @@ struct sway_node *seat_get_focus(struct sway_seat *seat) {
|
|||
if (!seat->has_focus) {
|
||||
return NULL;
|
||||
}
|
||||
if (wl_list_empty(&seat->focus_stack)) {
|
||||
return NULL;
|
||||
}
|
||||
sway_assert(!wl_list_empty(&seat->focus_stack),
|
||||
"focus_stack is empty, but has_focus is true");
|
||||
struct sway_seat_node *current =
|
||||
wl_container_of(seat->focus_stack.next, current, link);
|
||||
return current->node;
|
||||
|
|
|
|||
|
|
@ -80,17 +80,25 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
|
|||
double height = e->ref_height + grow_height;
|
||||
int min_width, max_width, min_height, max_height;
|
||||
floating_calculate_constraints(&min_width, &max_width,
|
||||
&min_height, &max_height);
|
||||
width = fmax(min_width + border_width, fmin(width, max_width));
|
||||
height = fmax(min_height + border_height, fmin(height, max_height));
|
||||
&min_height, &max_height);
|
||||
width = fmin(width, max_width - border_width);
|
||||
width = fmax(width, min_width + border_width);
|
||||
width = fmax(width, 1);
|
||||
height = fmin(height, max_height - border_height);
|
||||
height = fmax(height, min_height + border_height);
|
||||
height = fmax(height, 1);
|
||||
|
||||
// Apply the view's min/max size
|
||||
if (con->view) {
|
||||
double view_min_width, view_max_width, view_min_height, view_max_height;
|
||||
view_get_constraints(con->view, &view_min_width, &view_max_width,
|
||||
&view_min_height, &view_max_height);
|
||||
width = fmax(view_min_width + border_width, fmin(width, view_max_width));
|
||||
height = fmax(view_min_height + border_height, fmin(height, view_max_height));
|
||||
width = fmin(width, view_max_width - border_width);
|
||||
width = fmax(width, view_min_width + border_width);
|
||||
width = fmax(width, 1);
|
||||
height = fmin(height, view_max_height - border_height);
|
||||
height = fmax(height, view_min_height + border_height);
|
||||
height = fmax(height, 1);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -687,7 +687,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
}
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (!output->enabled && output != root->noop_output) {
|
||||
if (!output->enabled && output != root->fallback_output) {
|
||||
json_object_array_add(outputs,
|
||||
ipc_json_describe_disabled_output(output));
|
||||
}
|
||||
|
|
|
|||
40
sway/main.c
40
sway/main.c
|
|
@ -6,6 +6,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
|
||||
static bool terminate_request = false;
|
||||
static int exit_value = 0;
|
||||
static struct rlimit original_nofile_rlimit = {0};
|
||||
struct sway_server server = {0};
|
||||
struct sway_debug debug = {0};
|
||||
|
||||
|
|
@ -63,7 +65,7 @@ void detect_proprietary(int allow_unsupported_gpu) {
|
|||
sway_log(SWAY_ERROR,
|
||||
"Proprietary Nvidia drivers are NOT supported. "
|
||||
"Use Nouveau. To launch sway anyway, launch with "
|
||||
"--my-next-gpu-wont-be-nvidia and DO NOT report issues.");
|
||||
"--unsupported-gpu and DO NOT report issues.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -151,6 +153,9 @@ static void log_kernel(void) {
|
|||
|
||||
static bool drop_permissions(void) {
|
||||
if (getuid() != geteuid() || getgid() != getegid()) {
|
||||
sway_log(SWAY_ERROR, "!!! DEPRECATION WARNING: "
|
||||
"SUID privilege drop will be removed in a future release, please migrate to seatd-launch");
|
||||
|
||||
// Set the gid and uid in the correct order.
|
||||
if (setgid(getgid()) != 0) {
|
||||
sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start");
|
||||
|
|
@ -169,6 +174,33 @@ static bool drop_permissions(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void increase_nofile_limit(void) {
|
||||
if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
|
||||
sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: "
|
||||
"getrlimit(NOFILE) failed");
|
||||
return;
|
||||
}
|
||||
|
||||
struct rlimit new_rlimit = original_nofile_rlimit;
|
||||
new_rlimit.rlim_cur = new_rlimit.rlim_max;
|
||||
if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) {
|
||||
sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: "
|
||||
"setrlimit(NOFILE) failed");
|
||||
sway_log(SWAY_INFO, "Running with %d max open files",
|
||||
(int)original_nofile_rlimit.rlim_cur);
|
||||
}
|
||||
}
|
||||
|
||||
void restore_nofile_limit(void) {
|
||||
if (original_nofile_rlimit.rlim_cur == 0) {
|
||||
return;
|
||||
}
|
||||
if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
|
||||
sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: "
|
||||
"setrlimit(NOFILE) failed");
|
||||
}
|
||||
}
|
||||
|
||||
void enable_debug_flag(const char *flag) {
|
||||
if (strcmp(flag, "damage=highlight") == 0) {
|
||||
debug.damage = DAMAGE_HIGHLIGHT;
|
||||
|
|
@ -220,7 +252,6 @@ int main(int argc, char **argv) {
|
|||
{"verbose", no_argument, NULL, 'V'},
|
||||
{"get-socketpath", no_argument, NULL, 'p'},
|
||||
{"unsupported-gpu", no_argument, NULL, 'u'},
|
||||
{"my-next-gpu-wont-be-nvidia", no_argument, NULL, 'u'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
|
@ -314,7 +345,6 @@ int main(int argc, char **argv) {
|
|||
log_kernel();
|
||||
log_distro();
|
||||
log_env();
|
||||
detect_proprietary(allow_unsupported_gpu);
|
||||
|
||||
if (optind < argc) { // Behave as IPC client
|
||||
if (optind != 1) {
|
||||
|
|
@ -341,6 +371,8 @@ int main(int argc, char **argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
detect_proprietary(allow_unsupported_gpu);
|
||||
|
||||
if (!server_privileged_prepare(&server)) {
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -350,6 +382,8 @@ int main(int argc, char **argv) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
increase_nofile_limit();
|
||||
|
||||
// handle SIGTERM signals
|
||||
signal(SIGTERM, sig_handler);
|
||||
signal(SIGINT, sig_handler);
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ sway_sources = files(
|
|||
'commands/output/max_render_time.c',
|
||||
'commands/output/mode.c',
|
||||
'commands/output/position.c',
|
||||
'commands/output/render_bit_depth.c',
|
||||
'commands/output/scale.c',
|
||||
'commands/output/scale_filter.c',
|
||||
'commands/output/subpixel.c',
|
||||
|
|
|
|||
|
|
@ -7,17 +7,18 @@
|
|||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/backend/multi.h>
|
||||
#include <wlr/backend/noop.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/config.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_data_control_v1.h>
|
||||
#include <wlr/types/wlr_drm_lease_v1.h>
|
||||
#include <wlr/types/wlr_drm.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||
|
|
@ -73,12 +74,29 @@ static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
|
|||
bool server_init(struct sway_server *server) {
|
||||
sway_log(SWAY_DEBUG, "Initializing Wayland server");
|
||||
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend);
|
||||
assert(renderer);
|
||||
server->renderer = wlr_renderer_autocreate(server->backend);
|
||||
if (!server->renderer) {
|
||||
sway_log(SWAY_ERROR, "Failed to create renderer");
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_renderer_init_wl_display(renderer, server->wl_display);
|
||||
wlr_renderer_init_wl_shm(server->renderer, server->wl_display);
|
||||
|
||||
server->compositor = wlr_compositor_create(server->wl_display, renderer);
|
||||
if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) {
|
||||
wlr_drm_create(server->wl_display, server->renderer);
|
||||
server->linux_dmabuf_v1 =
|
||||
wlr_linux_dmabuf_v1_create(server->wl_display, server->renderer);
|
||||
}
|
||||
|
||||
server->allocator = wlr_allocator_autocreate(server->backend,
|
||||
server->renderer);
|
||||
if (!server->allocator) {
|
||||
sway_log(SWAY_ERROR, "Failed to create allocator");
|
||||
return false;
|
||||
}
|
||||
|
||||
server->compositor = wlr_compositor_create(server->wl_display,
|
||||
server->renderer);
|
||||
server->compositor_new_surface.notify = handle_compositor_new_surface;
|
||||
wl_signal_add(&server->compositor->events.new_surface,
|
||||
&server->compositor_new_surface);
|
||||
|
|
@ -206,20 +224,20 @@ bool server_init(struct sway_server *server) {
|
|||
return false;
|
||||
}
|
||||
|
||||
server->noop_backend = wlr_noop_backend_create(server->wl_display);
|
||||
|
||||
struct wlr_output *wlr_output = wlr_noop_add_output(server->noop_backend);
|
||||
root->noop_output = output_create(wlr_output);
|
||||
|
||||
server->headless_backend =
|
||||
wlr_headless_backend_create_with_renderer(server->wl_display, renderer);
|
||||
server->headless_backend = wlr_headless_backend_create(server->wl_display);
|
||||
if (!server->headless_backend) {
|
||||
sway_log(SWAY_INFO, "Failed to create secondary headless backend, "
|
||||
"starting without it");
|
||||
sway_log(SWAY_ERROR, "Failed to create secondary headless backend");
|
||||
wlr_backend_destroy(server->backend);
|
||||
return false;
|
||||
} else {
|
||||
wlr_multi_backend_add(server->backend, server->headless_backend);
|
||||
}
|
||||
|
||||
struct wlr_output *wlr_output =
|
||||
wlr_headless_add_output(server->headless_backend, 800, 600);
|
||||
wlr_output_set_name(wlr_output, "FALLBACK");
|
||||
root->fallback_output = output_create(wlr_output);
|
||||
|
||||
// This may have been set already via -Dtxn-timeout
|
||||
if (!server->txn_timeout_ms) {
|
||||
server->txn_timeout_ms = 200;
|
||||
|
|
@ -276,6 +294,7 @@ bool server_start(struct sway_server *server) {
|
|||
wlr_backend_destroy(server->backend);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,21 @@ must be separated by one space. For example:
|
|||
adaptive sync can improve latency, but can cause flickering on some
|
||||
hardware.
|
||||
|
||||
*output* <name> render_bit_depth 8|10
|
||||
Controls the color channel bit depth at which frames are rendered; the
|
||||
default is currently 8 bits per channel.
|
||||
|
||||
Setting higher values will not have an effect if hardware and software lack
|
||||
support for such bit depths. Successfully increasing the render bit depth
|
||||
will not necessarily increase the bit depth of the frames sent to a display.
|
||||
An increased render bit depth may provide smoother rendering of gradients,
|
||||
and screenshots which can more precisely store the colors of programs
|
||||
which display high bit depth colors.
|
||||
|
||||
Warnings: this can break screenshot/screencast programs which have not been
|
||||
updated to work with different bit depths. This command is experimental,
|
||||
and may be removed or changed in the future.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*sway*(5) *sway-input*(5)
|
||||
|
|
|
|||
|
|
@ -499,6 +499,12 @@ runtime.
|
|||
*client.focused_inactive*
|
||||
The most recently focused view within a container which is not focused.
|
||||
|
||||
*client.focused_tab_title*
|
||||
A view that has focused descendant container.
|
||||
Tab or stack container title that is the parent of the focused container
|
||||
but is not directly focused. Defaults to focused_inactive if not
|
||||
specified and does not use the indicator and child_border colors.
|
||||
|
||||
*client.placeholder*
|
||||
Ignored (present for i3 compatibility).
|
||||
|
||||
|
|
@ -554,6 +560,12 @@ The default colors are:
|
|||
: #ffffff
|
||||
: #484e50
|
||||
: #5f676a
|
||||
| *focused_tab_title*
|
||||
: #333333
|
||||
: #5f676a
|
||||
: #ffffff
|
||||
: n/a
|
||||
: n/a
|
||||
| *unfocused*
|
||||
: #333333
|
||||
: #222222
|
||||
|
|
@ -692,9 +704,10 @@ The default colors are:
|
|||
borders will only be enabled if the workspace has more than one visible
|
||||
child and gaps equal to zero.
|
||||
|
||||
*smart_gaps* on|off
|
||||
*smart_gaps* on|off|toggle|inverse_outer
|
||||
If smart_gaps are _on_ gaps will only be enabled if a workspace has more
|
||||
than one child.
|
||||
than one child. If smart_gaps are _inverse_outer_ outer gaps will only
|
||||
be enabled if a workspace has exactly one child.
|
||||
|
||||
*mark* --add|--replace [--toggle] <identifier>
|
||||
Marks are arbitrary labels that can be used to identify certain windows and
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ bool swaynag_spawn(const char *swaynag_command,
|
|||
sway_log(SWAY_ERROR, "Failed to create fork for swaynag");
|
||||
goto failed;
|
||||
} else if (pid == 0) {
|
||||
restore_nofile_limit();
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
sway_log_errno(SWAY_ERROR, "fork failed");
|
||||
|
|
|
|||
|
|
@ -5,8 +5,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/stat.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include "linux-dmabuf-unstable-v1-protocol.h"
|
||||
#include "cairo_util.h"
|
||||
#include "pango.h"
|
||||
#include "sway/config.h"
|
||||
|
|
@ -64,6 +68,7 @@ void container_destroy(struct sway_container *con) {
|
|||
wlr_texture_destroy(con->title_focused_inactive);
|
||||
wlr_texture_destroy(con->title_unfocused);
|
||||
wlr_texture_destroy(con->title_urgent);
|
||||
wlr_texture_destroy(con->title_focused_tab_title);
|
||||
list_free(con->pending.children);
|
||||
list_free(con->current.children);
|
||||
list_free(con->outputs);
|
||||
|
|
@ -73,11 +78,10 @@ void container_destroy(struct sway_container *con) {
|
|||
wlr_texture_destroy(con->marks_focused_inactive);
|
||||
wlr_texture_destroy(con->marks_unfocused);
|
||||
wlr_texture_destroy(con->marks_urgent);
|
||||
wlr_texture_destroy(con->marks_focused_tab_title);
|
||||
|
||||
if (con->view) {
|
||||
if (con->view->container == con) {
|
||||
con->view->container = NULL;
|
||||
}
|
||||
if (con->view && con->view->container == con) {
|
||||
con->view->container = NULL;
|
||||
if (con->view->destroying) {
|
||||
view_destroy(con->view);
|
||||
}
|
||||
|
|
@ -382,19 +386,17 @@ struct sway_container *tiling_container_at(struct sway_node *parent,
|
|||
}
|
||||
|
||||
static bool surface_is_popup(struct wlr_surface *surface) {
|
||||
if (wlr_surface_is_xdg_surface(surface)) {
|
||||
struct wlr_xdg_surface *xdg_surface =
|
||||
wlr_xdg_surface_from_wlr_surface(surface);
|
||||
while (xdg_surface && xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) {
|
||||
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
|
||||
return true;
|
||||
}
|
||||
xdg_surface = xdg_surface->toplevel->parent;
|
||||
while (!wlr_surface_is_xdg_surface(surface)) {
|
||||
if (!wlr_surface_is_subsurface(surface)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
struct wlr_subsurface *subsurface =
|
||||
wlr_subsurface_from_wlr_surface(surface);
|
||||
surface = subsurface->parent;
|
||||
}
|
||||
|
||||
return false;
|
||||
struct wlr_xdg_surface *xdg_surface =
|
||||
wlr_xdg_surface_from_wlr_surface(surface);
|
||||
return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP;
|
||||
}
|
||||
|
||||
struct sway_container *container_at(struct sway_workspace *workspace,
|
||||
|
|
@ -532,6 +534,13 @@ static void render_titlebar_text_texture(struct sway_output *output,
|
|||
|
||||
cairo_surface_t *surface = cairo_image_surface_create(
|
||||
CAIRO_FORMAT_ARGB32, width, height);
|
||||
cairo_status_t status = cairo_surface_status(surface);
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s",
|
||||
cairo_status_to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_t *cairo = cairo_create(surface);
|
||||
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
|
||||
cairo_set_font_options(cairo, fo);
|
||||
|
|
@ -549,8 +558,7 @@ static void render_titlebar_text_texture(struct sway_output *output,
|
|||
cairo_surface_flush(surface);
|
||||
unsigned char *data = cairo_image_surface_get_data(surface);
|
||||
int stride = cairo_image_surface_get_stride(surface);
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(
|
||||
output->wlr_output->backend);
|
||||
struct wlr_renderer *renderer = output->wlr_output->renderer;
|
||||
*texture = wlr_texture_from_pixels(
|
||||
renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
|
||||
cairo_surface_destroy(surface);
|
||||
|
|
@ -585,6 +593,8 @@ void container_update_title_textures(struct sway_container *container) {
|
|||
&config->border_colors.unfocused);
|
||||
update_title_texture(container, &container->title_urgent,
|
||||
&config->border_colors.urgent);
|
||||
update_title_texture(container, &container->title_focused_tab_title,
|
||||
&config->border_colors.focused_tab_title);
|
||||
container_damage_whole(container);
|
||||
}
|
||||
|
||||
|
|
@ -1050,6 +1060,16 @@ void container_end_mouse_operation(struct sway_container *container) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool devid_from_fd(int fd, dev_t *devid) {
|
||||
struct stat stat;
|
||||
if (fstat(fd, &stat) != 0) {
|
||||
sway_log_errno(SWAY_ERROR, "fstat failed");
|
||||
return false;
|
||||
}
|
||||
*devid = stat.st_rdev;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_fullscreen(struct sway_container *con, bool enable) {
|
||||
if (!con->view) {
|
||||
return;
|
||||
|
|
@ -1061,6 +1081,75 @@ static void set_fullscreen(struct sway_container *con, bool enable) {
|
|||
con->view->foreign_toplevel, enable);
|
||||
}
|
||||
}
|
||||
|
||||
if (!server.linux_dmabuf_v1 || !con->view->surface) {
|
||||
return;
|
||||
}
|
||||
if (!enable) {
|
||||
wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1,
|
||||
con->view->surface, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!con->pending.workspace || !con->pending.workspace->output) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct sway_output *output = con->pending.workspace->output;
|
||||
struct wlr_output *wlr_output = output->wlr_output;
|
||||
|
||||
// TODO: add wlroots helpers for all of this stuff
|
||||
|
||||
const struct wlr_drm_format_set *renderer_formats =
|
||||
wlr_renderer_get_dmabuf_texture_formats(server.renderer);
|
||||
assert(renderer_formats);
|
||||
|
||||
int renderer_drm_fd = wlr_renderer_get_drm_fd(server.renderer);
|
||||
int backend_drm_fd = wlr_backend_get_drm_fd(wlr_output->backend);
|
||||
if (renderer_drm_fd < 0 || backend_drm_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dev_t render_dev, scanout_dev;
|
||||
if (!devid_from_fd(renderer_drm_fd, &render_dev) ||
|
||||
!devid_from_fd(backend_drm_fd, &scanout_dev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const struct wlr_drm_format_set *output_formats =
|
||||
wlr_output_get_primary_formats(output->wlr_output,
|
||||
WLR_BUFFER_CAP_DMABUF);
|
||||
if (!output_formats) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_drm_format_set scanout_formats = {0};
|
||||
if (!wlr_drm_format_set_intersect(&scanout_formats,
|
||||
output_formats, renderer_formats)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_linux_dmabuf_feedback_v1_tranche tranches[] = {
|
||||
{
|
||||
.target_device = scanout_dev,
|
||||
.flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
|
||||
.formats = &scanout_formats,
|
||||
},
|
||||
{
|
||||
.target_device = render_dev,
|
||||
.formats = renderer_formats,
|
||||
},
|
||||
};
|
||||
|
||||
const struct wlr_linux_dmabuf_feedback_v1 feedback = {
|
||||
.main_device = render_dev,
|
||||
.tranches = tranches,
|
||||
.tranches_len = sizeof(tranches) / sizeof(tranches[0]),
|
||||
};
|
||||
wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1,
|
||||
con->view->surface, &feedback);
|
||||
|
||||
wlr_drm_format_set_finish(&scanout_formats);
|
||||
}
|
||||
|
||||
static void container_fullscreen_workspace(struct sway_container *con) {
|
||||
|
|
@ -1638,6 +1727,8 @@ void container_update_marks_textures(struct sway_container *con) {
|
|||
&config->border_colors.unfocused);
|
||||
update_marks_texture(con, &con->marks_urgent,
|
||||
&config->border_colors.urgent);
|
||||
update_marks_texture(con, &con->marks_focused_tab_title,
|
||||
&config->border_colors.focused_tab_title);
|
||||
container_damage_whole(con);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ static void restore_workspaces(struct sway_output *output) {
|
|||
}
|
||||
|
||||
// Saved workspaces
|
||||
while (root->noop_output->workspaces->length) {
|
||||
struct sway_workspace *ws = root->noop_output->workspaces->items[0];
|
||||
while (root->fallback_output->workspaces->length) {
|
||||
struct sway_workspace *ws = root->fallback_output->workspaces->items[0];
|
||||
workspace_detach(ws);
|
||||
output_add_workspace(output, ws);
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
|
|||
output->detected_subpixel = wlr_output->subpixel;
|
||||
output->scale_filter = SCALE_FILTER_NEAREST;
|
||||
|
||||
wl_signal_init(&output->events.destroy);
|
||||
wl_signal_init(&output->events.disable);
|
||||
|
||||
wl_list_insert(&root->all_outputs, &output->link);
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ static void output_evacuate(struct sway_output *output) {
|
|||
new_output = fallback_output;
|
||||
}
|
||||
if (!new_output) {
|
||||
new_output = root->noop_output;
|
||||
new_output = root->fallback_output;
|
||||
}
|
||||
|
||||
struct sway_workspace *new_output_ws =
|
||||
|
|
@ -262,7 +262,7 @@ void output_disable(struct sway_output *output) {
|
|||
}
|
||||
|
||||
sway_log(SWAY_DEBUG, "Disabling output '%s'", output->wlr_output->name);
|
||||
wl_signal_emit(&output->events.destroy, output);
|
||||
wl_signal_emit(&output->events.disable, output);
|
||||
|
||||
output_evacuate(output);
|
||||
|
||||
|
|
@ -286,13 +286,10 @@ void output_begin_destroy(struct sway_output *output) {
|
|||
return;
|
||||
}
|
||||
sway_log(SWAY_DEBUG, "Destroying output '%s'", output->wlr_output->name);
|
||||
wl_signal_emit(&output->node.events.destroy, &output->node);
|
||||
|
||||
output->node.destroying = true;
|
||||
node_set_dirty(&output->node);
|
||||
|
||||
wl_list_remove(&output->link);
|
||||
output->wlr_output->data = NULL;
|
||||
output->wlr_output = NULL;
|
||||
}
|
||||
|
||||
struct sway_output *output_from_wlr_output(struct wlr_output *output) {
|
||||
|
|
|
|||
|
|
@ -374,8 +374,8 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data),
|
|||
}
|
||||
|
||||
// Saved workspaces
|
||||
for (int i = 0; i < root->noop_output->workspaces->length; ++i) {
|
||||
struct sway_workspace *ws = root->noop_output->workspaces->items[i];
|
||||
for (int i = 0; i < root->fallback_output->workspaces->length; ++i) {
|
||||
struct sway_workspace *ws = root->fallback_output->workspaces->items[i];
|
||||
workspace_for_each_container(ws, f, data);
|
||||
}
|
||||
}
|
||||
|
|
@ -427,8 +427,8 @@ struct sway_container *root_find_container(
|
|||
}
|
||||
|
||||
// Saved workspaces
|
||||
for (int i = 0; i < root->noop_output->workspaces->length; ++i) {
|
||||
struct sway_workspace *ws = root->noop_output->workspaces->items[i];
|
||||
for (int i = 0; i < root->fallback_output->workspaces->length; ++i) {
|
||||
struct sway_workspace *ws = root->fallback_output->workspaces->items[i];
|
||||
if ((result = workspace_find_container(ws, test, data))) {
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -752,10 +752,29 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
|
|||
}
|
||||
|
||||
struct sway_seat *seat = input_manager_current_seat();
|
||||
struct sway_node *node = ws ? seat_get_focus_inactive(seat, &ws->node)
|
||||
: seat_get_focus_inactive(seat, &root->node);
|
||||
struct sway_container *target_sibling = node->type == N_CONTAINER ?
|
||||
node->sway_container : NULL;
|
||||
struct sway_node *node =
|
||||
seat_get_focus_inactive(seat, ws ? &ws->node : &root->node);
|
||||
struct sway_container *target_sibling = NULL;
|
||||
if (node && node->type == N_CONTAINER) {
|
||||
if (container_is_floating(node->sway_container)) {
|
||||
// If we're about to launch the view into the floating container, then
|
||||
// launch it as a tiled view instead.
|
||||
if (ws) {
|
||||
target_sibling = seat_get_focus_inactive_tiling(seat, ws);
|
||||
if (target_sibling) {
|
||||
struct sway_container *con =
|
||||
seat_get_focus_inactive_view(seat, &target_sibling->node);
|
||||
if (con) {
|
||||
target_sibling = con;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ws = seat_get_last_known_workspace(seat);
|
||||
}
|
||||
} else {
|
||||
target_sibling = node->sway_container;
|
||||
}
|
||||
}
|
||||
|
||||
view->foreign_toplevel =
|
||||
wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager);
|
||||
|
|
@ -776,13 +795,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
|
|||
&view->foreign_minimize);
|
||||
|
||||
|
||||
// If we're about to launch the view into the floating container, then
|
||||
// launch it as a tiled view in the root of the workspace instead.
|
||||
if (target_sibling && container_is_floating(target_sibling)) {
|
||||
target_sibling = NULL;
|
||||
ws = seat_get_last_known_workspace(seat);
|
||||
}
|
||||
|
||||
struct sway_container *container = view->container;
|
||||
if (target_sibling) {
|
||||
container_add_sibling(target_sibling, container, 1);
|
||||
|
|
@ -1129,9 +1141,12 @@ void view_child_init(struct sway_view_child *child,
|
|||
wl_signal_add(&view->events.unmap, &child->view_unmap);
|
||||
child->view_unmap.notify = view_child_handle_view_unmap;
|
||||
|
||||
struct sway_workspace *workspace = child->view->container->pending.workspace;
|
||||
if (workspace) {
|
||||
wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
|
||||
struct sway_container *container = child->view->container;
|
||||
if (container != NULL) {
|
||||
struct sway_workspace *workspace = container->pending.workspace;
|
||||
if (workspace) {
|
||||
wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
|
||||
}
|
||||
}
|
||||
|
||||
view_child_init_subsurfaces(child, surface);
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ struct sway_output *workspace_get_initial_output(const char *name) {
|
|||
} else if (focus && focus->type == N_CONTAINER) {
|
||||
return focus->sway_container->pending.workspace->output;
|
||||
}
|
||||
// Fallback to the first output or noop output for headless
|
||||
return root->outputs->length ? root->outputs->items[0] : root->noop_output;
|
||||
// Fallback to the first output or the headless output
|
||||
return root->outputs->length ? root->outputs->items[0] : root->fallback_output;
|
||||
}
|
||||
|
||||
struct sway_workspace *workspace_create(struct sway_output *output,
|
||||
|
|
@ -844,24 +844,36 @@ struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace,
|
|||
return con;
|
||||
}
|
||||
|
||||
bool workspace_has_single_visible_container(struct sway_workspace *ws) {
|
||||
struct sway_seat *seat = input_manager_get_default_seat();
|
||||
struct sway_container *focus =
|
||||
seat_get_focus_inactive_tiling(seat, ws);
|
||||
if (focus && !focus->view) {
|
||||
focus = seat_get_focus_inactive_view(seat, &focus->node);
|
||||
}
|
||||
return (focus && focus->view && view_ancestor_is_only_visible(focus->view));
|
||||
}
|
||||
|
||||
void workspace_add_gaps(struct sway_workspace *ws) {
|
||||
if (config->smart_gaps) {
|
||||
struct sway_seat *seat = input_manager_get_default_seat();
|
||||
struct sway_container *focus =
|
||||
seat_get_focus_inactive_tiling(seat, ws);
|
||||
if (focus && !focus->view) {
|
||||
focus = seat_get_focus_inactive_view(seat, &focus->node);
|
||||
}
|
||||
if (focus && focus->view && view_ancestor_is_only_visible(focus->view)) {
|
||||
ws->current_gaps.top = 0;
|
||||
ws->current_gaps.right = 0;
|
||||
ws->current_gaps.bottom = 0;
|
||||
ws->current_gaps.left = 0;
|
||||
return;
|
||||
}
|
||||
if (config->smart_gaps == SMART_GAPS_ON
|
||||
&& workspace_has_single_visible_container(ws)) {
|
||||
ws->current_gaps.top = 0;
|
||||
ws->current_gaps.right = 0;
|
||||
ws->current_gaps.bottom = 0;
|
||||
ws->current_gaps.left = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (config->smart_gaps == SMART_GAPS_INVERSE_OUTER
|
||||
&& !workspace_has_single_visible_container(ws)) {
|
||||
ws->current_gaps.top = 0;
|
||||
ws->current_gaps.right = 0;
|
||||
ws->current_gaps.bottom = 0;
|
||||
ws->current_gaps.left = 0;
|
||||
} else {
|
||||
ws->current_gaps = ws->gaps_outer;
|
||||
}
|
||||
|
||||
ws->current_gaps = ws->gaps_outer;
|
||||
// Add inner gaps and make sure we don't turn out negative
|
||||
ws->current_gaps.top = fmax(0, ws->current_gaps.top + ws->gaps_inner);
|
||||
ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue