Merge pull request #1 from swaywm/v1.7

V1.7
This commit is contained in:
William McKinnon 2022-04-26 21:44:51 -04:00 committed by GitHub
commit 4660771f6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
77 changed files with 703 additions and 306 deletions

View file

@ -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 },

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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");
}

View 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;
}

View file

@ -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();

View file

@ -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,

View file

@ -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);

View file

@ -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");

View file

@ -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");

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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,

View file

@ -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,
};

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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);

View file

@ -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',

View file

@ -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;
}

View file

@ -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)

View file

@ -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

View file

@ -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");

View file

@ -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);
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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);

View file

@ -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);