Merge branch 'master' into reduce-redundant-containers

This commit is contained in:
bonsaiiV 2024-07-28 18:52:16 +00:00 committed by GitHub
commit c32e795053
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 963 additions and 420 deletions

View file

@ -4,6 +4,7 @@ packages:
- eudev-dev
- gdk-pixbuf-dev
- json-c-dev
- lcms2-dev
- libdisplay-info-dev
- libevdev-dev
- libinput-dev
@ -38,9 +39,14 @@ tasks:
cd sway
ninja -C build
- build-no-xwayland: |
cd sway
cd wlroots
meson configure build -Dxwayland=disabled
ninja -C build
sudo ninja -C build install
cd ../sway
meson configure build --clearcache
ninja -C build
- build-static: |
cd sway
mkdir subprojects

View file

@ -3,6 +3,7 @@ packages:
- cairo
- gdk-pixbuf2
- json-c
- lcms2
- libdisplay-info
- libegl
- libinput

View file

@ -8,6 +8,7 @@ packages:
- devel/pkgconf
- graphics/cairo
- graphics/gdk-pixbuf2
- graphics/lcms2
- graphics/wayland
- graphics/wayland-protocols
- textproc/scdoc
@ -26,7 +27,7 @@ packages:
- x11/libX11
- x11/pixman
- x11/xcb-util-wm
- x11-servers/xwayland-devel
- x11-servers/xwayland
- misc/hwdata
sources:
- https://github.com/swaywm/sway

View file

@ -53,6 +53,8 @@ size_t escape_markup_text(const char *src, char *dest) {
PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
const char *text, double scale, bool markup) {
PangoLayout *layout = pango_cairo_create_layout(cairo);
pango_context_set_round_glyph_positions(pango_layout_get_context(layout), false);
PangoAttrList *attrs;
if (markup) {
char *buf;
@ -104,6 +106,7 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width,
void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) {
cairo_t *cairo = cairo_create(NULL);
PangoContext *pango = pango_cairo_create_context(cairo);
pango_context_set_round_glyph_positions(pango, false);
// When passing NULL as a language, pango uses the current locale.
PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);

View file

@ -249,6 +249,7 @@ sway_cmd input_cmd_seat;
sway_cmd input_cmd_accel_profile;
sway_cmd input_cmd_calibration_matrix;
sway_cmd input_cmd_click_method;
sway_cmd input_cmd_clickfinger_button_map;
sway_cmd input_cmd_drag;
sway_cmd input_cmd_drag_lock;
sway_cmd input_cmd_dwt;
@ -283,6 +284,7 @@ sway_cmd input_cmd_xkb_variant;
sway_cmd output_cmd_adaptive_sync;
sway_cmd output_cmd_background;
sway_cmd output_cmd_color_profile;
sway_cmd output_cmd_disable;
sway_cmd output_cmd_dpms;
sway_cmd output_cmd_enable;

View file

@ -7,6 +7,7 @@
#include <wlr/interfaces/wlr_switch.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/util/box.h>
#include <wlr/render/color.h>
#include <xkbcommon/xkbcommon.h>
#include <xf86drmMode.h>
#include "../include/config.h"
@ -148,6 +149,7 @@ struct input_config {
int accel_profile;
struct calibration_matrix calibration_matrix;
int click_method;
int clickfinger_button_map;
int drag;
int drag_lock;
int dwt;
@ -285,6 +287,8 @@ struct output_config {
int max_render_time; // In milliseconds
int adaptive_sync;
enum render_bit_depth render_bit_depth;
bool set_color_transform;
struct wlr_color_transform *color_transform;
char *background;
char *background_option;
@ -689,11 +693,21 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt
struct output_config *new_output_config(const char *name);
bool apply_output_configs(struct matched_output_config *configs,
size_t configs_len, bool test_only);
size_t configs_len, bool test_only, bool degrade_to_off);
void apply_all_output_configs(void);
struct output_config *store_output_config(struct output_config *oc);
void sort_output_configs_by_priority(struct matched_output_config *configs,
size_t configs_len);
/**
* store_output_config stores a new output config. An output may be matched by
* three different config types, in order of precedence: Identifier, name and
* wildcard. When storing a config type of lower precedence, assume that the
* user wants the config to take immediate effect by superseding (clearing) the
* same values from higher presedence configuration.
*/
void store_output_config(struct output_config *oc);
struct output_config *find_output_config(struct sway_output *output);

View file

@ -7,6 +7,10 @@
#include "list.h"
#include "tree/view.h"
#if WLR_HAS_XWAYLAND
#include "sway/xwayland.h"
#endif
enum criteria_type {
CT_COMMAND = 1 << 0,
CT_ASSIGN_OUTPUT = 1 << 1,
@ -36,7 +40,7 @@ struct criteria {
struct pattern *app_id;
struct pattern *con_mark;
uint32_t con_id; // internal ID
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct pattern *class;
uint32_t id; // X11 window ID
struct pattern *instance;

View file

@ -5,10 +5,11 @@
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_transient_seat_v1.h>
#include "sway/server.h"
#include "sway/config.h"
#include "list.h"
struct sway_server;
struct sway_input_device {
char *identifier;
struct wlr_input_device *wlr_device;

View file

@ -66,6 +66,8 @@ struct sway_output {
struct wl_signal disable;
} events;
struct wlr_color_transform *color_transform;
struct timespec last_presentation;
uint32_t refresh_nsec;
int max_render_time; // In milliseconds

View file

@ -5,7 +5,7 @@
#include "config.h"
#include "list.h"
#include "sway/desktop/idle_inhibit_v1.h"
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
#include "sway/xwayland.h"
#endif
@ -59,7 +59,7 @@ struct sway_server {
struct wlr_tablet_manager_v2 *tablet_v2;
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct sway_xwayland xwayland;
struct wl_listener xwayland_surface;
struct wl_listener xwayland_ready;
@ -81,6 +81,8 @@ struct sway_server {
struct wlr_pointer_constraints_v1 *pointer_constraints;
struct wl_listener pointer_constraint;
struct wlr_xdg_output_manager_v1 *xdg_output_manager_v1;
struct wlr_output_manager_v1 *output_manager_v1;
struct wl_listener output_manager_apply;
struct wl_listener output_manager_test;
@ -133,6 +135,8 @@ struct sway_server {
// Stores the nodes that have been marked as "dirty" and will be put into
// the pending transaction.
list_t *dirty_nodes;
struct wl_event_source *delayed_modeset;
};
extern struct sway_server server;
@ -165,7 +169,7 @@ void sway_session_lock_add_output(struct sway_session_lock *lock,
bool sway_session_lock_has_surface(struct sway_session_lock *lock,
struct wlr_surface *surface);
void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data);
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
void handle_xwayland_surface(struct wl_listener *listener, void *data);
#endif
void handle_server_decoration(struct wl_listener *listener, void *data);

View file

@ -175,8 +175,6 @@ struct sway_container *container_obstructing_fullscreen_container(struct sway_co
bool container_has_ancestor(struct sway_container *container,
struct sway_container *ancestor);
void container_update_textures_recursive(struct sway_container *con);
void container_reap_empty(struct sway_container *con);
struct sway_container *container_flatten(struct sway_container *container);

View file

@ -2,12 +2,12 @@
#define _SWAY_ROOT_H
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <wlr/config.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/render/wlr_texture.h>
#include "sway/tree/container.h"
#include "sway/tree/node.h"
#include "config.h"
#include "list.h"
extern struct sway_root *root;
@ -47,7 +47,7 @@ struct sway_root {
struct wlr_scene_tree *shell_top;
struct wlr_scene_tree *fullscreen;
struct wlr_scene_tree *fullscreen_global;
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct wlr_scene_tree *unmanaged;
#endif
struct wlr_scene_tree *shell_overlay;

View file

@ -1,10 +1,11 @@
#ifndef _SWAY_VIEW_H
#define _SWAY_VIEW_H
#include <wayland-server-core.h>
#include <wlr/config.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_scene.h>
#include "sway/config.h"
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
#include <wlr/xwayland.h>
#endif
#include "sway/input/input-manager.h"
@ -15,7 +16,7 @@ struct sway_xdg_decoration;
enum sway_view_type {
SWAY_VIEW_XDG_SHELL,
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
SWAY_VIEW_XWAYLAND,
#endif
};
@ -27,7 +28,7 @@ enum sway_view_prop {
VIEW_PROP_INSTANCE,
VIEW_PROP_WINDOW_TYPE,
VIEW_PROP_WINDOW_ROLE,
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
VIEW_PROP_X11_WINDOW_ID,
VIEW_PROP_X11_PARENT_ID,
#endif
@ -98,7 +99,7 @@ struct sway_view {
union {
struct wlr_xdg_toplevel *wlr_xdg_toplevel;
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct wlr_xwayland_surface *wlr_xwayland_surface;
#endif
};
@ -127,7 +128,7 @@ struct sway_xdg_shell_view {
struct wl_listener unmap;
struct wl_listener destroy;
};
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct sway_xwayland_view {
struct sway_view view;
@ -293,7 +294,7 @@ void view_center_and_clip_surface(struct sway_view *view);
struct sway_view *view_from_wlr_xdg_surface(
struct wlr_xdg_surface *xdg_surface);
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct sway_view *view_from_wlr_xwayland_surface(
struct wlr_xwayland_surface *xsurface);
#endif

View file

@ -3,7 +3,7 @@ project(
'c',
version: '1.10-dev',
license: 'MIT',
meson_version: '>=0.60.0',
meson_version: '>=1.3',
default_options: [
'c_std=c11',
'warning_level=2',
@ -38,14 +38,14 @@ if is_freebsd
endif
# Execute the wlroots subproject, if any
wlroots_version = ['>=0.18.0', '<0.19.0']
wlroots_version = ['>=0.19.0', '<0.20.0']
subproject(
'wlroots',
default_options: ['examples=false'],
required: false,
version: wlroots_version,
)
wlroots = dependency('wlroots', version: wlroots_version)
wlroots = dependency('wlroots-0.19', version: wlroots_version, fallback: 'wlroots')
wlroots_features = {
'xwayland': false,
'libinput_backend': false,
@ -57,10 +57,6 @@ foreach name, _ : wlroots_features
wlroots_features += { name: have }
endforeach
if get_option('xwayland').enabled() and not wlroots_features['xwayland']
error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support')
endif
null_dep = dependency('', required: false)
jsonc = dependency('json-c', version: '>=0.13')
@ -68,7 +64,7 @@ pcre2 = dependency('libpcre2-8')
wayland_server = dependency('wayland-server', version: '>=1.21.0')
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
wayland_protos = dependency('wayland-protocols', version: '>=1.24')
wayland_protos = dependency('wayland-protocols', version: '>=1.24', default_options: ['tests=false'])
xkbcommon = dependency('xkbcommon', version: '>=1.5.0')
cairo = dependency('cairo')
pango = dependency('pango')
@ -76,17 +72,15 @@ pangocairo = dependency('pangocairo')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
pixman = dependency('pixman-1')
libevdev = dependency('libevdev')
libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep
xcb = dependency('xcb', required: get_option('xwayland'))
libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.26.0') : null_dep
xcb = wlroots_features['xwayland'] ? dependency('xcb') : null_dep
drm = dependency('libdrm')
libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_dep
math = cc.find_library('m')
rt = cc.find_library('rt')
xcb_icccm = dependency('xcb-icccm', required: get_option('xwayland'))
xcb_icccm = wlroots_features['xwayland'] ? dependency('xcb-icccm') : null_dep
threads = dependency('threads') # for pthread_setschedparam
have_xwayland = xcb.found() and xcb_icccm.found() and wlroots_features['xwayland']
if get_option('sd-bus-provider') == 'auto'
if not get_option('tray').disabled()
assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto')
@ -110,7 +104,6 @@ have_tray = (not get_option('tray').disabled()) and tray_deps_found
conf_data = configuration_data()
conf_data.set10('HAVE_XWAYLAND', have_xwayland)
conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found())
conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd')
conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind')
@ -179,31 +172,10 @@ if git.found()
endif
add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c')
# Compute the relative path used by compiler invocations.
source_root = meson.current_source_dir().split('/')
build_root = meson.global_build_root().split('/')
relative_dir_parts = []
i = 0
in_prefix = true
foreach p : build_root
if i >= source_root.length() or not in_prefix or p != source_root[i]
in_prefix = false
relative_dir_parts += '..'
endif
i += 1
endforeach
i = 0
in_prefix = true
foreach p : source_root
if i >= build_root.length() or not in_prefix or build_root[i] != p
in_prefix = false
relative_dir_parts += p
endif
i += 1
endforeach
relative_dir = join_paths(relative_dir_parts) + '/'
fs = import('fs')
# Strip relative path prefixes from the code if possible, otherwise hide them.
relative_dir = fs.relative_to(meson.current_source_dir(), meson.global_build_root()) + '/'
if cc.has_argument('-fmacro-prefix-map=/prefix/to/hide=')
add_project_arguments(
'-fmacro-prefix-map=@0@='.format(relative_dir),
@ -271,7 +243,6 @@ endif
subdir('completions')
summary({
'xwayland': have_xwayland,
'gdk-pixbuf': gdk_pixbuf.found(),
'tray': have_tray,
'man-pages': scdoc.found(),

View file

@ -4,7 +4,6 @@ option('bash-completions', type: 'boolean', value: true, description: 'Install b
option('fish-completions', type: 'boolean', value: true, description: 'Install fish shell completions.')
option('swaybar', type: 'boolean', value: true, description: 'Enable support for swaybar')
option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag')
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray')
option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybar tray')
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')

View file

@ -7,10 +7,10 @@ wayland_scanner = find_program(
)
protocols = [
wl_protocol_dir / 'stable/tablet/tablet-v2.xml',
wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.xml',
wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',

View file

@ -11,6 +11,7 @@ static const struct cmd_handler input_handlers[] = {
{ "accel_profile", input_cmd_accel_profile },
{ "calibration_matrix", input_cmd_calibration_matrix },
{ "click_method", input_cmd_click_method },
{ "clickfinger_button_map", input_cmd_clickfinger_button_map },
{ "drag", input_cmd_drag },
{ "drag_lock", input_cmd_drag_lock },
{ "dwt", input_cmd_dwt },

View file

@ -0,0 +1,27 @@
#include <string.h>
#include <strings.h>
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
struct cmd_results *input_cmd_clickfinger_button_map(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "clickfinger_button_map", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *ic = config->handler_context.input_config;
if (!ic) {
return cmd_results_new(CMD_FAILURE, "No input device defined.");
}
if (strcasecmp(argv[0], "lrm") == 0) {
ic->clickfinger_button_map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM;
} else if (strcasecmp(argv[0], "lmr") == 0) {
ic->clickfinger_button_map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR;
} else {
return cmd_results_new(CMD_INVALID,
"Expected 'clickfinger_button_map <lrm|lmr>'");
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -5,6 +5,7 @@
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "sway/server.h"
#include "log.h"
#if WLR_HAS_LIBINPUT_BACKEND

View file

@ -3,6 +3,7 @@
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "sway/server.h"
#include "log.h"
struct xkb_switch_layout_action {

View file

@ -11,6 +11,7 @@
#include "sway/input/seat.h"
#include "sway/ipc-server.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"

View file

@ -10,6 +10,7 @@ static const struct cmd_handler output_handlers[] = {
{ "adaptive_sync", output_cmd_adaptive_sync },
{ "background", output_cmd_background },
{ "bg", output_cmd_background },
{ "color_profile", output_cmd_color_profile },
{ "disable", output_cmd_disable },
{ "dpms", output_cmd_dpms },
{ "enable", output_cmd_enable },

View file

@ -0,0 +1,101 @@
#include <fcntl.h>
#include <strings.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wlr/render/color.h>
#include "sway/commands.h"
#include "sway/config.h"
static bool read_file_into_buf(const char *path, void **buf, size_t *size) {
/* Why not use fopen/fread directly? glibc will succesfully open directories,
* not just files, and supports seeking on them. Instead, we directly
* work with file descriptors and use the more consistent open/fstat/read. */
int fd = open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
if (fd == -1) {
return false;
}
char *b = NULL;
struct stat info;
if (fstat(fd, &info) == -1) {
goto fail;
}
// only regular files, to avoid issues with e.g. opening pipes
if (!S_ISREG(info.st_mode)) {
goto fail;
}
off_t s = info.st_size;
if (s <= 0) {
goto fail;
}
b = calloc(1, s);
if (!b) {
goto fail;
}
size_t nread = 0;
while (nread < (size_t)s) {
size_t to_read = (size_t)s - nread;
ssize_t r = read(fd, b + nread, to_read);
if ((r == -1 && errno != EINTR) || r == 0) {
goto fail;
}
nread += (size_t)r;
}
close(fd);
*buf = b;
*size = (size_t)s;
return true; // success
fail:
free(b);
close(fd);
return false;
}
struct cmd_results *output_cmd_color_profile(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 color_profile first argument.");
}
if (strcmp(*argv, "srgb") == 0) {
wlr_color_transform_unref(config->handler_context.output_config->color_transform);
config->handler_context.output_config->color_transform = NULL;
config->handler_context.output_config->set_color_transform = true;
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
} else if (strcmp(*argv, "icc") == 0) {
if (argc < 2) {
return cmd_results_new(CMD_INVALID,
"Invalid color profile specification: icc type requires a file");
}
void *data = NULL;
size_t size = 0;
if (!read_file_into_buf(argv[1], &data, &size)) {
return cmd_results_new(CMD_FAILURE,
"Failed to load color profile: could not read ICC file");
}
struct wlr_color_transform *tmp =
wlr_color_transform_init_linear_to_icc(data, size);
if (!tmp) {
free(data);
return cmd_results_new(CMD_FAILURE,
"Failed to load color profile: failed to initialize transform from ICC");
}
free(data);
wlr_color_transform_unref(config->handler_context.output_config->color_transform);
config->handler_context.output_config->color_transform = tmp;
config->handler_context.output_config->set_color_transform = true;
config->handler_context.leftovers.argc = argc - 2;
config->handler_context.leftovers.argv = argv + 2;
} else {
return cmd_results_new(CMD_INVALID,
"Invalid color profile specification: first argument should be icc|srgb");
}
return NULL;
}

View file

@ -5,6 +5,7 @@
#include <wlr/types/wlr_pointer.h>
#include "sway/commands.h"
#include "sway/input/cursor.h"
#include "sway/server.h"
static struct cmd_results *press_or_release(struct sway_cursor *cursor,
char *action, char *button_str);

View file

@ -4,6 +4,7 @@
#include "sway/config.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/server.h"
enum operation {
OP_ENABLE,

View file

@ -2,6 +2,7 @@
#include "sway/commands.h"
#include "sway/input/seat.h"
#include "sway/input/input-manager.h"
#include "sway/server.h"
#include "util.h"
static struct cmd_results *handle_action(struct seat_config *sc,

View file

@ -3,6 +3,7 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/input/seat.h"
#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"

View file

@ -18,7 +18,7 @@ static bool test_con_id(struct sway_container *container, void *data) {
return container->node.id == *con_id;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
static bool test_id(struct sway_container *container, void *data) {
xcb_window_t *wid = data;
return (container->view && container->view->type == SWAY_VIEW_XWAYLAND
@ -53,7 +53,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
char *value = join_args(argv + 3, argc - 3);
if (strcasecmp(argv[2], "id") == 0) {
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
xcb_window_t id = strtol(value, NULL, 0);
other = root_find_container(test_id, &id);
#endif

View file

@ -10,7 +10,7 @@ struct cmd_results *cmd_xwayland(int argc, char **argv) {
return error;
}
#ifdef HAVE_XWAYLAND
#ifdef WLR_HAS_XWAYLAND
enum xwayland_mode xwayland;
if (strcmp(argv[0], "force") == 0) {
xwayland = XWAYLAND_MODE_IMMEDIATE;

View file

@ -23,6 +23,7 @@
#include "sway/config.h"
#include "sway/criteria.h"
#include "sway/desktop/transaction.h"
#include "sway/server.h"
#include "sway/swaynag.h"
#include "sway/tree/arrange.h"
#include "sway/tree/root.h"

View file

@ -12,6 +12,7 @@
#include "sway/config.h"
#include "sway/input/keyboard.h"
#include "sway/output.h"
#include "sway/server.h"
#include "config.h"
#include "list.h"
#include "log.h"

View file

@ -3,6 +3,7 @@
#include <float.h>
#include "sway/config.h"
#include "sway/input/keyboard.h"
#include "sway/server.h"
#include "log.h"
struct input_config *new_input_config(const char* identifier) {
@ -27,6 +28,7 @@ struct input_config *new_input_config(const char* identifier) {
input->dwtp = INT_MIN;
input->send_events = INT_MIN;
input->click_method = INT_MIN;
input->clickfinger_button_map = INT_MIN;
input->middle_emulation = INT_MIN;
input->natural_scroll = INT_MIN;
input->accel_profile = INT_MIN;
@ -54,6 +56,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
if (src->click_method != INT_MIN) {
dst->click_method = src->click_method;
}
if (src->clickfinger_button_map != INT_MIN) {
dst->clickfinger_button_map = src->clickfinger_button_map;
}
if (src->drag != INT_MIN) {
dst->drag = src->drag;
}

View file

@ -13,6 +13,7 @@
#include "sway/config.h"
#include "sway/input/cursor.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/root.h"
#include "log.h"
#include "util.h"
@ -75,10 +76,77 @@ struct output_config *new_output_config(const char *name) {
oc->max_render_time = -1;
oc->adaptive_sync = -1;
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
oc->set_color_transform = false;
oc->color_transform = NULL;
oc->power = -1;
return oc;
}
// supersede_output_config clears all fields in dst that were set in src
static void supersede_output_config(struct output_config *dst, struct output_config *src) {
if (src->enabled != -1) {
dst->enabled = -1;
}
if (src->width != -1) {
dst->width = -1;
}
if (src->height != -1) {
dst->height = -1;
}
if (src->x != -1) {
dst->x = -1;
}
if (src->y != -1) {
dst->y = -1;
}
if (src->scale != -1) {
dst->scale = -1;
}
if (src->scale_filter != SCALE_FILTER_DEFAULT) {
dst->scale_filter = SCALE_FILTER_DEFAULT;
}
if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
dst->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
}
if (src->refresh_rate != -1) {
dst->refresh_rate = -1;
}
if (src->custom_mode != -1) {
dst->custom_mode = -1;
}
if (src->drm_mode.type != (uint32_t) -1) {
dst->drm_mode.type = -1;
}
if (src->transform != -1) {
dst->transform = -1;
}
if (src->max_render_time != -1) {
dst->max_render_time = -1;
}
if (src->adaptive_sync != -1) {
dst->adaptive_sync = -1;
}
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
}
if (src->background) {
free(dst->background);
dst->background = NULL;
}
if (src->background_option) {
free(dst->background_option);
dst->background_option = NULL;
}
if (src->background_fallback) {
free(dst->background_fallback);
dst->background_fallback = NULL;
}
if (src->power != -1) {
dst->power = -1;
}
}
// merge_output_config sets all fields in dst that were set in src
static void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->enabled != -1) {
dst->enabled = src->enabled;
@ -125,6 +193,14 @@ static void merge_output_config(struct output_config *dst, struct output_config
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = src->render_bit_depth;
}
if (src->set_color_transform) {
if (src->color_transform) {
wlr_color_transform_ref(src->color_transform);
}
wlr_color_transform_unref(dst->color_transform);
dst->set_color_transform = true;
dst->color_transform = src->color_transform;
}
if (src->background) {
free(dst->background);
dst->background = strdup(src->background);
@ -142,94 +218,42 @@ static void merge_output_config(struct output_config *dst, struct output_config
}
}
static void merge_wildcard_on_all(struct output_config *wildcard) {
for (int i = 0; i < config->output_configs->length; i++) {
struct output_config *oc = config->output_configs->items[i];
if (strcmp(wildcard->name, oc->name) != 0) {
sway_log(SWAY_DEBUG, "Merging output * config on %s", oc->name);
merge_output_config(oc, wildcard);
}
}
}
static void merge_id_on_name(struct output_config *oc) {
struct sway_output *output = all_output_by_name_or_id(oc->name);
if (output == NULL) {
return;
}
const char *name = output->wlr_output->name;
char id[128];
output_get_identifier(id, sizeof(id), output);
char *id_on_name = format_str("%s on %s", id, name);
if (!id_on_name) {
return;
}
int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
if (i >= 0) {
sway_log(SWAY_DEBUG, "Merging on top of existing id on name config");
merge_output_config(config->output_configs->items[i], oc);
} else {
// If both a name and identifier config, exist generate an id on name
int ni = list_seq_find(config->output_configs, output_name_cmp, name);
int ii = list_seq_find(config->output_configs, output_name_cmp, id);
if ((ni >= 0 && ii >= 0) || (ni >= 0 && strcmp(oc->name, id) == 0)
|| (ii >= 0 && strcmp(oc->name, name) == 0)) {
struct output_config *ion_oc = new_output_config(id_on_name);
if (ni >= 0) {
merge_output_config(ion_oc, config->output_configs->items[ni]);
}
if (ii >= 0) {
merge_output_config(ion_oc, config->output_configs->items[ii]);
}
merge_output_config(ion_oc, oc);
list_add(config->output_configs, ion_oc);
sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\""
" (enabled: %d) (%dx%d@%fHz position %d,%d scale %f "
"transform %d) (bg %s %s) (power %d) (max render time: %d)",
ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height,
ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale,
ion_oc->transform, ion_oc->background,
ion_oc->background_option, ion_oc->power,
ion_oc->max_render_time);
}
}
free(id_on_name);
}
struct output_config *store_output_config(struct output_config *oc) {
void store_output_config(struct output_config *oc) {
bool merged = false;
bool wildcard = strcmp(oc->name, "*") == 0;
if (wildcard) {
merge_wildcard_on_all(oc);
} else {
merge_id_on_name(oc);
struct sway_output *output = wildcard ? NULL : all_output_by_name_or_id(oc->name);
char id[128];
if (output) {
output_get_identifier(id, sizeof(id), output);
}
int i = list_seq_find(config->output_configs, output_name_cmp, oc->name);
if (i >= 0) {
sway_log(SWAY_DEBUG, "Merging on top of existing output config");
struct output_config *current = config->output_configs->items[i];
merge_output_config(current, oc);
free_output_config(oc);
oc = current;
} else if (!wildcard) {
sway_log(SWAY_DEBUG, "Adding non-wildcard output config");
i = list_seq_find(config->output_configs, output_name_cmp, "*");
if (i >= 0) {
sway_log(SWAY_DEBUG, "Merging on top of output * config");
struct output_config *current = new_output_config(oc->name);
merge_output_config(current, config->output_configs->items[i]);
merge_output_config(current, oc);
free_output_config(oc);
oc = current;
for (int i = 0; i < config->output_configs->length; i++) {
struct output_config *old = config->output_configs->items[i];
// If the old config matches the new config's name, regardless of
// whether it was name or identifier, merge on top of the existing
// config. If the new config is a wildcard, this also merges on top of
// old wildcard configs.
if (strcmp(old->name, oc->name) == 0) {
merge_output_config(old, oc);
merged = true;
continue;
}
// If the new config is a wildcard config we supersede all non-wildcard
// configs. Old wildcard configs have already been handled above.
if (wildcard) {
supersede_output_config(old, oc);
continue;
}
// If the new config matches an output's name, and the old config
// matches on that output's identifier, supersede it.
if (output && strcmp(old->name, id) == 0 &&
strcmp(oc->name, output->wlr_output->name) == 0) {
supersede_output_config(old, oc);
}
list_add(config->output_configs, oc);
} else {
// New wildcard config. Just add it
sway_log(SWAY_DEBUG, "Adding output * config");
list_add(config->output_configs, oc);
}
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
@ -240,7 +264,13 @@ struct output_config *store_output_config(struct output_config *oc) {
oc->transform, oc->background, oc->background_option, oc->power,
oc->max_render_time);
return oc;
// If the configuration was not merged into an existing configuration, add
// it to the list. Otherwise we're done with it and can free it.
if (!merged) {
list_add(config->output_configs, oc);
} else {
free_output_config(oc);
}
}
static void set_mode(struct wlr_output *output, struct wlr_output_state *pending,
@ -367,22 +397,18 @@ 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 bool render_format_is_10bit(uint32_t render_format) {
return render_format == DRM_FORMAT_XRGB2101010 ||
render_format == DRM_FORMAT_XBGR2101010;
}
static bool render_format_is_bgr(uint32_t fmt) {
return fmt == DRM_FORMAT_XBGR2101010 || fmt == DRM_FORMAT_XBGR8888;
}
static bool output_config_is_disabling(struct output_config *oc) {
return oc && (!oc->enabled || oc->power == 0);
}
static void queue_output_config(struct output_config *oc,
struct sway_output *output, struct wlr_output_state *pending) {
@ -392,7 +418,7 @@ static void queue_output_config(struct output_config *oc,
struct wlr_output *wlr_output = output->wlr_output;
if (oc && (!oc->enabled || oc->power == 0)) {
if (output_config_is_disabling(oc)) {
sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name);
wlr_output_state_set_enabled(pending, false);
return;
@ -415,22 +441,6 @@ static void queue_output_config(struct output_config *oc,
struct wlr_output_mode *preferred_mode =
wlr_output_preferred_mode(wlr_output);
wlr_output_state_set_mode(pending, preferred_mode);
if (!wlr_output_test_state(wlr_output, pending)) {
sway_log(SWAY_DEBUG, "Preferred mode rejected, "
"falling back to another mode");
struct wlr_output_mode *mode;
wl_list_for_each(mode, &wlr_output->modes, link) {
if (mode == preferred_mode) {
continue;
}
wlr_output_state_set_mode(pending, mode);
if (wlr_output_test_state(wlr_output, pending)) {
break;
}
}
}
}
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
@ -449,7 +459,7 @@ static void queue_output_config(struct output_config *oc,
#endif
}
if (wlr_output->transform != tr) {
sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
sway_log(SWAY_DEBUG, "Set %s transform to %d", wlr_output->name, tr);
wlr_output_state_set_transform(pending, tr);
}
@ -481,25 +491,17 @@ static void queue_output_config(struct output_config *oc,
sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
oc->adaptive_sync);
wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
if (oc->adaptive_sync == 1 && !wlr_output_test_state(wlr_output, pending)) {
sway_log(SWAY_DEBUG, "Adaptive sync failed, ignoring");
wlr_output_state_set_adaptive_sync_enabled(pending, false);
}
}
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_state_set_render_format(pending, fmts[i]);
if (wlr_output_test_state(wlr_output, pending)) {
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]);
if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 &&
render_format_is_10bit(output->wlr_output->render_format)) {
// 10-bit was set successfully before, try to save some tests by reusing the format
wlr_output_state_set_render_format(pending, output->wlr_output->render_format);
} else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) {
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010);
} else {
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
}
}
}
@ -565,6 +567,13 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
output->max_render_time = oc->max_render_time;
}
if (oc && oc->set_color_transform) {
if (oc->color_transform) {
wlr_color_transform_ref(oc->color_transform);
}
wlr_color_transform_unref(output->color_transform);
output->color_transform = oc->color_transform;
}
return true;
}
@ -587,98 +596,285 @@ static void default_output_config(struct output_config *oc,
oc->max_render_time = 0;
}
static struct output_config *get_output_config(char *identifier,
struct sway_output *sway_output) {
// find_output_config returns a merged output_config containing all stored
// configuration that applies to the specified output.
struct output_config *find_output_config(struct sway_output *sway_output) {
const char *name = sway_output->wlr_output->name;
struct output_config *oc = NULL;
struct output_config *oc_id_on_name = NULL;
struct output_config *oc_name = NULL;
struct output_config *oc_id = NULL;
char *id_on_name = format_str("%s on %s", identifier, name);
int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
if (i >= 0) {
oc_id_on_name = config->output_configs->items[i];
} else {
i = list_seq_find(config->output_configs, output_name_cmp, name);
if (i >= 0) {
oc_name = config->output_configs->items[i];
}
i = list_seq_find(config->output_configs, output_name_cmp, identifier);
if (i >= 0) {
oc_id = config->output_configs->items[i];
}
}
struct output_config *result = new_output_config("temp");
struct output_config *result = new_output_config(name);
if (config->reloading) {
default_output_config(result, sway_output->wlr_output);
}
if (oc_id_on_name) {
// Already have an identifier on name config, use that
free(result->name);
result->name = strdup(id_on_name);
merge_output_config(result, oc_id_on_name);
} else if (oc_name && oc_id) {
// Generate a config named `<identifier> on <name>` which contains a
// merged copy of the identifier on name. This will make sure that both
// identifier and name configs are respected, with identifier getting
// priority
struct output_config *temp = new_output_config(id_on_name);
merge_output_config(temp, oc_name);
merge_output_config(temp, oc_id);
list_add(config->output_configs, temp);
free(result->name);
result->name = strdup(id_on_name);
merge_output_config(result, temp);
char id[128];
output_get_identifier(id, sizeof(id), sway_output);
sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)"
" (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)"
" (power %d) (max render time: %d)", result->name, result->enabled,
result->width, result->height, result->refresh_rate,
result->x, result->y, result->scale, result->transform,
result->background, result->background_option, result->power,
result->max_render_time);
} else if (oc_name) {
// No identifier config, just return a copy of the name config
free(result->name);
result->name = strdup(name);
merge_output_config(result, oc_name);
} else if (oc_id) {
// No name config, just return a copy of the identifier config
free(result->name);
result->name = strdup(identifier);
merge_output_config(result, oc_id);
} else {
i = list_seq_find(config->output_configs, output_name_cmp, "*");
if (i >= 0) {
// No name or identifier config, but there is a wildcard config
free(result->name);
result->name = strdup("*");
merge_output_config(result, config->output_configs->items[i]);
} else if (!config->reloading) {
int i;
bool match = false;
if ((i = list_seq_find(config->output_configs, output_name_cmp, "*")) >= 0) {
match = true;
oc = config->output_configs->items[i];
merge_output_config(result, oc);
}
if ((i = list_seq_find(config->output_configs, output_name_cmp, name)) >= 0) {
match = true;
oc = config->output_configs->items[i];
merge_output_config(result, oc);
}
if ((i = list_seq_find(config->output_configs, output_name_cmp, id)) >= 0) {
match = true;
oc = config->output_configs->items[i];
merge_output_config(result, oc);
}
if (!match && !config->reloading) {
// No name, identifier, or wildcard config. Since we are not
// reloading with defaults, the output config will be empty, so
// just return NULL
free_output_config(result);
result = NULL;
}
return NULL;
}
free(id_on_name);
return result;
}
struct output_config *find_output_config(struct sway_output *output) {
char id[128];
output_get_identifier(id, sizeof(id), output);
return get_output_config(id, output);
static bool config_has_auto_mode(struct output_config *oc) {
if (!oc) {
return true;
}
if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) {
return true;
} else if (oc->width > 0 && oc->height > 0) {
return true;
}
return false;
}
struct search_context {
struct wlr_output_swapchain_manager *swapchain_mgr;
struct wlr_backend_output_state *states;
struct matched_output_config *configs;
size_t configs_len;
bool degrade_to_off;
};
static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_state *state) {
sway_log(SWAY_DEBUG, "Output state for %s", wlr_output->name);
if (state->committed & WLR_OUTPUT_STATE_ENABLED) {
sway_log(SWAY_DEBUG, " enabled: %s", state->enabled ? "yes" : "no");
}
if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
sway_log(SWAY_DEBUG, " render_format: %d", state->render_format);
}
if (state->committed & WLR_OUTPUT_STATE_MODE) {
if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) {
sway_log(SWAY_DEBUG, " custom mode: %dx%d@%dmHz",
state->custom_mode.width, state->custom_mode.height, state->custom_mode.refresh);
} else {
sway_log(SWAY_DEBUG, " mode: %dx%d@%dmHz%s",
state->mode->width, state->mode->height, state->mode->refresh,
state->mode->preferred ? " (preferred)" : "");
}
}
if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
sway_log(SWAY_DEBUG, " adaptive_sync: %s",
state->adaptive_sync_enabled ? "enabled": "disabled");
}
}
static bool search_valid_config(struct search_context *ctx, size_t output_idx);
static void reset_output_state(struct wlr_output_state *state) {
wlr_output_state_finish(state);
wlr_output_state_init(state);
state->committed = 0;
}
static void clear_later_output_states(struct wlr_backend_output_state *states,
size_t configs_len, size_t output_idx) {
// Clear and disable all output states after this one to avoid conflict
// with previous tests.
for (size_t idx = output_idx+1; idx < configs_len; idx++) {
struct wlr_backend_output_state *backend_state = &states[idx];
struct wlr_output_state *state = &backend_state->base;
reset_output_state(state);
wlr_output_state_set_enabled(state, false);
}
}
static bool search_finish(struct search_context *ctx, size_t output_idx) {
struct wlr_backend_output_state *backend_state = &ctx->states[output_idx];
struct wlr_output_state *state = &backend_state->base;
struct wlr_output *wlr_output = backend_state->output;
clear_later_output_states(ctx->states, ctx->configs_len, output_idx);
dump_output_state(wlr_output, state);
return wlr_output_swapchain_manager_prepare(ctx->swapchain_mgr, ctx->states, ctx->configs_len) &&
search_valid_config(ctx, output_idx+1);
}
static bool search_adaptive_sync(struct search_context *ctx, size_t output_idx) {
struct matched_output_config *cfg = &ctx->configs[output_idx];
struct wlr_backend_output_state *backend_state = &ctx->states[output_idx];
struct wlr_output_state *state = &backend_state->base;
if (!backend_state->output->adaptive_sync_supported) {
return search_finish(ctx, output_idx);
}
if (cfg->config && cfg->config->adaptive_sync == 1) {
wlr_output_state_set_adaptive_sync_enabled(state, true);
if (search_finish(ctx, output_idx)) {
return true;
}
}
wlr_output_state_set_adaptive_sync_enabled(state, false);
return search_finish(ctx, output_idx);
}
static bool search_mode(struct search_context *ctx, size_t output_idx) {
struct matched_output_config *cfg = &ctx->configs[output_idx];
struct wlr_backend_output_state *backend_state = &ctx->states[output_idx];
struct wlr_output_state *state = &backend_state->base;
struct wlr_output *wlr_output = backend_state->output;
if (!config_has_auto_mode(cfg->config)) {
return search_adaptive_sync(ctx, output_idx);
}
struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output);
if (preferred_mode) {
wlr_output_state_set_mode(state, preferred_mode);
if (search_adaptive_sync(ctx, output_idx)) {
return true;
}
}
if (wl_list_empty(&wlr_output->modes)) {
state->committed &= ~WLR_OUTPUT_STATE_MODE;
return search_adaptive_sync(ctx, output_idx);
}
struct wlr_output_mode *mode;
wl_list_for_each(mode, &backend_state->output->modes, link) {
if (mode == preferred_mode) {
continue;
}
wlr_output_state_set_mode(state, mode);
if (search_adaptive_sync(ctx, output_idx)) {
return true;
}
}
return false;
}
static bool search_render_format(struct search_context *ctx, size_t output_idx) {
struct matched_output_config *cfg = &ctx->configs[output_idx];
struct wlr_backend_output_state *backend_state = &ctx->states[output_idx];
struct wlr_output_state *state = &backend_state->base;
struct wlr_output *wlr_output = backend_state->output;
uint32_t fmts[] = {
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_INVALID,
};
if (render_format_is_bgr(wlr_output->render_format)) {
// Start with BGR in the unlikely event that we previously required it.
fmts[0] = DRM_FORMAT_XBGR2101010;
fmts[1] = DRM_FORMAT_XRGB2101010;
}
const struct wlr_drm_format_set *primary_formats =
wlr_output_get_primary_formats(wlr_output, WLR_BUFFER_CAP_DMABUF);
bool need_10bit = cfg->config && cfg->config->render_bit_depth == RENDER_BIT_DEPTH_10;
for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) {
if (!need_10bit && render_format_is_10bit(fmts[idx])) {
continue;
}
if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) {
// This is not a supported format for this output
continue;
}
wlr_output_state_set_render_format(state, fmts[idx]);
if (search_mode(ctx, output_idx)) {
return true;
}
}
return false;
}
static bool search_valid_config(struct search_context *ctx, size_t output_idx) {
if (output_idx >= ctx->configs_len) {
// We reached the end of the search, all good!
return true;
}
struct matched_output_config *cfg = &ctx->configs[output_idx];
struct wlr_backend_output_state *backend_state = &ctx->states[output_idx];
struct wlr_output_state *state = &backend_state->base;
struct wlr_output *wlr_output = backend_state->output;
if (!output_config_is_disabling(cfg->config)) {
// Search through our possible configurations, doing a depth-first
// through render_format, modes, adaptive_sync and the next output's
// config.
queue_output_config(cfg->config, cfg->output, &backend_state->base);
if (search_render_format(ctx, output_idx)) {
return true;
} else if (!ctx->degrade_to_off) {
return false;
}
// We could not get anything to work, try to disable this output to see
// if we can at least make the outputs before us work.
sway_log(SWAY_DEBUG, "Unable to find valid config with output %s, disabling",
wlr_output->name);
reset_output_state(state);
}
wlr_output_state_set_enabled(state, false);
return search_finish(ctx, output_idx);
}
static int compare_matched_output_config_priority(const void *a, const void *b) {
const struct matched_output_config *amc = a;
const struct matched_output_config *bmc = b;
bool a_disabling = output_config_is_disabling(amc->config);
bool b_disabling = output_config_is_disabling(bmc->config);
bool a_enabled = amc->output->enabled;
bool b_enabled = bmc->output->enabled;
// We want to give priority to existing enabled outputs. To do so, we want
// the configuration order to be:
// 1. Existing, enabled outputs
// 2. Outputs that need to be enabled
// 3. Disabled or disabling outputs
if (a_enabled && !a_disabling) {
return -1;
} else if (b_enabled && !b_disabling) {
return 1;
} else if (b_disabling && !a_disabling) {
return -1;
} else if (a_disabling && !b_disabling) {
return 1;
}
return 0;
}
void sort_output_configs_by_priority(struct matched_output_config *configs,
size_t configs_len) {
qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority);
}
bool apply_output_configs(struct matched_output_config *configs,
size_t configs_len, bool test_only) {
size_t configs_len, bool test_only, bool degrade_to_off) {
struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
if (!states) {
return false;
@ -702,9 +898,19 @@ bool apply_output_configs(struct matched_output_config *configs,
bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, configs_len);
if (!ok) {
sway_log(SWAY_ERROR, "Swapchain prepare failed");
sway_log(SWAY_ERROR, "Requested backend configuration failed, searching for valid fallbacks");
struct search_context ctx = {
.swapchain_mgr = &swapchain_mgr,
.states = states,
.configs = configs,
.configs_len = configs_len,
.degrade_to_off = degrade_to_off,
};
if (!search_valid_config(&ctx, 0)) {
sway_log(SWAY_ERROR, "Search for valid config failed");
goto out;
}
}
if (test_only) {
// The swapchain manager already did a test for us
@ -718,6 +924,7 @@ bool apply_output_configs(struct matched_output_config *configs,
struct wlr_scene_output_state_options opts = {
.swapchain = wlr_output_swapchain_manager_get_swapchain(
&swapchain_mgr, backend_state->output),
.color_transform = cfg->output->color_transform,
};
struct wlr_scene_output *scene_output = cfg->output->scene_output;
struct wlr_output_state *state = &backend_state->base;
@ -789,7 +996,8 @@ void apply_all_output_configs(void) {
config->config = find_output_config(sway_output);
}
apply_output_configs(configs, configs_len, false);
sort_output_configs_by_priority(configs, configs_len);
apply_output_configs(configs, configs_len, false, true);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
free_output_config(cfg->config);
@ -804,6 +1012,7 @@ void free_output_config(struct output_config *oc) {
free(oc->name);
free(oc->background);
free(oc->background_option);
wlr_color_transform_unref(oc->color_transform);
free(oc);
}

View file

@ -7,6 +7,7 @@
#include "sway/criteria.h"
#include "sway/tree/container.h"
#include "sway/config.h"
#include "sway/server.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@ -22,7 +23,7 @@ bool criteria_is_empty(struct criteria *criteria) {
&& !criteria->app_id
&& !criteria->con_mark
&& !criteria->con_id
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
&& !criteria->class
&& !criteria->id
&& !criteria->instance
@ -90,7 +91,7 @@ void criteria_destroy(struct criteria *criteria) {
pattern_destroy(criteria->title);
pattern_destroy(criteria->shell);
pattern_destroy(criteria->app_id);
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
pattern_destroy(criteria->class);
pattern_destroy(criteria->instance);
pattern_destroy(criteria->window_role);
@ -110,7 +111,7 @@ static int regex_cmp(const char *item, const pcre2_code *regex) {
return result;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
static bool view_has_window_type(struct sway_view *view, enum atom_name name) {
if (view->type != SWAY_VIEW_XWAYLAND) {
return false;
@ -251,7 +252,7 @@ static bool criteria_matches_view(struct criteria *criteria,
return false;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
if (criteria->id) { // X11 window ID
uint32_t x11_window_id = view_get_x11_window_id(view);
if (!x11_window_id || x11_window_id != criteria->id) {
@ -428,7 +429,7 @@ list_t *criteria_get_containers(struct criteria *criteria) {
return matches;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
static enum atom_name parse_window_type(const char *type) {
if (strcasecmp(type, "normal") == 0) {
return NET_WM_WINDOW_TYPE_NORMAL;
@ -461,7 +462,7 @@ enum criteria_token {
T_CON_ID,
T_CON_MARK,
T_FLOATING,
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
T_CLASS,
T_ID,
T_INSTANCE,
@ -487,7 +488,7 @@ static enum criteria_token token_from_name(char *name) {
return T_CON_ID;
} else if (strcmp(name, "con_mark") == 0) {
return T_CON_MARK;
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
} else if (strcmp(name, "class") == 0) {
return T_CLASS;
} else if (strcmp(name, "id") == 0) {
@ -566,7 +567,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
case T_CON_MARK:
pattern_create(&criteria->con_mark, value);
break;
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
case T_CLASS:
pattern_create(&criteria->class, value);
break;
@ -674,7 +675,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
++head;
struct criteria *criteria = calloc(1, sizeof(struct criteria));
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
criteria->window_type = ATOM_LAST; // default value
#endif
char *name = NULL, *value = NULL;

View file

@ -4,6 +4,7 @@
#include "sway/input/seat.h"
#include "sway/output.h"
#include "sway/desktop/launcher.h"
#include "sway/server.h"
#include "sway/tree/node.h"
#include "sway/tree/container.h"
#include "sway/tree/workspace.h"

View file

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_scene.h>
@ -89,6 +90,43 @@ void arrange_layers(struct sway_output *output) {
} else {
arrange_popups(root->layers.popup);
}
// Find topmost keyboard interactive layer, if such a layer exists
struct wlr_scene_tree *layers_above_shell[] = {
output->layers.shell_overlay,
output->layers.shell_top,
};
size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
struct wlr_scene_node *node;
struct sway_layer_surface *topmost = NULL;
for (size_t i = 0; i < nlayers; ++i) {
wl_list_for_each_reverse(node,
&layers_above_shell[i]->children, link) {
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
SWAY_SCENE_DESC_LAYER_SHELL);
if (surface && surface->layer_surface->current.keyboard_interactive
== ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
surface->layer_surface->surface->mapped) {
topmost = surface;
break;
}
}
if (topmost != NULL) {
break;
}
}
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
seat->has_exclusive_layer = false;
if (topmost != NULL) {
seat_set_focus_layer(seat, topmost->layer_surface);
} else if (seat->focused_layer &&
seat->focused_layer->current.keyboard_interactive
!= ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
seat_set_focus_layer(seat, NULL);
}
}
}
static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
@ -432,6 +470,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
surface->output = output;
// now that the surface's output is known, we can advertise its scale
wlr_fractional_scale_v1_notify_scale(surface->layer_surface->surface,
layer_surface->output->scale);
wlr_surface_set_preferred_buffer_scale(surface->layer_surface->surface,
ceil(layer_surface->output->scale));
surface->surface_commit.notify = handle_surface_commit;
wl_signal_add(&layer_surface->surface->events.commit,
&surface->surface_commit);

View file

@ -243,13 +243,24 @@ static int output_repaint_timer_handler(void *data) {
output_configure_scene(output, &root->root_scene->tree.node, 1.0f);
if (output->gamma_lut_changed) {
struct wlr_output_state pending;
wlr_output_state_init(&pending);
if (!wlr_scene_output_build_state(output->scene_output, &pending, NULL)) {
struct wlr_scene_output_state_options opts = {
.color_transform = output->color_transform,
};
struct wlr_output *wlr_output = output->wlr_output;
struct wlr_scene_output *scene_output = output->scene_output;
if (!wlr_output->needs_frame && !output->gamma_lut_changed &&
!pixman_region32_not_empty(&scene_output->pending_commit_damage)) {
return 0;
}
struct wlr_output_state pending;
wlr_output_state_init(&pending);
if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) {
return 0;
}
if (output->gamma_lut_changed) {
output->gamma_lut_changed = false;
struct wlr_gamma_control_v1 *gamma_control =
wlr_gamma_control_manager_v1_get_control(
@ -259,17 +270,16 @@ static int output_repaint_timer_handler(void *data) {
return 0;
}
if (!wlr_output_commit_state(output->wlr_output, &pending)) {
if (!wlr_output_test_state(output->wlr_output, &pending)) {
wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
wlr_output_state_finish(&pending);
return 0;
wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL);
}
}
wlr_output_state_finish(&pending);
return 0;
if (!wlr_output_commit_state(output->wlr_output, &pending)) {
sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name);
}
wlr_scene_output_commit(output->scene_output, NULL);
wlr_output_state_finish(&pending);
return 0;
}
@ -362,6 +372,26 @@ static void update_output_manager_config(struct sway_server *server) {
ipc_event_output();
}
static int timer_modeset_handle(void *data) {
struct sway_server *server = data;
wl_event_source_remove(server->delayed_modeset);
server->delayed_modeset = NULL;
apply_all_output_configs();
transaction_commit_dirty();
update_output_manager_config(server);
return 0;
}
static void request_modeset(struct sway_server *server) {
if (server->delayed_modeset == NULL) {
server->delayed_modeset = wl_event_loop_add_timer(server->wl_event_loop,
timer_modeset_handle, server);
wl_event_source_timer_update(server->delayed_modeset, 10);
}
}
static void begin_destroy(struct sway_output *output) {
struct sway_server *server = output->server;
@ -385,9 +415,7 @@ static void begin_destroy(struct sway_output *output) {
output->wlr_output->data = NULL;
output->wlr_output = NULL;
transaction_commit_dirty();
update_output_manager_config(server);
request_modeset(server);
}
static void handle_destroy(struct wl_listener *listener, void *data) {
@ -521,11 +549,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
sway_session_lock_add_output(server->session_lock.lock, output);
}
apply_all_output_configs();
transaction_commit_dirty();
update_output_manager_config(server);
request_modeset(server);
}
void handle_output_layout_change(struct wl_listener *listener,
@ -609,7 +633,8 @@ static void output_manager_apply(struct sway_server *server,
}
}
bool ok = apply_output_configs(configs, configs_len, test_only);
sort_output_configs_by_priority(configs, configs_len);
bool ok = apply_output_configs(configs, configs_len, test_only, false);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
@ -619,7 +644,7 @@ static void output_manager_apply(struct sway_server *server,
if (!test_only && ok) {
struct wlr_output_configuration_head_v1 *config_head;
wl_list_for_each(config_head, &config->heads, link) {
if (config_head->state.output == sway_output->wlr_output) {
if (config_head->state.output == cfg->output->wlr_output) {
store_config = true;
break;
}
@ -676,5 +701,5 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
break;
}
store_output_config(oc);
apply_all_output_configs();
request_modeset(output->server);
}

View file

@ -10,6 +10,7 @@
#include "sway/input/cursor.h"
#include "sway/input/input-manager.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/node.h"
#include "sway/tree/view.h"
@ -313,7 +314,7 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
if (activated) {
arrange_container(child, width, height - title_bar_height,
false, 0);
title_bar_height == 0, 0);
} else {
disable_container(child);
}
@ -342,7 +343,7 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
if (activated) {
arrange_container(child, width, height - title_height,
false, 0);
title_bar_height == 0, 0);
} else {
disable_container(child);
}
@ -761,7 +762,7 @@ static bool should_configure(struct sway_node *node,
}
struct sway_container_state *cstate = &node->sway_container->current;
struct sway_container_state *istate = &instruction->container_state;
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
// Xwayland views are position-aware and need to be reconfigured
// when their position changes.
if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) {

View file

@ -289,6 +289,8 @@ static void handle_commit(struct wl_listener *listener, void *data) {
}
// XXX: https://github.com/swaywm/sway/issues/2176
wlr_xdg_surface_schedule_configure(xdg_surface);
wlr_xdg_toplevel_set_wm_capabilities(view->wlr_xdg_toplevel,
XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
// TODO: wlr_xdg_toplevel_set_bounds()
return;
}
@ -575,7 +577,4 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) {
wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base);
xdg_toplevel->base->data = xdg_shell_view;
wlr_xdg_toplevel_set_wm_capabilities(xdg_toplevel,
XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
}

View file

@ -71,7 +71,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
surface->set_geometry.notify = unmanaged_handle_set_geometry;
}
if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
if (wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
struct sway_seat *seat = input_manager_current_seat();
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
@ -96,7 +96,7 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
// This simply returns focus to the parent surface if there's one available.
// This seems to handle JetBrains issues.
if (xsurface->parent && xsurface->parent->surface
&& wlr_xwayland_or_surface_wants_focus(xsurface->parent)) {
&& wlr_xwayland_surface_override_redirect_wants_focus(xsurface->parent)) {
seat_set_focus_surface(seat, xsurface->parent->surface, false);
return;
}

View file

@ -25,6 +25,7 @@
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/scene_descriptor.h"
#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
@ -107,7 +108,7 @@ struct sway_node *node_at_coords(
return NULL;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) {
return NULL;
}
@ -577,7 +578,7 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor,
// tablet events until the drag is released, even if we are now over a
// non-tablet surface.
if (!cursor->simulating_pointer_from_tool_tip &&
((surface && wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) ||
((surface && wlr_surface_accepts_tablet_v2(surface, tablet->tablet_v2)) ||
wlr_tablet_tool_v2_has_implicit_grab(tool->tablet_v2_tool))) {
seatop_tablet_tool_motion(seat, tool, time_msec);
} else {
@ -663,7 +664,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec,
BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
} else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
} else if (!surface || !wlr_surface_accepts_tablet_v2(surface, tablet_v2)) {
// If we started holding the tool tip down on a surface that accepts
// tablet v2, we should notify that surface if it gets released over a
// surface that doesn't support v2.
@ -748,7 +749,7 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
bool mod_pressed = modifiers & config->floating_mod;
bool surface_supports_tablet_events =
surface && wlr_surface_accepts_tablet_v2(tablet_v2, surface);
surface && wlr_surface_accepts_tablet_v2(surface, tablet_v2);
// Simulate pointer when:
// 1. The modifier key is pressed, OR

View file

@ -13,6 +13,7 @@
#include "sway/input/seat.h"
#include "sway/input/cursor.h"
#include "sway/ipc-server.h"
#include "sway/server.h"
#include "log.h"
#if WLR_HAS_SESSION
@ -32,6 +33,7 @@ static struct modifier_key {
{ XKB_MOD_NAME_NUM, WLR_MODIFIER_MOD2 },
{ "Mod3", WLR_MODIFIER_MOD3 },
{ XKB_MOD_NAME_LOGO, WLR_MODIFIER_LOGO },
{ "Super", WLR_MODIFIER_LOGO },
{ "Mod5", WLR_MODIFIER_MOD5 },
};
@ -507,12 +509,13 @@ static void handle_key_event(struct sway_keyboard *keyboard,
}
if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
// If the pressed event was sent to a client, also send the released
// If the pressed event was sent to a client and we have a focused
// surface immediately before this event, also send the released
// event. In particular, don't send the released event to the IM grab.
bool pressed_sent = update_shortcut_state(
&keyboard->state_pressed_sent, event->keycode,
event->state, keyinfo.keycode, 0);
if (pressed_sent) {
if (pressed_sent && seat->wlr_seat->keyboard_state.focused_surface) {
wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
event->keycode, event->state);
@ -958,16 +961,8 @@ cleanup:
free(sway_group);
}
void sway_keyboard_configure(struct sway_keyboard *keyboard) {
struct input_config *input_config =
input_device_get_config(keyboard->seat_device->input_device);
if (!sway_assert(!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr),
"sway_keyboard_configure should not be called with a "
"keyboard group's keyboard")) {
return;
}
static void sway_keyboard_set_layout(struct sway_keyboard *keyboard,
struct input_config *input_config) {
struct xkb_keymap *keymap = sway_keyboard_compile_keymap(input_config, NULL);
if (!keymap) {
sway_log(SWAY_ERROR, "Failed to compile keymap. Attempting defaults");
@ -983,31 +978,13 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
!wlr_keyboard_keymaps_match(keyboard->keymap, keymap) : true;
bool effective_layout_changed = keyboard->effective_layout != 0;
int repeat_rate = 25;
if (input_config && input_config->repeat_rate != INT_MIN) {
repeat_rate = input_config->repeat_rate;
}
int repeat_delay = 600;
if (input_config && input_config->repeat_delay != INT_MIN) {
repeat_delay = input_config->repeat_delay;
}
bool repeat_info_changed = keyboard->repeat_rate != repeat_rate ||
keyboard->repeat_delay != repeat_delay;
if (keymap_changed || repeat_info_changed || config->reloading) {
if (keymap_changed || config->reloading) {
xkb_keymap_unref(keyboard->keymap);
keyboard->keymap = keymap;
keyboard->effective_layout = 0;
keyboard->repeat_rate = repeat_rate;
keyboard->repeat_delay = repeat_delay;
sway_keyboard_group_remove_invalid(keyboard);
wlr_keyboard_set_keymap(keyboard->wlr, keyboard->keymap);
wlr_keyboard_set_repeat_info(keyboard->wlr,
keyboard->repeat_rate, keyboard->repeat_delay);
if (!keyboard->wlr->group) {
sway_keyboard_group_add(keyboard);
}
@ -1058,6 +1035,49 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
wlr_seat_set_keyboard(seat, keyboard->wlr);
}
if (keymap_changed) {
ipc_event_input("xkb_keymap",
keyboard->seat_device->input_device);
} else if (effective_layout_changed) {
ipc_event_input("xkb_layout",
keyboard->seat_device->input_device);
}
}
void sway_keyboard_configure(struct sway_keyboard *keyboard) {
struct input_config *input_config =
input_device_get_config(keyboard->seat_device->input_device);
if (!sway_assert(!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr),
"sway_keyboard_configure should not be called with a "
"keyboard group's keyboard")) {
return;
}
int repeat_rate = 25;
if (input_config && input_config->repeat_rate != INT_MIN) {
repeat_rate = input_config->repeat_rate;
}
int repeat_delay = 600;
if (input_config && input_config->repeat_delay != INT_MIN) {
repeat_delay = input_config->repeat_delay;
}
bool repeat_info_changed = keyboard->repeat_rate != repeat_rate ||
keyboard->repeat_delay != repeat_delay;
if (repeat_info_changed || config->reloading) {
keyboard->repeat_rate = repeat_rate;
keyboard->repeat_delay = repeat_delay;
wlr_keyboard_set_repeat_info(keyboard->wlr,
keyboard->repeat_rate, keyboard->repeat_delay);
}
if (!keyboard->seat_device->input_device->is_virtual) {
sway_keyboard_set_layout(keyboard, input_config);
}
wl_list_remove(&keyboard->keyboard_key.link);
wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
keyboard->keyboard_key.notify = handle_keyboard_key;
@ -1067,13 +1087,6 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
&keyboard->keyboard_modifiers);
keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
if (keymap_changed) {
ipc_event_input("xkb_keymap",
keyboard->seat_device->input_device);
} else if (effective_layout_changed) {
ipc_event_input("xkb_layout",
keyboard->seat_device->input_device);
}
}
void sway_keyboard_destroy(struct sway_keyboard *keyboard) {

View file

@ -132,6 +132,16 @@ static bool set_click_method(struct libinput_device *device,
return true;
}
static bool set_clickfinger_button_map(struct libinput_device *device,
enum libinput_config_clickfinger_button_map map) {
if (libinput_device_config_click_get_clickfinger_button_map(device) == map) {
return false;
}
sway_log(SWAY_DEBUG, "clickfinger_set_button_map(%d)", map);
log_status(libinput_device_config_click_set_clickfinger_button_map(device, map));
return true;
}
static bool set_middle_emulation(struct libinput_device *dev,
enum libinput_config_middle_emulation_state mid) {
if (!libinput_device_config_middle_emulation_is_available(dev) ||
@ -281,6 +291,9 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device
if (ic->click_method != INT_MIN) {
changed |= set_click_method(device, ic->click_method);
}
if (ic->clickfinger_button_map != INT_MIN) {
changed |= set_clickfinger_button_map(device, ic->clickfinger_button_map);
}
if (ic->middle_emulation != INT_MIN) {
changed |= set_middle_emulation(device, ic->middle_emulation);
}
@ -356,6 +369,8 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
libinput_device_config_left_handed_get_default(device));
changed |= set_click_method(device,
libinput_device_config_click_get_default_method(device));
changed |= set_clickfinger_button_map(device,
libinput_device_config_click_get_default_clickfinger_button_map(device));
changed |= set_middle_emulation(device,
libinput_device_config_middle_emulation_get_default_enabled(device));
changed |= set_scroll_method(device,

View file

@ -190,7 +190,7 @@ static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) {
node->sway_container->view : NULL;
if (view && seat_is_input_allowed(seat, view->surface)) {
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
if (view->type == SWAY_VIEW_XWAYLAND) {
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
@ -802,11 +802,10 @@ static void seat_configure_keyboard(struct sway_seat *seat,
return;
}
// force notify reenter to pick up the new configuration. This reuses
// Notify reenter to pick up the new configuration. This reuses
// the current focused surface to avoid breaking input grabs.
struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface;
if (surface) {
wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat);
seat_keyboard_notify_enter(seat, surface);
}
}
@ -1002,7 +1001,7 @@ void seat_configure_xcursor(struct sway_seat *seat) {
setenv("XCURSOR_THEME", cursor_theme, 1);
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
if (server.xwayland.wlr_xwayland && (!server.xwayland.xcursor_manager ||
!xcursor_manager_is_named(server.xwayland.xcursor_manager,
cursor_theme) ||

View file

@ -11,11 +11,12 @@
#include "sway/input/tablet.h"
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/scene_descriptor.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "log.h"
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
#include "sway/xwayland.h"
#endif
@ -234,7 +235,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
node->sway_container : NULL;
struct wlr_layer_surface_v1 *layer;
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct wlr_xwayland_surface *xsurface;
#endif
if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) &&
@ -268,11 +269,11 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
seat_set_focus_container(seat, cont);
seatop_begin_down(seat, node->sway_container, sx, sy);
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
// Handle tapping on an xwayland unmanaged view
else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
xsurface->override_redirect &&
wlr_xwayland_or_surface_wants_focus(xsurface)) {
wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
seat_set_focus_surface(seat, xsurface->surface, false);
@ -514,13 +515,13 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
return;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
// Handle clicking on xwayland unmanaged view
struct wlr_xwayland_surface *xsurface;
if (surface &&
(xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
xsurface->override_redirect &&
wlr_xwayland_or_surface_wants_focus(xsurface)) {
wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
seat_set_focus_surface(seat, xsurface->surface, false);
@ -666,7 +667,7 @@ static void handle_touch_down(struct sway_seat *seat,
double sx, sy;
node_at_coords(seat, seat->touch_x, seat->touch_y, &surface, &sx, &sy);
if (surface && wlr_surface_accepts_touch(wlr_seat, surface)) {
if (surface && wlr_surface_accepts_touch(surface, wlr_seat)) {
if (seat_is_input_allowed(seat, surface)) {
cursor->simulating_pointer_from_touch = false;
seatop_begin_touch_down(seat, surface, event, sx, sy, lx, ly);

View file

@ -1,5 +1,6 @@
#include "sway/config.h"
#include "sway/input/switch.h"
#include "sway/server.h"
#include "log.h"
struct sway_switch *sway_switch_create(struct sway_seat *seat,

View file

@ -7,6 +7,7 @@
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/input/tablet.h"
#include "sway/server.h"
#if WLR_HAS_LIBINPUT_BACKEND
#include <wlr/backend/libinput.h>
@ -362,7 +363,7 @@ void sway_tablet_pad_set_focus(struct sway_tablet_pad *tablet_pad,
}
if (surface == NULL ||
!wlr_surface_accepts_tablet_v2(tablet_pad->tablet->tablet_v2, surface)) {
!wlr_surface_accepts_tablet_v2(surface, tablet_pad->tablet->tablet_v2)) {
return;
}

View file

@ -9,6 +9,8 @@
#include "sway/input/text_input.h"
#include "sway/input/text_input_popup.h"
#include "sway/layers.h"
#include "sway/server.h"
static void input_popup_update(struct sway_input_popup *popup);
static struct sway_text_input *relay_get_focusable_text_input(
@ -66,11 +68,13 @@ static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *
struct sway_input_method_relay *relay = wl_container_of(listener, relay,
input_method_keyboard_grab_destroy);
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
struct wlr_seat *wlr_seat = keyboard_grab->input_method->seat;
wl_list_remove(&relay->input_method_keyboard_grab_destroy.link);
if (keyboard_grab->keyboard) {
// send modifier state to original client
wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat,
wlr_seat_set_keyboard(wlr_seat, keyboard_grab->keyboard);
wlr_seat_keyboard_notify_modifiers(wlr_seat,
&keyboard_grab->keyboard->modifiers);
}
}

View file

@ -11,6 +11,7 @@
#include "log.h"
#include "sway/config.h"
#include "sway/ipc-json.h"
#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@ -154,7 +155,7 @@ static json_object *ipc_json_output_mode_description(
return mode_object;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
static const char *ipc_json_xwindow_type_description(struct sway_view *view) {
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
struct sway_xwayland *xwayland = &server.xwayland;
@ -577,9 +578,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
bool visible = view_is_visible(c->view);
json_object_object_add(object, "visible", json_object_new_boolean(visible));
bool has_titlebar = c->title_bar.tree->node.enabled;
struct wlr_box window_box = {
c->pending.content_x - c->pending.x,
(c->current.border == B_PIXEL) ? c->pending.content_y - c->pending.y : 0,
has_titlebar ? 0 : c->pending.content_y - c->pending.y,
c->pending.content_width,
c->pending.content_height
};
@ -633,7 +635,7 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
json_object_new_string(ipc_json_content_type_description(content_type)));
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
if (c->view->type == SWAY_VIEW_XWAYLAND) {
json_object_object_add(object, "window",
json_object_new_int(view_get_x11_window_id(c->view)));
@ -990,6 +992,18 @@ static json_object *describe_libinput_device(struct libinput_device *device) {
}
json_object_object_add(object, "click_method",
json_object_new_string(click_method));
const char *button_map = "unknown";
switch (libinput_device_config_click_get_clickfinger_button_map(device)) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
button_map = "lrm";
break;
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
button_map = "lmr";
break;
}
json_object_object_add(object, "clickfinger_button_map",
json_object_new_string(button_map));
}
if (libinput_device_config_middle_emulation_is_available(device)) {

View file

@ -154,6 +154,7 @@ sway_sources = files(
'commands/input/accel_profile.c',
'commands/input/calibration_matrix.c',
'commands/input/click_method.c',
'commands/input/clickfinger_button_map.c',
'commands/input/drag.c',
'commands/input/drag_lock.c',
'commands/input/dwt.c',
@ -202,6 +203,7 @@ sway_sources = files(
'commands/output/toggle.c',
'commands/output/transform.c',
'commands/output/unplug.c',
'commands/output/color_profile.c',
'tree/arrange.c',
'tree/container.c',
@ -231,7 +233,7 @@ sway_deps = [
xcb_icccm,
]
if have_xwayland
if wlroots_features['xwayland']
sway_sources += 'desktop/xwayland.c'
endif

View file

@ -56,7 +56,7 @@
#include "sway/input/cursor.h"
#include "sway/tree/root.h"
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
#include <wlr/xwayland/shell.h>
#include "sway/xwayland.h"
#endif
@ -113,12 +113,13 @@ static bool is_privileged(const struct wl_global *global) {
global == server.input->keyboard_shortcuts_inhibit->global ||
global == server.input->virtual_keyboard->global ||
global == server.input->virtual_pointer->global ||
global == server.input->transient_seat_manager->global;
global == server.input->transient_seat_manager->global ||
global == server.xdg_output_manager_v1->global;
}
static bool filter_global(const struct wl_client *client,
const struct wl_global *global, void *data) {
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
if (xwayland && global == xwayland->shell_v1->global) {
return xwayland->server != NULL && client == xwayland->server->client;
@ -240,14 +241,13 @@ bool server_init(struct sway_server *server) {
wlr_renderer_init_wl_shm(server->renderer, server->wl_display);
if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) {
if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) {
server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer(
server->wl_display, 4, server->renderer);
}
if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL &&
debug.legacy_wl_drm) {
if (debug.legacy_wl_drm) {
wlr_drm_create(server->wl_display, server->renderer);
}
}
server->allocator = wlr_allocator_autocreate(server->backend,
server->renderer);
@ -276,6 +276,7 @@ bool server_init(struct sway_server *server) {
wl_signal_add(&root->output_layout->events.change,
&server->output_layout_change);
server->xdg_output_manager_v1 =
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display);
@ -438,7 +439,7 @@ bool server_init(struct sway_server *server) {
void server_fini(struct sway_server *server) {
// TODO: free sway-specific resources
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
wlr_xwayland_destroy(server->xwayland.wlr_xwayland);
#endif
wl_display_destroy_clients(server->wl_display);
@ -448,7 +449,7 @@ void server_fini(struct sway_server *server) {
}
bool server_start(struct sway_server *server) {
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
if (config->xwayland != XWAYLAND_MODE_DISABLED) {
sway_log(SWAY_DEBUG, "Initializing Xwayland (lazy=%d)",
config->xwayland == XWAYLAND_MODE_LAZY);

View file

@ -143,6 +143,12 @@ The following commands may only be used in the configuration file.
*input* <identifier> click_method none|button_areas|clickfinger
Changes the click method for the specified device.
*input* <identifier> clickfinger_button_map lrm|lmr
Specifies which button mapping to use for clickfinger. _lrm_ treats 1 finger as
left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_
treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as
right click.
*input* <identifier> drag enabled|disabled
Enables or disables tap-and-drag for specified input device.

View file

@ -1168,7 +1168,7 @@ following properties will be included for devices that support them:
: Whether tap to click is enabled. It can be _enabled_ or _disabled_
|- tap_button_map
: string
: The finger to button mapping in use. It can be _lmr_ or _lrm_
: The finger to button mapping in use for tapping. It can be _lmr_ or _lrm_
|- tap_drag
: string
: Whether tap-and-drag is enabled. It can be _enabled_ or _disabled_
@ -1190,6 +1190,9 @@ following properties will be included for devices that support them:
|- click_method
: string
: The click method in use. It can be _none_, _button_areas_, or _clickfinger_
|- click_button_map
: string
: The finger to button mapping in use for clickfinger. It can be _lmr_ or _lrm_
|- middle_emulation
: string
: Whether middle emulation is enabled. It can be _enabled_ or _disabled_

View file

@ -178,6 +178,18 @@ must be separated by one space. For example:
updated to work with different bit depths. This command is experimental,
and may be removed or changed in the future.
*output* <name> color_profile srgb|[icc <file>]
Sets the color profile for an output. The default is _srgb_. <file> should be a
path to a display ICC profile.
Not all renderers support this feature; currently it only works with the
the Vulkan renderer. Even where supported, the application of the color
profile may be inaccurate.
This command is experimental, and may be removed or changed in the future. It
may have no effect or produce unexpected output when used together with future
HDR support features.
# SEE ALSO
*sway*(5) *sway-input*(5)

View file

@ -403,8 +403,8 @@ runtime.
For specifying modifier keys, you can use the XKB modifier names _Shift_,
_Lock_ (for Caps Lock), _Control_, _Mod1_ (for Alt), _Mod2_ (for Num Lock),
_Mod3_ (for XKB modifier Mod3), _Mod4_ (for the Logo key), and _Mod5_ (for
AltGr). In addition, you can use the aliases _Ctrl_ (for Control) and _Alt_
(for Alt).
AltGr). In addition, you can use the aliases _Ctrl_ (for Control), _Alt_
(for Alt), and _Super_ (for the Logo key).
Unless the flag _--locked_ is set, the command will not be run when a
screen locking program is active. If there is a matching binding with

View file

@ -58,7 +58,7 @@ struct text_buffer {
static int get_text_width(struct sway_text_node *props) {
int width = props->width;
if (props->max_width) {
if (props->max_width >= 0) {
width = MIN(width, props->max_width);
}
return MAX(width, 0);
@ -81,6 +81,11 @@ static void render_backing_buffer(struct text_buffer *buffer) {
return;
}
if (buffer->props.max_width == 0) {
wlr_scene_buffer_set_buffer(buffer->buffer_node, NULL);
return;
}
float scale = buffer->scale;
int width = ceil(buffer->props.width * scale);
int height = ceil(buffer->props.height * scale);
@ -236,6 +241,7 @@ struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent,
buffer->buffer_node = node;
buffer->props.node = &node->node;
buffer->props.max_width = -1;
buffer->text = strdup(text);
if (!buffer->text) {
free(buffer);
@ -288,6 +294,9 @@ void sway_text_node_set_text(struct sway_text_node *node, char *text) {
void sway_text_node_set_max_width(struct sway_text_node *node, int max_width) {
struct text_buffer *buffer = wl_container_of(node, buffer, props);
if (max_width == buffer->props.max_width) {
return;
}
buffer->props.max_width = max_width;
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
get_text_width(&buffer->props), buffer->props.height);
@ -297,6 +306,9 @@ void sway_text_node_set_max_width(struct sway_text_node *node, int max_width) {
void sway_text_node_set_background(struct sway_text_node *node, float background[4]) {
struct text_buffer *buffer = wl_container_of(node, buffer, props);
if (memcmp(&node->background, background, sizeof(*background) * 4) == 0) {
return;
}
memcpy(&node->background, background, sizeof(*background) * 4);
render_backing_buffer(buffer);
}

View file

@ -352,6 +352,8 @@ void container_arrange_title_bar(struct sway_container *con) {
int alloc_width = MIN((int)node->width,
width - h_padding - config->titlebar_h_padding);
alloc_width = MAX(alloc_width, 0);
sway_text_node_set_max_width(node, alloc_width);
wlr_scene_node_set_position(node->node,
h_padding, (height - node->height) >> 1);
@ -376,6 +378,8 @@ void container_arrange_title_bar(struct sway_container *con) {
int alloc_width = MIN((int) node->width,
width - h_padding - config->titlebar_h_padding);
alloc_width = MAX(alloc_width, 0);
sway_text_node_set_max_width(node, alloc_width);
wlr_scene_node_set_position(node->node,
h_padding, (height - node->height) >> 1);

View file

@ -279,6 +279,7 @@ void output_destroy(struct sway_output *output) {
list_free(output->workspaces);
list_free(output->current.workspaces);
wl_event_source_remove(output->repaint_timer);
wlr_color_transform_unref(output->color_transform);
free(output);
}

View file

@ -53,7 +53,7 @@ struct sway_root *root_create(struct wl_display *wl_display) {
root->layers.shell_top = alloc_scene_tree(root->layer_tree, &failed);
root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed);
root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed);
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
root->layers.unmanaged = alloc_scene_tree(root->layer_tree, &failed);
#endif
root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed);

View file

@ -1,16 +1,17 @@
#include <stdlib.h>
#include <strings.h>
#include <wayland-server-core.h>
#include <wlr/config.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include "config.h"
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
#include <wlr/xwayland.h>
#endif
#include "list.h"
@ -126,7 +127,7 @@ const char *view_get_instance(struct sway_view *view) {
}
return NULL;
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
uint32_t view_get_x11_window_id(struct sway_view *view) {
if (view->impl->get_int_prop) {
return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID);
@ -159,7 +160,7 @@ const char *view_get_shell(struct sway_view *view) {
switch(view->type) {
case SWAY_VIEW_XDG_SHELL:
return "xdg_shell";
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
case SWAY_VIEW_XWAYLAND:
return "xwayland";
#endif
@ -173,9 +174,9 @@ void view_get_constraints(struct sway_view *view, double *min_width,
view->impl->get_constraints(view,
min_width, max_width, min_height, max_height);
} else {
*min_width = DBL_MIN;
*min_width = 1;
*max_width = DBL_MAX;
*min_height = DBL_MIN;
*min_height = 1;
*max_height = DBL_MAX;
}
}
@ -365,8 +366,8 @@ void view_autoconfigure(struct sway_view *view) {
con->pending.content_x = x;
con->pending.content_y = y;
con->pending.content_width = width;
con->pending.content_height = height;
con->pending.content_width = fmax(width, 1);
con->pending.content_height = fmax(height, 1);
}
void view_set_activated(struct sway_view *view, bool activated) {
@ -499,7 +500,7 @@ void view_execute_criteria(struct sway_view *view) {
static void view_populate_pid(struct sway_view *view) {
pid_t pid;
switch (view->type) {
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
case SWAY_VIEW_XWAYLAND:;
struct wlr_xwayland_surface *surf =
wlr_xwayland_surface_try_from_wlr_surface(view->surface);
@ -741,6 +742,14 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
ws = select_workspace(view);
}
if (ws && ws->output) {
// Once the output is determined, we can notify the client early about
// scale to reduce startup jitter.
float scale = ws->output->wlr_output->scale;
wlr_fractional_scale_v1_notify_scale(wlr_surface, scale);
wlr_surface_set_preferred_buffer_scale(wlr_surface, ceil(scale));
}
struct sway_seat *seat = input_manager_current_seat();
struct sway_node *node =
seat_get_focus_inactive(seat, ws ? &ws->node : &root->node);
@ -838,10 +847,10 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
bool set_focus = should_focus(view);
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct wlr_xwayland_surface *xsurface;
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) {
set_focus &= wlr_xwayland_icccm_input_model(xsurface) !=
set_focus &= wlr_xwayland_surface_icccm_input_model(xsurface) !=
WLR_ICCCM_INPUT_MODEL_NONE;
}
#endif
@ -927,11 +936,14 @@ void view_update_size(struct sway_view *view) {
void view_center_and_clip_surface(struct sway_view *view) {
struct sway_container *con = view->container;
bool clip_to_geometry = true;
if (container_is_floating(con)) {
// We always center the current coordinates rather than the next, as the
// geometry immediately affects the currently active rendering.
int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2);
int y = (int) fmax(0, (con->current.content_height - view->geometry.height) / 2);
clip_to_geometry = !view->using_csd;
wlr_scene_node_set_position(&view->content_tree->node, x, y);
} else {
@ -940,12 +952,16 @@ void view_center_and_clip_surface(struct sway_view *view) {
// only make sure to clip the content if there is content to clip
if (!wl_list_empty(&con->view->content_tree->children)) {
wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &(struct wlr_box){
struct wlr_box clip = {0};
if (clip_to_geometry) {
clip = (struct wlr_box){
.x = con->view->geometry.x,
.y = con->view->geometry.y,
.width = con->current.content_width,
.height = con->current.content_height,
});
};
}
wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &clip);
}
}
@ -954,7 +970,7 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) {
return view_from_wlr_xdg_surface(xdg_surface);
}
#if HAVE_XWAYLAND
#if WLR_HAS_XWAYLAND
struct wlr_xwayland_surface *xsurface;
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) {
return view_from_wlr_xwayland_surface(xsurface);
@ -1178,7 +1194,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
ipc_event_window(view->container, "urgent");
if (!container_is_scratchpad_hidden(view->container)) {
if (!container_is_scratchpad_hidden_or_child(view->container)) {
workspace_detect_urgent(view->container->pending.workspace);
}
}

View file

@ -10,6 +10,7 @@
#include "sway/input/seat.h"
#include "sway/ipc-server.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/node.h"
@ -707,6 +708,11 @@ void workspace_for_each_container(struct sway_workspace *ws,
struct sway_container *workspace_find_container(struct sway_workspace *ws,
bool (*test)(struct sway_container *con, void *data), void *data) {
struct sway_container *result = NULL;
if (ws == NULL){
sway_log(SWAY_ERROR, "Cannot find container with no workspace.");
return NULL;
}
// Tiling
for (int i = 0; i < ws->tiling->length; ++i) {
struct sway_container *child = ws->tiling->items[i];

View file

@ -38,14 +38,14 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
}
// This is an activation request. If this context is internal we have ctx->seat.
struct sway_seat *seat = ctx->seat;
if (!seat) {
// Otherwise, use the seat indicated by the launcher client in set_serial
seat = ctx->token->seat ? ctx->token->seat->data : NULL;
if (ctx->seat) {
view_request_activate(view, ctx->seat);
return;
}
if (seat && ctx->had_focused_surface) {
view_request_activate(view, seat);
// Otherwise, activate if passed from another focused client
if (ctx->token->seat && ctx->had_focused_surface) {
view_request_activate(view, ctx->token->seat->data);
} else {
// The token is valid, but cannot be used to activate a window
view_request_urgent(view);