Merge branch 'master' into session-lock-input-fix

This commit is contained in:
Erik Reider 2026-02-06 14:34:04 +01:00 committed by GitHub
commit 6b3b69e3c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 224 additions and 124 deletions

View file

@ -267,6 +267,12 @@ enum render_bit_depth {
RENDER_BIT_DEPTH_10, RENDER_BIT_DEPTH_10,
}; };
enum color_profile {
COLOR_PROFILE_DEFAULT, // default is Transform with NULL color_transform
COLOR_PROFILE_TRANSFORM, // use color_transform from output_config
COLOR_PROFILE_TRANSFORM_WITH_DEVICE_PRIMARIES, // create transform from wlr_output
};
/** /**
* Size and position configuration for a particular output. * Size and position configuration for a particular output.
* *
@ -288,7 +294,7 @@ struct output_config {
int max_render_time; // In milliseconds int max_render_time; // In milliseconds
int adaptive_sync; int adaptive_sync;
enum render_bit_depth render_bit_depth; enum render_bit_depth render_bit_depth;
bool set_color_transform; enum color_profile color_profile;
struct wlr_color_transform *color_transform; struct wlr_color_transform *color_transform;
int allow_tearing; int allow_tearing;
int hdr; int hdr;

View file

@ -160,7 +160,7 @@ struct sway_debug {
extern struct sway_debug debug; extern struct sway_debug debug;
extern bool allow_unsupported_gpu; extern bool unsupported_gpu_detected;
void sway_terminate(int exit_code); void sway_terminate(int exit_code);

View file

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="idle">
<copyright><![CDATA[
Copyright (C) 2015 Martin Gräßlin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]></copyright>
<interface name="org_kde_kwin_idle" version="1">
<description summary="User idle time manager">
This interface allows to monitor user idle time on a given seat. The interface
allows to register timers which trigger after no user activity was registered
on the seat for a given interval. It notifies when user activity resumes.
This is useful for applications wanting to perform actions when the user is not
interacting with the system, e.g. chat applications setting the user as away, power
management features to dim screen, etc..
</description>
<request name="get_idle_timeout">
<arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="timeout" type="uint" summary="The idle timeout in msec"/>
</request>
</interface>
<interface name="org_kde_kwin_idle_timeout" version="1">
<request name="release" type="destructor">
<description summary="release the timeout object"/>
</request>
<request name="simulate_user_activity">
<description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/>
</request>
<event name="idle">
<description summary="Triggered when there has not been any user activity in the requested idle time interval"/>
</event>
<event name="resumed">
<description summary="Triggered on the first user activity after an idle event"/>
</event>
</interface>
</protocol>

View file

@ -12,7 +12,6 @@ protocols = [
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
'wlr-layer-shell-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml',
'idle.xml',
'wlr-output-power-management-unstable-v1.xml', 'wlr-output-power-management-unstable-v1.xml',
] ]

View file

@ -72,6 +72,10 @@ static struct cmd_results *parse_three_colors(char ***colors,
} }
struct cmd_results *bar_cmd_colors(int argc, char **argv) { struct cmd_results *bar_cmd_colors(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "colors", EXPECTED_AT_LEAST, 1))) {
return error;
}
return config_subcommand(argv, argc, bar_colors_handlers, return config_subcommand(argv, argc, bar_colors_handlers,
sizeof(bar_colors_handlers)); sizeof(bar_colors_handlers));
} }

View file

@ -137,11 +137,15 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
// If parent has only a singe child operate on its parent and // If parent has only a singe child operate on its parent and
// flatten once, like i3 // flatten once, like i3
if (container && container->pending.children->length == 1) { if (container && container->pending.children->length == 1) {
struct sway_container *child = container->pending.children->items[0]; // Also check grandparent to avoid restricting layouts
struct sway_container *parent = container->pending.parent; struct sway_container *parent = container->pending.parent;
container_replace(container, child); if (parent && parent->pending.children->length == 1) {
container_begin_destroy(container); struct sway_container *child = container->pending.children->items[0];
container = parent; struct sway_container *parent = container->pending.parent;
container_replace(container, child);
container_begin_destroy(container);
container = parent;
}
} }
} }

View file

@ -55,14 +55,30 @@ struct cmd_results *output_cmd_color_profile(int argc, char **argv) {
if (!config->handler_context.output_config) { if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config"); return cmd_results_new(CMD_FAILURE, "Missing output config");
} }
enum color_profile new_mode = COLOR_PROFILE_TRANSFORM;
if (argc >= 2 && strcmp(*argv, "--device-primaries") == 0) {
new_mode = COLOR_PROFILE_TRANSFORM_WITH_DEVICE_PRIMARIES;
argc--;
argv++;
}
if (!argc) { if (!argc) {
return cmd_results_new(CMD_INVALID, "Missing color_profile first argument."); return cmd_results_new(CMD_INVALID, "Missing color_profile first argument.");
} }
if (strcmp(*argv, "srgb") == 0) { if (strcmp(*argv, "gamma22") == 0) {
wlr_color_transform_unref(config->handler_context.output_config->color_transform); wlr_color_transform_unref(config->handler_context.output_config->color_transform);
config->handler_context.output_config->color_transform = NULL; config->handler_context.output_config->color_transform = NULL;
config->handler_context.output_config->set_color_transform = true; config->handler_context.output_config->color_profile = new_mode;
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
} else if (strcmp(*argv, "srgb") == 0) {
wlr_color_transform_unref(config->handler_context.output_config->color_transform);
config->handler_context.output_config->color_transform =
wlr_color_transform_init_linear_to_inverse_eotf(WLR_COLOR_TRANSFER_FUNCTION_SRGB);
config->handler_context.output_config->color_profile = new_mode;
config->handler_context.leftovers.argc = argc - 1; config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1; config->handler_context.leftovers.argv = argv + 1;
@ -71,6 +87,10 @@ struct cmd_results *output_cmd_color_profile(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, return cmd_results_new(CMD_INVALID,
"Invalid color profile specification: icc type requires a file"); "Invalid color profile specification: icc type requires a file");
} }
if (new_mode != COLOR_PROFILE_TRANSFORM) {
return cmd_results_new(CMD_INVALID,
"Invalid color profile specification: --device-primaries cannot be used with icc");
}
char *icc_path = strdup(argv[1]); char *icc_path = strdup(argv[1]);
if (!expand_path(&icc_path)) { if (!expand_path(&icc_path)) {
@ -100,13 +120,14 @@ struct cmd_results *output_cmd_color_profile(int argc, char **argv) {
wlr_color_transform_unref(config->handler_context.output_config->color_transform); wlr_color_transform_unref(config->handler_context.output_config->color_transform);
config->handler_context.output_config->color_transform = tmp; config->handler_context.output_config->color_transform = tmp;
config->handler_context.output_config->set_color_transform = true; config->handler_context.output_config->color_profile = COLOR_PROFILE_TRANSFORM;
config->handler_context.leftovers.argc = argc - 2; config->handler_context.leftovers.argc = argc - 2;
config->handler_context.leftovers.argv = argv + 2; config->handler_context.leftovers.argv = argv + 2;
} else { } else {
return cmd_results_new(CMD_INVALID, return cmd_results_new(CMD_INVALID,
"Invalid color profile specification: first argument should be icc|srgb"); "Invalid color profile specification: "
"first argument should be gamma22|icc|srgb");
} }
return NULL; return NULL;

View file

@ -75,7 +75,7 @@ struct output_config *new_output_config(const char *name) {
oc->max_render_time = -1; oc->max_render_time = -1;
oc->adaptive_sync = -1; oc->adaptive_sync = -1;
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
oc->set_color_transform = false; oc->color_profile = COLOR_PROFILE_DEFAULT;
oc->color_transform = NULL; oc->color_transform = NULL;
oc->power = -1; oc->power = -1;
oc->allow_tearing = -1; oc->allow_tearing = -1;
@ -130,12 +130,12 @@ static void supersede_output_config(struct output_config *dst, struct output_con
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
} }
if (src->set_color_transform) { if (src->color_profile != COLOR_PROFILE_DEFAULT) {
if (dst->color_transform) { if (dst->color_transform) {
wlr_color_transform_unref(dst->color_transform); wlr_color_transform_unref(dst->color_transform);
dst->color_transform = NULL; dst->color_transform = NULL;
} }
dst->set_color_transform = false; dst->color_profile = COLOR_PROFILE_DEFAULT;
} }
if (src->background) { if (src->background) {
free(dst->background); free(dst->background);
@ -207,12 +207,12 @@ static void merge_output_config(struct output_config *dst, struct output_config
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = src->render_bit_depth; dst->render_bit_depth = src->render_bit_depth;
} }
if (src->set_color_transform) { if (src->color_profile != COLOR_PROFILE_DEFAULT) {
if (src->color_transform) { if (src->color_transform) {
wlr_color_transform_ref(src->color_transform); wlr_color_transform_ref(src->color_transform);
} }
wlr_color_transform_unref(dst->color_transform); wlr_color_transform_unref(dst->color_transform);
dst->set_color_transform = true; dst->color_profile = src->color_profile;
dst->color_transform = src->color_transform; dst->color_transform = src->color_transform;
} }
if (src->background) { if (src->background) {
@ -562,8 +562,75 @@ static void queue_output_config(struct output_config *oc,
set_hdr(wlr_output, pending, hdr); set_hdr(wlr_output, pending, hdr);
} }
struct config_output_state {
struct wlr_color_transform *color_transform;
};
static void config_output_state_finish(struct config_output_state *state) {
wlr_color_transform_unref(state->color_transform);
}
static struct wlr_color_transform *color_profile_from_device(struct wlr_output *wlr_output,
struct wlr_color_transform *transfer_function) {
struct wlr_color_primaries srgb_primaries;
wlr_color_primaries_from_named(&srgb_primaries, WLR_COLOR_NAMED_PRIMARIES_SRGB);
const struct wlr_color_primaries *primaries = wlr_output->default_primaries;
if (primaries == NULL) {
sway_log(SWAY_INFO, "output has no reported color information");
if (transfer_function) {
wlr_color_transform_ref(transfer_function);
}
return transfer_function;
} else if (memcmp(primaries, &srgb_primaries, sizeof(*primaries)) == 0) {
sway_log(SWAY_INFO, "output reports sRGB colors, no correction needed");
if (transfer_function) {
wlr_color_transform_ref(transfer_function);
}
return transfer_function;
} else {
sway_log(SWAY_INFO, "Creating color profile from reported color primaries: "
"R(%f, %f) G(%f, %f) B(%f, %f) W(%f, %f)",
primaries->red.x, primaries->red.y, primaries->green.x, primaries->green.y,
primaries->blue.x, primaries->blue.y, primaries->white.x, primaries->white.y);
float matrix[9];
wlr_color_primaries_transform_absolute_colorimetric(&srgb_primaries, primaries, matrix);
struct wlr_color_transform *matrix_transform = wlr_color_transform_init_matrix(matrix);
if (matrix_transform == NULL) {
return NULL;
}
struct wlr_color_transform *resolved_tf = transfer_function ?
wlr_color_transform_ref(transfer_function) :
wlr_color_transform_init_linear_to_inverse_eotf(WLR_COLOR_TRANSFER_FUNCTION_GAMMA22);
if (resolved_tf == NULL) {
wlr_color_transform_unref(matrix_transform);
return NULL;
}
struct wlr_color_transform *transforms[] = { matrix_transform, resolved_tf };
size_t transforms_len = sizeof(transforms) / sizeof(transforms[0]);
struct wlr_color_transform *result = wlr_color_transform_init_pipeline(transforms, transforms_len);
wlr_color_transform_unref(matrix_transform);
wlr_color_transform_unref(resolved_tf);
return result;
}
}
static struct wlr_color_transform *get_color_profile(struct wlr_output *output,
struct output_config *oc) {
if (oc && oc->color_profile == COLOR_PROFILE_TRANSFORM) {
if (oc->color_transform) {
wlr_color_transform_ref(oc->color_transform);
}
return oc->color_transform;
} else if (oc && oc->color_profile == COLOR_PROFILE_TRANSFORM_WITH_DEVICE_PRIMARIES) {
return color_profile_from_device(output, oc->color_transform);
} else {
return NULL;
}
}
static bool finalize_output_config(struct output_config *oc, struct sway_output *output, static bool finalize_output_config(struct output_config *oc, struct sway_output *output,
const struct wlr_output_state *applied) { const struct wlr_output_state *applied, const struct config_output_state *config_applied) {
if (output == root->fallback_output) { if (output == root->fallback_output) {
return false; return false;
} }
@ -609,16 +676,11 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
output_enable(output); output_enable(output);
} }
if (oc && oc->set_color_transform) { wlr_color_transform_unref(output->color_transform);
if (oc->color_transform) { if (config_applied->color_transform != NULL) {
wlr_color_transform_ref(oc->color_transform); wlr_color_transform_ref(config_applied->color_transform);
}
wlr_color_transform_unref(output->color_transform);
output->color_transform = oc->color_transform;
} else {
wlr_color_transform_unref(output->color_transform);
output->color_transform = NULL;
} }
output->color_transform = config_applied->color_transform;
output->max_render_time = oc && oc->max_render_time > 0 ? oc->max_render_time : 0; output->max_render_time = oc && oc->max_render_time > 0 ? oc->max_render_time : 0;
output->allow_tearing = oc && oc->allow_tearing > 0; output->allow_tearing = oc && oc->allow_tearing > 0;
@ -935,17 +997,25 @@ static bool apply_resolved_output_configs(struct matched_output_config *configs,
if (!states) { if (!states) {
return false; return false;
} }
struct config_output_state *config_states = calloc(configs_len, sizeof(*config_states));
if (!config_states) {
free(states);
return false;
}
sway_log(SWAY_DEBUG, "Committing %zd outputs", configs_len); sway_log(SWAY_DEBUG, "Committing %zd outputs", configs_len);
for (size_t idx = 0; idx < configs_len; idx++) { for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx]; struct matched_output_config *cfg = &configs[idx];
struct wlr_backend_output_state *backend_state = &states[idx]; struct wlr_backend_output_state *backend_state = &states[idx];
struct config_output_state *config_state = &config_states[idx];
backend_state->output = cfg->output->wlr_output; backend_state->output = cfg->output->wlr_output;
wlr_output_state_init(&backend_state->base); wlr_output_state_init(&backend_state->base);
queue_output_config(cfg->config, cfg->output, &backend_state->base); queue_output_config(cfg->config, cfg->output, &backend_state->base);
dump_output_state(cfg->output->wlr_output, &backend_state->base); dump_output_state(cfg->output->wlr_output, &backend_state->base);
config_state->color_transform = get_color_profile(cfg->output->wlr_output, cfg->config);
} }
struct wlr_output_swapchain_manager swapchain_mgr; struct wlr_output_swapchain_manager swapchain_mgr;
@ -975,11 +1045,12 @@ static bool apply_resolved_output_configs(struct matched_output_config *configs,
for (size_t idx = 0; idx < configs_len; idx++) { for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx]; struct matched_output_config *cfg = &configs[idx];
struct wlr_backend_output_state *backend_state = &states[idx]; struct wlr_backend_output_state *backend_state = &states[idx];
struct config_output_state *config_state = &config_states[idx];
struct wlr_scene_output_state_options opts = { struct wlr_scene_output_state_options opts = {
.swapchain = wlr_output_swapchain_manager_get_swapchain( .swapchain = wlr_output_swapchain_manager_get_swapchain(
&swapchain_mgr, backend_state->output), &swapchain_mgr, backend_state->output),
.color_transform = cfg->output->color_transform, .color_transform = config_state->color_transform,
}; };
struct wlr_scene_output *scene_output = cfg->output->scene_output; struct wlr_scene_output *scene_output = cfg->output->scene_output;
struct wlr_output_state *state = &backend_state->base; struct wlr_output_state *state = &backend_state->base;
@ -1003,9 +1074,10 @@ static bool apply_resolved_output_configs(struct matched_output_config *configs,
for (size_t idx = 0; idx < configs_len; idx++) { for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx]; struct matched_output_config *cfg = &configs[idx];
struct wlr_backend_output_state *backend_state = &states[idx]; struct wlr_backend_output_state *backend_state = &states[idx];
struct config_output_state *config_state = &config_states[idx];
sway_log(SWAY_DEBUG, "Finalizing config for %s", sway_log(SWAY_DEBUG, "Finalizing config for %s",
cfg->output->wlr_output->name); cfg->output->wlr_output->name);
finalize_output_config(cfg->config, cfg->output, &backend_state->base); finalize_output_config(cfg->config, cfg->output, &backend_state->base, config_state);
} }
// Output layout being applied in finalize_output_config can shift outputs // Output layout being applied in finalize_output_config can shift outputs
@ -1026,8 +1098,10 @@ out:
for (size_t idx = 0; idx < configs_len; idx++) { for (size_t idx = 0; idx < configs_len; idx++) {
struct wlr_backend_output_state *backend_state = &states[idx]; struct wlr_backend_output_state *backend_state = &states[idx];
wlr_output_state_finish(&backend_state->base); wlr_output_state_finish(&backend_state->base);
config_output_state_finish(&config_states[idx]);
} }
free(states); free(states);
free(config_states);
// Reconfigure all devices, since input config may have been applied before // Reconfigure all devices, since input config may have been applied before
// this output came online, and some config items (like map_to_output) are // this output came online, and some config items (like map_to_output) are

View file

@ -354,6 +354,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_view->view; struct sway_view *view = &xdg_shell_view->view;
view_update_title(view, false); view_update_title(view, false);
view_execute_criteria(view); view_execute_criteria(view);
transaction_commit_dirty();
} }
static void handle_set_app_id(struct wl_listener *listener, void *data) { static void handle_set_app_id(struct wl_listener *listener, void *data) {
@ -362,6 +363,7 @@ static void handle_set_app_id(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_view->view; struct sway_view *view = &xdg_shell_view->view;
view_update_app_id(view); view_update_app_id(view);
view_execute_criteria(view); view_execute_criteria(view);
transaction_commit_dirty();
} }
static void handle_new_popup(struct wl_listener *listener, void *data) { static void handle_new_popup(struct wl_listener *listener, void *data) {
@ -384,6 +386,9 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view = struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_maximize); wl_container_of(listener, xdg_shell_view, request_maximize);
struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel; struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
if (!toplevel->base->surface->mapped) {
return;
}
wlr_xdg_surface_schedule_configure(toplevel->base); wlr_xdg_surface_schedule_configure(toplevel->base);
} }
@ -594,4 +599,5 @@ void xdg_toplevel_tag_manager_v1_handle_set_tag(struct wl_listener *listener, vo
free(xdg_shell_view->tag); free(xdg_shell_view->tag);
xdg_shell_view->tag = strdup(event->tag); xdg_shell_view->tag = strdup(event->tag);
view_execute_criteria(view); view_execute_criteria(view);
transaction_commit_dirty();
} }

View file

@ -689,6 +689,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) {
} }
view_update_title(view, false); view_update_title(view, false);
view_execute_criteria(view); view_execute_criteria(view);
transaction_commit_dirty();
} }
static void handle_set_class(struct wl_listener *listener, void *data) { static void handle_set_class(struct wl_listener *listener, void *data) {
@ -700,6 +701,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) {
return; return;
} }
view_execute_criteria(view); view_execute_criteria(view);
transaction_commit_dirty();
} }
static void handle_set_role(struct wl_listener *listener, void *data) { static void handle_set_role(struct wl_listener *listener, void *data) {
@ -711,6 +713,7 @@ static void handle_set_role(struct wl_listener *listener, void *data) {
return; return;
} }
view_execute_criteria(view); view_execute_criteria(view);
transaction_commit_dirty();
} }
static void handle_set_startup_id(struct wl_listener *listener, void *data) { static void handle_set_startup_id(struct wl_listener *listener, void *data) {
@ -747,6 +750,7 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) {
return; return;
} }
view_execute_criteria(view); view_execute_criteria(view);
transaction_commit_dirty();
} }
static void handle_set_hints(struct wl_listener *listener, void *data) { static void handle_set_hints(struct wl_listener *listener, void *data) {

View file

@ -644,6 +644,11 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
cursor_handle_activity_from_device(cursor, &event->tablet->base); cursor_handle_activity_from_device(cursor, &event->tablet->base);
struct sway_tablet_tool *sway_tool = event->tool->data; struct sway_tablet_tool *sway_tool = event->tool->data;
if (!sway_tool) {
sway_log(SWAY_DEBUG, "tool tip before proximity");
return;
}
struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2; struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2;
struct sway_seat *seat = cursor->seat; struct sway_seat *seat = cursor->seat;

View file

@ -1015,9 +1015,9 @@ void seat_configure_xcursor(struct sway_seat *seat) {
server.xwayland.xcursor_manager, "default", 1); server.xwayland.xcursor_manager, "default", 1);
if (xcursor != NULL) { if (xcursor != NULL) {
struct wlr_xcursor_image *image = xcursor->images[0]; struct wlr_xcursor_image *image = xcursor->images[0];
struct wlr_buffer *buffer = wlr_xcursor_image_get_buffer(image);
wlr_xwayland_set_cursor( wlr_xwayland_set_cursor(
server.xwayland.wlr_xwayland, image->buffer, server.xwayland.wlr_xwayland, buffer,
image->width * 4, image->width, image->height,
image->hotspot_x, image->hotspot_y); image->hotspot_x, image->hotspot_y);
} }
} }

View file

@ -105,10 +105,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
static void handle_unref(struct sway_seat *seat, struct sway_container *con) { static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
struct seatop_resize_tiling_event *e = seat->seatop_data; struct seatop_resize_tiling_event *e = seat->seatop_data;
if (e->con == con) { if (e->con == con || e->h_sib == con || e->v_sib == con) {
seatop_begin_default(seat);
}
if (e->h_sib == con || e->v_sib == con) {
seatop_begin_default(seat); seatop_begin_default(seat);
} }
} }

View file

@ -224,7 +224,7 @@ static const char usage[] =
"\n"; "\n";
int main(int argc, char **argv) { int main(int argc, char **argv) {
static bool verbose = false, debug = false, validate = false; bool verbose = false, debug = false, validate = false, allow_unsupported_gpu = false;
char *config_path = NULL; char *config_path = NULL;
@ -286,6 +286,12 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
char *unsupported_gpu_env = getenv("SWAY_UNSUPPORTED_GPU");
// we let the flag override the environment variable
if (!allow_unsupported_gpu && unsupported_gpu_env) {
allow_unsupported_gpu = parse_boolean(unsupported_gpu_env, false);
}
// As the 'callback' function for wlr_log is equivalent to that for // As the 'callback' function for wlr_log is equivalent to that for
// sway, we do not need to override it. // sway, we do not need to override it.
if (debug) { if (debug) {
@ -373,6 +379,20 @@ int main(int argc, char **argv) {
swaynag_show(&config->swaynag_config_errors); swaynag_show(&config->swaynag_config_errors);
} }
struct swaynag_instance nag_gpu = (struct swaynag_instance){
.args = "--type error "
"--message 'Proprietary GPU drivers are not supported by sway. Do not report issues.' "
"--detailed-message",
.detailed = true,
};
if (unsupported_gpu_detected && !allow_unsupported_gpu) {
swaynag_log(config->swaynag_command, &nag_gpu,
"To remove this message, launch sway with --unsupported-gpu "
"or set the environment variable SWAY_UNSUPPORTED_GPU=true.");
swaynag_show(&nag_gpu);
}
server_run(&server); server_run(&server);
shutdown: shutdown:
@ -385,6 +405,10 @@ shutdown:
free(config_path); free(config_path);
free_config(config); free_config(config);
if (nag_gpu.client != NULL) {
wl_client_destroy(nag_gpu.client);
}
pango_cairo_font_map_set_default(NULL); pango_cairo_font_map_set_default(NULL);
return exit_value; return exit_value;

View file

@ -11,6 +11,7 @@
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_alpha_modifier_v1.h> #include <wlr/types/wlr_alpha_modifier_v1.h>
#include <wlr/types/wlr_color_management_v1.h> #include <wlr/types/wlr_color_management_v1.h>
#include <wlr/types/wlr_color_representation_v1.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_content_type_v1.h> #include <wlr/types/wlr_content_type_v1.h>
#include <wlr/types/wlr_cursor_shape_v1.h> #include <wlr/types/wlr_cursor_shape_v1.h>
@ -77,7 +78,7 @@
#define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1 #define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1
#define SWAY_PRESENTATION_VERSION 2 #define SWAY_PRESENTATION_VERSION 2
bool allow_unsupported_gpu = false; bool unsupported_gpu_detected = false;
#if WLR_HAS_DRM_BACKEND #if WLR_HAS_DRM_BACKEND
static void handle_drm_lease_request(struct wl_listener *listener, void *data) { static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
@ -160,27 +161,16 @@ static void detect_proprietary(struct wlr_backend *backend, void *data) {
return; return;
} }
bool is_unsupported = false;
if (strcmp(version->name, "nvidia-drm") == 0) { if (strcmp(version->name, "nvidia-drm") == 0) {
is_unsupported = true; unsupported_gpu_detected = true;
sway_log(SWAY_ERROR, "!!! Proprietary Nvidia drivers are in use !!!"); sway_log(SWAY_ERROR, "!!! Proprietary Nvidia drivers are in use !!!");
if (!allow_unsupported_gpu) {
sway_log(SWAY_ERROR, "Use Nouveau instead");
}
} }
if (strcmp(version->name, "evdi") == 0) { if (strcmp(version->name, "evdi") == 0) {
is_unsupported = true; unsupported_gpu_detected = true;
sway_log(SWAY_ERROR, "!!! Proprietary DisplayLink drivers are in use !!!"); sway_log(SWAY_ERROR, "!!! Proprietary DisplayLink drivers are in use !!!");
} }
if (!allow_unsupported_gpu && is_unsupported) {
sway_log(SWAY_ERROR,
"Proprietary drivers are NOT supported. To launch sway anyway, "
"launch with --unsupported-gpu and DO NOT report issues.");
exit(EXIT_FAILURE);
}
drmFreeVersion(version); drmFreeVersion(version);
} }
@ -458,17 +448,14 @@ bool server_init(struct sway_server *server) {
const enum wp_color_manager_v1_render_intent render_intents[] = { const enum wp_color_manager_v1_render_intent render_intents[] = {
WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL, WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL,
}; };
const enum wp_color_manager_v1_transfer_function transfer_functions[] = { size_t transfer_functions_len = 0;
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, enum wp_color_manager_v1_transfer_function *transfer_functions =
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ, wlr_color_manager_v1_transfer_function_list_from_renderer(server->renderer, &transfer_functions_len);
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR, size_t primaries_len = 0;
}; enum wp_color_manager_v1_primaries *primaries =
const enum wp_color_manager_v1_primaries primaries[] = { wlr_color_manager_v1_primaries_list_from_renderer(server->renderer, &primaries_len);
WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
WP_COLOR_MANAGER_V1_PRIMARIES_BT2020,
};
struct wlr_color_manager_v1 *cm = wlr_color_manager_v1_create( struct wlr_color_manager_v1 *cm = wlr_color_manager_v1_create(
server->wl_display, 1, &(struct wlr_color_manager_v1_options){ server->wl_display, 2, &(struct wlr_color_manager_v1_options){
.features = { .features = {
.parametric = true, .parametric = true,
.set_mastering_display_primaries = true, .set_mastering_display_primaries = true,
@ -476,13 +463,18 @@ bool server_init(struct sway_server *server) {
.render_intents = render_intents, .render_intents = render_intents,
.render_intents_len = sizeof(render_intents) / sizeof(render_intents[0]), .render_intents_len = sizeof(render_intents) / sizeof(render_intents[0]),
.transfer_functions = transfer_functions, .transfer_functions = transfer_functions,
.transfer_functions_len = sizeof(transfer_functions) / sizeof(transfer_functions[0]), .transfer_functions_len = transfer_functions_len,
.primaries = primaries, .primaries = primaries,
.primaries_len = sizeof(primaries) / sizeof(primaries[0]), .primaries_len = primaries_len,
}); });
free(transfer_functions);
free(primaries);
wlr_scene_set_color_manager_v1(root->root_scene, cm); wlr_scene_set_color_manager_v1(root->root_scene, cm);
} }
wlr_color_representation_manager_v1_create_with_renderer(
server->wl_display, 1, server->renderer);
wl_list_init(&server->pending_launcher_ctxs); wl_list_init(&server->pending_launcher_ctxs);
// Avoid using "wayland-0" as display socket // Avoid using "wayland-0" as display socket

View file

@ -1116,7 +1116,7 @@ Returns the currently active binding mode.
A single object that contains the property _name_, which is set to the A single object that contains the property _name_, which is set to the
currently active binding mode as a string. currently active binding mode as a string.
*Exact Reply:* *Example Reply:*
``` ```
{ {
"name": "default" "name": "default"

View file

@ -178,9 +178,19 @@ must be separated by one space. For example:
updated to work with different bit depths. This command is experimental, updated to work with different bit depths. This command is experimental,
and may be removed or changed in the future. and may be removed or changed in the future.
*output* <name> color_profile srgb|[icc <file>] *output* <name> color_profile [--device-primaries] gamma22|srgb
Sets the color profile for an output. The default is _srgb_. <file> should be a Sets the color profile for an output. The default is _gamma22_.
path to a display ICC profile.
_--device-primaries_ will use the output's self-reported color primaries
when available (e.g. from display EDID).
Not all renderers support this feature; currently it only works with the
the Vulkan renderer. It is not compatible with HDR support features.
*output* <name> color_profile icc <file>
Sets the color profile for an output.
<file> should be a path to a display ICC profile.
Not all renderers support this feature; currently it only works with the Not all renderers support this feature; currently it only works with the
the Vulkan renderer. Even where supported, the application of the color the Vulkan renderer. Even where supported, the application of the color

View file

@ -43,21 +43,19 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
bool failed = false; bool failed = false;
view->scene_tree = alloc_scene_tree(root->staging, &failed); view->scene_tree = alloc_scene_tree(root->staging, &failed);
view->content_tree = alloc_scene_tree(view->scene_tree, &failed); view->content_tree = alloc_scene_tree(view->scene_tree, &failed);
if (failed) {
goto err;
}
if (!failed && !scene_descriptor_assign(&view->scene_tree->node, if (!scene_descriptor_assign(&view->scene_tree->node, SWAY_SCENE_DESC_VIEW, view)) {
SWAY_SCENE_DESC_VIEW, view)) { goto err;
failed = true;
} }
view->image_capture_scene = wlr_scene_create(); view->image_capture_scene = wlr_scene_create();
if (view->image_capture_scene == NULL) { if (view->image_capture_scene == NULL) {
failed = true; goto err;
}
if (failed) {
wlr_scene_node_destroy(&view->scene_tree->node);
return false;
} }
view->image_capture_scene->restack_xwayland_surfaces = false;
view->type = type; view->type = type;
view->impl = impl; view->impl = impl;
@ -67,6 +65,10 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
view->tearing_mode = TEARING_WINDOW_HINT; view->tearing_mode = TEARING_WINDOW_HINT;
wl_signal_init(&view->events.unmap); wl_signal_init(&view->events.unmap);
return true; return true;
err:
wlr_scene_node_destroy(&view->scene_tree->node);
return false;
} }
void view_destroy(struct sway_view *view) { void view_destroy(struct sway_view *view) {
@ -307,7 +309,7 @@ void view_autoconfigure(struct sway_view *view) {
} }
struct sway_output *output = ws ? ws->output : NULL; struct sway_output *output = ws ? ws->output : NULL;
if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) { if (output && con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) {
con->pending.content_x = output->lx; con->pending.content_x = output->lx;
con->pending.content_y = output->ly; con->pending.content_y = output->ly;
con->pending.content_width = output->width; con->pending.content_width = output->width;

View file

@ -45,6 +45,7 @@ int main(int argc, char **argv) {
if (config_path) { if (config_path) {
sway_log(SWAY_DEBUG, "Loading config file: %s", config_path); sway_log(SWAY_DEBUG, "Loading config file: %s", config_path);
status = swaynag_load_config(config_path, &swaynag, types); status = swaynag_load_config(config_path, &swaynag, types);
free(config_path);
if (status != 0) { if (status != 0) {
goto cleanup; goto cleanup;
} }