mirror of
https://github.com/swaywm/sway.git
synced 2024-11-27 18:31:28 +00:00
Merge branch 'master' into reduce-redundant-containers
This commit is contained in:
commit
c32e795053
|
@ -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
|
||||
|
|
|
@ -3,6 +3,7 @@ packages:
|
|||
- cairo
|
||||
- gdk-pixbuf2
|
||||
- json-c
|
||||
- lcms2
|
||||
- libdisplay-info
|
||||
- libegl
|
||||
- libinput
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
47
meson.build
47
meson.build
|
@ -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(),
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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 },
|
||||
|
|
27
sway/commands/input/clickfinger_button_map.c
Normal file
27
sway/commands/input/clickfinger_button_map.c
Normal 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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 },
|
||||
|
|
101
sway/commands/output/color_profile.c
Normal file
101
sway/commands/output/color_profile.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
// 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;
|
||||
}
|
||||
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);
|
||||
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,8 +898,18 @@ 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");
|
||||
goto out;
|
||||
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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
wlr_scene_output_commit(output->scene_output, NULL);
|
||||
if (!wlr_output_commit_state(output->wlr_output, &pending)) {
|
||||
sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
@ -1107,9 +1121,9 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
|
|||
struct xkb_keymap *keymap = keyboard->keymap;
|
||||
struct xkb_state *state = keyboard->xkb_state;
|
||||
|
||||
json_object_object_add(object, "repeat_delay",
|
||||
json_object_object_add(object, "repeat_delay",
|
||||
json_object_new_int(keyboard->repeat_info.delay));
|
||||
json_object_object_add(object, "repeat_rate",
|
||||
json_object_object_add(object, "repeat_rate",
|
||||
json_object_new_int(keyboard->repeat_info.rate));
|
||||
|
||||
json_object *layouts_arr = json_object_new_array();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,13 +241,12 @@ 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) {
|
||||
wlr_drm_create(server->wl_display, server->renderer);
|
||||
if (debug.legacy_wl_drm) {
|
||||
wlr_drm_create(server->wl_display, server->renderer);
|
||||
}
|
||||
}
|
||||
|
||||
server->allocator = wlr_allocator_autocreate(server->backend,
|
||||
|
@ -276,7 +276,8 @@ bool server_init(struct sway_server *server) {
|
|||
wl_signal_add(&root->output_layout->events.change,
|
||||
&server->output_layout_change);
|
||||
|
||||
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
|
||||
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);
|
||||
sway_idle_inhibit_manager_v1_init();
|
||||
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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){
|
||||
.x = con->view->geometry.x,
|
||||
.y = con->view->geometry.y,
|
||||
.width = con->current.content_width,
|
||||
.height = con->current.content_height,
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue