Compare commits

...

242 commits
1.10 ... master

Author SHA1 Message Date
llyyr
055be4ec35 sway/server: advertise gamma2.2 and bt1886 transfer functions 2025-10-28 23:34:18 +01:00
bonsaiiV
b7eb6177e1
sway/commands/layout: fix flatten parent once
Fixes: f50e307227 ("sway/commands/layout: flatten parent once")
2025-10-18 18:55:46 +02:00
llyyr
90d3270970 sway/input/cursor: send frame event when simulating pointer from tablet 2025-10-05 19:46:53 +02:00
Louis POIROT--HATTERMANN
ecfea6b8ae commands/scratchpad: don't hide scratchpad if no pending workspace
Fixes: https://github.com/swaywm/sway/issues/8909
2025-10-05 19:22:48 +02:00
nyxed
b4a9a1716f build: switch to explicit 'meson setup' syntax 2025-10-02 18:06:20 +02:00
llyyr
d9e615c507 sway/server: set color_manager for root scene
Chase https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5122/
2025-09-23 23:50:15 +02:00
Felix Pehla
bc96d0acdf README: update German translation
Update the information about display manager support (see #8861), as
well as markdown formatting of links and change some wording in the
German README.
2025-09-18 11:18:07 +02:00
Simon Ser
a7d9535eb3 input/text_input: stop using listener data
These are now NULL.

Fixes: aaab7f961e ("input/text_input: chase wlroots update")
Closes: https://github.com/swaywm/sway/issues/8864
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5107
2025-09-15 07:41:51 +02:00
nortio
7c1e192ea3
Update README.it.md for Italian
Updated italian readme to follow the recent changes to the English one.
I also removed "gestore di accesso" which in theory translates to
display manager, but in practice is never used in this context. Other
wikis such as [Debian](https://wiki.debian.org/it/DisplayManager) and
[Ubuntu](https://wiki.ubuntu-it.org/AmbienteGrafico/DisplayManager) just
use the term "Display Manager" as is. Another small thing that I
corrected is "canale di IRC" which sounds a bit weird.
2025-09-14 19:38:17 +02:00
aceydot
50a8750e01
Add Serbian README 2025-09-12 19:55:36 +02:00
Martin Dørum
a41b25020d
Update Norwegian README to make it more in line with the English one, as well as improving grammar 2025-09-12 15:43:30 +02:00
Kirill Chibisov
35b69158d7 readme: sync Japanese translation 2025-09-12 15:28:31 +02:00
Kirill Chibisov
862e9b8c20 readme: sync Russian translation 2025-09-12 15:28:31 +02:00
Oto Šťáva
68ac52ffc2 readme: Update and reword Czech translation 2025-09-11 23:48:16 +02:00
Przemysław Gasiński
e6fc3ffa3f readme: Update Polish translation regarding the support of display managers 2025-09-11 23:46:57 +02:00
Martin Dørum
70c51c44f6 update danish readme to reflect that display managers are supported 2025-09-11 17:20:07 +02:00
Simon Ser
ca45c22376 readme: mark display managers as supported
It's been a long while since we've heard about issues related to
display managers. Some used to be unreliable in the past, but by
now most issues have been ironed out. Let's start supporting them
officially.

I've considered translating other languages but I'm concerned about
messing up the sentence. I've updated languages I'm comfortable
with.
2025-09-11 14:14:51 +00:00
Nikola Kocic
c5456be750 xdg-shell: fix reported WM capabilities
Previously it was reporting window_menu and maximize instead of fullscreen because wlr_xdg_toplevel_set_wm_capabilities expects a bitmask (WLR_XDG_TOPLEVEL_WM_CAPABILITIES_*), and XDG_TOPLEVEL_WM_CAPABILITIES_* are supposed to be used as values in wl_array, so the values are different:
XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 4
2025-09-09 13:55:46 +02:00
Bill Li
aaab7f961e input/text_input: chase wlroots update
References:https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5107
2025-09-08 15:54:59 +00:00
Kenny Levinsen
73c244fb48 config/output: Only error when enabling HDR
We currently emit errors about HDR support even if HDR is not being
requested, which mean errors on every regular modeset when monitors not
supporting HDR are connected.

Only emit errors when attempting to enable HDR on such device.
2025-08-22 15:49:09 +02:00
Simon Ser
b3dcde8d69 Stop generating wayland-protocols server headers
We still need to generate wlr-protocols server headers, as well as
client headers and code.

References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5075
2025-08-14 10:09:59 +02:00
Joaquim Monteiro
0770a8d643 Add wl_fixes interface 2025-08-13 22:58:21 +02:00
Tim Hallmann
340505bb6f commands/resize: make resize consider all siblings
Fixes a compatibility issue with i3 where resizing works as described
hereafter:
> Direction can either be one of up, down, left or right. Or you can be
> less specific and use width or height, in which case i3 will take/give
> space from all the other containers.

Sway previously considered only the direct neighbours, not all siblings.

Fixes #5936
2025-08-03 20:15:39 +02:00
bonsaiiV
f50e307227
sway/commands/layout: flatten parent once
Applying layout changes to the parent of the parent, in case the parent only has a single child, stops the creation of a chain of single child containers.

Closes: https://github.com/swaywm/sway/issues/7945
2025-08-03 15:25:40 +02:00
Tomasz Buczyński
87fbcf0574 Add cursor->hidden check to handle_rebase
Fixes #6245
2025-08-03 15:01:21 +02:00
Kenny Levinsen
357d341f8f tree/node: Do not mark destroying nodes as dirty
Node destruction currently runs through the transaction system such that
a particular node is only destroyed after its use in an ongoing
transaction. If a node is dirtied after the node is marked as destroying
but before it is destroyed, the pointer added to dirty_nodes would
become a dangling pointer once the node was destroyed.

Do not dirty destroying nodes, and ensure that destroying is only set
after the last dirty.
2025-07-31 15:57:28 +02:00
Simon Ser
14fbe9242f Revert drag_lock default to disabled
I misunderstood the recommendation in the libinput release notes.
Instead of making enabled_sticky the default, leave the default
set to disabled.

Fixes: bbadf9b8b1 ("Add support for LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY")
Closes: https://github.com/swaywm/sway/issues/8758
2025-07-29 09:41:19 +02:00
Fenveireth
e50b16a699 tree/view: save new wlr_scene_buffer fields
Visble flicker can occur during transactions, if these are not copied
to the 'saved' scene
2025-07-20 15:16:03 +02:00
Simon Ser
cb33701f5e Add xdg_toplevel tag to criteria 2025-07-16 10:03:09 +02:00
Simon Ser
08142c3f3a Add xdg_toplevel tag to IPC 2025-07-16 10:03:09 +02:00
Simon Ser
3826535ab0 Wire up xdg-toplevel-tag-v1 2025-07-16 10:03:09 +02:00
Nuran Askarov
f57c82a6f7 Add link to README.az.md 2025-07-09 16:57:14 +02:00
Nuran Askarov
8d7c756276 Add README.az.md 2025-07-09 16:57:14 +02:00
Simon Ser
94c819cc1f Add features.hdr to output IPC response 2025-07-09 01:25:11 +02:00
Simon Ser
6fed1f9d89 Add support for color-management-v1
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4962
2025-07-09 01:25:11 +02:00
Simon Ser
bac8c0f4d0 Add support for HDR10 output 2025-07-09 01:25:11 +02:00
Simon Ser
c7d7d56f61 ipc-json, swaymsg: indicate when adaptive sync is unsupported 2025-07-08 15:58:53 +02:00
Simon Ser
a1ac2a2e93 Drop sway_output.events.disable
In general wl_signal isn't well-suited for Sway: Sway doesn't need
any modularity, and signals make it trickier to track down exactly
what happens down the stack.

Replace Sway's output disable signal with a simple list tracking
for the only user.
2025-07-02 21:21:53 +02:00
Kenny Levinsen
56f2db062d Revert "sway/tree: Simplify sway_node teardown"
This reverts commit e28e6484e8.

This change tried to remove nodes from all points of reference to allow
immediate destruction. However, it missed things like the children lists
cloned by transaction states of parent nodes.

Adding all that extra cleanup would not be in the spirit of a PR
claiming to simplify teardown. Let's wait for someone to come up with a
cleaner approach instead.

Fixes: https://github.com/swaywm/sway/pull/8738
2025-06-28 11:26:49 +02:00
Kenny Levinsen
0cd45d4ad2 Revert "tree/container: Remove child from all lists"
This reverts commit 3d6b9a2848.
2025-06-28 11:26:49 +02:00
Kenny Levinsen
3d6b9a2848 tree/container: Remove child from all lists
When a container is detached, we need to remove it from any lists it may
be part of. We use container_get_siblings to obtain the relevant list,
find our entry and remove it.

If the container is in a later list than the one returned by
container_get_siblings, or is in multiple lists for some reason,
container_detach will fail to remove the container, leaving a dangling
pointer when the container is freed.

Instead of calling container_get_siblings, check and remove the
container from all lists.
2025-06-26 22:05:05 +02:00
Kenny Levinsen
e28e6484e8 sway/tree: Simplify sway_node teardown
A sway_node may end up being referenced in either a queued transaction,
pending transaction or as a dirty node. To manage this, the transaction
system has been responsible for destroying containers, workspaces and
outputs at the end of their last referenced transaction.

This significantly complicates the teardown flow of surfaces and
outputs. Instead, remove the node from transactions and dirty lists so
that the callsite can remove and free the node immediately.
2025-06-26 22:05:05 +02:00
Kenny Levinsen
4f59eeef05 Remove the temporary SUID warning
A temporary SUID detection that would cause sway to exit was introduced
when SUID operation was deprecated, intended to avoid cases where a user
would not heed the deprecation notice, continued to use SUID and ended
up with sway accidentally running as root.

Remove the check, as the three years that have passed is sufficient time
for users to discover the deprecation and adapt. We did not care if
users intentionally want to run sway as root through SUID, we only
wanted to avoid surprise root.
2025-06-26 22:00:05 +02:00
Simon Ser
c2f08075ec tree/view: send event unconditionally in view_send_frame_done()
Previously, we were using wl_signal_emit_mutable() directly instead
of wlr_scene_buffer_send_frame_done(). This bypassed any visibility
checks, which matters before a surface is mapped.

Fixes flickering with an invalid size when launching new programs.

Fixes: eb8acfd7b1 ("Stop using wlr_scene_buffer_send_frame_done()")
2025-06-23 10:32:31 +02:00
Simon Ser
170c9c9525 Add support for toplevel capture
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5078
2025-06-16 14:28:20 +02:00
Simon Ser
eb8acfd7b1 Stop using wlr_scene_buffer_send_frame_done()
That function now takes the output as input. We don't always have
the output at hand, so use the function operating on a
wlr_scene_surface instead.
2025-06-16 14:28:20 +02:00
hwsmm
25ea1a0af2 seatop_default: Call seatop_rebase with proper timestamp 2025-06-16 11:26:26 +02:00
hwsmm
4b15b3427f Rename get_current_time_msec to get_current_time_in_msec and move to util.c
get_current_time_msec conflicts with a function with the same name in wlroots.
2025-06-16 11:26:26 +02:00
Simon Ser
17f7c1b782 build: set wrap_mode=nodownload in default options
This can be surprising (e.g. in CI, this can download source code
instead of using system libraries) and users can easily turn it
back on if desired.
2025-06-16 09:31:15 +02:00
Attila Fidan
6c27c2cdf2 text_input: Don't relay IM state from unfocused windows
Otherwise, applications can enable their text input and affect IM state
while a different application is focused.
2025-06-14 09:19:17 +02:00
Attila Fidan
1ab573bf54 text_input: Ignore enable requests from unfocused windows
Unfocused windows shouldn't be allowed to activate the IM.

This fixes an issue with swaymsg invocations that contain several
commands which result in multiple swift focus changes. An application
briefly gets text input focus, sends an enable request, then sway
processes it and activates the IM only after the commands are all
finished and focus is on something else which did not send an enable
request.
2025-06-14 09:19:17 +02:00
Simon Ser
0a740a24d9 build: bump version to 1.12-dev 2025-06-09 16:27:18 +02:00
Callum Andrew
3d401d9390 config.in: bind XF86Audio* keycodes to playerctl 2025-06-09 15:56:41 +02:00
Simon Ser
6816b51c86 Remove trailing spaces 2025-06-05 18:15:56 +02:00
YaoBing Xiao
9fb9e9f7d5 server: fix socket path memory leak
The socket path allocated with strdup() in server_init() was
not being freed in server_fini().
Remove const qualifier and add proper cleanup.
2025-06-05 09:59:46 +02:00
Konstantin Pospelov
7e7994dbb2 swaybar: deduplicate mode and workspace rendering code
The render_workspace_button and render_binding_mode_indicator functions are
almost the same. This commit extracts the common rendering code into a new
render_box function.
2025-05-25 14:48:14 +02:00
Simon Ser
63689bfb83 Log message on for_window command error 2025-05-25 13:59:34 +02:00
Bonsaiiv
45267bb576 Improve example of input section in default config
Previous example included a specific device name. This can be confusing
for beginners, as the default did not work on most devices.
2025-05-24 16:29:03 +02:00
Kenny Levinsen
534491d3aa tree/workspace: Remove exclude arg from get_highest_available
workspace_output_get_highest_available took an output to exclude as
argument, meant to avoid accidentally reselecting an output we are
evacuating workspaces from.

Outputs are now removed from the list before we evacuate, making
exclusion unnecessary. Remove the argument.
2025-05-22 17:12:51 +02:00
Kenny Levinsen
005924f260 output: Minimize interaction with output after destroy
When an output is destroyed, we go through the process of disabling it.
This includes evacuating all content away from the output, which can
lead to various modifications to the scene. With the scene_output still
present, this can lead to things like output_enter events being emitted
for the output currently being destroyed.

Ensure that the scene output is destroyed first and that the output is
immediately considered disabled.

References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3974
2025-05-22 17:12:51 +02:00
alex-huff
88c7b4a7eb transaction: fix floating fullscreen containers
8fecf3a introduced a regression where fullscreening a child of a
floating container would result in a black screen. This is because the
order of 'arrange_fullscreen' and 'arrange_worksplace_floating' was
swapped causing the fullscreen container's scene to get reparented after
it was parented in the fullscreen layer.

Fixes #8729
2025-05-21 21:38:27 -04:00
alex-huff
1b47277962 layer-shell: reclaim space from unmapped layer surfaces
wlroots resets 'initialized' when a layer surface is unmapped and sway
doesn't rearrange the layer surfaces in response to a commit of a
surface where 'initialized' is false. This results in space not getting
reclaimed from a recently unmapped layer surface until some other action
causes 'arrange_layers' to get called. This commit makes sure all layer
surfaces get rearranged when a layer surface is unmapped.
2025-05-21 20:33:27 -04:00
Simon Ser
5cfcd1c7c2 input: fix udev_device leak
libinput_device_get_udev_device() returns a ref'ed handle:
https://wayland.freedesktop.org/libinput/doc/latest/api/group__device.html#gac13c64ba19fc19094cff0e5354a2a7ce

Similar to this wlroots MR:
https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5074
2025-05-20 17:54:44 +02:00
alex-huff
8fecf3aa8c transaction: reparent scenes of containers behind fullscreen containers
Currently we do a good job of reparenting the scenes of a container when
it moves into a disabled workspace. We need to do this since normally
the scenes are reparented in the 'arrange_{children,container}'
functions but these don't get called for disabled workspaces. However,
the 'arrange_{children,container}' functions also don't get called when
there is a fullscreen container hiding them.

This commit makes sure to call 'disable_workspace' on workspaces with a
fullscreen container so that when a container is moved into the
workspace its scenes will be properly reparented. Also, when there is a
fullscreen global container 'disable_workspace' is called for all
workspaces since the scenes of a previously fullscreen global container
may still be parented in the 'fullscreen_global' layer.
Fixes #8705 #8659 #8432
2025-05-19 18:46:09 -04:00
alex-huff
fb6d61b58f transaction: fix size of child container decorations in stacking layouts
Before this commit stacking containers with more than one child sized
the active container's decorations as if there was only one titlebar.
Commit a25645a introduced the local variable 'net_height' but
incorrectly calculated it for stacking containers. Fixes #8686.
2025-05-19 12:29:09 +02:00
odyxz
810142dcc4 raise scratchpad container 2025-05-18 23:52:08 +02:00
alex-huff
a4072486de transaction: ensure border scene is enabled for floating containers
When a container that was previously an inactive child of a tabbed or
stacking layout becomes floating it's border scene-tree remains
disabled. This results in only the titlebar being rendered for the
container. This commit ensures the border scene-tree is enabled when
arranging floating containers.
Fixes #8721
2025-05-18 17:00:39 +02:00
Bill Li
652019d6da input/text_input: chase wlroots update
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5032

Fix #8718
2025-05-15 16:31:34 +02:00
GreyXor
3fbff5b4bb build: bump wlroots version 2025-05-15 11:53:32 +02:00
alex-huff
8d3a52aa30 move: fix broken titlebar when moving child to new workspace
Before this commit, when moving a non-leaf child of a tabbed or stacking
container to a new workspace, the child would be detached from the
parent container and the grandchildren would be sent to the new
workspace but the child itself wouldn't be destroyed causing the
titlebar to still be rendered as part of the parent container.
Fixes #8648.
2025-05-08 19:20:35 +02:00
Furkan Sahin
6021f4d83f input/seatop_down: Update decorations for touchscreen inputs
fixes #8675
2025-05-06 11:22:41 +02:00
alex-huff
4ab411cab0 transaction: Ensure all tabs are visible in tabbed mode
Before this commit when a child of a tabbed or stacking container was
taken out of fullscreen and a different sibling was focused in the same
transaction, the titlebar of the previously fullscreen container would
remain hidden. This commit makes sure that scene tree for decorations is
enabled for all containers within a tabbed or stacking container when it
is arranged.
2025-05-04 18:55:57 -04:00
Kenny Levinsen
f9945d81fb config/output: Fix missing output config supersedes
color_transform and allow_tearing was not handled by
supersede_output_config which could lead to configuration being
incorrectly applied.
2025-05-01 13:08:36 +02:00
Kenny Levinsen
8ac1f72c9e config/output: Use INT_MAX as x/y unset value
We oftne use -1 to indicate unset values. In case of output (x, y), we
would consider the fields set if they are not both -1. This means that
(0, -1) and (-1, 0) are valid coordinates, but (-1, -1) is not.

We support negative output positioning, so we cannot use -1 to mean
unset. Zero is also not an option as that would disallow reverting a set
position back to (0, 0).

INT_MAX is an unreasonable output position, so use it to indicate unset
values, and only use the value when both are set.
2025-05-01 00:00:50 +02:00
Pavel 'LEdoian' Turinsky
6cac61b6b9 Fix includes with relative paths
The function `load_include_configs` already changes the directory to the
one containing the parent config. Therefore, `load_include_config`
trying to assemble the "full" path leads to repetition of path segments,
making the `realpath` call fail with ENOENT.

Just calling `realpath` on the path itself from the directory with the
parent configuration is sufficient, so there is no point in passing
`parent_dir` to `load_include_config`.
2025-04-28 23:34:23 +02:00
Simon Ser
6894b498a8 build: bump version to 1.11-rc2 2025-04-27 22:52:48 +02:00
Furkan Sahin
5b8874e3f4 sway/commands: Handle incorrect resize unit
problem: an invalid usage of the command resize set will cause sway to crash because it doesn't check for an invalid height.
solution: validate height along with width.
2025-04-27 22:04:25 +02:00
Simon Ser
38a42f97d4 Replace signal() with sigaction()
The man page for signal(3) reads:

> new applications should use sigaction() rather than signal()
2025-04-27 18:42:12 +02:00
Simon Ser
0e19d85d37 Use pthread_atfork() to restore signals and NOFILE limit
This ensures these functions are always called (even when a library
such as wlroots or libc perform the fork) and removes the need to
manually call them.
2025-04-21 15:17:36 +02:00
Simon Ser
86ff19fade build: bump version to 1.11-rc1 2025-04-20 13:31:10 +02:00
Simon Ser
1d4632f97f Drop wl_drm again
In [1] we re-introduced a debug flag to enable wl_drm. Time has
passed and Xwayland + VA-API + amdvlk now all support
linux-dmabuf-v1.

[1]: https://github.com/swaywm/sway/pull/7916
2025-04-20 13:28:36 +02:00
Simon Ser
0153bc92ab server: move sway_terminate() definition to header 2025-04-17 23:31:55 +02:00
Simon Ser
d3e1c13e1f swaymsg, swaynag: drop sway_terminate() definitions
These are unused.
2025-04-17 23:31:55 +02:00
llyyr
8a8c78deac layer_shell: destroy layer_surface on assigned output destruction
According to the spec, the closed event should be sent when the surface
is no longer shown, because the output may have been destroyed or the
user may have asked for it to be removed. In such cases, the clients
should destroy the resource.

This fixes mako not being able to show notifications if the assigned
output was destroyed while a notificataion was still visible

Fixes: 188811f808 ("scene_graph: Port layer_shell")
2025-04-17 20:50:43 +02:00
Filip Vujičić
7733bf9963 Remove duplicate arrange_container 2025-04-17 19:05:36 +02:00
Simon Ser
3f0b3f8f9b Fix crash on shutdown when Xwayland is disabled 2025-04-14 10:21:18 +02:00
Loukas Agorgianitis
4943534929 server: fix shutdown crash when running on x11 backend
Signed-off-by: Loukas Agorgianitis <loukas@agorgianitis.com>
2025-04-14 09:30:49 +02:00
Ferdinand Bachmann
240a69ad63 server: recreate renderer in idle callback to avoid UAF
Destroying the wlr_renderer in a callback to its own renderer_lost event
is unsafe due to wl_signal_emit*() still accessing it after it was
destroyed.

Delegate recreation of renderer to an idle callback and ensure that only
one such idle callback is scheduled at a time by storing the returned
event source.
2025-04-13 23:40:56 +02:00
Ferdinand Bachmann
ab2e1f5817 tree/container: remove event listeners on destroy
Change begin_destroy to remove event listeners before the final destroy,
since otherwise event listeners would be removed twice, which crashes.

This fixes a crash in wlroots listener checks. See #8509.
2025-04-13 23:40:56 +02:00
Ferdinand Bachmann
53126cdceb input/text_input: remove event listeners on destroy
sway_input_method_relay can be destroyed from two sources, either the
seat is destroyed or the manager protocol objects are destroyed due
compositor exit.

This fixes a crash in wlroots listener checks. See #8509.
2025-04-13 23:40:56 +02:00
Ferdinand Bachmann
92c82e6952 desktop/idle_inhibit: remove event listeners on destroy
This fixes a crash in wlroots listener checks. See #8509.
2025-04-13 23:40:56 +02:00
Ferdinand Bachmann
e51ecf71aa input/input-manager: remove event listeners on fini
This fixes a crash in wlroots listener checks. See #8509.
2025-04-13 23:40:56 +02:00
Ferdinand Bachmann
0a9b0b83eb server: remove event listeners on fini
This fixes a crash in wlroots listener checks. See #8509.
2025-04-13 23:40:56 +02:00
Kenny Levinsen
583862e6d1 idle_inhibit: Check if layer surface output is enabled
While we we cannot easily check for true visibility of layer surfaces as
easily as for views, we can check at least check that the output
associated with the surface is enabled.
2025-04-13 16:24:02 +02:00
Kenny Levinsen
cc482228a4 idle_inhibit: Assume view is invisible by default
We have historically considered surfaces without a view visible. This
made sense in case of layer surfaces which do not have a view, but it
also allows unmapped surfaces to act as global inhibitors irrespective
of the current view state, which is not the intention fo the protocol.

As we now explicitly handle layer surfaces, assume that views are only
visible if they can be found and their visibility checked.
2025-04-13 16:24:02 +02:00
Kenny Levinsen
541183b322 idle_inhibit: Explicitly handle layer surfaces
Layer surfaces do not have a view, and while they can be occluded they
are always visible on their associated output - assuming it is enabled.
2025-04-13 16:24:02 +02:00
Kenny Levinsen
5e6a6ea340 idle_inhibit: Ignore inhibitors when locked
When a session is locked, no views are visible and there is no way to
interact with the user session. This means that all inhibitors based on
visibility - with the exception being inhibitors on the session lock
surfaces themselves - become inert, allowing the session to go idle.

The only inhibitor type on normal views that one could argue should
remain active is INHIBIT_IDLE_OPEN, but for now we disable all view
inhibitors regardless of type.
2025-04-13 16:24:02 +02:00
Daniel De Graaf
8f089f0229 Use wl_event_loop_add_signal for exit signals
This avoids calling non-async-signal-safe functions from within a signal
handler.
2025-04-12 23:10:39 +02:00
Furkan Sahin
cb246cb9c2 ipc: standardize pretty print with raw print
`swaymsg -t get_inputs --raw` calls it a pointer but `--pretty` calls it
a Mouse. Previous commit 6737b90cb that set this to pointer probably
forgo to update the pretty one.

closes #8584
2025-04-09 01:10:03 +02:00
Claudia
a25645a5a6 Fix tabbed/stacking container height regression
Commit c2d6aff added a bounds check on `height - title_bar_height`,
repurposing the local variable `height` in an attempt to DRY out the
expression.

However, because re-assignment occurs inside the loop body, its result
would leak across loop iterations, compounding its effect and leading
to the artifact reported in issue #8625, where each child except the
first in a tabbed container would acquire a visible waterline.

Introduce a second variable and reset it in each loop iteration to get
rid of the waterline.

Fixes #8625.
2025-03-27 08:09:53 +01:00
Dennis Baurichter
ab455bbada man: clarify criteria (incl. PCRE2 usage)
Replace the XWayland-only class attribute in the examples:
- The first example given should work for Wayland-native windows.
- The example 'Kill all windows with the title "Emacs"' should use
  title, not class. Also, it's a substring (regex) match.

There are many different implementations of regular expressions with
incompatible syntax. For example, GNU grep alone provides three
different ones. Clarify the use of PCRE2 by sway criteria.
2025-03-23 15:03:24 +01:00
Kenny Levinsen
c2d6aff64c Avoid crashing on too many containers
If far too many containers are created, they can become so small that
their size calculations come out negative, leading to crashes on
asserts.

Instead, set a lower bound for sizes and disable the container entirely
if it goes below it, giving whatever space it used to the last
container.

The splits are not recalculated, so currently the effect is that if all
containers have the same width fraction, they keep getting narrower
until at some point they all round to zero and the last container will
be given all the available space.

A better behavior would have been if the additional container did not
contribute to size and fraction calculations at all, but it's an extreme
edge-case, anything is better than crashing, and this is easier to
implement.
2025-03-21 21:08:04 -04:00
Paul Riou
4b185a0fe0 stringop: fix has_prefix() arg order in config parsing
has_prefix() expects the prefix to be the 2nd argument, not the first.

The config parsing was broken when using `--input-device=`.

Introduced by: 0c60d1581f "Use has_prefix()
instead of strncmp() throughout"
2025-03-20 21:31:32 +01:00
ShootingStarDragons
d148560f50 text_input: Fix ime panic in ext-session-lock
in the origin text_input.c, we only check the sway_view and layershell,
but now we have the third shell named sessionlock, so we need to modify
both text_input.c and view.c to handle the new type of shell
2025-03-20 15:55:21 +01:00
Kenny Levinsen
30434b2beb desktop/output: Skip repaint if wlr_output is disabled
When the repaint timer fires, we check if the sway_output is disabled,
and if so, skip the output commit after having reset frame_pending.

The sway_output enable flag is only updated if the output is disabled
and removed from the layout, not if the power is disabled for e.g. idle.
This can lead to situations where a commit is attempted on a disabled
output, which will lead to an attempted and failed primary swapchain
allocation.

Use the wlr_output.enabled state to check if the output is active.
2025-03-20 12:40:27 +01:00
Piotr Piwoński
3a49409dae sway/commands: Return error if container is not in scratchpad 2025-03-18 22:28:05 +01:00
melvinm1
2f5b3c0999 Fix output repositioning in global fullscreen
Call wlr_scene_output_set_position when in global fullscreen to
correctly set output positions when repositioning outputs (using
swaymsg output or similar).
2025-03-16 17:48:30 +01:00
Kenny Levinsen
61cc08cf3c config/output: Reset everything before swaybg exec
swaybar and the exec command reset signal masks, signal handlers and
NOFILE limit before exec, but swaybg was missing all that.

Reset it for swaybg as well.
2025-03-11 09:15:05 +01:00
Kenny Levinsen
8238e5242b Use SIG_IGN for SIGCHLD instead of our own handler
The behavior of handlers registered with signal(3p) is not well-defined
for signals delivered more than once, as laid out in the man page.

We should replace our use of signal with sigaction, but for SIGCHLD
specifically we can also just skip the signals altogether by setting the
handler to SIG_IGN which causes child reaping to not be required.

Fixes: https://github.com/swaywm/sway/pull/8567
2025-03-11 09:15:05 +01:00
llyyr
5d7b9a8320 sway/server: create ext-data-control manager 2025-03-09 10:46:26 +01:00
nilninull
9dcccf784b Add the DesktopNames key to the sway.desktop session file
According to
https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html,
to set the value of XDG_CURRENT_DESKTOP, a DesktopNames key is
required in the session file.  And the value of XDG_CURRENT_DESKTOP is
used to run xdg-desktop-portal*.  If this value is not set,
xdg-desktop-portal-wlr will not run at login.
2025-03-08 12:56:03 +01:00
Chris Perl
048e304b8a Remove constraint that con->view != NULL to use __focused__ criteria
To use something like:

  [con_id=__focused__] mark --add --toggle foo

The container must currently have a view. However, it is possible to
focus parent containers that do not have a view. For example, via:

  focus parent

Since containers without views can be the focused (meaning the container
is marked "focused": true in the output of: swaymsg -t get_tree), it
seems reasonable that a view is not required to target a container via
__focused__.
2025-03-07 17:53:40 +01:00
Kenny Levinsen
e3d9cc2aa5 Rework fork/exec strategy
cmd_exec_process is used whenever sway is meant to execute a child
process on behalf of the user, and had a lot of complexity.

In order to avoid having to wait on the user's process, a double-fork
was used, which in turn required us to wait on the outer process. In
order to track the child PID for launcher purposes, a pipe was used to
transmit the PID back to sway.

This resulted in sway blocking for 5-6 ms per exec on my system, which
is quite significant. The error handling was also quite lacking - the
read loop did not handle errors at all for example.

Instead, teach sway to handle SIGCHLD and do away with the double-fork.
This in turn allows us to get rid of the pipe as we can record the
child's PID directly. This reduces the time we block to just 1.5 ms on
my system. We'd be able to get down to just 150 µs if we could use
posix_spawn(3), but posix_spawn(3) cannot reset NOFILE. clone(2) or
vfork(2) would be alternatives, but that presents portability issues.

This change is replicated for swaybar, swaybg and swaynag handling,
which had similar albeit less complicated implementations.
2025-03-06 11:46:59 +01:00
Kenny Levinsen
962e1e70a6 sway_text_node: Remove use of source box
The source box is always set to the full buffer dimensions, making it
ineffective. Remove it.
2025-02-25 09:48:40 -05:00
Kenny Levinsen
8a60f30423 sway_text_node: Apply max_width when rendering
max_width was applied to the source box, but not to the cairo surface.
The cairo surface would therefore take on arbitrarily large dimensions
according to the required dimensions to fit the text input, which if
large enough would cause failures during output rendering and leave a
black hole in the titlebar.
2025-02-25 09:48:40 -05:00
Alexander Orzechowski
7fab75a7a6 commands/opacity: Call output_configure_scene on updated container
Calling container_update() wasn't enough: If there is no visible window
decorations (title bar, borders) container_update would basically no-op
and the scene wouldn't repaint with the update alpha. By also calling
output_configure_scene() we force a call to
wlr_scene_buffer_set_opacity() thus ensuring we update the scene.

Closes: #8580
2025-02-25 11:11:22 +01:00
Alexander Orzechowski
0da0d37f3d output: Allow configuring scene without an output 2025-02-25 11:11:22 +01:00
Alexander Orzechowski
38005bd854 output: Expose output_configure_scene to header 2025-02-25 11:11:22 +01:00
Mark Stosberg
10e50e6bf9 docs: use "window" instead of "view" throughout.
"view" is an internal term, while the commonly understood
user-facing term is "window"

Ref: #7323
2025-02-17 00:13:15 +01:00
Ferdinand Bachmann
c1031d8465 sway/ipc-json: add ext-foreign-toplevel-handle identifier to get_tree ipc output
Fixes #8291
2025-02-16 19:18:29 +01:00
Furkan Sahin
4852087e61 output/background: fix config ignoring fallback color
currently, the output background command handler prematurely
returns with an error if the background file cannot be accessed.
It should only error if user did not provide fallback color.

closes #8556

Changes

- Introduce variables to avoid uneccessary writing on output members
- Log a debug message when fallback is being used over inaccessible
   file
- Always parse the background color and swaynag warn if it is incorrect

- when updating output member variables, free previous values
- add cleanup label and goto it if `strdup` fails
- Move output->member initializations to before parsing fallback, Also
free and init output->background as well
2025-02-09 14:29:44 +01:00
Dan Baterisna
851b8c6fb6 man: Document bar mode toggle command
Functionality for switching swaybar's current mode between
hidden and docked currently exists, but is absent from the relevant
manpage.
2025-02-06 18:02:35 +01:00
Attila Fidan
d093c2e358 input/cursor: remove tool_proximity listener in destroy 2025-01-27 00:42:37 -05:00
Bill Li
3ff60987f3 Drop wlr_matrix.h include from sway/desktop/output.c
wlr_matrix is now private API.

Fixes #8549
2025-01-26 18:36:07 -05:00
Simon Ser
8acb0482da Add ext-image-copy-capture-v1 and ext-image-capture-source-v1
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4545
2025-01-21 20:26:19 +03:00
llyyr
30c858423d config/output: don't leak background_fallback 2025-01-16 16:03:36 +01:00
Jacob McNamee
0b08dce08c swaymsg: pretty-print sandbox properties 2025-01-13 08:54:23 +01:00
Jacob McNamee
f177d05441 tree/container: support sandbox properties in title format 2025-01-13 08:54:23 +01:00
Puck Meerburg
3ab1f0ca3d criteria: add sandbox properties 2025-01-13 08:54:23 +01:00
Puck Meerburg
60f06fc4f1 ipc-json: add sandbox properties to view JSON 2025-01-13 08:54:23 +01:00
Jacob McNamee
cff16d32f9 tree/view: add getters for sandbox properties 2025-01-13 08:54:23 +01:00
Jim
e3f0ba4cd9 Increase max default buffer size to 1 MiB
Increasing the max default buffer size prevents clients from crashing
when they need more than 4096 bytes. This can happen when the GUI thread
of the application is blocked, especially when moving your mouse over it
with high mouse sensitivity.
2025-01-12 22:38:04 +01:00
llyyr
3629a832e5 layer_shell: cleanup new_popup listener when destroying node 2025-01-11 10:32:08 -05:00
Simon Ser
a6c0441ee0 config/output: don't hardcode DMA-BUF in search_render_format()
We could be running with a backend which doesn't support DMA-BUFs,
e.g. inside a parent Wayland compositor without GPU acceleration.
2025-01-08 11:57:45 +01:00
mtvare6
c7c0a5a1b3 config/output: skip format checks if all are supported
Fixes #8496
2025-01-08 08:25:39 +01:00
Simon Ser
a1838c5522 Fix has_prefix() comparisons with 0
has_prefix() returns a bool, unlike strncmp() which returns an int.

Fixes: 0c60d1581f ("Use has_prefix() instead of strncmp() throughout")
Closes: https://github.com/swaywm/sway/issues/8527
2025-01-07 18:56:02 +01:00
Simon Ser
0c60d1581f Use has_prefix() instead of strncmp() throughout
This is safer than hardcoded string lengths.
2025-01-07 16:35:31 +01:00
Simon Ser
c55dff95bc stringop: move over has_prefix() 2025-01-07 16:35:31 +01:00
Hong Xu
801bc76ce3 Explain that the title bar always shows 2024-12-21 11:37:50 +01:00
Alexander Orzechowski
f293418d9d swaybar: Handle opaque region properly
The background color can be set individually for the different
elements of the bar. If any of the backgrounds have transparency, we have
to bail out from advertising an opaque surface.
2024-12-08 18:28:25 +01:00
Baltazár Radics
4eb86fce07 input/libinput: fix parsing input drag_lock command
Regression introduced by by b160fac9f7a
2024-12-08 16:15:48 +01:00
György Kurucz
1d783794b5 input/libinput: fix builtin device detection logic
Fixes: #8468
2024-11-23 11:17:17 +01:00
Violet Purcell
4faf0f9098 tree/container: remove output_{enter,leave} listeners in destroy
0d6cc471e9
added an assert that all signals are clear when destroying a
wlr_scene_buffer, which is currently triggering due to sway not removing
the output_enter and output_leave listeners on the container before
calling wlr_scene_node_destroy on output_handler. Remove the listeners
before wlr_scene_node_destroy is called.
2024-11-23 13:10:06 +03:00
Simon Ser
bbadf9b8b1 Add support for LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY
Use it as the default, as recommended by the libinput release
notes:
https://lists.freedesktop.org/archives/wayland-devel/2024-November/043860.html
2024-11-23 13:06:49 +03:00
Simon Ser
e2409aa496 ipc-json: handle LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY
New entry introduced in libinput 1.27.0.
2024-11-23 13:06:49 +03:00
Kenny Levinsen
5312376077 desktop/output: Clear repaint timer earlier in destroy
The teardown of a sway_output is split in two: begin_destroy and
output_destroy. The former clears some state such as NULL'ing the
reference to wlr_output, while the latter frees the struct and its
remaining resources.

If an output is destroyed while a repaint timer is pending, future frame
callbacks will no longer occur as the listener is torn down in
begin_destroy, but the repaint timer is not torn down and may still
fire until output_destroy is hit. As begin_destroy cleared the reference
to wlr_output, this leads to a NULL-pointer dereference.

Tear down the repaint timer in begin_destroy as there is no need for it.

Fixes: fdc4318ac6 ("desktop/output: Clear frame_pending even output is disabled")
2024-11-17 16:03:35 -05:00
mtvare6
fec3da7d58 commands/include: handle many files in single line
i3 supports including multiple files in a single line, whereas sway
limits to single file per line.
2024-11-17 19:18:51 +01:00
Kenny Levinsen
a2c73c9b8b ipc-server: Force modeset if needed after executing commands
IPC clients generally expect executed commands to have taken effect when
the command completes, while delayed modeset means that it can take
several milliseconds more before e.g. an output is enabled.

However, modesetting on every output command in the IPC call could on
systems with already slow modesetting behavior lead to an unresponsive
system for a not insignificant period of time.

To strike a balance, force modeset once all the commands of this IPC
call have executed if a modeset is pending.
2024-11-17 19:11:58 +01:00
Kenny Levinsen
6111297d91 config: Force modeset before running deferred configs
Some commands require outputs to be enabled. These commands are deferred
to allow outputs to be discovered, but the delayed modeset might only
run some time later.

Force a modeset to occur before running deferred commands.

Fixes: https://github.com/swaywm/sway/issues/8433
2024-11-17 19:11:58 +01:00
Solt Budavári
96db66abf0
Fix orthographic mistakes in Hungarian README
Fix a few mistakes so the text conforms to
Hungarian orthography. The following rules were
applied (the whole linked page is in Hungarian):

- <https://www.helyesiras.mta.hu/helyesiras/default/akh12#110>
- <https://www.helyesiras.mta.hu/helyesiras/default/akh12#112>
- <https://www.helyesiras.mta.hu/helyesiras/default/akh12#113>
- <https://www.helyesiras.mta.hu/helyesiras/default/akh12#215>
- <https://www.helyesiras.mta.hu/helyesiras/default/akh12#244>
2024-11-16 14:47:50 +01:00
Kenny Levinsen
fdc4318ac6 desktop/output: Clear frame_pending even output is disabled
frame_pending should always be cleared once the repaint callback is
fired to ensure that future frame scheduling is not accidentally held
back.
2024-11-11 14:36:33 +01:00
Kenny Levinsen
463c4c9369 desktop/output: Clean up output state if build_state fails
wlr_scene_output_build_state can fail for various reasons. Ensure that
the pending output state is cleaned up in that case.
2024-11-11 14:36:33 +01:00
Joan Bruguera Micó
f23d100747 swaybar: Emit property changes for SNI watcher
Emit property change signals for the IsStatusNotifierHostRegistered and
RegisteredStatusNotifierItems properties in StatusNotifierWatcher,
so code relying on the PropertiesChanged signal, instead of signals
such as StatusNotifierHostRegistered, can work properly.

A library that is affected by this is the libappindicator-gtk3* library
and it can cause tray icons to be missing after starting swaybar due to
a race condition, as follows:
* An application using libappindicator-gtk3 starts, e.g. nm-applet.
* Some time later, swaybar starts.
* swaybar creates the StatusNotifierWatcher.
* libappindicator-gtk3 observes the new watcher, but it sees that
  IsStatusNotifierHostRegistered=false, so it falls back to the
  Freedesktop System tray protocol.
* swaybar creates the StatusNotifierHost.
  At this point, libappindicator-gtk3 should "un-fallback" back to SNI.
  However, since swaybar does not emit the PropertiesChange signal on
  IsStatusNotifierHostRegistered, libappindicator-gtk3 doesn't get
  notified, and stays in fallback state forever.
* As a result, nm-applet will not show in the swaybar tray.

This race can be made reliable by inserting a 1-second long sleep here:
03483ff370/swaybar/tray/tray.c (L57)

(*) Note that the libappindicator-gtk3 library has been mostly replaced
    by libayatana-appindicator, which is not affected by this.
    The affected version is still used by Arch Linux, source code at:
    https://bazaar.launchpad.net/~indicator-applet-developers/libappindicator/trunk/files/298
2024-11-10 20:42:02 +01:00
Manuel Stoeckl
03483ff370 swaynag: fix null dereference on scale change
If cursor-shape-v1 is available, the old wl_cursor_theme path should
not be used.
2024-11-09 02:33:48 +01:00
mtvare6
62fd8c4d01 desktop/transaction: clamp vertical border length to 0
Fixes #8120
2024-11-07 22:41:14 -05:00
Kenny Levinsen
78fa4e9856 config/output: Update output position in two passes
The modeset logic iterates over all outputs at the end, sets their new
position in the layout and takes a copy of its geometry that is later
referenced by layout and scene management code.

If one output is auto configured, then a later output that is manually
configured can lead to the first output being moved without the stored
geometry being updated.

Split this into two passes: The first pass finalizes the output config
and makes updates to the layout, while the second pass updates the copy
of the geometry and arranges things as a result of it.
2024-11-06 01:28:55 +01:00
Alexander Orzechowski
4cfcb3643b container: Properly constrain title bar padding
Important for centered titles
2024-11-04 19:02:16 +01:00
Simon Ser
d417a8fcd0 release.sh: read meson-rewrite output from stdout
Since version 1.6, Meson now uses stdout:
3f4957c713
2024-10-31 10:31:38 +01:00
Kenny Levinsen
f38719f575 desktop/output: Add missing output config allocation checks 2024-10-30 19:56:07 -04:00
Kenny Levinsen
1e53007bc3 desktop/output: Store output config on request_state
An output backend might request any change to an output state at any
time, although currently only this is currently only used for changing
window size on the wayland and x11 backend.

Applying the configuration directly means that the current output state
becomes inconsistent with the configured state, which can cause the new
state to be reverted later if apply_stored_output_configs is called.

Before 4f9ce4675c. the output geometry would be updated by
arrange_outputs, but this is only done by the modeset logic now,
resulting in the stored geometry never being updated on wayland backend
window resize. This was not discovered as the stored geometry is not
used particularly often.

Solve both by storing a new output configuration and relying on the
modeset logic to apply a new state.

Fixes: 4f9ce4675c ("tree/arrange: Remove redundant output geometry update")
2024-10-30 19:56:07 -04:00
AsciiWolf
e7c972b04a Remove language bars from remaining non-English README files 2024-10-28 14:06:01 +01:00
llyyr
839434abc0 sway/server: bind to presentation-time-v2
Depends on: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4858
2024-10-27 19:20:20 -04:00
Kirill Primak
015e357fce desktop/output: chase wlroots private fields update
This will be replaced with a proper solution later.
2024-10-25 17:42:35 +02:00
Kenny Levinsen
a63027245a config/output: Remove remaining logs from queue_output_config
The job of queue_output_config is now just to fill out a
wlr_output_state according to the output configuration, but it still has
a lot of logging from before we had wlr_output_state or the new modeset
logic, when queue_output_state instead touched the implicit pending
state of wlr_output.

Whatever debug logs it had would already be covered by the output state
debug logs or the command debug logs, so let's just remove it.
2024-10-20 12:22:12 +02:00
Kenny Levinsen
17ecb9eb1d config/output: Remove initial values in find_output_config
Starting by setting some special initial output config values settings
was something sway used to do when the config was initially being
processed. This was later changed to always happen, as there shouldn't
be differences in how output config is calculated during config load and
after.

Most of these values are redundant, as they are either the zero value or
a value that would be selected if the unset (-1) value was found.

For output transforms, the automatic panel orientation code would only
trigger if the final output config has an unset transform, which the
initial values set in find_output_config made impossible.

Remove these initial values and instead use a fresh output config as is.
2024-10-20 12:22:12 +02:00
Kenny Levinsen
af0d4a048a config/output: Always set all output fields on finalize 2024-10-20 12:22:12 +02:00
Kenny Levinsen
7e0c0dda42 config/output: Always set output states from config
queue_output_config had some remaining logic that would avoid setting
output states if they already appeared to be in effect. That is not what
most of the states did nor what is currently expected, so clean that up.
2024-10-20 12:22:12 +02:00
Kenny Levinsen
7d93652105 config/output: Improve modeset state logging
Include scale and subpixel in the output state log, and log the output
state on first commit attempt instead of just during fallback search.
2024-10-20 12:22:12 +02:00
Simon Ser
35d8adefc4 input/seatop_default: refactor move/resize button logic
Make it so config->floating_mod_inverse only applies when pressing
mod, not when clicking on titlebars.

Centralize logic into shared variables.
2024-10-20 00:26:09 -04:00
Alexander Orzechowski
8363699f14 layer_shell: Restore sway 1.9 ordering 2024-10-18 14:10:28 +02:00
Alexander Orzechowski
ce6b2db0f2 layer_shell: Arrange exclusive zone clients first
This makes layer_shell more stable against the order of clients.
2024-10-18 14:10:28 +02:00
Jan Palus
db76fefd0c trigger container update after disabling urgent in timer
switching workspace directly to urgent window creates timer which delays
reset of urgent state so user is able to notice it. make sure state
change is reflected visually as well (border change) by triggering
container update

Fixes: #8377
2024-10-16 13:57:32 -04:00
Simon Ser
dd063a0ef7 input/keyboard: add support for pointer keys
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4775
2024-10-14 21:27:07 +02:00
Simon Ser
17e2e52c6d server: check backend support for timelines
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4848
2024-10-11 13:26:54 -04:00
Furkan Sahin
7f1cd0b73b
input/mouse: bugfix button2 being interpreted as trying to move the container
Man sway(5) specifies that when tiling_drag is enable, the floating_mod
can be used to drag tiling, as well as floating containers. However the
current code indiscriminately assumes any button press to be intended
for moving the container, consequently causing an unintended call to
`seatop_move_tilting:handle_button` rather than
`seatop_default:handle_button` to pass
`state=WL_POINTER_BUTTON_STATE_RELEASED` to `get_active_mouse_binding`

My idea was to make 'Handle moving a tiling container' follow the same
path as 'Handle moving a floating container' because the initial call to
handle moving a floating correctly exits that branch and ends up passing
the RELEASED state to `get_active_mouse_binding`.

Fixes #8334
2024-10-08 18:09:57 +02:00
ShootingStarDragons
f855b0898b fix: sway crashes if switch to another workspace with surface when IME popup is shown
in pr https://github.com/swaywm/sway/pull/8196, when im_popup_surface is unmapped, author set the popup->relative to NULL, butt popup is still in popup groups, where assert the relative is not NULL, this cause the panic

Take the suggestion of Nefsen402, remove the line where set relative to
NULL, and add NULL check in scene_descriptor_destory
2024-10-07 23:07:25 -04:00
Kenny Levinsen
c90cb37b2a Re-init renderer for all outputs on lost context
sway_root.outputs only include enabled outputs. We also need to re-init
the renderer for any disabled outputs, so use sway_root.all_outputs
instead.

Resolves the following heap-use-after-free accessing the render formats
when a disabled output is modeset after a GPU reset has occurred.
2024-10-02 21:09:55 -04:00
Alexander Orzechowski
9a9be01ad4 Fix alpha-modifier-v1 2024-09-29 23:01:14 +02:00
Simon Ser
a2757e5f16 release: push tags before creating GitHub release
Otherwise the GitHub release isn't attached to the Git tag.
2024-09-29 17:44:47 +02:00
Simon Ser
a0b3606f17 Add support for alpha-modifier-v1 2024-09-29 17:19:22 +02:00
Furkan Sahin
00e9a94152 swaybar: Fix 100% cpu usage if dbus dies.
Currently, swaybar does not gracefully die if it detects
that the dbus connection was lost. Although it's not recommended
to restart dbus without restarting the compositor, it can very
easily happen. In the case it does, compositor's tray should
not consume 100% cpu until it has to be force killed.

apply suggestions

just setting the bar to not running will call teardown and unref the
dbus.
2024-09-28 16:23:21 +02:00
Kenny Levinsen
63345977e2 desktop/output: Clear modeset timer on output manager apply
If a modeset timer exists at the time we apply an output manager config,
clear it to avoid a useless double commit.
2024-09-21 17:50:24 -04:00
Kenny Levinsen
cdff4f7c74 config: Batch input/output configuration on load
We batch modesets and input configuration performed during config reload
but commit for every command during the intial config load. There is no
need to perform commits during the initial config load as outputs have
not yet been created, but swaybg spawn should still be batched.

At the same time, replace direct calls to apply output configuration
with request_modeset to properly handle the modeset timer.
2024-09-21 17:50:24 -04:00
Kenny Levinsen
b73f54a966 desktop/output: Expose request_modeset
We remove the struct sway_server argument for consistency with the rest
of our internal APIs which rely on the global server instance.
2024-09-21 17:50:24 -04:00
Olivia Taliesin
b6da218974 Removed destination-is-ancestor check from container_move_to_container to match i3 behaviour 2024-09-21 17:46:20 -04:00
Kenny Levinsen
861dde100a commands/gaps: Check config->reading instead
Checking if the config is not active or is reloading is just a
convoluted way of checking if the config is being read.
2024-09-21 16:16:19 +02:00
Alexander Orzechowski
e9dd218231 text_input: Inline input_popup_update into input_popup_set_focus
This seems to be the intention of input_popup_update in the first place:
handle the scenario where the focus moves.
2024-09-20 19:40:18 +02:00
Alexander Orzechowski
74e507962e text_input: Properly handle map/unmap events
The last implementation would ignore these and get it could get into
a bad state where it would start crashing sway.
2024-09-20 19:40:18 +02:00
Alexander Orzechowski
023f6b0a50 transaction: Allow no popup descriptor in popup list
Input method popups in the future will destroy the scene descriptor when
it isn't mapped and therefore shouldn't be tampered with here.
2024-09-20 19:40:18 +02:00
Alexander Orzechowski
1537c9dae5 text_input: Move popup placement to own function 2024-09-20 19:40:18 +02:00
Alexander Orzechowski
48069097ea text_input: Check for allocation failure 2024-09-20 19:40:18 +02:00
Scott Dubinsky
266cd4515a Remove unguarded double include 2024-09-20 17:18:26 +02:00
Emil Engberg
e940acd374 Add toggle for output adaptive_sync 2024-09-20 15:38:27 +02:00
Kenny Levinsen
9765c29be1 config/output: Stringify render format when logging it 2024-09-20 14:08:04 +02:00
Kenny Levinsen
034d02f8a5 config/output: Add support for 6-bit render fmt
GUD devices uses RGB565 by default for performance reasons. Allow
specifying render_bit_depth 6 to pick this format. The definition works
out if you consider the maximum number of bits per channel instead of
the average.
2024-09-20 14:08:04 +02:00
Kenny Levinsen
785a459a55 ext-session-lock: Do not use commit listener to arrange
Arranging lock surfaces rely on the sway_output width and height being
updated, but these are only updated after the commit has been completed
and all commit listeners have executed. This means that the lock
surfaces will not be appropriately scaled to match a change in output
dimensions, and may reveal what is under the lock background.

Replace the implicit arrange through the output commit listener with an
explicit arrange after the output configuration is finalized.

This might have regressed by other transition away from output commit
listeners for other arrange tasks, but even then it would have
erroneously relied on signalling order.
2024-09-20 00:26:36 -04:00
Steffen Dirkwinkel
f957c7e658 config/output: support DRM_FORMAT_ARGB8888
Some display output hardware [1] doesn't support any of the current
formats, but works with ARGB8888. Fall back to it if available.

[1] 196145c606/drivers/gpu/drm/xlnx/zynqmp_disp.c (L313)

Signed-off-by: Steffen Dirkwinkel <s.dirkwinkel@beckhoff.com>
2024-09-13 13:09:48 +02:00
Kenny Levinsen
d7a76d381b config/output: Rename to apply_stored_output_configs 2024-09-10 14:13:36 -04:00
Kenny Levinsen
29b3f00e6f config/output: Accept a list of output_configs to use
Instead of using a single finalized output config per output, accept a
regular list of output configs like the one ultimately stored for
configuration purposes. This allows the output management code to test
an augmented configuration while still using the same output config
logic, without having to mutate the stored configuration.

This in turn allows us to make a few APIs private. A bug note about an
existing issue with derade to off is added as well.
2024-09-10 14:13:36 -04:00
Kenny Levinsen
0496477f92 config/output: Always start with default in find_output_config
We always need to start out with the default configuration, regardless
of whether the config is reloading or not to ensure that config
decisions are stable given a specific configuration.
2024-09-10 14:13:36 -04:00
Kenny Levinsen
a0c0349934 config/output: Support multiple matches in find_output_config
Simplify find_output_config and inline the search through the output
configs instead of using list_seq_find with a comparator function. The
new implementation will merge any amount of matched configs in order,
which will be relied upon in a future commit.
2024-09-10 14:13:36 -04:00
Adam Chovanec
fb5eadc363 readme: update Czech translation 2024-09-08 16:06:26 +02:00
llyyr
c5ba7f23a5 sway/input/keyboard: always set active keyboard if there is none
Previously, we incorrectly only set active keyboard for non-virtual
devices. 4c3c060211 incorrectly put
unrelated code in `sway_keyboard_set_layout`.

Fixes: 4c3c060211
2024-09-08 14:18:01 +02:00
Kenny Levinsen
f4a6b0395f tree/arrange; Skip arranging disabled outputs
Disabled outputs might not have a geometry to arrange for, so skip the
arrange to avoid messing up the workspace geometry.
2024-09-07 20:11:30 -04:00
Kenny Levinsen
14bff7b451 desktop/transaction: Deactivate workspace on inactive outputs
If the output is not active, it might not have a valid geometry to
arrange for. Outputs do not gain a geometry until modeset, so if an
output is connected with a configuration present to disable it, it will
not have a geometry. If the output has a past workspace restored, this
will be attemtped arranged to fit a 0x0 rectangle, which asserts when
trying to sort out borders.

Consider the workspace activated only if the output itself is active to
get the scene nodes disabled.
2024-09-07 20:11:30 -04:00
Kenny Levinsen
4f9ce4675c tree/arrange: Remove redundant output geometry update
This is handled by apply_output_configs.
2024-09-07 20:11:30 -04:00
Alexander Orzechowski
fc6b8d6af2 container: Skip % char if it doesn't match a view property
The else condition was missed here and we would never skip the % char
if it didn't end up matching with any property. Since we fail to skip
we would re-evaluate the % in an infinite loop never achieving any
forward-progress.

Fixes: https://github.com/swaywm/sway/issues/8333
2024-09-07 01:19:31 +02:00
Kenny Levinsen
4fe054c6db tree/output: Avoid duplicate input mapping configure 2024-09-05 18:19:16 -04:00
Kenny Levinsen
cfb292cca7 desktop/output: Avoid duplicate output manager update 2024-09-05 18:19:16 -04:00
Kenny Levinsen
af28ac04a4 (desktop|tree)/output: Do not use layout listener to arrange
Output layout changes originate from the centralized modeset
infrastructure and request_state which already takes care of arranging
and updating outputs as needed.
2024-09-04 13:49:35 -04:00
Kenny Levinsen
6045ad9a02 tree/output: Rely on modeset arranging root
output_enable/output_disable are only called from modeset, and from
output destroy which requests modeset. As such, they can rely on the
modeset handling arrange.
2024-09-04 13:49:35 -04:00
Kenny Levinsen
b83e5aaa54 desktop/output: Do not use commit listener to arrange
The reasoning for using a commit handler is to ensure that all paths for
output changes are correctly handled. With the centralized modeset
infrastructure in place, we can move the logic there. This allows us to
be smarter and avoid extraneous arranges, output manager updates and
transaction commits.

The side-effect is a minor duplication for the special-case
request_state, but the shared path will be relied upon further in future
commits to justify this duplication.
2024-09-04 13:49:35 -04:00
Norbert Bolanowski
be840f730e move title_format to container 2024-09-02 16:49:05 -04:00
Jon Wallace
980a4e0211 use subheadings instead 2024-08-28 10:59:56 +02:00
Jon Wallace
f2b2a81149 Use heading markdown to demarcate sections of commands
Its a little tought to notice that the COMMANDS section is actually 3 sections. Use markdown to make this easier to see for the user.
2024-08-28 10:59:56 +02:00
llyyr
77b9ddabe2 sway/tree/container: don't trunc coords in floating_fix_coordinates
This can cause issues such as the window not being shown at the exact
same coordinates when the old and new wlr_box aren't the same
dimensions and the container is being moved back-and-forth between them.

For example, in the case where a floating window gets moved
from one output to another but the outputs aren't the same resolution.
For e.g. have two displays that aren't the same resolution then:

1. Open a floating window and set it to pos 0,0 on output 2
2. Send it to scratchpad then `scratchpad show` on output 1
3. `scratchpad show` on output 2 again

Observe that the window isn't at 0,0 on output 2 anymore.
2024-08-22 23:43:22 +02:00
Anna (navi) Figueiredo Gomes
f00f964abf sway/commands/move.c: arrange new workspace
When moving a container to a new workspace, the workspace's dimension
are left unset. Usually this doesn't matter, but when moving a floating
container to a new workspace on a different output, this leads to the
position of the container being calculated with 0, so the container ends
up halfway offscreen on the leftmost topmost monitor.

Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
2024-08-22 23:41:33 +02:00
Alexander Orzechowski
7288f77bbe output: Chase wlroots!4803 2024-08-21 18:16:32 +03:00
Kenny Levinsen
f9c0f043e5 config/output: Skip search if config has a mode
When doing an output configuration search, the intent is to only look
for modes if the output's configuration does not contain a specific
mode. This was done by testing if config_has_auto_mode returned false.

config_has_auto_mode had its return values backwards, leading to other
modes being tested if the output configuration had specified modes or
modelines, leading to unwanted modes being selected.

Invert the function to config_has_manual_mode to give it a clearer name,
and fix the return values in the process.
2024-08-19 12:03:48 -04:00
Kenny Levinsen
ae7c1b139a config/output: Do not set adaptive_sync if not supported
After 4e38f93f36 ("config/output: Skip VRR tests when not supported"),
the configuration search no longer touches VRR state for outputs that
are known to not support it. This also means that it will not remove VRR
if already set, which could cause output configuration to fail.

Ensure that VRR state is never set for outputs that do not support it by
adding the same test for support to queue_output_config.

Fixes: 4e38f93f36 ("config/output: Skip VRR tests when not supported")
Fixes: https://github.com/swaywm/sway/issues/8296
2024-08-18 15:18:11 +02:00
Kirill Primak
c30c451907 xdg-shell: chase xdg_surface geometry updates 2024-08-14 15:04:00 -04:00
Alexander Orzechowski
c3279944fb output: Use wlr_scene_set_gamma_control_manager_v1 2024-08-14 20:45:04 +03:00
Alexander Orzechowski
5a3621460f output: Use wlr_scene_output_needs_frame 2024-08-14 20:45:04 +03:00
Felix Pehla
6576b99c24 commands/output/color_profile: allows use of relative path for ICC profile 2024-08-14 11:03:53 +02:00
Simon Ser
b44015578a Switch default config to wmenu-run
This removes the last dependency bit on dmenu. No need for
"swaymsg exec" anymore: wmenu-run handles the xdg-activation
shenanigans.
2024-08-11 19:47:39 +02:00
Simon Ser
9ba1beee58 Bind a few utilities to special keys in default config 2024-08-11 16:42:20 +02:00
JingMatrix
f344e9d5a5 Add null-safety check for virtual keyboard keymaps
Note that in the `sway_keyboard_configure` function of sway/input/keyboard.c,
we have skipped the `sway_keyboard_set_layout` function for virtual
keyboards, which then have null keymaps.
Hence, a null-safety check is needed at runtime.
2024-08-09 22:03:41 +02:00
Alexander Orzechowski
951a22c244 xwayland: Let scene restack 2024-08-07 23:58:13 +03:00
Kirill Primak
32e5e5232d tearing: fix UAF on destroy
Fixes: 9a1c411abd
2024-08-07 14:33:03 +02:00
Kirill Primak
3e956b9229 tearing: remove trailing whitespace 2024-08-07 14:33:03 +02:00
Simon Ser
05e895c463 Add support for linux-drm-syncobj-v1
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4262
2024-08-06 20:18:59 +02:00
Ricardo Steijn
9a1c411abd
Add support for tearing-control-v1
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3871

Adds option to allow tearing per output, as well as an option to force
enable or disable tearing for a specific application using a window
rule. Only works with fullscreen applications.
2024-08-05 02:13:49 +02:00
Alexander Orzechowski
b881c2e84c transaction: Reparent all container children when disabling for scratchpad
Fixes: #8205
2024-08-04 18:08:28 +02:00
James Knight
6e4ccb99c3 build: avoid git repository discovery when determining version
When attempting to use Git to populate commit/branch information in a
version string, it is possible through repository discovery that it
uses Git information not relevant to project. For example, if
repository content is extract into an interim build location when using
an embedded build framework (e.g. Buildroot), the project will not have
its Git repository to refer to. When it cannot find its repository, it
will look into its parent folders and may find the Git repository of
another project and use its branch/commit information.

This commit provides an explicit path to the project's Git repository
when consider commit/branch information. This will prevent any
repository discovery from occurring.

Signed-off-by: James Knight <james.d.knight@live.com>
2024-08-03 18:35:55 +02:00
Kirill Primak
9bb45a4037 xwayland: chase wlr_xwayland_surface_set_maximized() change
See
https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4670.
2024-08-02 16:57:01 +02:00
Simon Ser
7e74a49142 desktop/xwayland: don't restack when marking window as inactive
daaec72ac0 ("desktop/xwayland: restack surface upon activation")
has updated Sway for wlroots commit bfc69decdd04 ("xwm: do not
restack surfaces on activation"). However, it unconditionally
restacks the window above all other windows even if marking the
window as inactive.

Closes: https://github.com/swaywm/sway/issues/7974
2024-07-29 14:19:42 -04:00
Joan Bruguera Micó
4d4c88f0a7 layer-shell: Restore interactive layer focus code
Commit 188811f808 ("scene_graph: Port layer_shell") accidentally
removed code in `arrange_layers` to handle focus on layer shell
surfaces with keyboard interactivity.

Due to this, layer shell surfaces requesting exclusive keyboard
interactivity may not get automatically focused, and layer shell
surfaces giving up exclusive keyboard interactivity can remain focused.

Add the previous code back to fix the problem.

Note the non-rename change included in b4d7e84d38 ("desktop: Rename
layers to shell_layers") is not included as it also seems accidental.

Fixes: #7936
2024-07-22 17:03:26 -04:00
Kenny Levinsen
3f327b3db0 desktop/output: Stop repaint loop when not needed
1e0031781f refactored repaint to accumulate all changes in a single
wlr_output_state and commit them at the end of the repaint loop,
replacing a call to wlr_scene_output_commit. wlr_scene_output_commit
contains an early bail-out when no frame has been requested and no
damage has accumulated, which was not replicated as part of this
refactor, causing the repaint loop to never pause.

Replicate the logic to stop the repaint loop as needed.

Fixes: 1e0031781f ("desktop/output: unify page-flip codepath")
2024-07-14 18:24:13 -04:00
Simon Ser
a3a9ec1211 build: use fs.relative_to() instead of hand-rolled logic
Meson has introduced a relative_to() function [1] in its fs module
since version 1.3.

[1]: https://mesonbuild.com/Fs-module.html#relative_to
2024-07-14 18:03:43 -04:00
Bill Li
50073dc579 ci: use package x11-servers/xwayland instead of x11-servers/xwayland-devel 2024-07-14 23:19:19 +02:00
Bill Li
fc2796aee8 Chase wlroots!2434
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/2434
2024-07-14 23:19:19 +02:00
Bill Li
274a5fcb73 build: Bump wlroots version 2024-07-13 13:03:23 +02:00
138 changed files with 2835 additions and 1620 deletions

View file

@ -29,12 +29,12 @@ sources:
tasks:
- wlroots: |
cd wlroots
meson --prefix=/usr build -Dexamples=false
meson setup --prefix=/usr build -Dexamples=false
ninja -C build
sudo ninja -C build install
- setup: |
cd sway
meson build --fatal-meson-warnings -Dauto_features=enabled -Dtray=disabled
meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dtray=disabled
- build: |
cd sway
ninja -C build
@ -52,5 +52,5 @@ tasks:
mkdir subprojects
ln -s ../../wlroots subprojects/wlroots
rm -rf build
meson build --fatal-meson-warnings --default-library=static --force-fallback-for=wlroots
meson setup build --fatal-meson-warnings --default-library=static --force-fallback-for=wlroots
ninja -C build

View file

@ -26,12 +26,12 @@ sources:
tasks:
- wlroots: |
cd wlroots
meson --prefix=/usr build -Dexamples=false
meson setup --prefix=/usr build -Dexamples=false
ninja -C build
sudo ninja -C build install
- setup: |
cd sway
meson build --fatal-meson-warnings -Dauto_features=enabled -Dsd-bus-provider=libsystemd
meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dsd-bus-provider=libsystemd
- build: |
cd sway
ninja -C build

View file

@ -27,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
@ -39,7 +39,7 @@ tasks:
cd subprojects
ln -s ../../wlroots wlroots
cd ..
meson build --fatal-meson-warnings -Dtray=enabled -Dsd-bus-provider=basu
meson setup build --fatal-meson-warnings -Dtray=enabled -Dsd-bus-provider=basu
- build: |
cd sway
ninja -C build

View file

@ -37,7 +37,7 @@ _\* Compile-time dep_
نفذ هذه الأوامر:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install

66
README.az.md Normal file
View file

@ -0,0 +1,66 @@
# sway
sway [i3]-ə uyğun [Wayland] kompozitorudur. [Tez-tez verilən sualları] oxuyun.
[IRC kanalına] qoşulun ("irc.libera.chat"-da #sway).
## Buraxılış İmzaları
Buraxılışlar [E88F5E48] ilə imzalanıb və [GitHub-da][GitHub releases] dərc edilib.
## Quraşdırma
### Paketlərdən
Sway bir çox distributivdə mövcuddur. Öz distributiviniz üçün
"sway" paketini quraşdırmağa çalışın.
### Mənbə kodundan kompilyasiya
Test və ya inkişaf üçün sway və wlroots-un HEAD-ini qurmaq istəyirsinizsə,
[bu viki səhifəsini][Development setup] nəzərdən keçirin.
Asılılıqları quraşdırın:
* meson \*
* [wlroots]
* wayland
* wayland-protocols \*
* pcre2
* json-c
* pango
* cairo
* gdk-pixbuf2 (ixtiyari: sistem trayı üçün əlavə şəkil formatları)
* [swaybg] (ixtiyari: divar kağızı)
* [scdoc] (ixtiyari: man səhifələri) \*
* git (ixtiyari: versiya məlumatı) \*
_\* Kompilyasiya asılılıqları_
Bu əmrləri icra edin:
meson setup build/
ninja -C build/
sudo ninja -C build/ install
## Konfiqurasiya
Əgər artıq i3-dən istifadə edirsinizsə, i3 konfiqurasiyanızı `~/.config/sway/config`
ünvanına köçürün və o, dərhal işləyəcək. Əks halda, nümunə konfiqurasiya faylını
`~/.config/sway/config` ünvanına köçürün. O, adətən `/etc/sway/config` ünvanında yerləşir.
Konfiqurasiya haqqında məlumat üçün `man 5 sway` əmrini icra edin.
## İşə Salma
TTY-dan `sway`-ı işə salın. Bəzi ekran menecerləri işləyə bilər, lakin sway tərəfindən
dəstəklənmir (gdm-in kifayət qədər yaxşı işlədiyi məlumdur).
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/
[Tez-tez verilən sualları]: https://github.com/swaywm/sway/wiki
[IRC kanalına]: https://web.libera.chat/gamja/?channels=#sway
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[swaybg]: https://github.com/swaywm/swaybg/
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -1,25 +1,24 @@
# sway
[English][en] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Svenska][sv] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
sway je s [i3] kompatibilní [Wayland] kompozitor. Přečtěte si [FAQ]. Připojte se na
[IRC kanál][IRC channel] \(#sway na irc.libera.chat).
sway je [waylandový][Wayland] kompozitor kompatibilní s [i3]. Přečtěte si
[FAQ (anglicky)][FAQ]. Připojte se na [IRC kanál (anglicky)][IRC channel]
\(#sway na irc.libera.chat).
## Podpisy vydání
Vydání jsou podepsána [E88F5E48] a publikována [na GitHubu][GitHub releases].
Vydané verze jsou podepsány klíčem [E88F5E48] a publikovány
[na GitHubu][GitHub releases].
## Instalace
### Z balíč
### Z balíků
Sway je dostupný ve spoustě distribucí. Zkuste nainstalovat balíček "sway" ve vaší
distribuci.
Sway je dostupný v mnoha distribucích. Zkuste v té vaší nainstalovat balík "sway".
### Kompilace ze zdrojových kódů
Podívejte se na [tuto stránku wiki][Development setup], pokud chcete sestavit HEAD
sway a wlroots pro testování nebo vývoj.
Pokud chcete sestavit HEAD repozitáře sway a wlroots pro testování nebo vývoj,
použijte návod na [této stránce na wiki (anglicky)][Development setup].
Nainstalujte závislosti:
@ -31,15 +30,16 @@ Nainstalujte závislosti:
* json-c
* pango
* cairo
* gdk-pixbuf2 (volitelné: oznamovací oblast)
* [scdoc] (volitelné: manuálové stránky) \*
* gdk-pixbuf2 (volitelné: dodatečné formáty ikon pro oznamovací oblast)
* [swaybg] (volitelné: tapeta plochy)
* [scdoc] (volitelné: man stránky) \*
* git (volitelné: informace o verzi) \*
_\* Závislost pouze pro sestavení_
_\* Závislost pouze pro kompilaci_
Spusťte tyto příkazy:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install
@ -52,16 +52,16 @@ Pro více informací o konfiguraci spusťte `man 5 sway`.
## Spuštění
Spusťte `sway` z TTY. Některé správce zobrazení mohou fungovat, ale nejsou
podporovány sway (je známo, že gdm funguje docela dobře).
Spusťte `sway` z TTY nebo ze správce displeje.
[en]: https://github.com/swaywm/sway#readme
[ar]: README.ar.md
[cs]: README.cs.md
[de]: README.de.md
[dk]: README.dk.md
[es]: README.es.md
[fr]: README.fr.md
[sv]: README.sv.md
[ge]: README.ge.md
[gr]: README.gr.md
[hi]: README.hi.md
[hu]: README.hu.md
@ -70,10 +70,12 @@ podporovány sway (je známo, že gdm funguje docela dobře).
[ja]: README.ja.md
[ko]: README.ko.md
[nl]: README.nl.md
[no]: README.no.md
[pl]: README.pl.md
[pt]: README.pt.md
[ro]: README.ro.md
[ru]: README.ru.md
[sv]: README.sv.md
[tr]: README.tr.md
[uk]: README.uk.md
[zh-CN]: README.zh-CN.md
@ -86,4 +88,5 @@ podporovány sway (je známo, že gdm funguje docela dobře).
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[swaybg]: https://github.com/swaywm/swaybg/
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -1,21 +1,21 @@
# Sway
Sway ist ein [i3](https://i3wm.org/)-kompatibler [Wayland](http://wayland.freedesktop.org/)-Compositor. Lies die [FAQ](https://github.com/swaywm/sway/wiki). Tritt dem [IRC Channel](https://web.libera.chat/gamja/?channels=#sway) bei (#sway on irc.libera.chat; Englisch).
Sway ist ein [i3]-kompatibler [Wayland]-Compositor. Lies die [FAQ]. Tritt dem [IRC Channel] bei (#sway on irc.libera.chat; Englisch).
## Signaturen
Jedes Release wird mit dem PGP-Schlüssel [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) signiert und [auf GitHub](https://github.com/swaywm/sway/releases) veröffentlicht.
Jeder Release wird mit dem PGP-Schlüssel [E88F5E48] signiert und [auf GitHub][GitHub releases] veröffentlicht.
## Installation
### Über die Paketverwaltung
Sway kann in vielen Distributionen direkt durch die Paketverwaltung installiert werden. Versuche einfach das Packet "sway" zu installieren.
Sway kann in vielen Distributionen direkt durch die Paketverwaltung installiert werden. Versuche einfach das Paket "sway" zu installieren.
### Quellcode selbst kompilieren
sway benötigt die folgenden Pakete:
* meson \*
* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* [wlroots]
* wayland
* wayland-protocols\*
* pcre2
@ -23,21 +23,34 @@ sway benötigt die folgenden Pakete:
* pango
* cairo
* gdk-pixbuf2 (Optional, wird für das Benachrichtigungsfeld (System Tray) benötigt)
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (Optional, wird für die Dokumentation (Man Pages) benötigt)\*
* [swaybg] (Optional, wird für das Setzen von Desktophintergrundbildern benötigt)
* [scdoc] (Optional, wird für die Dokumentation (Man Pages) benötigt)\*
* git (Optional: Versionsinfo)\*
_\*Werden nur während des Kompilierens benötigt_
_\*Werden nur für das Kompilieren benötigt_
Führe die folgenden Befehle aus:
meson build
ninja -C build
sudo ninja -C build install
meson setup build/
ninja -C build/
sudo ninja -C build/ install
Schaue in das [Wiki][Development setup] (Englisch) für Informationen, falls du zum Testen oder Entwickeln den neuesten Stand (HEAD) von sway und wlroots kompilieren willst.
## Konfiguration
Falls du von i3 migrierst, kannst du deine Konfigurationsdatei nach `~/.config/sway/config` kopieren und die Einstellungen sollten ohne Weiteres funktionieren. Ansonsten kannst du die Beispielkonfiguration, die normalerweise in `/etc/sway/config` liegt, nach `~/.config/sway/config` kopieren. Die Dokumentation zur Konfigurationsdatei findest du in `man 5 sway`.
## Sway starten
Sway kann einfach mit dem Befehl `sway` vom TTY gestartet werden.
Display-Manager werden nicht offiziell unterstützt. Es gibt aber durchaus einige, die mit Sway funktionieren (z.B. gdm).
Sway kann einfach mit dem Befehl `sway` vom TTY oder mithilfe eines Displaymanagers gestartet werden.
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/
[FAQ]: https://github.com/swaywm/sway/wiki
[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[swaybg]: https://github.com/swaywm/swaybg
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -41,7 +41,7 @@ _\*Kompileringsafhængighed_
Kør følgende kommandoer:
meson build
meson setup build
ninja -C build
sudo ninja -C build install
@ -54,8 +54,7 @@ Hvis du allerede bruger i3 kan du bare kopiere din i3 konfiguration til
## Eksekvering
Kør `sway` fra en TTY. Nogle display managers kan fungere, men Sway yder ikke
support til dem (gdm er kendt for at fungere temmelig godt).
Kør `sway` fra en TTY eller fra en display manager.
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/

View file

@ -40,7 +40,7 @@ _\*Compile-time dep_
Desde su consola, ejecute las órdenes:
meson build
meson setup build
ninja -C build
sudo ninja -C build install

View file

@ -47,7 +47,7 @@ _\* Requis uniquement pour la compilation_
Exécutez ces commandes :
meson build
meson setup build
ninja -C build
sudo ninja -C build install
@ -61,9 +61,7 @@ documentation pour la configuration de sway.
## Exécution
Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent
fonctionner, mais ne sont pas supportés par Sway (gdm est réputé pour assez
bien fonctionner).
Exécutez `sway` à partir d'un TTY ou d'un gestionnaires d'affichage.
[Wayland]: http://wayland.freedesktop.org/
[i3]: https://i3wm.org/

View file

@ -35,7 +35,7 @@ _\* Compile-time dep_
გაუშვით ეს ბრძანებები:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install

View file

@ -40,7 +40,7 @@ _\*Compile-time dep_
Τρέξτε αυτά τα commands:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install

View file

@ -44,7 +44,7 @@ _\* Compilation के समय आवश्यक_
ये commands चलाएं:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install

View file

@ -1,10 +1,10 @@
# sway
A Sway egy [i3]-kompatibilis [Wayland] kompozitor. Olvasd el a [Gyarkan Ismételt Kérdéseket][FAQ]. Csatlakozz az [IRC csatornához][IRC channel] \(`#sway` az `irc.libera.chat`-en).
A Sway egy [i3]-kompatibilis [Wayland]-kompozitor. Olvasd el a [Gyarkan Ismételt Kérdéseket][FAQ]. Csatlakozz az [IRC-csatornához][IRC channel] \(`#sway` az `irc.libera.chat`-en).
## Csomagaláírások
A kiadott csomagok az [E88F5E48] kulccsal vannak aláírva és [GitHub-on][GitHub releases] publikálva.
A kiadott csomagok az [E88F5E48] kulccsal vannak aláírva, és [GitHubon][GitHub releases] publikálva.
## Telepítés
@ -13,7 +13,7 @@ A kiadott csomagok az [E88F5E48] kulccsal vannak aláírva és [GitHub-on][GitHu
A Sway sok disztribúció csomagkezelőjéből elérhető, próbáld meg a "sway"
csomagot telepíteni az általad használt eszközzel.
Ha szeretnél csomagot készíteni a saját disztribúciódhoz, ugorj be az IRC
Ha szeretnél csomagot készíteni a saját disztribúciódhoz, ugorj be az IRC-
csatornára, vagy küldj levelet a sir@cmpwn.com címre tanácsokért.
### Fordítás forráskódból
@ -40,13 +40,13 @@ _\*Fordításidejű függőség_
Futtasd ezeket a parancsokat:
meson build
meson setup build
ninja -C build
sudo ninja -C build install
## Konfiguráció
Ha előzőleg i3-mat használtál, akkor átmásolhatod az i3 beállításaidat a
Ha előzőleg i3-at használtál, akkor átmásolhatod az i3-beállításaidat a
`~/.config/sway/config` file-ba és ugyanúgy működni fognak. Egyéb esetben másold
le kiindulási alapnak a mintát, ami általában az `etc/sway/config` elérési
útvonalon található.
@ -55,7 +55,7 @@ kapcsolatban.
## Futtatás
Futtasd a `sway` parancsot egy TTY felületről. Néhány bejelentkezéskezelő
Futtasd a `sway` parancsot egy TTY-felületről. Néhány bejelentkezéskezelő
(display manager) működhet, de alapvetően nem támogatottak a sway által. (A
gdm-ről ismeretes, hogy egész jól működik.)

View file

@ -41,7 +41,7 @@ _\*نیازمندی‌های زمان کامپایل برنامه_
این فرمان‌ها را اجرا کنید:
meson build
meson setup build
ninja -C build
sudo ninja -C build install

View file

@ -1,7 +1,7 @@
# sway
sway è un compositore di [Wayland] compatibile con [i3]. Leggi le [FAQ].
Unisciti al [canale di IRC] \(#sway su irc.libera.chat).
Unisciti al [canale IRC] \(#sway su irc.libera.chat).
## Firma delle versioni
@ -38,7 +38,7 @@ _\* Dipendenza necessaria per la compilazione_
Esegui questi comandi:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install
@ -52,13 +52,12 @@ configurazione.
## Esecuzione
Lancia `sway` da un TTY. Alcuni gestori d'accesso potrebbero funzionare ma non
sono supportati da sway (gdm funziona abbastanza bene).
Lancia `sway` da un TTY o da un display manager.
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/
[FAQ]: https://github.com/swaywm/sway/wiki
[canale di IRC]: https://web.libera.chat/gamja/?channels=#sway
[canale IRC]: https://web.libera.chat/gamja/?channels=#sway
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup

View file

@ -42,7 +42,7 @@ _\*コンパイル時の依存_
次のコマンドを実行してください:
meson build
meson setup build
ninja -C build
sudo ninja -C build install
@ -52,5 +52,4 @@ _\*コンパイル時の依存_
## 実行
`sway`をTTYから実行してください。いくつかのディスプレイマネージャは動くかもしれませんが、Swayからサポートされていません(gdmは非常に良く動作することが知られています)。
`sway`をTTYまたはディスプレイマネージャから実行してください。

View file

@ -39,7 +39,7 @@ _\*컴파일 떄 필요_
다음 명령을 실행하세요:
meson build
meson setup build
ninja -C build
sudo ninja -C build install
@ -52,4 +52,4 @@ i3를 이미 사용 중이라면, i3 config을 `~/.config/sway/config`로 복사
## 실행
TTY에서 `sway`를 실행하세요. 일부 display manager는 작동하지만, sway로 부터 지원되지 않습니다(gdm은 상당히 잘 작동한다고 알려져 있습니다).
TTY나 display manager에서 `sway`를 실행하세요.

View file

@ -1,6 +1,6 @@
# sway
**[English][en]** - [عربي][ar] - [Česky][cs] - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [ქართული][ge] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Norsk][no] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Svenska][sv] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
**[English][en]** - [عربي][ar] - [Azərbaycanca][az] - [Česky][cs] - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [ქართული][ge] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Norsk][no] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Српски][sr] - [Svenska][sv] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
sway is an [i3]-compatible [Wayland] compositor. Read the [FAQ]. Join the
[IRC channel] \(#sway on irc.libera.chat).
@ -40,7 +40,7 @@ _\* Compile-time dep_
Run these commands:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install
@ -53,11 +53,11 @@ Run `man 5 sway` for information on the configuration.
## Running
Run `sway` from a TTY. Some display managers may work but are not supported by
sway (gdm is known to work fairly well).
Run `sway` from a TTY or from a display manager.
[en]: https://github.com/swaywm/sway#readme
[ar]: README.ar.md
[az]: README.az.md
[cs]: README.cs.md
[de]: README.de.md
[dk]: README.dk.md
@ -77,6 +77,7 @@ sway (gdm is known to work fairly well).
[pt]: README.pt.md
[ro]: README.ro.md
[ru]: README.ru.md
[sr]: README.sr.md
[sv]: README.sv.md
[tr]: README.tr.md
[uk]: README.uk.md

View file

@ -40,7 +40,7 @@ _\* Compileerafhankelijkheden_
Voer deze opdrachten uit:
meson build
meson setup build
ninja -C build
sudo ninja -C build install

View file

@ -1,29 +1,25 @@
# Sway
Sway er en [i3]-kompatibel [Wayland] compositor. Les [Ofte stilte spørsmål].
Delta på [IRC kanalen][IRC kanal] \(#sway på irc.libera.chat).
Sway er en [i3]-kompatibel [Wayland]-compositor. Les [Ofte stilte spørsmål].
Delta på [IRC-kanalen][IRC-kanal] \(#sway på irc.libera.chat).
## Utgivelses Signaturer
## Signaturer
Utgivelser er signert med [E88F5E48] og publisert [på GitHub][GitHub
releases].
Utgivelser er signert med [E88F5E48] og publisert [på GitHub][GitHub releases].
## Installasjon
### Fra systempakker
Sway er tilgjengelig i mange distribusjoner. Prøv å installere "sway" pakken
Sway er tilgjengelig i mange distribusjoner. Prøv å installere pakken "sway"
fra din distro sine repoer.
Er du interessert i å pakke Sway for din distribusjon kan du ta turen innom
IRC-kanalen eller send en e-post til sir@cmpwn.com for råd.
### Kompilering fra kildekode
Se [denne wiki-siden][Oppsetting for utvikling] hvis du vil bygge fra HEAD grenen av sway og
wlroots for testing eller utvikling.
Se [denne wiki-siden][Oppsetting for utvikling] hvis du vil bygge fra HEAD-grenen av
sway og wlroots for testing eller utvikling.
Installasjonsavhengigheter:
Installer avhengigheter:
* meson \*
* [wlroots]
@ -33,36 +29,37 @@ Installasjonsavhengigheter:
* json-c
* pango
* cairo
* gdk-pixbuf2 (valgfritt: system tray)
* gdk-pixbuf2 (valgfritt: støtte for ekstra bildeformater i system tray)
* [swaybg] (valgfritt: bakgrunnsbilde)
* [scdoc] (valgfritt: man pages) \*
* git \*
* git (valgfritt: versjonsinformasjon) \*
_\* Kompileringsavhengigheter_
Kjør følgende kommandoer:
meson build
ninja -C build
sudo ninja -C build install
meson setup build/
ninja -C build/
sudo ninja -C build/ install
## Konfigurasjon
Hvis du allerede bruker i3 kan du bare kopiere din i3 konfigurasjon til
Hvis du allerede bruker i3 kan du bare kopiere din i3-konfigurasjon til
`~/.config/sway/config`. Ellers skal du kopiere eksempelkonfigurasjonsfilen til
`~/.config/sway/config`. Eksempel filen er normalt plasert i `/etc/sway/config`. Kjør
`man 5 sway` for å få oplysninger om konfigurasjonen.
`~/.config/sway/config`. Eksempelfilen er normalt plasert i `/etc/sway/config`.
Kjør `man 5 sway` for å få opplysninger om konfigurasjonen.
## Utførelse
## Kjøring
Kjør `sway` fra en TTY. Noen display managers kan fungere, men Sway har ikke
støtte for dem (gdm er kjent for å fungere ganske bra).
Kjør `sway` fra en TTY eller fra en display manager.
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/
[Ofte stilte spørsmål]: https://github.com/swaywm/sway/wiki
[IRC kanal]: https://web.libera.chat/gamja/?channels=#sway
[IRC-kanal]: https://web.libera.chat/gamja/?channels=#sway
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Oppsetting for utvikling]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[swaybg]: https://github.com/swaywm/swaybg/
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -40,7 +40,7 @@ _\*zależności kompilacji_
Wykonaj następujące polecenia:
meson build
meson setup build
ninja -C build
sudo ninja -C build install
@ -53,5 +53,4 @@ Wykonaj polecenie `man 5 sway` aby uzyskać informacje dotyczące konfiguracji.
## Uruchamianie
Wykonaj polecenie `sway` z poziomu TTY. Niektóre menedżery wyświetlania mogą umożliwiać rozruch z ich
poziomu, ale nie jest to wspierane przez sway (w gdm podobno działa to całkiem nieźle).
Wykonaj polecenie `sway` z poziomu TTY lub menedżera wyświetlania.

View file

@ -42,7 +42,7 @@ _\*Dependência de tempo de compilação_
Execute esses comandos:
meson build
meson setup build
ninja -C build
sudo ninja -C build install

View file

@ -38,7 +38,7 @@ Dependențe pentru instalare:
Rulați aceste comenzi:
```
meson build
meson setup build
ninja -C build
sudo ninja -C build install
```

View file

@ -41,7 +41,7 @@ _\*Зависимости для сборки_
Выполните эти команды:
meson build
meson setup build
ninja -C build
sudo ninja -C build install
@ -54,8 +54,7 @@ _\*Зависимости для сборки_
## Запуск
Выполните команду `sway` прямо из TTY. Некоторые дисплейные менеджеры могут работать, но они не поддерживаются со стороны
sway (gdm работает довольно неплохо).
Выполните команду `sway` прямо из TTY или дисплейного менеджера.
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/

65
README.sr.md Normal file
View file

@ -0,0 +1,65 @@
# sway
sway је [i3]-компатибилан [Wayland] композитор. Прочитајте [FAQ]. Придружите се
[IRC каналу] \(#sway на irc.libera.chat).
## Потписи Издања
Издања су потписана са [E88F5E48] и објављена [на GitHub-у][GitHub releases].
## Инсталација
### Из пакета
Sway је доступан у многим дистрибуцијама. Покушајте да инсталирате "sway" пакет за
вашу.
### Компајлирање из Извора
Погледајте [ову вики страницу][Development setup], ако желите да компајлирате HEAD верзију
sway-а и wlroots-а за тестирање или развој.
Инсталирајте зависности:
* meson \*
* [wlroots]
* wayland
* wayland-protocols \*
* pcre2
* json-c
* pango
* cairo
* gdk-pixbuf2 (опционо: додатни формати слика за системску траку)
* [swaybg] (опционо: позадина)
* [scdoc] (опционо: man странице) \*
* git (опционо: информације о верзији) \*
_\* Потребно само за компајлирање_
Покрените следеће команде:
meson setup build/
ninja -C build/
sudo ninja -C build/ install
## Конфигурација
Ако већ користите i3, копирајте вашу i3 конфигурацију у `~/.config/sway/config` и
радиће одмах. У супротном, копирајте пример конфигурационе датотеке у
`~/.config/sway/config`. Обично се налази у `/etc/sway/config`.
Покрените `man 5 sway` за информације о конфигурацији.
## Покретање
Покрените `sway` из TTY-a или из менаџера приказа.
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/
[FAQ]: https://github.com/swaywm/sway/wiki
[IRC каналу]: https://web.libera.chat/gamja/?channels=#sway
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[swaybg]: https://github.com/swaywm/swaybg/
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -1,7 +1,5 @@
# sway
[English][en] - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - **[Svenska][sv]** - [Ελληνικά][gr] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
sway är en [i3]-kompatibel [Wayland] compositor. Läs våran [FAQ]-sida. Gå med i vår
[IRC-kanal] \(#sway på irc.libera.chat).
@ -37,7 +35,7 @@ _\* Krav för kompilering_
Kör dessa kommandon:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install

View file

@ -38,7 +38,7 @@ _\*Derleme-anı bağımlılıkları_
Şu komutları çalıştırın:
meson build
meson setup build
ninja -C build
sudo ninja -C build install

View file

@ -51,7 +51,7 @@ _\*Лише для компіляції_
Виконайте ці команди:
meson build
meson setup build
ninja -C build
sudo ninja -C build install

View file

@ -35,7 +35,7 @@ _\*编译时依赖_
运行如下命令:
meson build/
meson setup build/
ninja -C build/
sudo ninja -C build/ install

View file

@ -40,7 +40,7 @@ _\*編譯時相依_
執行這些指令:
meson build
meson setup build
ninja -C build
sudo ninja -C build install

View file

@ -360,3 +360,7 @@ char *format_str(const char *fmt, ...) {
va_end(args);
return str;
}
bool has_prefix(const char *str, const char *prefix) {
return strncmp(str, prefix, strlen(prefix)) == 0;
}

View file

@ -141,3 +141,9 @@ bool sway_set_cloexec(int fd, bool cloexec) {
}
return true;
}
uint32_t get_current_time_in_msec(void) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec * 1000 + now.tv_nsec / 1000000;
}

View file

@ -16,9 +16,7 @@ set $right l
# Your preferred terminal emulator
set $term foot
# Your preferred application launcher
# Note: pass the final command to swaymsg so that the resulting window can be opened
# on the original workspace that the command was run on.
set $menu dmenu_path | wmenu | xargs swaymsg exec --
set $menu wmenu-run
### Output configuration
#
@ -48,14 +46,18 @@ output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
#
# Example configuration:
#
# input "2:14:SynPS/2_Synaptics_TouchPad" {
# input type:touchpad {
# dwt enabled
# tap enabled
# natural_scroll enabled
# middle_emulation enabled
# }
#
# You can get the names of your inputs by running: swaymsg -t get_inputs
# input type:keyboard {
# xkb_layout "eu"
# }
#
# You can also configure each device individually.
# Read `man 5 sway-input` for more information about this section.
### Key bindings
@ -195,6 +197,28 @@ mode "resize" {
bindsym Escape mode "default"
}
bindsym $mod+r mode "resize"
#
# Utilities:
#
# Special keys to adjust volume via PulseAudio
bindsym --locked XF86AudioMute exec pactl set-sink-mute \@DEFAULT_SINK@ toggle
bindsym --locked XF86AudioLowerVolume exec pactl set-sink-volume \@DEFAULT_SINK@ -5%
bindsym --locked XF86AudioRaiseVolume exec pactl set-sink-volume \@DEFAULT_SINK@ +5%
bindsym --locked XF86AudioMicMute exec pactl set-source-mute \@DEFAULT_SOURCE@ toggle
# Special keys to control media via playerctl
bindsym --locked XF86AudioPlay exec playerctl play-pause
bindsym --locked XF86AudioPause exec playerctl play-pause
bindsym --locked XF86AudioPrev exec playerctl previous
bindsym --locked XF86AudioNext exec playerctl next
bindsym --locked XF86AudioStop exec playerctl stop
# Special keys to adjust brightness via brightnessctl
bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
# Special key to take a screenshot with grim
bindsym Print exec grim
#
# Status Bar:

View file

@ -40,4 +40,6 @@ bool expand_path(char **path);
char *vformat_str(const char *fmt, va_list args) _SWAY_ATTRIB_PRINTF(1, 0);
char *format_str(const char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
bool has_prefix(const char *str, const char *prefix);
#endif

View file

@ -104,6 +104,7 @@ struct sway_container *container_find_resize_parent(struct sway_container *con,
sway_cmd cmd_exec_validate;
sway_cmd cmd_exec_process;
sway_cmd cmd_allow_tearing;
sway_cmd cmd_assign;
sway_cmd cmd_bar;
sway_cmd cmd_bindcode;
@ -283,11 +284,13 @@ sway_cmd input_cmd_xkb_switch_layout;
sway_cmd input_cmd_xkb_variant;
sway_cmd output_cmd_adaptive_sync;
sway_cmd output_cmd_allow_tearing;
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;
sway_cmd output_cmd_hdr;
sway_cmd output_cmd_max_render_time;
sway_cmd output_cmd_mode;
sway_cmd output_cmd_modeline;

View file

@ -261,7 +261,8 @@ enum scale_filter_mode {
};
enum render_bit_depth {
RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8
RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8 for SDR, 10 for HDR
RENDER_BIT_DEPTH_6,
RENDER_BIT_DEPTH_8,
RENDER_BIT_DEPTH_10,
};
@ -289,20 +290,14 @@ struct output_config {
enum render_bit_depth render_bit_depth;
bool set_color_transform;
struct wlr_color_transform *color_transform;
int allow_tearing;
int hdr;
char *background;
char *background_option;
char *background_fallback;
};
/**
* An output config pre-matched to an output
*/
struct matched_output_config {
struct sway_output *output;
struct output_config *config;
};
/**
* Stores size of gaps for each side
*/
@ -692,13 +687,10 @@ 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, bool degrade_to_off);
bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
bool test_only, bool degrade_to_off);
void apply_all_output_configs(void);
void sort_output_configs_by_priority(struct matched_output_config *configs,
size_t configs_len);
void apply_stored_output_configs(void);
/**
* store_output_config stores a new output config. An output may be matched by
@ -713,6 +705,10 @@ struct output_config *find_output_config(struct sway_output *output);
void free_output_config(struct output_config *oc);
void request_modeset(void);
void force_modeset(void);
bool modeset_is_pending(void);
bool spawn_swaybg(void);
int workspace_output_cmp_workspace(const void *a, const void *b);

View file

@ -53,6 +53,10 @@ struct criteria {
char urgent; // 'l' for latest or 'o' for oldest
struct pattern *workspace;
pid_t pid;
struct pattern *sandbox_engine;
struct pattern *sandbox_app_id;
struct pattern *sandbox_instance_id;
struct pattern *tag;
};
bool criteria_is_empty(struct criteria *criteria);

View file

@ -13,6 +13,7 @@ enum sway_idle_inhibit_mode {
struct sway_idle_inhibit_manager_v1 {
struct wlr_idle_inhibit_manager_v1 *wlr_manager;
struct wl_listener new_idle_inhibitor_v1;
struct wl_listener manager_destroy;
struct wl_list inhibitors;
};

View file

@ -39,6 +39,8 @@ struct sway_input_manager {
struct sway_input_manager *input_manager_create(struct sway_server *server);
void input_manager_finish(struct sway_input_manager *input);
bool input_manager_has_focus(struct sway_node *node);
void input_manager_set_focus(struct sway_node *node);

View file

@ -25,8 +25,10 @@ struct sway_input_method_relay {
struct wlr_input_method_v2 *input_method; // doesn't have to be present
struct wl_listener text_input_new;
struct wl_listener text_input_manager_destroy;
struct wl_listener input_method_new;
struct wl_listener input_method_manager_destroy;
struct wl_listener input_method_commit;
struct wl_listener input_method_new_popup_surface;
struct wl_listener input_method_grab_keyboard;

View file

@ -9,11 +9,14 @@ struct sway_input_popup {
struct wlr_scene_tree *scene_tree;
struct sway_popup_desc desc;
struct wlr_input_popup_surface_v2 *popup_surface;
struct wlr_output *fixed_output;
struct wl_list link;
struct wl_listener popup_destroy;
struct wl_listener popup_surface_commit;
struct wl_listener popup_surface_map;
struct wl_listener popup_surface_unmap;
struct wl_listener focused_surface_unmap;
};

View file

@ -9,7 +9,6 @@ struct sway_layer_surface {
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener surface_commit;
struct wl_listener output_destroy;
struct wl_listener node_destroy;
struct wl_listener new_popup;
@ -19,6 +18,8 @@ struct sway_layer_surface {
struct sway_popup_desc desc;
struct sway_output *output;
struct wl_list link; // sway_output.layer_surfaces
struct wlr_scene_layer_surface_v1 *scene;
struct wlr_scene_tree *tree;
struct wlr_layer_surface_v1 *layer_surface;
@ -41,4 +42,6 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
void arrange_layers(struct sway_output *output);
void destroy_layers(struct sway_output *output);
#endif

6
include/sway/lock.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef _SWAY_LOCK_H
#define _SWAY_LOCK_H
void arrange_locks(void);
#endif

View file

@ -52,27 +52,25 @@ struct sway_output {
bool enabled;
list_t *workspaces;
struct wl_list layer_surfaces; // sway_layer_surface.link
struct sway_output_state current;
struct wl_listener layout_destroy;
struct wl_listener destroy;
struct wl_listener commit;
struct wl_listener present;
struct wl_listener frame;
struct wl_listener request_state;
struct {
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
struct wl_event_source *repaint_timer;
bool gamma_lut_changed;
bool allow_tearing;
bool hdr;
};
struct sway_output_non_desktop {
@ -92,6 +90,9 @@ struct sway_output *output_from_wlr_output(struct wlr_output *output);
struct sway_output *output_get_in_direction(struct sway_output *reference,
enum wlr_direction direction);
void output_configure_scene(struct sway_output *output,
struct wlr_scene_node *node, float opacity);
void output_add_workspace(struct sway_output *output,
struct sway_workspace *workspace);
@ -130,15 +131,13 @@ struct sway_container *output_find_container(struct sway_output *output,
void output_get_box(struct sway_output *output, struct wlr_box *box);
bool output_supports_hdr(struct wlr_output *output, const char **unsupported_reason_ptr);
enum sway_container_layout output_get_default_layout(
struct sway_output *output);
enum wlr_direction opposite_direction(enum wlr_direction d);
void handle_output_layout_change(struct wl_listener *listener, void *data);
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data);
void handle_output_manager_apply(struct wl_listener *listener, void *data);
void handle_output_manager_test(struct wl_listener *listener, void *data);
@ -148,4 +147,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
void update_output_manager_config(struct sway_server *server);
#endif

View file

@ -27,7 +27,7 @@ struct sway_session_lock {
struct sway_server {
struct wl_display *wl_display;
struct wl_event_loop *wl_event_loop;
const char *socket;
char *socket;
struct wlr_backend *backend;
struct wlr_session *session;
@ -45,8 +45,8 @@ struct sway_server {
struct sway_input_manager *input;
struct wl_listener new_output;
struct wl_listener output_layout_change;
struct wl_listener renderer_lost;
struct wl_event_source *recreating_renderer;
struct wlr_idle_notifier_v1 *idle_notifier_v1;
struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1;
@ -105,17 +105,28 @@ struct sway_server {
struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
struct wlr_content_type_manager_v1 *content_type_manager_v1;
struct wlr_data_control_manager_v1 *data_control_manager_v1;
struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1;
struct wlr_ext_data_control_manager_v1 *ext_data_control_manager_v1;
struct wlr_screencopy_manager_v1 *screencopy_manager_v1;
struct wlr_ext_image_copy_capture_manager_v1 *ext_image_copy_capture_manager_v1;
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1;
struct wlr_security_context_manager_v1 *security_context_manager_v1;
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *ext_foreign_toplevel_image_capture_source_manager_v1;
struct wl_listener new_foreign_toplevel_capture_request;
struct wlr_xdg_activation_v1 *xdg_activation_v1;
struct wl_listener xdg_activation_v1_request_activate;
struct wl_listener xdg_activation_v1_new_token;
struct wl_listener xdg_toplevel_tag_manager_v1_set_tag;
struct wl_listener request_set_cursor_shape;
struct wlr_tearing_control_manager_v1 *tearing_control_v1;
struct wl_listener tearing_control_new_object;
struct wl_list tearing_controllers; // sway_tearing_controller::link
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
// The timeout for transactions, after which a transaction is applied
@ -145,20 +156,19 @@ struct sway_debug {
bool noatomic; // Ignore atomic layout updates
bool txn_timings; // Log verbose messages about transactions
bool txn_wait; // Always wait for the timeout before applying
bool legacy_wl_drm; // Enable the legacy wl_drm interface
};
extern struct sway_debug debug;
extern bool allow_unsupported_gpu;
void sway_terminate(int exit_code);
bool server_init(struct sway_server *server);
void server_fini(struct sway_server *server);
bool server_start(struct sway_server *server);
void server_run(struct sway_server *server);
void restore_nofile_limit(void);
void handle_new_output(struct wl_listener *listener, void *data);
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
@ -182,4 +192,6 @@ void xdg_activation_v1_handle_new_token(struct wl_listener *listener,
void set_rr_scheduling(void);
void handle_new_tearing_hint(struct wl_listener *listener, void *data);
#endif

View file

@ -95,6 +95,7 @@ struct sway_container {
struct wl_listener output_enter;
struct wl_listener output_leave;
struct wl_listener output_handler_destroy;
struct sway_container_state current;
struct sway_container_state pending;
@ -103,6 +104,8 @@ struct sway_container {
char *formatted_title; // The title displayed in the title bar
int title_width;
char *title_format;
enum sway_container_layout prev_split_layout;
// Whether stickiness has been enabled on this container. Use
@ -183,6 +186,8 @@ void container_update_title_bar(struct sway_container *container);
void container_update_marks(struct sway_container *container);
size_t parse_title_format(struct sway_container *container, char *buffer);
size_t container_build_representation(enum sway_container_layout layout,
list_t *children, char *buffer);

View file

@ -16,8 +16,6 @@ struct sway_root {
struct sway_node node;
struct wlr_output_layout *output_layout;
struct wl_listener output_layout_change;
// scene node layout:
// - root
// - staging

View file

@ -4,6 +4,7 @@
#include <wlr/config.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_tearing_control_v1.h>
#include "sway/config.h"
#if WLR_HAS_XWAYLAND
#include <wlr/xwayland.h>
@ -24,6 +25,7 @@ enum sway_view_type {
enum sway_view_prop {
VIEW_PROP_TITLE,
VIEW_PROP_APP_ID,
VIEW_PROP_TAG,
VIEW_PROP_CLASS,
VIEW_PROP_INSTANCE,
VIEW_PROP_WINDOW_TYPE,
@ -34,6 +36,12 @@ enum sway_view_prop {
#endif
};
enum sway_view_tearing_mode {
TEARING_OVERRIDE_FALSE,
TEARING_OVERRIDE_TRUE,
TEARING_WINDOW_HINT,
};
struct sway_view_impl {
void (*get_constraints)(struct sway_view *view, double *min_width,
double *max_width, double *min_height, double *max_height);
@ -62,6 +70,9 @@ struct sway_view {
struct wlr_scene_tree *content_tree;
struct wlr_scene_tree *saved_surface_tree;
struct wlr_scene *image_capture_scene;
struct wlr_ext_image_capture_source_v1 *image_capture_source;
struct sway_container *container; // NULL if unmapped and transactions finished
struct wlr_surface *surface; // NULL for unmapped views
struct sway_xdg_decoration *xdg_decoration;
@ -73,8 +84,6 @@ struct sway_view {
// Used when changing a view from tiled to floating.
int natural_width, natural_height;
char *title_format;
bool using_csd;
struct timespec urgent;
@ -111,11 +120,17 @@ struct sway_view {
int max_render_time; // In milliseconds
enum seat_config_shortcuts_inhibit shortcuts_inhibit;
enum sway_view_tearing_mode tearing_mode;
enum wp_tearing_control_v1_presentation_hint tearing_hint;
};
struct sway_xdg_shell_view {
struct sway_view view;
struct wlr_scene_tree *image_capture_tree;
char *tag;
struct wl_listener commit;
struct wl_listener request_move;
struct wl_listener request_resize;
@ -134,6 +149,8 @@ struct sway_xwayland_view {
struct wlr_scene_tree *surface_tree;
struct wlr_scene_surface *image_capture_scene_surface;
struct wl_listener commit;
struct wl_listener request_move;
struct wl_listener request_resize;
@ -184,10 +201,12 @@ struct sway_popup_desc {
struct sway_xdg_popup {
struct sway_view *view;
struct wlr_xdg_popup *wlr_xdg_popup;
struct wlr_scene_tree *scene_tree;
struct wlr_scene_tree *xdg_surface_tree;
struct wlr_xdg_popup *wlr_xdg_popup;
struct wlr_scene_tree *image_capture_tree;
struct sway_popup_desc desc;
@ -213,6 +232,14 @@ const char *view_get_window_role(struct sway_view *view);
uint32_t view_get_window_type(struct sway_view *view);
const char *view_get_sandbox_engine(struct sway_view *view);
const char *view_get_sandbox_app_id(struct sway_view *view);
const char *view_get_sandbox_instance_id(struct sway_view *view);
const char *view_get_tag(struct sway_view *view);
const char *view_get_shell(struct sway_view *view);
void view_get_constraints(struct sway_view *view, double *min_width,
@ -335,4 +362,8 @@ void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
void view_send_frame_done(struct sway_view *view);
bool view_can_tear(struct sway_view *view);
void xdg_toplevel_tag_manager_v1_handle_set_tag(struct wl_listener *listener, void *data);
#endif

View file

@ -96,7 +96,7 @@ void workspace_output_add_priority(struct sway_workspace *workspace,
struct sway_output *output);
struct sway_output *workspace_output_get_highest_available(
struct sway_workspace *ws, struct sway_output *exclude);
struct sway_workspace *ws);
void workspace_detect_urgent(struct sway_workspace *workspace);

View file

@ -14,6 +14,11 @@ struct box_colors {
uint32_t text;
};
struct box_size {
uint32_t width;
uint32_t height;
};
struct config_output {
struct wl_list link; // swaybar_config::outputs
char *name;

View file

@ -61,4 +61,6 @@ const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);
bool sway_set_cloexec(int fd, bool cloexec);
uint32_t get_current_time_in_msec(void);
#endif

View file

@ -1,13 +1,14 @@
project(
'sway',
'c',
version: '1.10-dev',
version: '1.12-dev',
license: 'MIT',
meson_version: '>=0.60.0',
meson_version: '>=1.3',
default_options: [
'c_std=c11',
'warning_level=2',
'werror=true',
'wrap_mode=nodownload',
],
)
@ -38,14 +39,14 @@ if is_freebsd
endif
# Execute the wlroots subproject, if any
wlroots_version = ['>=0.18.0', '<0.19.0']
wlroots_version = ['>=0.20.0', '<0.21.0']
subproject(
'wlroots',
default_options: ['examples=false'],
required: false,
version: wlroots_version,
)
wlroots = dependency('wlroots-0.18', version: wlroots_version, fallback: 'wlroots')
wlroots = dependency('wlroots-0.20', version: wlroots_version, fallback: 'wlroots')
wlroots_features = {
'xwayland': false,
'libinput_backend': false,
@ -64,7 +65,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', default_options: ['tests=false'])
wayland_protos = dependency('wayland-protocols', version: '>=1.41', default_options: ['tests=false'])
xkbcommon = dependency('xkbcommon', version: '>=1.5.0')
cairo = dependency('cairo')
pango = dependency('pango')
@ -79,7 +80,7 @@ libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_de
math = cc.find_library('m')
rt = cc.find_library('rt')
xcb_icccm = wlroots_features['xwayland'] ? dependency('xcb-icccm') : null_dep
threads = dependency('threads') # for pthread_setschedparam
threads = dependency('threads') # for pthread_setschedparam and pthread_atfork
if get_option('sd-bus-provider') == 'auto'
if not get_option('tray').disabled()
@ -109,11 +110,9 @@ conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd
conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind')
conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu')
conf_data.set10('HAVE_TRAY', have_tray)
conf_data.set10('HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', cc.has_header_symbol(
'libinput.h',
'LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM',
dependencies: libinput,
))
foreach sym : ['LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', 'LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY']
conf_data.set10('HAVE_' + sym, cc.has_header_symbol('libinput.h', sym, dependencies: libinput))
endforeach
scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
if scdoc.found()
@ -160,8 +159,8 @@ add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir
version = '"@0@"'.format(meson.project_version())
git = find_program('git', native: true, required: false)
if git.found()
git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false)
git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
git_commit = run_command([git, '--git-dir=.git', 'rev-parse', '--short', 'HEAD'], check: false)
git_branch = run_command([git, '--git-dir=.git', 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
if git_commit.returncode() == 0 and git_branch.returncode() == 0
version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format(
meson.project_version(),
@ -172,31 +171,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),

View file

@ -9,11 +9,8 @@ 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/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',
wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
'wlr-layer-shell-unstable-v1.xml',
'idle.xml',
'wlr-output-power-management-unstable-v1.xml',

View file

@ -1,7 +1,7 @@
#!/bin/sh -eu
prev=$(git describe --tags --abbrev=0)
next=$(meson rewrite kwargs info project / 2>&1 >/dev/null | jq -r '.kwargs["project#/"].version')
next=$(meson rewrite kwargs info project / | jq -r '.kwargs["project#/"].version')
case "$next" in
*-dev)
@ -28,4 +28,5 @@ archive=$prefix.tar.gz
git archive --prefix="$prefix/" -o "$archive" "$next"
gpg --output "$archive".sig --detach-sig "$archive"
git push --follow-tags
gh release create "sway $next" -t "$next" -n "" -d "$archive" "$archive.sig"

View file

@ -3,3 +3,4 @@ Name=Sway
Comment=An i3-compatible Wayland compositor
Exec=sway
Type=Application
DesktopNames=sway;wlroots

View file

@ -112,6 +112,7 @@ static const struct cmd_handler config_handlers[] = {
/* Runtime-only commands. Keep alphabetized */
static const struct cmd_handler command_handlers[] = {
{ "allow_tearing", cmd_allow_tearing },
{ "border", cmd_border },
{ "create_output", cmd_create_output },
{ "exit", cmd_exit },

View file

@ -0,0 +1,24 @@
#include <sway/commands.h>
#include "sway/config.h"
#include "sway/tree/view.h"
#include "util.h"
struct cmd_results *cmd_allow_tearing(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "allow_tearing", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct sway_container *container = config->handler_context.container;
if (!container || !container->view) {
return cmd_results_new(CMD_INVALID, "Tearing can only be allowed on views");
}
bool wants_tearing = parse_boolean(argv[0], true);
struct sway_view *view = container->view;
view->tearing_mode = wants_tearing ? TEARING_OVERRIDE_TRUE :
TEARING_OVERRIDE_FALSE;
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -23,7 +23,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
--argc; ++argv;
if (strncmp(*argv, "", strlen("")) == 0) {
if (has_prefix(*argv, "")) {
if (argc < 2) {
free(criteria);
return cmd_results_new(CMD_INVALID, "Missing workspace");

View file

@ -11,7 +11,7 @@ struct cmd_results *bar_cmd_font(int argc, char **argv) {
char *font = join_args(argv, argc);
free(config->current_bar->font);
if (strncmp(font, "pango:", 6) == 0) {
if (has_prefix(font, "pango:")) {
if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) {
config->current_bar->pango_markup = true;
}

View file

@ -367,8 +367,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
}
} else if (strcmp("--exclude-titlebar", argv[0]) == 0) {
exclude_titlebar = true;
} else if (strncmp("--input-device=", argv[0],
strlen("--input-device=")) == 0) {
} else if (has_prefix(argv[0], "--input-device=")) {
free(binding->input);
binding->input = strdup(argv[0] + strlen("--input-device="));
strip_quotes(binding->input);
@ -399,7 +398,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
list_t *split = split_string(argv[0], "+");
for (int i = 0; i < split->length; ++i) {
// Check for group
if (strncmp(split->items[i], "Group", strlen("Group")) == 0) {
if (has_prefix(split->items[i], "Group")) {
if (binding->group != XKB_LAYOUT_INVALID) {
free_sway_binding(binding);
list_free_items_and_destroy(split);

View file

@ -25,16 +25,6 @@ struct cmd_results *cmd_exec_validate(int argc, char **argv) {
return error;
}
static void export_xdga_token(struct launcher_ctx *ctx) {
const char *token = launcher_ctx_get_token_name(ctx);
setenv("XDG_ACTIVATION_TOKEN", token, 1);
}
static void export_startup_id(struct launcher_ctx *ctx) {
const char *token = launcher_ctx_get_token_name(ctx);
setenv("DESKTOP_STARTUP_ID", token, 1);
}
struct cmd_results *cmd_exec_process(int argc, char **argv) {
struct cmd_results *error = NULL;
char *cmd = NULL;
@ -56,67 +46,37 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
sway_log(SWAY_DEBUG, "Executing %s", cmd);
int fd[2];
if (pipe(fd) != 0) {
sway_log(SWAY_ERROR, "Unable to create pipe for fork");
struct launcher_ctx *ctx = launcher_ctx_create_internal();
// Fork process
pid_t child = fork();
if (child == 0) {
setsid();
if (ctx) {
const char *token = launcher_ctx_get_token_name(ctx);
setenv("XDG_ACTIVATION_TOKEN", token, 1);
if (!no_startup_id) {
setenv("DESKTOP_STARTUP_ID", token, 1);
}
}
pid_t pid, child;
struct launcher_ctx *ctx = launcher_ctx_create_internal();
// Fork process
if ((pid = fork()) == 0) {
// Fork child process again
restore_nofile_limit();
setsid();
sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
signal(SIGPIPE, SIG_DFL);
close(fd[0]);
if ((child = fork()) == 0) {
close(fd[1]);
if (ctx) {
export_xdga_token(ctx);
}
if (ctx && !no_startup_id) {
export_startup_id(ctx);
}
execlp("sh", "sh", "-c", cmd, (void*)NULL);
sway_log_errno(SWAY_ERROR, "execlp failed");
_exit(1);
}
ssize_t s = 0;
while ((size_t)s < sizeof(pid_t)) {
s += write(fd[1], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
}
close(fd[1]);
sway_log_errno(SWAY_ERROR, "execve failed");
_exit(0); // Close child process
} else if (pid < 0) {
} else if (child < 0) {
launcher_ctx_destroy(ctx);
free(cmd);
close(fd[0]);
close(fd[1]);
return cmd_results_new(CMD_FAILURE, "fork() failed");
}
free(cmd);
close(fd[1]); // close write
ssize_t s = 0;
while ((size_t)s < sizeof(pid_t)) {
s += read(fd[0], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
}
close(fd[0]);
// cleanup child process
waitpid(pid, NULL, 0);
if (child > 0) {
sway_log(SWAY_DEBUG, "Child process created with pid %d", child);
if (ctx != NULL) {
sway_log(SWAY_DEBUG, "Recording workspace for process %d", child);
ctx->pid = child;
}
} else {
launcher_ctx_destroy(ctx);
return cmd_results_new(CMD_FAILURE, "Second fork() failed");
}
free(cmd);
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -1,8 +1,7 @@
#include <stddef.h>
#include "sway/commands.h"
#include "sway/config.h"
void sway_terminate(int exit_code);
#include "sway/server.h"
struct cmd_results *cmd_exit(int argc, char **argv) {
struct cmd_results *error = NULL;

View file

@ -13,9 +13,9 @@ struct cmd_results *cmd_font(int argc, char **argv) {
char *font = join_args(argv, argc);
free(config->font);
if (strncmp(font, "pango:", 6) == 0) {
if (has_prefix(font, "pango:")) {
config->pango_markup = true;
config->font = strdup(font + 6);
config->font = strdup(font + strlen("pango:"));
free(font);
} else {
config->pango_markup = false;

View file

@ -215,15 +215,13 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
return error;
}
bool config_loading = !config->active || config->reloading;
if (argc == 2) {
return gaps_set_defaults(argc, argv);
}
if (argc == 4 && !config_loading) {
if (argc == 4 && !config->reading) {
return gaps_set_runtime(argc, argv);
}
if (config_loading) {
if (config->reading) {
return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults);
}
return cmd_results_new(CMD_INVALID, "Expected %s or %s",

View file

@ -121,8 +121,7 @@ static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, boo
binding->flags |= BINDING_EXACT;
} else if (strcmp("--no-warn", argv[0]) == 0) {
warn = false;
} else if (strncmp("--input-device=", argv[0],
strlen("--input-device=")) == 0) {
} else if (has_prefix(argv[0], "--input-device=")) {
free(binding->input);
binding->input = strdup(argv[0] + strlen("--input-device="));
} else {

View file

@ -3,12 +3,12 @@
struct cmd_results *cmd_include(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "include", EXPECTED_EQUAL_TO, 1))) {
if ((error = checkarg(argc, "include", EXPECTED_AT_LEAST, 1))) {
return error;
}
char *files = join_args(argv, argc);
// We don't care if the included config(s) fails to load.
load_include_configs(argv[0], config, &config->swaynag_config_errors);
load_include_configs(files, config, &config->swaynag_config_errors);
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -94,7 +94,7 @@ struct cmd_results *cmd_input(int argc, char **argv) {
return res;
}
if (!config->reloading) {
if (!config->reading) {
input_manager_apply_input_config(ic);
}
} else {

View file

@ -15,6 +15,11 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "No input device defined.");
}
#if HAVE_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY
if (strcmp(argv[0], "enabled_sticky") == 0) {
ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY;
} else
#endif
if (parse_boolean(argv[0], true)) {
ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
} else {

View file

@ -86,7 +86,7 @@ static void toggle_select_send_events_for_device(struct input_config *ic,
static void toggle_send_events(int argc, char **argv) {
struct input_config *ic = config->handler_context.input_config;
bool wildcard = strcmp(ic->identifier, "*") == 0;
const char *type = strncmp(ic->identifier, "type:", strlen("type:")) == 0
const char *type = has_prefix(ic->identifier, "type:")
? ic->identifier + strlen("type:") : NULL;
struct sway_input_device *device = NULL;
wl_list_for_each(device, &server.input->devices, link) {
@ -146,8 +146,7 @@ struct cmd_results *input_cmd_events(int argc, char **argv) {
toggle_send_events(argc - 1, argv + 1);
if (strcmp(ic->identifier, "*") == 0 ||
strncmp(ic->identifier, "type:", strlen("type:")) == 0) {
if (strcmp(ic->identifier, "*") == 0 || has_prefix(ic->identifier, "type:")) {
// Update the device input configs and then reset the type/wildcard
// config send events mode so that is does not override the device
// ones. The device ones will be applied when attempting to apply

View file

@ -95,10 +95,18 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
continue;
}
struct wlr_keyboard *keyboard =
wlr_keyboard_from_input_device(dev->wlr_device);
if (keyboard->keymap == NULL && dev->is_virtual) {
// The `sway_keyboard_set_layout` function is by default skipped
// when configuring virtual keyboards.
continue;
}
struct xkb_switch_layout_action *action =
&actions[actions_len++];
action->keyboard = keyboard;
action->keyboard = wlr_keyboard_from_input_device(dev->wlr_device);
if (relative) {
action->layout = get_layout_relative(action->keyboard, relative);
} else {

View file

@ -134,6 +134,19 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
// Operate on parent container, like i3.
if (container) {
container = container->pending.parent;
// If parent has only a singe child operate on its parent and
// flatten once, like i3
if (container && container->pending.children->length == 1) {
// Also check grandparent to avoid restricting layouts
struct sway_container *parent = container->pending.parent;
if (parent && parent->pending.children->length == 1) {
struct sway_container *child = container->pending.children->items[0];
struct sway_container *parent = container->pending.parent;
container_replace(container, child);
container_begin_destroy(container);
container = parent;
}
}
}
// We could be working with a container OR a workspace. These are different

View file

@ -23,7 +23,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
}
bool add = false, toggle = false;
while (argc > 0 && strncmp(*argv, "--", 2) == 0) {
while (argc > 0 && has_prefix(*argv, "--")) {
if (strcmp(*argv, "--add") == 0) {
add = true;
} else if (strcmp(*argv, "--replace") == 0) {

View file

@ -222,6 +222,7 @@ static void container_move_to_workspace(struct sway_container *container,
container_detach(container);
if (workspace_is_empty(workspace) && container->pending.children) {
workspace_unwrap_children(workspace, container);
container_reap_empty(container);
} else {
container->pending.width = container->pending.height = 0;
container->width_fraction = container->height_fraction = 0;
@ -240,7 +241,6 @@ static void container_move_to_workspace(struct sway_container *container,
static void container_move_to_container(struct sway_container *container,
struct sway_container *destination) {
if (container == destination
|| container_has_ancestor(container, destination)
|| container_has_ancestor(destination, container)) {
return;
}
@ -510,6 +510,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
}
}
ws = workspace_create(NULL, ws_name);
arrange_workspace(ws);
}
free(ws_name);
struct sway_container *dst = seat_get_focus_inactive_tiling(seat, ws);

View file

@ -2,7 +2,8 @@
#include <stdlib.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/tree/view.h"
#include "sway/tree/container.h"
#include "sway/output.h"
#include "log.h"
struct cmd_results *cmd_opacity(int argc, char **argv) {
@ -37,6 +38,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
}
con->alpha = val;
output_configure_scene(NULL, &con->scene_tree->node, 1);
container_update(con);
return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -8,12 +8,14 @@
// must be in order for the bsearch
static const struct cmd_handler output_handlers[] = {
{ "adaptive_sync", output_cmd_adaptive_sync },
{ "allow_tearing", output_cmd_allow_tearing },
{ "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 },
{ "hdr", output_cmd_hdr },
{ "max_render_time", output_cmd_max_render_time },
{ "mode", output_cmd_mode },
{ "modeline", output_cmd_modeline },
@ -106,18 +108,17 @@ struct cmd_results *cmd_output(int argc, char **argv) {
store_output_config(output);
// If reloading, the output configs will be applied after reading the
// entire config and before the deferred commands so that an auto generated
// workspace name is not given to re-enabled outputs.
if (!config->reloading && !config->validating) {
apply_all_output_configs();
if (background) {
if (!spawn_swaybg()) {
if (config->reading) {
// When reading the config file, we wait till the end to do a single
// modeset and swaybg spawn.
return cmd_results_new(CMD_SUCCESS, NULL);
}
request_modeset();
if (background && !spawn_swaybg()) {
return cmd_results_new(CMD_FAILURE,
"Failed to apply background configuration");
}
}
}
return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -1,5 +1,7 @@
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
#include "util.h"
struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
@ -10,12 +12,26 @@ struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Missing adaptive_sync argument");
}
if (parse_boolean(argv[0], true)) {
config->handler_context.output_config->adaptive_sync = 1;
} else {
config->handler_context.output_config->adaptive_sync = 0;
bool current_value = true;
if (strcasecmp(argv[0], "toggle") == 0) {
const char *oc_name = config->handler_context.output_config->name;
if (strcmp(oc_name, "*") == 0) {
return cmd_results_new(CMD_INVALID,
"Cannot apply toggle to all outputs");
}
struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
if (!sway_output || !sway_output->wlr_output) {
return cmd_results_new(CMD_FAILURE,
"Cannot apply toggle to unknown output %s", oc_name);
}
current_value =
sway_output->wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
}
config->handler_context.output_config->adaptive_sync = parse_boolean(argv[0], current_value);
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
return NULL;

View file

@ -0,0 +1,23 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "util.h"
struct cmd_results *output_cmd_allow_tearing(int argc, char **argv) {
if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config");
}
if (argc == 0) {
return cmd_results_new(CMD_INVALID, "Missing allow_tearing argument");
}
if (parse_boolean(argv[0],
(config->handler_context.output_config->allow_tearing == 1))) {
config->handler_context.output_config->allow_tearing = 1;
} else {
config->handler_context.output_config->allow_tearing = 0;
}
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
return NULL;
}

View file

@ -3,10 +3,8 @@
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/swaynag.h"
#include "log.h"
#include "stringop.h"
@ -42,14 +40,14 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
}
struct output_config *output = config->handler_context.output_config;
char *src = NULL;
if (strcasecmp(argv[1], "solid_color") == 0) {
if (!validate_color(argv[0])) {
return cmd_results_new(CMD_INVALID,
"Colors should be of the form #RRGGBB");
}
output->background = strdup(argv[0]);
output->background_option = strdup("solid_color");
if (!(output->background = strdup(argv[0]))) goto cleanup;
if (!(output->background_option = strdup("solid_color"))) goto cleanup;
output->background_fallback = NULL;
argc -= 2; argv += 2;
} else {
@ -77,37 +75,25 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Missing background file");
}
char *src = join_args(argv, j);
if (!(src = join_args(argv, j))) goto cleanup;
if (!expand_path(&src)) {
struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID,
"Invalid syntax (%s)", src);
free(src);
return cmd_res;
}
if (!src) {
sway_log(SWAY_ERROR, "Failed to allocate expanded path");
return cmd_results_new(CMD_FAILURE, "Unable to allocate resource");
}
if (config->reading && *src != '/') {
// src file is inside configuration dir
char *conf = strdup(config->current_config_path);
if (!conf) {
sway_log(SWAY_ERROR, "Failed to duplicate string");
free(src);
return cmd_results_new(CMD_FAILURE,
"Unable to allocate resources");
}
if (!conf) goto cleanup;
char *conf_path = dirname(conf);
char *real_src = malloc(strlen(conf_path) + strlen(src) + 2);
if (!real_src) {
free(src);
free(conf);
sway_log(SWAY_ERROR, "Unable to allocate memory");
return cmd_results_new(CMD_FAILURE,
"Unable to allocate resources");
goto cleanup;
}
snprintf(real_src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, src);
@ -117,40 +103,48 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
}
bool can_access = access(src, F_OK) != -1;
argc -= j + 1; argv += j + 1;
free(output->background_option);
free(output->background_fallback);
free(output->background);
output->background = output->background_option = output->background_fallback = NULL;
char *fallback = NULL;
if (argc && *argv[0] == '#') {
if (validate_color(argv[0])) {
if (!(fallback = strdup(argv[0]))) goto cleanup;
output->background_fallback = fallback;
} else {
sway_log(SWAY_ERROR, "fallback '%s' should be of the form #RRGGBB", argv[0]);
config_add_swaynag_warning("fallback '%s' should be of the form #RRGGBB\n", argv[0]);
}
argc--; argv++;
}
if (!can_access) {
sway_log_errno(SWAY_ERROR, "Unable to access background file '%s'",
src);
config_add_swaynag_warning("Unable to access background file '%s'",
src);
struct cmd_results *result = cmd_results_new(CMD_FAILURE,
"unable to access background file '%s'", src);
if (!fallback) {
sway_log(SWAY_ERROR, "Unable to access background file '%s' "
"and no valid fallback provided", src);
struct cmd_results *res = cmd_results_new(CMD_FAILURE, "Unable to access "
"background file '%s' and no valid fallback provided", src);
free(src);
return result;
return res;
}
sway_log(SWAY_DEBUG, "Cannot access file '%s', using fallback '%s'", src, fallback);
output->background = fallback;
if (!(output->background_option = strdup("solid_color"))) goto cleanup;
output->background_fallback = NULL;
} else {
output->background = src;
output->background_option = strdup(mode);
}
argc -= j + 1; argv += j + 1;
output->background_fallback = NULL;
if (argc && *argv[0] == '#') {
if (!validate_color(argv[0])) {
return cmd_results_new(CMD_INVALID,
"fallback color should be of the form #RRGGBB");
}
output->background_fallback = strdup(argv[0]);
argc--; argv++;
if (!can_access) {
output->background = output->background_fallback;
output->background_option = strdup("solid_color");
output->background_fallback = NULL;
if (!(output->background_option = strdup(mode))) goto cleanup;
}
}
}
config->handler_context.leftovers.argc = argc;
config->handler_context.leftovers.argv = argv;
return NULL;
cleanup:
free(src);
sway_log(SWAY_ERROR, "Failed to allocate resources");
return cmd_results_new(CMD_FAILURE, "Unable to allocate resources");
}

View file

@ -5,6 +5,7 @@
#include <wlr/render/color.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "stringop.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,
@ -70,12 +71,23 @@ struct cmd_results *output_cmd_color_profile(int argc, char **argv) {
return cmd_results_new(CMD_INVALID,
"Invalid color profile specification: icc type requires a file");
}
char *icc_path = strdup(argv[1]);
if (!expand_path(&icc_path)) {
struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID,
"Invalid color profile specification: invalid file path");
free(icc_path);
return cmd_res;
}
void *data = NULL;
size_t size = 0;
if (!read_file_into_buf(argv[1], &data, &size)) {
if (!read_file_into_buf(icc_path, &data, &size)) {
free(icc_path);
return cmd_results_new(CMD_FAILURE,
"Failed to load color profile: could not read ICC file");
}
free(icc_path);
struct wlr_color_transform *tmp =
wlr_color_transform_init_linear_to_icc(data, size);

View file

@ -0,0 +1,37 @@
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
#include "util.h"
struct cmd_results *output_cmd_hdr(int argc, char **argv) {
if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config");
}
if (argc == 0) {
return cmd_results_new(CMD_INVALID, "Missing hdr argument");
}
bool current = false;
if (strcasecmp(argv[0], "toggle") == 0) {
const char *oc_name = config->handler_context.output_config->name;
if (strcmp(oc_name, "*") == 0) {
return cmd_results_new(CMD_INVALID,
"Cannot apply toggle to all outputs");
}
struct sway_output *output = all_output_by_name_or_id(oc_name);
if (!output) {
return cmd_results_new(CMD_FAILURE,
"Cannot apply toggle to unknown output %s", oc_name);
}
current = output->hdr;
}
config->handler_context.output_config->hdr = parse_boolean(argv[0], current);
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
return NULL;
}

View file

@ -11,7 +11,10 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Missing bit depth argument.");
}
if (strcmp(*argv, "8") == 0) {
if (strcmp(*argv, "6") == 0) {
config->handler_context.output_config->render_bit_depth =
RENDER_BIT_DEPTH_6;
} else if (strcmp(*argv, "8") == 0) {
config->handler_context.output_config->render_bit_depth =
RENDER_BIT_DEPTH_8;
} else if (strcmp(*argv, "10") == 0) {
@ -19,7 +22,7 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
RENDER_BIT_DEPTH_10;
} else {
return cmd_results_new(CMD_INVALID,
"Invalid bit depth. Must be a value in (8|10).");
"Invalid bit depth. Must be a value in (6|8|10).");
}
config->handler_context.leftovers.argc = argc - 1;

View file

@ -80,61 +80,46 @@ void container_resize_tiled(struct sway_container *con,
}
// For HORIZONTAL or VERTICAL, we are growing in two directions so select
// both adjacent siblings. For RIGHT or DOWN, just select the next sibling.
// For LEFT or UP, convert it to a RIGHT or DOWN resize and reassign con to
// the previous sibling.
struct sway_container *prev = NULL;
struct sway_container *next = NULL;
// all adjacent siblings. For RIGHT or DOWN or LEFT or UP select just the
// previous or next sibling.
list_t *resize = create_list();
list_t *siblings = container_get_siblings(con);
int index = container_sibling_index(con);
if (axis == AXIS_HORIZONTAL || axis == AXIS_VERTICAL) {
if (index == 0) {
next = siblings->items[1];
} else if (index == siblings->length - 1) {
// Convert edge to top/left
next = con;
con = siblings->items[index - 1];
amount = -amount;
} else {
prev = siblings->items[index - 1];
next = siblings->items[index + 1];
}
list_cat(resize, siblings);
} else if (axis == WLR_EDGE_TOP || axis == WLR_EDGE_LEFT) {
if (!sway_assert(index > 0, "Didn't expect first child")) {
return;
goto cleanup;
}
next = con;
con = siblings->items[index - 1];
amount = -amount;
list_add(resize, siblings->items[index - 1]);
list_add(resize, con);
} else {
if (!sway_assert(index < siblings->length - 1,
"Didn't expect last child")) {
return;
goto cleanup;
}
next = siblings->items[index + 1];
list_add(resize, con);
list_add(resize, siblings->items[index + 1]);
}
// Apply new dimensions
int sibling_amount = prev ? ceil((double)amount / 2.0) : amount;
int sibling_amount = ceil((double)amount / (double)(resize->length - 1));
if (is_horizontal(axis)) {
if (con->pending.width + amount < MIN_SANE_W) {
return;
for (int i = 0; i < resize->length; i++) {
struct sway_container *sibling = resize->items[i];
double change = sibling == con ? amount : -sibling_amount;
if (sibling->pending.width + change < MIN_SANE_W) {
goto cleanup;
}
if (next->pending.width - sibling_amount < MIN_SANE_W) {
return;
}
if (prev && prev->pending.width - sibling_amount < MIN_SANE_W) {
return;
}
if (con->child_total_width <= 0) {
return;
goto cleanup;
}
// We're going to resize so snap all the width fractions to full pixels
// to avoid rounding issues
list_t *siblings = container_get_siblings(con);
for (int i = 0; i < siblings->length; ++i) {
struct sway_container *con = siblings->items[i];
con->width_fraction = con->pending.width / con->child_total_width;
@ -142,30 +127,27 @@ void container_resize_tiled(struct sway_container *con,
double amount_fraction = (double)amount / con->child_total_width;
double sibling_amount_fraction =
prev ? amount_fraction / 2.0 : amount_fraction;
amount_fraction / (double)(resize->length - 1);
con->width_fraction += amount_fraction;
next->width_fraction -= sibling_amount_fraction;
if (prev) {
prev->width_fraction -= sibling_amount_fraction;
for (int i = 0; i < resize->length; i++) {
struct sway_container *sibling = resize->items[i];
sibling->width_fraction +=
sibling == con ? amount_fraction : -sibling_amount_fraction;
}
} else {
if (con->pending.height + amount < MIN_SANE_H) {
return;
for (int i = 0; i < resize->length; i++) {
struct sway_container *sibling = resize->items[i];
double change = sibling == con ? amount : -sibling_amount;
if (sibling->pending.height + change < MIN_SANE_H) {
goto cleanup;
}
if (next->pending.height - sibling_amount < MIN_SANE_H) {
return;
}
if (prev && prev->pending.height - sibling_amount < MIN_SANE_H) {
return;
}
if (con->child_total_height <= 0) {
return;
goto cleanup;
}
// We're going to resize so snap all the height fractions to full pixels
// to avoid rounding issues
list_t *siblings = container_get_siblings(con);
for (int i = 0; i < siblings->length; ++i) {
struct sway_container *con = siblings->items[i];
con->height_fraction = con->pending.height / con->child_total_height;
@ -173,12 +155,12 @@ void container_resize_tiled(struct sway_container *con,
double amount_fraction = (double)amount / con->child_total_height;
double sibling_amount_fraction =
prev ? amount_fraction / 2.0 : amount_fraction;
amount_fraction / (double)(resize->length - 1);
con->height_fraction += amount_fraction;
next->height_fraction -= sibling_amount_fraction;
if (prev) {
prev->height_fraction -= sibling_amount_fraction;
for (int i = 0; i < resize->length; i++) {
struct sway_container *sibling = resize->items[i];
sibling->height_fraction +=
sibling == con ? amount_fraction : -sibling_amount_fraction;
}
}
@ -187,6 +169,9 @@ void container_resize_tiled(struct sway_container *con,
} else {
arrange_workspace(con->pending.workspace);
}
cleanup:
list_free(resize);
}
/**
@ -457,7 +442,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
if (argc > num_consumed_args) {
return cmd_results_new(CMD_INVALID, "%s", usage);
}
if (width.unit == MOVEMENT_UNIT_INVALID) {
if (height.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, "%s", usage);
}
}

View file

@ -118,10 +118,10 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) {
// If using criteria, this command is executed for every container which
// matches the criteria. If this container isn't in the scratchpad,
// we'll just silently return a success. The same is true if the
// we'll return an error. The same is true if the
// overridden node is not a container.
if (!con || !con->scratchpad) {
return cmd_results_new(CMD_SUCCESS, NULL);
return cmd_results_new(CMD_INVALID, "Container is not in scratchpad.");
}
scratchpad_toggle_container(con);
} else {

View file

@ -1,3 +1,4 @@
#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
@ -11,16 +12,19 @@ struct cmd_results *cmd_title_format(int argc, char **argv) {
return error;
}
struct sway_container *container = config->handler_context.container;
if (!container || !container->view) {
if (!container) {
return cmd_results_new(CMD_INVALID,
"Only views can have a title_format");
"Only valid containers can have a title_format");
}
struct sway_view *view = container->view;
char *format = join_args(argv, argc);
if (view->title_format) {
free(view->title_format);
if (container->title_format) {
free(container->title_format);
}
container->title_format = format;
if (container->view) {
view_update_title(container->view, true);
} else {
container_update_representation(container);
}
view->title_format = format;
view_update_title(view, true);
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -516,7 +516,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
// Only really necessary if not explicitly `font` is set in the config.
config_update_font_height();
if (is_active && !validating) {
if (!validating) {
input_manager_verify_fallback_seat();
for (int i = 0; i < config->input_configs->length; i++) {
@ -533,14 +533,16 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
}
sway_switch_retrigger_bindings_for_all();
apply_all_output_configs();
spawn_swaybg();
config->reloading = false;
if (is_active) {
request_modeset();
if (config->swaynag_config_errors.client != NULL) {
swaynag_show(&config->swaynag_config_errors);
}
}
}
if (old_config) {
destroy_removed_seats(old_config, config);
@ -550,28 +552,12 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
return success;
}
static bool load_include_config(const char *path, const char *parent_dir,
struct sway_config *config, struct swaynag_instance *swaynag) {
static bool load_include_config(const char *path, struct sway_config *config,
struct swaynag_instance *swaynag) {
// save parent config
const char *parent_config = config->current_config_path;
char *full_path;
int len = strlen(path);
if (len >= 1 && path[0] != '/') {
len = len + strlen(parent_dir) + 2;
full_path = malloc(len * sizeof(char));
if (!full_path) {
sway_log(SWAY_ERROR,
"Unable to allocate full path to included config");
return false;
}
snprintf(full_path, len, "%s/%s", parent_dir, path);
} else {
full_path = strdup(path);
}
char *real_path = realpath(full_path, NULL);
free(full_path);
char *real_path = realpath(path, NULL);
if (real_path == NULL) {
sway_log(SWAY_DEBUG, "%s not found.", path);
@ -623,7 +609,7 @@ void load_include_configs(const char *path, struct sway_config *config,
char **w = p.we_wordv;
size_t i;
for (i = 0; i < p.we_wordc; ++i) {
load_include_config(w[i], parent_dir, config, swaynag);
load_include_config(w[i], config, swaynag);
}
wordfree(&p);
}
@ -923,8 +909,8 @@ char *do_var_replacement(char *str) {
// Find matching variable
for (i = 0; i < config->symbols->length; ++i) {
struct sway_variable *var = config->symbols->items[i];
if (has_prefix(find, var->name)) {
int vnlen = strlen(var->name);
if (strncmp(find, var->name, vnlen) == 0) {
int vvlen = strlen(var->value);
char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
if (!newstr) {

View file

@ -212,19 +212,6 @@ static void invoke_swaybar(struct bar_config *bar) {
if (pid < 0) {
sway_log(SWAY_ERROR, "Failed to create fork for swaybar");
return;
} else if (pid == 0) {
// Remove the SIGUSR1 handler that wlroots adds for xwayland
sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
signal(SIGPIPE, SIG_DFL);
restore_nofile_limit();
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
_exit(EXIT_FAILURE);
} else if (pid == 0) {
if (!sway_set_cloexec(sockets[1], false)) {
_exit(EXIT_FAILURE);
@ -242,19 +229,12 @@ static void invoke_swaybar(struct bar_config *bar) {
execvp(cmd[0], cmd);
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
if (close(sockets[1]) != 0) {
sway_log_errno(SWAY_ERROR, "close failed");
return;
}
if (waitpid(pid, NULL, 0) < 0) {
sway_log_errno(SWAY_ERROR, "waitpid failed");
return;
}
sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id);
}

View file

@ -300,7 +300,7 @@ struct input_config *store_input_config(struct input_config *ic,
return NULL;
}
bool type = strncmp(ic->identifier, "type:", strlen("type:")) == 0;
bool type = has_prefix(ic->identifier, "type:");
if (type && error && !validate_type_on_existing(ic, error)) {
return NULL;
}

View file

@ -6,14 +6,20 @@
#include <sys/wait.h>
#include <unistd.h>
#include <wlr/config.h>
#include <wlr/render/allocator.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_swapchain_manager.h>
#include <xf86drm.h>
#include "sway/config.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/layers.h"
#include "sway/lock.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/root.h"
#include "log.h"
#include "util.h"
@ -22,13 +28,6 @@
#include <wlr/backend/drm.h>
#endif
int output_name_cmp(const void *item, const void *data) {
const struct output_config *output = item;
const char *name = data;
return strcmp(output->name, name);
}
void output_get_identifier(char *identifier, size_t len,
struct sway_output *output) {
struct wlr_output *wlr_output = output->wlr_output;
@ -68,7 +67,7 @@ struct output_config *new_output_config(const char *name) {
oc->refresh_rate = -1;
oc->custom_mode = -1;
oc->drm_mode.type = -1;
oc->x = oc->y = -1;
oc->x = oc->y = INT_MAX;
oc->scale = -1;
oc->scale_filter = SCALE_FILTER_DEFAULT;
oc->transform = -1;
@ -79,6 +78,8 @@ struct output_config *new_output_config(const char *name) {
oc->set_color_transform = false;
oc->color_transform = NULL;
oc->power = -1;
oc->allow_tearing = -1;
oc->hdr = -1;
return oc;
}
@ -93,11 +94,11 @@ static void supersede_output_config(struct output_config *dst, struct output_con
if (src->height != -1) {
dst->height = -1;
}
if (src->x != -1) {
dst->x = -1;
if (src->x != INT_MAX) {
dst->x = INT_MAX;
}
if (src->y != -1) {
dst->y = -1;
if (src->y != INT_MAX) {
dst->y = INT_MAX;
}
if (src->scale != -1) {
dst->scale = -1;
@ -129,6 +130,13 @@ static void supersede_output_config(struct output_config *dst, struct output_con
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
}
if (src->set_color_transform) {
if (dst->color_transform) {
wlr_color_transform_unref(dst->color_transform);
dst->color_transform = NULL;
}
dst->set_color_transform = false;
}
if (src->background) {
free(dst->background);
dst->background = NULL;
@ -144,6 +152,12 @@ static void supersede_output_config(struct output_config *dst, struct output_con
if (src->power != -1) {
dst->power = -1;
}
if (src->allow_tearing != -1) {
dst->allow_tearing = -1;
}
if (src->hdr != -1) {
dst->hdr = -1;
}
}
// merge_output_config sets all fields in dst that were set in src
@ -157,10 +171,10 @@ static void merge_output_config(struct output_config *dst, struct output_config
if (src->height != -1) {
dst->height = src->height;
}
if (src->x != -1) {
if (src->x != INT_MAX) {
dst->x = src->x;
}
if (src->y != -1) {
if (src->y != INT_MAX) {
dst->y = src->y;
}
if (src->scale != -1) {
@ -216,6 +230,12 @@ static void merge_output_config(struct output_config *dst, struct output_config
if (src->power != -1) {
dst->power = src->power;
}
if (src->allow_tearing != -1) {
dst->allow_tearing = src->allow_tearing;
}
if (src->hdr != -1) {
dst->hdr = src->hdr;
}
}
void store_output_config(struct output_config *oc) {
@ -258,11 +278,11 @@ void store_output_config(struct output_config *oc) {
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
"(max render time: %d)",
"(max render time: %d) (allow tearing: %d) (hdr: %d)",
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
oc->transform, oc->background, oc->background_option, oc->power,
oc->max_render_time);
oc->max_render_time, oc->allow_tearing, oc->hdr);
// 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.
@ -283,7 +303,6 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
mhz = mhz <= 0 ? INT_MAX : mhz;
if (wl_list_empty(&output->modes) || custom) {
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
wlr_output_state_set_custom_mode(pending, width, height,
refresh_rate > 0 ? mhz : 0);
return;
@ -303,10 +322,7 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
}
}
}
if (best) {
sway_log(SWAY_INFO, "Assigning configured mode (%dx%d@%.3fHz) to %s",
best->width, best->height, best->refresh / 1000.f, output->name);
} else {
if (!best) {
best = wlr_output_preferred_mode(output);
sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, "
"applying preferred mode (%dx%d@%.3fHz)",
@ -323,7 +339,6 @@ static void set_modeline(struct wlr_output *output,
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
return;
}
sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
if (mode) {
wlr_output_state_set_mode(pending, mode);
@ -333,6 +348,45 @@ static void set_modeline(struct wlr_output *output,
#endif
}
bool output_supports_hdr(struct wlr_output *output, const char **unsupported_reason_ptr) {
const char *unsupported_reason = NULL;
if (!(output->supported_primaries & WLR_COLOR_NAMED_PRIMARIES_BT2020)) {
unsupported_reason = "BT2020 primaries not supported by output";
} else if (!(output->supported_transfer_functions & WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ)) {
unsupported_reason = "PQ transfer function not supported by output";
} else if (!server.renderer->features.output_color_transform) {
unsupported_reason = "renderer doesn't support output color transforms";
}
if (unsupported_reason_ptr != NULL) {
*unsupported_reason_ptr = unsupported_reason;
}
return unsupported_reason == NULL;
}
static void set_hdr(struct wlr_output *output, struct wlr_output_state *pending, bool enabled) {
const char *unsupported_reason = NULL;
if (enabled && !output_supports_hdr(output, &unsupported_reason)) {
sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: %s",
output->name, unsupported_reason);
enabled = false;
}
if (!enabled) {
if (output->supported_primaries != 0 || output->supported_transfer_functions != 0) {
sway_log(SWAY_DEBUG, "Disabling HDR on output %s", output->name);
wlr_output_state_set_image_description(pending, NULL);
}
return;
}
sway_log(SWAY_DEBUG, "Enabling HDR on output %s", output->name);
const struct wlr_output_image_description image_desc = {
.primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020,
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ,
};
wlr_output_state_set_image_description(pending, &image_desc);
}
/* Some manufacturers hardcode the aspect-ratio of the output in the physical
* size field. */
static bool phys_size_is_aspect_ratio(struct wlr_output *output) {
@ -389,7 +443,6 @@ static int compute_default_scale(struct wlr_output *output,
double dpi_x = (double) width / (output->phys_width / MM_PER_INCH);
double dpi_y = (double) height / (output->phys_height / MM_PER_INCH);
sway_log(SWAY_DEBUG, "Output DPI: %fx%f", dpi_x, dpi_y);
if (dpi_x <= HIDPI_DPI_LIMIT || dpi_y <= HIDPI_DPI_LIMIT) {
return 1;
}
@ -397,9 +450,25 @@ static int compute_default_scale(struct wlr_output *output,
return 2;
}
static bool render_format_is_10bit(uint32_t render_format) {
return render_format == DRM_FORMAT_XRGB2101010 ||
render_format == DRM_FORMAT_XBGR2101010;
static enum render_bit_depth bit_depth_from_format(uint32_t render_format) {
if (render_format == DRM_FORMAT_XRGB2101010 || render_format == DRM_FORMAT_XBGR2101010) {
return RENDER_BIT_DEPTH_10;
} else if (render_format == DRM_FORMAT_XRGB8888 || render_format == DRM_FORMAT_ARGB8888) {
return RENDER_BIT_DEPTH_8;
} else if (render_format == DRM_FORMAT_RGB565) {
return RENDER_BIT_DEPTH_6;
}
return RENDER_BIT_DEPTH_DEFAULT;
}
static enum render_bit_depth get_config_render_bit_depth(const struct output_config *oc) {
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
return oc->render_bit_depth;
}
if (oc && oc->hdr == 1) {
return RENDER_BIT_DEPTH_10;
}
return RENDER_BIT_DEPTH_8;
}
static bool render_format_is_bgr(uint32_t fmt) {
@ -419,94 +488,82 @@ static void queue_output_config(struct output_config *oc,
struct wlr_output *wlr_output = output->wlr_output;
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;
}
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
wlr_output_state_set_enabled(pending, true);
if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
sway_log(SWAY_DEBUG, "Set %s modeline",
wlr_output->name);
set_modeline(wlr_output, pending, &oc->drm_mode);
} else if (oc && oc->width > 0 && oc->height > 0) {
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
wlr_output->name, oc->width, oc->height, oc->refresh_rate);
set_mode(wlr_output, pending, oc->width, oc->height,
oc->refresh_rate, oc->custom_mode == 1);
} else if (!wl_list_empty(&wlr_output->modes)) {
sway_log(SWAY_DEBUG, "Set preferred mode");
struct wlr_output_mode *preferred_mode =
wlr_output_preferred_mode(wlr_output);
wlr_output_state_set_mode(pending, preferred_mode);
}
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
sway_wl_output_subpixel_to_string(oc->subpixel));
if (oc && oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
wlr_output_state_set_subpixel(pending, oc->subpixel);
} else {
wlr_output_state_set_subpixel(pending, output->detected_subpixel);
}
enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
if (oc && oc->transform >= 0) {
tr = oc->transform;
wlr_output_state_set_transform(pending, oc->transform);
#if WLR_HAS_DRM_BACKEND
} else if (wlr_output_is_drm(wlr_output)) {
tr = wlr_drm_connector_get_panel_orientation(wlr_output);
sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr);
wlr_output_state_set_transform(pending,
wlr_drm_connector_get_panel_orientation(wlr_output));
#endif
}
if (wlr_output->transform != tr) {
sway_log(SWAY_DEBUG, "Set %s transform to %d", wlr_output->name, tr);
wlr_output_state_set_transform(pending, tr);
} else {
wlr_output_state_set_transform(pending, WL_OUTPUT_TRANSFORM_NORMAL);
}
// Apply the scale last before the commit, because the scale auto-detection
// reads the pending output size
float scale;
// Apply the scale after sorting out the mode, because the scale
// auto-detection reads the pending output size
if (oc && oc->scale > 0) {
scale = oc->scale;
// The factional-scale-v1 protocol uses increments of 120ths to send
// the scale factor to the client. Adjust the scale so that we use the
// same value as the clients'.
float adjusted_scale = round(scale * 120) / 120;
if (scale != adjusted_scale) {
sway_log(SWAY_INFO, "Adjusting output scale from %f to %f",
scale, adjusted_scale);
scale = adjusted_scale;
}
wlr_output_state_set_scale(pending, round(oc->scale * 120) / 120);
} else {
scale = compute_default_scale(wlr_output, pending);
sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale);
}
if (scale != wlr_output->scale) {
sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale);
wlr_output_state_set_scale(pending, scale);
wlr_output_state_set_scale(pending,
compute_default_scale(wlr_output, pending));
}
if (wlr_output->adaptive_sync_supported) {
if (oc && oc->adaptive_sync != -1) {
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);
} else {
wlr_output_state_set_adaptive_sync_enabled(pending, false);
}
}
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 &&
render_format_is_10bit(output->wlr_output->render_format)) {
enum render_bit_depth render_bit_depth = get_config_render_bit_depth(oc);
if (render_bit_depth == RENDER_BIT_DEPTH_10 &&
bit_depth_from_format(output->wlr_output->render_format) == render_bit_depth) {
// 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) {
} else if (render_bit_depth == RENDER_BIT_DEPTH_10) {
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010);
} else if (render_bit_depth == RENDER_BIT_DEPTH_6) {
wlr_output_state_set_render_format(pending, DRM_FORMAT_RGB565);
} else {
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
}
bool hdr = oc && oc->hdr == 1;
if (hdr && oc->color_transform != NULL) {
sway_log(SWAY_ERROR, "Cannot HDR on output %s: output has an ICC profile set", wlr_output->name);
hdr = false;
}
set_hdr(wlr_output, pending, hdr);
}
static bool finalize_output_config(struct output_config *oc, struct sway_output *output) {
static bool finalize_output_config(struct output_config *oc, struct sway_output *output,
const struct wlr_output_state *applied) {
if (output == root->fallback_output) {
return false;
}
@ -521,9 +578,9 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
return true;
}
if (oc) {
enum scale_filter_mode scale_filter_old = output->scale_filter;
switch (oc->scale_filter) {
enum scale_filter_mode scale_filter_new = oc ? oc->scale_filter : SCALE_FILTER_DEFAULT;
switch (scale_filter_new) {
case SCALE_FILTER_DEFAULT:
case SCALE_FILTER_SMART:
output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ?
@ -531,7 +588,7 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
break;
case SCALE_FILTER_LINEAR:
case SCALE_FILTER_NEAREST:
output->scale_filter = oc->scale_filter;
output->scale_filter = scale_filter_new;
break;
}
if (scale_filter_old != output->scale_filter) {
@ -539,109 +596,86 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
sway_output_scale_filter_to_string(output->scale_filter));
wlr_damage_ring_add_whole(&output->scene_output->damage_ring);
}
}
// Find position for it
if (oc && (oc->x != -1 || oc->y != -1)) {
if (oc && oc->x != INT_MAX && oc->y != INT_MAX) {
sway_log(SWAY_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
wlr_output_layout_add(root->output_layout, wlr_output, oc->x, oc->y);
} else {
wlr_output_layout_add_auto(root->output_layout, wlr_output);
}
// Update output->{lx, ly, width, height}
struct wlr_box output_box;
wlr_output_layout_get_box(root->output_layout, wlr_output, &output_box);
output->lx = output_box.x;
output->ly = output_box.y;
output->width = output_box.width;
output->height = output_box.height;
if (!output->enabled) {
output_enable(output);
}
if (oc && oc->max_render_time >= 0) {
sway_log(SWAY_DEBUG, "Set %s max render time to %d",
oc->name, oc->max_render_time);
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;
} else {
wlr_color_transform_unref(output->color_transform);
output->color_transform = NULL;
}
output->max_render_time = oc && oc->max_render_time > 0 ? oc->max_render_time : 0;
output->allow_tearing = oc && oc->allow_tearing > 0;
output->hdr = applied->image_description != NULL;
return true;
}
static void default_output_config(struct output_config *oc,
struct wlr_output *wlr_output) {
oc->enabled = 1;
oc->power = 1;
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
if (mode != NULL) {
oc->width = mode->width;
oc->height = mode->height;
oc->refresh_rate = mode->refresh / 1000.f;
}
oc->x = oc->y = -1;
oc->scale = 0; // auto
oc->scale_filter = SCALE_FILTER_DEFAULT;
struct sway_output *output = wlr_output->data;
oc->subpixel = output->detected_subpixel;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
oc->max_render_time = 0;
static void output_update_position(struct sway_output *output) {
struct wlr_box output_box;
wlr_output_layout_get_box(root->output_layout, output->wlr_output, &output_box);
output->lx = output_box.x;
output->ly = output_box.y;
output->width = output_box.width;
output->height = output_box.height;
}
// 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) {
// find_output_config_from_list returns a merged output_config containing all
// stored configuration that applies to the specified output.
static struct output_config *find_output_config_from_list(
struct output_config **configs, size_t configs_len,
struct sway_output *sway_output) {
const char *name = sway_output->wlr_output->name;
struct output_config *oc = NULL;
struct output_config *result = new_output_config(name);
if (config->reloading) {
default_output_config(result, sway_output->wlr_output);
if (result == NULL) {
return NULL;
}
char id[128];
output_get_identifier(id, sizeof(id), sway_output);
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];
// We take a new config and merge on top, in order, the wildcard config,
// output config by name, and output config by identifier to form the final
// config. If there are multiple matches, they are merged in order.
struct output_config *oc = NULL;
const char *names[] = {"*", name, id, NULL};
for (const char **name = &names[0]; *name; name++) {
for (size_t idx = 0; idx < configs_len; idx++) {
oc = configs[idx];
if (strcmp(oc->name, *name) == 0) {
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;
}
return result;
}
static bool config_has_auto_mode(struct output_config *oc) {
struct output_config *find_output_config(struct sway_output *sway_output) {
return find_output_config_from_list(
(struct output_config **)config->output_configs->items,
config->output_configs->length, sway_output);
}
static bool config_has_manual_mode(struct output_config *oc) {
if (!oc) {
return true;
return false;
}
if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) {
return true;
@ -651,6 +685,14 @@ static bool config_has_auto_mode(struct output_config *oc) {
return false;
}
/**
* An output config pre-matched to an output
*/
struct matched_output_config {
struct sway_output *output;
struct output_config *config;
};
struct search_context {
struct wlr_output_swapchain_manager *swapchain_mgr;
struct wlr_backend_output_state *states;
@ -665,7 +707,9 @@ static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_s
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);
char *format_name = drmGetFormatName(state->render_format);
sway_log(SWAY_DEBUG, " render_format: %s", format_name);
free(format_name);
}
if (state->committed & WLR_OUTPUT_STATE_MODE) {
if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) {
@ -681,6 +725,13 @@ static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_s
sway_log(SWAY_DEBUG, " adaptive_sync: %s",
state->adaptive_sync_enabled ? "enabled": "disabled");
}
if (state->committed & WLR_OUTPUT_STATE_SCALE) {
sway_log(SWAY_DEBUG, " scale: %f", state->scale);
}
if (state->committed & WLR_OUTPUT_STATE_SUBPIXEL) {
sway_log(SWAY_DEBUG, " subpixel: %s",
sway_wl_output_subpixel_to_string(state->subpixel));
}
}
static bool search_valid_config(struct search_context *ctx, size_t output_idx);
@ -742,7 +793,8 @@ static bool search_mode(struct search_context *ctx, size_t 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)) {
// We only search for mode if one is not explicitly specified in the config
if (config_has_manual_mode(cfg->config)) {
return search_adaptive_sync(ctx, output_idx);
}
@ -783,6 +835,8 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx)
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_RGB565,
DRM_FORMAT_INVALID,
};
if (render_format_is_bgr(wlr_output->render_format)) {
@ -792,13 +846,15 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx)
}
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;
wlr_output_get_primary_formats(wlr_output, server.allocator->buffer_caps);
enum render_bit_depth needed_bits = get_config_render_bit_depth(cfg->config);
for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) {
if (!need_10bit && render_format_is_10bit(fmts[idx])) {
enum render_bit_depth format_bits = bit_depth_from_format(fmts[idx]);
if (needed_bits < format_bits) {
continue;
}
if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) {
// If primary_formats is NULL, all formats are supported
if (primary_formats && !wlr_drm_format_set_get(primary_formats, fmts[idx])) {
// This is not a supported format for this output
continue;
}
@ -868,12 +924,12 @@ static int compare_matched_output_config_priority(const void *a, const void *b)
return 0;
}
void sort_output_configs_by_priority(struct matched_output_config *configs,
size_t configs_len) {
static 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,
static bool apply_resolved_output_configs(struct matched_output_config *configs,
size_t configs_len, bool test_only, bool degrade_to_off) {
struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
if (!states) {
@ -888,9 +944,8 @@ bool apply_output_configs(struct matched_output_config *configs,
backend_state->output = cfg->output->wlr_output;
wlr_output_state_init(&backend_state->base);
sway_log(SWAY_DEBUG, "Preparing config for %s",
cfg->output->wlr_output->name);
queue_output_config(cfg->config, cfg->output, &backend_state->base);
dump_output_state(cfg->output->wlr_output, &backend_state->base);
}
struct wlr_output_swapchain_manager swapchain_mgr;
@ -947,11 +1002,25 @@ bool apply_output_configs(struct matched_output_config *configs,
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
struct wlr_backend_output_state *backend_state = &states[idx];
sway_log(SWAY_DEBUG, "Finalizing config for %s",
cfg->output->wlr_output->name);
finalize_output_config(cfg->config, cfg->output);
finalize_output_config(cfg->config, cfg->output, &backend_state->base);
}
// Output layout being applied in finalize_output_config can shift outputs
// around, so we do a second pass to update positions and arrange.
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
output_update_position(cfg->output);
arrange_layers(cfg->output);
}
arrange_root();
arrange_locks();
update_output_manager_config(&server);
transaction_commit_dirty();
out:
wlr_output_swapchain_manager_finish(&swapchain_mgr);
for (size_t idx = 0; idx < configs_len; idx++) {
@ -976,11 +1045,12 @@ out:
return ok;
}
void apply_all_output_configs(void) {
bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
bool test_only, bool degrade_to_off) {
size_t configs_len = wl_list_length(&root->all_outputs);
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
if (!configs) {
return;
return false;
}
int config_idx = 0;
@ -993,16 +1063,22 @@ void apply_all_output_configs(void) {
struct matched_output_config *config = &configs[config_idx++];
config->output = sway_output;
config->config = find_output_config(sway_output);
config->config = find_output_config_from_list(ocs, ocs_len, sway_output);
}
sort_output_configs_by_priority(configs, configs_len);
apply_output_configs(configs, configs_len, false, true);
bool ok = apply_resolved_output_configs(configs, configs_len, test_only, degrade_to_off);
for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx];
free_output_config(cfg->config);
}
free(configs);
return ok;
}
void apply_stored_output_configs(void) {
apply_output_configs((struct output_config **)config->output_configs->items,
config->output_configs->length, false, true);
}
void free_output_config(struct output_config *oc) {
@ -1012,6 +1088,7 @@ void free_output_config(struct output_config *oc) {
free(oc->name);
free(oc->background);
free(oc->background_option);
free(oc->background_fallback);
wlr_color_transform_unref(oc->color_transform);
free(oc);
}
@ -1052,13 +1129,6 @@ static bool _spawn_swaybg(char **command) {
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
return false;
} else if (pid == 0) {
restore_nofile_limit();
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
_exit(EXIT_FAILURE);
} else if (pid == 0) {
if (!sway_set_cloexec(sockets[1], false)) {
_exit(EXIT_FAILURE);
@ -1075,20 +1145,12 @@ static bool _spawn_swaybg(char **command) {
command[0]);
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
if (close(sockets[1]) != 0) {
sway_log_errno(SWAY_ERROR, "close failed");
return false;
}
int fork_status = 0;
if (waitpid(pid, &fork_status, 0) < 0) {
sway_log_errno(SWAY_ERROR, "waitpid failed");
return false;
}
return WIFEXITED(fork_status) && WEXITSTATUS(fork_status) == EXIT_SUCCESS;
return true;
}
bool spawn_swaybg(void) {

View file

@ -34,7 +34,11 @@ bool criteria_is_empty(struct criteria *criteria) {
&& !criteria->tiling
&& !criteria->urgent
&& !criteria->workspace
&& !criteria->pid;
&& !criteria->pid
&& !criteria->sandbox_engine
&& !criteria->sandbox_app_id
&& !criteria->sandbox_instance_id
&& !criteria->tag;
}
// The error pointer is used for parsing functions, and saves having to pass it
@ -98,6 +102,10 @@ void criteria_destroy(struct criteria *criteria) {
#endif
pattern_destroy(criteria->con_mark);
pattern_destroy(criteria->workspace);
pattern_destroy(criteria->sandbox_engine);
pattern_destroy(criteria->sandbox_app_id);
pattern_destroy(criteria->sandbox_instance_id);
pattern_destroy(criteria->tag);
free(criteria->target);
free(criteria->cmdlist);
free(criteria->raw);
@ -248,6 +256,86 @@ static bool criteria_matches_view(struct criteria *criteria,
}
}
if (criteria->sandbox_engine) {
const char *sandbox_engine = view_get_sandbox_engine(view);
if (!sandbox_engine) {
return false;
}
switch (criteria->sandbox_engine->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(sandbox_engine, view_get_sandbox_engine(focused))) {
return false;
}
break;
case PATTERN_PCRE2:
if (regex_cmp(sandbox_engine, criteria->sandbox_engine->regex) < 0) {
return false;
}
break;
}
}
if (criteria->sandbox_app_id) {
const char *sandbox_app_id = view_get_sandbox_app_id(view);
if (!sandbox_app_id) {
return false;
}
switch (criteria->sandbox_app_id->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(sandbox_app_id, view_get_sandbox_app_id(focused))) {
return false;
}
break;
case PATTERN_PCRE2:
if (regex_cmp(sandbox_app_id, criteria->sandbox_app_id->regex) < 0) {
return false;
}
break;
}
}
if (criteria->sandbox_instance_id) {
const char *sandbox_instance_id = view_get_sandbox_instance_id(view);
if (!sandbox_instance_id) {
return false;
}
switch (criteria->sandbox_instance_id->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(sandbox_instance_id, view_get_sandbox_instance_id(focused))) {
return false;
}
break;
case PATTERN_PCRE2:
if (regex_cmp(sandbox_instance_id, criteria->sandbox_instance_id->regex) < 0) {
return false;
}
break;
}
}
if (criteria->tag) {
const char *tag = view_get_tag(view);
if (!tag) {
return false;
}
switch (criteria->tag->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(tag, view_get_tag(focused))) {
return false;
}
break;
case PATTERN_PCRE2:
if (regex_cmp(tag, criteria->tag->regex) < 0) {
return false;
}
break;
}
}
if (!criteria_matches_container(criteria, view->container)) {
return false;
}
@ -475,6 +563,10 @@ enum criteria_token {
T_URGENT,
T_WORKSPACE,
T_PID,
T_SANDBOX_ENGINE,
T_SANDBOX_APP_ID,
T_SANDBOX_INSTANCE_ID,
T_TAG,
T_INVALID,
};
@ -514,6 +606,14 @@ static enum criteria_token token_from_name(char *name) {
return T_FLOATING;
} else if (strcmp(name, "pid") == 0) {
return T_PID;
} else if (strcmp(name, "sandbox_engine") == 0) {
return T_SANDBOX_ENGINE;
} else if (strcmp(name, "sandbox_app_id") == 0) {
return T_SANDBOX_APP_ID;
} else if (strcmp(name, "sandbox_instance_id") == 0) {
return T_SANDBOX_INSTANCE_ID;
} else if (strcmp(name, "tag") == 0) {
return T_TAG;
}
return T_INVALID;
}
@ -555,8 +655,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
if (strcmp(value, "__focused__") == 0) {
struct sway_seat *seat = input_manager_current_seat();
struct sway_container *focus = seat_get_focused_container(seat);
struct sway_view *view = focus ? focus->view : NULL;
criteria->con_id = view ? view->container->node.id : 0;
criteria->con_id = focus ? focus->node.id : 0;
} else {
criteria->con_id = strtoul(value, &endptr, 10);
if (*endptr != 0) {
@ -617,6 +716,18 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
error = strdup("The value for 'pid' should be numeric");
}
break;
case T_SANDBOX_ENGINE:
pattern_create(&criteria->sandbox_engine, value);
break;
case T_SANDBOX_APP_ID:
pattern_create(&criteria->sandbox_app_id, value);
break;
case T_SANDBOX_INSTANCE_ID:
pattern_create(&criteria->sandbox_instance_id, value);
break;
case T_TAG:
pattern_create(&criteria->tag, value);
break;
case T_INVALID:
break;
}

View file

@ -1,5 +1,6 @@
#include <stdlib.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include "log.h"
#include "sway/desktop/idle_inhibit_v1.h"
#include "sway/input/seat.h"
@ -44,6 +45,14 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
sway_idle_inhibit_v1_check_active();
}
void handle_manager_destroy(struct wl_listener *listener, void *data) {
struct sway_idle_inhibit_manager_v1 *manager =
wl_container_of(listener, manager, manager_destroy);
wl_list_remove(&manager->manager_destroy.link);
wl_list_remove(&manager->new_idle_inhibitor_v1.link);
}
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
enum sway_idle_inhibit_mode mode) {
struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1;
@ -103,11 +112,34 @@ void sway_idle_inhibit_v1_user_inhibitor_destroy(
}
bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) {
if (server.session_lock.lock) {
// A session lock is active. In this case, only application inhibitors
// on the session lock surface can have any effect.
if (inhibitor->mode != INHIBIT_IDLE_APPLICATION) {
return false;
}
struct wlr_surface *wlr_surface = inhibitor->wlr_inhibitor->surface;
if (!wlr_session_lock_surface_v1_try_from_wlr_surface(wlr_surface)) {
return false;
}
return wlr_surface->mapped;
}
switch (inhibitor->mode) {
case INHIBIT_IDLE_APPLICATION:;
// If there is no view associated with the inhibitor, assume visible
struct sway_view *view = view_from_wlr_surface(inhibitor->wlr_inhibitor->surface);
return !view || !view->container || view_is_visible(view);
struct wlr_surface *wlr_surface = inhibitor->wlr_inhibitor->surface;
struct wlr_layer_surface_v1 *layer_surface =
wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface);
if (layer_surface) {
// Layer surfaces can be occluded but are always on screen after
// they have been mapped.
return layer_surface->output && layer_surface->output->enabled &&
wlr_surface->mapped;
}
// If there is no view associated with the inhibitor, assume invisible
struct sway_view *view = view_from_wlr_surface(wlr_surface);
return view && view->container && view_is_visible(view);
case INHIBIT_IDLE_FOCUS:;
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
@ -153,6 +185,9 @@ bool sway_idle_inhibit_manager_v1_init(void) {
wl_signal_add(&manager->wlr_manager->events.new_inhibitor,
&manager->new_idle_inhibitor_v1);
manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1;
wl_signal_add(&manager->wlr_manager->events.destroy,
&manager->manager_destroy);
manager->manager_destroy.notify = handle_manager_destroy;
wl_list_init(&manager->inhibitors);
return true;

View file

@ -54,7 +54,7 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
}
static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
struct wlr_box *usable_area, struct wlr_scene_tree *tree) {
struct wlr_box *usable_area, struct wlr_scene_tree *tree, bool exclusive) {
struct wlr_scene_node *node;
wl_list_for_each(node, &tree->children, link) {
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
@ -68,6 +68,10 @@ static void arrange_surface(struct sway_output *output, const struct wlr_box *fu
continue;
}
if ((surface->scene->layer_surface->current.exclusive_zone > 0) != exclusive) {
continue;
}
wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
}
}
@ -78,10 +82,15 @@ void arrange_layers(struct sway_output *output) {
&usable_area.width, &usable_area.height);
const struct wlr_box full_area = usable_area;
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, true);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, true);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, true);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, true);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, false);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, false);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, false);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, false);
if (!wlr_box_equal(&usable_area, &output->usable_area)) {
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
@ -90,6 +99,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,
@ -170,14 +216,6 @@ static struct sway_layer_surface *find_mapped_layer_by_client(
return NULL;
}
static void handle_output_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *layer =
wl_container_of(listener, layer, output_destroy);
layer->output = NULL;
wlr_scene_node_destroy(&layer->scene->tree->node);
}
static void handle_node_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *layer =
wl_container_of(listener, layer, node_destroy);
@ -210,10 +248,11 @@ static void handle_node_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&layer->unmap.link);
wl_list_remove(&layer->surface_commit.link);
wl_list_remove(&layer->node_destroy.link);
wl_list_remove(&layer->output_destroy.link);
wl_list_remove(&layer->new_popup.link);
layer->layer_surface->data = NULL;
wl_list_remove(&layer->link);
free(layer);
}
@ -222,12 +261,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
wl_container_of(listener, surface, surface_commit);
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
if (!layer_surface->initialized) {
return;
}
uint32_t committed = layer_surface->current.committed;
if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) {
if (layer_surface->initialized && committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) {
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer;
struct wlr_scene_tree *output_layer = sway_layer_get_scene(
surface->output, layer_type);
@ -432,6 +467,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
}
surface->output = output;
wl_list_insert(&output->layer_surfaces, &surface->link);
// now that the surface's output is known, we can advertise its scale
wlr_fractional_scale_v1_notify_scale(surface->layer_surface->surface,
@ -449,9 +485,14 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
surface->new_popup.notify = handle_new_popup;
wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
surface->output_destroy.notify = handle_output_destroy;
wl_signal_add(&output->events.disable, &surface->output_destroy);
surface->node_destroy.notify = handle_node_destroy;
wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);
}
void destroy_layers(struct sway_output *output) {
struct sway_layer_surface *layer, *layer_tmp;
wl_list_for_each_safe(layer, layer_tmp, &output->layer_surfaces, link) {
layer->output = NULL;
wlr_layer_surface_v1_destroy(layer->layer_surface);
}
}

View file

@ -8,8 +8,8 @@
#include <wlr/render/swapchain.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_alpha_modifier_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
@ -97,11 +97,11 @@ struct buffer_timer {
};
static int handle_buffer_timer(void *data) {
struct wlr_scene_buffer *buffer = data;
struct wlr_scene_surface *scene_surface = data;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_scene_buffer_send_frame_done(buffer, &now);
wlr_scene_surface_send_frame_done(scene_surface, &now);
return 0;
}
@ -114,7 +114,9 @@ static void handle_buffer_timer_destroy(struct wl_listener *listener,
free(timer);
}
static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_buffer *buffer) {
static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_surface *scene_surface) {
struct wlr_scene_buffer *buffer = scene_surface->buffer;
struct buffer_timer *timer =
scene_descriptor_try_get(&buffer->node, SWAY_SCENE_DESC_BUFFER_TIMER);
if (timer) {
@ -127,7 +129,7 @@ static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_buffer *
}
timer->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop,
handle_buffer_timer, buffer);
handle_buffer_timer, scene_surface);
if (!timer->frame_done_timer) {
free(timer);
return NULL;
@ -151,6 +153,11 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer,
return;
}
struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(buffer);
if (scene_surface == NULL) {
return;
}
struct wlr_scene_node *current = &buffer->node;
while (true) {
struct sway_view *view = scene_descriptor_try_get(current,
@ -173,13 +180,13 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer,
struct buffer_timer *timer = NULL;
if (output->max_render_time != 0 && view_max_render_time != 0 && delay > 0) {
timer = buffer_timer_get_or_create(buffer);
timer = buffer_timer_get_or_create(scene_surface);
}
if (timer) {
wl_event_source_timer_update(timer->frame_done_timer, delay);
} else {
wlr_scene_buffer_send_frame_done(buffer, &data->when);
wlr_scene_surface_send_frame_done(scene_surface, &data->when);
}
}
@ -187,8 +194,8 @@ static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output,
struct wlr_scene_buffer *buffer) {
// if we are scaling down, we should always choose linear
if (buffer->dst_width > 0 && buffer->dst_height > 0 && (
buffer->dst_width < buffer->buffer_width ||
buffer->dst_height < buffer->buffer_height)) {
buffer->dst_width < buffer->WLR_PRIVATE.buffer_width ||
buffer->dst_height < buffer->WLR_PRIVATE.buffer_height)) {
return WLR_SCALE_FILTER_BILINEAR;
}
@ -202,7 +209,7 @@ static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output,
}
}
static void output_configure_scene(struct sway_output *output,
void output_configure_scene(struct sway_output *output,
struct wlr_scene_node *node, float opacity) {
if (!node->enabled) {
return;
@ -216,11 +223,22 @@ static void output_configure_scene(struct sway_output *output,
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(buffer);
if (surface) {
const struct wlr_alpha_modifier_surface_v1_state *alpha_modifier_state =
wlr_alpha_modifier_v1_get_surface_state(surface->surface);
if (alpha_modifier_state != NULL) {
opacity *= (float)alpha_modifier_state->multiplier;
}
}
// hack: don't call the scene setter because that will damage all outputs
// We don't want to damage outputs that aren't our current output that
// we're configuring
if (output) {
buffer->filter_mode = get_scale_filter(output, buffer);
}
wlr_scene_buffer_set_opacity(buffer, opacity);
} else if (node->type == WLR_SCENE_NODE_TREE) {
@ -232,40 +250,56 @@ static void output_configure_scene(struct sway_output *output,
}
}
static bool output_can_tear(struct sway_output *output) {
struct sway_workspace *workspace = output->current.active_workspace;
if (!workspace) {
return false;
}
struct sway_container *fullscreen_con = root->fullscreen_global;
if (!fullscreen_con) {
fullscreen_con = workspace->current.fullscreen;
}
if (fullscreen_con && fullscreen_con->view) {
return (output->allow_tearing && view_can_tear(fullscreen_con->view));
}
return false;
}
static int output_repaint_timer_handler(void *data) {
struct sway_output *output = data;
if (!output->enabled) {
output->wlr_output->frame_pending = false;
if (!output->wlr_output->enabled) {
return 0;
}
output->wlr_output->frame_pending = false;
output_configure_scene(output, &root->root_scene->tree.node, 1.0f);
struct wlr_scene_output_state_options opts = {
.color_transform = output->color_transform,
};
struct wlr_output_state pending;
wlr_output_state_init(&pending);
if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) {
struct wlr_scene_output *scene_output = output->scene_output;
if (!wlr_scene_output_needs_frame(scene_output)) {
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(
server.gamma_control_manager_v1, output->wlr_output);
if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) {
struct wlr_output_state pending;
wlr_output_state_init(&pending);
if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) {
wlr_output_state_finish(&pending);
return 0;
}
if (output_can_tear(output)) {
pending.tearing_page_flip = true;
if (!wlr_output_test_state(output->wlr_output, &pending)) {
wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL);
sway_log(SWAY_DEBUG, "Output test failed on '%s', retrying without tearing page-flip",
output->wlr_output->name);
pending.tearing_page_flip = false;
}
}
@ -340,7 +374,7 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
}
static void update_output_manager_config(struct sway_server *server) {
void update_output_manager_config(struct sway_server *server) {
struct wlr_output_configuration_v1 *config =
wlr_output_configuration_v1_create();
@ -370,45 +404,56 @@ static int timer_modeset_handle(void *data) {
wl_event_source_remove(server->delayed_modeset);
server->delayed_modeset = NULL;
apply_all_output_configs();
transaction_commit_dirty();
update_output_manager_config(server);
apply_stored_output_configs();
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);
void request_modeset(void) {
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);
}
}
bool modeset_is_pending(void) {
return server.delayed_modeset != NULL;
}
void force_modeset(void) {
if (server.delayed_modeset != NULL) {
wl_event_source_remove(server.delayed_modeset);
server.delayed_modeset = NULL;
}
apply_stored_output_configs();
}
static void begin_destroy(struct sway_output *output) {
struct sway_server *server = output->server;
if (output->enabled) {
output_disable(output);
}
output_begin_destroy(output);
wl_list_remove(&output->link);
wl_list_remove(&output->layout_destroy.link);
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->commit.link);
wl_list_remove(&output->present.link);
wl_list_remove(&output->frame.link);
wl_list_remove(&output->request_state.link);
// Remove the scene_output first to ensure that the scene does not emit
// events for this output.
wlr_scene_output_destroy(output->scene_output);
output->scene_output = NULL;
if (output->enabled) {
output_disable(output);
}
output_begin_destroy(output);
wl_list_remove(&output->link);
output->wlr_output->data = NULL;
output->wlr_output = NULL;
request_modeset(server);
wl_event_source_remove(output->repaint_timer);
output->repaint_timer = NULL;
request_modeset();
}
static void handle_destroy(struct wl_listener *listener, void *data) {
@ -421,31 +466,6 @@ static void handle_layout_destroy(struct wl_listener *listener, void *data) {
begin_destroy(output);
}
static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, commit);
struct wlr_output_event_commit *event = data;
if (!output->enabled) {
return;
}
if (event->state->committed & (
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_TRANSFORM |
WLR_OUTPUT_STATE_SCALE)) {
arrange_layers(output);
arrange_output(output);
transaction_commit_dirty();
update_output_manager_config(output->server);
}
// Next time the output is enabled, try to re-apply the gamma LUT
if ((event->state->committed & WLR_OUTPUT_STATE_ENABLED) && !output->wlr_output->enabled) {
output->gamma_lut_changed = true;
}
}
static void handle_present(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, present);
struct wlr_output_event_present *output_event = data;
@ -454,7 +474,7 @@ static void handle_present(struct wl_listener *listener, void *data) {
return;
}
output->last_presentation = *output_event->when;
output->last_presentation = output_event->when;
output->refresh_nsec = output_event->refresh;
}
@ -462,7 +482,44 @@ static void handle_request_state(struct wl_listener *listener, void *data) {
struct sway_output *output =
wl_container_of(listener, output, request_state);
const struct wlr_output_event_request_state *event = data;
wlr_output_commit_state(output->wlr_output, event->state);
const struct wlr_output_state *state = event->state;
// Store the requested changes so that the active configuration is
// consistent with the current state, and to avoid duplicate logic to apply
// the changes.
struct output_config *oc = new_output_config(output->wlr_output->name);
if (!oc) {
sway_log(SWAY_ERROR, "Allocation failed");
return;
}
int committed = state->committed;
if (committed & WLR_OUTPUT_STATE_MODE) {
if (state->mode != NULL) {
oc->width = state->mode->width;
oc->height = state->mode->height;
oc->refresh_rate = state->mode->refresh / 1000.f;
} else {
oc->width = state->custom_mode.width;
oc->height = state->custom_mode.height;
oc->refresh_rate = state->custom_mode.refresh / 1000.f;
}
committed &= ~WLR_OUTPUT_STATE_MODE;
}
if (committed & WLR_OUTPUT_STATE_SCALE) {
oc->scale = state->scale;
committed &= ~WLR_OUTPUT_STATE_SCALE;
}
if (committed & WLR_OUTPUT_STATE_TRANSFORM) {
oc->transform = state->transform;
committed &= ~WLR_OUTPUT_STATE_TRANSFORM;
}
// We do not expect or support any other changes here
assert(committed == 0);
store_output_config(oc);
force_modeset();
}
static unsigned int last_headless_num = 0;
@ -526,8 +583,6 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->layout_destroy.notify = handle_layout_destroy;
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
wl_signal_add(&wlr_output->events.commit, &output->commit);
output->commit.notify = handle_commit;
wl_signal_add(&wlr_output->events.present, &output->present);
output->present.notify = handle_present;
wl_signal_add(&wlr_output->events.frame, &output->frame);
@ -542,35 +597,16 @@ void handle_new_output(struct wl_listener *listener, void *data) {
sway_session_lock_add_output(server->session_lock.lock, output);
}
request_modeset(server);
}
void handle_output_layout_change(struct wl_listener *listener,
void *data) {
struct sway_server *server =
wl_container_of(listener, server, output_layout_change);
update_output_manager_config(server);
}
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
struct sway_server *server =
wl_container_of(listener, server, gamma_control_set_gamma);
const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
struct sway_output *output = event->output->data;
if(!output) {
return;
}
output->gamma_lut_changed = true;
wlr_output_schedule_frame(output->wlr_output);
request_modeset();
}
static struct output_config *output_config_for_config_head(
struct wlr_output_configuration_head_v1 *config_head,
struct sway_output *output) {
struct output_config *oc = new_output_config(output->wlr_output->name);
struct wlr_output_configuration_head_v1 *config_head) {
struct output_config *oc = new_output_config(config_head->state.output->name);
if (!oc) {
return NULL;
}
oc->enabled = config_head->state.enabled;
if (!oc->enabled) {
return oc;
@ -596,71 +632,59 @@ static struct output_config *output_config_for_config_head(
}
static void output_manager_apply(struct sway_server *server,
struct wlr_output_configuration_v1 *config, bool test_only) {
size_t configs_len = wl_list_length(&root->all_outputs);
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
struct wlr_output_configuration_v1 *cfg, bool test_only) {
bool ok = false;
size_t configs_len = config->output_configs->length + wl_list_length(&cfg->heads);
struct output_config **configs = calloc(configs_len, sizeof(*configs));
if (!configs) {
return;
sway_log(SWAY_ERROR, "Allocation failed");
goto error;
}
size_t start_new_configs = config->output_configs->length;
for (size_t idx = 0; idx < start_new_configs; idx++) {
configs[idx] = config->output_configs->items[idx];
}
int config_idx = 0;
struct sway_output *sway_output;
wl_list_for_each(sway_output, &root->all_outputs, link) {
if (sway_output == root->fallback_output) {
configs_len--;
continue;
}
struct matched_output_config *cfg = &configs[config_idx++];
cfg->output = sway_output;
size_t config_idx = start_new_configs;
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) {
cfg->config = output_config_for_config_head(config_head, sway_output);
break;
}
}
if (!cfg->config) {
cfg->config = find_output_config(sway_output);
wl_list_for_each(config_head, &cfg->heads, link) {
// Generate the configuration and store it as a temporary
// config. We keep a record of it so we can remove it later.
struct output_config *oc = output_config_for_config_head(config_head);
if (!oc) {
sway_log(SWAY_ERROR, "Allocation failed");
goto error_config;
}
configs[config_idx++] = oc;
}
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];
// Try to commit without degrade to off enabled. Note that this will fail
// if any output configured for enablement fails to be enabled, even if it
// was not part of the config heads we were asked to configure.
ok = apply_output_configs(configs, configs_len, test_only, false);
// Only store new configs for successful non-test commits. Old configs,
// test-only and failed commits just get freed.
bool store_config = false;
error_config:
for (size_t idx = start_new_configs; idx < configs_len; idx++) {
struct output_config *cfg = configs[idx];
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 == cfg->output->wlr_output) {
store_config = true;
break;
}
}
}
if (store_config) {
store_output_config(cfg->config);
store_output_config(cfg);
} else {
free_output_config(cfg->config);
free_output_config(cfg);
}
}
free(configs);
error:
if (ok) {
wlr_output_configuration_v1_send_succeeded(config);
wlr_output_configuration_v1_send_succeeded(cfg);
if (server->delayed_modeset != NULL) {
wl_event_source_remove(server->delayed_modeset);
server->delayed_modeset = NULL;
}
} else {
wlr_output_configuration_v1_send_failed(config);
}
wlr_output_configuration_v1_destroy(config);
if (!test_only) {
update_output_manager_config(server);
wlr_output_configuration_v1_send_failed(cfg);
}
wlr_output_configuration_v1_destroy(cfg);
}
void handle_output_manager_apply(struct wl_listener *listener, void *data) {
@ -685,6 +709,11 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
struct sway_output *output = event->output->data;
struct output_config *oc = new_output_config(output->wlr_output->name);
if (!oc) {
sway_log(SWAY_ERROR, "Allocation failed");
return;
}
switch (event->mode) {
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
oc->power = 0;
@ -694,5 +723,5 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
break;
}
store_output_config(oc);
request_modeset(output->server);
request_modeset();
}

64
sway/desktop/tearing.c Normal file
View file

@ -0,0 +1,64 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_tearing_control_v1.h>
#include "sway/server.h"
#include "sway/tree/view.h"
#include "sway/output.h"
#include "log.h"
struct sway_tearing_controller {
struct wlr_tearing_control_v1 *tearing_control;
struct wl_listener set_hint;
struct wl_listener destroy;
struct wl_list link; // sway_server::tearing_controllers
};
static void handle_tearing_controller_set_hint(struct wl_listener *listener,
void *data) {
struct sway_tearing_controller *controller =
wl_container_of(listener, controller, set_hint);
struct sway_view *view = view_from_wlr_surface(
controller->tearing_control->surface);
if (view) {
view->tearing_hint = controller->tearing_control->current;
}
}
static void handle_tearing_controller_destroy(struct wl_listener *listener,
void *data) {
struct sway_tearing_controller *controller =
wl_container_of(listener, controller, destroy);
wl_list_remove(&controller->set_hint.link);
wl_list_remove(&controller->destroy.link);
wl_list_remove(&controller->link);
free(controller);
}
void handle_new_tearing_hint(struct wl_listener *listener,
void *data) {
struct sway_server *server =
wl_container_of(listener, server, tearing_control_new_object);
struct wlr_tearing_control_v1 *tearing_control = data;
enum wp_tearing_control_v1_presentation_hint hint =
wlr_tearing_control_manager_v1_surface_hint_from_surface(
server->tearing_control_v1, tearing_control->surface);
sway_log(SWAY_DEBUG, "New presentation hint %d received for surface %p",
hint, tearing_control->surface);
struct sway_tearing_controller *controller =
calloc(1, sizeof(struct sway_tearing_controller));
if (!controller) {
return;
}
controller->tearing_control = tearing_control;
controller->set_hint.notify = handle_tearing_controller_set_hint;
wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint);
controller->destroy.notify = handle_tearing_controller_destroy;
wl_signal_add(&tearing_control->events.destroy, &controller->destroy);
wl_list_init(&controller->link);
wl_list_insert(&server->tearing_controllers, &controller->link);
}

View file

@ -309,12 +309,13 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
arrange_title_bar(child, title_offset, -title_bar_height,
next_title_offset - title_offset, title_bar_height);
wlr_scene_node_set_enabled(&child->border.tree->node, activated);
wlr_scene_node_set_enabled(&child->scene_tree->node, true);
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
wlr_scene_node_reparent(&child->scene_tree->node, content);
if (activated) {
arrange_container(child, width, height - title_bar_height,
title_bar_height == 0, 0);
int net_height = height - title_bar_height;
if (activated && width > 0 && net_height > 0) {
arrange_container(child, width, net_height, title_bar_height == 0, 0);
} else {
disable_container(child);
}
@ -338,12 +339,13 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
arrange_title_bar(child, 0, y - title_height, width, title_bar_height);
wlr_scene_node_set_enabled(&child->border.tree->node, activated);
wlr_scene_node_set_enabled(&child->scene_tree->node, true);
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
wlr_scene_node_reparent(&child->scene_tree->node, content);
if (activated) {
arrange_container(child, width, height - title_height,
title_bar_height == 0, 0);
int net_height = height - title_height;
if (activated && width > 0 && net_height > 0) {
arrange_container(child, width, net_height, title_bar_height == 0, 0);
} else {
disable_container(child);
}
@ -359,8 +361,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
wlr_scene_node_set_enabled(&child->border.tree->node, true);
wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
wlr_scene_node_reparent(&child->scene_tree->node, content);
if (width > 0 && cheight > 0) {
arrange_container(child, width, cheight, true, gaps);
off += cheight + gaps;
} else {
disable_container(child);
}
}
} else if (layout == L_HORIZ) {
int off = 0;
@ -371,8 +377,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
wlr_scene_node_set_enabled(&child->border.tree->node, true);
wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
wlr_scene_node_reparent(&child->scene_tree->node, content);
if (cwidth > 0 && height > 0) {
arrange_container(child, cwidth, height, true, gaps);
off += cwidth + gaps;
} else {
disable_container(child);
}
}
} else {
sway_assert(false, "unreachable");
@ -424,13 +434,14 @@ static void arrange_container(struct sway_container *con,
int border_bottom = con->current.border_bottom ? border_width : 0;
int border_left = con->current.border_left ? border_width : 0;
int border_right = con->current.border_right ? border_width : 0;
int vert_border_height = MAX(0, height - border_top - border_bottom);
wlr_scene_rect_set_size(con->border.top, width, border_top);
wlr_scene_rect_set_size(con->border.bottom, width, border_bottom);
wlr_scene_rect_set_size(con->border.left,
border_left, height - border_top - border_bottom);
border_left, vert_border_height);
wlr_scene_rect_set_size(con->border.right,
border_right, height - border_top - border_bottom);
border_right, vert_border_height);
wlr_scene_node_set_position(&con->border.top->node, 0, 0);
wlr_scene_node_set_position(&con->border.bottom->node,
@ -523,6 +534,7 @@ static void arrange_workspace_floating(struct sway_workspace *ws) {
wlr_scene_node_set_position(&floater->scene_tree->node,
floater->current.x, floater->current.y);
wlr_scene_node_set_enabled(&floater->scene_tree->node, true);
wlr_scene_node_set_enabled(&floater->border.tree->node, true);
arrange_container(floater, floater->current.width, floater->current.height,
true, ws->gaps_inner);
@ -559,7 +571,7 @@ static void arrange_output(struct sway_output *output, int width, int height) {
for (int i = 0; i < output->current.workspaces->length; i++) {
struct sway_workspace *child = output->current.workspaces->items[i];
bool activated = output->current.active_workspace == child;
bool activated = output->current.active_workspace == child && output->wlr_output->enabled;
wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
@ -575,15 +587,16 @@ static void arrange_output(struct sway_output *output, int width, int height) {
wlr_scene_node_set_enabled(&child->layers.tiling->node, !fs);
wlr_scene_node_set_enabled(&child->layers.fullscreen->node, fs);
arrange_workspace_floating(child);
wlr_scene_node_set_enabled(&output->layers.shell_background->node, !fs);
wlr_scene_node_set_enabled(&output->layers.shell_bottom->node, !fs);
wlr_scene_node_set_enabled(&output->layers.fullscreen->node, fs);
if (fs) {
disable_workspace(child);
wlr_scene_rect_set_size(output->fullscreen_background, width, height);
arrange_workspace_floating(child);
arrange_fullscreen(child->layers.fullscreen, fs, child,
width, height);
} else {
@ -596,6 +609,7 @@ static void arrange_output(struct sway_output *output, int width, int height) {
arrange_workspace_tiling(child,
area->width - gaps->left - gaps->right,
area->height - gaps->top - gaps->bottom);
arrange_workspace_floating(child);
}
} else {
wlr_scene_node_set_enabled(&child->layers.tiling->node, false);
@ -612,11 +626,13 @@ void arrange_popups(struct wlr_scene_tree *popups) {
struct sway_popup_desc *popup = scene_descriptor_try_get(node,
SWAY_SCENE_DESC_POPUP);
if (popup) {
int lx, ly;
wlr_scene_node_coords(popup->relative, &lx, &ly);
wlr_scene_node_set_position(node, lx, ly);
}
}
}
static void arrange_root(struct sway_root *root) {
struct sway_container *fs = root->fullscreen_global;
@ -632,6 +648,15 @@ static void arrange_root(struct sway_root *root) {
for (int i = 0; i < root->scratchpad->length; i++) {
struct sway_container *con = root->scratchpad->items[i];
// When a container is moved to a scratchpad, it's possible that it
// was moved into a floating container as part of the same transaction.
// In this case, we need to make sure we reparent all the container's
// children so that disabling the container will disable all descendants.
if (!con->view) for (int ii = 0; ii < con->current.children->length; ii++) {
struct sway_container *child = con->current.children->items[ii];
wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree);
}
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
}
@ -640,6 +665,15 @@ static void arrange_root(struct sway_root *root) {
struct sway_output *output = root->outputs->items[i];
struct sway_workspace *ws = output->current.active_workspace;
wlr_scene_output_set_position(output->scene_output, output->lx, output->ly);
// disable all workspaces to get to a known state
for (int j = 0; j < output->current.workspaces->length; j++) {
struct sway_workspace *workspace = output->current.workspaces->items[j];
disable_workspace(workspace);
}
// arrange the active workspace
if (ws) {
arrange_workspace_floating(ws);
}

View file

@ -3,6 +3,7 @@
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_xdg_toplevel_tag_v1.h>
#include <wlr/util/edges.h>
#include "log.h"
#include "sway/decoration.h"
@ -20,13 +21,13 @@
static struct sway_xdg_popup *popup_create(
struct wlr_xdg_popup *wlr_popup, struct sway_view *view,
struct wlr_scene_tree *parent);
struct wlr_scene_tree *parent, struct wlr_scene_tree *image_capture_parent);
static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
struct sway_xdg_popup *popup =
wl_container_of(listener, popup, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
popup_create(wlr_popup, popup->view, popup->xdg_surface_tree);
popup_create(wlr_popup, popup->view, popup->xdg_surface_tree, popup->image_capture_tree);
}
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
@ -77,7 +78,8 @@ static void popup_handle_reposition(struct wl_listener *listener, void *data) {
}
static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup,
struct sway_view *view, struct wlr_scene_tree *parent) {
struct sway_view *view, struct wlr_scene_tree *parent,
struct wlr_scene_tree *image_capture_parent) {
struct wlr_xdg_surface *xdg_surface = wlr_popup->base;
struct sway_xdg_popup *popup = calloc(1, sizeof(struct sway_xdg_popup));
@ -113,6 +115,11 @@ static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup,
return NULL;
}
popup->image_capture_tree = wlr_scene_xdg_surface_create(image_capture_parent, xdg_surface);
if (popup->image_capture_tree == NULL) {
return NULL;
}
popup->wlr_xdg_popup = xdg_surface->popup;
struct sway_xdg_shell_view *shell_view =
wl_container_of(view, shell_view, view);
@ -151,7 +158,8 @@ static void get_constraints(struct sway_view *view, double *min_width,
static const char *get_string_prop(struct sway_view *view,
enum sway_view_prop prop) {
if (xdg_shell_view_from_view(view) == NULL) {
struct sway_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
if (xdg_shell_view == NULL) {
return NULL;
}
switch (prop) {
@ -159,6 +167,8 @@ static const char *get_string_prop(struct sway_view *view,
return view->wlr_xdg_toplevel->title;
case VIEW_PROP_APP_ID:
return view->wlr_xdg_toplevel->app_id;
case VIEW_PROP_TAG:
return xdg_shell_view->tag;
default:
return NULL;
}
@ -259,6 +269,7 @@ static void destroy(struct sway_view *view) {
if (xdg_shell_view == NULL) {
return;
}
free(xdg_shell_view->tag);
free(xdg_shell_view);
}
@ -290,7 +301,7 @@ 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);
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
// TODO: wlr_xdg_toplevel_set_bounds()
return;
}
@ -299,18 +310,17 @@ static void handle_commit(struct wl_listener *listener, void *data) {
return;
}
struct wlr_box new_geo;
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
bool new_size = new_geo.width != view->geometry.width ||
new_geo.height != view->geometry.height ||
new_geo.x != view->geometry.x ||
new_geo.y != view->geometry.y;
struct wlr_box *new_geo = &xdg_surface->geometry;
bool new_size = new_geo->width != view->geometry.width ||
new_geo->height != view->geometry.height ||
new_geo->x != view->geometry.x ||
new_geo->y != view->geometry.y;
if (new_size) {
// The client changed its surface size in this commit. For floating
// containers, we resize the container to match. For tiling containers,
// we only recenter the surface.
memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
memcpy(&view->geometry, new_geo, sizeof(struct wlr_box));
if (container_is_floating(view->container)) {
view_update_size(view);
// Only set the toplevel size the current container actually has a size.
@ -360,7 +370,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
struct wlr_xdg_popup *wlr_popup = data;
struct sway_xdg_popup *popup = popup_create(wlr_popup,
&xdg_shell_view->view, root->layers.popup);
&xdg_shell_view->view, root->layers.popup, xdg_shell_view->image_capture_tree);
if (!popup) {
return;
}
@ -463,12 +473,8 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_view->view;
struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
view->natural_width = toplevel->base->current.geometry.width;
view->natural_height = toplevel->base->current.geometry.height;
if (!view->natural_width && !view->natural_height) {
view->natural_width = toplevel->base->surface->current.width;
view->natural_height = toplevel->base->surface->current.height;
}
view->natural_width = toplevel->base->geometry.width;
view->natural_height = toplevel->base->geometry.height;
bool csd = false;
@ -575,6 +581,17 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) {
wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy);
wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base);
xdg_shell_view->image_capture_tree =
wlr_scene_xdg_surface_create(&xdg_shell_view->view.image_capture_scene->tree, xdg_toplevel->base);
xdg_toplevel->base->data = xdg_shell_view;
}
void xdg_toplevel_tag_manager_v1_handle_set_tag(struct wl_listener *listener, void *data) {
const struct wlr_xdg_toplevel_tag_manager_v1_set_tag_event *event = data;
struct sway_view *view = view_from_wlr_xdg_surface(event->toplevel->base);
struct sway_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view);
free(xdg_shell_view->tag);
xdg_shell_view->tag = strdup(event->tag);
view_execute_criteria(view);
}

View file

@ -71,7 +71,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
surface->set_geometry.notify = unmanaged_handle_set_geometry;
}
if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
if (wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
struct sway_seat *seat = input_manager_current_seat();
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
@ -96,7 +96,7 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
// This simply returns focus to the parent surface if there's one available.
// This seems to handle JetBrains issues.
if (xsurface->parent && xsurface->parent->surface
&& wlr_xwayland_or_surface_wants_focus(xsurface->parent)) {
&& wlr_xwayland_surface_override_redirect_wants_focus(xsurface->parent)) {
seat_set_focus_surface(seat, xsurface->parent->surface, false);
return;
}
@ -289,7 +289,6 @@ static void set_activated(struct sway_view *view, bool activated) {
}
wlr_xwayland_surface_activate(surface, activated);
wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE);
}
static void set_tiled(struct sway_view *view, bool tiled) {
@ -297,7 +296,7 @@ static void set_tiled(struct sway_view *view, bool tiled) {
return;
}
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
wlr_xwayland_surface_set_maximized(surface, tiled);
wlr_xwayland_surface_set_maximized(surface, tiled, tiled);
}
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
@ -498,6 +497,9 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->commit.link);
wl_list_remove(&xwayland_view->surface_tree_destroy.link);
wlr_scene_node_destroy(&xwayland_view->image_capture_scene_surface->buffer->node);
xwayland_view->image_capture_scene_surface = NULL;
if (xwayland_view->surface_tree) {
wlr_scene_node_destroy(&xwayland_view->surface_tree->node);
xwayland_view->surface_tree = NULL;
@ -538,6 +540,9 @@ static void handle_map(struct wl_listener *listener, void *data) {
&xwayland_view->surface_tree_destroy);
}
xwayland_view->image_capture_scene_surface =
wlr_scene_surface_create(&xwayland_view->view.image_capture_scene->tree, xsurface->surface);
transaction_commit_dirty();
}

View file

@ -32,12 +32,6 @@
#include "sway/tree/workspace.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
static uint32_t get_current_time_msec(void) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec * 1000 + now.tv_nsec / 1000000;
}
/**
* Returns the node at the cursor's position. If there is a surface at that
* location, it is stored in **surface (it may not be a view).
@ -144,7 +138,7 @@ struct sway_node *node_at_coords(
}
void cursor_rebase(struct sway_cursor *cursor) {
uint32_t time_msec = get_current_time_msec();
uint32_t time_msec = get_current_time_in_msec();
seatop_rebase(cursor->seat, time_msec);
}
@ -359,7 +353,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
enum wl_pointer_button_state state) {
if (time_msec == 0) {
time_msec = get_current_time_msec();
time_msec = get_current_time_in_msec();
}
seatop_button(cursor->seat, time_msec, device, button, state);
@ -578,12 +572,13 @@ 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 {
wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool);
pointer_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
}
}
@ -664,7 +659,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.
@ -749,7 +744,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
@ -1047,6 +1042,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
wl_list_remove(&cursor->touch_frame.link);
wl_list_remove(&cursor->tool_axis.link);
wl_list_remove(&cursor->tool_tip.link);
wl_list_remove(&cursor->tool_proximity.link);
wl_list_remove(&cursor->tool_button.link);
wl_list_remove(&cursor->request_set_cursor.link);
@ -1212,7 +1208,7 @@ uint32_t get_mouse_bindsym(const char *name, char **error) {
SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT,
SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA};
return buttons[number - 1];
} else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) {
} else if (has_prefix(name, "BTN_")) {
// Get event code from name
int code = libevdev_event_code_from_name(EV_KEY, name);
if (code == -1) {
@ -1237,7 +1233,7 @@ uint32_t get_mouse_bindcode(const char *name, char **error) {
return 0;
}
const char *event = libevdev_event_code_get_name(EV_KEY, code);
if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
if (!event || !has_prefix(event, "BTN_")) {
*error = format_str("Event code %d (%s) is not a button",
code, event ? event : "(null)");
return 0;

View file

@ -4,7 +4,6 @@
#include <math.h>
#include <assert.h>
#include <wlr/config.h>
#include <wlr/backend/libinput.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
@ -494,6 +493,14 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) {
return input;
}
void input_manager_finish(struct sway_input_manager *input) {
wl_list_remove(&input->new_input.link);
wl_list_remove(&input->virtual_keyboard_new.link);
wl_list_remove(&input->virtual_pointer_new.link);
wl_list_remove(&input->keyboard_shortcuts_inhibit_new_inhibitor.link);
wl_list_remove(&input->transient_seat_create.link);
}
bool input_manager_has_focus(struct sway_node *node) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
@ -578,7 +585,7 @@ void input_manager_configure_all_input_mappings(void) {
void input_manager_apply_input_config(struct input_config *input_config) {
struct sway_input_device *input_device = NULL;
bool wildcard = strcmp(input_config->identifier, "*") == 0;
bool type_wildcard = strncmp(input_config->identifier, "type:", 5) == 0;
bool type_wildcard = has_prefix(input_config->identifier, "type:");
wl_list_for_each(input_device, &server.input->devices, link) {
bool type_matches = type_wildcard &&
strcmp(input_device_get_type(input_device), input_config->identifier + 5) == 0;

View file

@ -4,6 +4,7 @@
#include <wlr/config.h>
#include <wlr/backend/multi.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <xkbcommon/xkbcommon-names.h>
@ -267,6 +268,7 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
const xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) {
for (size_t i = 0; i < keysyms_len; ++i) {
xkb_keysym_t keysym = pressed_keysyms[i];
if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
keysym <= XKB_KEY_XF86Switch_VT_12) {
#if WLR_HAS_SESSION
@ -282,6 +284,36 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
return false;
}
static bool keyboard_execute_pointer_keysyms(struct sway_keyboard *keyboard,
uint32_t time, const xkb_keysym_t *pressed_keysyms, size_t keysyms_len,
enum wl_keyboard_key_state state) {
struct sway_cursor *cursor = keyboard->seat_device->sway_seat->cursor;
for (size_t i = 0; i < keysyms_len; ++i) {
xkb_keysym_t keysym = pressed_keysyms[i];
uint32_t button = wlr_keyboard_keysym_to_pointer_button(keysym);
if (button != 0) {
dispatch_cursor_button(cursor, &keyboard->wlr->base, time, button,
(enum wl_pointer_button_state)state);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
return true;
}
int dx, dy;
wlr_keyboard_keysym_to_pointer_motion(keysym, &dx, &dy);
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && (dx != 0 || dy != 0)) {
dx *= 10;
dy *= 10;
pointer_motion(cursor, time, &keyboard->wlr->base, dx, dy, dx, dy);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
return true;
}
}
return false;
}
/**
* Get keysyms and modifiers from the keyboard as xkb sees them.
*
@ -507,6 +539,11 @@ static void handle_key_event(struct sway_keyboard *keyboard,
keyboard, keyinfo.raw_keysyms, keyinfo.raw_modifiers,
keyinfo.raw_keysyms_len);
}
if (!handled) {
handled = keyboard_execute_pointer_keysyms(keyboard, event->time_msec,
keyinfo.translated_keysyms, keyinfo.translated_keysyms_len,
event->state);
}
if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
// If the pressed event was sent to a client and we have a focused
@ -1028,13 +1065,6 @@ static void sway_keyboard_set_layout(struct sway_keyboard *keyboard,
}
}
// If the seat has no active keyboard, set this one
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
if (current_keyboard == NULL) {
wlr_seat_set_keyboard(seat, keyboard->wlr);
}
if (keymap_changed) {
ipc_event_input("xkb_keymap",
keyboard->seat_device->input_device);
@ -1078,6 +1108,13 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
sway_keyboard_set_layout(keyboard, input_config);
}
// If the seat has no active keyboard, set this one
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
if (current_keyboard == NULL) {
wlr_seat_set_keyboard(seat, keyboard->wlr);
}
wl_list_remove(&keyboard->keyboard_key.link);
wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
keyboard->keyboard_key.notify = handle_keyboard_key;

Some files were not shown because too many files have changed in this diff Show more