rebase: Sway 1.8 (#78)
* build: bump wlroots dependency to 0.16.0 * swaymsg: replace if with switch in pretty_print * swaymsg: add GET_TREE pretty-printing * swaybar: fix errno handling in status_handle_readable If getline fails once, it was not reset before the next getline call. errno is only overwritten by getline on error. * Add cairo_image_surface_create error handling cairo_image_surface_create can fail, e.g. when running out of memory or when the size is too big. Avoid crashing in this case. Closes: https://github.com/swaywm/sway/issues/6531 * build: bump version to 1.8-dev Historically we've been sticking with the last release number in the master branch. However that's a bit confusing, people can't easily figure out whether they're using a release or a work-in-progress snapshot. Only the commit hash appended to the version number may help, but that's not very explicit and disappears when using a tarball. We could bump the version in master to the next release number. However during the RC cycle there would be a downgrade from 1.8 to 1.8-rc1. Also it would be hard to tell the difference between a stable release and an old snapshot. This patch introduces a new pre-release identifier, "dev". It's alphabetically before "rc" so it should be correctly sorted by semver comparisons. "dev" is upgraded to "rc" (and then to stable) when doing a release. The master branch always uses a "dev" version, only release branches use "rc" or stable versions. * [IPC] Add repeat delay/rate info to keyboard Closes #6735 wlroots already has the info in the struct so let's access it and print it out. * input/seat: unset has_focus when focus_stack becomes empty We currently track the focus of a seat in two ways: we use a list called focus_stack to track the order in which nodes have been focused, with the first node representing what's currently focused, and we use a variable called has_focus to indicate whether anything has focus--i.e. whether we should actually treat that first node as focused at any given time. In a number of places, we treat has_focus as implying that a focused node exists. If it's true, we attempt to dereference the return value of seat_get_focus(), our helper function for getting the first node in focus_list, with no further checks. But this isn't quite correct with the current implementation of seat_get_focus(): not only does it return NULL when has_focus is false, it also returns NULL when focus_stack contains no items. In most cases, focus_stack never becomes empty and so this doesn't matter at all. Since focus_stack stores a history of focused nodes, we rarely remove nodes from it. The exception to this is when a node itself goes away. In that case, we call seat_node_destroy() to remove it from focus_stack and free it. But we don't unset has_focus if we've removed the final node! This lets us get into a state where has_focus is true but seat_get_focus() returns NULL, leading to a segfault when we try to dereference it. Fix the issue both by updating has_focus in seat_node_destroy() and by adding an assertion in seat_get_focus() that ensures focus_stack and has_focus are in sync, which will make it easier to track down similar issues in the future. Fixes #6395. [1] There's some discussion in #1585 from when this was implemented about whether has_focus is actually necessary; it's possible we could remove it entirely, but for the moment this is the architecture we have. * swaybar: fix tray_padding vs min-height re: scale Co-authored-by: xdavidwu <xdavidwuph@gmail.com> * swaybar: fix tray item icon scaling, positioning * container: Fix crash when view unmaps + maps quickly Followup on4e4898e90f
. If a view quickly maps and unmaps repeatedly, there will be multiple destroyed containers with same view in a single transaction. Each of these containers will then try to destroy this view, resulting in use after free. The container should only destroy the view if the view still belongs to the container. Simple reproducer: couple XMapWindow + XUnmapWindow in a loop followed by XDestroyWindow. See #6605 * commands/move: Fix crash when pos_y is omitted Fixes #6737 * Destroy sub-surfaces with parent layer-shell surface Closes: https://github.com/swaywm/sway/issues/6337 * Add safety assert in parse_movement_unit Let's add this just in case a caller passes argc == 0. References: https://github.com/swaywm/sway/issues/6737#issuecomment-1008082540 * meson: check: false on run_command Future meson releases will change the default and warns when the implicit default is used, breaking builds. Explicitly set check: false to maintain behavior and silence warnings. * Print deprecation notice when running SUID SUID privilege drop is needed for the "builtin"-backend of libseat, which copied our old "direct" backend behavior for the sake of compatibility and ease of transition. libseat now has a better alternative in the form of seatd-launch. It uses the normal seatd daemon and libseat backend and takes care of SUID for us. Add a soft deprecation warning to highlight our future intent of removing this code. The deprecation cycle is needed to avoid surprises when sway no longer drops privileges. * xdg-shell: use toplevel geometry to adjust the popup box `popup_unconstrain` uses view coordinates to init the output box for popups. However wlroots expects the box to be set in a toplevel surface coordinate system, which is not always equal to view. The difference between those is a window geometry set via xdg-shell. GTK4 reserves some space for client-side decoration and thus has a window with top left corner not matching to (0, 0) of a surface. The box calculated without taking that into account was slightly shifted compared to the actual output and allowed to position part of the popup off screen. * build: fix building with basu02b412a
introduced the use of list for sdbus deps, however it was assuming that all packages which were in a list has a version higher than 239. That is true for libsystemd and libelogind, since they use the same versions, however basu is using version numbers which are way lower than what libsystemd/libelogind are using, so basu only build is failing. * Upgrade for wlroots surface refactoring See [1] for details. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3412 * commands/focus: drop trailing whitespace * input/cursor: count pointer gestures as idle activity Fixes https://github.com/swaywm/sway/issues/6765. * input/cursor: treat swipe begin as idle activity too Accidentally overlooked in fd53f80. * treat fullscreen windows as 'tiled' for commands/focus * transaction: destroying nodes aren't hidden Commit37d7bc6998
("transaction: Only wait for ack from visible views") introduced a check which uses view_is_visible() to check if a view is still visible on the screen. However view_is_visible() will early return in case the node is in the destroying state. This is incorrect for transactions, since a destroying view which is visible will trigger configure events for other clients. This bug was visible when repeatedly opening and closing two views side by side, since we ignore the destroying node we get a frame where the still open view is shown with the old configure values and the rest is the desktop background. The next frame is than correct again. Fix this by considering destroying views as visible, we correctly wait for them and send the configure events to other views in time, fixing the background flicker. Fixes #6473 * build: execute wlroots subproject before finding deps wlroots often requires dependencies more recent than Sway's. Executing the wlroots subproject first will give Meson a chance to find these newer dependencies, possibly via subprojects. The subproject will override the "wlroots" dependency when executed, so we don't need to use get_variable anymore. References: https://github.com/swaywm/sway/pull/6498#issuecomment-1001746017 * tray: do not render passive items https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierItem/#org.freedesktop.statusnotifieritem.status * cmd/swap: error on swapping a container with itself * input/cursor: pass through pointer hold gestures This just follows swaywm/wlroots#3047, so `wl_pointer_gestures_v1` clients can be notified of these events. * swaynag: remove buffer destruction condition An address of a variable can never be NULL, so checking it doesn't make sense; and `destroy_buffer()` can operate on already destroyed buffers anyway. Fixes #6780 * Use bools for CLI flags * xwayland: listen to `request_activate` event When REAPER submenu is closed `XCB_CLIENT_MESSAGE` with type `NET_ACTIVE_WINDOW` is sent to set focus to parent menu. Closes: https://github.com/swaywm/sway/issues/6324 * chore: chase wlr_output_layout_get_box() update https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3439 * Chase wlroots xdg-shell refactor * Minor update to focus_on_window_activation Removed xwayland limitation since wayland clients are supported via xdg-activation. * Translated README into Italian * readme: add link to Italian translation * readme: sort language list alphabetically * readme: use relative links for translations * xdg-shell: use wlr_xdg_toplevel in sway_view Improved type safety. Closes: https://github.com/swaywm/sway/issues/6813 * xdg-shell: use wlr_xdg_popup in sway_xdg_popup Improved type safety. * Fix snprintf compiler warning * Remove all sprintf calls Replace them with snprintf, which ensures buffer overflows won't happen. * sway/commands: add missing wlr_keyboard interface include in xkb_switch_layout * sway/input: use wlr_input_device from input device base * Remove some erroneous apostrophes in comments * Don't enter seatop_move_floating when fullscreen Currently, a floating window that's been fullscreened can send us xdg_toplevel::move, and we'll enter seatop_move_floating, which lets us drag the surface around while it's fullscreen. We don't want this--fullscreen surfaces should always be aligned to the screen--so add the same check that seatop_default already does when entering this mode. Tested with Weston's weston-fullscreen demo, which sends a move request if you click anywhere on its surface. * swaynag: die on all allocation failures * sway/input: don't pass possibly invalid modifiers pointer active_keyboard may be NULL, in which case an invalid pointer could be passed to wlr_input_method_keyboard_grab_v2_send_modifiers. This procedure call is unnecessary since wlroots commit 372a52ec "input method: send modifiers in set_keyboard", so the call can simply be removed. Fixes #6836. * sway/input: destroy sway_switch properly Fix: #6861 Added seat_device_destroy function to seat_device_destroy function. * commands/focus: fix segfault when no container is already focused. Fixes #6690. * Remove WLR_SWITCH_STATE_TOGGLE usage Ref [1]. [1]:4792446ee8
* Replace pcre with pcre2 Closes: https://github.com/swaywm/sway/issues/6838 * swaybar: remove swaybar_output.input_region No need to keep the region around, we can immediately destroy it after the wl_surface.set_input_region request. * swaybar: set opaque region When the background color is fully opaque, set the surface's opaque region to the whole surface. * Updating criteria checking with PCRE2 * swaynag: allocate button_details with details They are used together, so it doesn't make sense to allocate them separately. * swaynag: statically allocate button_close, and move declaration Every swaynag has a close button, so it doesn't make sense to allocate it dynamically. The declaration is moved later to when it is actually needed. * swaynag: remove unnecessary zero of swaynag struct Global variables are initialized to 0. * swaynag: remove redundant status variables in main Instead, we just use `status` for all failures. * remove unnecessary strlen call * sway/input/cursor: take device mm size from wlr_tablet * sway/input/seat: take output name from specialized input device * sway/input: follow up wlroots input device events renaming * sway/input: fix bad position of wlr_drag * sway/input: wlr_seat_keyboard() now takes wlr_keyboard * bash-completion: localize variables * sway/main: move constants off the stack This makes stack traces from gdb slightly easier to read. * Fix farsi label * Avoid format-truncation warning The existing code gives this error when compiled with GCC 12: ../sway/server.c: In function ‘server_init’: ../sway/server.c:217:75: error: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 8 [-Werror=format-truncation=] 217 | snprintf(name_candidate, sizeof(name_candidate), "wayland-%d", i); | ^~ ../sway/server.c:217:66: note: directive argument in the range [-2147483647, 32] 217 | snprintf(name_candidate, sizeof(name_candidate), "wayland-%d", i); | ^~~~~~~~~~~~ ../sway/server.c:217:17: note: ‘snprintf’ output between 10 and 20 bytes into a destination of size 16 217 | snprintf(name_candidate, sizeof(name_candidate), "wayland-%d", i); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Because i is never negative, this is a false positive, but it is easy to change i to unsigned to silence the error. * Shuffle variables to satisfy -Werror=restrict This also fixes an invalid strlen invocation on uninitialized memory. * layer_shell: keep output non-NULL wherever possible Our layer shell implementation assigns every layer surface to an output on creation. It tracks this output using the output field on the underlying wlr_layer_surface_v1 structure. As such, much of the existing code assumes that output is always non-NULL and omits NULL checks accordingly. However, there are currently two cases where we destroy a sway_layer_surface and output is NULL. The first is when we can't find an output to assign the surface to and destroy it immediately after creation. The second is when we destroy a surface in response to its output getting destroyed, as we set output to NULL in handle_output_destroy() before we call wlr_layer_surface_v1_destroy(), which is what calls the appropriate unmap and destroy callbacks. The former case doesn't cause any problems, since we haven't even allocated a sway_layer_surface at that point or registered any callbacks. The latter case, however, currently triggers a crash (#6120) if a popup is visible, since our popup_handle_unmap() implementation can't handle a NULL output. To fix this issue, keep output set until right before we free the sway_layer_surface. All we need to do is remove some of the cleanup logic from handle_output_destroy(), since as of commitc9060bcc12
("layer-shell: replace close() with destroy()") that same logic is guaranteed to be happen later when wlroots calls handle_destroy() as part of wlr_layer_surface_v1_destroy(). This lets us remove some NULL checks from other unmap/destroy callbacks, which is nice. We also don't need to check that the wlr_output points to a valid sway_output anymore, since we unset that pointer after disabling the output as of commita0bbe67076
("Address emersions comments on output re-enabling") Just to be safe, I've added assertions that the wlr_output is non-NULL wherever we use it. Fixes #6120. * Chase wlroots X11 hints update * Add Swedish README * Support cursor capture in grimshot Refactor argument parser Bring back `sh` compatibility Default to NOTIFY=no * Update grimshot.1.scd Fixed typo. The object is **files**, which is plural. **image** modifies files; it's not countable. * xkb_switch_layout: fix relative layout switches Fixes #6011 * Implement ext-session-lock-v1 * Avoid inspecting a NULL view in seat_set_focus Fixes #6968 * swaynag: do error checking and rename read_from_stdin read_from_stdin not only read from stdin, but trimming trailing newlines, so rename it to reflect this. * swaynag: improve robustness when loading config * swaynag: combine consecutive declaration/assignments * config: Remove unused mouse binding structure Mouse bindings are handled alongside normal bindings. Remove the unused separate data structure definition to avoid confusion. Signed-off-by: Michael Weiser <michael.weiser@gmx.de> * Replace strncpy with memcpy strncpy is useless here, is dangerous because it doesn't guarantee that the string is NUL-terminated and causes the following warning: ../sway/criteria.c: In function ‘criteria_parse’: ../sway/criteria.c:712:25: error: ‘strncpy’ destination unchanged after copying no bytes [-Werror=stringop-truncation] 712 | strncpy(value, valuestart, head - valuestart); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Add descriptions for `stacking` and `tabbed` layouts Resolves #5918 * man: Fix trailing spaces * server: request xdg-shell v2 Wlroots does not yet support the newer xdg-shell versions and now requires the compositor to set the supported xdg-shell version during creation. Set this to v2 for sway as well. Fixes https://github.com/swaywm/sway/issues/7001 * realtime: request SCHED_RR using CAP_SYS_NICE Try to gain SCHED_RR (round-robin) realtime scheduling privileges before starting the server. This requires CAP_SYS_NICE on Linux systems. We additionally register a pthread_atfork callback which resets the scheduling class back to SCHED_OTHER (the Linux system default). Due to CAP_SYS_NICE, setting RLIMIT_RTPRIO has no effect on the process as documented within man 7 sched (from Linux): Privileged (CAP_SYS_NICE) threads ignore the RLIMIT_RTPRIO limit; as with older kernels, they can make arbitrary changes to scheduling policy and priority. See getrlimit(2) for further information on RLIMIT_RTPRIO Note that this requires the sway distribution packagers to set the CAP_SYS_NICE capability on the sway binary. Supersedes #6992 * ext-session-lock: disable direct scan-out when locked * Polish the language in README.zh-CN.md & sync with English one Co-Authored-By: Urey. Xue <urey.s.knowledge@gmail.com> * De-duplicate IPC output descriptions * Handle NULL output make/model/serial * chore: chase wlroots xdg-shell update * xdg-shell: schedule a configure on maximize request This commit reverts 03879290dbee26127f6867ef60bc2a7f9a6c8c5f and fc84bcb7fb0ffa29b1f9bed287762241a3473803. * Add a Hindi (हिन्दी) translation to the README Hindi is one of the most prominent languages of the Indian Subcontinent. This commit adds the translation of the README into the Hindi language. Some of the words are still written in English because there wasn't an appropriate technical term of the word in the language. Co-authored-by: Surendrajat <surendrajat@protonmail.com> * sway: add bindgesture command Co-authored-by: Michael Weiser <michael.weiser@gmx.de> * build: link with -pthread Fixes the following FreeBSD error: ld: error: undefined symbol: pthread_getschedparam >>> referenced by realtime.c:25 (../sway/realtime.c:25) >>> sway/sway.p/realtime.c.o:(set_rr_scheduling) Fixes: a3a82efbf6b5 ("realtime: request SCHED_RR using CAP_SYS_NICE") * ipc: remove chatty debug log messages These aren't particularly useful, and clobber the debug logs. * Refuse to start when SUID is detected This ensures that those surprised by the deprecation of SUID operation receive an error rather than accidentally having sway run as root. This detection will be removed in a future release. * swaynag: move close_button up to fix SIGSEGV When swaynag_parse_options encounters '--dismiss-button' (or its shorthand '-s'), it sets the text of the first button in the swaynag.buttons list, which is expected to exist and to be the dismiss button, to the one passed by the user. Commit 4780afb68b4ee2cdf0e4925f40cf885819f8a74a ("swaynag: statically allocate button_close, and move declaration") moved the list initialization to after swaynag_parse_options is called which made that code fail. For example, the command 'swaynag --dismiss-button Dismiss' crashes and 'swaynag --message Message --button Yes "" --dismiss-button Dismiss' shows the wrong buttons. Move it back to before swaynag_parse_options is called. * config/output: use wlr_output_commit_state This makes the code more robust because we don't potentially leave bad state in wlr_output.pending behind anymore. This also fixes a bug. Closes: https://github.com/swaywm/sway/issues/7043 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3610 * Allocate enough space for `cmd_results->error` * Remove access to wlr_input_device union References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3626 Closes: https://github.com/swaywm/sway/issues/7077 * Rename dpms output command to power The "dpms" command refers to VESA Display Power Management Signaling, a deprecated standard. It's superseded by VESA DPM. Instead of tying out command name to a particular standard, use the neutral term "power". * Strip quotes in bindsym --input-device=... If the input device is quoted, which is common when using variables in the config file, those quotes must be ignored here, or the input device will be ignored. Fixes #7029. * Avoid unecessary string copy * Reject font values that are invalid for pango Use pango to parse font configuration early, and reject the command as invalid if the value is invalid for pango. Since we're already parsing the font into a `PangoFontDescription`, keep that instance around and avoid re-parsing the font each time we render text. Fixes: https://github.com/swaywm/sway/issues/6805 * Reuse parsed PangoFontDescription Avoids parsing the configured font each time text is rendered. * ipc: add "power" to output reply * config.in: switch to `output power` * Remove internal references to DPMS While at it, use an int for the config field, just like we do for all other fields. * fix: remove redundant empty statement in main.c This semi-colon looks like a typo. Luckily, it has no effect on the code as it's treated as an empty statement leading the switch case. Really straightforward nitpick change, was just something I was confused by when reading over the code. * input: chase delta_discrete semantics change * swaymsg: fix floating_nodes being ignored Fix floating_nodes being ignored in pretty_print_tree. * ipc: make get_deco_rect check config->hide_lone_tab Without this, the `IPC_GET_TREE` ipc call would return false information about the container's `deco_rect` and `rect` properties if `hide_edge_borders --i3` was in effect. * grimshot: fix tilde expansion within quotes * Enable single-pixel-buffer-v1 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3428 * sway-output.5: improve display of parameter Since "width" and "height" are separate parameters, show them as such. * man: sway(5) move fixes * ipc: drop WLR_OUTPUT_ADAPTIVE_SYNC_UNKNOWN case This has been removed from wlroots. * config/output: test adaptive sync Required for [1]. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3637 * Fix crash in xdg_activation_v1.c wlr_xdg_surface_from_wlr_surface() can return a NULL pointer, so check for NULL before dereferencing it. * sway: Add non-desktop-output type Currently, when encountering a non-desktop display, sway offers the output for leasing and returns without storing it in a sway specific output type like `struct sway_output`. Additionally, running `swaymsg -t get_outputs` doesn't show non-desktop outputs. This commit stores the non-desktop outputs into a struct called `sway_output_non_desktop`, and adds them to a list on `sway_root` * sway: add non-desktop outputs to json when running `swaymsg -t get_outputs` * swaymsg: show non-desktop property when pretty printing outputs * man: Add XWayland information * ipc: expose mode picture aspect ratio * swaymsg: show mode picture aspect ratio * build: simplify protocol paths No need for arrays here. * sway/commands/output: Add command for unplugging non-physical outputs * Improve Japanese translation * allow pointer_constraints on layer_shell surfaces * check for NULL * use seat directly * Use keyboard_state.focused_surface directly * input: focus floating container when clicked on border Fixes #7209. * input: focus container when scrolling on titlebar Fixes #6503. * Fix leaks in criteria_destroy() * Avoid double free in criteria_destroy() * Add support for ext-idle-notify-v1 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3753 * input: tweak focus behavior to allow focusing parent containers Sway focuses the inactive child when focusing split containers. However, there is currently no way to focus the parent container itself by mouse. A user must use the keyboard to do so. This commit maintains the current behavior, but makes it such that a second click on the split container titlebar (i.e., after its children are visible) focuses the split container itself. * Fix keymap being NULL and segfaulting on dev add Moved `libinput_config` to the callers of `sway_input_configure_libinput_device` so that we send the event after the added event. * Rework session lock keyboard focus handling When removing outputs, it is possible to end up in a situation where none of the session lock client's surfaces have keyboard focus, resulting in it not receiving keyboard events. Track the focused surface and update it as needed on surface destroy. * Fix focus tracking when session lock is active Remove the incorrect attempt to block focus changes when an input grab is present and replace it with the same logic used for layer_shell-based screen lockers: restore the focus after changing it. This fixes a use-after-free of seat->workspace if outputs are destroyed while a screen lock is enabled. * container_floating_set_default_size: Store workspace size box on the stack * Support libinput's 1.21 new dwtp option Support the new dwtp (disable while trackpointing) option introduced in libinput 1.21, allowing users to control whether the trackpoint (like those in Thinkpads, but not only) should be disabled while using the keyboard/touchpad. See: https://gitlab.freedesktop.org/libinput/libinput/-/issues/731 * tree: support formatting null titles Any windows that have never had a title set visually behave closer to that of an empty title, but are unformattable, as the code bails out early on a NULL title. * criteria: allow matching on empty (NULL) titles * criteria: allow matching for NULL string criteria * ci: install hwdata * Use wl_signal_emit_mutable() This function fixes segfaults when emitting a signal potentially removes arbitrary listeners. * Use wlr_damage_ring wlr_output_damage is to be replaced with wlr_damage_ring, so use that. * lock: fix crash on output destroy Closes: https://github.com/swaywm/sway/issues/7120 * container_get_siblings: handle NULL workspace * ci: checkout wlroots 0.16.0 * workspace_create: Don't allow NULL name (cherry picked from commit 34933bb84350fe805d82276ea02d5732546e9993) * output: set damage ring bounds to pixel values Fixes: https://github.com/swaywm/sway/issues/7254 (cherry picked from commit 85005b52fe5b832e4ea914fa28048b0c5c803769) * Use shm_open instead of mkstemp shm_open is more reliable because it does not require a writeable filesystem folder, unlike mkstemp. (cherry picked from commit e2bc8866f46701e9c825ad7fa5baac02b2e4898f) * build: drop wayland-scanner fallback (cherry picked from commit 366f6ef3d31688631dc453028e108f98a1d7ab57) * build: unify server & client protocol generation No need to make a difference here, let's just generate header files for both. (cherry picked from commit 5be5a038da8a3789a19945719f2a27233291445d) * build: drop "server" from target name for protocol code (cherry picked from commit e5475d9310941ce88ed016ce1515b36e3a440252) * build: drop intermediate libraries for protocols (cherry picked from commit af8a5a8918ef42336194fb1077b008a736de7af9) * root: move the workspace matching code to its own file This removes the pid_workspace bits from tree/root before it gets too interesting. No functional change. (cherry picked from commit eb5021ef990fb29ff86544aea58d687ad62c757a) * node: prettify node type names (cherry picked from commit 1c4b94ae3ca94b972410c80a61404a347af1ee68) * launcher: track workspaces by node This removes the need to rename the pid_workspaces when a workspace is renamed. It also opens the possibility of tracking other node types. Tracking containers would allow application to be placed correctly in the container tree even if the user has moved their focus elsewhere since it was launched. (cherry picked from commit 3b49f2782e8faf68766269b9c7390b16e25ae824) * launcher: use xdga tokens This reuses wlroots token tracking for workspace matching. It doesn't export any xdga tokens for clients yet. (cherry picked from commit bd66f4943da1c96edc3ba49573e27b42b688c543) * launcher: rename pid_workspace to launcher_ctx Soon we will match views with more than just a pid. (cherry picked from commit d75c9f9722389d441fd24bd490c5cf12c4bef39a) * view: associate launch contexts with views Views now maintain a reference to a launch context which, as a last resort, is populated at map time with a context associated with its pid. This opens the possibility of populating it before map via another source, e.g. xdga-tokens or configuration. (cherry picked from commit 864b3a9a18f236f92f1898bb44ab977ceaebfd68) * launcher: initialize launcher_ctxs once on startup (cherry picked from commit 66568508c06267445489d655c91c94a34d6d9ffe) * launcher: fudge the interface a bit We want to create a context before knowing the pid it will match with. (cherry picked from commit bdeb9f95651f6c99cc2f4cfb59020ddee202cf36) * launcher: export xdga tokens and use them for workspace matching (cherry picked from commit 30ad4dc4a5a41ce7c7aa85096a6e18f374172983) * launcher: export X startup ids and use them for workspace matching (cherry picked from commit 28fda4c0d38907fab94dc7d82c9dcf0754748b4e) * swaybar: Prioritize hotspot events to bar bindings This is consistent with i3bar's behaviour, and for example, allows binding a command to button1, while still being able to click on tray icons or other zones on the bar's status line which may have their own bindings. E.g., in Sway, without this commit, this config. makes tray icons unclickable: bar { # ... bindsym button1 exec swaynag -m You_clicked_the_tray._Want_some_help? } But the same configuration in i3 (with i3-nagbar) keeps tray items clickable. Signed-off-by: Joan Bruguera <joanbrugueram@gmail.com> (cherry picked from commit 53f9dbd424dc173a85c9f4cd30802259d38b1ef4) * swaybar: Make hotspots block bar release bindings The previous commit prioritized hotspots before bar bindings for press events, which matches i3's behaviour. However, since hotspots don't need to do any processing on release events, those were not handled, and simply fell through to `bindsym --release` bar bindings (if any). This is counter-intuitive, and doesn't match i3's behaviour. Instead in case a hotspot handles the press event, it should also handle the release event, doing nothing, but blocking the event from triggering a --release bar binding. E.g., in Sway, without this commit, this config. shows a text on tray clicks: bar { # ... bindsym --release button1 exec swaynag -m I_got_the_release_event. } But the same configuration in i3 (with i3-nagbar) doesn't show the text. Signed-off-by: Joan Bruguera <joanbrugueram@gmail.com> (cherry picked from commit 94b69acf0d7b26ee5af2172300cb18473508da76) * build: drop unused wayland-egl dependency (cherry picked from commit 37e4a3d6370dc6ba2b0877d588845c06781e880e) * build: bump version to 1.8-rc1 * Fix build on Debian Stable (cherry picked from commit dca0bb5749bc16f91ab964fc1b06ebb9a453368f) * build: fix have_xwayland when xcb-icccm is not found xcb-icccm is required to build Xwayland support. Backported from commit d41f11e6bd8cef80f02dda4c66d4a31611aed753. * build: bump version to 1.8-rc2 * seat: Avoid sending redundant keymaps on reload When we reload the config, we reset every input device and re-apply configuration from the config file. This means that the keyboard keymap is updated at least once during config reload, more if the config file contains keyboard configuration. When they keyboard keymap changes and is updated through wlr_seat, the keymap ends up sent to every keyboard bound in every client, seemingly multiple times. On an x230 of mine with a keyboard layout set in the config file, I see 42 keymap events sent to foot on config reload. Reduce events from keyboard configurations by skipping all but the currently active keyboard for the seat, and by clearing the active keyboard during input manager device reset. After this change, I only see a single just-in-time keymap event. Fixes: https://github.com/swaywm/sway/issues/6654 * criteria: be lenient on window_role and instance too * build: bump version to 1.8-rc3 * commands/move: Warp cursor after moving workspace to another output This makes sway's behavior consistent with i3 when `mouse_warping` is set to any value besides `none`. Fixes #7027. (cherry picked from commit e3c63bf58d0744dfb436f0f38442ce3735e40f47) * seat: Set keyboard if seat keyboard is NULL sway sends wl_keyboard.enter on seat focus change and when a keyboard active on a seat is configured. If all keyboards are removed and a keyboard is added back without changing the focused client, no new notify event would be sent despite having keyboard focus. This could lead to key events without notify, which is a protocol violation. As a quick fix, when configuring a keyboard on a seat where no keyboard is currently active, activate the keyboard so that a focused surface will receive a notify event. Regressed by: e1b268af98edeb09e570e8855ef64f0719cbafe2 Closes: https://github.com/swaywm/sway/issues/7330 (cherry picked from commit 1ade0ce753dc5f588584f444ce80d27c3b1e4300) * build: bump version to 1.8-rc4 * swaynag: fix NULL font description The font description was only set if provided on the CLI. It was left NULL for the defaults and when reading from the config file. Closes: https://github.com/swaywm/sway/issues/7186 (cherry picked from commit fd0af78e43f4dd67a404f475c676b25ae38a4b82) * build: bump version to 1.8 * Removed other README languages * Fixed build issues * Removed alpha from render_data struct * Updated PKGBUILDs and COPR spec * Update sway/desktop/render.c Co-authored-by: Alexis Tacnet <alexistacnet@gmail.com> * Fixed deco_data not being initialized properly * Replaced wlr_egl_(make|unset)_current with eglMakeCurrent * Added matrix_projection into fx_renderer Signed-off-by: Michael Weiser <michael.weiser@gmx.de> Co-authored-by: Sefa Eyeoglu <contact@scrumplex.net> Co-authored-by: Simon Ser <contact@emersion.fr> Co-authored-by: Seth Barberee <seth.barberee@gmail.com> Co-authored-by: Thomas Hebb <tommyhebb@gmail.com> Co-authored-by: Nathan Schulte <nmschulte@gmail.com> Co-authored-by: xdavidwu <xdavidwuph@gmail.com> Co-authored-by: David Rosca <nowrep@gmail.com> Co-authored-by: David96 <david@hameipe.de> Co-authored-by: Kenny Levinsen <kl@kl.wtf> Co-authored-by: Aleksei Bavshin <alebastr89@gmail.com> Co-authored-by: Kirill Chibisov <contact@kchibisov.com> Co-authored-by: Tudor Brindus <me@tbrindus.ca> Co-authored-by: Patrick Hilhorst <git@hilhorst.be> Co-authored-by: Rouven Czerwinski <rouven@czerwinskis.de> Co-authored-by: Tobias Bengfort <tobias.bengfort@posteo.de> Co-authored-by: Ronan Pigott <rpigott@berkeley.edu> Co-authored-by: Kirill Primak <vyivel@eclair.cafe> Co-authored-by: Tuomas Yrjölä <mail@yrhki.fi> Co-authored-by: Kirill Primak <vyivel@posteo.net> Co-authored-by: Alexander Browne <elcste@users.noreply.github.com> Co-authored-by: Marco Rubin <20150305+Rubo3@users.noreply.github.com> Co-authored-by: Muhamed Hobi <woohoomoo2u@gmail.com> Co-authored-by: Simon Zeni <simon@bl4ckb0ne.ca> Co-authored-by: Nihal Jere <nihal@nihaljere.xyz> Co-authored-by: Alexander Gramiak <agrambot@gmail.com> Co-authored-by: Moon Sungjoon <sumoon@seoulsaram.org> Co-authored-by: Nicolas Avrutin <nicolas@avrutin.net> Co-authored-by: ndren <andreien@ctemplar.com> Co-authored-by: Bill Li <billli11hkb@gmail.com> Co-authored-by: Leonardo Hernández Hernández <leohdz172@protonmail.com> Co-authored-by: Oğuz Ersen <oguz@ersen.moe> Co-authored-by: Manuel Stoeckl <code@mstoeckl.com> Co-authored-by: Yasin Silavi <59373143+sttatusx@users.noreply.github.com> Co-authored-by: Daniel De Graaf <code@danieldg.net> Co-authored-by: kraftwerk28 <kefirchik3@gmail.com> Co-authored-by: Eskil <67291226+eschillus@users.noreply.github.com> Co-authored-by: Alice Carroll <git@alice-carroll.pet> Co-authored-by: Alan <51193876+Pound-Hash@users.noreply.github.com> Co-authored-by: Victor Makarov <vitja.makarov@gmail.com> Co-authored-by: Michael Weiser <michael.weiser@gmx.de> Co-authored-by: -k <slowdive@me.com> Co-authored-by: Hongyi <61831273+FrozenArcher@users.noreply.github.com> Co-authored-by: Urey. Xue <urey.s.knowledge@gmail.com> Co-authored-by: LordRishav <75823494+LordRishav@users.noreply.github.com> Co-authored-by: Surendrajat <surendrajat@protonmail.com> Co-authored-by: Florian Franzen <Florian.Franzen@gmail.com> Co-authored-by: Greg Depoire--Ferrer <greg@gregdf.com> Co-authored-by: Thomas Jost <schnouki@schnouki.net> Co-authored-by: Hugo Osvaldo Barrera <hugo@barrera.io> Co-authored-by: zkldi <ktchidev@gmail.com> Co-authored-by: llyyr <llyyr.public@gmail.com> Co-authored-by: Baltazár Radics <baltazar.radics@gmail.com> Co-authored-by: Martin Michlmayr <tbm@cyrius.com> Co-authored-by: Filip Szczepański <jazz2rulez@gmail.com> Co-authored-by: Alex Maese <memaese@hotmail.com> Co-authored-by: マリウス <marius@xn--gckvb8fzb.com> Co-authored-by: Andri Yngvason <andri@yngvason.is> Co-authored-by: ohno418 <yutaro.ono.418@gmail.com> Co-authored-by: Ferdinand Schober <ferdinand.schober@fau.de> Co-authored-by: cparm <armelcadetpetit@gmail.com> Co-authored-by: Yaroslav de la Peña Smirnov <yps@yaroslavps.com> Co-authored-by: Alexander Orzechowski <orzechowski.alexander@gmail.com> Co-authored-by: pudiva chip líquida <pudiva@skylittlesystem.org> Co-authored-by: Puck Meerburg <puck@puckipedia.com> Co-authored-by: Callum Andrew <calcium@mailbox.org> Co-authored-by: Ronan Pigott <ronan@rjp.ie> Co-authored-by: Joan Bruguera <joanbrugueram@gmail.com> Co-authored-by: nerdopolis <bluescreen_avenger@verizon.net> Co-authored-by: Ankit Pandey <anpandey@protonmail.com> Co-authored-by: Alexis Tacnet <alexistacnet@gmail.com>
This commit is contained in:
parent
0365cc5d50
commit
94ebb45ee3
|
@ -1,7 +1,6 @@
|
||||||
# SwayFX: A Beautiful Sway Fork
|
# SwayFX: A Beautiful Sway Fork
|
||||||
|
|
||||||
![](assets/swayfx_screenshot.jpg)
|
![swayfx_screenshot](assets/swayfx_screenshot.jpg)
|
||||||
|
|
||||||
Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and replaces it with our fx_renderer, capable of rendering with fancy GLES2 effects. This, along with a couple of minor changes, expands sway's featureset to include the following:
|
Sway is an incredible window manager, and certainly one of the most well established wayland window managers. However, it is restricted to only include the functionality that existed in i3. This fork ditches the simple wlr_renderer, and replaces it with our fx_renderer, capable of rendering with fancy GLES2 effects. This, along with a couple of minor changes, expands sway's featureset to include the following:
|
||||||
|
|
||||||
+ **Anti-aliased rounded corners, borders, and titlebars**
|
+ **Anti-aliased rounded corners, borders, and titlebars**
|
||||||
|
@ -51,7 +50,7 @@ Install dependencies:
|
||||||
* wlroots
|
* wlroots
|
||||||
* wayland
|
* wayland
|
||||||
* wayland-protocols \*
|
* wayland-protocols \*
|
||||||
* pcre
|
* pcre2
|
||||||
* json-c
|
* json-c
|
||||||
* pango
|
* pango
|
||||||
* cairo
|
* cairo
|
||||||
|
@ -78,9 +77,9 @@ SwayFX will drop root permissions shortly after startup.
|
||||||
SwayFX would love to receive any new features that you're willing to build! Generally, we'd like to focus on eye-candy type improvements to keep our scope appropriate. If you'd like to build something that you think may be out of that focus, please raise an issue and we can discuss whether or not it will fit within this project.
|
SwayFX would love to receive any new features that you're willing to build! Generally, we'd like to focus on eye-candy type improvements to keep our scope appropriate. If you'd like to build something that you think may be out of that focus, please raise an issue and we can discuss whether or not it will fit within this project.
|
||||||
|
|
||||||
Here's a quick outline of where most of our changes lie vs the main sway repository:
|
Here's a quick outline of where most of our changes lie vs the main sway repository:
|
||||||
|
|
||||||
+ `sway/desktop/render.c`: the file that handles calling `fx_renderer` to render to the screen, handles damage tracking and scaling
|
+ `sway/desktop/render.c`: the file that handles calling `fx_renderer` to render to the screen, handles damage tracking and scaling
|
||||||
+ `sway/desktop/fx_renderer.c`: the meat and potatoes of this project, structured as similarly to wlr_renderer as possible
|
+ `sway/desktop/fx_renderer.c`: the meat and potatoes of this project, structured as similarly to wlr_renderer as possible
|
||||||
+ `sway/desktop/shaders`: where all of the shaders that fx_renderer uses live
|
+ `sway/desktop/shaders`: where all of the shaders that fx_renderer uses live
|
||||||
|
|
||||||
Please join our (for the time being very small) Discord server for development chatter! https://discord.gg/jVjjFdcN
|
Please join our (for the time being very small) Discord server for development chatter! https://discord.gg/jVjjFdcN
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@ depends=(
|
||||||
"libxcb"
|
"libxcb"
|
||||||
"libxkbcommon.so"
|
"libxkbcommon.so"
|
||||||
"pango"
|
"pango"
|
||||||
"pcre"
|
"pcre2"
|
||||||
"ttf-font"
|
"ttf-font"
|
||||||
"wlroots<0.16"
|
"wlroots<0.17"
|
||||||
)
|
)
|
||||||
optdepends=(
|
optdepends=(
|
||||||
"alacritty: Terminal emulator used by the default config"
|
"alacritty: Terminal emulator used by the default config"
|
||||||
|
|
|
@ -23,9 +23,9 @@ depends=(
|
||||||
"libxcb"
|
"libxcb"
|
||||||
"libxkbcommon.so"
|
"libxkbcommon.so"
|
||||||
"pango"
|
"pango"
|
||||||
"pcre"
|
"pcre2"
|
||||||
"ttf-font"
|
"ttf-font"
|
||||||
"wlroots<0.16"
|
"wlroots<0.17"
|
||||||
)
|
)
|
||||||
optdepends=(
|
optdepends=(
|
||||||
"alacritty: Terminal emulator used by the default config"
|
"alacritty: Terminal emulator used by the default config"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
### CHANGE THESE VARIABLES BEFORE RELEASE:
|
### CHANGE THESE VARIABLES BEFORE RELEASE:
|
||||||
# Change to current Sway base version!
|
# Change to current Sway base version!
|
||||||
%global SwayBaseVersion 1.7
|
%global SwayBaseVersion 1.8
|
||||||
# Change to current SwayFX tag!
|
# Change to current SwayFX tag!
|
||||||
%global Tag 0.1.1
|
%global Tag 0.1.1
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ BuildRequires: pkgconfig(gdk-pixbuf-2.0)
|
||||||
BuildRequires: pkgconfig(json-c) >= 0.13
|
BuildRequires: pkgconfig(json-c) >= 0.13
|
||||||
BuildRequires: pkgconfig(libdrm)
|
BuildRequires: pkgconfig(libdrm)
|
||||||
BuildRequires: pkgconfig(libevdev)
|
BuildRequires: pkgconfig(libevdev)
|
||||||
BuildRequires: pkgconfig(libinput) >= 1.6.0
|
BuildRequires: pkgconfig(libinput) >= 1.21.0
|
||||||
BuildRequires: pkgconfig(libpcre)
|
BuildRequires: pkgconfig(libpcre2)
|
||||||
BuildRequires: pkgconfig(libsystemd) >= 239
|
BuildRequires: pkgconfig(libsystemd) >= 239
|
||||||
BuildRequires: pkgconfig(libudev)
|
BuildRequires: pkgconfig(libudev)
|
||||||
BuildRequires: pkgconfig(pango)
|
BuildRequires: pkgconfig(pango)
|
||||||
|
@ -35,7 +35,7 @@ BuildRequires: pkgconfig(wayland-cursor)
|
||||||
BuildRequires: pkgconfig(wayland-egl)
|
BuildRequires: pkgconfig(wayland-egl)
|
||||||
BuildRequires: pkgconfig(wayland-server) >= 1.20.0
|
BuildRequires: pkgconfig(wayland-server) >= 1.20.0
|
||||||
BuildRequires: pkgconfig(wayland-protocols) >= 1.24
|
BuildRequires: pkgconfig(wayland-protocols) >= 1.24
|
||||||
BuildRequires: (pkgconfig(wlroots) >= 0.15.0 with pkgconfig(wlroots) < 0.16)
|
BuildRequires: (pkgconfig(wlroots) >= 0.16.0 with pkgconfig(wlroots) < 0.17)
|
||||||
BuildRequires: pkgconfig(xcb)
|
BuildRequires: pkgconfig(xcb)
|
||||||
BuildRequires: pkgconfig(xkbcommon)
|
BuildRequires: pkgconfig(xkbcommon)
|
||||||
# Dmenu is the default launcher in sway
|
# Dmenu is the default launcher in sway
|
||||||
|
|
|
@ -1,50 +1,43 @@
|
||||||
#define _POSIX_C_SOURCE 200809
|
#define _POSIX_C_SOURCE 200809
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <pango/pangocairo.h>
|
#include <pango/pangocairo.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "pool-buffer.h"
|
#include "pool-buffer.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static int create_pool_file(size_t size, char **name) {
|
static int anonymous_shm_open(void) {
|
||||||
static const char template[] = "sway-client-XXXXXX";
|
int retries = 100;
|
||||||
const char *path = getenv("XDG_RUNTIME_DIR");
|
|
||||||
if (path == NULL) {
|
|
||||||
fprintf(stderr, "XDG_RUNTIME_DIR is not set\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t name_size = strlen(template) + 1 + strlen(path) + 1;
|
do {
|
||||||
*name = malloc(name_size);
|
// try a probably-unique name
|
||||||
if (*name == NULL) {
|
struct timespec ts;
|
||||||
fprintf(stderr, "allocation failed\n");
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
return -1;
|
pid_t pid = getpid();
|
||||||
}
|
char name[50];
|
||||||
snprintf(*name, name_size, "%s/%s", path, template);
|
snprintf(name, sizeof(name), "/sway-%x-%x",
|
||||||
|
(unsigned int)pid, (unsigned int)ts.tv_nsec);
|
||||||
|
|
||||||
int fd = mkstemp(*name);
|
// shm_open guarantees that O_CLOEXEC is set
|
||||||
if (fd < 0) {
|
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||||
return -1;
|
if (fd >= 0) {
|
||||||
}
|
shm_unlink(name);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sway_set_cloexec(fd, true)) {
|
--retries;
|
||||||
close(fd);
|
} while (retries > 0 && errno == EEXIST);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ftruncate(fd, size) < 0) {
|
return -1;
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void buffer_release(void *data, struct wl_buffer *wl_buffer) {
|
static void buffer_release(void *data, struct wl_buffer *wl_buffer) {
|
||||||
|
@ -62,17 +55,20 @@ static struct pool_buffer *create_buffer(struct wl_shm *shm,
|
||||||
uint32_t stride = width * 4;
|
uint32_t stride = width * 4;
|
||||||
size_t size = stride * height;
|
size_t size = stride * height;
|
||||||
|
|
||||||
char *name;
|
int fd = anonymous_shm_open();
|
||||||
int fd = create_pool_file(size, &name);
|
if (fd == -1) {
|
||||||
assert(fd != -1);
|
return NULL;
|
||||||
|
}
|
||||||
|
if (ftruncate(fd, size) < 0) {
|
||||||
|
close(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
|
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
|
||||||
buf->buffer = wl_shm_pool_create_buffer(pool, 0,
|
buf->buffer = wl_shm_pool_create_buffer(pool, 0,
|
||||||
width, height, stride, format);
|
width, height, stride, format);
|
||||||
wl_shm_pool_destroy(pool);
|
wl_shm_pool_destroy(pool);
|
||||||
close(fd);
|
close(fd);
|
||||||
unlink(name);
|
|
||||||
free(name);
|
|
||||||
|
|
||||||
buf->size = size;
|
buf->size = size;
|
||||||
buf->width = width;
|
buf->width = width;
|
||||||
|
|
350
common/gesture.c
Normal file
350
common/gesture.c
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "gesture.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "list.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "stringop.h"
|
||||||
|
|
||||||
|
const uint8_t GESTURE_FINGERS_ANY = 0;
|
||||||
|
|
||||||
|
// Helper to easily allocate and format string
|
||||||
|
static char *strformat(const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int length = vsnprintf(NULL, 0, format, args) + 1;
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
char *result = malloc(length);
|
||||||
|
if (result) {
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(result, length, format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *gesture_parse(const char *input, struct gesture *output) {
|
||||||
|
// Clear output in case of failure
|
||||||
|
output->type = GESTURE_TYPE_NONE;
|
||||||
|
output->fingers = GESTURE_FINGERS_ANY;
|
||||||
|
output->directions = GESTURE_DIRECTION_NONE;
|
||||||
|
|
||||||
|
// Split input type, fingers and directions
|
||||||
|
list_t *split = split_string(input, ":");
|
||||||
|
if (split->length < 1 || split->length > 3) {
|
||||||
|
return strformat(
|
||||||
|
"expected <gesture>[:<fingers>][:direction], got %s",
|
||||||
|
input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse gesture type
|
||||||
|
if (strcmp(split->items[0], "hold") == 0) {
|
||||||
|
output->type = GESTURE_TYPE_HOLD;
|
||||||
|
} else if (strcmp(split->items[0], "pinch") == 0) {
|
||||||
|
output->type = GESTURE_TYPE_PINCH;
|
||||||
|
} else if (strcmp(split->items[0], "swipe") == 0) {
|
||||||
|
output->type = GESTURE_TYPE_SWIPE;
|
||||||
|
} else {
|
||||||
|
return strformat("expected hold|pinch|swipe, got %s",
|
||||||
|
split->items[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse optional arguments
|
||||||
|
if (split->length > 1) {
|
||||||
|
char *next = split->items[1];
|
||||||
|
|
||||||
|
// Try to parse as finger count (1-9)
|
||||||
|
if (strlen(next) == 1 && '1' <= next[0] && next[0] <= '9') {
|
||||||
|
output->fingers = atoi(next);
|
||||||
|
|
||||||
|
// Move to next if available
|
||||||
|
next = split->length == 3 ? split->items[2] : NULL;
|
||||||
|
} else if (split->length == 3) {
|
||||||
|
// Fail here if argument can only be finger count
|
||||||
|
return strformat("expected 1-9, got %s", next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is an argument left, try to parse as direction
|
||||||
|
if (next) {
|
||||||
|
list_t *directions = split_string(next, "+");
|
||||||
|
|
||||||
|
for (int i = 0; i < directions->length; ++i) {
|
||||||
|
const char *item = directions->items[i];
|
||||||
|
if (strcmp(item, "any") == 0) {
|
||||||
|
continue;
|
||||||
|
} else if (strcmp(item, "up") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_UP;
|
||||||
|
} else if (strcmp(item, "down") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_DOWN;
|
||||||
|
} else if (strcmp(item, "left") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_LEFT;
|
||||||
|
} else if (strcmp(item, "right") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_RIGHT;
|
||||||
|
} else if (strcmp(item, "inward") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_INWARD;
|
||||||
|
} else if (strcmp(item, "outward") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_OUTWARD;
|
||||||
|
} else if (strcmp(item, "clockwise") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_CLOCKWISE;
|
||||||
|
} else if (strcmp(item, "counterclockwise") == 0) {
|
||||||
|
output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
|
||||||
|
} else {
|
||||||
|
return strformat("expected direction, got %s", item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_free_items_and_destroy(directions);
|
||||||
|
}
|
||||||
|
} // if optional args
|
||||||
|
|
||||||
|
list_free_items_and_destroy(split);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *gesture_type_string(enum gesture_type type) {
|
||||||
|
switch (type) {
|
||||||
|
case GESTURE_TYPE_NONE:
|
||||||
|
return "none";
|
||||||
|
case GESTURE_TYPE_HOLD:
|
||||||
|
return "hold";
|
||||||
|
case GESTURE_TYPE_PINCH:
|
||||||
|
return "pinch";
|
||||||
|
case GESTURE_TYPE_SWIPE:
|
||||||
|
return "swipe";
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *gesture_direction_string(enum gesture_direction direction) {
|
||||||
|
switch (direction) {
|
||||||
|
case GESTURE_DIRECTION_NONE:
|
||||||
|
return "none";
|
||||||
|
case GESTURE_DIRECTION_UP:
|
||||||
|
return "up";
|
||||||
|
case GESTURE_DIRECTION_DOWN:
|
||||||
|
return "down";
|
||||||
|
case GESTURE_DIRECTION_LEFT:
|
||||||
|
return "left";
|
||||||
|
case GESTURE_DIRECTION_RIGHT:
|
||||||
|
return "right";
|
||||||
|
case GESTURE_DIRECTION_INWARD:
|
||||||
|
return "inward";
|
||||||
|
case GESTURE_DIRECTION_OUTWARD:
|
||||||
|
return "outward";
|
||||||
|
case GESTURE_DIRECTION_CLOCKWISE:
|
||||||
|
return "clockwise";
|
||||||
|
case GESTURE_DIRECTION_COUNTERCLOCKWISE:
|
||||||
|
return "counterclockwise";
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to turn combination of directions flags into string representation.
|
||||||
|
static char *gesture_directions_to_string(uint32_t directions) {
|
||||||
|
char *result = NULL;
|
||||||
|
|
||||||
|
for (uint8_t bit = 0; bit < 32; bit++) {
|
||||||
|
uint32_t masked = directions & (1 << bit);
|
||||||
|
if (masked) {
|
||||||
|
const char *name = gesture_direction_string(masked);
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
name = "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
result = strdup(name);
|
||||||
|
} else {
|
||||||
|
char *new = strformat("%s+%s", result, name);
|
||||||
|
free(result);
|
||||||
|
result = new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
return strdup("any");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *gesture_to_string(struct gesture *gesture) {
|
||||||
|
char *directions = gesture_directions_to_string(gesture->directions);
|
||||||
|
char *result = strformat("%s:%u:%s",
|
||||||
|
gesture_type_string(gesture->type),
|
||||||
|
gesture->fingers, directions);
|
||||||
|
free(directions);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gesture_check(struct gesture *target, enum gesture_type type, uint8_t fingers) {
|
||||||
|
// Check that gesture type matches
|
||||||
|
if (target->type != type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that finger count matches
|
||||||
|
if (target->fingers != GESTURE_FINGERS_ANY && target->fingers != fingers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gesture_match(struct gesture *target, struct gesture *to_match, bool exact) {
|
||||||
|
// Check type and fingers
|
||||||
|
if (!gesture_check(target, to_match->type, to_match->fingers)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce exact matches ...
|
||||||
|
if (exact && target->directions != to_match->directions) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... or ensure all target directions are matched
|
||||||
|
return (target->directions & to_match->directions) == target->directions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gesture_equal(struct gesture *a, struct gesture *b) {
|
||||||
|
return a->type == b->type
|
||||||
|
&& a->fingers == b->fingers
|
||||||
|
&& a->directions == b->directions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return count of set bits in directions bit field.
|
||||||
|
static uint8_t gesture_directions_count(uint32_t directions) {
|
||||||
|
uint8_t count = 0;
|
||||||
|
for (; directions; directions >>= 1) {
|
||||||
|
count += directions & 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare direction bit count of two direction.
|
||||||
|
static int8_t gesture_directions_compare(uint32_t a, uint32_t b) {
|
||||||
|
return gesture_directions_count(a) - gesture_directions_count(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two direction based on their direction bit count
|
||||||
|
int8_t gesture_compare(struct gesture *a, struct gesture *b) {
|
||||||
|
return gesture_directions_compare(a->directions, b->directions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gesture_tracker_begin(struct gesture_tracker *tracker,
|
||||||
|
enum gesture_type type, uint8_t fingers) {
|
||||||
|
tracker->type = type;
|
||||||
|
tracker->fingers = fingers;
|
||||||
|
|
||||||
|
tracker->dx = 0.0;
|
||||||
|
tracker->dy = 0.0;
|
||||||
|
tracker->scale = 1.0;
|
||||||
|
tracker->rotation = 0.0;
|
||||||
|
|
||||||
|
sway_log(SWAY_DEBUG, "begin tracking %s:%u:? gesture",
|
||||||
|
gesture_type_string(type), fingers);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gesture_tracker_check(struct gesture_tracker *tracker, enum gesture_type type) {
|
||||||
|
return tracker->type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gesture_tracker_update(struct gesture_tracker *tracker,
|
||||||
|
double dx, double dy, double scale, double rotation) {
|
||||||
|
if (tracker->type == GESTURE_TYPE_HOLD) {
|
||||||
|
sway_assert(false, "hold does not update.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker->dx += dx;
|
||||||
|
tracker->dy += dy;
|
||||||
|
|
||||||
|
if (tracker->type == GESTURE_TYPE_PINCH) {
|
||||||
|
tracker->scale = scale;
|
||||||
|
tracker->rotation += rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
sway_log(SWAY_DEBUG, "update tracking %s:%u:? gesture: %f %f %f %f",
|
||||||
|
gesture_type_string(tracker->type),
|
||||||
|
tracker->fingers,
|
||||||
|
tracker->dx, tracker->dy,
|
||||||
|
tracker->scale, tracker->rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gesture_tracker_cancel(struct gesture_tracker *tracker) {
|
||||||
|
sway_log(SWAY_DEBUG, "cancel tracking %s:%u:? gesture",
|
||||||
|
gesture_type_string(tracker->type), tracker->fingers);
|
||||||
|
|
||||||
|
tracker->type = GESTURE_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gesture *gesture_tracker_end(struct gesture_tracker *tracker) {
|
||||||
|
struct gesture *result = calloc(1, sizeof(struct gesture));
|
||||||
|
|
||||||
|
// Ignore gesture under some threshold
|
||||||
|
// TODO: Make configurable
|
||||||
|
const double min_rotation = 5;
|
||||||
|
const double min_scale_delta = 0.1;
|
||||||
|
|
||||||
|
// Determine direction
|
||||||
|
switch(tracker->type) {
|
||||||
|
// Gestures with scale and rotation
|
||||||
|
case GESTURE_TYPE_PINCH:
|
||||||
|
if (tracker->rotation > min_rotation) {
|
||||||
|
result->directions |= GESTURE_DIRECTION_CLOCKWISE;
|
||||||
|
}
|
||||||
|
if (tracker->rotation < -min_rotation) {
|
||||||
|
result->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tracker->scale > (1.0 + min_scale_delta)) {
|
||||||
|
result->directions |= GESTURE_DIRECTION_OUTWARD;
|
||||||
|
}
|
||||||
|
if (tracker->scale < (1.0 - min_scale_delta)) {
|
||||||
|
result->directions |= GESTURE_DIRECTION_INWARD;
|
||||||
|
}
|
||||||
|
__attribute__ ((fallthrough));
|
||||||
|
// Gestures with dx and dy
|
||||||
|
case GESTURE_TYPE_SWIPE:
|
||||||
|
if (fabs(tracker->dx) > fabs(tracker->dy)) {
|
||||||
|
if (tracker->dx > 0) {
|
||||||
|
result->directions |= GESTURE_DIRECTION_RIGHT;
|
||||||
|
} else {
|
||||||
|
result->directions |= GESTURE_DIRECTION_LEFT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (tracker->dy > 0) {
|
||||||
|
result->directions |= GESTURE_DIRECTION_DOWN;
|
||||||
|
} else {
|
||||||
|
result->directions |= GESTURE_DIRECTION_UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Gesture without any direction
|
||||||
|
case GESTURE_TYPE_HOLD:
|
||||||
|
break;
|
||||||
|
// Not tracking any gesture
|
||||||
|
case GESTURE_TYPE_NONE:
|
||||||
|
sway_assert(false, "Not tracking any gesture.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->type = tracker->type;
|
||||||
|
result->fingers = tracker->fingers;
|
||||||
|
|
||||||
|
char *description = gesture_to_string(result);
|
||||||
|
sway_log(SWAY_DEBUG, "end tracking gesture: %s", description);
|
||||||
|
free(description);
|
||||||
|
|
||||||
|
tracker->type = GESTURE_TYPE_NONE;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ lib_sway_common = static_library(
|
||||||
files(
|
files(
|
||||||
'background-image.c',
|
'background-image.c',
|
||||||
'cairo.c',
|
'cairo.c',
|
||||||
|
'gesture.c',
|
||||||
'ipc-client.c',
|
'ipc-client.c',
|
||||||
'log.c',
|
'log.c',
|
||||||
'loop.c',
|
'loop.c',
|
||||||
|
|
|
@ -50,7 +50,7 @@ size_t escape_markup_text(const char *src, char *dest) {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
|
PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
|
||||||
const char *text, double scale, bool markup) {
|
const char *text, double scale, bool markup) {
|
||||||
PangoLayout *layout = pango_cairo_create_layout(cairo);
|
PangoLayout *layout = pango_cairo_create_layout(cairo);
|
||||||
PangoAttrList *attrs;
|
PangoAttrList *attrs;
|
||||||
|
@ -73,16 +73,14 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
|
||||||
}
|
}
|
||||||
|
|
||||||
pango_attr_list_insert(attrs, pango_attr_scale_new(scale));
|
pango_attr_list_insert(attrs, pango_attr_scale_new(scale));
|
||||||
PangoFontDescription *desc = pango_font_description_from_string(font);
|
|
||||||
pango_layout_set_font_description(layout, desc);
|
pango_layout_set_font_description(layout, desc);
|
||||||
pango_layout_set_single_paragraph_mode(layout, 1);
|
pango_layout_set_single_paragraph_mode(layout, 1);
|
||||||
pango_layout_set_attributes(layout, attrs);
|
pango_layout_set_attributes(layout, attrs);
|
||||||
pango_attr_list_unref(attrs);
|
pango_attr_list_unref(attrs);
|
||||||
pango_font_description_free(desc);
|
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
|
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
|
||||||
int *baseline, double scale, bool markup, const char *fmt, ...) {
|
int *baseline, double scale, bool markup, const char *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
@ -99,7 +97,7 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
|
||||||
vsnprintf(buf, length, fmt, args);
|
vsnprintf(buf, length, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup);
|
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
|
||||||
pango_cairo_update_layout(cairo, layout);
|
pango_cairo_update_layout(cairo, layout);
|
||||||
pango_layout_get_pixel_size(layout, width, height);
|
pango_layout_get_pixel_size(layout, width, height);
|
||||||
if (baseline) {
|
if (baseline) {
|
||||||
|
@ -109,10 +107,9 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_text_metrics(const char *font, int *height, int *baseline) {
|
void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) {
|
||||||
cairo_t *cairo = cairo_create(NULL);
|
cairo_t *cairo = cairo_create(NULL);
|
||||||
PangoContext *pango = pango_cairo_create_context(cairo);
|
PangoContext *pango = pango_cairo_create_context(cairo);
|
||||||
PangoFontDescription *description = pango_font_description_from_string(font);
|
|
||||||
// When passing NULL as a language, pango uses the current locale.
|
// When passing NULL as a language, pango uses the current locale.
|
||||||
PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);
|
PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);
|
||||||
|
|
||||||
|
@ -120,12 +117,11 @@ void get_text_metrics(const char *font, int *height, int *baseline) {
|
||||||
*height = *baseline + pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
|
*height = *baseline + pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
|
||||||
|
|
||||||
pango_font_metrics_unref(metrics);
|
pango_font_metrics_unref(metrics);
|
||||||
pango_font_description_free(description);
|
|
||||||
g_object_unref(pango);
|
g_object_unref(pango);
|
||||||
cairo_destroy(cairo);
|
cairo_destroy(cairo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_text(cairo_t *cairo, const char *font,
|
void render_text(cairo_t *cairo, const PangoFontDescription *desc,
|
||||||
double scale, bool markup, const char *fmt, ...) {
|
double scale, bool markup, const char *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
@ -142,7 +138,7 @@ void render_text(cairo_t *cairo, const char *font,
|
||||||
vsnprintf(buf, length, fmt, args);
|
vsnprintf(buf, length, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup);
|
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
|
||||||
cairo_font_options_t *fo = cairo_font_options_create();
|
cairo_font_options_t *fo = cairo_font_options_create();
|
||||||
cairo_get_font_options(cairo, fo);
|
cairo_get_font_options(cairo, fo);
|
||||||
pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo);
|
pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
_sway()
|
_sway()
|
||||||
{
|
{
|
||||||
local cur prev
|
local cur prev short long
|
||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
|
|
||||||
short=(
|
short=(
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
_swaybar()
|
_swaybar()
|
||||||
{
|
{
|
||||||
local cur prev
|
local cur prev short long
|
||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
|
|
||||||
short=(
|
short=(
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
_swaymsg()
|
_swaymsg()
|
||||||
{
|
{
|
||||||
local cur prev
|
local cur prev types short long
|
||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
|
|
||||||
types=(
|
types=(
|
||||||
|
|
|
@ -46,7 +46,7 @@ output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
|
||||||
#
|
#
|
||||||
# exec swayidle -w \
|
# exec swayidle -w \
|
||||||
# timeout 300 'swaylock -f -c 000000' \
|
# timeout 300 'swaylock -f -c 000000' \
|
||||||
# timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \
|
# timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
|
||||||
# before-sleep 'swaylock -f -c 000000'
|
# before-sleep 'swaylock -f -c 000000'
|
||||||
#
|
#
|
||||||
# This will lock your screen after 300 seconds of inactivity, then turn off
|
# This will lock your screen after 300 seconds of inactivity, then turn off
|
||||||
|
|
|
@ -13,18 +13,32 @@
|
||||||
## See `man 1 grimshot` or `grimshot usage` for further details.
|
## See `man 1 grimshot` or `grimshot usage` for further details.
|
||||||
|
|
||||||
getTargetDirectory() {
|
getTargetDirectory() {
|
||||||
test -f ${XDG_CONFIG_HOME:-~/.config}/user-dirs.dirs && \
|
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" && \
|
||||||
. ${XDG_CONFIG_HOME:-~/.config}/user-dirs.dirs
|
. "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs"
|
||||||
|
|
||||||
echo ${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}}
|
echo "${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$1" = "--notify" ]; then
|
NOTIFY=no
|
||||||
NOTIFY=yes
|
CURSOR=
|
||||||
shift 1
|
|
||||||
else
|
while [ $# -gt 0 ]; do
|
||||||
NOTIFY=no
|
key="$1"
|
||||||
fi
|
|
||||||
|
case $key in
|
||||||
|
-n|--notify)
|
||||||
|
NOTIFY=yes
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
|
-c|--cursor)
|
||||||
|
CURSOR=yes
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
|
*) # unknown option
|
||||||
|
break # done with parsing --flags
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
ACTION=${1:-usage}
|
ACTION=${1:-usage}
|
||||||
SUBJECT=${2:-screen}
|
SUBJECT=${2:-screen}
|
||||||
|
@ -32,7 +46,7 @@ FILE=${3:-$(getTargetDirectory)/$(date -Ins).png}
|
||||||
|
|
||||||
if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then
|
if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then
|
||||||
echo "Usage:"
|
echo "Usage:"
|
||||||
echo " grimshot [--notify] (copy|save) [active|screen|output|area|window] [FILE|-]"
|
echo " grimshot [--notify] [--cursor] (copy|save) [active|screen|output|area|window] [FILE|-]"
|
||||||
echo " grimshot check"
|
echo " grimshot check"
|
||||||
echo " grimshot usage"
|
echo " grimshot usage"
|
||||||
echo ""
|
echo ""
|
||||||
|
@ -67,7 +81,7 @@ notifyError() {
|
||||||
MESSAGE=${1:-"Error taking screenshot with grim"}
|
MESSAGE=${1:-"Error taking screenshot with grim"}
|
||||||
notify -u critical "$TITLE" "$MESSAGE"
|
notify -u critical "$TITLE" "$MESSAGE"
|
||||||
else
|
else
|
||||||
echo $1
|
echo "$1"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,12 +105,12 @@ takeScreenshot() {
|
||||||
FILE=$1
|
FILE=$1
|
||||||
GEOM=$2
|
GEOM=$2
|
||||||
OUTPUT=$3
|
OUTPUT=$3
|
||||||
if [ ! -z "$OUTPUT" ]; then
|
if [ -n "$OUTPUT" ]; then
|
||||||
grim -o "$OUTPUT" "$FILE" || die "Unable to invoke grim"
|
grim ${CURSOR:+-c} -o "$OUTPUT" "$FILE" || die "Unable to invoke grim"
|
||||||
elif [ -z "$GEOM" ]; then
|
elif [ -z "$GEOM" ]; then
|
||||||
grim "$FILE" || die "Unable to invoke grim"
|
grim ${CURSOR:+-c} "$FILE" || die "Unable to invoke grim"
|
||||||
else
|
else
|
||||||
grim -g "$GEOM" "$FILE" || die "Unable to invoke grim"
|
grim ${CURSOR:+-c} -g "$GEOM" "$FILE" || die "Unable to invoke grim"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +161,7 @@ else
|
||||||
TITLE="Screenshot of $SUBJECT"
|
TITLE="Screenshot of $SUBJECT"
|
||||||
MESSAGE=$(basename "$FILE")
|
MESSAGE=$(basename "$FILE")
|
||||||
notifyOk "$MESSAGE" "$TITLE"
|
notifyOk "$MESSAGE" "$TITLE"
|
||||||
echo $FILE
|
echo "$FILE"
|
||||||
else
|
else
|
||||||
notifyError "Error taking screenshot with grim"
|
notifyError "Error taking screenshot with grim"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
.\" Generated by scdoc 1.11.1
|
.\" Generated by scdoc 1.11.2
|
||||||
.\" Complete documentation for this program is not available as a GNU info page
|
.\" Complete documentation for this program is not available as a GNU info page
|
||||||
.ie \n(.g .ds Aq \(aq
|
.ie \n(.g .ds Aq \(aq
|
||||||
.el .ds Aq '
|
.el .ds Aq '
|
||||||
.nh
|
.nh
|
||||||
.ad l
|
.ad l
|
||||||
.\" Begin generated content:
|
.\" Begin generated content:
|
||||||
.TH "grimshot" "1" "2021-02-23"
|
.TH "grimshot" "1" "2022-03-31"
|
||||||
.P
|
.P
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.P
|
.P
|
||||||
|
@ -13,7 +13,7 @@ grimshot - a helper for screenshots within sway
|
||||||
.P
|
.P
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.P
|
.P
|
||||||
\fBgrimshot\fR [--notify] (copy|save) [TARGET] [FILE]
|
\fBgrimshot\fR [--notify] [--cursor] (copy|save) [TARGET] [FILE]
|
||||||
.br
|
.br
|
||||||
\fBgrimshot\fR check
|
\fBgrimshot\fR check
|
||||||
.br
|
.br
|
||||||
|
@ -26,12 +26,17 @@ grimshot - a helper for screenshots within sway
|
||||||
Show notifications to the user that a screenshot has been taken.\&
|
Show notifications to the user that a screenshot has been taken.\&
|
||||||
.P
|
.P
|
||||||
.RE
|
.RE
|
||||||
|
\fB--cursor\fR
|
||||||
|
.RS 4
|
||||||
|
Include cursors in the screenshot.\&
|
||||||
|
.P
|
||||||
|
.RE
|
||||||
\fBsave\fR
|
\fBsave\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Save the screenshot into a regular file.\& Grimshot will write images
|
Save the screenshot into a regular file.\& Grimshot will write images
|
||||||
files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined
|
files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined
|
||||||
in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\&
|
in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\&
|
||||||
Set FILE to '-' to pipe the output to STDOUT.\&
|
Set FILE to '\&-'\& to pipe the output to STDOUT.\&
|
||||||
.P
|
.P
|
||||||
.RE
|
.RE
|
||||||
\fBcopy\fR
|
\fBcopy\fR
|
||||||
|
|
|
@ -6,7 +6,7 @@ grimshot - a helper for screenshots within sway
|
||||||
|
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
|
|
||||||
*grimshot* [--notify] (copy|save) [TARGET] [FILE]++
|
*grimshot* [--notify] [--cursor] (copy|save) [TARGET] [FILE]++
|
||||||
*grimshot* check++
|
*grimshot* check++
|
||||||
*grimshot* usage
|
*grimshot* usage
|
||||||
|
|
||||||
|
@ -15,8 +15,11 @@ grimshot - a helper for screenshots within sway
|
||||||
*--notify*
|
*--notify*
|
||||||
Show notifications to the user that a screenshot has been taken.
|
Show notifications to the user that a screenshot has been taken.
|
||||||
|
|
||||||
|
*--cursor*
|
||||||
|
Include cursors in the screenshot.
|
||||||
|
|
||||||
*save*
|
*save*
|
||||||
Save the screenshot into a regular file. Grimshot will write images
|
Save the screenshot into a regular file. Grimshot will write image
|
||||||
files to *XDG_SCREENSHOTS_DIR* if this is set (or defined
|
files to *XDG_SCREENSHOTS_DIR* if this is set (or defined
|
||||||
in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*.
|
in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*.
|
||||||
Set FILE to '-' to pipe the output to STDOUT.
|
Set FILE to '-' to pipe the output to STDOUT.
|
||||||
|
|
104
include/gesture.h
Normal file
104
include/gesture.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#ifndef _SWAY_GESTURE_H
|
||||||
|
#define _SWAY_GESTURE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A gesture type used in binding.
|
||||||
|
*/
|
||||||
|
enum gesture_type {
|
||||||
|
GESTURE_TYPE_NONE = 0,
|
||||||
|
GESTURE_TYPE_HOLD,
|
||||||
|
GESTURE_TYPE_PINCH,
|
||||||
|
GESTURE_TYPE_SWIPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Turns single type enum value to constant string representation.
|
||||||
|
const char *gesture_type_string(enum gesture_type direction);
|
||||||
|
|
||||||
|
// Value to use to accept any finger count
|
||||||
|
extern const uint8_t GESTURE_FINGERS_ANY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A gesture direction used in binding.
|
||||||
|
*/
|
||||||
|
enum gesture_direction {
|
||||||
|
GESTURE_DIRECTION_NONE = 0,
|
||||||
|
// Directions based on delta x and y
|
||||||
|
GESTURE_DIRECTION_UP = 1 << 0,
|
||||||
|
GESTURE_DIRECTION_DOWN = 1 << 1,
|
||||||
|
GESTURE_DIRECTION_LEFT = 1 << 2,
|
||||||
|
GESTURE_DIRECTION_RIGHT = 1 << 3,
|
||||||
|
// Directions based on scale
|
||||||
|
GESTURE_DIRECTION_INWARD = 1 << 4,
|
||||||
|
GESTURE_DIRECTION_OUTWARD = 1 << 5,
|
||||||
|
// Directions based on rotation
|
||||||
|
GESTURE_DIRECTION_CLOCKWISE = 1 << 6,
|
||||||
|
GESTURE_DIRECTION_COUNTERCLOCKWISE = 1 << 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Turns single direction enum value to constant string representation.
|
||||||
|
const char *gesture_direction_string(enum gesture_direction direction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct representing a pointer gesture
|
||||||
|
*/
|
||||||
|
struct gesture {
|
||||||
|
enum gesture_type type;
|
||||||
|
uint8_t fingers;
|
||||||
|
uint32_t directions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses gesture from <gesture>[:<fingers>][:<directions>] string.
|
||||||
|
*
|
||||||
|
* Return NULL on success, otherwise error message string
|
||||||
|
*/
|
||||||
|
char *gesture_parse(const char *input, struct gesture *output);
|
||||||
|
|
||||||
|
// Turns gesture into string representation
|
||||||
|
char *gesture_to_string(struct gesture *gesture);
|
||||||
|
|
||||||
|
// Check if gesture is of certain type and finger count.
|
||||||
|
bool gesture_check(struct gesture *target,
|
||||||
|
enum gesture_type type, uint8_t fingers);
|
||||||
|
|
||||||
|
// Check if a gesture target/binding is match by other gesture/input
|
||||||
|
bool gesture_match(struct gesture *target,
|
||||||
|
struct gesture *to_match, bool exact);
|
||||||
|
|
||||||
|
// Returns true if gesture are exactly the same
|
||||||
|
bool gesture_equal(struct gesture *a, struct gesture *b);
|
||||||
|
|
||||||
|
// Compare distance between two matched target gestures.
|
||||||
|
int8_t gesture_compare(struct gesture *a, struct gesture *b);
|
||||||
|
|
||||||
|
// Small helper struct to track gestures over time
|
||||||
|
struct gesture_tracker {
|
||||||
|
enum gesture_type type;
|
||||||
|
uint8_t fingers;
|
||||||
|
double dx, dy;
|
||||||
|
double scale;
|
||||||
|
double rotation;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Begin gesture tracking
|
||||||
|
void gesture_tracker_begin(struct gesture_tracker *tracker,
|
||||||
|
enum gesture_type type, uint8_t fingers);
|
||||||
|
|
||||||
|
// Check if the provides type is currently being tracked
|
||||||
|
bool gesture_tracker_check(struct gesture_tracker *tracker,
|
||||||
|
enum gesture_type type);
|
||||||
|
|
||||||
|
// Update gesture track with new data point
|
||||||
|
void gesture_tracker_update(struct gesture_tracker *tracker, double dx,
|
||||||
|
double dy, double scale, double rotation);
|
||||||
|
|
||||||
|
// Reset tracker
|
||||||
|
void gesture_tracker_cancel(struct gesture_tracker *tracker);
|
||||||
|
|
||||||
|
// Reset tracker and return gesture tracked
|
||||||
|
struct gesture *gesture_tracker_end(struct gesture_tracker *tracker);
|
||||||
|
|
||||||
|
#endif
|
|
@ -13,12 +13,12 @@
|
||||||
* escaped string to dest if provided.
|
* escaped string to dest if provided.
|
||||||
*/
|
*/
|
||||||
size_t escape_markup_text(const char *src, char *dest);
|
size_t escape_markup_text(const char *src, char *dest);
|
||||||
PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
|
PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
|
||||||
const char *text, double scale, bool markup);
|
const char *text, double scale, bool markup);
|
||||||
void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
|
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
|
||||||
int *baseline, double scale, bool markup, const char *fmt, ...);
|
int *baseline, double scale, bool markup, const char *fmt, ...);
|
||||||
void get_text_metrics(const char *font, int *height, int *baseline);
|
void get_text_metrics(const PangoFontDescription *desc, int *height, int *baseline);
|
||||||
void render_text(cairo_t *cairo, const char *font,
|
void render_text(cairo_t *cairo, PangoFontDescription *desc,
|
||||||
double scale, bool markup, const char *fmt, ...);
|
double scale, bool markup, const char *fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define _SWAY_STRINGOP_H
|
#define _SWAY_STRINGOP_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
|
||||||
void strip_whitespace(char *str);
|
void strip_whitespace(char *str);
|
||||||
|
|
|
@ -106,6 +106,7 @@ sway_cmd cmd_exec_process;
|
||||||
sway_cmd cmd_assign;
|
sway_cmd cmd_assign;
|
||||||
sway_cmd cmd_bar;
|
sway_cmd cmd_bar;
|
||||||
sway_cmd cmd_bindcode;
|
sway_cmd cmd_bindcode;
|
||||||
|
sway_cmd cmd_bindgesture;
|
||||||
sway_cmd cmd_bindswitch;
|
sway_cmd cmd_bindswitch;
|
||||||
sway_cmd cmd_bindsym;
|
sway_cmd cmd_bindsym;
|
||||||
sway_cmd cmd_border;
|
sway_cmd cmd_border;
|
||||||
|
@ -196,6 +197,7 @@ sway_cmd cmd_titlebar_border_thickness;
|
||||||
sway_cmd cmd_titlebar_padding;
|
sway_cmd cmd_titlebar_padding;
|
||||||
sway_cmd cmd_unbindcode;
|
sway_cmd cmd_unbindcode;
|
||||||
sway_cmd cmd_unbindswitch;
|
sway_cmd cmd_unbindswitch;
|
||||||
|
sway_cmd cmd_unbindgesture;
|
||||||
sway_cmd cmd_unbindsym;
|
sway_cmd cmd_unbindsym;
|
||||||
sway_cmd cmd_unmark;
|
sway_cmd cmd_unmark;
|
||||||
sway_cmd cmd_urgent;
|
sway_cmd cmd_urgent;
|
||||||
|
@ -255,6 +257,7 @@ sway_cmd input_cmd_click_method;
|
||||||
sway_cmd input_cmd_drag;
|
sway_cmd input_cmd_drag;
|
||||||
sway_cmd input_cmd_drag_lock;
|
sway_cmd input_cmd_drag_lock;
|
||||||
sway_cmd input_cmd_dwt;
|
sway_cmd input_cmd_dwt;
|
||||||
|
sway_cmd input_cmd_dwtp;
|
||||||
sway_cmd input_cmd_events;
|
sway_cmd input_cmd_events;
|
||||||
sway_cmd input_cmd_left_handed;
|
sway_cmd input_cmd_left_handed;
|
||||||
sway_cmd input_cmd_map_from_region;
|
sway_cmd input_cmd_map_from_region;
|
||||||
|
@ -290,12 +293,14 @@ sway_cmd output_cmd_max_render_time;
|
||||||
sway_cmd output_cmd_mode;
|
sway_cmd output_cmd_mode;
|
||||||
sway_cmd output_cmd_modeline;
|
sway_cmd output_cmd_modeline;
|
||||||
sway_cmd output_cmd_position;
|
sway_cmd output_cmd_position;
|
||||||
|
sway_cmd output_cmd_power;
|
||||||
sway_cmd output_cmd_render_bit_depth;
|
sway_cmd output_cmd_render_bit_depth;
|
||||||
sway_cmd output_cmd_scale;
|
sway_cmd output_cmd_scale;
|
||||||
sway_cmd output_cmd_scale_filter;
|
sway_cmd output_cmd_scale_filter;
|
||||||
sway_cmd output_cmd_subpixel;
|
sway_cmd output_cmd_subpixel;
|
||||||
sway_cmd output_cmd_toggle;
|
sway_cmd output_cmd_toggle;
|
||||||
sway_cmd output_cmd_transform;
|
sway_cmd output_cmd_transform;
|
||||||
|
sway_cmd output_cmd_unplug;
|
||||||
|
|
||||||
sway_cmd seat_cmd_attach;
|
sway_cmd seat_cmd_attach;
|
||||||
sway_cmd seat_cmd_cursor;
|
sway_cmd seat_cmd_cursor;
|
||||||
|
|
|
@ -10,12 +10,14 @@
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include <xf86drmMode.h>
|
#include <xf86drmMode.h>
|
||||||
#include "../include/config.h"
|
#include "../include/config.h"
|
||||||
|
#include "gesture.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "swaynag.h"
|
#include "swaynag.h"
|
||||||
#include "tree/container.h"
|
#include "tree/container.h"
|
||||||
#include "sway/input/tablet.h"
|
#include "sway/input/tablet.h"
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
// TODO: Refactor this shit
|
// TODO: Refactor this shit
|
||||||
|
|
||||||
|
@ -32,7 +34,8 @@ enum binding_input_type {
|
||||||
BINDING_KEYSYM,
|
BINDING_KEYSYM,
|
||||||
BINDING_MOUSECODE,
|
BINDING_MOUSECODE,
|
||||||
BINDING_MOUSESYM,
|
BINDING_MOUSESYM,
|
||||||
BINDING_SWITCH
|
BINDING_SWITCH, // dummy, only used to call seat_execute_command
|
||||||
|
BINDING_GESTURE // dummy, only used to call seat_execute_command
|
||||||
};
|
};
|
||||||
|
|
||||||
enum binding_flags {
|
enum binding_flags {
|
||||||
|
@ -45,10 +48,11 @@ enum binding_flags {
|
||||||
BINDING_RELOAD = 1 << 6, // switch only; (re)trigger binding on reload
|
BINDING_RELOAD = 1 << 6, // switch only; (re)trigger binding on reload
|
||||||
BINDING_INHIBITED = 1 << 7, // keyboard only: ignore shortcut inhibitor
|
BINDING_INHIBITED = 1 << 7, // keyboard only: ignore shortcut inhibitor
|
||||||
BINDING_NOREPEAT = 1 << 8, // keyboard only; do not trigger when repeating a held key
|
BINDING_NOREPEAT = 1 << 8, // keyboard only; do not trigger when repeating a held key
|
||||||
|
BINDING_EXACT = 1 << 9, // gesture only; only trigger on exact match
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key binding and an associated command.
|
* A key (or mouse) binding and an associated command.
|
||||||
*/
|
*/
|
||||||
struct sway_binding {
|
struct sway_binding {
|
||||||
enum binding_input_type type;
|
enum binding_input_type type;
|
||||||
|
@ -62,12 +66,10 @@ struct sway_binding {
|
||||||
char *command;
|
char *command;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
enum sway_switch_trigger {
|
||||||
* A mouse binding and an associated command.
|
SWAY_SWITCH_TRIGGER_OFF,
|
||||||
*/
|
SWAY_SWITCH_TRIGGER_ON,
|
||||||
struct sway_mouse_binding {
|
SWAY_SWITCH_TRIGGER_TOGGLE,
|
||||||
uint32_t button;
|
|
||||||
char *command;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,11 +77,21 @@ struct sway_mouse_binding {
|
||||||
*/
|
*/
|
||||||
struct sway_switch_binding {
|
struct sway_switch_binding {
|
||||||
enum wlr_switch_type type;
|
enum wlr_switch_type type;
|
||||||
enum wlr_switch_state state;
|
enum sway_switch_trigger trigger;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
char *command;
|
char *command;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A gesture binding and an associated command.
|
||||||
|
*/
|
||||||
|
struct sway_gesture_binding {
|
||||||
|
char *input;
|
||||||
|
uint32_t flags;
|
||||||
|
struct gesture gesture;
|
||||||
|
char *command;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Focus on window activation.
|
* Focus on window activation.
|
||||||
*/
|
*/
|
||||||
|
@ -99,6 +111,7 @@ struct sway_mode {
|
||||||
list_t *keycode_bindings;
|
list_t *keycode_bindings;
|
||||||
list_t *mouse_bindings;
|
list_t *mouse_bindings;
|
||||||
list_t *switch_bindings;
|
list_t *switch_bindings;
|
||||||
|
list_t *gesture_bindings;
|
||||||
bool pango;
|
bool pango;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -137,6 +150,7 @@ struct input_config {
|
||||||
int drag;
|
int drag;
|
||||||
int drag_lock;
|
int drag_lock;
|
||||||
int dwt;
|
int dwt;
|
||||||
|
int dwtp;
|
||||||
int left_handed;
|
int left_handed;
|
||||||
int middle_emulation;
|
int middle_emulation;
|
||||||
int natural_scroll;
|
int natural_scroll;
|
||||||
|
@ -234,12 +248,6 @@ struct seat_config {
|
||||||
} xcursor_theme;
|
} xcursor_theme;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum config_dpms {
|
|
||||||
DPMS_IGNORE,
|
|
||||||
DPMS_ON,
|
|
||||||
DPMS_OFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum scale_filter_mode {
|
enum scale_filter_mode {
|
||||||
SCALE_FILTER_DEFAULT, // the default is currently smart
|
SCALE_FILTER_DEFAULT, // the default is currently smart
|
||||||
SCALE_FILTER_LINEAR,
|
SCALE_FILTER_LINEAR,
|
||||||
|
@ -261,6 +269,7 @@ enum render_bit_depth {
|
||||||
struct output_config {
|
struct output_config {
|
||||||
char *name;
|
char *name;
|
||||||
int enabled;
|
int enabled;
|
||||||
|
int power;
|
||||||
int width, height;
|
int width, height;
|
||||||
float refresh_rate;
|
float refresh_rate;
|
||||||
int custom_mode;
|
int custom_mode;
|
||||||
|
@ -277,7 +286,6 @@ struct output_config {
|
||||||
char *background;
|
char *background;
|
||||||
char *background_option;
|
char *background_option;
|
||||||
char *background_fallback;
|
char *background_fallback;
|
||||||
enum config_dpms dpms_state;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -501,7 +509,8 @@ struct sway_config {
|
||||||
char *floating_scroll_right_cmd;
|
char *floating_scroll_right_cmd;
|
||||||
enum sway_container_layout default_orientation;
|
enum sway_container_layout default_orientation;
|
||||||
enum sway_container_layout default_layout;
|
enum sway_container_layout default_layout;
|
||||||
char *font;
|
char *font; // Used for IPC.
|
||||||
|
PangoFontDescription *font_description; // Used internally for rendering and validating.
|
||||||
int font_height;
|
int font_height;
|
||||||
int font_baseline;
|
int font_baseline;
|
||||||
bool pango_markup;
|
bool pango_markup;
|
||||||
|
@ -700,6 +709,8 @@ void free_sway_binding(struct sway_binding *sb);
|
||||||
|
|
||||||
void free_switch_binding(struct sway_switch_binding *binding);
|
void free_switch_binding(struct sway_switch_binding *binding);
|
||||||
|
|
||||||
|
void free_gesture_binding(struct sway_gesture_binding *binding);
|
||||||
|
|
||||||
void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding);
|
void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding);
|
||||||
|
|
||||||
void load_swaybar(struct bar_config *bar);
|
void load_swaybar(struct bar_config *bar);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#ifndef _SWAY_CRITERIA_H
|
#ifndef _SWAY_CRITERIA_H
|
||||||
#define _SWAY_CRITERIA_H
|
#define _SWAY_CRITERIA_H
|
||||||
|
|
||||||
#include <pcre.h>
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||||
|
#include <pcre2.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "tree/view.h"
|
#include "tree/view.h"
|
||||||
|
@ -15,13 +16,13 @@ enum criteria_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum pattern_type {
|
enum pattern_type {
|
||||||
PATTERN_PCRE,
|
PATTERN_PCRE2,
|
||||||
PATTERN_FOCUSED,
|
PATTERN_FOCUSED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pattern {
|
struct pattern {
|
||||||
enum pattern_type match_type;
|
enum pattern_type match_type;
|
||||||
pcre *regex;
|
pcre2_code *regex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct criteria {
|
struct criteria {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
|
||||||
struct sway_container;
|
struct sway_container;
|
||||||
struct sway_view;
|
struct sway_view;
|
||||||
|
|
32
include/sway/desktop/launcher.h
Normal file
32
include/sway/desktop/launcher.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef _SWAY_LAUNCHER_H
|
||||||
|
#define _SWAY_LAUNCHER_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct launcher_ctx {
|
||||||
|
pid_t pid;
|
||||||
|
char *name;
|
||||||
|
struct wlr_xdg_activation_token_v1 *token;
|
||||||
|
struct wl_listener token_destroy;
|
||||||
|
|
||||||
|
bool activated;
|
||||||
|
|
||||||
|
struct sway_node *node;
|
||||||
|
struct wl_listener node_destroy;
|
||||||
|
|
||||||
|
struct wl_list link; // sway_server::pending_launcher_ctxs
|
||||||
|
};
|
||||||
|
|
||||||
|
struct launcher_ctx *launcher_ctx_find_pid(pid_t pid);
|
||||||
|
|
||||||
|
struct sway_workspace *launcher_ctx_get_workspace(struct launcher_ctx *ctx);
|
||||||
|
|
||||||
|
void launcher_ctx_consume(struct launcher_ctx *ctx);
|
||||||
|
|
||||||
|
void launcher_ctx_destroy(struct launcher_ctx *ctx);
|
||||||
|
|
||||||
|
struct launcher_ctx *launcher_ctx_create(void);
|
||||||
|
|
||||||
|
const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx);
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,7 +4,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||||
#include <wlr/types/wlr_pointer_gestures_v1.h>
|
#include <wlr/types/wlr_pointer_gestures_v1.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@ struct sway_cursor {
|
||||||
bool active_confine_requires_warp;
|
bool active_confine_requires_warp;
|
||||||
|
|
||||||
struct wlr_pointer_gestures_v1 *pointer_gestures;
|
struct wlr_pointer_gestures_v1 *pointer_gestures;
|
||||||
|
struct wl_listener hold_begin;
|
||||||
|
struct wl_listener hold_end;
|
||||||
struct wl_listener pinch_begin;
|
struct wl_listener pinch_begin;
|
||||||
struct wl_listener pinch_update;
|
struct wl_listener pinch_update;
|
||||||
struct wl_listener pinch_end;
|
struct wl_listener pinch_end;
|
||||||
|
@ -110,7 +112,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
|
||||||
enum wlr_button_state state);
|
enum wlr_button_state state);
|
||||||
|
|
||||||
void dispatch_cursor_axis(struct sway_cursor *cursor,
|
void dispatch_cursor_axis(struct sway_cursor *cursor,
|
||||||
struct wlr_event_pointer_axis *event);
|
struct wlr_pointer_axis_event *event);
|
||||||
|
|
||||||
void cursor_set_image(struct sway_cursor *cursor, const char *image,
|
void cursor_set_image(struct sway_cursor *cursor, const char *image,
|
||||||
struct wl_client *client);
|
struct wl_client *client);
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct sway_shortcut_state {
|
||||||
|
|
||||||
struct sway_keyboard {
|
struct sway_keyboard {
|
||||||
struct sway_seat_device *seat_device;
|
struct sway_seat_device *seat_device;
|
||||||
|
struct wlr_keyboard *wlr;
|
||||||
|
|
||||||
struct xkb_keymap *keymap;
|
struct xkb_keymap *keymap;
|
||||||
xkb_layout_index_t effective_layout;
|
xkb_layout_index_t effective_layout;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define _SWAY_INPUT_LIBINPUT_H
|
#define _SWAY_INPUT_LIBINPUT_H
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
|
|
||||||
void sway_input_configure_libinput_device(struct sway_input_device *device);
|
bool sway_input_configure_libinput_device(struct sway_input_device *device);
|
||||||
|
|
||||||
void sway_input_reset_libinput_device(struct sway_input_device *device);
|
void sway_input_reset_libinput_device(struct sway_input_device *device);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,23 @@ struct sway_seatop_impl {
|
||||||
enum wlr_button_state state);
|
enum wlr_button_state state);
|
||||||
void (*pointer_motion)(struct sway_seat *seat, uint32_t time_msec);
|
void (*pointer_motion)(struct sway_seat *seat, uint32_t time_msec);
|
||||||
void (*pointer_axis)(struct sway_seat *seat,
|
void (*pointer_axis)(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_axis *event);
|
struct wlr_pointer_axis_event *event);
|
||||||
|
void (*hold_begin)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_begin_event *event);
|
||||||
|
void (*hold_end)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_end_event *event);
|
||||||
|
void (*pinch_begin)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_begin_event *event);
|
||||||
|
void (*pinch_update)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_update_event *event);
|
||||||
|
void (*pinch_end)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_end_event *event);
|
||||||
|
void (*swipe_begin)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_begin_event *event);
|
||||||
|
void (*swipe_update)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_update_event *event);
|
||||||
|
void (*swipe_end)(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_end_event *event);
|
||||||
void (*rebase)(struct sway_seat *seat, uint32_t time_msec);
|
void (*rebase)(struct sway_seat *seat, uint32_t time_msec);
|
||||||
void (*tablet_tool_motion)(struct sway_seat *seat,
|
void (*tablet_tool_motion)(struct sway_seat *seat,
|
||||||
struct sway_tablet_tool *tool, uint32_t time_msec);
|
struct sway_tablet_tool *tool, uint32_t time_msec);
|
||||||
|
@ -274,7 +290,7 @@ void seatop_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec);
|
void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec);
|
||||||
|
|
||||||
void seatop_pointer_axis(struct sway_seat *seat,
|
void seatop_pointer_axis(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_axis *event);
|
struct wlr_pointer_axis_event *event);
|
||||||
|
|
||||||
void seatop_tablet_tool_tip(struct sway_seat *seat,
|
void seatop_tablet_tool_tip(struct sway_seat *seat,
|
||||||
struct sway_tablet_tool *tool, uint32_t time_msec,
|
struct sway_tablet_tool *tool, uint32_t time_msec,
|
||||||
|
@ -283,6 +299,25 @@ void seatop_tablet_tool_tip(struct sway_seat *seat,
|
||||||
void seatop_tablet_tool_motion(struct sway_seat *seat,
|
void seatop_tablet_tool_motion(struct sway_seat *seat,
|
||||||
struct sway_tablet_tool *tool, uint32_t time_msec);
|
struct sway_tablet_tool *tool, uint32_t time_msec);
|
||||||
|
|
||||||
|
void seatop_hold_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_begin_event *event);
|
||||||
|
void seatop_hold_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_end_event *event);
|
||||||
|
|
||||||
|
void seatop_pinch_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_begin_event *event);
|
||||||
|
void seatop_pinch_update(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_update_event *event);
|
||||||
|
void seatop_pinch_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_end_event *event);
|
||||||
|
|
||||||
|
void seatop_swipe_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_begin_event *event);
|
||||||
|
void seatop_swipe_update(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_update_event *event);
|
||||||
|
void seatop_swipe_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_end_event *event);
|
||||||
|
|
||||||
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec);
|
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
struct sway_switch {
|
struct sway_switch {
|
||||||
struct sway_seat_device *seat_device;
|
struct sway_seat_device *seat_device;
|
||||||
|
struct wlr_switch *wlr;
|
||||||
enum wlr_switch_state state;
|
enum wlr_switch_state state;
|
||||||
enum wlr_switch_type type;
|
enum wlr_switch_type type;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ struct sway_tablet_pad {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
struct sway_seat_device *seat_device;
|
struct sway_seat_device *seat_device;
|
||||||
struct sway_tablet *tablet;
|
struct sway_tablet *tablet;
|
||||||
|
struct wlr_tablet_pad *wlr;
|
||||||
struct wlr_tablet_v2_tablet_pad *tablet_v2_pad;
|
struct wlr_tablet_v2_tablet_pad *tablet_v2_pad;
|
||||||
|
|
||||||
struct wl_listener attach;
|
struct wl_listener attach;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <wlr/types/wlr_text_input_v3.h>
|
#include <wlr/types/wlr_text_input_v3.h>
|
||||||
#include <wlr/types/wlr_input_method_v2.h>
|
#include <wlr/types/wlr_input_method_v2.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef _SWAY_IPC_JSON_H
|
#ifndef _SWAY_IPC_JSON_H
|
||||||
#define _SWAY_IPC_JSON_H
|
#define _SWAY_IPC_JSON_H
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
|
#include "sway/output.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
|
|
||||||
|
@ -9,6 +10,7 @@ json_object *ipc_json_get_version(void);
|
||||||
json_object *ipc_json_get_binding_mode(void);
|
json_object *ipc_json_get_binding_mode(void);
|
||||||
|
|
||||||
json_object *ipc_json_describe_disabled_output(struct sway_output *o);
|
json_object *ipc_json_describe_disabled_output(struct sway_output *o);
|
||||||
|
json_object *ipc_json_describe_non_desktop_output(struct sway_output_non_desktop *o);
|
||||||
json_object *ipc_json_describe_node(struct sway_node *node);
|
json_object *ipc_json_describe_node(struct sway_node *node);
|
||||||
json_object *ipc_json_describe_node_recursive(struct sway_node *node);
|
json_object *ipc_json_describe_node_recursive(struct sway_node *node);
|
||||||
json_object *ipc_json_describe_input(struct sway_input_device *device);
|
json_object *ipc_json_describe_input(struct sway_input_device *device);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef _SWAY_LAYERS_H
|
#ifndef _SWAY_LAYERS_H
|
||||||
#define _SWAY_LAYERS_H
|
#define _SWAY_LAYERS_H
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||||
|
|
||||||
enum layer_parent {
|
enum layer_parent {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/types/wlr_damage_ring.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "sway/desktop/fx_renderer.h"
|
#include "sway/desktop/fx_renderer.h"
|
||||||
|
@ -27,13 +28,13 @@ struct sway_output {
|
||||||
struct wlr_box usable_area;
|
struct wlr_box usable_area;
|
||||||
|
|
||||||
struct timespec last_frame;
|
struct timespec last_frame;
|
||||||
struct wlr_output_damage *damage;
|
struct wlr_damage_ring damage_ring;
|
||||||
|
|
||||||
int lx, ly; // layout coords
|
int lx, ly; // layout coords
|
||||||
int width, height; // transformed buffer size
|
int width, height; // transformed buffer size
|
||||||
enum wl_output_subpixel detected_subpixel;
|
enum wl_output_subpixel detected_subpixel;
|
||||||
enum scale_filter_mode scale_filter;
|
enum scale_filter_mode scale_filter;
|
||||||
// last applied mode when the output is DPMS'ed
|
// last applied mode when the output is powered off
|
||||||
struct wlr_output_mode *current_mode;
|
struct wlr_output_mode *current_mode;
|
||||||
|
|
||||||
bool enabling, enabled;
|
bool enabling, enabled;
|
||||||
|
@ -45,8 +46,9 @@ struct sway_output {
|
||||||
struct wl_listener commit;
|
struct wl_listener commit;
|
||||||
struct wl_listener mode;
|
struct wl_listener mode;
|
||||||
struct wl_listener present;
|
struct wl_listener present;
|
||||||
struct wl_listener damage_destroy;
|
struct wl_listener damage;
|
||||||
struct wl_listener damage_frame;
|
struct wl_listener frame;
|
||||||
|
struct wl_listener needs_frame;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct wl_signal disable;
|
struct wl_signal disable;
|
||||||
|
@ -58,6 +60,12 @@ struct sway_output {
|
||||||
struct wl_event_source *repaint_timer;
|
struct wl_event_source *repaint_timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sway_output_non_desktop {
|
||||||
|
struct wlr_output *wlr_output;
|
||||||
|
|
||||||
|
struct wl_listener destroy;
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_output *output_create(struct wlr_output *wlr_output);
|
struct sway_output *output_create(struct wlr_output *wlr_output);
|
||||||
|
|
||||||
void output_destroy(struct sway_output *output);
|
void output_destroy(struct sway_output *output);
|
||||||
|
@ -184,4 +192,6 @@ void handle_output_manager_test(struct wl_listener *listener, void *data);
|
||||||
void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
|
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <wlr/types/wlr_output_power_management_v1.h>
|
#include <wlr/types/wlr_output_power_management_v1.h>
|
||||||
#include <wlr/types/wlr_presentation_time.h>
|
#include <wlr/types/wlr_presentation_time.h>
|
||||||
#include <wlr/types/wlr_relative_pointer_v1.h>
|
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||||
|
#include <wlr/types/wlr_session_lock_v1.h>
|
||||||
#include <wlr/types/wlr_server_decoration.h>
|
#include <wlr/types/wlr_server_decoration.h>
|
||||||
#include <wlr/types/wlr_text_input_v3.h>
|
#include <wlr/types/wlr_text_input_v3.h>
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
@ -52,6 +53,7 @@ struct sway_server {
|
||||||
struct wl_listener output_layout_change;
|
struct wl_listener output_layout_change;
|
||||||
|
|
||||||
struct wlr_idle *idle;
|
struct wlr_idle *idle;
|
||||||
|
struct wlr_idle_notifier_v1 *idle_notifier_v1;
|
||||||
struct sway_idle_inhibit_manager_v1 *idle_inhibit_manager_v1;
|
struct sway_idle_inhibit_manager_v1 *idle_inhibit_manager_v1;
|
||||||
|
|
||||||
struct wlr_layer_shell_v1 *layer_shell;
|
struct wlr_layer_shell_v1 *layer_shell;
|
||||||
|
@ -90,6 +92,20 @@ struct sway_server {
|
||||||
struct wl_listener output_manager_apply;
|
struct wl_listener output_manager_apply;
|
||||||
struct wl_listener output_manager_test;
|
struct wl_listener output_manager_test;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool locked;
|
||||||
|
struct wlr_session_lock_manager_v1 *manager;
|
||||||
|
|
||||||
|
struct wlr_session_lock_v1 *lock;
|
||||||
|
struct wlr_surface *focused;
|
||||||
|
struct wl_listener lock_new_surface;
|
||||||
|
struct wl_listener lock_unlock;
|
||||||
|
struct wl_listener lock_destroy;
|
||||||
|
|
||||||
|
struct wl_listener new_lock;
|
||||||
|
struct wl_listener manager_destroy;
|
||||||
|
} session_lock;
|
||||||
|
|
||||||
struct wlr_output_power_manager_v1 *output_power_manager_v1;
|
struct wlr_output_power_manager_v1 *output_power_manager_v1;
|
||||||
struct wl_listener output_power_manager_set_mode;
|
struct wl_listener output_power_manager_set_mode;
|
||||||
struct wlr_input_method_manager_v2 *input_method;
|
struct wlr_input_method_manager_v2 *input_method;
|
||||||
|
@ -99,6 +115,8 @@ struct sway_server {
|
||||||
struct wlr_xdg_activation_v1 *xdg_activation_v1;
|
struct wlr_xdg_activation_v1 *xdg_activation_v1;
|
||||||
struct wl_listener xdg_activation_v1_request_activate;
|
struct wl_listener xdg_activation_v1_request_activate;
|
||||||
|
|
||||||
|
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
|
||||||
|
|
||||||
// The timeout for transactions, after which a transaction is applied
|
// The timeout for transactions, after which a transaction is applied
|
||||||
// regardless of readiness.
|
// regardless of readiness.
|
||||||
size_t txn_timeout_ms;
|
size_t txn_timeout_ms;
|
||||||
|
@ -135,8 +153,6 @@ struct sway_debug {
|
||||||
|
|
||||||
extern struct sway_debug debug;
|
extern struct sway_debug debug;
|
||||||
|
|
||||||
/* Prepares an unprivileged server_init by performing all privileged operations in advance */
|
|
||||||
bool server_privileged_prepare(struct sway_server *server);
|
|
||||||
bool server_init(struct sway_server *server);
|
bool server_init(struct sway_server *server);
|
||||||
void server_fini(struct sway_server *server);
|
void server_fini(struct sway_server *server);
|
||||||
bool server_start(struct sway_server *server);
|
bool server_start(struct sway_server *server);
|
||||||
|
@ -149,6 +165,7 @@ void handle_new_output(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
|
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
|
||||||
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
|
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
|
||||||
|
void sway_session_lock_init(void);
|
||||||
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
|
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
||||||
|
@ -159,4 +176,6 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data);
|
||||||
void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
|
void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
|
void set_rr_scheduling(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef _SWAY_SURFACE_H
|
#ifndef _SWAY_SURFACE_H
|
||||||
#define _SWAY_SURFACE_H
|
#define _SWAY_SURFACE_H
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
|
||||||
struct sway_surface {
|
struct sway_surface {
|
||||||
struct wlr_surface *wlr_surface;
|
struct wlr_surface *wlr_surface;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define _SWAY_CONTAINER_H
|
#define _SWAY_CONTAINER_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "sway/tree/node.h"
|
#include "sway/tree/node.h"
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ bool container_is_sticky_or_child(struct sway_container *con);
|
||||||
* This will destroy pairs of redundant H/V splits
|
* This will destroy pairs of redundant H/V splits
|
||||||
* e.g. H[V[H[app app]] app] -> H[app app app]
|
* e.g. H[V[H[app app]] app] -> H[app app app]
|
||||||
* The middle "V[H[" are eliminated by a call to container_squash
|
* The middle "V[H[" are eliminated by a call to container_squash
|
||||||
* on the V[ con. It's grandchildren are added to it's parent.
|
* on the V[ con. It's grandchildren are added to its parent.
|
||||||
*
|
*
|
||||||
* This function is roughly equivalent to i3's tree_flatten here:
|
* This function is roughly equivalent to i3's tree_flatten here:
|
||||||
* https://github.com/i3/i3/blob/1f0c628cde40cf87371481041b7197344e0417c6/src/tree.c#L651
|
* https://github.com/i3/i3/blob/1f0c628cde40cf87371481041b7197344e0417c6/src/tree.c#L651
|
||||||
|
|
|
@ -28,6 +28,7 @@ struct sway_root {
|
||||||
double width, height;
|
double width, height;
|
||||||
|
|
||||||
list_t *outputs; // struct sway_output
|
list_t *outputs; // struct sway_output
|
||||||
|
list_t *non_desktop_outputs; // struct sway_output_non_desktop
|
||||||
list_t *scratchpad; // struct sway_container
|
list_t *scratchpad; // struct sway_container
|
||||||
|
|
||||||
// For when there's no connected outputs
|
// For when there's no connected outputs
|
||||||
|
@ -68,12 +69,6 @@ void root_scratchpad_show(struct sway_container *con);
|
||||||
*/
|
*/
|
||||||
void root_scratchpad_hide(struct sway_container *con);
|
void root_scratchpad_hide(struct sway_container *con);
|
||||||
|
|
||||||
struct sway_workspace *root_workspace_for_pid(pid_t pid);
|
|
||||||
|
|
||||||
void root_record_workspace_pid(pid_t pid);
|
|
||||||
|
|
||||||
void root_remove_workspace_pid(pid_t pid);
|
|
||||||
|
|
||||||
void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data),
|
void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data),
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
|
@ -91,6 +86,4 @@ struct sway_container *root_find_container(
|
||||||
|
|
||||||
void root_get_box(struct sway_root *root, struct wlr_box *box);
|
void root_get_box(struct sway_root *root, struct wlr_box *box);
|
||||||
|
|
||||||
void root_rename_pid_workspaces(const char *old_name, const char *new_name);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef _SWAY_VIEW_H
|
#ifndef _SWAY_VIEW_H
|
||||||
#define _SWAY_VIEW_H
|
#define _SWAY_VIEW_H
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
#include <wlr/xwayland.h>
|
#include <wlr/xwayland.h>
|
||||||
|
@ -74,6 +74,7 @@ struct sway_view {
|
||||||
struct sway_xdg_decoration *xdg_decoration;
|
struct sway_xdg_decoration *xdg_decoration;
|
||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
struct launcher_ctx *ctx;
|
||||||
|
|
||||||
// The size the view would want to be if it weren't tiled.
|
// The size the view would want to be if it weren't tiled.
|
||||||
// Used when changing a view from tiled to floating.
|
// Used when changing a view from tiled to floating.
|
||||||
|
@ -109,7 +110,7 @@ struct sway_view {
|
||||||
list_t *executed_criteria; // struct criteria *
|
list_t *executed_criteria; // struct criteria *
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct wlr_xdg_surface *wlr_xdg_surface;
|
struct wlr_xdg_toplevel *wlr_xdg_toplevel;
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
struct wlr_xwayland_surface *wlr_xwayland_surface;
|
struct wlr_xwayland_surface *wlr_xwayland_surface;
|
||||||
#endif
|
#endif
|
||||||
|
@ -132,6 +133,7 @@ struct sway_xdg_shell_view {
|
||||||
struct wl_listener commit;
|
struct wl_listener commit;
|
||||||
struct wl_listener request_move;
|
struct wl_listener request_move;
|
||||||
struct wl_listener request_resize;
|
struct wl_listener request_resize;
|
||||||
|
struct wl_listener request_maximize;
|
||||||
struct wl_listener request_fullscreen;
|
struct wl_listener request_fullscreen;
|
||||||
struct wl_listener set_title;
|
struct wl_listener set_title;
|
||||||
struct wl_listener set_app_id;
|
struct wl_listener set_app_id;
|
||||||
|
@ -155,6 +157,7 @@ struct sway_xwayland_view {
|
||||||
struct wl_listener set_title;
|
struct wl_listener set_title;
|
||||||
struct wl_listener set_class;
|
struct wl_listener set_class;
|
||||||
struct wl_listener set_role;
|
struct wl_listener set_role;
|
||||||
|
struct wl_listener set_startup_id;
|
||||||
struct wl_listener set_window_type;
|
struct wl_listener set_window_type;
|
||||||
struct wl_listener set_hints;
|
struct wl_listener set_hints;
|
||||||
struct wl_listener set_decorations;
|
struct wl_listener set_decorations;
|
||||||
|
@ -170,6 +173,7 @@ struct sway_xwayland_unmanaged {
|
||||||
|
|
||||||
int lx, ly;
|
int lx, ly;
|
||||||
|
|
||||||
|
struct wl_listener request_activate;
|
||||||
struct wl_listener request_configure;
|
struct wl_listener request_configure;
|
||||||
struct wl_listener request_fullscreen;
|
struct wl_listener request_fullscreen;
|
||||||
struct wl_listener commit;
|
struct wl_listener commit;
|
||||||
|
@ -217,7 +221,7 @@ struct sway_subsurface {
|
||||||
struct sway_xdg_popup {
|
struct sway_xdg_popup {
|
||||||
struct sway_view_child child;
|
struct sway_view_child child;
|
||||||
|
|
||||||
struct wlr_xdg_surface *wlr_xdg_surface;
|
struct wlr_xdg_popup *wlr_xdg_popup;
|
||||||
|
|
||||||
struct wl_listener new_popup;
|
struct wl_listener new_popup;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
|
@ -371,4 +375,6 @@ void view_save_buffer(struct sway_view *view);
|
||||||
|
|
||||||
bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
|
bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
|
||||||
|
|
||||||
|
void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -58,7 +58,6 @@ struct swaybar_output {
|
||||||
struct zxdg_output_v1 *xdg_output;
|
struct zxdg_output_v1 *xdg_output;
|
||||||
struct wl_surface *surface;
|
struct wl_surface *surface;
|
||||||
struct zwlr_layer_surface_v1 *layer_surface;
|
struct zwlr_layer_surface_v1 *layer_surface;
|
||||||
struct wl_region *input_region;
|
|
||||||
uint32_t wl_name;
|
uint32_t wl_name;
|
||||||
|
|
||||||
struct wl_list workspaces; // swaybar_workspace::link
|
struct wl_list workspaces; // swaybar_workspace::link
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "../include/config.h"
|
#include "../include/config.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
struct box_colors {
|
struct box_colors {
|
||||||
uint32_t border;
|
uint32_t border;
|
||||||
|
@ -28,7 +29,7 @@ struct swaybar_config {
|
||||||
char *status_command;
|
char *status_command;
|
||||||
bool pango_markup;
|
bool pango_markup;
|
||||||
uint32_t position; // zwlr_layer_surface_v1_anchor
|
uint32_t position; // zwlr_layer_surface_v1_anchor
|
||||||
char *font;
|
PangoFontDescription *font_description;
|
||||||
char *sep_symbol;
|
char *sep_symbol;
|
||||||
char *mode;
|
char *mode;
|
||||||
char *hidden_state;
|
char *hidden_state;
|
||||||
|
|
|
@ -30,6 +30,6 @@ void i3bar_block_unref(struct i3bar_block *block);
|
||||||
bool i3bar_handle_readable(struct status_line *status);
|
bool i3bar_handle_readable(struct status_line *status);
|
||||||
enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
|
enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
|
||||||
struct i3bar_block *block, double x, double y, double rx, double ry,
|
struct i3bar_block *block, double x, double y, double rx, double ry,
|
||||||
double w, double h, int scale, uint32_t button);
|
double w, double h, int scale, uint32_t button, bool released);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct swaybar_hotspot {
|
||||||
int x, y, width, height;
|
int x, y, width, height;
|
||||||
enum hotspot_event_handling (*callback)(struct swaybar_output *output,
|
enum hotspot_event_handling (*callback)(struct swaybar_output *output,
|
||||||
struct swaybar_hotspot *hotspot, double x, double y, uint32_t button,
|
struct swaybar_hotspot *hotspot, double x, double y, uint32_t button,
|
||||||
void *data);
|
bool released, void *data);
|
||||||
void (*destroy)(void *data);
|
void (*destroy)(void *data);
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
|
@ -67,7 +67,7 @@ struct swaynag_details {
|
||||||
int offset;
|
int offset;
|
||||||
int visible_lines;
|
int visible_lines;
|
||||||
int total_lines;
|
int total_lines;
|
||||||
struct swaynag_button *button_details;
|
struct swaynag_button button_details;
|
||||||
struct swaynag_button button_up;
|
struct swaynag_button button_up;
|
||||||
struct swaynag_button button_down;
|
struct swaynag_button button_down;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
struct swaynag_type {
|
struct swaynag_type {
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
char *font;
|
char *font; // Used for debugging.
|
||||||
|
PangoFontDescription *font_description;
|
||||||
char *output;
|
char *output;
|
||||||
uint32_t anchors;
|
uint32_t anchors;
|
||||||
int32_t layer; // enum zwlr_layer_shell_v1_layer or -1 if unset
|
int32_t layer; // enum zwlr_layer_shell_v1_layer or -1 if unset
|
||||||
|
|
34
meson.build
34
meson.build
|
@ -35,14 +35,24 @@ if is_freebsd
|
||||||
add_project_arguments('-D_C11_SOURCE', language: 'c')
|
add_project_arguments('-D_C11_SOURCE', language: 'c')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Execute the wlroots subproject, if any
|
||||||
|
wlroots_version = ['>=0.16.0', '<0.17.0']
|
||||||
|
subproject(
|
||||||
|
'wlroots',
|
||||||
|
default_options: ['examples=false'],
|
||||||
|
required: false,
|
||||||
|
version: wlroots_version,
|
||||||
|
)
|
||||||
|
|
||||||
jsonc = dependency('json-c', version: '>=0.13')
|
jsonc = dependency('json-c', version: '>=0.13')
|
||||||
pcre = dependency('libpcre')
|
pcre2 = dependency('libpcre2-8')
|
||||||
wayland_server = dependency('wayland-server', version: '>=1.20.0')
|
wayland_server = dependency('wayland-server', version: '>=1.21.0')
|
||||||
wayland_client = dependency('wayland-client')
|
wayland_client = dependency('wayland-client')
|
||||||
wayland_cursor = dependency('wayland-cursor')
|
wayland_cursor = dependency('wayland-cursor')
|
||||||
wayland_egl = dependency('wayland-egl')
|
wayland_egl = dependency('wayland-egl')
|
||||||
egl = dependency('egl')
|
egl = dependency('egl')
|
||||||
wayland_protos = dependency('wayland-protocols', version: '>=1.24')
|
wayland_protos = dependency('wayland-protocols', version: '>=1.24')
|
||||||
|
wlroots = dependency('wlroots', version: wlroots_version)
|
||||||
xkbcommon = dependency('xkbcommon')
|
xkbcommon = dependency('xkbcommon')
|
||||||
cairo = dependency('cairo')
|
cairo = dependency('cairo')
|
||||||
pango = dependency('pango')
|
pango = dependency('pango')
|
||||||
|
@ -51,7 +61,7 @@ gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
|
||||||
pixman = dependency('pixman-1')
|
pixman = dependency('pixman-1')
|
||||||
glesv2 = dependency('glesv2')
|
glesv2 = dependency('glesv2')
|
||||||
libevdev = dependency('libevdev')
|
libevdev = dependency('libevdev')
|
||||||
libinput = dependency('libinput', version: '>=1.6.0')
|
libinput = dependency('libinput', version: '>=1.21.0')
|
||||||
xcb = dependency('xcb', required: get_option('xwayland'))
|
xcb = dependency('xcb', required: get_option('xwayland'))
|
||||||
drm_full = dependency('libdrm') # only needed for drm_fourcc.h
|
drm_full = dependency('libdrm') # only needed for drm_fourcc.h
|
||||||
drm = drm_full.partial_dependency(compile_args: true, includes: true)
|
drm = drm_full.partial_dependency(compile_args: true, includes: true)
|
||||||
|
@ -60,20 +70,8 @@ bash_comp = dependency('bash-completion', required: false)
|
||||||
fish_comp = dependency('fish', required: false)
|
fish_comp = dependency('fish', required: false)
|
||||||
math = cc.find_library('m')
|
math = cc.find_library('m')
|
||||||
rt = cc.find_library('rt')
|
rt = cc.find_library('rt')
|
||||||
|
xcb_icccm = dependency('xcb-icccm', required: get_option('xwayland'))
|
||||||
# Try first to find wlroots as a subproject, then as a system dependency
|
threads = dependency('threads') # for pthread_setschedparam
|
||||||
wlroots_version = ['>=0.15.0', '<0.16.0']
|
|
||||||
wlroots_proj = subproject(
|
|
||||||
'wlroots',
|
|
||||||
default_options: ['examples=false'],
|
|
||||||
required: false,
|
|
||||||
version: wlroots_version,
|
|
||||||
)
|
|
||||||
if wlroots_proj.found()
|
|
||||||
wlroots = wlroots_proj.get_variable('wlroots')
|
|
||||||
else
|
|
||||||
wlroots = dependency('wlroots', version: wlroots_version)
|
|
||||||
endif
|
|
||||||
|
|
||||||
wlroots_features = {
|
wlroots_features = {
|
||||||
'xwayland': false,
|
'xwayland': false,
|
||||||
|
@ -87,7 +85,7 @@ endforeach
|
||||||
if get_option('xwayland').enabled() and not wlroots_features['xwayland']
|
if get_option('xwayland').enabled() and not wlroots_features['xwayland']
|
||||||
error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support')
|
error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support')
|
||||||
endif
|
endif
|
||||||
have_xwayland = xcb.found() and wlroots_features['xwayland']
|
have_xwayland = xcb.found() and xcb_icccm.found() and wlroots_features['xwayland']
|
||||||
|
|
||||||
if get_option('sd-bus-provider') == 'auto'
|
if get_option('sd-bus-provider') == 'auto'
|
||||||
if not get_option('tray').disabled()
|
if not get_option('tray').disabled()
|
||||||
|
|
|
@ -1,81 +1,42 @@
|
||||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||||
|
|
||||||
wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)
|
wayland_scanner_dep = dependency('wayland-scanner', native: true)
|
||||||
if wayland_scanner_dep.found()
|
wayland_scanner = find_program(
|
||||||
wayland_scanner = find_program(
|
wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'),
|
||||||
wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'),
|
native: true,
|
||||||
native: true,
|
)
|
||||||
)
|
|
||||||
else
|
|
||||||
wayland_scanner = find_program('wayland-scanner', native: true)
|
|
||||||
endif
|
|
||||||
|
|
||||||
protocols = [
|
protocols = [
|
||||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.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/xdg-output/xdg-output-unstable-v1.xml',
|
||||||
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
|
wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
|
||||||
[wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'],
|
wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.xml',
|
||||||
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
|
wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
'wlr-layer-shell-unstable-v1.xml',
|
||||||
['idle.xml'],
|
'idle.xml',
|
||||||
['wlr-input-inhibitor-unstable-v1.xml'],
|
'wlr-input-inhibitor-unstable-v1.xml',
|
||||||
['wlr-output-power-management-unstable-v1.xml'],
|
'wlr-output-power-management-unstable-v1.xml',
|
||||||
]
|
|
||||||
|
|
||||||
client_protocols = [
|
|
||||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
|
||||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
|
||||||
['wlr-input-inhibitor-unstable-v1.xml'],
|
|
||||||
]
|
]
|
||||||
|
|
||||||
wl_protos_src = []
|
wl_protos_src = []
|
||||||
wl_protos_headers = []
|
|
||||||
|
|
||||||
foreach p : protocols
|
foreach xml : protocols
|
||||||
xml = join_paths(p)
|
|
||||||
wl_protos_src += custom_target(
|
wl_protos_src += custom_target(
|
||||||
xml.underscorify() + '_server_c',
|
xml.underscorify() + '_c',
|
||||||
input: xml,
|
input: xml,
|
||||||
output: '@BASENAME@-protocol.c',
|
output: '@BASENAME@-protocol.c',
|
||||||
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
|
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
|
||||||
)
|
)
|
||||||
wl_protos_headers += custom_target(
|
wl_protos_src += custom_target(
|
||||||
xml.underscorify() + '_server_h',
|
xml.underscorify() + '_server_h',
|
||||||
input: xml,
|
input: xml,
|
||||||
output: '@BASENAME@-protocol.h',
|
output: '@BASENAME@-protocol.h',
|
||||||
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
|
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
|
||||||
)
|
)
|
||||||
endforeach
|
wl_protos_src += custom_target(
|
||||||
|
|
||||||
foreach p : client_protocols
|
|
||||||
xml = join_paths(p)
|
|
||||||
wl_protos_headers += custom_target(
|
|
||||||
xml.underscorify() + '_client_h',
|
xml.underscorify() + '_client_h',
|
||||||
input: xml,
|
input: xml,
|
||||||
output: '@BASENAME@-client-protocol.h',
|
output: '@BASENAME@-client-protocol.h',
|
||||||
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],
|
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],
|
||||||
)
|
)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
lib_client_protos = static_library(
|
|
||||||
'client_protos',
|
|
||||||
wl_protos_src + wl_protos_headers,
|
|
||||||
dependencies: wayland_client.partial_dependency(compile_args: true),
|
|
||||||
)
|
|
||||||
|
|
||||||
client_protos = declare_dependency(
|
|
||||||
link_with: lib_client_protos,
|
|
||||||
sources: wl_protos_headers,
|
|
||||||
)
|
|
||||||
|
|
||||||
lib_server_protos = static_library(
|
|
||||||
'server_protos',
|
|
||||||
wl_protos_src + wl_protos_headers,
|
|
||||||
dependencies: wayland_server.partial_dependency(compile_args: true),
|
|
||||||
)
|
|
||||||
|
|
||||||
server_protos = declare_dependency(
|
|
||||||
link_with: lib_server_protos,
|
|
||||||
sources: wl_protos_headers,
|
|
||||||
)
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ static const struct cmd_handler handlers[] = {
|
||||||
{ "assign", cmd_assign },
|
{ "assign", cmd_assign },
|
||||||
{ "bar", cmd_bar },
|
{ "bar", cmd_bar },
|
||||||
{ "bindcode", cmd_bindcode },
|
{ "bindcode", cmd_bindcode },
|
||||||
|
{ "bindgesture", cmd_bindgesture },
|
||||||
{ "bindswitch", cmd_bindswitch },
|
{ "bindswitch", cmd_bindswitch },
|
||||||
{ "bindsym", cmd_bindsym },
|
{ "bindsym", cmd_bindsym },
|
||||||
{ "client.background", cmd_client_noop },
|
{ "client.background", cmd_client_noop },
|
||||||
|
@ -96,6 +97,7 @@ static const struct cmd_handler handlers[] = {
|
||||||
{ "titlebar_border_thickness", cmd_titlebar_border_thickness },
|
{ "titlebar_border_thickness", cmd_titlebar_border_thickness },
|
||||||
{ "titlebar_padding", cmd_titlebar_padding },
|
{ "titlebar_padding", cmd_titlebar_padding },
|
||||||
{ "unbindcode", cmd_unbindcode },
|
{ "unbindcode", cmd_unbindcode },
|
||||||
|
{ "unbindgesture", cmd_unbindgesture },
|
||||||
{ "unbindswitch", cmd_unbindswitch },
|
{ "unbindswitch", cmd_unbindswitch },
|
||||||
{ "unbindsym", cmd_unbindsym },
|
{ "unbindsym", cmd_unbindsym },
|
||||||
{ "workspace", cmd_workspace },
|
{ "workspace", cmd_workspace },
|
||||||
|
@ -412,6 +414,7 @@ struct cmd_results *config_command(char *exec, char **new_block) {
|
||||||
&& handler->handle != cmd_bindsym
|
&& handler->handle != cmd_bindsym
|
||||||
&& handler->handle != cmd_bindcode
|
&& handler->handle != cmd_bindcode
|
||||||
&& handler->handle != cmd_bindswitch
|
&& handler->handle != cmd_bindswitch
|
||||||
|
&& handler->handle != cmd_bindgesture
|
||||||
&& handler->handle != cmd_set
|
&& handler->handle != cmd_set
|
||||||
&& handler->handle != cmd_for_window
|
&& handler->handle != cmd_for_window
|
||||||
&& (*argv[i] == '\"' || *argv[i] == '\'')) {
|
&& (*argv[i] == '\"' || *argv[i] == '\'')) {
|
||||||
|
@ -487,13 +490,19 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
|
||||||
}
|
}
|
||||||
results->status = status;
|
results->status = status;
|
||||||
if (format) {
|
if (format) {
|
||||||
char *error = malloc(256);
|
char *error = NULL;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
if (error) {
|
int slen = vsnprintf(NULL, 0, format, args);
|
||||||
vsnprintf(error, 256, format, args);
|
|
||||||
}
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
if (slen > 0) {
|
||||||
|
error = malloc(slen + 1);
|
||||||
|
if (error != NULL) {
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(error, slen + 1, format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
results->error = error;
|
results->error = error;
|
||||||
} else {
|
} else {
|
||||||
results->error = NULL;
|
results->error = NULL;
|
||||||
|
|
|
@ -47,7 +47,7 @@ static bool binding_switch_compare(struct sway_switch_binding *binding_a,
|
||||||
if (binding_a->type != binding_b->type) {
|
if (binding_a->type != binding_b->type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (binding_a->state != binding_b->state) {
|
if (binding_a->trigger != binding_b->trigger) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((binding_a->flags & BINDING_LOCKED) !=
|
if ((binding_a->flags & BINDING_LOCKED) !=
|
||||||
|
@ -372,6 +372,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
|
||||||
strlen("--input-device=")) == 0) {
|
strlen("--input-device=")) == 0) {
|
||||||
free(binding->input);
|
free(binding->input);
|
||||||
binding->input = strdup(argv[0] + strlen("--input-device="));
|
binding->input = strdup(argv[0] + strlen("--input-device="));
|
||||||
|
strip_quotes(binding->input);
|
||||||
} else if (strcmp("--no-warn", argv[0]) == 0) {
|
} else if (strcmp("--no-warn", argv[0]) == 0) {
|
||||||
warn = false;
|
warn = false;
|
||||||
} else if (strcmp("--no-repeat", argv[0]) == 0) {
|
} else if (strcmp("--no-repeat", argv[0]) == 0) {
|
||||||
|
@ -551,11 +552,11 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
|
||||||
"unknown switch %s)", bindtype, split->items[0]);
|
"unknown switch %s)", bindtype, split->items[0]);
|
||||||
}
|
}
|
||||||
if (strcmp(split->items[1], "on") == 0) {
|
if (strcmp(split->items[1], "on") == 0) {
|
||||||
binding->state = WLR_SWITCH_STATE_ON;
|
binding->trigger = SWAY_SWITCH_TRIGGER_ON;
|
||||||
} else if (strcmp(split->items[1], "off") == 0) {
|
} else if (strcmp(split->items[1], "off") == 0) {
|
||||||
binding->state = WLR_SWITCH_STATE_OFF;
|
binding->trigger = SWAY_SWITCH_TRIGGER_OFF;
|
||||||
} else if (strcmp(split->items[1], "toggle") == 0) {
|
} else if (strcmp(split->items[1], "toggle") == 0) {
|
||||||
binding->state = WLR_SWITCH_STATE_TOGGLE;
|
binding->trigger = SWAY_SWITCH_TRIGGER_TOGGLE;
|
||||||
} else {
|
} else {
|
||||||
free_switch_binding(binding);
|
free_switch_binding(binding);
|
||||||
return cmd_results_new(CMD_FAILURE,
|
return cmd_results_new(CMD_FAILURE,
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
|
#include "sway/desktop/launcher.h"
|
||||||
|
#include "sway/server.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
|
@ -25,11 +27,22 @@ struct cmd_results *cmd_exec_validate(int argc, char **argv) {
|
||||||
return error;
|
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 *cmd_exec_process(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
char *cmd = NULL;
|
char *cmd = NULL;
|
||||||
|
bool no_startup_id = false;
|
||||||
if (strcmp(argv[0], "--no-startup-id") == 0) {
|
if (strcmp(argv[0], "--no-startup-id") == 0) {
|
||||||
sway_log(SWAY_INFO, "exec switch '--no-startup-id' not supported, ignored.");
|
no_startup_id = true;
|
||||||
--argc; ++argv;
|
--argc; ++argv;
|
||||||
if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
|
if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
|
||||||
return error;
|
return error;
|
||||||
|
@ -51,6 +64,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t pid, child;
|
pid_t pid, child;
|
||||||
|
struct launcher_ctx *ctx = launcher_ctx_create();
|
||||||
// Fork process
|
// Fork process
|
||||||
if ((pid = fork()) == 0) {
|
if ((pid = fork()) == 0) {
|
||||||
// Fork child process again
|
// Fork child process again
|
||||||
|
@ -63,6 +77,12 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
if ((child = fork()) == 0) {
|
if ((child = fork()) == 0) {
|
||||||
close(fd[1]);
|
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);
|
execlp("sh", "sh", "-c", cmd, (void *)NULL);
|
||||||
sway_log_errno(SWAY_ERROR, "execlp failed");
|
sway_log_errno(SWAY_ERROR, "execlp failed");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
@ -90,8 +110,12 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
waitpid(pid, NULL, 0);
|
waitpid(pid, NULL, 0);
|
||||||
if (child > 0) {
|
if (child > 0) {
|
||||||
sway_log(SWAY_DEBUG, "Child process created with pid %d", child);
|
sway_log(SWAY_DEBUG, "Child process created with pid %d", child);
|
||||||
root_record_workspace_pid(child);
|
if (ctx != NULL) {
|
||||||
|
sway_log(SWAY_DEBUG, "Recording workspace for process %d", child);
|
||||||
|
ctx->pid = child;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
launcher_ctx_destroy(ctx);
|
||||||
return cmd_results_new(CMD_FAILURE, "Second fork() failed");
|
return cmd_results_new(CMD_FAILURE, "Second fork() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,7 +285,7 @@ static struct cmd_results *focus_mode(struct sway_workspace *ws,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return cmd_results_new(CMD_FAILURE,
|
return cmd_results_new(CMD_FAILURE,
|
||||||
"Failed to find a %s container in workspace",
|
"Failed to find a %s container in workspace.",
|
||||||
floating ? "floating" : "tiling");
|
floating ? "floating" : "tiling");
|
||||||
}
|
}
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
@ -295,7 +295,7 @@ static struct cmd_results *focus_output(struct sway_seat *seat,
|
||||||
int argc, char **argv) {
|
int argc, char **argv) {
|
||||||
if (!argc) {
|
if (!argc) {
|
||||||
return cmd_results_new(CMD_INVALID,
|
return cmd_results_new(CMD_INVALID,
|
||||||
"Expected 'focus output <direction|name>'");
|
"Expected 'focus output <direction|name>'.");
|
||||||
}
|
}
|
||||||
char *identifier = join_args(argv, argc);
|
char *identifier = join_args(argv, argc);
|
||||||
struct sway_output *output = output_by_name_or_id(identifier);
|
struct sway_output *output = output_by_name_or_id(identifier);
|
||||||
|
@ -305,13 +305,13 @@ static struct cmd_results *focus_output(struct sway_seat *seat,
|
||||||
if (!parse_direction(identifier, &direction)) {
|
if (!parse_direction(identifier, &direction)) {
|
||||||
free(identifier);
|
free(identifier);
|
||||||
return cmd_results_new(CMD_INVALID,
|
return cmd_results_new(CMD_INVALID,
|
||||||
"There is no output with that name");
|
"There is no output with that name.");
|
||||||
}
|
}
|
||||||
struct sway_workspace *ws = seat_get_focused_workspace(seat);
|
struct sway_workspace *ws = seat_get_focused_workspace(seat);
|
||||||
if (!ws) {
|
if (!ws) {
|
||||||
free(identifier);
|
free(identifier);
|
||||||
return cmd_results_new(CMD_FAILURE,
|
return cmd_results_new(CMD_FAILURE,
|
||||||
"No focused workspace to base directions off of");
|
"No focused workspace to base directions off of.");
|
||||||
}
|
}
|
||||||
output = output_get_in_direction(ws->output, direction);
|
output = output_get_in_direction(ws->output, direction);
|
||||||
|
|
||||||
|
@ -375,10 +375,14 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
|
||||||
struct sway_seat *seat = config->handler_context.seat;
|
struct sway_seat *seat = config->handler_context.seat;
|
||||||
if (node->type < N_WORKSPACE) {
|
if (node->type < N_WORKSPACE) {
|
||||||
return cmd_results_new(CMD_FAILURE,
|
return cmd_results_new(CMD_FAILURE,
|
||||||
"Command 'focus' cannot be used above the workspace level");
|
"Command 'focus' cannot be used above the workspace level.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 0 && container) {
|
if (argc == 0) {
|
||||||
|
if (!container) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "No container to focus was specified.");
|
||||||
|
}
|
||||||
|
|
||||||
if (container_is_scratchpad_hidden_or_child(container)) {
|
if (container_is_scratchpad_hidden_or_child(container)) {
|
||||||
root_scratchpad_show(container);
|
root_scratchpad_show(container);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
#include <pango/pangocairo.h>
|
||||||
|
|
||||||
struct cmd_results *cmd_font(int argc, char **argv) {
|
struct cmd_results *cmd_font(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
|
@ -16,12 +17,34 @@ struct cmd_results *cmd_font(int argc, char **argv) {
|
||||||
if (strncmp(font, "pango:", 6) == 0) {
|
if (strncmp(font, "pango:", 6) == 0) {
|
||||||
config->pango_markup = true;
|
config->pango_markup = true;
|
||||||
config->font = strdup(font + 6);
|
config->font = strdup(font + 6);
|
||||||
|
free(font);
|
||||||
} else {
|
} else {
|
||||||
config->pango_markup = false;
|
config->pango_markup = false;
|
||||||
config->font = strdup(font);
|
config->font = font;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(font);
|
// Parse the font early so we can reject it if it's not valid for pango.
|
||||||
|
// Also avoids re-parsing each time we render text.
|
||||||
|
PangoFontDescription *font_description = pango_font_description_from_string(config->font);
|
||||||
|
|
||||||
|
const char *family = pango_font_description_get_family(font_description);
|
||||||
|
if (family == NULL) {
|
||||||
|
pango_font_description_free(font_description);
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Invalid font family.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const gint size = pango_font_description_get_size(font_description);
|
||||||
|
if (size == 0) {
|
||||||
|
pango_font_description_free(font_description);
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Invalid font size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->font_description != NULL) {
|
||||||
|
pango_font_description_free(config->font_description);
|
||||||
|
}
|
||||||
|
|
||||||
|
config->font_description = font_description;
|
||||||
config_update_font_height();
|
config_update_font_height();
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
166
sway/commands/gesture.c
Normal file
166
sway/commands/gesture.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "sway/config.h"
|
||||||
|
|
||||||
|
#include "gesture.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "stringop.h"
|
||||||
|
#include "sway/commands.h"
|
||||||
|
|
||||||
|
void free_gesture_binding(struct sway_gesture_binding *binding) {
|
||||||
|
if (!binding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(binding->input);
|
||||||
|
free(binding->command);
|
||||||
|
free(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the bindings have the same gesture type, direction, etc
|
||||||
|
*/
|
||||||
|
static bool binding_gesture_equal(struct sway_gesture_binding *binding_a,
|
||||||
|
struct sway_gesture_binding *binding_b) {
|
||||||
|
if (strcmp(binding_a->input, binding_b->input) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gesture_equal(&binding_a->gesture, &binding_b->gesture)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((binding_a->flags & BINDING_EXACT) !=
|
||||||
|
(binding_b->flags & BINDING_EXACT)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add gesture binding to config
|
||||||
|
*/
|
||||||
|
static struct cmd_results *gesture_binding_add(
|
||||||
|
struct sway_gesture_binding *binding,
|
||||||
|
const char *gesturecombo, bool warn) {
|
||||||
|
list_t *mode_bindings = config->current_mode->gesture_bindings;
|
||||||
|
// overwrite the binding if it already exists
|
||||||
|
bool overwritten = false;
|
||||||
|
for (int i = 0; i < mode_bindings->length; ++i) {
|
||||||
|
struct sway_gesture_binding *config_binding = mode_bindings->items[i];
|
||||||
|
if (binding_gesture_equal(binding, config_binding)) {
|
||||||
|
sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`",
|
||||||
|
gesturecombo, binding->command, config_binding->command);
|
||||||
|
if (warn) {
|
||||||
|
config_add_swaynag_warning("Overwriting binding"
|
||||||
|
"'%s' to `%s` from `%s`",
|
||||||
|
gesturecombo, binding->command,
|
||||||
|
config_binding->command);
|
||||||
|
}
|
||||||
|
free_gesture_binding(config_binding);
|
||||||
|
mode_bindings->items[i] = binding;
|
||||||
|
overwritten = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!overwritten) {
|
||||||
|
list_add(mode_bindings, binding);
|
||||||
|
sway_log(SWAY_DEBUG, "bindgesture - Bound %s to command `%s`",
|
||||||
|
gesturecombo, binding->command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove gesture binding from config
|
||||||
|
*/
|
||||||
|
static struct cmd_results *gesture_binding_remove(
|
||||||
|
struct sway_gesture_binding *binding, const char *gesturecombo) {
|
||||||
|
list_t *mode_bindings = config->current_mode->gesture_bindings;
|
||||||
|
for (int i = 0; i < mode_bindings->length; ++i) {
|
||||||
|
struct sway_gesture_binding *config_binding = mode_bindings->items[i];
|
||||||
|
if (binding_gesture_equal(binding, config_binding)) {
|
||||||
|
free_gesture_binding(config_binding);
|
||||||
|
free_gesture_binding(binding);
|
||||||
|
list_del(mode_bindings, i);
|
||||||
|
sway_log(SWAY_DEBUG, "unbindgesture - Unbound %s gesture",
|
||||||
|
gesturecombo);
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_gesture_binding(binding);
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Could not find gesture binding `%s`",
|
||||||
|
gesturecombo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse and execute bindgesture or unbindgesture command.
|
||||||
|
*/
|
||||||
|
static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, bool unbind) {
|
||||||
|
int minargs = 2;
|
||||||
|
char *bindtype = "bindgesture";
|
||||||
|
if (unbind) {
|
||||||
|
minargs--;
|
||||||
|
bindtype = "unbindgesture";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd_results *error = NULL;
|
||||||
|
if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
struct sway_gesture_binding *binding = calloc(1, sizeof(struct sway_gesture_binding));
|
||||||
|
if (!binding) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Unable to allocate binding");
|
||||||
|
}
|
||||||
|
binding->input = strdup("*");
|
||||||
|
|
||||||
|
bool warn = true;
|
||||||
|
|
||||||
|
// Handle flags
|
||||||
|
while (argc > 0) {
|
||||||
|
if (strcmp("--exact", argv[0]) == 0) {
|
||||||
|
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) {
|
||||||
|
free(binding->input);
|
||||||
|
binding->input = strdup(argv[0] + strlen("--input-device="));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < minargs) {
|
||||||
|
free(binding);
|
||||||
|
return cmd_results_new(CMD_FAILURE,
|
||||||
|
"Invalid %s command (expected at least %d "
|
||||||
|
"non-option arguments, got %d)", bindtype, minargs, argc);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* errmsg = NULL;
|
||||||
|
if ((errmsg = gesture_parse(argv[0], &binding->gesture))) {
|
||||||
|
free(binding);
|
||||||
|
struct cmd_results *final = cmd_results_new(CMD_FAILURE,
|
||||||
|
"Invalid %s command (%s)",
|
||||||
|
bindtype, errmsg);
|
||||||
|
free(errmsg);
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unbind) {
|
||||||
|
return gesture_binding_remove(binding, argv[0]);
|
||||||
|
}
|
||||||
|
binding->command = join_args(argv + 1, argc - 1);
|
||||||
|
return gesture_binding_add(binding, argv[0], warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd_results *cmd_bindgesture(int argc, char **argv) {
|
||||||
|
return cmd_bind_or_unbind_gesture(argc, argv, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd_results *cmd_unbindgesture(int argc, char **argv) {
|
||||||
|
return cmd_bind_or_unbind_gesture(argc, argv, true);
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ static const struct cmd_handler input_handlers[] = {
|
||||||
{ "drag", input_cmd_drag },
|
{ "drag", input_cmd_drag },
|
||||||
{ "drag_lock", input_cmd_drag_lock },
|
{ "drag_lock", input_cmd_drag_lock },
|
||||||
{ "dwt", input_cmd_dwt },
|
{ "dwt", input_cmd_dwt },
|
||||||
|
{ "dwtp", input_cmd_dwtp },
|
||||||
{ "events", input_cmd_events },
|
{ "events", input_cmd_events },
|
||||||
{ "left_handed", input_cmd_left_handed },
|
{ "left_handed", input_cmd_left_handed },
|
||||||
{ "map_from_region", input_cmd_map_from_region },
|
{ "map_from_region", input_cmd_map_from_region },
|
||||||
|
|
25
sway/commands/input/dwtp.c
Normal file
25
sway/commands/input/dwtp.c
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include "sway/config.h"
|
||||||
|
#include "sway/commands.h"
|
||||||
|
#include "sway/input/input-manager.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct cmd_results *input_cmd_dwtp(int argc, char **argv) {
|
||||||
|
struct cmd_results *error = NULL;
|
||||||
|
if ((error = checkarg(argc, "dwtp", EXPECTED_AT_LEAST, 1))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
struct input_config *ic = config->handler_context.input_config;
|
||||||
|
if (!ic) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "No input device defined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse_boolean(argv[0], true)) {
|
||||||
|
ic->dwtp = LIBINPUT_CONFIG_DWTP_ENABLED;
|
||||||
|
} else {
|
||||||
|
ic->dwtp = LIBINPUT_CONFIG_DWTP_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
}
|
|
@ -1,10 +1,16 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <wlr/interfaces/wlr_keyboard.h>
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
struct xkb_switch_layout_action {
|
||||||
|
struct wlr_keyboard *keyboard;
|
||||||
|
xkb_layout_index_t layout;
|
||||||
|
};
|
||||||
|
|
||||||
static void switch_layout(struct wlr_keyboard *kbd, xkb_layout_index_t idx) {
|
static void switch_layout(struct wlr_keyboard *kbd, xkb_layout_index_t idx) {
|
||||||
xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap);
|
xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap);
|
||||||
if (idx >= num_layouts) {
|
if (idx >= num_layouts) {
|
||||||
|
@ -28,10 +34,10 @@ static xkb_layout_index_t get_current_layout_index(struct wlr_keyboard *kbd) {
|
||||||
return layout_idx;
|
return layout_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void switch_layout_relative(struct wlr_keyboard *kbd, int dir) {
|
static xkb_layout_index_t get_layout_relative(struct wlr_keyboard *kbd, int dir) {
|
||||||
xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap);
|
xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap);
|
||||||
xkb_layout_index_t idx = get_current_layout_index(kbd);
|
xkb_layout_index_t idx = get_current_layout_index(kbd);
|
||||||
switch_layout(kbd, (idx + num_layouts + dir) % num_layouts);
|
return (idx + num_layouts + dir) % num_layouts;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
|
struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
|
||||||
|
@ -66,6 +72,18 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
|
||||||
relative = 0;
|
relative = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct xkb_switch_layout_action *actions = calloc(
|
||||||
|
wl_list_length(&server.input->devices),
|
||||||
|
sizeof(struct xkb_switch_layout_action));
|
||||||
|
size_t actions_len = 0;
|
||||||
|
|
||||||
|
if (!actions) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Unable to allocate actions");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate new indexes first because switching a layout in one
|
||||||
|
keyboard may result in a change on other keyboards as well because
|
||||||
|
of keyboard groups. */
|
||||||
struct sway_input_device *dev;
|
struct sway_input_device *dev;
|
||||||
wl_list_for_each(dev, &server.input->devices, link) {
|
wl_list_for_each(dev, &server.input->devices, link) {
|
||||||
if (strcmp(ic->identifier, "*") != 0 &&
|
if (strcmp(ic->identifier, "*") != 0 &&
|
||||||
|
@ -76,12 +94,22 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
|
||||||
if (dev->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
if (dev->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct xkb_switch_layout_action *action =
|
||||||
|
&actions[actions_len++];
|
||||||
|
|
||||||
|
action->keyboard = wlr_keyboard_from_input_device(dev->wlr_device);
|
||||||
if (relative) {
|
if (relative) {
|
||||||
switch_layout_relative(dev->wlr_device->keyboard, relative);
|
action->layout = get_layout_relative(action->keyboard, relative);
|
||||||
} else {
|
} else {
|
||||||
switch_layout(dev->wlr_device->keyboard, layout);
|
action->layout = layout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < actions_len; i++) {
|
||||||
|
switch_layout(actions[i].keyboard, actions[i].layout);
|
||||||
|
}
|
||||||
|
free(actions);
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,12 @@
|
||||||
// Must be in order for the bsearch
|
// Must be in order for the bsearch
|
||||||
static const struct cmd_handler mode_handlers[] = {
|
static const struct cmd_handler mode_handlers[] = {
|
||||||
{ "bindcode", cmd_bindcode },
|
{ "bindcode", cmd_bindcode },
|
||||||
|
{ "bindgesture", cmd_bindgesture },
|
||||||
{ "bindswitch", cmd_bindswitch },
|
{ "bindswitch", cmd_bindswitch },
|
||||||
{ "bindsym", cmd_bindsym },
|
{ "bindsym", cmd_bindsym },
|
||||||
{ "set", cmd_set },
|
{ "set", cmd_set },
|
||||||
{ "unbindcode", cmd_unbindcode },
|
{ "unbindcode", cmd_unbindcode },
|
||||||
|
{ "unbindgesture", cmd_unbindgesture },
|
||||||
{ "unbindswitch", cmd_unbindswitch },
|
{ "unbindswitch", cmd_unbindswitch },
|
||||||
{ "unbindsym", cmd_unbindsym },
|
{ "unbindsym", cmd_unbindsym },
|
||||||
};
|
};
|
||||||
|
@ -59,6 +61,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
|
||||||
mode->keycode_bindings = create_list();
|
mode->keycode_bindings = create_list();
|
||||||
mode->mouse_bindings = create_list();
|
mode->mouse_bindings = create_list();
|
||||||
mode->switch_bindings = create_list();
|
mode->switch_bindings = create_list();
|
||||||
|
mode->gesture_bindings = create_list();
|
||||||
mode->pango = pango;
|
mode->pango = pango;
|
||||||
list_add(config->modes, mode);
|
list_add(config->modes, mode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -686,6 +686,9 @@ static struct cmd_results *cmd_move_workspace(int argc, char **argv) {
|
||||||
arrange_output(old_output);
|
arrange_output(old_output);
|
||||||
arrange_output(new_output);
|
arrange_output(new_output);
|
||||||
|
|
||||||
|
struct sway_seat *seat = config->handler_context.seat;
|
||||||
|
seat_consider_warp_to_focus(seat);
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,15 +791,15 @@ static struct cmd_results *cmd_move_to_position_pointer(
|
||||||
struct wlr_output *output = wlr_output_layout_output_at(
|
struct wlr_output *output = wlr_output_layout_output_at(
|
||||||
root->output_layout, cursor->x, cursor->y);
|
root->output_layout, cursor->x, cursor->y);
|
||||||
if (output) {
|
if (output) {
|
||||||
struct wlr_box *box =
|
struct wlr_box box;
|
||||||
wlr_output_layout_get_box(root->output_layout, output);
|
wlr_output_layout_get_box(root->output_layout, output, &box);
|
||||||
lx = fmax(lx, box->x);
|
lx = fmax(lx, box.x);
|
||||||
ly = fmax(ly, box->y);
|
ly = fmax(ly, box.y);
|
||||||
if (lx + container->pending.width > box->x + box->width) {
|
if (lx + container->pending.width > box.x + box.width) {
|
||||||
lx = box->x + box->width - container->pending.width;
|
lx = box.x + box.width - container->pending.width;
|
||||||
}
|
}
|
||||||
if (ly + container->pending.height > box->y + box->height) {
|
if (ly + container->pending.height > box.y + box.height) {
|
||||||
ly = box->y + box->height - container->pending.height;
|
ly = box.y + box.height - container->pending.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ static const struct cmd_handler output_handlers[] = {
|
||||||
{ "modeline", output_cmd_modeline },
|
{ "modeline", output_cmd_modeline },
|
||||||
{ "pos", output_cmd_position },
|
{ "pos", output_cmd_position },
|
||||||
{ "position", output_cmd_position },
|
{ "position", output_cmd_position },
|
||||||
|
{ "power", output_cmd_power },
|
||||||
{ "render_bit_depth", output_cmd_render_bit_depth },
|
{ "render_bit_depth", output_cmd_render_bit_depth },
|
||||||
{ "res", output_cmd_mode },
|
{ "res", output_cmd_mode },
|
||||||
{ "resolution", output_cmd_mode },
|
{ "resolution", output_cmd_mode },
|
||||||
|
@ -26,6 +27,7 @@ static const struct cmd_handler output_handlers[] = {
|
||||||
{ "subpixel", output_cmd_subpixel },
|
{ "subpixel", output_cmd_subpixel },
|
||||||
{ "toggle", output_cmd_toggle },
|
{ "toggle", output_cmd_toggle },
|
||||||
{ "transform", output_cmd_transform },
|
{ "transform", output_cmd_transform },
|
||||||
|
{ "unplug", output_cmd_unplug },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmd_results *cmd_output(int argc, char **argv) {
|
struct cmd_results *cmd_output(int argc, char **argv) {
|
||||||
|
|
|
@ -102,19 +102,19 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char *conf_path = dirname(conf);
|
char *conf_path = dirname(conf);
|
||||||
char *rel_path = src;
|
char *real_src = malloc(strlen(conf_path) + strlen(src) + 2);
|
||||||
src = malloc(strlen(conf_path) + strlen(src) + 2);
|
if (!real_src) {
|
||||||
if (!src) {
|
free(src);
|
||||||
free(rel_path);
|
|
||||||
free(conf);
|
free(conf);
|
||||||
sway_log(SWAY_ERROR, "Unable to allocate memory");
|
sway_log(SWAY_ERROR, "Unable to allocate memory");
|
||||||
return cmd_results_new(CMD_FAILURE,
|
return cmd_results_new(CMD_FAILURE,
|
||||||
"Unable to allocate resources");
|
"Unable to allocate resources");
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(src, "%s/%s", conf_path, rel_path);
|
snprintf(real_src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, src);
|
||||||
free(rel_path);
|
free(src);
|
||||||
free(conf);
|
free(conf);
|
||||||
|
src = real_src;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_access = access(src, F_OK) != -1;
|
bool can_access = access(src, F_OK) != -1;
|
||||||
|
|
|
@ -1,45 +1,8 @@
|
||||||
|
#include "log.h"
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
|
||||||
#include "sway/output.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include <strings.h>
|
|
||||||
|
|
||||||
struct cmd_results *output_cmd_dpms(int argc, char **argv) {
|
struct cmd_results *output_cmd_dpms(int argc, char **argv) {
|
||||||
if (!config->handler_context.output_config) {
|
sway_log(SWAY_INFO, "The \"output dpms\" command is deprecated, "
|
||||||
return cmd_results_new(CMD_FAILURE, "Missing output config");
|
"use \"output power\" instead");
|
||||||
}
|
return output_cmd_power(argc, argv);
|
||||||
if (!argc) {
|
|
||||||
return cmd_results_new(CMD_INVALID, "Missing dpms argument.");
|
|
||||||
}
|
|
||||||
|
|
||||||
enum config_dpms current_dpms = DPMS_ON;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sway_output->enabled && !sway_output->wlr_output->enabled) {
|
|
||||||
current_dpms = DPMS_OFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parse_boolean(argv[0], current_dpms == DPMS_ON)) {
|
|
||||||
config->handler_context.output_config->dpms_state = DPMS_ON;
|
|
||||||
} else {
|
|
||||||
config->handler_context.output_config->dpms_state = DPMS_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
config->handler_context.leftovers.argc = argc - 1;
|
|
||||||
config->handler_context.leftovers.argv = argv + 1;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
43
sway/commands/output/power.c
Normal file
43
sway/commands/output/power.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <strings.h>
|
||||||
|
#include "sway/commands.h"
|
||||||
|
#include "sway/config.h"
|
||||||
|
#include "sway/output.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct cmd_results *output_cmd_power(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 power argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool current = 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sway_output->enabled && !sway_output->wlr_output->enabled) {
|
||||||
|
current = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse_boolean(argv[0], current)) {
|
||||||
|
config->handler_context.output_config->power = 1;
|
||||||
|
} else {
|
||||||
|
config->handler_context.output_config->power = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
config->handler_context.leftovers.argc = argc - 1;
|
||||||
|
config->handler_context.leftovers.argv = argv + 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
54
sway/commands/output/unplug.c
Normal file
54
sway/commands/output/unplug.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include <strings.h>
|
||||||
|
#include <wlr/config.h>
|
||||||
|
#include <wlr/backend/headless.h>
|
||||||
|
#include <wlr/backend/wayland.h>
|
||||||
|
#if WLR_HAS_X11_BACKEND
|
||||||
|
#include <wlr/backend/x11.h>
|
||||||
|
#endif
|
||||||
|
#include "sway/commands.h"
|
||||||
|
#include "sway/config.h"
|
||||||
|
#include "sway/output.h"
|
||||||
|
|
||||||
|
static bool is_backend_allowed(struct wlr_backend *backend) {
|
||||||
|
if (wlr_backend_is_headless(backend)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (wlr_backend_is_wl(backend)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#if WLR_HAS_X11_BACKEND
|
||||||
|
if (wlr_backend_is_x11(backend)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This command is intended for developer use only.
|
||||||
|
*/
|
||||||
|
struct cmd_results *output_cmd_unplug(int argc, char **argv) {
|
||||||
|
if (!config->handler_context.output_config) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Missing output config");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *oc_name = config->handler_context.output_config->name;
|
||||||
|
if (strcmp(oc_name, "*") == 0) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "Won't unplug all outputs");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
|
||||||
|
if (!sway_output) {
|
||||||
|
return cmd_results_new(CMD_INVALID,
|
||||||
|
"Cannot unplug unknown output %s", oc_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_backend_allowed(sway_output->wlr_output->backend)) {
|
||||||
|
return cmd_results_new(CMD_INVALID,
|
||||||
|
"Can only unplug outputs with headless, wayland or x11 backend");
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_output_destroy(sway_output->wlr_output);
|
||||||
|
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
|
#include "sway/desktop/launcher.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
|
@ -91,8 +92,6 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
|
sway_log(SWAY_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
|
||||||
|
|
||||||
root_rename_pid_workspaces(workspace->name, new_name);
|
|
||||||
|
|
||||||
free(workspace->name);
|
free(workspace->name);
|
||||||
workspace->name = new_name;
|
workspace->name = new_name;
|
||||||
|
|
||||||
|
|
|
@ -111,8 +111,8 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
|
||||||
: WLR_AXIS_ORIENTATION_HORIZONTAL;
|
: WLR_AXIS_ORIENTATION_HORIZONTAL;
|
||||||
double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT)
|
double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT)
|
||||||
? -1 : 1;
|
? -1 : 1;
|
||||||
struct wlr_event_pointer_axis event = {
|
struct wlr_pointer_axis_event event = {
|
||||||
.device = NULL,
|
.pointer = NULL,
|
||||||
.time_msec = 0,
|
.time_msec = 0,
|
||||||
.source = WLR_AXIS_SOURCE_WHEEL,
|
.source = WLR_AXIS_SOURCE_WHEEL,
|
||||||
.orientation = orientation,
|
.orientation = orientation,
|
||||||
|
|
|
@ -82,6 +82,12 @@ static void free_mode(struct sway_mode *mode) {
|
||||||
}
|
}
|
||||||
list_free(mode->switch_bindings);
|
list_free(mode->switch_bindings);
|
||||||
}
|
}
|
||||||
|
if (mode->gesture_bindings) {
|
||||||
|
for (int i = 0; i < mode->gesture_bindings->length; i++) {
|
||||||
|
free_gesture_binding(mode->gesture_bindings->items[i]);
|
||||||
|
}
|
||||||
|
list_free(mode->gesture_bindings);
|
||||||
|
}
|
||||||
free(mode);
|
free(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +228,7 @@ static void config_defaults(struct sway_config *config) {
|
||||||
if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup;
|
if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup;
|
||||||
if (!(config->current_mode->mouse_bindings = create_list())) goto cleanup;
|
if (!(config->current_mode->mouse_bindings = create_list())) goto cleanup;
|
||||||
if (!(config->current_mode->switch_bindings = create_list())) goto cleanup;
|
if (!(config->current_mode->switch_bindings = create_list())) goto cleanup;
|
||||||
|
if (!(config->current_mode->gesture_bindings = create_list())) goto cleanup;
|
||||||
list_add(config->modes, config->current_mode);
|
list_add(config->modes, config->current_mode);
|
||||||
|
|
||||||
config->floating_mod = 0;
|
config->floating_mod = 0;
|
||||||
|
@ -236,6 +243,7 @@ static void config_defaults(struct sway_config *config) {
|
||||||
config->default_layout = L_NONE;
|
config->default_layout = L_NONE;
|
||||||
config->default_orientation = L_NONE;
|
config->default_orientation = L_NONE;
|
||||||
if (!(config->font = strdup("monospace 10"))) goto cleanup;
|
if (!(config->font = strdup("monospace 10"))) goto cleanup;
|
||||||
|
config->font_description = pango_font_description_from_string(config->font);
|
||||||
config->urgent_timeout = 500;
|
config->urgent_timeout = 500;
|
||||||
config->focus_on_window_activation = FOWA_URGENT;
|
config->focus_on_window_activation = FOWA_URGENT;
|
||||||
config->popup_during_fullscreen = POPUP_SMART;
|
config->popup_during_fullscreen = POPUP_SMART;
|
||||||
|
@ -1005,7 +1013,7 @@ int workspace_output_cmp_workspace(const void *a, const void *b) {
|
||||||
void config_update_font_height(void) {
|
void config_update_font_height(void) {
|
||||||
int prev_max_height = config->font_height;
|
int prev_max_height = config->font_height;
|
||||||
|
|
||||||
get_text_metrics(config->font, &config->font_height, &config->font_baseline);
|
get_text_metrics(config->font_description, &config->font_height, &config->font_baseline);
|
||||||
|
|
||||||
if (config->font_height != prev_max_height) {
|
if (config->font_height != prev_max_height) {
|
||||||
arrange_root();
|
arrange_root();
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct input_config *new_input_config(const char* identifier) {
|
||||||
input->drag = INT_MIN;
|
input->drag = INT_MIN;
|
||||||
input->drag_lock = INT_MIN;
|
input->drag_lock = INT_MIN;
|
||||||
input->dwt = INT_MIN;
|
input->dwt = INT_MIN;
|
||||||
|
input->dwtp = INT_MIN;
|
||||||
input->send_events = INT_MIN;
|
input->send_events = INT_MIN;
|
||||||
input->click_method = INT_MIN;
|
input->click_method = INT_MIN;
|
||||||
input->middle_emulation = INT_MIN;
|
input->middle_emulation = INT_MIN;
|
||||||
|
@ -61,6 +62,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
|
||||||
if (src->dwt != INT_MIN) {
|
if (src->dwt != INT_MIN) {
|
||||||
dst->dwt = src->dwt;
|
dst->dwt = src->dwt;
|
||||||
}
|
}
|
||||||
|
if (src->dwtp != INT_MIN) {
|
||||||
|
dst->dwtp = src->dwtp;
|
||||||
|
}
|
||||||
if (src->left_handed != INT_MIN) {
|
if (src->left_handed != INT_MIN) {
|
||||||
dst->left_handed = src->left_handed;
|
dst->left_handed = src->left_handed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,10 @@ int output_name_cmp(const void *item, const void *data) {
|
||||||
void output_get_identifier(char *identifier, size_t len,
|
void output_get_identifier(char *identifier, size_t len,
|
||||||
struct sway_output *output) {
|
struct sway_output *output) {
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
snprintf(identifier, len, "%s %s %s", wlr_output->make, wlr_output->model,
|
snprintf(identifier, len, "%s %s %s",
|
||||||
wlr_output->serial);
|
wlr_output->make ? wlr_output->make : "Unknown",
|
||||||
|
wlr_output->model ? wlr_output->model : "Unknown",
|
||||||
|
wlr_output->serial ? wlr_output->serial : "Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) {
|
const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) {
|
||||||
|
@ -69,6 +71,7 @@ struct output_config *new_output_config(const char *name) {
|
||||||
oc->max_render_time = -1;
|
oc->max_render_time = -1;
|
||||||
oc->adaptive_sync = -1;
|
oc->adaptive_sync = -1;
|
||||||
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
|
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
|
||||||
|
oc->power = -1;
|
||||||
return oc;
|
return oc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,8 +133,8 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
|
||||||
free(dst->background_fallback);
|
free(dst->background_fallback);
|
||||||
dst->background_fallback = strdup(src->background_fallback);
|
dst->background_fallback = strdup(src->background_fallback);
|
||||||
}
|
}
|
||||||
if (src->dpms_state != 0) {
|
if (src->power != -1) {
|
||||||
dst->dpms_state = src->dpms_state;
|
dst->power = src->power;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,11 +193,11 @@ static void merge_id_on_name(struct output_config *oc) {
|
||||||
list_add(config->output_configs, ion_oc);
|
list_add(config->output_configs, ion_oc);
|
||||||
sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\""
|
sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\""
|
||||||
" (enabled: %d) (%dx%d@%fHz position %d,%d scale %f "
|
" (enabled: %d) (%dx%d@%fHz position %d,%d scale %f "
|
||||||
"transform %d) (bg %s %s) (dpms %d) (max render time: %d)",
|
"transform %d) (bg %s %s) (power %d) (max render time: %d)",
|
||||||
ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height,
|
ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height,
|
||||||
ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale,
|
ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale,
|
||||||
ion_oc->transform, ion_oc->background,
|
ion_oc->transform, ion_oc->background,
|
||||||
ion_oc->background_option, ion_oc->dpms_state,
|
ion_oc->background_option, ion_oc->power,
|
||||||
ion_oc->max_render_time);
|
ion_oc->max_render_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,18 +238,18 @@ struct output_config *store_output_config(struct output_config *oc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
|
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) (dpms %d) "
|
"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
|
||||||
"(max render time: %d)",
|
"(max render time: %d)",
|
||||||
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
|
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->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
|
||||||
oc->transform, oc->background, oc->background_option, oc->dpms_state,
|
oc->transform, oc->background, oc->background_option, oc->power,
|
||||||
oc->max_render_time);
|
oc->max_render_time);
|
||||||
|
|
||||||
return oc;
|
return oc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_mode(struct wlr_output *output, int width, int height,
|
static void set_mode(struct wlr_output *output, struct wlr_output_state *pending,
|
||||||
float refresh_rate, bool custom) {
|
int width, int height, float refresh_rate, bool custom) {
|
||||||
// Not all floating point integers can be represented exactly
|
// Not all floating point integers can be represented exactly
|
||||||
// as (int)(1000 * mHz / 1000.f)
|
// as (int)(1000 * mHz / 1000.f)
|
||||||
// round() the result to avoid any error
|
// round() the result to avoid any error
|
||||||
|
@ -254,7 +257,7 @@ static void set_mode(struct wlr_output *output, int width, int height,
|
||||||
|
|
||||||
if (wl_list_empty(&output->modes) || custom) {
|
if (wl_list_empty(&output->modes) || custom) {
|
||||||
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
|
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
|
||||||
wlr_output_set_custom_mode(output, width, height,
|
wlr_output_state_set_custom_mode(pending, width, height,
|
||||||
refresh_rate > 0 ? mhz : 0);
|
refresh_rate > 0 ? mhz : 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -278,10 +281,11 @@ static void set_mode(struct wlr_output *output, int width, int height,
|
||||||
} else {
|
} else {
|
||||||
sway_log(SWAY_DEBUG, "Assigning configured mode to %s", output->name);
|
sway_log(SWAY_DEBUG, "Assigning configured mode to %s", output->name);
|
||||||
}
|
}
|
||||||
wlr_output_set_mode(output, best);
|
wlr_output_state_set_mode(pending, best);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) {
|
static void set_modeline(struct wlr_output *output,
|
||||||
|
struct wlr_output_state *pending, drmModeModeInfo *drm_mode) {
|
||||||
if (!wlr_output_is_drm(output)) {
|
if (!wlr_output_is_drm(output)) {
|
||||||
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
|
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
|
||||||
return;
|
return;
|
||||||
|
@ -289,7 +293,7 @@ static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) {
|
||||||
sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
|
sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
|
||||||
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
|
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
|
||||||
if (mode) {
|
if (mode) {
|
||||||
wlr_output_set_mode(output, mode);
|
wlr_output_state_set_mode(pending, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,23 +315,24 @@ static bool phys_size_is_aspect_ratio(struct wlr_output *output) {
|
||||||
// 1 inch = 25.4 mm
|
// 1 inch = 25.4 mm
|
||||||
#define MM_PER_INCH 25.4
|
#define MM_PER_INCH 25.4
|
||||||
|
|
||||||
static int compute_default_scale(struct wlr_output *output) {
|
static int compute_default_scale(struct wlr_output *output,
|
||||||
|
struct wlr_output_state *pending) {
|
||||||
struct wlr_box box = { .width = output->width, .height = output->height };
|
struct wlr_box box = { .width = output->width, .height = output->height };
|
||||||
if (output->pending.committed & WLR_OUTPUT_STATE_MODE) {
|
if (pending->committed & WLR_OUTPUT_STATE_MODE) {
|
||||||
switch (output->pending.mode_type) {
|
switch (pending->mode_type) {
|
||||||
case WLR_OUTPUT_STATE_MODE_FIXED:
|
case WLR_OUTPUT_STATE_MODE_FIXED:
|
||||||
box.width = output->pending.mode->width;
|
box.width = pending->mode->width;
|
||||||
box.height = output->pending.mode->height;
|
box.height = pending->mode->height;
|
||||||
break;
|
break;
|
||||||
case WLR_OUTPUT_STATE_MODE_CUSTOM:
|
case WLR_OUTPUT_STATE_MODE_CUSTOM:
|
||||||
box.width = output->pending.custom_mode.width;
|
box.width = pending->custom_mode.width;
|
||||||
box.height = output->pending.custom_mode.height;
|
box.height = pending->custom_mode.height;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enum wl_output_transform transform = output->transform;
|
enum wl_output_transform transform = output->transform;
|
||||||
if (output->pending.committed & WLR_OUTPUT_STATE_TRANSFORM) {
|
if (pending->committed & WLR_OUTPUT_STATE_TRANSFORM) {
|
||||||
transform = output->pending.transform;
|
transform = pending->transform;
|
||||||
}
|
}
|
||||||
wlr_box_transform(&box, &box, transform, box.width, box.height);
|
wlr_box_transform(&box, &box, transform, box.width, box.height);
|
||||||
|
|
||||||
|
@ -374,38 +379,38 @@ static const uint32_t *bit_depth_preferences[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void queue_output_config(struct output_config *oc,
|
static void queue_output_config(struct output_config *oc,
|
||||||
struct sway_output *output) {
|
struct sway_output *output, struct wlr_output_state *pending) {
|
||||||
if (output == root->fallback_output) {
|
if (output == root->fallback_output) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
|
||||||
if (oc && (!oc->enabled || oc->dpms_state == DPMS_OFF)) {
|
if (oc && (!oc->enabled || oc->power == 0)) {
|
||||||
sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name);
|
sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name);
|
||||||
wlr_output_enable(wlr_output, false);
|
wlr_output_state_set_enabled(pending, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
|
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
|
||||||
wlr_output_enable(wlr_output, true);
|
wlr_output_state_set_enabled(pending, true);
|
||||||
|
|
||||||
if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
|
if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s modeline",
|
sway_log(SWAY_DEBUG, "Set %s modeline",
|
||||||
wlr_output->name);
|
wlr_output->name);
|
||||||
set_modeline(wlr_output, &oc->drm_mode);
|
set_modeline(wlr_output, pending, &oc->drm_mode);
|
||||||
} else if (oc && oc->width > 0 && oc->height > 0) {
|
} else if (oc && oc->width > 0 && oc->height > 0) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
|
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
|
||||||
wlr_output->name, oc->width, oc->height, oc->refresh_rate);
|
wlr_output->name, oc->width, oc->height, oc->refresh_rate);
|
||||||
set_mode(wlr_output, oc->width, oc->height,
|
set_mode(wlr_output, pending, oc->width, oc->height,
|
||||||
oc->refresh_rate, oc->custom_mode == 1);
|
oc->refresh_rate, oc->custom_mode == 1);
|
||||||
} else if (!wl_list_empty(&wlr_output->modes)) {
|
} else if (!wl_list_empty(&wlr_output->modes)) {
|
||||||
sway_log(SWAY_DEBUG, "Set preferred mode");
|
sway_log(SWAY_DEBUG, "Set preferred mode");
|
||||||
struct wlr_output_mode *preferred_mode =
|
struct wlr_output_mode *preferred_mode =
|
||||||
wlr_output_preferred_mode(wlr_output);
|
wlr_output_preferred_mode(wlr_output);
|
||||||
wlr_output_set_mode(wlr_output, preferred_mode);
|
wlr_output_state_set_mode(pending, preferred_mode);
|
||||||
|
|
||||||
if (!wlr_output_test(wlr_output)) {
|
if (!wlr_output_test_state(wlr_output, pending)) {
|
||||||
sway_log(SWAY_DEBUG, "Preferred mode rejected, "
|
sway_log(SWAY_DEBUG, "Preferred mode rejected, "
|
||||||
"falling back to another mode");
|
"falling back to another mode");
|
||||||
struct wlr_output_mode *mode;
|
struct wlr_output_mode *mode;
|
||||||
|
@ -414,8 +419,8 @@ static void queue_output_config(struct output_config *oc,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_output_set_mode(wlr_output, mode);
|
wlr_output_state_set_mode(pending, mode);
|
||||||
if (wlr_output_test(wlr_output)) {
|
if (wlr_output_test_state(wlr_output, pending)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,7 +430,7 @@ static void queue_output_config(struct output_config *oc,
|
||||||
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
|
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
|
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
|
||||||
sway_wl_output_subpixel_to_string(oc->subpixel));
|
sway_wl_output_subpixel_to_string(oc->subpixel));
|
||||||
wlr_output_set_subpixel(wlr_output, oc->subpixel);
|
wlr_output_state_set_subpixel(pending, oc->subpixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
|
enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
|
@ -437,7 +442,7 @@ static void queue_output_config(struct output_config *oc,
|
||||||
}
|
}
|
||||||
if (wlr_output->transform != tr) {
|
if (wlr_output->transform != tr) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
|
sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
|
||||||
wlr_output_set_transform(wlr_output, tr);
|
wlr_output_state_set_transform(pending, tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the scale last before the commit, because the scale auto-detection
|
// Apply the scale last before the commit, because the scale auto-detection
|
||||||
|
@ -446,18 +451,22 @@ static void queue_output_config(struct output_config *oc,
|
||||||
if (oc && oc->scale > 0) {
|
if (oc && oc->scale > 0) {
|
||||||
scale = oc->scale;
|
scale = oc->scale;
|
||||||
} else {
|
} else {
|
||||||
scale = compute_default_scale(wlr_output);
|
scale = compute_default_scale(wlr_output, pending);
|
||||||
sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale);
|
sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale);
|
||||||
}
|
}
|
||||||
if (scale != wlr_output->scale) {
|
if (scale != wlr_output->scale) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale);
|
sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale);
|
||||||
wlr_output_set_scale(wlr_output, scale);
|
wlr_output_state_set_scale(pending, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oc && oc->adaptive_sync != -1) {
|
if (oc && oc->adaptive_sync != -1) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
|
sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
|
||||||
oc->adaptive_sync);
|
oc->adaptive_sync);
|
||||||
wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1);
|
wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
|
||||||
|
if (oc->adaptive_sync == 1 && !wlr_output_test_state(wlr_output, pending)) {
|
||||||
|
sway_log(SWAY_DEBUG, "Adaptive sync failed, ignoring");
|
||||||
|
wlr_output_state_set_adaptive_sync_enabled(pending, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
|
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
|
||||||
|
@ -465,8 +474,8 @@ static void queue_output_config(struct output_config *oc,
|
||||||
assert(fmts);
|
assert(fmts);
|
||||||
|
|
||||||
for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
|
for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
|
||||||
wlr_output_set_render_format(wlr_output, fmts[i]);
|
wlr_output_state_set_render_format(pending, fmts[i]);
|
||||||
if (wlr_output_test(wlr_output)) {
|
if (wlr_output_test_state(wlr_output, pending)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,14 +496,15 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
|
||||||
// Flag to prevent the output mode event handler from calling us
|
// Flag to prevent the output mode event handler from calling us
|
||||||
output->enabling = (!oc || oc->enabled);
|
output->enabling = (!oc || oc->enabled);
|
||||||
|
|
||||||
queue_output_config(oc, output);
|
struct wlr_output_state pending = {0};
|
||||||
|
queue_output_config(oc, output, &pending);
|
||||||
|
|
||||||
if (!oc || oc->dpms_state != DPMS_OFF) {
|
if (!oc || oc->power != 0) {
|
||||||
output->current_mode = wlr_output->pending.mode;
|
output->current_mode = pending.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
|
sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
|
||||||
if (!wlr_output_commit(wlr_output)) {
|
if (!wlr_output_commit_state(wlr_output, &pending)) {
|
||||||
// Failed to commit output changes, maybe the output is missing a CRTC.
|
// Failed to commit output changes, maybe the output is missing a CRTC.
|
||||||
// Leave the output disabled for now and try again when the output gets
|
// Leave the output disabled for now and try again when the output gets
|
||||||
// the mode we asked for.
|
// the mode we asked for.
|
||||||
|
@ -546,12 +556,12 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update output->{lx, ly, width, height}
|
// Update output->{lx, ly, width, height}
|
||||||
struct wlr_box *output_box =
|
struct wlr_box output_box;
|
||||||
wlr_output_layout_get_box(root->output_layout, wlr_output);
|
wlr_output_layout_get_box(root->output_layout, wlr_output, &output_box);
|
||||||
output->lx = output_box->x;
|
output->lx = output_box.x;
|
||||||
output->ly = output_box->y;
|
output->ly = output_box.y;
|
||||||
output->width = output_box->width;
|
output->width = output_box.width;
|
||||||
output->height = output_box->height;
|
output->height = output_box.height;
|
||||||
|
|
||||||
if (!output->enabled) {
|
if (!output->enabled) {
|
||||||
output_enable(output);
|
output_enable(output);
|
||||||
|
@ -577,15 +587,15 @@ bool test_output_config(struct output_config *oc, struct sway_output *output) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_output_config(oc, output);
|
struct wlr_output_state pending = {0};
|
||||||
bool ok = wlr_output_test(output->wlr_output);
|
queue_output_config(oc, output, &pending);
|
||||||
wlr_output_rollback(output->wlr_output);
|
return wlr_output_test_state(output->wlr_output, &pending);
|
||||||
return ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_output_config(struct output_config *oc,
|
static void default_output_config(struct output_config *oc,
|
||||||
struct wlr_output *wlr_output) {
|
struct wlr_output *wlr_output) {
|
||||||
oc->enabled = 1;
|
oc->enabled = 1;
|
||||||
|
oc->power = 1;
|
||||||
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
|
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
|
||||||
if (mode != NULL) {
|
if (mode != NULL) {
|
||||||
oc->width = mode->width;
|
oc->width = mode->width;
|
||||||
|
@ -598,7 +608,6 @@ static void default_output_config(struct output_config *oc,
|
||||||
struct sway_output *output = wlr_output->data;
|
struct sway_output *output = wlr_output->data;
|
||||||
oc->subpixel = output->detected_subpixel;
|
oc->subpixel = output->detected_subpixel;
|
||||||
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
oc->dpms_state = DPMS_ON;
|
|
||||||
oc->max_render_time = 0;
|
oc->max_render_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,10 +662,10 @@ static struct output_config *get_output_config(char *identifier,
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)"
|
sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)"
|
||||||
" (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)"
|
" (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)"
|
||||||
" (dpms %d) (max render time: %d)", result->name, result->enabled,
|
" (power %d) (max render time: %d)", result->name, result->enabled,
|
||||||
result->width, result->height, result->refresh_rate,
|
result->width, result->height, result->refresh_rate,
|
||||||
result->x, result->y, result->scale, result->transform,
|
result->x, result->y, result->scale, result->transform,
|
||||||
result->background, result->background_option, result->dpms_state,
|
result->background, result->background_option, result->power,
|
||||||
result->max_render_time);
|
result->max_render_time);
|
||||||
} else if (oc_name) {
|
} else if (oc_name) {
|
||||||
// No identifier config, just return a copy of the name config
|
// No identifier config, just return a copy of the name config
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <pcre.h>
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||||
|
#include <pcre2.h>
|
||||||
#include "sway/criteria.h"
|
#include "sway/criteria.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
@ -40,17 +41,19 @@ bool criteria_is_empty(struct criteria *criteria) {
|
||||||
char *error = NULL;
|
char *error = NULL;
|
||||||
|
|
||||||
// Returns error string on failure or NULL otherwise.
|
// Returns error string on failure or NULL otherwise.
|
||||||
static bool generate_regex(pcre **regex, char *value) {
|
static bool generate_regex(pcre2_code **regex, char *value) {
|
||||||
const char *reg_err;
|
int errorcode;
|
||||||
int offset;
|
PCRE2_SIZE offset;
|
||||||
|
|
||||||
*regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL);
|
|
||||||
|
|
||||||
|
*regex = pcre2_compile((PCRE2_SPTR)value, PCRE2_ZERO_TERMINATED, PCRE2_UTF | PCRE2_UCP, &errorcode, &offset, NULL);
|
||||||
if (!*regex) {
|
if (!*regex) {
|
||||||
|
PCRE2_UCHAR buffer[256];
|
||||||
|
pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
|
||||||
|
|
||||||
const char *fmt = "Regex compilation for '%s' failed: %s";
|
const char *fmt = "Regex compilation for '%s' failed: %s";
|
||||||
int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3;
|
int len = strlen(fmt) + strlen(value) + strlen((char*) buffer) - 3;
|
||||||
error = malloc(len);
|
error = malloc(len);
|
||||||
snprintf(error, len, fmt, value, reg_err);
|
snprintf(error, len, fmt, value, buffer);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +69,7 @@ static bool pattern_create(struct pattern **pattern, char *value) {
|
||||||
if (strcmp(value, "__focused__") == 0) {
|
if (strcmp(value, "__focused__") == 0) {
|
||||||
(*pattern)->match_type = PATTERN_FOCUSED;
|
(*pattern)->match_type = PATTERN_FOCUSED;
|
||||||
} else {
|
} else {
|
||||||
(*pattern)->match_type = PATTERN_PCRE;
|
(*pattern)->match_type = PATTERN_PCRE2;
|
||||||
if (!generate_regex(&(*pattern)->regex, value)) {
|
if (!generate_regex(&(*pattern)->regex, value)) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -77,7 +80,7 @@ static bool pattern_create(struct pattern **pattern, char *value) {
|
||||||
static void pattern_destroy(struct pattern *pattern) {
|
static void pattern_destroy(struct pattern *pattern) {
|
||||||
if (pattern) {
|
if (pattern) {
|
||||||
if (pattern->regex) {
|
if (pattern->regex) {
|
||||||
pcre_free(pattern->regex);
|
pcre2_code_free(pattern->regex);
|
||||||
}
|
}
|
||||||
free(pattern);
|
free(pattern);
|
||||||
}
|
}
|
||||||
|
@ -93,14 +96,18 @@ void criteria_destroy(struct criteria *criteria) {
|
||||||
pattern_destroy(criteria->window_role);
|
pattern_destroy(criteria->window_role);
|
||||||
#endif
|
#endif
|
||||||
pattern_destroy(criteria->con_mark);
|
pattern_destroy(criteria->con_mark);
|
||||||
free(criteria->workspace);
|
pattern_destroy(criteria->workspace);
|
||||||
|
free(criteria->target);
|
||||||
free(criteria->cmdlist);
|
free(criteria->cmdlist);
|
||||||
free(criteria->raw);
|
free(criteria->raw);
|
||||||
free(criteria);
|
free(criteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int regex_cmp(const char *item, const pcre *regex) {
|
static int regex_cmp(const char *item, const pcre2_code *regex) {
|
||||||
return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);
|
pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL);
|
||||||
|
int result = pcre2_match(regex, (PCRE2_SPTR)item, strlen(item), 0, 0, match_data, NULL);
|
||||||
|
pcre2_match_data_free(match_data);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
|
@ -155,7 +162,7 @@ static bool criteria_matches_container(struct criteria *criteria,
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
struct sway_container *con = container;
|
struct sway_container *con = container;
|
||||||
for (int i = 0; i < con->marks->length; ++i) {
|
for (int i = 0; i < con->marks->length; ++i) {
|
||||||
if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) == 0) {
|
if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) >= 0) {
|
||||||
exists = true;
|
exists = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +190,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
if (criteria->title) {
|
if (criteria->title) {
|
||||||
const char *title = view_get_title(view);
|
const char *title = view_get_title(view);
|
||||||
if (!title) {
|
if (!title) {
|
||||||
return false;
|
title = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (criteria->title->match_type) {
|
switch (criteria->title->match_type) {
|
||||||
|
@ -192,8 +199,8 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PATTERN_PCRE:
|
case PATTERN_PCRE2:
|
||||||
if (regex_cmp(title, criteria->title->regex) != 0) {
|
if (regex_cmp(title, criteria->title->regex) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -203,7 +210,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
if (criteria->shell) {
|
if (criteria->shell) {
|
||||||
const char *shell = view_get_shell(view);
|
const char *shell = view_get_shell(view);
|
||||||
if (!shell) {
|
if (!shell) {
|
||||||
return false;
|
shell = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (criteria->shell->match_type) {
|
switch (criteria->shell->match_type) {
|
||||||
|
@ -212,8 +219,8 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PATTERN_PCRE:
|
case PATTERN_PCRE2:
|
||||||
if (regex_cmp(shell, criteria->shell->regex) != 0) {
|
if (regex_cmp(shell, criteria->shell->regex) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -223,7 +230,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
if (criteria->app_id) {
|
if (criteria->app_id) {
|
||||||
const char *app_id = view_get_app_id(view);
|
const char *app_id = view_get_app_id(view);
|
||||||
if (!app_id) {
|
if (!app_id) {
|
||||||
return false;
|
app_id = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (criteria->app_id->match_type) {
|
switch (criteria->app_id->match_type) {
|
||||||
|
@ -232,8 +239,8 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PATTERN_PCRE:
|
case PATTERN_PCRE2:
|
||||||
if (regex_cmp(app_id, criteria->app_id->regex) != 0) {
|
if (regex_cmp(app_id, criteria->app_id->regex) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -255,7 +262,7 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
if (criteria->class) {
|
if (criteria->class) {
|
||||||
const char *class = view_get_class(view);
|
const char *class = view_get_class(view);
|
||||||
if (!class) {
|
if (!class) {
|
||||||
return false;
|
class = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (criteria->class->match_type) {
|
switch (criteria->class->match_type) {
|
||||||
|
@ -264,8 +271,8 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PATTERN_PCRE:
|
case PATTERN_PCRE2:
|
||||||
if (regex_cmp(class, criteria->class->regex) != 0) {
|
if (regex_cmp(class, criteria->class->regex) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -275,17 +282,17 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
if (criteria->instance) {
|
if (criteria->instance) {
|
||||||
const char *instance = view_get_instance(view);
|
const char *instance = view_get_instance(view);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
return false;
|
instance = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (criteria->instance->match_type) {
|
switch (criteria->instance->match_type) {
|
||||||
case PATTERN_FOCUSED:
|
case PATTERN_FOCUSED:
|
||||||
if (focused && strcmp(instance, view_get_instance(focused))) {
|
if (focused && lenient_strcmp(instance, view_get_instance(focused))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PATTERN_PCRE:
|
case PATTERN_PCRE2:
|
||||||
if (regex_cmp(instance, criteria->instance->regex) != 0) {
|
if (regex_cmp(instance, criteria->instance->regex) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -295,17 +302,17 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
if (criteria->window_role) {
|
if (criteria->window_role) {
|
||||||
const char *window_role = view_get_window_role(view);
|
const char *window_role = view_get_window_role(view);
|
||||||
if (!window_role) {
|
if (!window_role) {
|
||||||
return false;
|
window_role = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (criteria->window_role->match_type) {
|
switch (criteria->window_role->match_type) {
|
||||||
case PATTERN_FOCUSED:
|
case PATTERN_FOCUSED:
|
||||||
if (focused && strcmp(window_role, view_get_window_role(focused))) {
|
if (focused && lenient_strcmp(window_role, view_get_window_role(focused))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PATTERN_PCRE:
|
case PATTERN_PCRE2:
|
||||||
if (regex_cmp(window_role, criteria->window_role->regex) != 0) {
|
if (regex_cmp(window_role, criteria->window_role->regex) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -363,8 +370,8 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PATTERN_PCRE:
|
case PATTERN_PCRE2:
|
||||||
if (regex_cmp(ws->name, criteria->workspace->regex) != 0) {
|
if (regex_cmp(ws->name, criteria->workspace->regex) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -676,7 +683,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
|
||||||
}
|
}
|
||||||
name = calloc(head - namestart + 1, 1);
|
name = calloc(head - namestart + 1, 1);
|
||||||
if (head != namestart) {
|
if (head != namestart) {
|
||||||
strncpy(name, namestart, head - namestart);
|
memcpy(name, namestart, head - namestart);
|
||||||
}
|
}
|
||||||
// Parse token value
|
// Parse token value
|
||||||
skip_spaces(&head);
|
skip_spaces(&head);
|
||||||
|
@ -703,7 +710,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value = calloc(head - valuestart + 1, 1);
|
value = calloc(head - valuestart + 1, 1);
|
||||||
strncpy(value, valuestart, head - valuestart);
|
memcpy(value, valuestart, head - valuestart);
|
||||||
if (in_quotes) {
|
if (in_quotes) {
|
||||||
++head;
|
++head;
|
||||||
in_quotes = false;
|
in_quotes = false;
|
||||||
|
@ -734,7 +741,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
|
||||||
++head;
|
++head;
|
||||||
int len = head - raw;
|
int len = head - raw;
|
||||||
criteria->raw = calloc(len + 1, 1);
|
criteria->raw = calloc(len + 1, 1);
|
||||||
strncpy(criteria->raw, raw, len);
|
memcpy(criteria->raw, raw, len);
|
||||||
return criteria;
|
return criteria;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
|
|
@ -6,10 +6,11 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
|
||||||
bool whole) {
|
bool whole) {
|
||||||
for (int i = 0; i < root->outputs->length; ++i) {
|
for (int i = 0; i < root->outputs->length; ++i) {
|
||||||
struct sway_output *output = root->outputs->items[i];
|
struct sway_output *output = root->outputs->items[i];
|
||||||
struct wlr_box *output_box = wlr_output_layout_get_box(
|
struct wlr_box output_box;
|
||||||
root->output_layout, output->wlr_output);
|
wlr_output_layout_get_box(root->output_layout,
|
||||||
output_damage_surface(output, lx - output_box->x,
|
output->wlr_output, &output_box);
|
||||||
ly - output_box->y, surface, whole);
|
output_damage_surface(output, lx - output_box.x,
|
||||||
|
ly - output_box.y, surface, whole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,71 @@ static const GLfloat verts[] = {
|
||||||
0, 1, // bottom left
|
0, 1, // bottom left
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const float transforms[][9] = {
|
||||||
|
[WL_OUTPUT_TRANSFORM_NORMAL] = {
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
[WL_OUTPUT_TRANSFORM_90] = {
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
[WL_OUTPUT_TRANSFORM_180] = {
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
[WL_OUTPUT_TRANSFORM_270] = {
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
[WL_OUTPUT_TRANSFORM_FLIPPED] = {
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
[WL_OUTPUT_TRANSFORM_FLIPPED_90] = {
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
[WL_OUTPUT_TRANSFORM_FLIPPED_180] = {
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
[WL_OUTPUT_TRANSFORM_FLIPPED_270] = {
|
||||||
|
0.0f, -1.0f, 0.0f,
|
||||||
|
-1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void matrix_projection(float mat[static 9], int width, int height,
|
||||||
|
enum wl_output_transform transform) {
|
||||||
|
memset(mat, 0, sizeof(*mat) * 9);
|
||||||
|
|
||||||
|
const float *t = transforms[transform];
|
||||||
|
float x = 2.0f / width;
|
||||||
|
float y = 2.0f / height;
|
||||||
|
|
||||||
|
// Rotation + reflection
|
||||||
|
mat[0] = x * t[0];
|
||||||
|
mat[1] = x * t[1];
|
||||||
|
mat[3] = y * -t[3];
|
||||||
|
mat[4] = y * -t[4];
|
||||||
|
|
||||||
|
// Translation
|
||||||
|
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
|
||||||
|
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
|
||||||
|
|
||||||
|
// Identity
|
||||||
|
mat[8] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
static GLuint compile_shader(GLuint type, const GLchar *src) {
|
static GLuint compile_shader(GLuint type, const GLchar *src) {
|
||||||
GLuint shader = glCreateShader(type);
|
GLuint shader = glCreateShader(type);
|
||||||
glShaderSource(shader, 1, &src, NULL);
|
glShaderSource(shader, 1, &src, NULL);
|
||||||
|
@ -156,7 +221,8 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
|
||||||
|
|
||||||
// TODO: wlr_egl_make_current or eglMakeCurrent?
|
// TODO: wlr_egl_make_current or eglMakeCurrent?
|
||||||
// TODO: assert instead of conditional statement?
|
// TODO: assert instead of conditional statement?
|
||||||
if (!wlr_egl_make_current(egl)) {
|
if (!eglMakeCurrent(wlr_egl_get_display(egl), EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||||
|
wlr_egl_get_context(egl))) {
|
||||||
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not make EGL current");
|
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not make EGL current");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +308,11 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_egl_unset_current(renderer->egl);
|
if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl),
|
||||||
|
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
|
||||||
|
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
sway_log(SWAY_INFO, "GLES2 RENDERER: Shaders Initialized Successfully");
|
sway_log(SWAY_INFO, "GLES2 RENDERER: Shaders Initialized Successfully");
|
||||||
return renderer;
|
return renderer;
|
||||||
|
@ -257,7 +327,10 @@ error:
|
||||||
glDeleteProgram(renderer->shaders.tex_rgbx.program);
|
glDeleteProgram(renderer->shaders.tex_rgbx.program);
|
||||||
glDeleteProgram(renderer->shaders.tex_ext.program);
|
glDeleteProgram(renderer->shaders.tex_ext.program);
|
||||||
|
|
||||||
wlr_egl_unset_current(renderer->egl);
|
if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl),
|
||||||
|
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
|
||||||
|
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: more freeing?
|
// TODO: more freeing?
|
||||||
free(renderer);
|
free(renderer);
|
||||||
|
@ -270,7 +343,7 @@ void fx_renderer_begin(struct fx_renderer *renderer, uint32_t width, uint32_t he
|
||||||
glViewport(0, 0, width, height);
|
glViewport(0, 0, width, height);
|
||||||
|
|
||||||
// refresh projection matrix
|
// refresh projection matrix
|
||||||
wlr_matrix_projection(renderer->projection, width, height,
|
matrix_projection(renderer->projection, width, height,
|
||||||
WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
WL_OUTPUT_TRANSFORM_FLIPPED_180);
|
||||||
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
#include <wlr/types/wlr_idle.h>
|
||||||
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sway/desktop/idle_inhibit_v1.h"
|
#include "sway/desktop/idle_inhibit_v1.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
|
@ -140,6 +141,7 @@ void sway_idle_inhibit_v1_check_active(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wlr_idle_set_enabled(manager->idle, NULL, !inhibited);
|
wlr_idle_set_enabled(manager->idle, NULL, !inhibited);
|
||||||
|
wlr_idle_notifier_v1_set_inhibited(server.idle_notifier_v1, inhibited);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
|
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
|
||||||
|
|
211
sway/desktop/launcher.c
Normal file
211
sway/desktop/launcher.c
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wlr/types/wlr_xdg_activation_v1.h>
|
||||||
|
#include "sway/input/seat.h"
|
||||||
|
#include "sway/output.h"
|
||||||
|
#include "sway/desktop/launcher.h"
|
||||||
|
#include "sway/tree/node.h"
|
||||||
|
#include "sway/tree/container.h"
|
||||||
|
#include "sway/tree/workspace.h"
|
||||||
|
#include "sway/tree/root.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the pid of a parent process given the pid of a child process.
|
||||||
|
*
|
||||||
|
* Returns the parent pid or NULL if the parent pid cannot be determined.
|
||||||
|
*/
|
||||||
|
static pid_t get_parent_pid(pid_t child) {
|
||||||
|
pid_t parent = -1;
|
||||||
|
char file_name[100];
|
||||||
|
char *buffer = NULL;
|
||||||
|
const char *sep = " ";
|
||||||
|
FILE *stat = NULL;
|
||||||
|
size_t buf_size = 0;
|
||||||
|
|
||||||
|
snprintf(file_name, sizeof(file_name), "/proc/%d/stat", child);
|
||||||
|
|
||||||
|
if ((stat = fopen(file_name, "r"))) {
|
||||||
|
if (getline(&buffer, &buf_size, stat) != -1) {
|
||||||
|
strtok(buffer, sep); // pid
|
||||||
|
strtok(NULL, sep); // executable name
|
||||||
|
strtok(NULL, sep); // state
|
||||||
|
char *token = strtok(NULL, sep); // parent pid
|
||||||
|
parent = strtol(token, NULL, 10);
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
fclose(stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
return (parent == child) ? -1 : parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void launcher_ctx_consume(struct launcher_ctx *ctx) {
|
||||||
|
// The view is now responsible for destroying this ctx
|
||||||
|
wl_list_remove(&ctx->token_destroy.link);
|
||||||
|
wl_list_init(&ctx->token_destroy.link);
|
||||||
|
|
||||||
|
if (!ctx->activated) {
|
||||||
|
// An unactivated token hasn't been destroyed yet
|
||||||
|
wlr_xdg_activation_token_v1_destroy(ctx->token);
|
||||||
|
}
|
||||||
|
ctx->token = NULL;
|
||||||
|
|
||||||
|
// Prevent additional matches
|
||||||
|
wl_list_remove(&ctx->link);
|
||||||
|
wl_list_init(&ctx->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void launcher_ctx_destroy(struct launcher_ctx *ctx) {
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_list_remove(&ctx->node_destroy.link);
|
||||||
|
wl_list_remove(&ctx->token_destroy.link);
|
||||||
|
wl_list_remove(&ctx->link);
|
||||||
|
wlr_xdg_activation_token_v1_destroy(ctx->token);
|
||||||
|
free(ctx->name);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct launcher_ctx *launcher_ctx_find_pid(pid_t pid) {
|
||||||
|
if (wl_list_empty(&server.pending_launcher_ctxs)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct launcher_ctx *ctx = NULL;
|
||||||
|
sway_log(SWAY_DEBUG, "Looking up workspace for pid %d", pid);
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct launcher_ctx *_ctx = NULL;
|
||||||
|
wl_list_for_each(_ctx, &server.pending_launcher_ctxs, link) {
|
||||||
|
if (pid == _ctx->pid) {
|
||||||
|
ctx = _ctx;
|
||||||
|
sway_log(SWAY_DEBUG,
|
||||||
|
"found %s match for pid %d: %s",
|
||||||
|
node_type_to_str(ctx->node->type), pid, node_get_name(ctx->node));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pid = get_parent_pid(pid);
|
||||||
|
} while (pid > 1);
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_workspace *launcher_ctx_get_workspace(
|
||||||
|
struct launcher_ctx *ctx) {
|
||||||
|
struct sway_workspace *ws = NULL;
|
||||||
|
struct sway_output *output = NULL;
|
||||||
|
|
||||||
|
switch (ctx->node->type) {
|
||||||
|
case N_CONTAINER:
|
||||||
|
// Unimplemented
|
||||||
|
// TODO: add container matching?
|
||||||
|
ws = ctx->node->sway_container->pending.workspace;
|
||||||
|
break;
|
||||||
|
case N_WORKSPACE:
|
||||||
|
ws = ctx->node->sway_workspace;
|
||||||
|
break;
|
||||||
|
case N_OUTPUT:
|
||||||
|
output = ctx->node->sway_output;
|
||||||
|
ws = workspace_by_name(ctx->name);
|
||||||
|
if (!ws) {
|
||||||
|
sway_log(SWAY_DEBUG,
|
||||||
|
"Creating workspace %s for pid %d because it disappeared",
|
||||||
|
ctx->name, ctx->pid);
|
||||||
|
if (!output->enabled) {
|
||||||
|
sway_log(SWAY_DEBUG,
|
||||||
|
"Workspace output %s is disabled, trying another one",
|
||||||
|
output->wlr_output->name);
|
||||||
|
output = NULL;
|
||||||
|
}
|
||||||
|
ws = workspace_create(output, ctx->name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case N_ROOT:
|
||||||
|
ws = workspace_create(NULL, ctx->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ctx_handle_node_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct launcher_ctx *ctx = wl_container_of(listener, ctx, node_destroy);
|
||||||
|
switch (ctx->node->type) {
|
||||||
|
case N_CONTAINER:
|
||||||
|
// Unimplemented
|
||||||
|
break;
|
||||||
|
case N_WORKSPACE:;
|
||||||
|
struct sway_workspace *ws = ctx->node->sway_workspace;
|
||||||
|
wl_list_remove(&ctx->node_destroy.link);
|
||||||
|
wl_list_init(&ctx->node_destroy.link);
|
||||||
|
// We want to save this ws name to recreate later, hopefully on the
|
||||||
|
// same output
|
||||||
|
free(ctx->name);
|
||||||
|
ctx->name = strdup(ws->name);
|
||||||
|
if (!ws->output || ws->output->node.destroying) {
|
||||||
|
// If the output is being destroyed it would be pointless to track
|
||||||
|
// If the output is being disabled, we'll find out if it's still
|
||||||
|
// disabled when we try to match it.
|
||||||
|
ctx->node = &root->node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ctx->node = &ws->output->node;
|
||||||
|
wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy);
|
||||||
|
break;
|
||||||
|
case N_OUTPUT:
|
||||||
|
wl_list_remove(&ctx->node_destroy.link);
|
||||||
|
wl_list_init(&ctx->node_destroy.link);
|
||||||
|
// We'll make the ws ctx->name somewhere else
|
||||||
|
ctx->node = &root->node;
|
||||||
|
break;
|
||||||
|
case N_ROOT:
|
||||||
|
// Unreachable
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void token_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct launcher_ctx *ctx = wl_container_of(listener, ctx, token_destroy);
|
||||||
|
ctx->token = NULL;
|
||||||
|
launcher_ctx_destroy(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct launcher_ctx *launcher_ctx_create() {
|
||||||
|
struct sway_seat *seat = input_manager_current_seat();
|
||||||
|
struct sway_workspace *ws = seat_get_focused_workspace(seat);
|
||||||
|
if (!ws) {
|
||||||
|
sway_log(SWAY_DEBUG, "Failed to create launch context. No workspace.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct launcher_ctx *ctx = calloc(1, sizeof(struct launcher_ctx));
|
||||||
|
struct wlr_xdg_activation_token_v1 *token =
|
||||||
|
wlr_xdg_activation_token_v1_create(server.xdg_activation_v1);
|
||||||
|
token->data = ctx;
|
||||||
|
ctx->name = strdup(ws->name);
|
||||||
|
ctx->token = token;
|
||||||
|
ctx->node = &ws->node;
|
||||||
|
|
||||||
|
ctx->node_destroy.notify = ctx_handle_node_destroy;
|
||||||
|
wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy);
|
||||||
|
|
||||||
|
ctx->token_destroy.notify = token_handle_destroy;
|
||||||
|
wl_signal_add(&token->events.destroy, &ctx->token_destroy);
|
||||||
|
|
||||||
|
wl_list_init(&ctx->link);
|
||||||
|
wl_list_insert(&server.pending_launcher_ctxs, &ctx->link);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx) {
|
||||||
|
const char *token = wlr_xdg_activation_token_v1_get_name(ctx->token);
|
||||||
|
return token;
|
||||||
|
}
|
|
@ -3,8 +3,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||||
#include <wlr/types/wlr_output_damage.h>
|
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sway/desktop/transaction.h"
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
|
@ -270,10 +270,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_resource_get_client(sway_layer->layer_surface->resource);
|
wl_resource_get_client(sway_layer->layer_surface->resource);
|
||||||
bool set_focus = seat->exclusive_client == client;
|
bool set_focus = seat->exclusive_client == client;
|
||||||
|
|
||||||
wl_list_remove(&sway_layer->output_destroy.link);
|
|
||||||
wl_list_remove(&sway_layer->link);
|
|
||||||
wl_list_init(&sway_layer->link);
|
|
||||||
|
|
||||||
if (set_focus) {
|
if (set_focus) {
|
||||||
struct sway_layer_surface *layer =
|
struct sway_layer_surface *layer =
|
||||||
find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
|
find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
|
||||||
|
@ -282,7 +278,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_layer->layer_surface->output = NULL;
|
|
||||||
wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
|
wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,10 +286,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
|
||||||
wl_container_of(listener, layer, surface_commit);
|
wl_container_of(listener, layer, surface_commit);
|
||||||
struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
|
struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
|
||||||
struct wlr_output *wlr_output = layer_surface->output;
|
struct wlr_output *wlr_output = layer_surface->output;
|
||||||
if (wlr_output == NULL) {
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_output *output = wlr_output->data;
|
struct sway_output *output = wlr_output->data;
|
||||||
struct wlr_box old_extent = layer->extent;
|
struct wlr_box old_extent = layer->extent;
|
||||||
|
|
||||||
|
@ -341,13 +333,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
|
||||||
cursor_rebase_all();
|
cursor_rebase_all();
|
||||||
|
|
||||||
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
|
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
|
||||||
if (wlr_output == NULL) {
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct sway_output *output = wlr_output->data;
|
struct sway_output *output = wlr_output->data;
|
||||||
if (output == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
||||||
sway_layer->layer_surface->surface, true);
|
sway_layer->layer_surface->surface, true);
|
||||||
}
|
}
|
||||||
|
@ -375,22 +362,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_list_remove(&sway_layer->surface_commit.link);
|
wl_list_remove(&sway_layer->surface_commit.link);
|
||||||
wl_list_remove(&sway_layer->new_popup.link);
|
wl_list_remove(&sway_layer->new_popup.link);
|
||||||
wl_list_remove(&sway_layer->new_subsurface.link);
|
wl_list_remove(&sway_layer->new_subsurface.link);
|
||||||
if (sway_layer->layer_surface->output != NULL) {
|
|
||||||
struct sway_output *output = sway_layer->layer_surface->output->data;
|
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
|
||||||
if (output != NULL) {
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
arrange_layers(output);
|
struct sway_output *output = wlr_output->data;
|
||||||
transaction_commit_dirty();
|
arrange_layers(output);
|
||||||
}
|
transaction_commit_dirty();
|
||||||
wl_list_remove(&sway_layer->output_destroy.link);
|
wl_list_remove(&sway_layer->output_destroy.link);
|
||||||
sway_layer->layer_surface->output = NULL;
|
sway_layer->layer_surface->output = NULL;
|
||||||
}
|
|
||||||
free(sway_layer);
|
free(sway_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_map(struct wl_listener *listener, void *data) {
|
static void handle_map(struct wl_listener *listener, void *data) {
|
||||||
struct sway_layer_surface *sway_layer = wl_container_of(listener,
|
struct sway_layer_surface *sway_layer = wl_container_of(listener,
|
||||||
sway_layer, map);
|
sway_layer, map);
|
||||||
struct sway_output *output = sway_layer->layer_surface->output->data;
|
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
|
||||||
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
|
struct sway_output *output = wlr_output->data;
|
||||||
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
|
||||||
sway_layer->layer_surface->surface, true);
|
sway_layer->layer_surface->surface, true);
|
||||||
wlr_surface_send_enter(sway_layer->layer_surface->surface,
|
wlr_surface_send_enter(sway_layer->layer_surface->surface,
|
||||||
|
@ -408,9 +397,7 @@ static void subsurface_damage(struct sway_layer_subsurface *subsurface,
|
||||||
bool whole) {
|
bool whole) {
|
||||||
struct sway_layer_surface *layer = subsurface->layer_surface;
|
struct sway_layer_surface *layer = subsurface->layer_surface;
|
||||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||||
if (!wlr_output) {
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct sway_output *output = wlr_output->data;
|
struct sway_output *output = wlr_output->data;
|
||||||
int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
|
int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
|
||||||
int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
|
int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
|
||||||
|
@ -496,15 +483,15 @@ static struct sway_layer_surface *popup_get_layer(
|
||||||
static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
|
static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
|
||||||
struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
|
struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
|
||||||
struct wlr_surface *surface = popup->base->surface;
|
struct wlr_surface *surface = popup->base->surface;
|
||||||
int popup_sx = popup->geometry.x - popup->base->current.geometry.x;
|
int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x;
|
||||||
int popup_sy = popup->geometry.y - popup->base->current.geometry.y;
|
int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y;
|
||||||
int ox = popup_sx, oy = popup_sy;
|
int ox = popup_sx, oy = popup_sy;
|
||||||
struct sway_layer_surface *layer;
|
struct sway_layer_surface *layer;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
|
if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
|
||||||
layer_popup = layer_popup->parent_popup;
|
layer_popup = layer_popup->parent_popup;
|
||||||
ox += layer_popup->wlr_popup->geometry.x;
|
ox += layer_popup->wlr_popup->current.geometry.x;
|
||||||
oy += layer_popup->wlr_popup->geometry.y;
|
oy += layer_popup->wlr_popup->current.geometry.y;
|
||||||
} else {
|
} else {
|
||||||
layer = layer_popup->parent_layer;
|
layer = layer_popup->parent_layer;
|
||||||
ox += layer->geo.x;
|
ox += layer->geo.x;
|
||||||
|
@ -513,6 +500,7 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||||
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
struct sway_output *output = wlr_output->data;
|
struct sway_output *output = wlr_output->data;
|
||||||
output_damage_surface(output, ox, oy, surface, whole);
|
output_damage_surface(output, ox, oy, surface, whole);
|
||||||
}
|
}
|
||||||
|
@ -521,6 +509,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) {
|
||||||
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
|
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
|
||||||
struct sway_layer_surface *layer = popup_get_layer(popup);
|
struct sway_layer_surface *layer = popup_get_layer(popup);
|
||||||
struct wlr_output *wlr_output = layer->layer_surface->output;
|
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||||
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
|
wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
|
||||||
popup_damage(popup, true);
|
popup_damage(popup, true);
|
||||||
}
|
}
|
||||||
|
@ -550,7 +539,9 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
|
||||||
struct sway_layer_surface *layer = popup_get_layer(popup);
|
struct sway_layer_surface *layer = popup_get_layer(popup);
|
||||||
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
|
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
|
||||||
|
|
||||||
struct sway_output *output = layer->layer_surface->output->data;
|
struct wlr_output *wlr_output = layer->layer_surface->output;
|
||||||
|
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
|
||||||
|
struct sway_output *output = wlr_output->data;
|
||||||
|
|
||||||
// the output box expressed in the coordinate system of the toplevel parent
|
// the output box expressed in the coordinate system of the toplevel parent
|
||||||
// of the popup
|
// of the popup
|
||||||
|
@ -642,6 +633,10 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
|
||||||
sway_log(SWAY_ERROR,
|
sway_log(SWAY_ERROR,
|
||||||
"no output to auto-assign layer surface '%s' to",
|
"no output to auto-assign layer surface '%s' to",
|
||||||
layer_surface->namespace);
|
layer_surface->namespace);
|
||||||
|
// Note that layer_surface->output can be NULL
|
||||||
|
// here, but none of our destroy callbacks are
|
||||||
|
// registered yet so we don't have to make them
|
||||||
|
// handle that case.
|
||||||
wlr_layer_surface_v1_destroy(layer_surface);
|
wlr_layer_surface_v1_destroy(layer_surface);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,10 @@
|
||||||
#include <wlr/types/wlr_buffer.h>
|
#include <wlr/types/wlr_buffer.h>
|
||||||
#include <wlr/types/wlr_drm_lease_v1.h>
|
#include <wlr/types/wlr_drm_lease_v1.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/types/wlr_output_damage.h>
|
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_presentation_time.h>
|
#include <wlr/types/wlr_presentation_time.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/util/region.h>
|
#include <wlr/util/region.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
@ -276,6 +275,25 @@ static void for_each_surface_container_iterator(struct sway_container *con,
|
||||||
|
|
||||||
static void output_for_each_surface(struct sway_output *output,
|
static void output_for_each_surface(struct sway_output *output,
|
||||||
sway_surface_iterator_func_t iterator, void *user_data) {
|
sway_surface_iterator_func_t iterator, void *user_data) {
|
||||||
|
if (server.session_lock.locked) {
|
||||||
|
if (server.session_lock.lock == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct wlr_session_lock_surface_v1 *lock_surface;
|
||||||
|
wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
|
||||||
|
if (lock_surface->output != output->wlr_output) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!lock_surface->mapped) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output_surface_for_each_surface(output, lock_surface->surface,
|
||||||
|
0.0, 0.0, iterator, user_data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (output_has_opaque_overlay_layer_surface(output)) {
|
if (output_has_opaque_overlay_layer_surface(output)) {
|
||||||
goto overlay;
|
goto overlay;
|
||||||
}
|
}
|
||||||
|
@ -435,6 +453,10 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server.session_lock.locked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!wl_list_empty(&view->saved_buffers)) {
|
if (!wl_list_empty(&view->saved_buffers)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -533,31 +555,43 @@ static int output_repaint_timer_handler(void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needs_frame;
|
int buffer_age;
|
||||||
pixman_region32_t damage;
|
if (!wlr_output_attach_render(output->wlr_output, &buffer_age)) {
|
||||||
pixman_region32_init(&damage);
|
|
||||||
if (!wlr_output_damage_attach_render(output->damage,
|
|
||||||
&needs_frame, &damage)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_frame) {
|
pixman_region32_t damage;
|
||||||
struct timespec now;
|
pixman_region32_init(&damage);
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage);
|
||||||
|
if (!output->wlr_output->needs_frame &&
|
||||||
output_render(output, &now, &damage);
|
!pixman_region32_not_empty(&output->damage_ring.current)) {
|
||||||
} else {
|
pixman_region32_fini(&damage);
|
||||||
wlr_output_rollback(output->wlr_output);
|
wlr_output_rollback(output->wlr_output);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timespec now;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
|
output_render(output, &now, &damage);
|
||||||
|
|
||||||
pixman_region32_fini(&damage);
|
pixman_region32_fini(&damage);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
|
static void handle_damage(struct wl_listener *listener, void *user_data) {
|
||||||
struct sway_output *output =
|
struct sway_output *output =
|
||||||
wl_container_of(listener, output, damage_frame);
|
wl_container_of(listener, output, damage);
|
||||||
|
struct wlr_output_event_damage *event = user_data;
|
||||||
|
if (wlr_damage_ring_add(&output->damage_ring, event->damage)) {
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_frame(struct wl_listener *listener, void *user_data) {
|
||||||
|
struct sway_output *output =
|
||||||
|
wl_container_of(listener, output, frame);
|
||||||
if (!output->enabled || !output->wlr_output->enabled) {
|
if (!output->enabled || !output->wlr_output->enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -620,11 +654,18 @@ static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
|
||||||
send_frame_done(output, &data);
|
send_frame_done(output, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_needs_frame(struct wl_listener *listener, void *user_data) {
|
||||||
|
struct sway_output *output =
|
||||||
|
wl_container_of(listener, output, needs_frame);
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
}
|
||||||
|
|
||||||
void output_damage_whole(struct sway_output *output) {
|
void output_damage_whole(struct sway_output *output) {
|
||||||
// The output can exist with no wlr_output if it's just been disconnected
|
// The output can exist with no wlr_output if it's just been disconnected
|
||||||
// and the transaction to evacuate it has't completed yet.
|
// and the transaction to evacuate it has't completed yet.
|
||||||
if (output && output->wlr_output && output->damage) {
|
if (output != NULL && output->wlr_output != NULL) {
|
||||||
wlr_output_damage_add_whole(output->damage);
|
wlr_damage_ring_add_whole(&output->damage_ring);
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,11 +689,15 @@ static void damage_surface_iterator(struct sway_output *output,
|
||||||
ceil(output->wlr_output->scale) - surface->current.scale);
|
ceil(output->wlr_output->scale) - surface->current.scale);
|
||||||
}
|
}
|
||||||
pixman_region32_translate(&damage, box.x, box.y);
|
pixman_region32_translate(&damage, box.x, box.y);
|
||||||
wlr_output_damage_add(output->damage, &damage);
|
if (wlr_damage_ring_add(&output->damage_ring, &damage)) {
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
}
|
||||||
pixman_region32_fini(&damage);
|
pixman_region32_fini(&damage);
|
||||||
|
|
||||||
if (whole) {
|
if (whole) {
|
||||||
wlr_output_damage_add_box(output->damage, &box);
|
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wl_list_empty(&surface->current.frame_callback_list)) {
|
if (!wl_list_empty(&surface->current.frame_callback_list)) {
|
||||||
|
@ -682,7 +727,9 @@ void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
|
||||||
box.x -= output->lx;
|
box.x -= output->lx;
|
||||||
box.y -= output->ly;
|
box.y -= output->ly;
|
||||||
scale_box(&box, output->wlr_output->scale);
|
scale_box(&box, output->wlr_output->scale);
|
||||||
wlr_output_damage_add_box(output->damage, &box);
|
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void damage_child_views_iterator(struct sway_container *con,
|
static void damage_child_views_iterator(struct sway_container *con,
|
||||||
|
@ -706,7 +753,9 @@ void output_damage_whole_container(struct sway_output *output,
|
||||||
.height = con->current.height + 2,
|
.height = con->current.height + 2,
|
||||||
};
|
};
|
||||||
scale_box(&box, output->wlr_output->scale);
|
scale_box(&box, output->wlr_output->scale);
|
||||||
wlr_output_damage_add_box(output->damage, &box);
|
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
}
|
||||||
// Damage subsurfaces as well, which may extend outside the box
|
// Damage subsurfaces as well, which may extend outside the box
|
||||||
if (con->view) {
|
if (con->view) {
|
||||||
damage_child_views_iterator(con, output);
|
damage_child_views_iterator(con, output);
|
||||||
|
@ -715,20 +764,6 @@ void output_damage_whole_container(struct sway_output *output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void damage_handle_destroy(struct wl_listener *listener, void *data) {
|
|
||||||
struct sway_output *output =
|
|
||||||
wl_container_of(listener, output, damage_destroy);
|
|
||||||
if (!output->enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
output_disable(output);
|
|
||||||
|
|
||||||
wl_list_remove(&output->damage_destroy.link);
|
|
||||||
wl_list_remove(&output->damage_frame.link);
|
|
||||||
|
|
||||||
transaction_commit_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_output_manager_config(struct sway_server *server) {
|
static void update_output_manager_config(struct sway_server *server) {
|
||||||
struct wlr_output_configuration_v1 *config =
|
struct wlr_output_configuration_v1 *config =
|
||||||
wlr_output_configuration_v1_create();
|
wlr_output_configuration_v1_create();
|
||||||
|
@ -740,14 +775,15 @@ static void update_output_manager_config(struct sway_server *server) {
|
||||||
}
|
}
|
||||||
struct wlr_output_configuration_head_v1 *config_head =
|
struct wlr_output_configuration_head_v1 *config_head =
|
||||||
wlr_output_configuration_head_v1_create(config, output->wlr_output);
|
wlr_output_configuration_head_v1_create(config, output->wlr_output);
|
||||||
struct wlr_box *output_box = wlr_output_layout_get_box(
|
struct wlr_box output_box;
|
||||||
root->output_layout, output->wlr_output);
|
wlr_output_layout_get_box(root->output_layout,
|
||||||
// We mark the output enabled even if it is switched off by DPMS
|
output->wlr_output, &output_box);
|
||||||
|
// We mark the output enabled when it's switched off but not disabled
|
||||||
config_head->state.enabled = output->current_mode != NULL && output->enabled;
|
config_head->state.enabled = output->current_mode != NULL && output->enabled;
|
||||||
config_head->state.mode = output->current_mode;
|
config_head->state.mode = output->current_mode;
|
||||||
if (output_box) {
|
if (!wlr_box_empty(&output_box)) {
|
||||||
config_head->state.x = output_box->x;
|
config_head->state.x = output_box.x;
|
||||||
config_head->state.y = output_box->y;
|
config_head->state.y = output_box.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,18 +793,24 @@ static void update_output_manager_config(struct sway_server *server) {
|
||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
struct sway_output *output = wl_container_of(listener, output, destroy);
|
struct sway_output *output = wl_container_of(listener, output, destroy);
|
||||||
struct sway_server *server = output->server;
|
struct sway_server *server = output->server;
|
||||||
output_begin_destroy(output);
|
|
||||||
|
|
||||||
if (output->enabled) {
|
if (output->enabled) {
|
||||||
output_disable(output);
|
output_disable(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output_begin_destroy(output);
|
||||||
|
|
||||||
wl_list_remove(&output->link);
|
wl_list_remove(&output->link);
|
||||||
|
|
||||||
wl_list_remove(&output->destroy.link);
|
wl_list_remove(&output->destroy.link);
|
||||||
wl_list_remove(&output->commit.link);
|
wl_list_remove(&output->commit.link);
|
||||||
wl_list_remove(&output->mode.link);
|
wl_list_remove(&output->mode.link);
|
||||||
wl_list_remove(&output->present.link);
|
wl_list_remove(&output->present.link);
|
||||||
|
wl_list_remove(&output->damage.link);
|
||||||
|
wl_list_remove(&output->frame.link);
|
||||||
|
wl_list_remove(&output->needs_frame.link);
|
||||||
|
|
||||||
|
wlr_damage_ring_finish(&output->damage_ring);
|
||||||
|
|
||||||
output->wlr_output->data = NULL;
|
output->wlr_output->data = NULL;
|
||||||
output->wlr_output = NULL;
|
output->wlr_output = NULL;
|
||||||
|
@ -796,10 +838,16 @@ static void handle_mode(struct wl_listener *listener, void *data) {
|
||||||
if (!output->enabled) {
|
if (!output->enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrange_layers(output);
|
arrange_layers(output);
|
||||||
arrange_output(output);
|
arrange_output(output);
|
||||||
transaction_commit_dirty();
|
transaction_commit_dirty();
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
|
||||||
|
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
|
||||||
update_output_manager_config(output->server);
|
update_output_manager_config(output->server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,6 +875,13 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
update_output_manager_config(output->server);
|
update_output_manager_config(output->server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM)) {
|
||||||
|
int width, height;
|
||||||
|
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
|
||||||
|
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
|
||||||
|
wlr_output_schedule_frame(output->wlr_output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_present(struct wl_listener *listener, void *data) {
|
static void handle_present(struct wl_listener *listener, void *data) {
|
||||||
|
@ -862,10 +917,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
if (wlr_output->non_desktop) {
|
if (wlr_output->non_desktop) {
|
||||||
sway_log(SWAY_DEBUG, "Not configuring non-desktop output");
|
sway_log(SWAY_DEBUG, "Not configuring non-desktop output");
|
||||||
|
struct sway_output_non_desktop *non_desktop = output_non_desktop_create(wlr_output);
|
||||||
if (server->drm_lease_manager) {
|
if (server->drm_lease_manager) {
|
||||||
wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager,
|
wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager,
|
||||||
wlr_output);
|
wlr_output);
|
||||||
}
|
}
|
||||||
|
list_add(root->non_desktop_outputs, non_desktop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,7 +937,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
output->server = server;
|
output->server = server;
|
||||||
output->damage = wlr_output_damage_create(wlr_output);
|
wlr_damage_ring_init(&output->damage_ring);
|
||||||
|
|
||||||
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
|
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
|
||||||
output->destroy.notify = handle_destroy;
|
output->destroy.notify = handle_destroy;
|
||||||
|
@ -890,10 +947,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
output->mode.notify = handle_mode;
|
output->mode.notify = handle_mode;
|
||||||
wl_signal_add(&wlr_output->events.present, &output->present);
|
wl_signal_add(&wlr_output->events.present, &output->present);
|
||||||
output->present.notify = handle_present;
|
output->present.notify = handle_present;
|
||||||
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
|
wl_signal_add(&wlr_output->events.damage, &output->damage);
|
||||||
output->damage_frame.notify = damage_handle_frame;
|
output->damage.notify = handle_damage;
|
||||||
wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
|
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
||||||
output->damage_destroy.notify = damage_handle_destroy;
|
output->frame.notify = handle_frame;
|
||||||
|
wl_signal_add(&wlr_output->events.needs_frame, &output->needs_frame);
|
||||||
|
output->needs_frame.notify = handle_needs_frame;
|
||||||
|
|
||||||
output->repaint_timer = wl_event_loop_add_timer(server->wl_event_loop,
|
output->repaint_timer = wl_event_loop_add_timer(server->wl_event_loop,
|
||||||
output_repaint_timer_handler, output);
|
output_repaint_timer_handler, output);
|
||||||
|
@ -1007,10 +1066,10 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
||||||
struct output_config *oc = new_output_config(output->wlr_output->name);
|
struct output_config *oc = new_output_config(output->wlr_output->name);
|
||||||
switch (event->mode) {
|
switch (event->mode) {
|
||||||
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
|
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
|
||||||
oc->dpms_state = DPMS_OFF;
|
oc->power = 0;
|
||||||
break;
|
break;
|
||||||
case ZWLR_OUTPUT_POWER_V1_MODE_ON:
|
case ZWLR_OUTPUT_POWER_V1_MODE_ON:
|
||||||
oc->dpms_state = DPMS_ON;
|
oc->power = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
oc = store_output_config(oc);
|
oc = store_output_config(oc);
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
#include <wlr/render/gles2.h>
|
#include <wlr/render/gles2.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_buffer.h>
|
#include <wlr/types/wlr_buffer.h>
|
||||||
|
#include <wlr/types/wlr_damage_ring.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
#include <wlr/types/wlr_output_damage.h>
|
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/util/region.h>
|
#include <wlr/util/region.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -1301,6 +1301,41 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
fx_renderer_clear((float[]){1, 1, 0, 1});
|
fx_renderer_clear((float[]){1, 1, 0, 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server.session_lock.locked) {
|
||||||
|
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
if (server.session_lock.lock == NULL) {
|
||||||
|
// abandoned lock -> red BG
|
||||||
|
clear_color[0] = 1.f;
|
||||||
|
}
|
||||||
|
int nrects;
|
||||||
|
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
|
||||||
|
for (int i = 0; i < nrects; ++i) {
|
||||||
|
scissor_output(wlr_output, &rects[i]);
|
||||||
|
fx_renderer_clear(clear_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server.session_lock.lock != NULL) {
|
||||||
|
struct render_data data = {
|
||||||
|
.damage = damage,
|
||||||
|
.deco_data = get_undecorated_decoration_data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_session_lock_surface_v1 *lock_surface;
|
||||||
|
wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
|
||||||
|
if (lock_surface->output != wlr_output) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!lock_surface->mapped) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output_surface_for_each_surface(output, lock_surface->surface,
|
||||||
|
0.0, 0.0, render_surface_iterator, &data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto renderer_end;
|
||||||
|
}
|
||||||
|
|
||||||
if (output_has_opaque_overlay_layer_surface(output)) {
|
if (output_has_opaque_overlay_layer_surface(output)) {
|
||||||
goto render_overlay;
|
goto render_overlay;
|
||||||
}
|
}
|
||||||
|
@ -1409,7 +1444,7 @@ renderer_end:
|
||||||
|
|
||||||
enum wl_output_transform transform =
|
enum wl_output_transform transform =
|
||||||
wlr_output_transform_invert(wlr_output->transform);
|
wlr_output_transform_invert(wlr_output->transform);
|
||||||
wlr_region_transform(&frame_damage, &output->damage->current,
|
wlr_region_transform(&frame_damage, &output->damage_ring.current,
|
||||||
transform, width, height);
|
transform, width, height);
|
||||||
|
|
||||||
if (debug.damage != DAMAGE_DEFAULT) {
|
if (debug.damage != DAMAGE_DEFAULT) {
|
||||||
|
@ -1423,5 +1458,7 @@ renderer_end:
|
||||||
if (!wlr_output_commit(wlr_output)) {
|
if (!wlr_output_commit(wlr_output)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wlr_damage_ring_rotate(&output->damage_ring);
|
||||||
output->last_frame = *when;
|
output->last_frame = *when;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <wlr/types/wlr_surface.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
#include "sway/surface.h"
|
#include "sway/surface.h"
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,11 @@ static const struct sway_view_child_impl popup_impl;
|
||||||
static void popup_get_view_coords(struct sway_view_child *child,
|
static void popup_get_view_coords(struct sway_view_child *child,
|
||||||
int *sx, int *sy) {
|
int *sx, int *sy) {
|
||||||
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
|
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
|
||||||
struct wlr_xdg_surface *surface = popup->wlr_xdg_surface;
|
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
|
||||||
|
|
||||||
wlr_xdg_popup_get_toplevel_coords(surface->popup,
|
wlr_xdg_popup_get_toplevel_coords(wlr_popup,
|
||||||
surface->popup->geometry.x - surface->current.geometry.x,
|
wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x,
|
||||||
surface->popup->geometry.y - surface->current.geometry.y,
|
wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y,
|
||||||
sx, sy);
|
sx, sy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
static void popup_unconstrain(struct sway_xdg_popup *popup) {
|
static void popup_unconstrain(struct sway_xdg_popup *popup) {
|
||||||
struct sway_view *view = popup->child.view;
|
struct sway_view *view = popup->child.view;
|
||||||
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup;
|
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
|
||||||
|
|
||||||
struct sway_output *output = view->container->pending.workspace->output;
|
struct sway_output *output = view->container->pending.workspace->output;
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ static struct sway_xdg_popup *popup_create(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
|
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
|
||||||
popup->wlr_xdg_surface = xdg_surface;
|
popup->wlr_xdg_popup = xdg_surface->popup;
|
||||||
|
|
||||||
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
|
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
|
||||||
popup->new_popup.notify = popup_handle_new_popup;
|
popup->new_popup.notify = popup_handle_new_popup;
|
||||||
|
@ -119,7 +119,7 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view(
|
||||||
static void get_constraints(struct sway_view *view, double *min_width,
|
static void get_constraints(struct sway_view *view, double *min_width,
|
||||||
double *max_width, double *min_height, double *max_height) {
|
double *max_width, double *min_height, double *max_height) {
|
||||||
struct wlr_xdg_toplevel_state *state =
|
struct wlr_xdg_toplevel_state *state =
|
||||||
&view->wlr_xdg_surface->toplevel->current;
|
&view->wlr_xdg_toplevel->current;
|
||||||
*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
|
*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
|
||||||
*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
|
*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
|
||||||
*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
|
*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
|
||||||
|
@ -133,9 +133,9 @@ static const char *get_string_prop(struct sway_view *view,
|
||||||
}
|
}
|
||||||
switch (prop) {
|
switch (prop) {
|
||||||
case VIEW_PROP_TITLE:
|
case VIEW_PROP_TITLE:
|
||||||
return view->wlr_xdg_surface->toplevel->title;
|
return view->wlr_xdg_toplevel->title;
|
||||||
case VIEW_PROP_APP_ID:
|
case VIEW_PROP_APP_ID:
|
||||||
return view->wlr_xdg_surface->toplevel->app_id;
|
return view->wlr_xdg_toplevel->app_id;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -148,50 +148,45 @@ static uint32_t configure(struct sway_view *view, double lx, double ly,
|
||||||
if (xdg_shell_view == NULL) {
|
if (xdg_shell_view == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
|
return wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel,
|
||||||
|
width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_activated(struct sway_view *view, bool activated) {
|
static void set_activated(struct sway_view *view, bool activated) {
|
||||||
if (xdg_shell_view_from_view(view) == NULL) {
|
if (xdg_shell_view_from_view(view) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
|
wlr_xdg_toplevel_set_activated(view->wlr_xdg_toplevel, activated);
|
||||||
if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
|
|
||||||
wlr_xdg_toplevel_set_activated(surface, activated);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_tiled(struct sway_view *view, bool tiled) {
|
static void set_tiled(struct sway_view *view, bool tiled) {
|
||||||
if (xdg_shell_view_from_view(view) == NULL) {
|
if (xdg_shell_view_from_view(view) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
|
|
||||||
enum wlr_edges edges = WLR_EDGE_NONE;
|
enum wlr_edges edges = WLR_EDGE_NONE;
|
||||||
if (tiled) {
|
if (tiled) {
|
||||||
edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP |
|
edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP |
|
||||||
WLR_EDGE_BOTTOM;
|
WLR_EDGE_BOTTOM;
|
||||||
}
|
}
|
||||||
wlr_xdg_toplevel_set_tiled(surface, edges);
|
wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
|
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
|
||||||
if (xdg_shell_view_from_view(view) == NULL) {
|
if (xdg_shell_view_from_view(view) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
|
wlr_xdg_toplevel_set_fullscreen(view->wlr_xdg_toplevel, fullscreen);
|
||||||
wlr_xdg_toplevel_set_fullscreen(surface, fullscreen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_resizing(struct sway_view *view, bool resizing) {
|
static void set_resizing(struct sway_view *view, bool resizing) {
|
||||||
if (xdg_shell_view_from_view(view) == NULL) {
|
if (xdg_shell_view_from_view(view) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
|
wlr_xdg_toplevel_set_resizing(view->wlr_xdg_toplevel, resizing);
|
||||||
wlr_xdg_toplevel_set_resizing(surface, resizing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wants_floating(struct sway_view *view) {
|
static bool wants_floating(struct sway_view *view) {
|
||||||
struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel;
|
struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
|
||||||
struct wlr_xdg_toplevel_state *state = &toplevel->current;
|
struct wlr_xdg_toplevel_state *state = &toplevel->current;
|
||||||
return (state->min_width != 0 && state->min_height != 0
|
return (state->min_width != 0 && state->min_height != 0
|
||||||
&& (state->min_width == state->max_width
|
&& (state->min_width == state->max_width
|
||||||
|
@ -204,7 +199,7 @@ static void for_each_surface(struct sway_view *view,
|
||||||
if (xdg_shell_view_from_view(view) == NULL) {
|
if (xdg_shell_view_from_view(view) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wlr_xdg_surface_for_each_surface(view->wlr_xdg_surface, iterator,
|
wlr_xdg_surface_for_each_surface(view->wlr_xdg_toplevel->base, iterator,
|
||||||
user_data);
|
user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,8 +208,8 @@ static void for_each_popup_surface(struct sway_view *view,
|
||||||
if (xdg_shell_view_from_view(view) == NULL) {
|
if (xdg_shell_view_from_view(view) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_surface, iterator,
|
wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_toplevel->base,
|
||||||
user_data);
|
iterator, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_transient_for(struct sway_view *child,
|
static bool is_transient_for(struct sway_view *child,
|
||||||
|
@ -222,12 +217,12 @@ static bool is_transient_for(struct sway_view *child,
|
||||||
if (xdg_shell_view_from_view(child) == NULL) {
|
if (xdg_shell_view_from_view(child) == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct wlr_xdg_surface *surface = child->wlr_xdg_surface;
|
struct wlr_xdg_toplevel *toplevel = child->wlr_xdg_toplevel;
|
||||||
while (surface && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
|
while (toplevel) {
|
||||||
if (surface->toplevel->parent == ancestor->wlr_xdg_surface) {
|
if (toplevel->parent == ancestor->wlr_xdg_toplevel) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
surface = surface->toplevel->parent;
|
toplevel = toplevel->parent;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -236,17 +231,13 @@ static void _close(struct sway_view *view) {
|
||||||
if (xdg_shell_view_from_view(view) == NULL) {
|
if (xdg_shell_view_from_view(view) == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
|
wlr_xdg_toplevel_send_close(view->wlr_xdg_toplevel);
|
||||||
if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL
|
|
||||||
&& surface->toplevel) {
|
|
||||||
wlr_xdg_toplevel_send_close(surface);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_popups(struct sway_view *view) {
|
static void close_popups(struct sway_view *view) {
|
||||||
struct wlr_xdg_popup *popup, *tmp;
|
struct wlr_xdg_popup *popup, *tmp;
|
||||||
wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) {
|
wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_toplevel->base->popups, link) {
|
||||||
wlr_xdg_popup_destroy(popup->base);
|
wlr_xdg_popup_destroy(popup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +271,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
||||||
struct sway_xdg_shell_view *xdg_shell_view =
|
struct sway_xdg_shell_view *xdg_shell_view =
|
||||||
wl_container_of(listener, xdg_shell_view, commit);
|
wl_container_of(listener, xdg_shell_view, commit);
|
||||||
struct sway_view *view = &xdg_shell_view->view;
|
struct sway_view *view = &xdg_shell_view->view;
|
||||||
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
|
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base;
|
||||||
|
|
||||||
struct wlr_box new_geo;
|
struct wlr_box new_geo;
|
||||||
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
|
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
|
||||||
|
@ -334,26 +325,27 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
|
||||||
popup_create(wlr_popup, &xdg_shell_view->view);
|
popup_create(wlr_popup, &xdg_shell_view->view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_request_maximize(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_xdg_shell_view *xdg_shell_view =
|
||||||
|
wl_container_of(listener, xdg_shell_view, request_maximize);
|
||||||
|
struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
|
||||||
|
wlr_xdg_surface_schedule_configure(toplevel->base);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
|
static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
|
||||||
struct sway_xdg_shell_view *xdg_shell_view =
|
struct sway_xdg_shell_view *xdg_shell_view =
|
||||||
wl_container_of(listener, xdg_shell_view, request_fullscreen);
|
wl_container_of(listener, xdg_shell_view, request_fullscreen);
|
||||||
struct wlr_xdg_toplevel_set_fullscreen_event *e = data;
|
struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
|
||||||
struct wlr_xdg_surface *xdg_surface =
|
|
||||||
xdg_shell_view->view.wlr_xdg_surface;
|
|
||||||
struct sway_view *view = &xdg_shell_view->view;
|
struct sway_view *view = &xdg_shell_view->view;
|
||||||
|
|
||||||
if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL,
|
if (!toplevel->base->mapped) {
|
||||||
"xdg_shell requested fullscreen of surface with role %i",
|
|
||||||
xdg_surface->role)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!xdg_surface->mapped) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sway_container *container = view->container;
|
struct sway_container *container = view->container;
|
||||||
if (e->fullscreen && e->output && e->output->data) {
|
struct wlr_xdg_toplevel_requested *req = &toplevel->requested;
|
||||||
struct sway_output *output = e->output->data;
|
if (req->fullscreen && req->fullscreen_output && req->fullscreen_output->data) {
|
||||||
|
struct sway_output *output = req->fullscreen_output->data;
|
||||||
struct sway_workspace *ws = output_get_active_workspace(output);
|
struct sway_workspace *ws = output_get_active_workspace(output);
|
||||||
if (ws && !container_is_scratchpad_hidden(container) &&
|
if (ws && !container_is_scratchpad_hidden(container) &&
|
||||||
container->pending.workspace != ws) {
|
container->pending.workspace != ws) {
|
||||||
|
@ -365,7 +357,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container_set_fullscreen(container, e->fullscreen);
|
container_set_fullscreen(container, req->fullscreen);
|
||||||
|
|
||||||
arrange_root();
|
arrange_root();
|
||||||
transaction_commit_dirty();
|
transaction_commit_dirty();
|
||||||
|
@ -375,7 +367,8 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
|
||||||
struct sway_xdg_shell_view *xdg_shell_view =
|
struct sway_xdg_shell_view *xdg_shell_view =
|
||||||
wl_container_of(listener, xdg_shell_view, request_move);
|
wl_container_of(listener, xdg_shell_view, request_move);
|
||||||
struct sway_view *view = &xdg_shell_view->view;
|
struct sway_view *view = &xdg_shell_view->view;
|
||||||
if (!container_is_floating(view->container)) {
|
if (!container_is_floating(view->container) ||
|
||||||
|
view->container->pending.fullscreen_mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_xdg_toplevel_move_event *e = data;
|
struct wlr_xdg_toplevel_move_event *e = data;
|
||||||
|
@ -412,6 +405,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
wl_list_remove(&xdg_shell_view->commit.link);
|
wl_list_remove(&xdg_shell_view->commit.link);
|
||||||
wl_list_remove(&xdg_shell_view->new_popup.link);
|
wl_list_remove(&xdg_shell_view->new_popup.link);
|
||||||
|
wl_list_remove(&xdg_shell_view->request_maximize.link);
|
||||||
wl_list_remove(&xdg_shell_view->request_fullscreen.link);
|
wl_list_remove(&xdg_shell_view->request_fullscreen.link);
|
||||||
wl_list_remove(&xdg_shell_view->request_move.link);
|
wl_list_remove(&xdg_shell_view->request_move.link);
|
||||||
wl_list_remove(&xdg_shell_view->request_resize.link);
|
wl_list_remove(&xdg_shell_view->request_resize.link);
|
||||||
|
@ -423,13 +417,13 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
||||||
struct sway_xdg_shell_view *xdg_shell_view =
|
struct sway_xdg_shell_view *xdg_shell_view =
|
||||||
wl_container_of(listener, xdg_shell_view, map);
|
wl_container_of(listener, xdg_shell_view, map);
|
||||||
struct sway_view *view = &xdg_shell_view->view;
|
struct sway_view *view = &xdg_shell_view->view;
|
||||||
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
|
struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
|
||||||
|
|
||||||
view->natural_width = view->wlr_xdg_surface->current.geometry.width;
|
view->natural_width = toplevel->base->current.geometry.width;
|
||||||
view->natural_height = view->wlr_xdg_surface->current.geometry.height;
|
view->natural_height = toplevel->base->current.geometry.height;
|
||||||
if (!view->natural_width && !view->natural_height) {
|
if (!view->natural_width && !view->natural_height) {
|
||||||
view->natural_width = view->wlr_xdg_surface->surface->current.width;
|
view->natural_width = toplevel->base->surface->current.width;
|
||||||
view->natural_height = view->wlr_xdg_surface->surface->current.height;
|
view->natural_height = toplevel->base->surface->current.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool csd = false;
|
bool csd = false;
|
||||||
|
@ -440,44 +434,48 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
||||||
csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
|
csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
|
||||||
} else {
|
} else {
|
||||||
struct sway_server_decoration *deco =
|
struct sway_server_decoration *deco =
|
||||||
decoration_from_surface(xdg_surface->surface);
|
decoration_from_surface(toplevel->base->surface);
|
||||||
csd = !deco || deco->wlr_server_decoration->mode ==
|
csd = !deco || deco->wlr_server_decoration->mode ==
|
||||||
WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
|
WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
view_map(view, view->wlr_xdg_surface->surface,
|
view_map(view, toplevel->base->surface,
|
||||||
xdg_surface->toplevel->requested.fullscreen,
|
toplevel->requested.fullscreen,
|
||||||
xdg_surface->toplevel->requested.fullscreen_output,
|
toplevel->requested.fullscreen_output,
|
||||||
csd);
|
csd);
|
||||||
|
|
||||||
transaction_commit_dirty();
|
transaction_commit_dirty();
|
||||||
|
|
||||||
xdg_shell_view->commit.notify = handle_commit;
|
xdg_shell_view->commit.notify = handle_commit;
|
||||||
wl_signal_add(&xdg_surface->surface->events.commit,
|
wl_signal_add(&toplevel->base->surface->events.commit,
|
||||||
&xdg_shell_view->commit);
|
&xdg_shell_view->commit);
|
||||||
|
|
||||||
xdg_shell_view->new_popup.notify = handle_new_popup;
|
xdg_shell_view->new_popup.notify = handle_new_popup;
|
||||||
wl_signal_add(&xdg_surface->events.new_popup,
|
wl_signal_add(&toplevel->base->events.new_popup,
|
||||||
&xdg_shell_view->new_popup);
|
&xdg_shell_view->new_popup);
|
||||||
|
|
||||||
|
xdg_shell_view->request_maximize.notify = handle_request_maximize;
|
||||||
|
wl_signal_add(&toplevel->events.request_maximize,
|
||||||
|
&xdg_shell_view->request_maximize);
|
||||||
|
|
||||||
xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
|
xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
|
||||||
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
|
wl_signal_add(&toplevel->events.request_fullscreen,
|
||||||
&xdg_shell_view->request_fullscreen);
|
&xdg_shell_view->request_fullscreen);
|
||||||
|
|
||||||
xdg_shell_view->request_move.notify = handle_request_move;
|
xdg_shell_view->request_move.notify = handle_request_move;
|
||||||
wl_signal_add(&xdg_surface->toplevel->events.request_move,
|
wl_signal_add(&toplevel->events.request_move,
|
||||||
&xdg_shell_view->request_move);
|
&xdg_shell_view->request_move);
|
||||||
|
|
||||||
xdg_shell_view->request_resize.notify = handle_request_resize;
|
xdg_shell_view->request_resize.notify = handle_request_resize;
|
||||||
wl_signal_add(&xdg_surface->toplevel->events.request_resize,
|
wl_signal_add(&toplevel->events.request_resize,
|
||||||
&xdg_shell_view->request_resize);
|
&xdg_shell_view->request_resize);
|
||||||
|
|
||||||
xdg_shell_view->set_title.notify = handle_set_title;
|
xdg_shell_view->set_title.notify = handle_set_title;
|
||||||
wl_signal_add(&xdg_surface->toplevel->events.set_title,
|
wl_signal_add(&toplevel->events.set_title,
|
||||||
&xdg_shell_view->set_title);
|
&xdg_shell_view->set_title);
|
||||||
|
|
||||||
xdg_shell_view->set_app_id.notify = handle_set_app_id;
|
xdg_shell_view->set_app_id.notify = handle_set_app_id;
|
||||||
wl_signal_add(&xdg_surface->toplevel->events.set_app_id,
|
wl_signal_add(&toplevel->events.set_app_id,
|
||||||
&xdg_shell_view->set_app_id);
|
&xdg_shell_view->set_app_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,7 +489,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_list_remove(&xdg_shell_view->destroy.link);
|
wl_list_remove(&xdg_shell_view->destroy.link);
|
||||||
wl_list_remove(&xdg_shell_view->map.link);
|
wl_list_remove(&xdg_shell_view->map.link);
|
||||||
wl_list_remove(&xdg_shell_view->unmap.link);
|
wl_list_remove(&xdg_shell_view->unmap.link);
|
||||||
view->wlr_xdg_surface = NULL;
|
view->wlr_xdg_toplevel = NULL;
|
||||||
if (view->xdg_decoration) {
|
if (view->xdg_decoration) {
|
||||||
view->xdg_decoration->view = NULL;
|
view->xdg_decoration->view = NULL;
|
||||||
}
|
}
|
||||||
|
@ -522,7 +520,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
|
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
|
||||||
xdg_shell_view->view.wlr_xdg_surface = xdg_surface;
|
xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel;
|
||||||
|
|
||||||
xdg_shell_view->map.notify = handle_map;
|
xdg_shell_view->map.notify = handle_map;
|
||||||
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
|
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
|
#include <wlr/types/wlr_xdg_activation_v1.h>
|
||||||
#include <wlr/xwayland.h>
|
#include <wlr/xwayland.h>
|
||||||
|
#include <xcb/xcb_icccm.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sway/desktop.h"
|
#include "sway/desktop.h"
|
||||||
#include "sway/desktop/transaction.h"
|
#include "sway/desktop/transaction.h"
|
||||||
|
@ -15,6 +17,7 @@
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/tree/arrange.h"
|
#include "sway/tree/arrange.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
|
#include "sway/server.h"
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/view.h"
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
|
|
||||||
|
@ -121,6 +124,20 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_xwayland_surface *xsurface = data;
|
||||||
|
if (!xsurface->mapped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct sway_seat *seat = input_manager_current_seat();
|
||||||
|
struct sway_container *focus = seat_get_focused_container(seat);
|
||||||
|
if (focus && focus->view && focus->view->pid != xsurface->pid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
seat_set_focus_surface(seat, xsurface->surface, false);
|
||||||
|
}
|
||||||
|
|
||||||
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
|
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
struct sway_xwayland_unmanaged *surface =
|
struct sway_xwayland_unmanaged *surface =
|
||||||
wl_container_of(listener, surface, destroy);
|
wl_container_of(listener, surface, destroy);
|
||||||
|
@ -129,6 +146,7 @@ static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_list_remove(&surface->unmap.link);
|
wl_list_remove(&surface->unmap.link);
|
||||||
wl_list_remove(&surface->destroy.link);
|
wl_list_remove(&surface->destroy.link);
|
||||||
wl_list_remove(&surface->override_redirect.link);
|
wl_list_remove(&surface->override_redirect.link);
|
||||||
|
wl_list_remove(&surface->request_activate.link);
|
||||||
free(surface);
|
free(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +194,8 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
|
||||||
surface->destroy.notify = unmanaged_handle_destroy;
|
surface->destroy.notify = unmanaged_handle_destroy;
|
||||||
wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect);
|
wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect);
|
||||||
surface->override_redirect.notify = unmanaged_handle_override_redirect;
|
surface->override_redirect.notify = unmanaged_handle_override_redirect;
|
||||||
|
wl_signal_add(&xsurface->events.request_activate, &surface->request_activate);
|
||||||
|
surface->request_activate.notify = unmanaged_handle_request_activate;
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +314,7 @@ static bool wants_floating(struct sway_view *view) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
|
xcb_size_hints_t *size_hints = surface->size_hints;
|
||||||
if (size_hints != NULL &&
|
if (size_hints != NULL &&
|
||||||
size_hints->min_width > 0 && size_hints->min_height > 0 &&
|
size_hints->min_width > 0 && size_hints->min_height > 0 &&
|
||||||
(size_hints->max_width == size_hints->min_width ||
|
(size_hints->max_width == size_hints->min_width ||
|
||||||
|
@ -348,7 +368,7 @@ static void destroy(struct sway_view *view) {
|
||||||
static void get_constraints(struct sway_view *view, double *min_width,
|
static void get_constraints(struct sway_view *view, double *min_width,
|
||||||
double *max_width, double *min_height, double *max_height) {
|
double *max_width, double *min_height, double *max_height) {
|
||||||
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
|
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
|
||||||
struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
|
xcb_size_hints_t *size_hints = surface->size_hints;
|
||||||
|
|
||||||
if (size_hints == NULL) {
|
if (size_hints == NULL) {
|
||||||
*min_width = DBL_MIN;
|
*min_width = DBL_MIN;
|
||||||
|
@ -448,6 +468,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_list_remove(&xwayland_view->set_title.link);
|
wl_list_remove(&xwayland_view->set_title.link);
|
||||||
wl_list_remove(&xwayland_view->set_class.link);
|
wl_list_remove(&xwayland_view->set_class.link);
|
||||||
wl_list_remove(&xwayland_view->set_role.link);
|
wl_list_remove(&xwayland_view->set_role.link);
|
||||||
|
wl_list_remove(&xwayland_view->set_startup_id.link);
|
||||||
wl_list_remove(&xwayland_view->set_window_type.link);
|
wl_list_remove(&xwayland_view->set_window_type.link);
|
||||||
wl_list_remove(&xwayland_view->set_hints.link);
|
wl_list_remove(&xwayland_view->set_hints.link);
|
||||||
wl_list_remove(&xwayland_view->set_decorations.link);
|
wl_list_remove(&xwayland_view->set_decorations.link);
|
||||||
|
@ -577,7 +598,8 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
|
||||||
if (!xsurface->mapped) {
|
if (!xsurface->mapped) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!container_is_floating(view->container)) {
|
if (!container_is_floating(view->container) ||
|
||||||
|
view->container->pending.fullscreen_mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct sway_seat *seat = input_manager_current_seat();
|
struct sway_seat *seat = input_manager_current_seat();
|
||||||
|
@ -647,6 +669,31 @@ static void handle_set_role(struct wl_listener *listener, void *data) {
|
||||||
view_execute_criteria(view);
|
view_execute_criteria(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_set_startup_id(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_xwayland_view *xwayland_view =
|
||||||
|
wl_container_of(listener, xwayland_view, set_startup_id);
|
||||||
|
struct sway_view *view = &xwayland_view->view;
|
||||||
|
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
|
||||||
|
if (xsurface->startup_id == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_xdg_activation_token_v1 *token =
|
||||||
|
wlr_xdg_activation_v1_find_token(
|
||||||
|
server.xdg_activation_v1, xsurface->startup_id);
|
||||||
|
if (token == NULL) {
|
||||||
|
// Tried to activate with an unknown or expired token
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct launcher_ctx *ctx = token->data;
|
||||||
|
if (token->data == NULL) {
|
||||||
|
// TODO: support external launchers in X
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
view_assign_ctx(view, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_set_window_type(struct wl_listener *listener, void *data) {
|
static void handle_set_window_type(struct wl_listener *listener, void *data) {
|
||||||
struct sway_xwayland_view *xwayland_view =
|
struct sway_xwayland_view *xwayland_view =
|
||||||
wl_container_of(listener, xwayland_view, set_window_type);
|
wl_container_of(listener, xwayland_view, set_window_type);
|
||||||
|
@ -666,14 +713,15 @@ static void handle_set_hints(struct wl_listener *listener, void *data) {
|
||||||
if (!xsurface->mapped) {
|
if (!xsurface->mapped) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!xsurface->hints_urgency && view->urgent_timer) {
|
const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints);
|
||||||
|
if (!hints_urgency && view->urgent_timer) {
|
||||||
// The view is in the timeout period. We'll ignore the request to
|
// The view is in the timeout period. We'll ignore the request to
|
||||||
// unset urgency so that the view remains urgent until the timer clears
|
// unset urgency so that the view remains urgent until the timer clears
|
||||||
// it.
|
// it.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (view->allow_request_urgent) {
|
if (view->allow_request_urgent) {
|
||||||
view_set_urgent(view, (bool)xsurface->hints_urgency);
|
view_set_urgent(view, hints_urgency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,6 +779,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu
|
||||||
wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role);
|
wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role);
|
||||||
xwayland_view->set_role.notify = handle_set_role;
|
xwayland_view->set_role.notify = handle_set_role;
|
||||||
|
|
||||||
|
wl_signal_add(&xsurface->events.set_startup_id,
|
||||||
|
&xwayland_view->set_startup_id);
|
||||||
|
xwayland_view->set_startup_id.notify = handle_set_startup_id;
|
||||||
|
|
||||||
wl_signal_add(&xsurface->events.set_window_type,
|
wl_signal_add(&xsurface->events.set_window_type,
|
||||||
&xwayland_view->set_window_type);
|
&xwayland_view->set_window_type);
|
||||||
xwayland_view->set_window_type.notify = handle_set_window_type;
|
xwayland_view->set_window_type.notify = handle_set_window_type;
|
||||||
|
|
|
@ -386,28 +386,29 @@ static void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
|
||||||
static void handle_pointer_motion_relative(
|
static void handle_pointer_motion_relative(
|
||||||
struct wl_listener *listener, void *data) {
|
struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
|
||||||
struct wlr_event_pointer_motion *e = data;
|
struct wlr_pointer_motion_event *e = data;
|
||||||
cursor_handle_activity_from_device(cursor, e->device);
|
cursor_handle_activity_from_device(cursor, &e->pointer->base);
|
||||||
|
|
||||||
pointer_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y,
|
pointer_motion(cursor, e->time_msec, &e->pointer->base, e->delta_x,
|
||||||
e->unaccel_dx, e->unaccel_dy);
|
e->delta_y, e->unaccel_dx, e->unaccel_dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_motion_absolute(
|
static void handle_pointer_motion_absolute(
|
||||||
struct wl_listener *listener, void *data) {
|
struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor =
|
struct sway_cursor *cursor =
|
||||||
wl_container_of(listener, cursor, motion_absolute);
|
wl_container_of(listener, cursor, motion_absolute);
|
||||||
struct wlr_event_pointer_motion_absolute *event = data;
|
struct wlr_pointer_motion_absolute_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
|
|
||||||
double lx, ly;
|
double lx, ly;
|
||||||
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
|
wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->pointer->base,
|
||||||
event->x, event->y, &lx, &ly);
|
event->x, event->y, &lx, &ly);
|
||||||
|
|
||||||
double dx = lx - cursor->cursor->x;
|
double dx = lx - cursor->cursor->x;
|
||||||
double dy = ly - cursor->cursor->y;
|
double dy = ly - cursor->cursor->y;
|
||||||
|
|
||||||
pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
|
pointer_motion(cursor, event->time_msec, &event->pointer->base, dx, dy,
|
||||||
|
dx, dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatch_cursor_button(struct sway_cursor *cursor,
|
void dispatch_cursor_button(struct sway_cursor *cursor,
|
||||||
|
@ -422,7 +423,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
|
||||||
|
|
||||||
static void handle_pointer_button(struct wl_listener *listener, void *data) {
|
static void handle_pointer_button(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
|
||||||
struct wlr_event_pointer_button *event = data;
|
struct wlr_pointer_button_event *event = data;
|
||||||
|
|
||||||
if (event->state == WLR_BUTTON_PRESSED) {
|
if (event->state == WLR_BUTTON_PRESSED) {
|
||||||
cursor->pressed_button_count++;
|
cursor->pressed_button_count++;
|
||||||
|
@ -434,20 +435,20 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
dispatch_cursor_button(cursor, event->device,
|
dispatch_cursor_button(cursor, &event->pointer->base,
|
||||||
event->time_msec, event->button, event->state);
|
event->time_msec, event->button, event->state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatch_cursor_axis(struct sway_cursor *cursor,
|
void dispatch_cursor_axis(struct sway_cursor *cursor,
|
||||||
struct wlr_event_pointer_axis *event) {
|
struct wlr_pointer_axis_event *event) {
|
||||||
seatop_pointer_axis(cursor->seat, event);
|
seatop_pointer_axis(cursor->seat, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_axis(struct wl_listener *listener, void *data) {
|
static void handle_pointer_axis(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);
|
||||||
struct wlr_event_pointer_axis *event = data;
|
struct wlr_pointer_axis_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
dispatch_cursor_axis(cursor, event);
|
dispatch_cursor_axis(cursor, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,8 +459,8 @@ static void handle_pointer_frame(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
static void handle_touch_down(struct wl_listener *listener, void *data) {
|
static void handle_touch_down(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down);
|
||||||
struct wlr_event_touch_down *event = data;
|
struct wlr_touch_down_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->touch->base);
|
||||||
cursor_hide(cursor);
|
cursor_hide(cursor);
|
||||||
|
|
||||||
struct sway_seat *seat = cursor->seat;
|
struct sway_seat *seat = cursor->seat;
|
||||||
|
@ -467,7 +468,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
|
|
||||||
double lx, ly;
|
double lx, ly;
|
||||||
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
|
wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
|
||||||
event->x, event->y, &lx, &ly);
|
event->x, event->y, &lx, &ly);
|
||||||
double sx, sy;
|
double sx, sy;
|
||||||
struct sway_node *focused_node = node_at_coords(seat, lx, ly, &surface, &sx, &sy);
|
struct sway_node *focused_node = node_at_coords(seat, lx, ly, &surface, &sx, &sy);
|
||||||
|
@ -495,24 +496,25 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
dx = lx - cursor->cursor->x;
|
dx = lx - cursor->cursor->x;
|
||||||
dy = ly - cursor->cursor->y;
|
dy = ly - cursor->cursor->y;
|
||||||
pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
|
pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy,
|
||||||
dispatch_cursor_button(cursor, event->device, event->time_msec,
|
dx, dy);
|
||||||
|
dispatch_cursor_button(cursor, &event->touch->base, event->time_msec,
|
||||||
BTN_LEFT, WLR_BUTTON_PRESSED);
|
BTN_LEFT, WLR_BUTTON_PRESSED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_touch_up(struct wl_listener *listener, void *data) {
|
static void handle_touch_up(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up);
|
||||||
struct wlr_event_touch_up *event = data;
|
struct wlr_touch_up_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->touch->base);
|
||||||
|
|
||||||
struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
|
struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
|
||||||
|
|
||||||
if (cursor->simulating_pointer_from_touch) {
|
if (cursor->simulating_pointer_from_touch) {
|
||||||
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
|
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
|
||||||
cursor->pointer_touch_up = true;
|
cursor->pointer_touch_up = true;
|
||||||
dispatch_cursor_button(cursor, event->device, event->time_msec,
|
dispatch_cursor_button(cursor, &event->touch->base,
|
||||||
BTN_LEFT, WLR_BUTTON_RELEASED);
|
event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id);
|
wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id);
|
||||||
|
@ -522,15 +524,15 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
|
||||||
static void handle_touch_motion(struct wl_listener *listener, void *data) {
|
static void handle_touch_motion(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor =
|
struct sway_cursor *cursor =
|
||||||
wl_container_of(listener, cursor, touch_motion);
|
wl_container_of(listener, cursor, touch_motion);
|
||||||
struct wlr_event_touch_motion *event = data;
|
struct wlr_touch_motion_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->touch->base);
|
||||||
|
|
||||||
struct sway_seat *seat = cursor->seat;
|
struct sway_seat *seat = cursor->seat;
|
||||||
struct wlr_seat *wlr_seat = seat->wlr_seat;
|
struct wlr_seat *wlr_seat = seat->wlr_seat;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
|
|
||||||
double lx, ly;
|
double lx, ly;
|
||||||
wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
|
wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
|
||||||
event->x, event->y, &lx, &ly);
|
event->x, event->y, &lx, &ly);
|
||||||
double sx, sy;
|
double sx, sy;
|
||||||
node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
|
node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
|
||||||
|
@ -552,7 +554,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
|
||||||
double dx, dy;
|
double dx, dy;
|
||||||
dx = lx - cursor->cursor->x;
|
dx = lx - cursor->cursor->x;
|
||||||
dy = ly - cursor->cursor->y;
|
dy = ly - cursor->cursor->y;
|
||||||
pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
|
pointer_motion(cursor, event->time_msec, &event->touch->base,
|
||||||
|
dx, dy, dx, dy);
|
||||||
}
|
}
|
||||||
} else if (surface) {
|
} else if (surface) {
|
||||||
wlr_seat_touch_notify_motion(wlr_seat, event->time_msec,
|
wlr_seat_touch_notify_motion(wlr_seat, event->time_msec,
|
||||||
|
@ -591,14 +594,15 @@ static void apply_mapping_from_region(struct wlr_input_device *device,
|
||||||
double x1 = region->x1, x2 = region->x2;
|
double x1 = region->x1, x2 = region->x2;
|
||||||
double y1 = region->y1, y2 = region->y2;
|
double y1 = region->y1, y2 = region->y2;
|
||||||
|
|
||||||
if (region->mm) {
|
if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
|
||||||
if (device->width_mm == 0 || device->height_mm == 0) {
|
struct wlr_tablet *tablet = wlr_tablet_from_input_device(device);
|
||||||
|
if (tablet->width_mm == 0 || tablet->height_mm == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
x1 /= device->width_mm;
|
x1 /= tablet->width_mm;
|
||||||
x2 /= device->width_mm;
|
x2 /= tablet->width_mm;
|
||||||
y1 /= device->height_mm;
|
y1 /= tablet->height_mm;
|
||||||
y2 /= device->height_mm;
|
y2 /= tablet->height_mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
*x = apply_mapping_from_coord(x1, x2, *x);
|
*x = apply_mapping_from_coord(x1, x2, *x);
|
||||||
|
@ -660,8 +664,8 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor,
|
||||||
|
|
||||||
static void handle_tool_axis(struct wl_listener *listener, void *data) {
|
static void handle_tool_axis(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);
|
||||||
struct wlr_event_tablet_tool_axis *event = data;
|
struct wlr_tablet_tool_axis_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->tablet->base);
|
||||||
|
|
||||||
struct sway_tablet_tool *sway_tool = event->tool->data;
|
struct sway_tablet_tool *sway_tool = event->tool->data;
|
||||||
if (!sway_tool) {
|
if (!sway_tool) {
|
||||||
|
@ -716,8 +720,8 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
static void handle_tool_tip(struct wl_listener *listener, void *data) {
|
static void handle_tool_tip(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip);
|
||||||
struct wlr_event_tablet_tool_tip *event = data;
|
struct wlr_tablet_tool_tip_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->tablet->base);
|
||||||
|
|
||||||
struct sway_tablet_tool *sway_tool = event->tool->data;
|
struct sway_tablet_tool *sway_tool = event->tool->data;
|
||||||
struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2;
|
struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2;
|
||||||
|
@ -732,7 +736,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
|
||||||
if (cursor->simulating_pointer_from_tool_tip &&
|
if (cursor->simulating_pointer_from_tool_tip &&
|
||||||
event->state == WLR_TABLET_TOOL_TIP_UP) {
|
event->state == WLR_TABLET_TOOL_TIP_UP) {
|
||||||
cursor->simulating_pointer_from_tool_tip = false;
|
cursor->simulating_pointer_from_tool_tip = false;
|
||||||
dispatch_cursor_button(cursor, event->device, event->time_msec,
|
dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec,
|
||||||
BTN_LEFT, WLR_BUTTON_RELEASED);
|
BTN_LEFT, WLR_BUTTON_RELEASED);
|
||||||
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
|
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(tablet_v2, surface)) {
|
||||||
|
@ -744,8 +748,8 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
|
||||||
WLR_TABLET_TOOL_TIP_UP);
|
WLR_TABLET_TOOL_TIP_UP);
|
||||||
} else {
|
} else {
|
||||||
cursor->simulating_pointer_from_tool_tip = true;
|
cursor->simulating_pointer_from_tool_tip = true;
|
||||||
dispatch_cursor_button(cursor, event->device, event->time_msec,
|
dispatch_cursor_button(cursor, &event->tablet->base,
|
||||||
BTN_LEFT, WLR_BUTTON_PRESSED);
|
event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED);
|
||||||
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
|
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -767,12 +771,13 @@ static struct sway_tablet *get_tablet_for_device(struct sway_cursor *cursor,
|
||||||
static void handle_tool_proximity(struct wl_listener *listener, void *data) {
|
static void handle_tool_proximity(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor =
|
struct sway_cursor *cursor =
|
||||||
wl_container_of(listener, cursor, tool_proximity);
|
wl_container_of(listener, cursor, tool_proximity);
|
||||||
struct wlr_event_tablet_tool_proximity *event = data;
|
struct wlr_tablet_tool_proximity_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->tablet->base);
|
||||||
|
|
||||||
struct wlr_tablet_tool *tool = event->tool;
|
struct wlr_tablet_tool *tool = event->tool;
|
||||||
if (!tool->data) {
|
if (!tool->data) {
|
||||||
struct sway_tablet *tablet = get_tablet_for_device(cursor, event->device);
|
struct sway_tablet *tablet = get_tablet_for_device(cursor,
|
||||||
|
&event->tablet->base);
|
||||||
if (!tablet) {
|
if (!tablet) {
|
||||||
sway_log(SWAY_ERROR, "no tablet for tablet tool");
|
sway_log(SWAY_ERROR, "no tablet for tablet tool");
|
||||||
return;
|
return;
|
||||||
|
@ -797,8 +802,8 @@ static void handle_tool_proximity(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
static void handle_tool_button(struct wl_listener *listener, void *data) {
|
static void handle_tool_button(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button);
|
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button);
|
||||||
struct wlr_event_tablet_tool_button *event = data;
|
struct wlr_tablet_tool_button_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->tablet->base);
|
||||||
|
|
||||||
struct sway_tablet_tool *sway_tool = event->tool->data;
|
struct sway_tablet_tool *sway_tool = event->tool->data;
|
||||||
if (!sway_tool) {
|
if (!sway_tool) {
|
||||||
|
@ -819,14 +824,14 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
|
||||||
switch (event->state) {
|
switch (event->state) {
|
||||||
case WLR_BUTTON_PRESSED:
|
case WLR_BUTTON_PRESSED:
|
||||||
if (cursor->tool_buttons == 0) {
|
if (cursor->tool_buttons == 0) {
|
||||||
dispatch_cursor_button(cursor, event->device,
|
dispatch_cursor_button(cursor, &event->tablet->base,
|
||||||
event->time_msec, BTN_RIGHT, event->state);
|
event->time_msec, BTN_RIGHT, event->state);
|
||||||
}
|
}
|
||||||
cursor->tool_buttons++;
|
cursor->tool_buttons++;
|
||||||
break;
|
break;
|
||||||
case WLR_BUTTON_RELEASED:
|
case WLR_BUTTON_RELEASED:
|
||||||
if (cursor->tool_buttons == 1) {
|
if (cursor->tool_buttons == 1) {
|
||||||
dispatch_cursor_button(cursor, event->device,
|
dispatch_cursor_button(cursor, &event->tablet->base,
|
||||||
event->time_msec, BTN_RIGHT, event->state);
|
event->time_msec, BTN_RIGHT, event->state);
|
||||||
}
|
}
|
||||||
cursor->tool_buttons--;
|
cursor->tool_buttons--;
|
||||||
|
@ -923,65 +928,68 @@ static void handle_request_pointer_set_cursor(struct wl_listener *listener,
|
||||||
event->hotspot_y, focused_client);
|
event->hotspot_y, focused_client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_pointer_hold_begin(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
|
listener, cursor, hold_begin);
|
||||||
|
struct wlr_pointer_hold_begin_event *event = data;
|
||||||
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
|
seatop_hold_begin(cursor->seat, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pointer_hold_end(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
|
listener, cursor, hold_end);
|
||||||
|
struct wlr_pointer_hold_end_event *event = data;
|
||||||
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
|
seatop_hold_end(cursor->seat, event);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) {
|
static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
listener, cursor, pinch_begin);
|
listener, cursor, pinch_begin);
|
||||||
struct wlr_event_pointer_pinch_begin *event = data;
|
struct wlr_pointer_pinch_begin_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
wlr_pointer_gestures_v1_send_pinch_begin(
|
seatop_pinch_begin(cursor->seat, event);
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
|
||||||
event->time_msec, event->fingers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) {
|
static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
listener, cursor, pinch_update);
|
listener, cursor, pinch_update);
|
||||||
struct wlr_event_pointer_pinch_update *event = data;
|
struct wlr_pointer_pinch_update_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
wlr_pointer_gestures_v1_send_pinch_update(
|
seatop_pinch_update(cursor->seat, event);
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
|
||||||
event->time_msec, event->dx, event->dy,
|
|
||||||
event->scale, event->rotation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) {
|
static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
listener, cursor, pinch_end);
|
listener, cursor, pinch_end);
|
||||||
struct wlr_event_pointer_pinch_end *event = data;
|
struct wlr_pointer_pinch_end_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
wlr_pointer_gestures_v1_send_pinch_end(
|
seatop_pinch_end(cursor->seat, event);
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
|
||||||
event->time_msec, event->cancelled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) {
|
static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
listener, cursor, swipe_begin);
|
listener, cursor, swipe_begin);
|
||||||
struct wlr_event_pointer_swipe_begin *event = data;
|
struct wlr_pointer_swipe_begin_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
wlr_pointer_gestures_v1_send_swipe_begin(
|
seatop_swipe_begin(cursor->seat, event);
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
|
||||||
event->time_msec, event->fingers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) {
|
static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
listener, cursor, swipe_update);
|
listener, cursor, swipe_update);
|
||||||
struct wlr_event_pointer_swipe_update *event = data;
|
struct wlr_pointer_swipe_update_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
wlr_pointer_gestures_v1_send_swipe_update(
|
seatop_swipe_update(cursor->seat, event);
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
|
||||||
event->time_msec, event->dx, event->dy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) {
|
static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) {
|
||||||
struct sway_cursor *cursor = wl_container_of(
|
struct sway_cursor *cursor = wl_container_of(
|
||||||
listener, cursor, swipe_end);
|
listener, cursor, swipe_end);
|
||||||
struct wlr_event_pointer_swipe_end *event = data;
|
struct wlr_pointer_swipe_end_event *event = data;
|
||||||
cursor_handle_activity_from_device(cursor, event->device);
|
cursor_handle_activity_from_device(cursor, &event->pointer->base);
|
||||||
wlr_pointer_gestures_v1_send_swipe_end(
|
seatop_swipe_end(cursor->seat, event);
|
||||||
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
|
||||||
event->time_msec, event->cancelled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_image_surface_destroy(struct wl_listener *listener,
|
static void handle_image_surface_destroy(struct wl_listener *listener,
|
||||||
|
@ -1055,6 +1063,8 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
|
||||||
wl_event_source_remove(cursor->hide_source);
|
wl_event_source_remove(cursor->hide_source);
|
||||||
|
|
||||||
wl_list_remove(&cursor->image_surface_destroy.link);
|
wl_list_remove(&cursor->image_surface_destroy.link);
|
||||||
|
wl_list_remove(&cursor->hold_begin.link);
|
||||||
|
wl_list_remove(&cursor->hold_end.link);
|
||||||
wl_list_remove(&cursor->pinch_begin.link);
|
wl_list_remove(&cursor->pinch_begin.link);
|
||||||
wl_list_remove(&cursor->pinch_update.link);
|
wl_list_remove(&cursor->pinch_update.link);
|
||||||
wl_list_remove(&cursor->pinch_end.link);
|
wl_list_remove(&cursor->pinch_end.link);
|
||||||
|
@ -1104,19 +1114,27 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
|
||||||
wl_list_init(&cursor->image_surface_destroy.link);
|
wl_list_init(&cursor->image_surface_destroy.link);
|
||||||
cursor->image_surface_destroy.notify = handle_image_surface_destroy;
|
cursor->image_surface_destroy.notify = handle_image_surface_destroy;
|
||||||
|
|
||||||
|
// gesture events
|
||||||
cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display);
|
cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display);
|
||||||
cursor->pinch_begin.notify = handle_pointer_pinch_begin;
|
|
||||||
|
wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin);
|
||||||
|
cursor->hold_begin.notify = handle_pointer_hold_begin;
|
||||||
|
wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end);
|
||||||
|
cursor->hold_end.notify = handle_pointer_hold_end;
|
||||||
|
|
||||||
wl_signal_add(&wlr_cursor->events.pinch_begin, &cursor->pinch_begin);
|
wl_signal_add(&wlr_cursor->events.pinch_begin, &cursor->pinch_begin);
|
||||||
cursor->pinch_update.notify = handle_pointer_pinch_update;
|
cursor->pinch_begin.notify = handle_pointer_pinch_begin;
|
||||||
wl_signal_add(&wlr_cursor->events.pinch_update, &cursor->pinch_update);
|
wl_signal_add(&wlr_cursor->events.pinch_update, &cursor->pinch_update);
|
||||||
cursor->pinch_end.notify = handle_pointer_pinch_end;
|
cursor->pinch_update.notify = handle_pointer_pinch_update;
|
||||||
wl_signal_add(&wlr_cursor->events.pinch_end, &cursor->pinch_end);
|
wl_signal_add(&wlr_cursor->events.pinch_end, &cursor->pinch_end);
|
||||||
cursor->swipe_begin.notify = handle_pointer_swipe_begin;
|
cursor->pinch_end.notify = handle_pointer_pinch_end;
|
||||||
|
|
||||||
wl_signal_add(&wlr_cursor->events.swipe_begin, &cursor->swipe_begin);
|
wl_signal_add(&wlr_cursor->events.swipe_begin, &cursor->swipe_begin);
|
||||||
cursor->swipe_update.notify = handle_pointer_swipe_update;
|
cursor->swipe_begin.notify = handle_pointer_swipe_begin;
|
||||||
wl_signal_add(&wlr_cursor->events.swipe_update, &cursor->swipe_update);
|
wl_signal_add(&wlr_cursor->events.swipe_update, &cursor->swipe_update);
|
||||||
cursor->swipe_end.notify = handle_pointer_swipe_end;
|
cursor->swipe_update.notify = handle_pointer_swipe_update;
|
||||||
wl_signal_add(&wlr_cursor->events.swipe_end, &cursor->swipe_end);
|
wl_signal_add(&wlr_cursor->events.swipe_end, &cursor->swipe_end);
|
||||||
|
cursor->swipe_end.notify = handle_pointer_swipe_end;
|
||||||
|
|
||||||
// input events
|
// input events
|
||||||
wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
|
wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
|
||||||
|
@ -1354,12 +1372,9 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) {
|
||||||
sway_constraint->destroy.notify = handle_constraint_destroy;
|
sway_constraint->destroy.notify = handle_constraint_destroy;
|
||||||
wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy);
|
wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy);
|
||||||
|
|
||||||
struct sway_node *focus = seat_get_focus(seat);
|
struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface;
|
||||||
if (focus && node_is_view(focus)) {
|
if (surface && surface == constraint->surface) {
|
||||||
struct wlr_surface *surface = focus->sway_container->view->surface;
|
sway_cursor_constrain(seat->cursor, constraint);
|
||||||
if (surface == constraint->surface) {
|
|
||||||
sway_cursor_constrain(seat->cursor, constraint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
apply_input_type_config(input_device);
|
apply_input_type_config(input_device);
|
||||||
|
|
||||||
sway_input_configure_libinput_device(input_device);
|
bool config_changed = sway_input_configure_libinput_device(input_device);
|
||||||
|
|
||||||
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
|
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
|
||||||
input_device->device_destroy.notify = handle_device_destroy;
|
input_device->device_destroy.notify = handle_device_destroy;
|
||||||
|
@ -274,6 +274,10 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ipc_event_input("added", input_device);
|
ipc_event_input("added", input_device);
|
||||||
|
|
||||||
|
if (config_changed) {
|
||||||
|
ipc_event_input("libinput_config", input_device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_inhibit_activate(struct wl_listener *listener, void *data) {
|
static void handle_inhibit_activate(struct wl_listener *listener, void *data) {
|
||||||
|
@ -289,6 +293,10 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
|
||||||
struct sway_input_manager *input_manager = wl_container_of(
|
struct sway_input_manager *input_manager = wl_container_of(
|
||||||
listener, input_manager, inhibit_deactivate);
|
listener, input_manager, inhibit_deactivate);
|
||||||
struct sway_seat *seat;
|
struct sway_seat *seat;
|
||||||
|
if (server.session_lock.locked) {
|
||||||
|
// Don't deactivate the grab of a screenlocker
|
||||||
|
return;
|
||||||
|
}
|
||||||
wl_list_for_each(seat, &input_manager->seats, link) {
|
wl_list_for_each(seat, &input_manager->seats, link) {
|
||||||
seat_set_exclusive_client(seat, NULL);
|
seat_set_exclusive_client(seat, NULL);
|
||||||
struct sway_node *previous = seat_get_focus(seat);
|
struct sway_node *previous = seat_get_focus(seat);
|
||||||
|
@ -377,7 +385,7 @@ void handle_virtual_keyboard(struct wl_listener *listener, void *data) {
|
||||||
struct sway_input_manager *input_manager =
|
struct sway_input_manager *input_manager =
|
||||||
wl_container_of(listener, input_manager, virtual_keyboard_new);
|
wl_container_of(listener, input_manager, virtual_keyboard_new);
|
||||||
struct wlr_virtual_keyboard_v1 *keyboard = data;
|
struct wlr_virtual_keyboard_v1 *keyboard = data;
|
||||||
struct wlr_input_device *device = &keyboard->input_device;
|
struct wlr_input_device *device = &keyboard->keyboard.base;
|
||||||
|
|
||||||
// TODO: Amend protocol to allow NULL seat
|
// TODO: Amend protocol to allow NULL seat
|
||||||
struct sway_seat *seat = keyboard->seat ?
|
struct sway_seat *seat = keyboard->seat ?
|
||||||
|
@ -410,7 +418,7 @@ void handle_virtual_pointer(struct wl_listener *listener, void *data) {
|
||||||
wl_container_of(listener, input_manager, virtual_pointer_new);
|
wl_container_of(listener, input_manager, virtual_pointer_new);
|
||||||
struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
|
struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
|
||||||
struct wlr_virtual_pointer_v1 *pointer = event->new_pointer;
|
struct wlr_virtual_pointer_v1 *pointer = event->new_pointer;
|
||||||
struct wlr_input_device *device = &pointer->input_device;
|
struct wlr_input_device *device = &pointer->pointer.base;
|
||||||
|
|
||||||
struct sway_seat *seat = event->suggested_seat ?
|
struct sway_seat *seat = event->suggested_seat ?
|
||||||
input_manager_sway_seat_from_wlr_seat(event->suggested_seat) :
|
input_manager_sway_seat_from_wlr_seat(event->suggested_seat) :
|
||||||
|
@ -524,11 +532,14 @@ static void retranslate_keysyms(struct input_config *input_config) {
|
||||||
|
|
||||||
static void input_manager_configure_input(
|
static void input_manager_configure_input(
|
||||||
struct sway_input_device *input_device) {
|
struct sway_input_device *input_device) {
|
||||||
sway_input_configure_libinput_device(input_device);
|
bool config_changed = sway_input_configure_libinput_device(input_device);
|
||||||
struct sway_seat *seat = NULL;
|
struct sway_seat *seat = NULL;
|
||||||
wl_list_for_each(seat, &server.input->seats, link) {
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
seat_configure_device(seat, input_device);
|
seat_configure_device(seat, input_device);
|
||||||
}
|
}
|
||||||
|
if (config_changed) {
|
||||||
|
ipc_event_input("libinput_config", input_device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_manager_configure_all_inputs(void) {
|
void input_manager_configure_all_inputs(void) {
|
||||||
|
@ -564,6 +575,13 @@ void input_manager_reset_input(struct sway_input_device *input_device) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_manager_reset_all_inputs(void) {
|
void input_manager_reset_all_inputs(void) {
|
||||||
|
// Set the active keyboard to NULL to avoid spamming configuration updates
|
||||||
|
// for all keyboard devices.
|
||||||
|
struct sway_seat *seat;
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
wlr_seat_set_keyboard(seat->wlr_seat, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
struct sway_input_device *input_device = NULL;
|
struct sway_input_device *input_device = NULL;
|
||||||
wl_list_for_each(input_device, &server.input->devices, link) {
|
wl_list_for_each(input_device, &server.input->devices, link) {
|
||||||
input_manager_reset_input(input_device);
|
input_manager_reset_input(input_device);
|
||||||
|
@ -572,7 +590,6 @@ void input_manager_reset_all_inputs(void) {
|
||||||
// If there is at least one keyboard using the default keymap, repeat delay,
|
// If there is at least one keyboard using the default keymap, repeat delay,
|
||||||
// and repeat rate, then it is possible that there is a keyboard group that
|
// and repeat rate, then it is possible that there is a keyboard group that
|
||||||
// need their keyboard disarmed.
|
// need their keyboard disarmed.
|
||||||
struct sway_seat *seat;
|
|
||||||
wl_list_for_each(seat, &server.input->seats, link) {
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
struct sway_keyboard_group *group;
|
struct sway_keyboard_group *group;
|
||||||
wl_list_for_each(group, &seat->keyboard_groups, link) {
|
wl_list_for_each(group, &seat->keyboard_groups, link) {
|
||||||
|
|
|
@ -291,14 +291,12 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
|
||||||
static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
|
static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
|
||||||
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
|
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
|
||||||
uint32_t *modifiers) {
|
uint32_t *modifiers) {
|
||||||
struct wlr_input_device *device =
|
*modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
|
||||||
keyboard->seat_device->input_device->wlr_device;
|
|
||||||
*modifiers = wlr_keyboard_get_modifiers(device->keyboard);
|
|
||||||
xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
|
xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
|
||||||
device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB);
|
keyboard->wlr->xkb_state, keycode, XKB_CONSUMED_MODE_XKB);
|
||||||
*modifiers = *modifiers & ~consumed;
|
*modifiers = *modifiers & ~consumed;
|
||||||
|
|
||||||
return xkb_state_key_get_syms(device->keyboard->xkb_state,
|
return xkb_state_key_get_syms(keyboard->wlr->xkb_state,
|
||||||
keycode, keysyms);
|
keycode, keysyms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,13 +312,11 @@ static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
|
||||||
static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
|
static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
|
||||||
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
|
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
|
||||||
uint32_t *modifiers) {
|
uint32_t *modifiers) {
|
||||||
struct wlr_input_device *device =
|
*modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
|
||||||
keyboard->seat_device->input_device->wlr_device;
|
|
||||||
*modifiers = wlr_keyboard_get_modifiers(device->keyboard);
|
|
||||||
|
|
||||||
xkb_layout_index_t layout_index = xkb_state_key_get_layout(
|
xkb_layout_index_t layout_index = xkb_state_key_get_layout(
|
||||||
device->keyboard->xkb_state, keycode);
|
keyboard->wlr->xkb_state, keycode);
|
||||||
return xkb_keymap_key_get_syms_by_level(device->keyboard->keymap,
|
return xkb_keymap_key_get_syms_by_level(keyboard->wlr->keymap,
|
||||||
keycode, layout_index, 0, keysyms);
|
keycode, layout_index, 0, keysyms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,8 +356,7 @@ static void update_keyboard_state(struct sway_keyboard *keyboard,
|
||||||
keyinfo->keycode, &keyinfo->translated_keysyms,
|
keyinfo->keycode, &keyinfo->translated_keysyms,
|
||||||
&keyinfo->translated_modifiers);
|
&keyinfo->translated_modifiers);
|
||||||
|
|
||||||
keyinfo->code_modifiers = wlr_keyboard_get_modifiers(
|
keyinfo->code_modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
|
||||||
keyboard->seat_device->input_device->wlr_device->keyboard);
|
|
||||||
|
|
||||||
// Update shortcut model keyinfo
|
// Update shortcut model keyinfo
|
||||||
update_shortcut_state(&keyboard->state_keycodes, raw_keycode, keystate,
|
update_shortcut_state(&keyboard->state_keycodes, raw_keycode, keystate,
|
||||||
|
@ -401,15 +396,16 @@ static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_key_event(struct sway_keyboard *keyboard,
|
static void handle_key_event(struct sway_keyboard *keyboard,
|
||||||
struct wlr_event_keyboard_key *event) {
|
struct wlr_keyboard_key_event *event) {
|
||||||
struct sway_seat *seat = keyboard->seat_device->sway_seat;
|
struct sway_seat *seat = keyboard->seat_device->sway_seat;
|
||||||
struct wlr_seat *wlr_seat = seat->wlr_seat;
|
struct wlr_seat *wlr_seat = seat->wlr_seat;
|
||||||
struct wlr_input_device *wlr_device =
|
struct wlr_input_device *wlr_device =
|
||||||
keyboard->seat_device->input_device->wlr_device;
|
keyboard->seat_device->input_device->wlr_device;
|
||||||
char *device_identifier = input_device_get_identifier(wlr_device);
|
char *device_identifier = input_device_get_identifier(wlr_device);
|
||||||
bool exact_identifier = wlr_device->keyboard->group != NULL;
|
bool exact_identifier = keyboard->wlr->group != NULL;
|
||||||
seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
|
seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
|
||||||
bool input_inhibited = seat->exclusive_client != NULL;
|
bool input_inhibited = seat->exclusive_client != NULL ||
|
||||||
|
server.session_lock.locked;
|
||||||
struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
|
struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
|
||||||
keyboard_shortcuts_inhibitor_get_for_focused_surface(seat);
|
keyboard_shortcuts_inhibitor_get_for_focused_surface(seat);
|
||||||
bool shortcuts_inhibited = sway_inhibitor && sway_inhibitor->inhibitor->active;
|
bool shortcuts_inhibited = sway_inhibitor && sway_inhibitor->inhibitor->active;
|
||||||
|
@ -477,10 +473,10 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
||||||
// Set up (or clear) keyboard repeat for a pressed binding. Since the
|
// Set up (or clear) keyboard repeat for a pressed binding. Since the
|
||||||
// binding may remove the keyboard, the timer needs to be updated first
|
// binding may remove the keyboard, the timer needs to be updated first
|
||||||
if (binding && !(binding->flags & BINDING_NOREPEAT) &&
|
if (binding && !(binding->flags & BINDING_NOREPEAT) &&
|
||||||
wlr_device->keyboard->repeat_info.delay > 0) {
|
keyboard->wlr->repeat_info.delay > 0) {
|
||||||
keyboard->repeat_binding = binding;
|
keyboard->repeat_binding = binding;
|
||||||
if (wl_event_source_timer_update(keyboard->key_repeat_source,
|
if (wl_event_source_timer_update(keyboard->key_repeat_source,
|
||||||
wlr_device->keyboard->repeat_info.delay) < 0) {
|
keyboard->wlr->repeat_info.delay) < 0) {
|
||||||
sway_log(SWAY_DEBUG, "failed to set key repeat timer");
|
sway_log(SWAY_DEBUG, "failed to set key repeat timer");
|
||||||
}
|
}
|
||||||
} else if (keyboard->repeat_binding) {
|
} else if (keyboard->repeat_binding) {
|
||||||
|
@ -492,7 +488,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handled && wlr_device->keyboard->group) {
|
if (!handled && keyboard->wlr->group) {
|
||||||
// Only handle device specific bindings for keyboards in a group
|
// Only handle device specific bindings for keyboards in a group
|
||||||
free(device_identifier);
|
free(device_identifier);
|
||||||
return;
|
return;
|
||||||
|
@ -517,7 +513,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
||||||
&keyboard->state_pressed_sent, event->keycode,
|
&keyboard->state_pressed_sent, event->keycode,
|
||||||
event->state, keyinfo.keycode, 0);
|
event->state, keyinfo.keycode, 0);
|
||||||
if (pressed_sent) {
|
if (pressed_sent) {
|
||||||
wlr_seat_set_keyboard(wlr_seat, wlr_device);
|
wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
|
||||||
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
||||||
event->keycode, event->state);
|
event->keycode, event->state);
|
||||||
handled = true;
|
handled = true;
|
||||||
|
@ -528,8 +524,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
||||||
struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
|
struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
|
||||||
|
|
||||||
if (kb_grab) {
|
if (kb_grab) {
|
||||||
wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
|
wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, keyboard->wlr);
|
||||||
wlr_device->keyboard);
|
|
||||||
wlr_input_method_keyboard_grab_v2_send_key(kb_grab,
|
wlr_input_method_keyboard_grab_v2_send_key(kb_grab,
|
||||||
event->time_msec, event->keycode, event->state);
|
event->time_msec, event->keycode, event->state);
|
||||||
handled = true;
|
handled = true;
|
||||||
|
@ -542,7 +537,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
||||||
update_shortcut_state(
|
update_shortcut_state(
|
||||||
&keyboard->state_pressed_sent, event->keycode, event->state,
|
&keyboard->state_pressed_sent, event->keycode, event->state,
|
||||||
keyinfo.keycode, 0);
|
keyinfo.keycode, 0);
|
||||||
wlr_seat_set_keyboard(wlr_seat, wlr_device);
|
wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
|
||||||
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
|
||||||
event->keycode, event->state);
|
event->keycode, event->state);
|
||||||
}
|
}
|
||||||
|
@ -618,14 +613,12 @@ static void handle_keyboard_group_leave(struct wl_listener *listener,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_keyboard_repeat(void *data) {
|
static int handle_keyboard_repeat(void *data) {
|
||||||
struct sway_keyboard *keyboard = (struct sway_keyboard *)data;
|
struct sway_keyboard *keyboard = data;
|
||||||
struct wlr_keyboard *wlr_device =
|
|
||||||
keyboard->seat_device->input_device->wlr_device->keyboard;
|
|
||||||
if (keyboard->repeat_binding) {
|
if (keyboard->repeat_binding) {
|
||||||
if (wlr_device->repeat_info.rate > 0) {
|
if (keyboard->wlr->repeat_info.rate > 0) {
|
||||||
// We queue the next event first, as the command might cancel it
|
// We queue the next event first, as the command might cancel it
|
||||||
if (wl_event_source_timer_update(keyboard->key_repeat_source,
|
if (wl_event_source_timer_update(keyboard->key_repeat_source,
|
||||||
1000 / wlr_device->repeat_info.rate) < 0) {
|
1000 / keyboard->wlr->repeat_info.rate) < 0) {
|
||||||
sway_log(SWAY_DEBUG, "failed to update key repeat timer");
|
sway_log(SWAY_DEBUG, "failed to update key repeat timer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -658,31 +651,28 @@ static void determine_bar_visibility(uint32_t modifiers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_modifier_event(struct sway_keyboard *keyboard) {
|
static void handle_modifier_event(struct sway_keyboard *keyboard) {
|
||||||
struct wlr_input_device *wlr_device =
|
if (!keyboard->wlr->group) {
|
||||||
keyboard->seat_device->input_device->wlr_device;
|
|
||||||
if (!wlr_device->keyboard->group) {
|
|
||||||
struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
|
struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
|
||||||
|
|
||||||
if (kb_grab) {
|
if (kb_grab) {
|
||||||
wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
|
wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, keyboard->wlr);
|
||||||
wlr_device->keyboard);
|
|
||||||
wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab,
|
wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab,
|
||||||
&wlr_device->keyboard->modifiers);
|
&keyboard->wlr->modifiers);
|
||||||
} else {
|
} else {
|
||||||
struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
|
struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
|
||||||
wlr_seat_set_keyboard(wlr_seat, wlr_device);
|
wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
|
||||||
wlr_seat_keyboard_notify_modifiers(wlr_seat,
|
wlr_seat_keyboard_notify_modifiers(wlr_seat,
|
||||||
&wlr_device->keyboard->modifiers);
|
&keyboard->wlr->modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
|
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
|
||||||
determine_bar_visibility(modifiers);
|
determine_bar_visibility(modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlr_device->keyboard->modifiers.group != keyboard->effective_layout) {
|
if (keyboard->wlr->modifiers.group != keyboard->effective_layout) {
|
||||||
keyboard->effective_layout = wlr_device->keyboard->modifiers.group;
|
keyboard->effective_layout = keyboard->wlr->modifiers.group;
|
||||||
|
|
||||||
if (!wlr_keyboard_group_from_wlr_keyboard(wlr_device->keyboard)) {
|
if (!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr)) {
|
||||||
ipc_event_input("xkb_layout", keyboard->seat_device->input_device);
|
ipc_event_input("xkb_layout", keyboard->seat_device->input_device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -711,6 +701,7 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
|
||||||
}
|
}
|
||||||
|
|
||||||
keyboard->seat_device = device;
|
keyboard->seat_device = device;
|
||||||
|
keyboard->wlr = wlr_keyboard_from_input_device(device->input_device->wlr_device);
|
||||||
device->keyboard = keyboard;
|
device->keyboard = keyboard;
|
||||||
|
|
||||||
wl_list_init(&keyboard->keyboard_key.link);
|
wl_list_init(&keyboard->keyboard_key.link);
|
||||||
|
@ -819,13 +810,12 @@ static void destroy_empty_wlr_keyboard_group(void *data) {
|
||||||
|
|
||||||
static void sway_keyboard_group_remove(struct sway_keyboard *keyboard) {
|
static void sway_keyboard_group_remove(struct sway_keyboard *keyboard) {
|
||||||
struct sway_input_device *device = keyboard->seat_device->input_device;
|
struct sway_input_device *device = keyboard->seat_device->input_device;
|
||||||
struct wlr_keyboard *wlr_keyboard = device->wlr_device->keyboard;
|
struct wlr_keyboard_group *wlr_group = keyboard->wlr->group;
|
||||||
struct wlr_keyboard_group *wlr_group = wlr_keyboard->group;
|
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Removing keyboard %s from group %p",
|
sway_log(SWAY_DEBUG, "Removing keyboard %s from group %p",
|
||||||
device->identifier, wlr_group);
|
device->identifier, wlr_group);
|
||||||
|
|
||||||
wlr_keyboard_group_remove_keyboard(wlr_keyboard->group, wlr_keyboard);
|
wlr_keyboard_group_remove_keyboard(keyboard->wlr->group, keyboard->wlr);
|
||||||
|
|
||||||
if (wl_list_empty(&wlr_group->devices)) {
|
if (wl_list_empty(&wlr_group->devices)) {
|
||||||
sway_log(SWAY_DEBUG, "Destroying empty keyboard group %p",
|
sway_log(SWAY_DEBUG, "Destroying empty keyboard group %p",
|
||||||
|
@ -850,9 +840,7 @@ static void sway_keyboard_group_remove(struct sway_keyboard *keyboard) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) {
|
static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) {
|
||||||
struct sway_input_device *device = keyboard->seat_device->input_device;
|
if (!keyboard->wlr->group) {
|
||||||
struct wlr_keyboard *wlr_keyboard = device->wlr_device->keyboard;
|
|
||||||
if (!wlr_keyboard->group) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,7 +856,7 @@ static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) {
|
||||||
break;
|
break;
|
||||||
case KEYBOARD_GROUP_DEFAULT: /* fallthrough */
|
case KEYBOARD_GROUP_DEFAULT: /* fallthrough */
|
||||||
case KEYBOARD_GROUP_SMART:;
|
case KEYBOARD_GROUP_SMART:;
|
||||||
struct wlr_keyboard_group *group = wlr_keyboard->group;
|
struct wlr_keyboard_group *group = keyboard->wlr->group;
|
||||||
if (!wlr_keyboard_keymaps_match(keyboard->keymap, group->keyboard.keymap) ||
|
if (!wlr_keyboard_keymaps_match(keyboard->keymap, group->keyboard.keymap) ||
|
||||||
!repeat_info_match(keyboard, &group->keyboard)) {
|
!repeat_info_match(keyboard, &group->keyboard)) {
|
||||||
sway_keyboard_group_remove(keyboard);
|
sway_keyboard_group_remove(keyboard);
|
||||||
|
@ -879,7 +867,6 @@ static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) {
|
||||||
|
|
||||||
static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
|
static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
|
||||||
struct sway_input_device *device = keyboard->seat_device->input_device;
|
struct sway_input_device *device = keyboard->seat_device->input_device;
|
||||||
struct wlr_keyboard *wlr_keyboard = device->wlr_device->keyboard;
|
|
||||||
struct sway_seat *seat = keyboard->seat_device->sway_seat;
|
struct sway_seat *seat = keyboard->seat_device->sway_seat;
|
||||||
struct seat_config *sc = seat_get_config(seat);
|
struct seat_config *sc = seat_get_config(seat);
|
||||||
|
|
||||||
|
@ -911,7 +898,7 @@ static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
|
||||||
repeat_info_match(keyboard, &wlr_group->keyboard)) {
|
repeat_info_match(keyboard, &wlr_group->keyboard)) {
|
||||||
sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p",
|
sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p",
|
||||||
device->identifier, wlr_group);
|
device->identifier, wlr_group);
|
||||||
wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard);
|
wlr_keyboard_group_add_keyboard(wlr_group, keyboard->wlr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -950,7 +937,7 @@ static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
sway_group->seat_device->input_device->wlr_device =
|
sway_group->seat_device->input_device->wlr_device =
|
||||||
sway_group->wlr_group->input_device;
|
&sway_group->wlr_group->keyboard.base;
|
||||||
|
|
||||||
if (!sway_keyboard_create(seat, sway_group->seat_device)) {
|
if (!sway_keyboard_create(seat, sway_group->seat_device)) {
|
||||||
sway_log(SWAY_ERROR, "Failed to allocate sway_keyboard for group");
|
sway_log(SWAY_ERROR, "Failed to allocate sway_keyboard for group");
|
||||||
|
@ -959,7 +946,7 @@ static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p",
|
sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p",
|
||||||
device->identifier, sway_group->wlr_group);
|
device->identifier, sway_group->wlr_group);
|
||||||
wlr_keyboard_group_add_keyboard(sway_group->wlr_group, wlr_keyboard);
|
wlr_keyboard_group_add_keyboard(sway_group->wlr_group, keyboard->wlr);
|
||||||
|
|
||||||
wl_list_insert(&seat->keyboard_groups, &sway_group->link);
|
wl_list_insert(&seat->keyboard_groups, &sway_group->link);
|
||||||
|
|
||||||
|
@ -991,10 +978,8 @@ cleanup:
|
||||||
void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
||||||
struct input_config *input_config =
|
struct input_config *input_config =
|
||||||
input_device_get_config(keyboard->seat_device->input_device);
|
input_device_get_config(keyboard->seat_device->input_device);
|
||||||
struct wlr_input_device *wlr_device =
|
|
||||||
keyboard->seat_device->input_device->wlr_device;
|
|
||||||
|
|
||||||
if (!sway_assert(!wlr_keyboard_group_from_wlr_keyboard(wlr_device->keyboard),
|
if (!sway_assert(!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr),
|
||||||
"sway_keyboard_configure should not be called with a "
|
"sway_keyboard_configure should not be called with a "
|
||||||
"keyboard group's keyboard")) {
|
"keyboard group's keyboard")) {
|
||||||
return;
|
return;
|
||||||
|
@ -1036,11 +1021,11 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
||||||
|
|
||||||
sway_keyboard_group_remove_invalid(keyboard);
|
sway_keyboard_group_remove_invalid(keyboard);
|
||||||
|
|
||||||
wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap);
|
wlr_keyboard_set_keymap(keyboard->wlr, keyboard->keymap);
|
||||||
wlr_keyboard_set_repeat_info(wlr_device->keyboard,
|
wlr_keyboard_set_repeat_info(keyboard->wlr,
|
||||||
keyboard->repeat_rate, keyboard->repeat_delay);
|
keyboard->repeat_rate, keyboard->repeat_delay);
|
||||||
|
|
||||||
if (!wlr_device->keyboard->group) {
|
if (!keyboard->wlr->group) {
|
||||||
sway_keyboard_group_add(keyboard);
|
sway_keyboard_group_add(keyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,40 +1045,42 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (locked_mods) {
|
if (locked_mods) {
|
||||||
wlr_keyboard_notify_modifiers(wlr_device->keyboard, 0, 0,
|
wlr_keyboard_notify_modifiers(keyboard->wlr, 0, 0,
|
||||||
locked_mods, 0);
|
locked_mods, 0);
|
||||||
uint32_t leds = 0;
|
uint32_t leds = 0;
|
||||||
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
|
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
|
||||||
if (xkb_state_led_index_is_active(
|
if (xkb_state_led_index_is_active(keyboard->wlr->xkb_state,
|
||||||
wlr_device->keyboard->xkb_state,
|
keyboard->wlr->led_indexes[i])) {
|
||||||
wlr_device->keyboard->led_indexes[i])) {
|
|
||||||
leds |= (1 << i);
|
leds |= (1 << i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wlr_device->keyboard->group) {
|
if (keyboard->wlr->group) {
|
||||||
wlr_keyboard_led_update(
|
wlr_keyboard_led_update(&keyboard->wlr->group->keyboard, leds);
|
||||||
&wlr_device->keyboard->group->keyboard, leds);
|
|
||||||
} else {
|
} else {
|
||||||
wlr_keyboard_led_update(wlr_device->keyboard, leds);
|
wlr_keyboard_led_update(keyboard->wlr, leds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
xkb_keymap_unref(keymap);
|
xkb_keymap_unref(keymap);
|
||||||
sway_keyboard_group_remove_invalid(keyboard);
|
sway_keyboard_group_remove_invalid(keyboard);
|
||||||
if (!wlr_device->keyboard->group) {
|
if (!keyboard->wlr->group) {
|
||||||
sway_keyboard_group_add(keyboard);
|
sway_keyboard_group_add(keyboard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the seat has no active keyboard, set this one
|
||||||
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
|
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
|
||||||
wlr_seat_set_keyboard(seat, wlr_device);
|
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_list_remove(&keyboard->keyboard_key.link);
|
||||||
wl_signal_add(&wlr_device->keyboard->events.key, &keyboard->keyboard_key);
|
wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
|
||||||
keyboard->keyboard_key.notify = handle_keyboard_key;
|
keyboard->keyboard_key.notify = handle_keyboard_key;
|
||||||
|
|
||||||
wl_list_remove(&keyboard->keyboard_modifiers.link);
|
wl_list_remove(&keyboard->keyboard_modifiers.link);
|
||||||
wl_signal_add(&wlr_device->keyboard->events.modifiers,
|
wl_signal_add(&keyboard->wlr->events.modifiers,
|
||||||
&keyboard->keyboard_modifiers);
|
&keyboard->keyboard_modifiers);
|
||||||
keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
|
keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
|
||||||
|
|
||||||
|
@ -1110,12 +1097,11 @@ void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
|
||||||
if (!keyboard) {
|
if (!keyboard) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (keyboard->seat_device->input_device->wlr_device->keyboard->group) {
|
if (keyboard->wlr->group) {
|
||||||
sway_keyboard_group_remove(keyboard);
|
sway_keyboard_group_remove(keyboard);
|
||||||
}
|
}
|
||||||
struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
|
struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
|
||||||
struct sway_input_device *device = keyboard->seat_device->input_device;
|
if (wlr_seat_get_keyboard(wlr_seat) == keyboard->wlr) {
|
||||||
if (wlr_seat_get_keyboard(wlr_seat) == device->wlr_device->keyboard) {
|
|
||||||
wlr_seat_set_keyboard(wlr_seat, NULL);
|
wlr_seat_set_keyboard(wlr_seat, NULL);
|
||||||
}
|
}
|
||||||
if (keyboard->keymap) {
|
if (keyboard->keymap) {
|
||||||
|
|
|
@ -166,6 +166,16 @@ static bool set_dwt(struct libinput_device *device, bool dwt) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool set_dwtp(struct libinput_device *device, bool dwtp) {
|
||||||
|
if (!libinput_device_config_dwtp_is_available(device) ||
|
||||||
|
libinput_device_config_dwtp_get_enabled(device) == dwtp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sway_log(SWAY_DEBUG, "dwtp_set_enabled(%d)", dwtp);
|
||||||
|
log_status(libinput_device_config_dwtp_set_enabled(device, dwtp));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
|
static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
|
||||||
if (!libinput_device_config_calibration_has_matrix(dev)) {
|
if (!libinput_device_config_calibration_has_matrix(dev)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -187,10 +197,10 @@ static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sway_input_configure_libinput_device(struct sway_input_device *input_device) {
|
bool sway_input_configure_libinput_device(struct sway_input_device *input_device) {
|
||||||
struct input_config *ic = input_device_get_config(input_device);
|
struct input_config *ic = input_device_get_config(input_device);
|
||||||
if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
|
if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct libinput_device *device =
|
struct libinput_device *device =
|
||||||
|
@ -255,13 +265,14 @@ void sway_input_configure_libinput_device(struct sway_input_device *input_device
|
||||||
if (ic->dwt != INT_MIN) {
|
if (ic->dwt != INT_MIN) {
|
||||||
changed |= set_dwt(device, ic->dwt);
|
changed |= set_dwt(device, ic->dwt);
|
||||||
}
|
}
|
||||||
|
if (ic->dwtp != INT_MIN) {
|
||||||
|
changed |= set_dwtp(device, ic->dwtp);
|
||||||
|
}
|
||||||
if (ic->calibration_matrix.configured) {
|
if (ic->calibration_matrix.configured) {
|
||||||
changed |= set_calibration_matrix(device, ic->calibration_matrix.matrix);
|
changed |= set_calibration_matrix(device, ic->calibration_matrix.matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
return changed;
|
||||||
ipc_event_input("libinput_config", input_device);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
|
void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
|
||||||
|
@ -304,6 +315,8 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
|
||||||
libinput_device_config_scroll_get_default_button(device));
|
libinput_device_config_scroll_get_default_button(device));
|
||||||
changed |= set_dwt(device,
|
changed |= set_dwt(device,
|
||||||
libinput_device_config_dwt_get_default_enabled(device));
|
libinput_device_config_dwt_get_default_enabled(device));
|
||||||
|
changed |= set_dwtp(device,
|
||||||
|
libinput_device_config_dwtp_get_default_enabled(device));
|
||||||
|
|
||||||
float matrix[6];
|
float matrix[6];
|
||||||
libinput_device_config_calibration_get_default_matrix(device, matrix);
|
libinput_device_config_calibration_get_default_matrix(device, matrix);
|
||||||
|
|
|
@ -7,10 +7,12 @@
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
#include <wlr/types/wlr_idle.h>
|
||||||
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_keyboard_group.h>
|
#include <wlr/types/wlr_keyboard_group.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_primary_selection.h>
|
#include <wlr/types/wlr_primary_selection.h>
|
||||||
#include <wlr/types/wlr_tablet_v2.h>
|
#include <wlr/types/wlr_tablet_v2.h>
|
||||||
|
#include <wlr/types/wlr_touch.h>
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
@ -42,6 +44,7 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
|
||||||
sway_keyboard_destroy(seat_device->keyboard);
|
sway_keyboard_destroy(seat_device->keyboard);
|
||||||
sway_tablet_destroy(seat_device->tablet);
|
sway_tablet_destroy(seat_device->tablet);
|
||||||
sway_tablet_pad_destroy(seat_device->tablet_pad);
|
sway_tablet_pad_destroy(seat_device->tablet_pad);
|
||||||
|
sway_switch_destroy(seat_device->switch_device);
|
||||||
wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor,
|
wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor,
|
||||||
seat_device->input_device->wlr_device);
|
seat_device->input_device->wlr_device);
|
||||||
wl_list_remove(&seat_device->link);
|
wl_list_remove(&seat_device->link);
|
||||||
|
@ -110,6 +113,7 @@ void seat_idle_notify_activity(struct sway_seat *seat,
|
||||||
}
|
}
|
||||||
if ((source & mask) > 0) {
|
if ((source & mask) > 0) {
|
||||||
wlr_idle_notify_activity(server.idle, seat->wlr_seat);
|
wlr_idle_notify_activity(server.idle, seat->wlr_seat);
|
||||||
|
wlr_idle_notifier_v1_notify_activity(server.idle_notifier_v1, seat->wlr_seat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +144,7 @@ static struct sway_keyboard *sway_keyboard_for_wlr_keyboard(
|
||||||
if (input_device->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
if (input_device->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (input_device->wlr_device->keyboard == wlr_keyboard) {
|
if (input_device->wlr_device == &wlr_keyboard->base) {
|
||||||
return seat_device->keyboard;
|
return seat_device->keyboard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +152,7 @@ static struct sway_keyboard *sway_keyboard_for_wlr_keyboard(
|
||||||
wl_list_for_each(group, &seat->keyboard_groups, link) {
|
wl_list_for_each(group, &seat->keyboard_groups, link) {
|
||||||
struct sway_input_device *input_device =
|
struct sway_input_device *input_device =
|
||||||
group->seat_device->input_device;
|
group->seat_device->input_device;
|
||||||
if (input_device->wlr_device->keyboard == wlr_keyboard) {
|
if (input_device->wlr_device == &wlr_keyboard->base) {
|
||||||
return group->seat_device->keyboard;
|
return group->seat_device->keyboard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +249,7 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
|
||||||
seat_node_destroy(seat_node);
|
seat_node_destroy(seat_node);
|
||||||
// If an unmanaged or layer surface is focused when an output gets
|
// If an unmanaged or layer surface is focused when an output gets
|
||||||
// disabled and an empty workspace on the output was focused by the
|
// disabled and an empty workspace on the output was focused by the
|
||||||
// seat, the seat needs to refocus it's focus inactive to update the
|
// seat, the seat needs to refocus its focus inactive to update the
|
||||||
// value of seat->workspace.
|
// value of seat->workspace.
|
||||||
if (seat->workspace == node->sway_workspace) {
|
if (seat->workspace == node->sway_workspace) {
|
||||||
struct sway_node *node = seat_get_focus_inactive(seat, &root->node);
|
struct sway_node *node = seat_get_focus_inactive(seat, &root->node);
|
||||||
|
@ -378,8 +382,8 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
|
||||||
case WLR_DRAG_GRAB_KEYBOARD:
|
case WLR_DRAG_GRAB_KEYBOARD:
|
||||||
return;
|
return;
|
||||||
case WLR_DRAG_GRAB_KEYBOARD_POINTER:
|
case WLR_DRAG_GRAB_KEYBOARD_POINTER:
|
||||||
icon->x = cursor->x;
|
icon->x = cursor->x + wlr_icon->surface->sx;
|
||||||
icon->y = cursor->y;
|
icon->y = cursor->y + wlr_icon->surface->sy;
|
||||||
break;
|
break;
|
||||||
case WLR_DRAG_GRAB_KEYBOARD_TOUCH:;
|
case WLR_DRAG_GRAB_KEYBOARD_TOUCH:;
|
||||||
struct wlr_touch_point *point =
|
struct wlr_touch_point *point =
|
||||||
|
@ -387,8 +391,8 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
|
||||||
if (point == NULL) {
|
if (point == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
icon->x = seat->touch_x;
|
icon->x = seat->touch_x + wlr_icon->surface->sx;
|
||||||
icon->y = seat->touch_y;
|
icon->y = seat->touch_y + wlr_icon->surface->sy;
|
||||||
}
|
}
|
||||||
|
|
||||||
drag_icon_damage_whole(icon);
|
drag_icon_damage_whole(icon);
|
||||||
|
@ -724,14 +728,25 @@ static void seat_apply_input_config(struct sway_seat *seat,
|
||||||
ic == NULL ? MAPPED_TO_DEFAULT : ic->mapped_to;
|
ic == NULL ? MAPPED_TO_DEFAULT : ic->mapped_to;
|
||||||
|
|
||||||
switch (mapped_to) {
|
switch (mapped_to) {
|
||||||
case MAPPED_TO_DEFAULT:
|
case MAPPED_TO_DEFAULT:;
|
||||||
/*
|
/*
|
||||||
* If the wlroots backend provides an output name, use that.
|
* If the wlroots backend provides an output name, use that.
|
||||||
*
|
*
|
||||||
* Otherwise, try to map built-in touch and tablet tool devices to the
|
* Otherwise, try to map built-in touch and pointer devices to the
|
||||||
* built-in output.
|
* built-in output.
|
||||||
*/
|
*/
|
||||||
mapped_to_output = sway_device->input_device->wlr_device->output_name;
|
struct wlr_input_device *dev = sway_device->input_device->wlr_device;
|
||||||
|
switch (dev->type) {
|
||||||
|
case WLR_INPUT_DEVICE_POINTER:
|
||||||
|
mapped_to_output = wlr_pointer_from_input_device(dev)->output_name;
|
||||||
|
break;
|
||||||
|
case WLR_INPUT_DEVICE_TOUCH:
|
||||||
|
mapped_to_output = wlr_touch_from_input_device(dev)->output_name;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mapped_to_output = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) &&
|
if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) &&
|
||||||
sway_libinput_device_is_builtin(sway_device->input_device)) {
|
sway_libinput_device_is_builtin(sway_device->input_device)) {
|
||||||
mapped_to_output = get_builtin_output_name();
|
mapped_to_output = get_builtin_output_name();
|
||||||
|
@ -799,13 +814,22 @@ static void seat_configure_keyboard(struct sway_seat *seat,
|
||||||
sway_keyboard_create(seat, seat_device);
|
sway_keyboard_create(seat, seat_device);
|
||||||
}
|
}
|
||||||
sway_keyboard_configure(seat_device->keyboard);
|
sway_keyboard_configure(seat_device->keyboard);
|
||||||
wlr_seat_set_keyboard(seat->wlr_seat,
|
|
||||||
seat_device->input_device->wlr_device);
|
// We only need to update the current keyboard, as the rest will be updated
|
||||||
struct sway_node *focus = seat_get_focus(seat);
|
// as they are activated.
|
||||||
if (focus && node_is_view(focus)) {
|
struct wlr_keyboard *wlr_keyboard =
|
||||||
// force notify reenter to pick up the new configuration
|
wlr_keyboard_from_input_device(seat_device->input_device->wlr_device);
|
||||||
|
struct wlr_keyboard *current_keyboard = seat->wlr_seat->keyboard_state.keyboard;
|
||||||
|
if (wlr_keyboard != current_keyboard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// force notify reenter to pick up the new configuration. This reuses
|
||||||
|
// the current focused surface to avoid breaking input grabs.
|
||||||
|
struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface;
|
||||||
|
if (surface) {
|
||||||
wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat);
|
wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat);
|
||||||
seat_keyboard_notify_enter(seat, focus->sway_container->view->surface);
|
seat_keyboard_notify_enter(seat, surface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1057,7 +1081,8 @@ void seat_configure_xcursor(struct sway_seat *seat) {
|
||||||
bool seat_is_input_allowed(struct sway_seat *seat,
|
bool seat_is_input_allowed(struct sway_seat *seat,
|
||||||
struct wlr_surface *surface) {
|
struct wlr_surface *surface) {
|
||||||
struct wl_client *client = wl_resource_get_client(surface->resource);
|
struct wl_client *client = wl_resource_get_client(surface->resource);
|
||||||
return !seat->exclusive_client || seat->exclusive_client == client;
|
return seat->exclusive_client == client ||
|
||||||
|
(seat->exclusive_client == NULL && !server.session_lock.locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_unfocus(struct sway_container *con, void *data) {
|
static void send_unfocus(struct sway_container *con, void *data) {
|
||||||
|
@ -1116,15 +1141,7 @@ void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
|
static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *node) {
|
||||||
if (seat->focused_layer) {
|
|
||||||
struct wlr_layer_surface_v1 *layer = seat->focused_layer;
|
|
||||||
seat_set_focus_layer(seat, NULL);
|
|
||||||
seat_set_focus(seat, node);
|
|
||||||
seat_set_focus_layer(seat, layer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_node *last_focus = seat_get_focus(seat);
|
struct sway_node *last_focus = seat_get_focus(seat);
|
||||||
if (last_focus == node) {
|
if (last_focus == node) {
|
||||||
return;
|
return;
|
||||||
|
@ -1257,6 +1274,20 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
|
||||||
|
if (seat->focused_layer) {
|
||||||
|
struct wlr_layer_surface_v1 *layer = seat->focused_layer;
|
||||||
|
seat_set_focus_layer(seat, NULL);
|
||||||
|
seat_set_workspace_focus(seat, node);
|
||||||
|
seat_set_focus_layer(seat, layer);
|
||||||
|
} else {
|
||||||
|
seat_set_workspace_focus(seat, node);
|
||||||
|
}
|
||||||
|
if (server.session_lock.locked) {
|
||||||
|
seat_set_focus_surface(seat, server.session_lock.focused, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void seat_set_focus_container(struct sway_seat *seat,
|
void seat_set_focus_container(struct sway_seat *seat,
|
||||||
struct sway_container *con) {
|
struct sway_container *con) {
|
||||||
seat_set_focus(seat, con ? &con->node : NULL);
|
seat_set_focus(seat, con ? &con->node : NULL);
|
||||||
|
@ -1561,7 +1592,7 @@ void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void seatop_pointer_axis(struct sway_seat *seat,
|
void seatop_pointer_axis(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_axis *event) {
|
struct wlr_pointer_axis_event *event) {
|
||||||
if (seat->seatop_impl->pointer_axis) {
|
if (seat->seatop_impl->pointer_axis) {
|
||||||
seat->seatop_impl->pointer_axis(seat, event);
|
seat->seatop_impl->pointer_axis(seat, event);
|
||||||
}
|
}
|
||||||
|
@ -1584,6 +1615,62 @@ void seatop_tablet_tool_motion(struct sway_seat *seat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void seatop_hold_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_begin_event *event) {
|
||||||
|
if (seat->seatop_impl->hold_begin) {
|
||||||
|
seat->seatop_impl->hold_begin(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void seatop_hold_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_end_event *event) {
|
||||||
|
if (seat->seatop_impl->hold_end) {
|
||||||
|
seat->seatop_impl->hold_end(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void seatop_pinch_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_begin_event *event) {
|
||||||
|
if (seat->seatop_impl->pinch_begin) {
|
||||||
|
seat->seatop_impl->pinch_begin(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void seatop_pinch_update(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_update_event *event) {
|
||||||
|
if (seat->seatop_impl->pinch_update) {
|
||||||
|
seat->seatop_impl->pinch_update(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void seatop_pinch_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_end_event *event) {
|
||||||
|
if (seat->seatop_impl->pinch_end) {
|
||||||
|
seat->seatop_impl->pinch_end(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void seatop_swipe_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_begin_event *event) {
|
||||||
|
if (seat->seatop_impl->swipe_begin) {
|
||||||
|
seat->seatop_impl->swipe_begin(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void seatop_swipe_update(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_update_event *event) {
|
||||||
|
if (seat->seatop_impl->swipe_update) {
|
||||||
|
seat->seatop_impl->swipe_update(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void seatop_swipe_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_end_event *event) {
|
||||||
|
if (seat->seatop_impl->swipe_end) {
|
||||||
|
seat->seatop_impl->swipe_end(seat, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec) {
|
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec) {
|
||||||
if (seat->seatop_impl->rebase) {
|
if (seat->seatop_impl->rebase) {
|
||||||
seat->seatop_impl->rebase(seat, time_msec);
|
seat->seatop_impl->rebase(seat, time_msec);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_tablet_v2.h>
|
#include <wlr/types/wlr_tablet_v2.h>
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
|
#include "gesture.h"
|
||||||
#include "sway/desktop/transaction.h"
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
|
@ -20,6 +21,7 @@ struct seatop_default_event {
|
||||||
struct sway_node *previous_node;
|
struct sway_node *previous_node;
|
||||||
uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
|
uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
|
||||||
size_t pressed_button_count;
|
size_t pressed_button_count;
|
||||||
|
struct gesture_tracker gestures;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-----------------------------------------\
|
/*-----------------------------------------\
|
||||||
|
@ -427,13 +429,31 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle changing focus when clicking on a container
|
||||||
|
if (cont && state == WLR_BUTTON_PRESSED) {
|
||||||
|
// Default case: focus the container that was just clicked.
|
||||||
|
node = &cont->node;
|
||||||
|
|
||||||
|
// If the container is a tab/stacked container and the click happened
|
||||||
|
// on a tab, switch to the tab. If the tab contents were already
|
||||||
|
// focused, focus the tab container itself. If the tab container was
|
||||||
|
// already focused, cycle back to focusing the tab contents.
|
||||||
|
if (on_titlebar) {
|
||||||
|
struct sway_container *focus = seat_get_focused_container(seat);
|
||||||
|
if (focus == cont || !container_has_ancestor(focus, cont)) {
|
||||||
|
node = seat_get_focus_inactive(seat, &cont->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seat_set_focus(seat, node);
|
||||||
|
transaction_commit_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
// Handle beginning floating move
|
// Handle beginning floating move
|
||||||
if (cont && is_floating_or_child && !is_fullscreen_or_child &&
|
if (cont && is_floating_or_child && !is_fullscreen_or_child &&
|
||||||
state == WLR_BUTTON_PRESSED) {
|
state == WLR_BUTTON_PRESSED) {
|
||||||
uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
|
uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
|
||||||
if (button == btn_move && (mod_pressed || on_titlebar)) {
|
if (button == btn_move && (mod_pressed || on_titlebar)) {
|
||||||
seat_set_focus_container(seat,
|
|
||||||
seat_get_focus_inactive_view(seat, &cont->node));
|
|
||||||
seatop_begin_move_floating(seat, container_toplevel_ancestor(cont));
|
seatop_begin_move_floating(seat, container_toplevel_ancestor(cont));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -444,6 +464,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
state == WLR_BUTTON_PRESSED) {
|
state == WLR_BUTTON_PRESSED) {
|
||||||
// Via border
|
// Via border
|
||||||
if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
|
if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
|
||||||
|
seat_set_focus_container(seat, cont);
|
||||||
seatop_begin_resize_floating(seat, cont, resize_edge);
|
seatop_begin_resize_floating(seat, cont, resize_edge);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -458,6 +479,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
|
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
|
||||||
edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ?
|
edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ?
|
||||||
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
|
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
|
||||||
|
seat_set_focus_container(seat, floater);
|
||||||
seatop_begin_resize_floating(seat, floater, edge);
|
seatop_begin_resize_floating(seat, floater, edge);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -467,25 +489,18 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
if (config->tiling_drag && (mod_pressed || on_titlebar) &&
|
if (config->tiling_drag && (mod_pressed || on_titlebar) &&
|
||||||
state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
|
state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
|
||||||
cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
|
cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
|
||||||
struct sway_container *focus = seat_get_focused_container(seat);
|
// If moving a container by its title bar, use a threshold for the drag
|
||||||
bool focused = focus == cont || container_has_ancestor(focus, cont);
|
|
||||||
if (on_titlebar && !focused) {
|
|
||||||
node = seat_get_focus_inactive(seat, &cont->node);
|
|
||||||
seat_set_focus(seat, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If moving a container by it's title bar, use a threshold for the drag
|
|
||||||
if (!mod_pressed && config->tiling_drag_threshold > 0) {
|
if (!mod_pressed && config->tiling_drag_threshold > 0) {
|
||||||
seatop_begin_move_tiling_threshold(seat, cont);
|
seatop_begin_move_tiling_threshold(seat, cont);
|
||||||
} else {
|
} else {
|
||||||
seatop_begin_move_tiling(seat, cont);
|
seatop_begin_move_tiling(seat, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle mousedown on a container surface
|
// Handle mousedown on a container surface
|
||||||
if (surface && cont && state == WLR_BUTTON_PRESSED) {
|
if (surface && cont && state == WLR_BUTTON_PRESSED) {
|
||||||
seat_set_focus_container(seat, cont);
|
|
||||||
seatop_begin_down(seat, cont, time_msec, sx, sy);
|
seatop_begin_down(seat, cont, time_msec, sx, sy);
|
||||||
seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
|
seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
|
||||||
return;
|
return;
|
||||||
|
@ -493,9 +508,6 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
|
|
||||||
// Handle clicking a container surface or decorations
|
// Handle clicking a container surface or decorations
|
||||||
if (cont && state == WLR_BUTTON_PRESSED) {
|
if (cont && state == WLR_BUTTON_PRESSED) {
|
||||||
node = seat_get_focus_inactive(seat, &cont->node);
|
|
||||||
seat_set_focus(seat, node);
|
|
||||||
transaction_commit_dirty();
|
|
||||||
seat_pointer_notify_button(seat, time_msec, button, state);
|
seat_pointer_notify_button(seat, time_msec, button, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -645,7 +657,7 @@ static void handle_tablet_tool_motion(struct sway_seat *seat,
|
||||||
* Functions used by handle_pointer_axis /
|
* Functions used by handle_pointer_axis /
|
||||||
*--------------------------------------*/
|
*--------------------------------------*/
|
||||||
|
|
||||||
static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
|
static uint32_t wl_axis_to_button(struct wlr_pointer_axis_event *event) {
|
||||||
switch (event->orientation) {
|
switch (event->orientation) {
|
||||||
case WLR_AXIS_ORIENTATION_VERTICAL:
|
case WLR_AXIS_ORIENTATION_VERTICAL:
|
||||||
return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
|
return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
|
||||||
|
@ -658,9 +670,9 @@ static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_pointer_axis(struct sway_seat *seat,
|
static void handle_pointer_axis(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_axis *event) {
|
struct wlr_pointer_axis_event *event) {
|
||||||
struct sway_input_device *input_device =
|
struct sway_input_device *input_device =
|
||||||
event->device ? event->device->data : NULL;
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
struct input_config *ic =
|
struct input_config *ic =
|
||||||
input_device ? input_device_get_config(input_device) : NULL;
|
input_device ? input_device_get_config(input_device) : NULL;
|
||||||
struct sway_cursor *cursor = seat->cursor;
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
@ -706,6 +718,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
|
||||||
|
|
||||||
// Scrolling on a tabbed or stacked title bar (handled as press event)
|
// Scrolling on a tabbed or stacked title bar (handled as press event)
|
||||||
if (!handled && (on_titlebar || on_titlebar_border)) {
|
if (!handled && (on_titlebar || on_titlebar_border)) {
|
||||||
|
struct sway_node *new_focus;
|
||||||
enum sway_container_layout layout = container_parent_layout(cont);
|
enum sway_container_layout layout = container_parent_layout(cont);
|
||||||
if (layout == L_TABBED || layout == L_STACKED) {
|
if (layout == L_TABBED || layout == L_STACKED) {
|
||||||
struct sway_node *tabcontainer = node_get_parent(node);
|
struct sway_node *tabcontainer = node_get_parent(node);
|
||||||
|
@ -713,7 +726,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
|
||||||
seat_get_active_tiling_child(seat, tabcontainer);
|
seat_get_active_tiling_child(seat, tabcontainer);
|
||||||
list_t *siblings = container_get_siblings(cont);
|
list_t *siblings = container_get_siblings(cont);
|
||||||
int desired = list_find(siblings, active->sway_container) +
|
int desired = list_find(siblings, active->sway_container) +
|
||||||
round(scroll_factor * event->delta_discrete);
|
round(scroll_factor * event->delta_discrete / WLR_POINTER_AXIS_DISCRETE_STEP);
|
||||||
if (desired < 0) {
|
if (desired < 0) {
|
||||||
desired = 0;
|
desired = 0;
|
||||||
} else if (desired >= siblings->length) {
|
} else if (desired >= siblings->length) {
|
||||||
|
@ -722,14 +735,16 @@ static void handle_pointer_axis(struct sway_seat *seat,
|
||||||
|
|
||||||
struct sway_container *new_sibling_con = siblings->items[desired];
|
struct sway_container *new_sibling_con = siblings->items[desired];
|
||||||
struct sway_node *new_sibling = &new_sibling_con->node;
|
struct sway_node *new_sibling = &new_sibling_con->node;
|
||||||
struct sway_node *new_focus =
|
|
||||||
seat_get_focus_inactive(seat, new_sibling);
|
|
||||||
// Use the focused child of the tabbed/stacked container, not the
|
// Use the focused child of the tabbed/stacked container, not the
|
||||||
// container the user scrolled on.
|
// container the user scrolled on.
|
||||||
seat_set_focus(seat, new_focus);
|
new_focus = seat_get_focus_inactive(seat, new_sibling);
|
||||||
transaction_commit_dirty();
|
} else {
|
||||||
handled = true;
|
new_focus = seat_get_focus_inactive(seat, &cont->node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seat_set_focus(seat, new_focus);
|
||||||
|
transaction_commit_dirty();
|
||||||
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle mouse bindings - x11 mouse buttons 4-7 - release event
|
// Handle mouse bindings - x11 mouse buttons 4-7 - release event
|
||||||
|
@ -750,6 +765,304 @@ static void handle_pointer_axis(struct sway_seat *seat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*------------------------------------\
|
||||||
|
* Functions used by gesture support /
|
||||||
|
*----------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check gesture binding for a specific gesture type and finger count.
|
||||||
|
* Returns true if binding is present, false otherwise
|
||||||
|
*/
|
||||||
|
static bool gesture_binding_check(list_t *bindings, enum gesture_type type,
|
||||||
|
uint8_t fingers, struct sway_input_device *device) {
|
||||||
|
char *input =
|
||||||
|
device ? input_device_get_identifier(device->wlr_device) : strdup("*");
|
||||||
|
|
||||||
|
for (int i = 0; i < bindings->length; ++i) {
|
||||||
|
struct sway_gesture_binding *binding = bindings->items[i];
|
||||||
|
|
||||||
|
// Check type and finger count
|
||||||
|
if (!gesture_check(&binding->gesture, type, fingers)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that input matches
|
||||||
|
if (strcmp(binding->input, "*") != 0 &&
|
||||||
|
strcmp(binding->input, input) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(input);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(input);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the gesture binding which matches gesture type, finger count
|
||||||
|
* and direction, otherwise return null.
|
||||||
|
*/
|
||||||
|
static struct sway_gesture_binding* gesture_binding_match(
|
||||||
|
list_t *bindings, struct gesture *gesture, const char *input) {
|
||||||
|
struct sway_gesture_binding *current = NULL;
|
||||||
|
|
||||||
|
// Find best matching binding
|
||||||
|
for (int i = 0; i < bindings->length; ++i) {
|
||||||
|
struct sway_gesture_binding *binding = bindings->items[i];
|
||||||
|
bool exact = binding->flags & BINDING_EXACT;
|
||||||
|
|
||||||
|
// Check gesture matching
|
||||||
|
if (!gesture_match(&binding->gesture, gesture, exact)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check input matching
|
||||||
|
if (strcmp(binding->input, "*") != 0 &&
|
||||||
|
strcmp(binding->input, input) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we already have a match ...
|
||||||
|
if (current) {
|
||||||
|
// ... check if input matching is equivalent
|
||||||
|
if (strcmp(current->input, binding->input) == 0) {
|
||||||
|
|
||||||
|
// ... - do not override an exact binding
|
||||||
|
if (!exact && current->flags & BINDING_EXACT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... - and ensure direction matching is better or equal
|
||||||
|
if (gesture_compare(¤t->gesture, &binding->gesture) > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (strcmp(binding->input, "*") == 0) {
|
||||||
|
// ... do not accept worse input match
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept newer or better match
|
||||||
|
current = binding;
|
||||||
|
|
||||||
|
// If exact binding and input is found, quit search
|
||||||
|
if (strcmp(current->input, input) == 0 &&
|
||||||
|
gesture_compare(¤t->gesture, gesture) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for all gesture bindings
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper around gesture_tracker_end to use tracker with sway bindings
|
||||||
|
static struct sway_gesture_binding* gesture_tracker_end_and_match(
|
||||||
|
struct gesture_tracker *tracker, struct sway_input_device* device) {
|
||||||
|
// Determine name of input that received gesture
|
||||||
|
char *input = device
|
||||||
|
? input_device_get_identifier(device->wlr_device)
|
||||||
|
: strdup("*");
|
||||||
|
|
||||||
|
// Match tracking result to binding
|
||||||
|
struct gesture *gesture = gesture_tracker_end(tracker);
|
||||||
|
struct sway_gesture_binding *binding = gesture_binding_match(
|
||||||
|
config->current_mode->gesture_bindings, gesture, input);
|
||||||
|
free(gesture);
|
||||||
|
free(input);
|
||||||
|
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Small wrapper around seat_execute_command to work on gesture bindings
|
||||||
|
static void gesture_binding_execute(struct sway_seat *seat,
|
||||||
|
struct sway_gesture_binding *binding) {
|
||||||
|
struct sway_binding *dummy_binding =
|
||||||
|
calloc(1, sizeof(struct sway_binding));
|
||||||
|
dummy_binding->type = BINDING_GESTURE;
|
||||||
|
dummy_binding->command = binding->command;
|
||||||
|
|
||||||
|
char *description = gesture_to_string(&binding->gesture);
|
||||||
|
sway_log(SWAY_DEBUG, "executing gesture binding: %s", description);
|
||||||
|
free(description);
|
||||||
|
|
||||||
|
seat_execute_command(seat, dummy_binding);
|
||||||
|
|
||||||
|
free(dummy_binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_hold_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_begin_event *event) {
|
||||||
|
// Start tracking gesture if there is a matching binding ...
|
||||||
|
struct sway_input_device *device =
|
||||||
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
|
list_t *bindings = config->current_mode->gesture_bindings;
|
||||||
|
if (gesture_binding_check(bindings, GESTURE_TYPE_HOLD, event->fingers, device)) {
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_HOLD, event->fingers);
|
||||||
|
} else {
|
||||||
|
// ... otherwise forward to client
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_hold_begin(
|
||||||
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
|
event->time_msec, event->fingers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_hold_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_hold_end_event *event) {
|
||||||
|
// Ensure that gesture is being tracked and was not cancelled
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) {
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_hold_end(
|
||||||
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
|
event->time_msec, event->cancelled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event->cancelled) {
|
||||||
|
gesture_tracker_cancel(&seatop->gestures);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End gesture tracking and execute matched binding
|
||||||
|
struct sway_input_device *device =
|
||||||
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
|
struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
|
||||||
|
&seatop->gestures, device);
|
||||||
|
|
||||||
|
if (binding) {
|
||||||
|
gesture_binding_execute(seat, binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pinch_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_begin_event *event) {
|
||||||
|
// Start tracking gesture if there is a matching binding ...
|
||||||
|
struct sway_input_device *device =
|
||||||
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
|
list_t *bindings = config->current_mode->gesture_bindings;
|
||||||
|
if (gesture_binding_check(bindings, GESTURE_TYPE_PINCH, event->fingers, device)) {
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_PINCH, event->fingers);
|
||||||
|
} else {
|
||||||
|
// ... otherwise forward to client
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_pinch_begin(
|
||||||
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
|
event->time_msec, event->fingers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pinch_update(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_update_event *event) {
|
||||||
|
// Update any ongoing tracking ...
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) {
|
||||||
|
gesture_tracker_update(&seatop->gestures, event->dx, event->dy,
|
||||||
|
event->scale, event->rotation);
|
||||||
|
} else {
|
||||||
|
// ... otherwise forward to client
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_pinch_update(
|
||||||
|
cursor->pointer_gestures,
|
||||||
|
cursor->seat->wlr_seat,
|
||||||
|
event->time_msec, event->dx, event->dy,
|
||||||
|
event->scale, event->rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pinch_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_pinch_end_event *event) {
|
||||||
|
// Ensure that gesture is being tracked and was not cancelled
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) {
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_pinch_end(
|
||||||
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
|
event->time_msec, event->cancelled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event->cancelled) {
|
||||||
|
gesture_tracker_cancel(&seatop->gestures);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End gesture tracking and execute matched binding
|
||||||
|
struct sway_input_device *device =
|
||||||
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
|
struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
|
||||||
|
&seatop->gestures, device);
|
||||||
|
|
||||||
|
if (binding) {
|
||||||
|
gesture_binding_execute(seat, binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_swipe_begin(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_begin_event *event) {
|
||||||
|
// Start tracking gesture if there is a matching binding ...
|
||||||
|
struct sway_input_device *device =
|
||||||
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
|
list_t *bindings = config->current_mode->gesture_bindings;
|
||||||
|
if (gesture_binding_check(bindings, GESTURE_TYPE_SWIPE, event->fingers, device)) {
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_SWIPE, event->fingers);
|
||||||
|
} else {
|
||||||
|
// ... otherwise forward to client
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_swipe_begin(
|
||||||
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
|
event->time_msec, event->fingers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_swipe_update(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_update_event *event) {
|
||||||
|
|
||||||
|
// Update any ongoing tracking ...
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
|
||||||
|
gesture_tracker_update(&seatop->gestures,
|
||||||
|
event->dx, event->dy, NAN, NAN);
|
||||||
|
} else {
|
||||||
|
// ... otherwise forward to client
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_swipe_update(
|
||||||
|
cursor->pointer_gestures, cursor->seat->wlr_seat,
|
||||||
|
event->time_msec, event->dx, event->dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_swipe_end(struct sway_seat *seat,
|
||||||
|
struct wlr_pointer_swipe_end_event *event) {
|
||||||
|
// Ensure gesture is being tracked and was not cancelled
|
||||||
|
struct seatop_default_event *seatop = seat->seatop_data;
|
||||||
|
if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
|
||||||
|
struct sway_cursor *cursor = seat->cursor;
|
||||||
|
wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures,
|
||||||
|
cursor->seat->wlr_seat, event->time_msec, event->cancelled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event->cancelled) {
|
||||||
|
gesture_tracker_cancel(&seatop->gestures);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End gesture tracking and execute matched binding
|
||||||
|
struct sway_input_device *device =
|
||||||
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
|
struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
|
||||||
|
&seatop->gestures, device);
|
||||||
|
|
||||||
|
if (binding) {
|
||||||
|
gesture_binding_execute(seat, binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------\
|
/*----------------------------------\
|
||||||
* Functions used by handle_rebase /
|
* Functions used by handle_rebase /
|
||||||
*--------------------------------*/
|
*--------------------------------*/
|
||||||
|
@ -779,6 +1092,14 @@ static const struct sway_seatop_impl seatop_impl = {
|
||||||
.pointer_axis = handle_pointer_axis,
|
.pointer_axis = handle_pointer_axis,
|
||||||
.tablet_tool_tip = handle_tablet_tool_tip,
|
.tablet_tool_tip = handle_tablet_tool_tip,
|
||||||
.tablet_tool_motion = handle_tablet_tool_motion,
|
.tablet_tool_motion = handle_tablet_tool_motion,
|
||||||
|
.hold_begin = handle_hold_begin,
|
||||||
|
.hold_end = handle_hold_end,
|
||||||
|
.pinch_begin = handle_pinch_begin,
|
||||||
|
.pinch_update = handle_pinch_update,
|
||||||
|
.pinch_end = handle_pinch_end,
|
||||||
|
.swipe_begin = handle_swipe_begin,
|
||||||
|
.swipe_update = handle_swipe_update,
|
||||||
|
.swipe_end = handle_swipe_end,
|
||||||
.rebase = handle_rebase,
|
.rebase = handle_rebase,
|
||||||
.allow_set_cursor = true,
|
.allow_set_cursor = true,
|
||||||
};
|
};
|
||||||
|
@ -789,8 +1110,8 @@ void seatop_begin_default(struct sway_seat *seat) {
|
||||||
struct seatop_default_event *e =
|
struct seatop_default_event *e =
|
||||||
calloc(1, sizeof(struct seatop_default_event));
|
calloc(1, sizeof(struct seatop_default_event));
|
||||||
sway_assert(e, "Unable to allocate seatop_default_event");
|
sway_assert(e, "Unable to allocate seatop_default_event");
|
||||||
|
|
||||||
seat->seatop_impl = &seatop_impl;
|
seat->seatop_impl = &seatop_impl;
|
||||||
seat->seatop_data = e;
|
seat->seatop_data = e;
|
||||||
|
|
||||||
seatop_rebase(seat, 0);
|
seatop_rebase(seat, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,9 @@ struct seatop_down_event {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handle_pointer_axis(struct sway_seat *seat,
|
static void handle_pointer_axis(struct sway_seat *seat,
|
||||||
struct wlr_event_pointer_axis *event) {
|
struct wlr_pointer_axis_event *event) {
|
||||||
struct sway_input_device *input_device =
|
struct sway_input_device *input_device =
|
||||||
event->device ? event->device->data : NULL;
|
event->pointer ? event->pointer->base.data : NULL;
|
||||||
struct input_config *ic =
|
struct input_config *ic =
|
||||||
input_device ? input_device_get_config(input_device) : NULL;
|
input_device ? input_device_get_config(input_device) : NULL;
|
||||||
float scroll_factor =
|
float scroll_factor =
|
||||||
|
|
|
@ -11,6 +11,7 @@ struct sway_switch *sway_switch_create(struct sway_seat *seat,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
device->switch_device = switch_device;
|
device->switch_device = switch_device;
|
||||||
|
switch_device->wlr = wlr_switch_from_input_device(device->input_device->wlr_device);
|
||||||
switch_device->seat_device = device;
|
switch_device->seat_device = device;
|
||||||
switch_device->state = WLR_SWITCH_STATE_OFF;
|
switch_device->state = WLR_SWITCH_STATE_OFF;
|
||||||
wl_list_init(&switch_device->switch_toggle.link);
|
wl_list_init(&switch_device->switch_toggle.link);
|
||||||
|
@ -19,9 +20,23 @@ struct sway_switch *sway_switch_create(struct sway_seat *seat,
|
||||||
return switch_device;
|
return switch_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sway_switch_trigger_test(enum sway_switch_trigger trigger,
|
||||||
|
enum wlr_switch_state state) {
|
||||||
|
switch (trigger) {
|
||||||
|
case SWAY_SWITCH_TRIGGER_ON:
|
||||||
|
return state == WLR_SWITCH_STATE_ON;
|
||||||
|
case SWAY_SWITCH_TRIGGER_OFF:
|
||||||
|
return state == WLR_SWITCH_STATE_OFF;
|
||||||
|
case SWAY_SWITCH_TRIGGER_TOGGLE:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
abort(); // unreachable
|
||||||
|
}
|
||||||
|
|
||||||
static void execute_binding(struct sway_switch *sway_switch) {
|
static void execute_binding(struct sway_switch *sway_switch) {
|
||||||
struct sway_seat* seat = sway_switch->seat_device->sway_seat;
|
struct sway_seat* seat = sway_switch->seat_device->sway_seat;
|
||||||
bool input_inhibited = seat->exclusive_client != NULL;
|
bool input_inhibited = seat->exclusive_client != NULL ||
|
||||||
|
server.session_lock.locked;
|
||||||
|
|
||||||
list_t *bindings = config->current_mode->switch_bindings;
|
list_t *bindings = config->current_mode->switch_bindings;
|
||||||
struct sway_switch_binding *matched_binding = NULL;
|
struct sway_switch_binding *matched_binding = NULL;
|
||||||
|
@ -30,11 +45,10 @@ static void execute_binding(struct sway_switch *sway_switch) {
|
||||||
if (binding->type != sway_switch->type) {
|
if (binding->type != sway_switch->type) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (binding->state != WLR_SWITCH_STATE_TOGGLE &&
|
if (!sway_switch_trigger_test(binding->trigger, sway_switch->state)) {
|
||||||
binding->state != sway_switch->state) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (config->reloading && (binding->state == WLR_SWITCH_STATE_TOGGLE
|
if (config->reloading && (binding->trigger == SWAY_SWITCH_TRIGGER_TOGGLE
|
||||||
|| (binding->flags & BINDING_RELOAD) == 0)) {
|
|| (binding->flags & BINDING_RELOAD) == 0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +79,7 @@ static void execute_binding(struct sway_switch *sway_switch) {
|
||||||
static void handle_switch_toggle(struct wl_listener *listener, void *data) {
|
static void handle_switch_toggle(struct wl_listener *listener, void *data) {
|
||||||
struct sway_switch *sway_switch =
|
struct sway_switch *sway_switch =
|
||||||
wl_container_of(listener, sway_switch, switch_toggle);
|
wl_container_of(listener, sway_switch, switch_toggle);
|
||||||
struct wlr_event_switch_toggle *event = data;
|
struct wlr_switch_toggle_event *event = data;
|
||||||
struct sway_seat *seat = sway_switch->seat_device->sway_seat;
|
struct sway_seat *seat = sway_switch->seat_device->sway_seat;
|
||||||
seat_idle_notify_activity(seat, IDLE_SOURCE_SWITCH);
|
seat_idle_notify_activity(seat, IDLE_SOURCE_SWITCH);
|
||||||
|
|
||||||
|
@ -82,10 +96,8 @@ static void handle_switch_toggle(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sway_switch_configure(struct sway_switch *sway_switch) {
|
void sway_switch_configure(struct sway_switch *sway_switch) {
|
||||||
struct wlr_input_device *wlr_device =
|
|
||||||
sway_switch->seat_device->input_device->wlr_device;
|
|
||||||
wl_list_remove(&sway_switch->switch_toggle.link);
|
wl_list_remove(&sway_switch->switch_toggle.link);
|
||||||
wl_signal_add(&wlr_device->switch_device->events.toggle,
|
wl_signal_add(&sway_switch->wlr->events.toggle,
|
||||||
&sway_switch->switch_toggle);
|
&sway_switch->switch_toggle);
|
||||||
sway_switch->switch_toggle.notify = handle_switch_toggle;
|
sway_switch->switch_toggle.notify = handle_switch_toggle;
|
||||||
sway_log(SWAY_DEBUG, "Configured switch for device");
|
sway_log(SWAY_DEBUG, "Configured switch for device");
|
||||||
|
|
|
@ -196,7 +196,7 @@ static void handle_tablet_pad_attach(struct wl_listener *listener,
|
||||||
|
|
||||||
static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) {
|
static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) {
|
||||||
struct sway_tablet_pad *pad = wl_container_of(listener, pad, ring);
|
struct sway_tablet_pad *pad = wl_container_of(listener, pad, ring);
|
||||||
struct wlr_event_tablet_pad_ring *event = data;
|
struct wlr_tablet_pad_ring_event *event = data;
|
||||||
|
|
||||||
if (!pad->current_surface) {
|
if (!pad->current_surface) {
|
||||||
return;
|
return;
|
||||||
|
@ -210,7 +210,7 @@ static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) {
|
static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) {
|
||||||
struct sway_tablet_pad *pad = wl_container_of(listener, pad, strip);
|
struct sway_tablet_pad *pad = wl_container_of(listener, pad, strip);
|
||||||
struct wlr_event_tablet_pad_strip *event = data;
|
struct wlr_tablet_pad_strip_event *event = data;
|
||||||
|
|
||||||
if (!pad->current_surface) {
|
if (!pad->current_surface) {
|
||||||
return;
|
return;
|
||||||
|
@ -224,7 +224,7 @@ static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
static void handle_tablet_pad_button(struct wl_listener *listener, void *data) {
|
static void handle_tablet_pad_button(struct wl_listener *listener, void *data) {
|
||||||
struct sway_tablet_pad *pad = wl_container_of(listener, pad, button);
|
struct sway_tablet_pad *pad = wl_container_of(listener, pad, button);
|
||||||
struct wlr_event_tablet_pad_button *event = data;
|
struct wlr_tablet_pad_button_event *event = data;
|
||||||
|
|
||||||
if (!pad->current_surface) {
|
if (!pad->current_surface) {
|
||||||
return;
|
return;
|
||||||
|
@ -246,6 +246,7 @@ struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tablet_pad->wlr = wlr_tablet_pad_from_input_device(device->input_device->wlr_device);
|
||||||
tablet_pad->seat_device = device;
|
tablet_pad->seat_device = device;
|
||||||
wl_list_init(&tablet_pad->attach.link);
|
wl_list_init(&tablet_pad->attach.link);
|
||||||
wl_list_init(&tablet_pad->button.link);
|
wl_list_init(&tablet_pad->button.link);
|
||||||
|
@ -260,40 +261,40 @@ struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat,
|
||||||
}
|
}
|
||||||
|
|
||||||
void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad) {
|
void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad) {
|
||||||
struct wlr_input_device *device =
|
struct wlr_input_device *wlr_device =
|
||||||
tablet_pad->seat_device->input_device->wlr_device;
|
tablet_pad->seat_device->input_device->wlr_device;
|
||||||
struct sway_seat *seat = tablet_pad->seat_device->sway_seat;
|
struct sway_seat *seat = tablet_pad->seat_device->sway_seat;
|
||||||
|
|
||||||
if (!tablet_pad->tablet_v2_pad) {
|
if (!tablet_pad->tablet_v2_pad) {
|
||||||
tablet_pad->tablet_v2_pad =
|
tablet_pad->tablet_v2_pad =
|
||||||
wlr_tablet_pad_create(server.tablet_v2, seat->wlr_seat, device);
|
wlr_tablet_pad_create(server.tablet_v2, seat->wlr_seat, wlr_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_remove(&tablet_pad->attach.link);
|
wl_list_remove(&tablet_pad->attach.link);
|
||||||
tablet_pad->attach.notify = handle_tablet_pad_attach;
|
tablet_pad->attach.notify = handle_tablet_pad_attach;
|
||||||
wl_signal_add(&device->tablet_pad->events.attach_tablet,
|
wl_signal_add(&tablet_pad->wlr->events.attach_tablet,
|
||||||
&tablet_pad->attach);
|
&tablet_pad->attach);
|
||||||
|
|
||||||
wl_list_remove(&tablet_pad->button.link);
|
wl_list_remove(&tablet_pad->button.link);
|
||||||
tablet_pad->button.notify = handle_tablet_pad_button;
|
tablet_pad->button.notify = handle_tablet_pad_button;
|
||||||
wl_signal_add(&device->tablet_pad->events.button, &tablet_pad->button);
|
wl_signal_add(&tablet_pad->wlr->events.button, &tablet_pad->button);
|
||||||
|
|
||||||
wl_list_remove(&tablet_pad->strip.link);
|
wl_list_remove(&tablet_pad->strip.link);
|
||||||
tablet_pad->strip.notify = handle_tablet_pad_strip;
|
tablet_pad->strip.notify = handle_tablet_pad_strip;
|
||||||
wl_signal_add(&device->tablet_pad->events.strip, &tablet_pad->strip);
|
wl_signal_add(&tablet_pad->wlr->events.strip, &tablet_pad->strip);
|
||||||
|
|
||||||
wl_list_remove(&tablet_pad->ring.link);
|
wl_list_remove(&tablet_pad->ring.link);
|
||||||
tablet_pad->ring.notify = handle_tablet_pad_ring;
|
tablet_pad->ring.notify = handle_tablet_pad_ring;
|
||||||
wl_signal_add(&device->tablet_pad->events.ring, &tablet_pad->ring);
|
wl_signal_add(&tablet_pad->wlr->events.ring, &tablet_pad->ring);
|
||||||
|
|
||||||
/* Search for a sibling tablet */
|
/* Search for a sibling tablet */
|
||||||
if (!wlr_input_device_is_libinput(device)) {
|
if (!wlr_input_device_is_libinput(wlr_device)) {
|
||||||
/* We can only do this on libinput devices */
|
/* We can only do this on libinput devices */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct libinput_device_group *group =
|
struct libinput_device_group *group =
|
||||||
libinput_device_get_device_group(wlr_libinput_get_device_handle(device));
|
libinput_device_get_device_group(wlr_libinput_get_device_handle(wlr_device));
|
||||||
struct sway_tablet *tool;
|
struct sway_tablet *tool;
|
||||||
wl_list_for_each(tool, &seat->cursor->tablets, link) {
|
wl_list_for_each(tool, &seat->cursor->tablets, link) {
|
||||||
struct wlr_input_device *tablet =
|
struct wlr_input_device *tablet =
|
||||||
|
|
|
@ -77,8 +77,6 @@ static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) {
|
||||||
struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat);
|
struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat);
|
||||||
wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,
|
wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,
|
||||||
active_keyboard);
|
active_keyboard);
|
||||||
wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab,
|
|
||||||
&active_keyboard->modifiers);
|
|
||||||
|
|
||||||
wl_signal_add(&keyboard_grab->events.destroy,
|
wl_signal_add(&keyboard_grab->events.destroy,
|
||||||
&relay->input_method_keyboard_grab_destroy);
|
&relay->input_method_keyboard_grab_destroy);
|
||||||
|
|
173
sway/ipc-json.c
173
sway/ipc-json.c
|
@ -112,12 +112,43 @@ static const char *ipc_json_output_adaptive_sync_status_description(
|
||||||
return "disabled";
|
return "disabled";
|
||||||
case WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED:
|
case WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED:
|
||||||
return "enabled";
|
return "enabled";
|
||||||
case WLR_OUTPUT_ADAPTIVE_SYNC_UNKNOWN:
|
|
||||||
return "unknown";
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *ipc_json_output_mode_aspect_ratio_description(
|
||||||
|
enum wlr_output_mode_aspect_ratio aspect_ratio) {
|
||||||
|
switch (aspect_ratio) {
|
||||||
|
case WLR_OUTPUT_MODE_ASPECT_RATIO_NONE:
|
||||||
|
return "none";
|
||||||
|
case WLR_OUTPUT_MODE_ASPECT_RATIO_4_3:
|
||||||
|
return "4:3";
|
||||||
|
case WLR_OUTPUT_MODE_ASPECT_RATIO_16_9:
|
||||||
|
return "16:9";
|
||||||
|
case WLR_OUTPUT_MODE_ASPECT_RATIO_64_27:
|
||||||
|
return "64:27";
|
||||||
|
case WLR_OUTPUT_MODE_ASPECT_RATIO_256_135:
|
||||||
|
return "256:135";
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_object *ipc_json_output_mode_description(
|
||||||
|
const struct wlr_output_mode *mode) {
|
||||||
|
const char *pic_ar =
|
||||||
|
ipc_json_output_mode_aspect_ratio_description(mode->picture_aspect_ratio);
|
||||||
|
json_object *mode_object = json_object_new_object();
|
||||||
|
json_object_object_add(mode_object, "width",
|
||||||
|
json_object_new_int(mode->width));
|
||||||
|
json_object_object_add(mode_object, "height",
|
||||||
|
json_object_new_int(mode->height));
|
||||||
|
json_object_object_add(mode_object, "refresh",
|
||||||
|
json_object_new_int(mode->refresh));
|
||||||
|
json_object_object_add(mode_object, "picture_aspect_ratio",
|
||||||
|
json_object_new_string(pic_ar));
|
||||||
|
return mode_object;
|
||||||
|
}
|
||||||
|
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
static const char *ipc_json_xwindow_type_description(struct sway_view *view) {
|
static const char *ipc_json_xwindow_type_description(struct sway_view *view) {
|
||||||
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
|
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
|
||||||
|
@ -242,23 +273,50 @@ static json_object *ipc_json_create_node(int id, const char* type, char *name,
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ipc_json_describe_wlr_output(struct wlr_output *wlr_output, json_object *object) {
|
||||||
|
json_object_object_add(object, "primary", json_object_new_boolean(false));
|
||||||
|
json_object_object_add(object, "make",
|
||||||
|
json_object_new_string(wlr_output->make ? wlr_output->make : "Unknown"));
|
||||||
|
json_object_object_add(object, "model",
|
||||||
|
json_object_new_string(wlr_output->model ? wlr_output->model : "Unknown"));
|
||||||
|
json_object_object_add(object, "serial",
|
||||||
|
json_object_new_string(wlr_output->serial ? wlr_output->serial : "Unknown"));
|
||||||
|
|
||||||
|
json_object *modes_array = json_object_new_array();
|
||||||
|
struct wlr_output_mode *mode;
|
||||||
|
wl_list_for_each(mode, &wlr_output->modes, link) {
|
||||||
|
json_object *mode_object = json_object_new_object();
|
||||||
|
json_object_object_add(mode_object, "width",
|
||||||
|
json_object_new_int(mode->width));
|
||||||
|
json_object_object_add(mode_object, "height",
|
||||||
|
json_object_new_int(mode->height));
|
||||||
|
json_object_object_add(mode_object, "refresh",
|
||||||
|
json_object_new_int(mode->refresh));
|
||||||
|
json_object_array_add(modes_array, mode_object);
|
||||||
|
}
|
||||||
|
json_object_object_add(object, "modes", modes_array);
|
||||||
|
}
|
||||||
|
|
||||||
static void ipc_json_describe_output(struct sway_output *output,
|
static void ipc_json_describe_output(struct sway_output *output,
|
||||||
json_object *object) {
|
json_object *object) {
|
||||||
|
ipc_json_describe_wlr_output(output->wlr_output, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ipc_json_describe_enabled_output(struct sway_output *output,
|
||||||
|
json_object *object) {
|
||||||
|
ipc_json_describe_output(output, object);
|
||||||
|
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
json_object_object_add(object, "non_desktop", json_object_new_boolean(false));
|
||||||
json_object_object_add(object, "active", json_object_new_boolean(true));
|
json_object_object_add(object, "active", json_object_new_boolean(true));
|
||||||
json_object_object_add(object, "dpms",
|
json_object_object_add(object, "dpms",
|
||||||
json_object_new_boolean(wlr_output->enabled));
|
json_object_new_boolean(wlr_output->enabled));
|
||||||
json_object_object_add(object, "primary", json_object_new_boolean(false));
|
json_object_object_add(object, "power",
|
||||||
|
json_object_new_boolean(wlr_output->enabled));
|
||||||
json_object_object_add(object, "layout", json_object_new_string("output"));
|
json_object_object_add(object, "layout", json_object_new_string("output"));
|
||||||
json_object_object_add(object, "orientation",
|
json_object_object_add(object, "orientation",
|
||||||
json_object_new_string(
|
json_object_new_string(
|
||||||
ipc_json_orientation_description(L_NONE)));
|
ipc_json_orientation_description(L_NONE)));
|
||||||
json_object_object_add(object, "make",
|
|
||||||
json_object_new_string(wlr_output->make));
|
|
||||||
json_object_object_add(object, "model",
|
|
||||||
json_object_new_string(wlr_output->model));
|
|
||||||
json_object_object_add(object, "serial",
|
|
||||||
json_object_new_string(wlr_output->serial));
|
|
||||||
json_object_object_add(object, "scale",
|
json_object_object_add(object, "scale",
|
||||||
json_object_new_double(wlr_output->scale));
|
json_object_new_double(wlr_output->scale));
|
||||||
json_object_object_add(object, "scale_filter",
|
json_object_object_add(object, "scale_filter",
|
||||||
|
@ -283,25 +341,26 @@ static void ipc_json_describe_output(struct sway_output *output,
|
||||||
json_object *modes_array = json_object_new_array();
|
json_object *modes_array = json_object_new_array();
|
||||||
struct wlr_output_mode *mode;
|
struct wlr_output_mode *mode;
|
||||||
wl_list_for_each(mode, &wlr_output->modes, link) {
|
wl_list_for_each(mode, &wlr_output->modes, link) {
|
||||||
json_object *mode_object = json_object_new_object();
|
json_object *mode_object =
|
||||||
json_object_object_add(mode_object, "width",
|
ipc_json_output_mode_description(mode);
|
||||||
json_object_new_int(mode->width));
|
|
||||||
json_object_object_add(mode_object, "height",
|
|
||||||
json_object_new_int(mode->height));
|
|
||||||
json_object_object_add(mode_object, "refresh",
|
|
||||||
json_object_new_int(mode->refresh));
|
|
||||||
json_object_array_add(modes_array, mode_object);
|
json_object_array_add(modes_array, mode_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object_object_add(object, "modes", modes_array);
|
json_object_object_add(object, "modes", modes_array);
|
||||||
|
|
||||||
json_object *current_mode_object = json_object_new_object();
|
json_object *current_mode_object;
|
||||||
json_object_object_add(current_mode_object, "width",
|
if (wlr_output->current_mode != NULL) {
|
||||||
json_object_new_int(wlr_output->width));
|
current_mode_object =
|
||||||
json_object_object_add(current_mode_object, "height",
|
ipc_json_output_mode_description(wlr_output->current_mode);
|
||||||
json_object_new_int(wlr_output->height));
|
} else {
|
||||||
json_object_object_add(current_mode_object, "refresh",
|
current_mode_object = json_object_new_object();
|
||||||
json_object_new_int(wlr_output->refresh));
|
json_object_object_add(current_mode_object, "width",
|
||||||
|
json_object_new_int(wlr_output->width));
|
||||||
|
json_object_object_add(current_mode_object, "height",
|
||||||
|
json_object_new_int(wlr_output->height));
|
||||||
|
json_object_object_add(current_mode_object, "refresh",
|
||||||
|
json_object_new_int(wlr_output->refresh));
|
||||||
|
}
|
||||||
json_object_object_add(object, "current_mode", current_mode_object);
|
json_object_object_add(object, "current_mode", current_mode_object);
|
||||||
|
|
||||||
struct sway_node *parent = node_get_parent(&output->node);
|
struct sway_node *parent = node_get_parent(&output->node);
|
||||||
|
@ -325,33 +384,15 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
|
||||||
|
|
||||||
json_object *object = json_object_new_object();
|
json_object *object = json_object_new_object();
|
||||||
|
|
||||||
|
ipc_json_describe_output(output, object);
|
||||||
|
|
||||||
|
json_object_object_add(object, "non_desktop", json_object_new_boolean(false));
|
||||||
json_object_object_add(object, "type", json_object_new_string("output"));
|
json_object_object_add(object, "type", json_object_new_string("output"));
|
||||||
json_object_object_add(object, "name",
|
json_object_object_add(object, "name",
|
||||||
json_object_new_string(wlr_output->name));
|
json_object_new_string(wlr_output->name));
|
||||||
json_object_object_add(object, "active", json_object_new_boolean(false));
|
json_object_object_add(object, "active", json_object_new_boolean(false));
|
||||||
json_object_object_add(object, "dpms", json_object_new_boolean(false));
|
json_object_object_add(object, "dpms", json_object_new_boolean(false));
|
||||||
json_object_object_add(object, "primary", json_object_new_boolean(false));
|
json_object_object_add(object, "power", json_object_new_boolean(false));
|
||||||
json_object_object_add(object, "make",
|
|
||||||
json_object_new_string(wlr_output->make));
|
|
||||||
json_object_object_add(object, "model",
|
|
||||||
json_object_new_string(wlr_output->model));
|
|
||||||
json_object_object_add(object, "serial",
|
|
||||||
json_object_new_string(wlr_output->serial));
|
|
||||||
|
|
||||||
json_object *modes_array = json_object_new_array();
|
|
||||||
struct wlr_output_mode *mode;
|
|
||||||
wl_list_for_each(mode, &wlr_output->modes, link) {
|
|
||||||
json_object *mode_object = json_object_new_object();
|
|
||||||
json_object_object_add(mode_object, "width",
|
|
||||||
json_object_new_int(mode->width));
|
|
||||||
json_object_object_add(mode_object, "height",
|
|
||||||
json_object_new_int(mode->height));
|
|
||||||
json_object_object_add(mode_object, "refresh",
|
|
||||||
json_object_new_int(mode->refresh));
|
|
||||||
json_object_array_add(modes_array, mode_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_object_object_add(object, "modes", modes_array);
|
|
||||||
|
|
||||||
json_object_object_add(object, "current_workspace", NULL);
|
json_object_object_add(object, "current_workspace", NULL);
|
||||||
|
|
||||||
|
@ -367,6 +408,21 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json_object *ipc_json_describe_non_desktop_output(struct sway_output_non_desktop *output) {
|
||||||
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
|
||||||
|
json_object *object = json_object_new_object();
|
||||||
|
|
||||||
|
ipc_json_describe_wlr_output(wlr_output, object);
|
||||||
|
|
||||||
|
json_object_object_add(object, "non_desktop", json_object_new_boolean(true));
|
||||||
|
json_object_object_add(object, "type", json_object_new_string("output"));
|
||||||
|
json_object_object_add(object, "name",
|
||||||
|
json_object_new_string(wlr_output->name));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
static json_object *ipc_json_describe_scratchpad_output(void) {
|
static json_object *ipc_json_describe_scratchpad_output(void) {
|
||||||
struct wlr_box box;
|
struct wlr_box box;
|
||||||
root_get_box(root, &box);
|
root_get_box(root, &box);
|
||||||
|
@ -453,7 +509,9 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace,
|
||||||
|
|
||||||
static void get_deco_rect(struct sway_container *c, struct wlr_box *deco_rect) {
|
static void get_deco_rect(struct sway_container *c, struct wlr_box *deco_rect) {
|
||||||
enum sway_container_layout parent_layout = container_parent_layout(c);
|
enum sway_container_layout parent_layout = container_parent_layout(c);
|
||||||
bool tab_or_stack = parent_layout == L_TABBED || parent_layout == L_STACKED;
|
list_t *siblings = container_get_siblings(c);
|
||||||
|
bool tab_or_stack = (parent_layout == L_TABBED || parent_layout == L_STACKED)
|
||||||
|
&& ((siblings && siblings->length > 1) || !config->hide_lone_tab);
|
||||||
if (((!tab_or_stack || container_is_floating(c)) &&
|
if (((!tab_or_stack || container_is_floating(c)) &&
|
||||||
c->current.border != B_NORMAL) ||
|
c->current.border != B_NORMAL) ||
|
||||||
c->pending.fullscreen_mode != FULLSCREEN_NONE ||
|
c->pending.fullscreen_mode != FULLSCREEN_NONE ||
|
||||||
|
@ -706,7 +764,7 @@ json_object *ipc_json_describe_node(struct sway_node *node) {
|
||||||
case N_ROOT:
|
case N_ROOT:
|
||||||
break;
|
break;
|
||||||
case N_OUTPUT:
|
case N_OUTPUT:
|
||||||
ipc_json_describe_output(node->sway_output, object);
|
ipc_json_describe_enabled_output(node->sway_output, object);
|
||||||
break;
|
break;
|
||||||
case N_CONTAINER:
|
case N_CONTAINER:
|
||||||
ipc_json_describe_container(node->sway_container, object);
|
ipc_json_describe_container(node->sway_container, object);
|
||||||
|
@ -942,6 +1000,19 @@ static json_object *describe_libinput_device(struct libinput_device *device) {
|
||||||
json_object_object_add(object, "dwt", json_object_new_string(dwt));
|
json_object_object_add(object, "dwt", json_object_new_string(dwt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (libinput_device_config_dwtp_is_available(device)) {
|
||||||
|
const char *dwtp = "unknown";
|
||||||
|
switch (libinput_device_config_dwtp_get_enabled(device)) {
|
||||||
|
case LIBINPUT_CONFIG_DWTP_ENABLED:
|
||||||
|
dwtp = "enabled";
|
||||||
|
break;
|
||||||
|
case LIBINPUT_CONFIG_DWTP_DISABLED:
|
||||||
|
dwtp = "disabled";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
json_object_object_add(object, "dwtp", json_object_new_string(dwtp));
|
||||||
|
}
|
||||||
|
|
||||||
if (libinput_device_config_calibration_has_matrix(device)) {
|
if (libinput_device_config_calibration_has_matrix(device)) {
|
||||||
float matrix[6];
|
float matrix[6];
|
||||||
libinput_device_config_calibration_get_matrix(device, matrix);
|
libinput_device_config_calibration_get_matrix(device, matrix);
|
||||||
|
@ -977,10 +1048,16 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
|
||||||
input_device_get_type(device)));
|
input_device_get_type(device)));
|
||||||
|
|
||||||
if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
|
if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
|
||||||
struct wlr_keyboard *keyboard = device->wlr_device->keyboard;
|
struct wlr_keyboard *keyboard =
|
||||||
|
wlr_keyboard_from_input_device(device->wlr_device);
|
||||||
struct xkb_keymap *keymap = keyboard->keymap;
|
struct xkb_keymap *keymap = keyboard->keymap;
|
||||||
struct xkb_state *state = keyboard->xkb_state;
|
struct xkb_state *state = keyboard->xkb_state;
|
||||||
|
|
||||||
|
json_object_object_add(object, "repeat_delay",
|
||||||
|
json_object_new_int(keyboard->repeat_info.delay));
|
||||||
|
json_object_object_add(object, "repeat_rate",
|
||||||
|
json_object_new_int(keyboard->repeat_info.rate));
|
||||||
|
|
||||||
json_object *layouts_arr = json_object_new_array();
|
json_object *layouts_arr = json_object_new_array();
|
||||||
json_object_object_add(object, "xkb_layout_names", layouts_arr);
|
json_object_object_add(object, "xkb_layout_names", layouts_arr);
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,6 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
|
||||||
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
||||||
(void) fd;
|
(void) fd;
|
||||||
struct sway_server *server = data;
|
struct sway_server *server = data;
|
||||||
sway_log(SWAY_DEBUG, "Event on IPC listening socket");
|
|
||||||
assert(mask == WL_EVENT_READABLE);
|
assert(mask == WL_EVENT_READABLE);
|
||||||
|
|
||||||
int client_fd = accept(ipc_socket, NULL, NULL);
|
int client_fd = accept(ipc_socket, NULL, NULL);
|
||||||
|
@ -211,13 +210,10 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & WL_EVENT_HANGUP) {
|
if (mask & WL_EVENT_HANGUP) {
|
||||||
sway_log(SWAY_DEBUG, "Client %d hung up", client->fd);
|
|
||||||
ipc_client_disconnect(client);
|
ipc_client_disconnect(client);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Client %d readable", client->fd);
|
|
||||||
|
|
||||||
int read_available;
|
int read_available;
|
||||||
if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
|
if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
|
||||||
sway_log_errno(SWAY_INFO, "Unable to read IPC socket buffer size");
|
sway_log_errno(SWAY_INFO, "Unable to read IPC socket buffer size");
|
||||||
|
@ -523,7 +519,6 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & WL_EVENT_HANGUP) {
|
if (mask & WL_EVENT_HANGUP) {
|
||||||
sway_log(SWAY_DEBUG, "Client %d hung up", client->fd);
|
|
||||||
ipc_client_disconnect(client);
|
ipc_client_disconnect(client);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -532,8 +527,6 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Client %d writable", client->fd);
|
|
||||||
|
|
||||||
ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
|
ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
|
||||||
|
|
||||||
if (written == -1 && errno == EAGAIN) {
|
if (written == -1 && errno == EAGAIN) {
|
||||||
|
@ -692,6 +685,12 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
||||||
ipc_json_describe_disabled_output(output));
|
ipc_json_describe_disabled_output(output));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < root->non_desktop_outputs->length; i++) {
|
||||||
|
struct sway_output_non_desktop *non_desktop_output = root->non_desktop_outputs->items[i];
|
||||||
|
json_object_array_add(outputs, ipc_json_describe_non_desktop_output(non_desktop_output));
|
||||||
|
}
|
||||||
|
|
||||||
const char *json_string = json_object_to_json_string(outputs);
|
const char *json_string = json_object_to_json_string(outputs);
|
||||||
ipc_send_reply(client, payload_type, json_string,
|
ipc_send_reply(client, payload_type, json_string,
|
||||||
(uint32_t)strlen(json_string));
|
(uint32_t)strlen(json_string));
|
||||||
|
@ -955,7 +954,5 @@ bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_typ
|
||||||
ipc_client_handle_writable, client);
|
ipc_client_handle_writable, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Added IPC reply of type 0x%x to client %d queue: %s",
|
|
||||||
payload_type, client->fd, payload);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
225
sway/lock.c
Normal file
225
sway/lock.c
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <assert.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "sway/input/keyboard.h"
|
||||||
|
#include "sway/input/seat.h"
|
||||||
|
#include "sway/output.h"
|
||||||
|
#include "sway/server.h"
|
||||||
|
|
||||||
|
struct sway_session_lock_surface {
|
||||||
|
struct wlr_session_lock_surface_v1 *lock_surface;
|
||||||
|
struct sway_output *output;
|
||||||
|
struct wlr_surface *surface;
|
||||||
|
struct wl_listener map;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener surface_commit;
|
||||||
|
struct wl_listener output_mode;
|
||||||
|
struct wl_listener output_commit;
|
||||||
|
struct wl_listener output_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void set_lock_focused_surface(struct wlr_surface *focused) {
|
||||||
|
server.session_lock.focused = focused;
|
||||||
|
|
||||||
|
struct sway_seat *seat;
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat_set_focus_surface(seat, focused, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_surface_map(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, map);
|
||||||
|
if (server.session_lock.focused == NULL) {
|
||||||
|
set_lock_focused_surface(surf->surface);
|
||||||
|
}
|
||||||
|
output_damage_whole(surf->output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_surface_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, surface_commit);
|
||||||
|
output_damage_surface(surf->output, 0, 0, surf->surface, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_mode(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_mode);
|
||||||
|
wlr_session_lock_surface_v1_configure(surf->lock_surface,
|
||||||
|
surf->output->width, surf->output->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_output_event_commit *event = data;
|
||||||
|
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_commit);
|
||||||
|
if (event->committed & (
|
||||||
|
WLR_OUTPUT_STATE_MODE |
|
||||||
|
WLR_OUTPUT_STATE_SCALE |
|
||||||
|
WLR_OUTPUT_STATE_TRANSFORM)) {
|
||||||
|
wlr_session_lock_surface_v1_configure(surf->lock_surface,
|
||||||
|
surf->output->width, surf->output->height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_lock_surface(struct sway_session_lock_surface *surf) {
|
||||||
|
// Move the seat focus to another surface if one is available
|
||||||
|
if (server.session_lock.focused == surf->surface) {
|
||||||
|
struct wlr_surface *next_focus = NULL;
|
||||||
|
|
||||||
|
struct wlr_session_lock_surface_v1 *other;
|
||||||
|
wl_list_for_each(other, &server.session_lock.lock->surfaces, link) {
|
||||||
|
if (other != surf->lock_surface && other->mapped) {
|
||||||
|
next_focus = other->surface;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_lock_focused_surface(next_focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&surf->map.link);
|
||||||
|
wl_list_remove(&surf->destroy.link);
|
||||||
|
wl_list_remove(&surf->surface_commit.link);
|
||||||
|
wl_list_remove(&surf->output_mode.link);
|
||||||
|
wl_list_remove(&surf->output_commit.link);
|
||||||
|
wl_list_remove(&surf->output_destroy.link);
|
||||||
|
output_damage_whole(surf->output);
|
||||||
|
free(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_surface_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_session_lock_surface *surf = wl_container_of(listener, surf, destroy);
|
||||||
|
destroy_lock_surface(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_session_lock_surface *surf =
|
||||||
|
wl_container_of(listener, surf, output_destroy);
|
||||||
|
destroy_lock_surface(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_new_surface(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_session_lock_surface_v1 *lock_surface = data;
|
||||||
|
struct sway_session_lock_surface *surf = calloc(1, sizeof(*surf));
|
||||||
|
if (surf == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sway_log(SWAY_DEBUG, "new lock layer surface");
|
||||||
|
|
||||||
|
struct sway_output *output = lock_surface->output->data;
|
||||||
|
wlr_session_lock_surface_v1_configure(lock_surface, output->width, output->height);
|
||||||
|
|
||||||
|
surf->lock_surface = lock_surface;
|
||||||
|
surf->surface = lock_surface->surface;
|
||||||
|
surf->output = output;
|
||||||
|
surf->map.notify = handle_surface_map;
|
||||||
|
wl_signal_add(&lock_surface->events.map, &surf->map);
|
||||||
|
surf->destroy.notify = handle_surface_destroy;
|
||||||
|
wl_signal_add(&lock_surface->events.destroy, &surf->destroy);
|
||||||
|
surf->surface_commit.notify = handle_surface_commit;
|
||||||
|
wl_signal_add(&surf->surface->events.commit, &surf->surface_commit);
|
||||||
|
surf->output_mode.notify = handle_output_mode;
|
||||||
|
wl_signal_add(&output->wlr_output->events.mode, &surf->output_mode);
|
||||||
|
surf->output_commit.notify = handle_output_commit;
|
||||||
|
wl_signal_add(&output->wlr_output->events.commit, &surf->output_commit);
|
||||||
|
surf->output_destroy.notify = handle_output_destroy;
|
||||||
|
wl_signal_add(&output->node.events.destroy, &surf->output_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_unlock(struct wl_listener *listener, void *data) {
|
||||||
|
sway_log(SWAY_DEBUG, "session unlocked");
|
||||||
|
server.session_lock.locked = false;
|
||||||
|
server.session_lock.lock = NULL;
|
||||||
|
server.session_lock.focused = NULL;
|
||||||
|
|
||||||
|
wl_list_remove(&server.session_lock.lock_new_surface.link);
|
||||||
|
wl_list_remove(&server.session_lock.lock_unlock.link);
|
||||||
|
wl_list_remove(&server.session_lock.lock_destroy.link);
|
||||||
|
|
||||||
|
struct sway_seat *seat;
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat_set_exclusive_client(seat, NULL);
|
||||||
|
// copied from seat_set_focus_layer -- deduplicate?
|
||||||
|
struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);
|
||||||
|
if (previous) {
|
||||||
|
// Hack to get seat to re-focus the return value of get_focus
|
||||||
|
seat_set_focus(seat, NULL);
|
||||||
|
seat_set_focus(seat, previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// redraw everything
|
||||||
|
for (int i = 0; i < root->outputs->length; ++i) {
|
||||||
|
struct sway_output *output = root->outputs->items[i];
|
||||||
|
output_damage_whole(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_abandon(struct wl_listener *listener, void *data) {
|
||||||
|
sway_log(SWAY_INFO, "session lock abandoned");
|
||||||
|
server.session_lock.lock = NULL;
|
||||||
|
server.session_lock.focused = NULL;
|
||||||
|
|
||||||
|
wl_list_remove(&server.session_lock.lock_new_surface.link);
|
||||||
|
wl_list_remove(&server.session_lock.lock_unlock.link);
|
||||||
|
wl_list_remove(&server.session_lock.lock_destroy.link);
|
||||||
|
|
||||||
|
struct sway_seat *seat;
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat->exclusive_client = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// redraw everything
|
||||||
|
for (int i = 0; i < root->outputs->length; ++i) {
|
||||||
|
struct sway_output *output = root->outputs->items[i];
|
||||||
|
output_damage_whole(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_session_lock(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_session_lock_v1 *lock = data;
|
||||||
|
struct wl_client *client = wl_resource_get_client(lock->resource);
|
||||||
|
|
||||||
|
if (server.session_lock.lock) {
|
||||||
|
wlr_session_lock_v1_destroy(lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sway_log(SWAY_DEBUG, "session locked");
|
||||||
|
server.session_lock.locked = true;
|
||||||
|
server.session_lock.lock = lock;
|
||||||
|
|
||||||
|
struct sway_seat *seat;
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat_set_exclusive_client(seat, client);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_add(&lock->events.new_surface, &server.session_lock.lock_new_surface);
|
||||||
|
wl_signal_add(&lock->events.unlock, &server.session_lock.lock_unlock);
|
||||||
|
wl_signal_add(&lock->events.destroy, &server.session_lock.lock_destroy);
|
||||||
|
|
||||||
|
wlr_session_lock_v1_send_locked(lock);
|
||||||
|
|
||||||
|
// redraw everything
|
||||||
|
for (int i = 0; i < root->outputs->length; ++i) {
|
||||||
|
struct sway_output *output = root->outputs->items[i];
|
||||||
|
output_damage_whole(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_session_lock_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
assert(server.session_lock.lock == NULL);
|
||||||
|
wl_list_remove(&server.session_lock.new_lock.link);
|
||||||
|
wl_list_remove(&server.session_lock.manager_destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sway_session_lock_init(void) {
|
||||||
|
server.session_lock.manager = wlr_session_lock_manager_v1_create(server.wl_display);
|
||||||
|
|
||||||
|
server.session_lock.lock_new_surface.notify = handle_new_surface;
|
||||||
|
server.session_lock.lock_unlock.notify = handle_unlock;
|
||||||
|
server.session_lock.lock_destroy.notify = handle_abandon;
|
||||||
|
server.session_lock.new_lock.notify = handle_session_lock;
|
||||||
|
server.session_lock.manager_destroy.notify = handle_session_lock_destroy;
|
||||||
|
wl_signal_add(&server.session_lock.manager->events.new_lock,
|
||||||
|
&server.session_lock.new_lock);
|
||||||
|
wl_signal_add(&server.session_lock.manager->events.destroy,
|
||||||
|
&server.session_lock.manager_destroy);
|
||||||
|
}
|
108
sway/main.c
108
sway/main.c
|
@ -150,27 +150,17 @@ static void log_kernel(void) {
|
||||||
pclose(f);
|
pclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool detect_suid(void) {
|
||||||
static bool drop_permissions(void) {
|
if (geteuid() != 0 && getegid() != 0) {
|
||||||
if (getuid() != geteuid() || getgid() != getegid()) {
|
|
||||||
sway_log(SWAY_ERROR, "!!! DEPRECATION WARNING: "
|
|
||||||
"SUID privilege drop will be removed in a future release, please migrate to seatd-launch");
|
|
||||||
|
|
||||||
// Set the gid and uid in the correct order.
|
|
||||||
if (setgid(getgid()) != 0) {
|
|
||||||
sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (setuid(getuid()) != 0) {
|
|
||||||
sway_log(SWAY_ERROR, "Unable to drop root user, refusing to start");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (setgid(0) != -1 || setuid(0) != -1) {
|
|
||||||
sway_log(SWAY_ERROR, "Unable to drop root (we shouldn't be able to "
|
|
||||||
"restore it after setuid), refusing to start");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getuid() == geteuid() && getgid() == getegid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sway_log(SWAY_ERROR, "SUID operation is no longer supported, refusing to start. "
|
||||||
|
"This check will be removed in a future release.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,35 +230,35 @@ static void handle_wlr_log(enum wlr_log_importance importance,
|
||||||
_sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args);
|
_sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
static const struct option long_options[] = {
|
||||||
static int verbose = 0, debug = 0, validate = 0, allow_unsupported_gpu = 0;
|
{"help", no_argument, NULL, 'h'},
|
||||||
|
{"config", required_argument, NULL, 'c'},
|
||||||
|
{"validate", no_argument, NULL, 'C'},
|
||||||
|
{"debug", no_argument, NULL, 'd'},
|
||||||
|
{"version", no_argument, NULL, 'v'},
|
||||||
|
{"verbose", no_argument, NULL, 'V'},
|
||||||
|
{"get-socketpath", no_argument, NULL, 'p'},
|
||||||
|
{"unsupported-gpu", no_argument, NULL, 'u'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
static const struct option long_options[] = {
|
static const char usage[] =
|
||||||
{"help", no_argument, NULL, 'h'},
|
"Usage: sway [options] [command]\n"
|
||||||
{"config", required_argument, NULL, 'c'},
|
"\n"
|
||||||
{"validate", no_argument, NULL, 'C'},
|
" -h, --help Show help message and quit.\n"
|
||||||
{"debug", no_argument, NULL, 'd'},
|
" -c, --config <config> Specify a config file.\n"
|
||||||
{"version", no_argument, NULL, 'v'},
|
" -C, --validate Check the validity of the config file, then exit.\n"
|
||||||
{"verbose", no_argument, NULL, 'V'},
|
" -d, --debug Enables full logging, including debug information.\n"
|
||||||
{"get-socketpath", no_argument, NULL, 'p'},
|
" -v, --version Show the version number and quit.\n"
|
||||||
{"unsupported-gpu", no_argument, NULL, 'u'},
|
" -V, --verbose Enables more verbose logging.\n"
|
||||||
{0, 0, 0, 0}
|
" --get-socketpath Gets the IPC socket path and prints it, then exits.\n"
|
||||||
};
|
"\n";
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
static bool verbose = false, debug = false, validate = false, allow_unsupported_gpu = false;
|
||||||
|
|
||||||
char *config_path = NULL;
|
char *config_path = NULL;
|
||||||
|
|
||||||
const char* usage =
|
|
||||||
"Usage: sway [options] [command]\n"
|
|
||||||
"\n"
|
|
||||||
" -h, --help Show help message and quit.\n"
|
|
||||||
" -c, --config <config> Specify a config file.\n"
|
|
||||||
" -C, --validate Check the validity of the config file, then exit.\n"
|
|
||||||
" -d, --debug Enables full logging, including debug information.\n"
|
|
||||||
" -v, --version Show the version number and quit.\n"
|
|
||||||
" -V, --verbose Enables more verbose logging.\n"
|
|
||||||
" --get-socketpath Gets the IPC socket path and prints it, then exits.\n"
|
|
||||||
"\n";
|
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -286,25 +276,25 @@ int main(int argc, char **argv) {
|
||||||
config_path = strdup(optarg);
|
config_path = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'C': // validate
|
case 'C': // validate
|
||||||
validate = 1;
|
validate = true;
|
||||||
break;
|
break;
|
||||||
case 'd': // debug
|
case 'd': // debug
|
||||||
debug = 1;
|
debug = true;
|
||||||
break;
|
break;
|
||||||
case 'D': // extended debug options
|
case 'D': // extended debug options
|
||||||
enable_debug_flag(optarg);
|
enable_debug_flag(optarg);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
allow_unsupported_gpu = 1;
|
allow_unsupported_gpu = true;
|
||||||
break;
|
break;
|
||||||
case 'v': // version
|
case 'v': // version
|
||||||
printf("sway version " SWAY_VERSION "\n");
|
printf("sway version " SWAY_VERSION "\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
break;
|
break;
|
||||||
case 'V': // verbose
|
case 'V': // verbose
|
||||||
verbose = 1;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
case 'p': ; // --get-socketpath
|
case 'p': // --get-socketpath
|
||||||
if (getenv("SWAYSOCK")) {
|
if (getenv("SWAYSOCK")) {
|
||||||
printf("%s\n", getenv("SWAYSOCK"));
|
printf("%s\n", getenv("SWAYSOCK"));
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
@ -319,6 +309,11 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SUID operation is deprecated, so block it for now.
|
||||||
|
if (detect_suid()) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the
|
// Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the
|
||||||
// clear error message (when not running as an IPC client).
|
// clear error message (when not running as an IPC client).
|
||||||
if (!getenv("XDG_RUNTIME_DIR") && optind == argc) {
|
if (!getenv("XDG_RUNTIME_DIR") && optind == argc) {
|
||||||
|
@ -357,9 +352,6 @@ int main(int argc, char **argv) {
|
||||||
"`sway -d 2>sway.log`.");
|
"`sway -d 2>sway.log`.");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (!drop_permissions()) {
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
char *socket_path = getenv("SWAYSOCK");
|
char *socket_path = getenv("SWAYSOCK");
|
||||||
if (!socket_path) {
|
if (!socket_path) {
|
||||||
sway_log(SWAY_ERROR, "Unable to retrieve socket path");
|
sway_log(SWAY_ERROR, "Unable to retrieve socket path");
|
||||||
|
@ -372,16 +364,6 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_proprietary(allow_unsupported_gpu);
|
detect_proprietary(allow_unsupported_gpu);
|
||||||
|
|
||||||
if (!server_privileged_prepare(&server)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drop_permissions()) {
|
|
||||||
server_fini(&server);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
increase_nofile_limit();
|
increase_nofile_limit();
|
||||||
|
|
||||||
// handle SIGTERM signals
|
// handle SIGTERM signals
|
||||||
|
@ -413,6 +395,8 @@ int main(int argc, char **argv) {
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_rr_scheduling();
|
||||||
|
|
||||||
if (!server_start(&server)) {
|
if (!server_start(&server)) {
|
||||||
sway_terminate(EXIT_FAILURE);
|
sway_terminate(EXIT_FAILURE);
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
|
|
457
sway/meson.build
457
sway/meson.build
|
@ -1,245 +1,252 @@
|
||||||
sway_sources = files(
|
sway_sources = files(
|
||||||
'commands.c',
|
'commands.c',
|
||||||
'config.c',
|
'config.c',
|
||||||
'criteria.c',
|
'criteria.c',
|
||||||
'decoration.c',
|
'decoration.c',
|
||||||
'ipc-json.c',
|
'ipc-json.c',
|
||||||
'ipc-server.c',
|
'ipc-server.c',
|
||||||
'main.c',
|
'lock.c',
|
||||||
'server.c',
|
'main.c',
|
||||||
'swaynag.c',
|
'realtime.c',
|
||||||
'xdg_activation_v1.c',
|
'server.c',
|
||||||
'xdg_decoration.c',
|
'swaynag.c',
|
||||||
|
'xdg_activation_v1.c',
|
||||||
|
'xdg_decoration.c',
|
||||||
|
|
||||||
'desktop/desktop.c',
|
'desktop/desktop.c',
|
||||||
'desktop/fx_renderer.c',
|
'desktop/fx_renderer.c',
|
||||||
'desktop/idle_inhibit_v1.c',
|
'desktop/idle_inhibit_v1.c',
|
||||||
'desktop/layer_shell.c',
|
'desktop/layer_shell.c',
|
||||||
'desktop/output.c',
|
'desktop/output.c',
|
||||||
'desktop/render.c',
|
'desktop/render.c',
|
||||||
'desktop/surface.c',
|
'desktop/surface.c',
|
||||||
'desktop/transaction.c',
|
'desktop/transaction.c',
|
||||||
'desktop/xdg_shell.c',
|
'desktop/xdg_shell.c',
|
||||||
|
'desktop/launcher.c',
|
||||||
|
'input/input-manager.c',
|
||||||
|
'input/cursor.c',
|
||||||
|
'input/keyboard.c',
|
||||||
|
'input/libinput.c',
|
||||||
|
'input/seat.c',
|
||||||
|
'input/seatop_default.c',
|
||||||
|
'input/seatop_down.c',
|
||||||
|
'input/seatop_move_floating.c',
|
||||||
|
'input/seatop_move_tiling.c',
|
||||||
|
'input/seatop_resize_floating.c',
|
||||||
|
'input/seatop_resize_tiling.c',
|
||||||
|
'input/switch.c',
|
||||||
|
'input/tablet.c',
|
||||||
|
'input/text_input.c',
|
||||||
|
|
||||||
'input/input-manager.c',
|
'config/bar.c',
|
||||||
'input/cursor.c',
|
'config/output.c',
|
||||||
'input/keyboard.c',
|
'config/seat.c',
|
||||||
'input/libinput.c',
|
'config/input.c',
|
||||||
'input/seat.c',
|
|
||||||
'input/seatop_default.c',
|
|
||||||
'input/seatop_down.c',
|
|
||||||
'input/seatop_move_floating.c',
|
|
||||||
'input/seatop_move_tiling.c',
|
|
||||||
'input/seatop_resize_floating.c',
|
|
||||||
'input/seatop_resize_tiling.c',
|
|
||||||
'input/switch.c',
|
|
||||||
'input/tablet.c',
|
|
||||||
'input/text_input.c',
|
|
||||||
|
|
||||||
'config/bar.c',
|
'commands/assign.c',
|
||||||
'config/output.c',
|
'commands/bar.c',
|
||||||
'config/seat.c',
|
'commands/bind.c',
|
||||||
'config/input.c',
|
'commands/border.c',
|
||||||
|
'commands/client.c',
|
||||||
|
'commands/corner_radius.c',
|
||||||
|
'commands/create_output.c',
|
||||||
|
'commands/default_border.c',
|
||||||
|
'commands/default_floating_border.c',
|
||||||
|
'commands/default_orientation.c',
|
||||||
|
'commands/dim_inactive.c',
|
||||||
|
'commands/dim_inactive_colors.c',
|
||||||
|
'commands/exit.c',
|
||||||
|
'commands/exec.c',
|
||||||
|
'commands/exec_always.c',
|
||||||
|
'commands/floating.c',
|
||||||
|
'commands/floating_minmax_size.c',
|
||||||
|
'commands/floating_modifier.c',
|
||||||
|
'commands/focus.c',
|
||||||
|
'commands/focus_follows_mouse.c',
|
||||||
|
'commands/focus_on_window_activation.c',
|
||||||
|
'commands/focus_wrapping.c',
|
||||||
|
'commands/font.c',
|
||||||
|
'commands/for_window.c',
|
||||||
|
'commands/force_display_urgency_hint.c',
|
||||||
|
'commands/force_focus_wrapping.c',
|
||||||
|
'commands/fullscreen.c',
|
||||||
|
'commands/gaps.c',
|
||||||
|
'commands/gesture.c',
|
||||||
|
'commands/hide_edge_borders.c',
|
||||||
|
'commands/inhibit_idle.c',
|
||||||
|
'commands/kill.c',
|
||||||
|
'commands/mark.c',
|
||||||
|
'commands/max_render_time.c',
|
||||||
|
'commands/opacity.c',
|
||||||
|
'commands/include.c',
|
||||||
|
'commands/input.c',
|
||||||
|
'commands/layout.c',
|
||||||
|
'commands/mode.c',
|
||||||
|
'commands/mouse_warping.c',
|
||||||
|
'commands/move.c',
|
||||||
|
'commands/new_float.c',
|
||||||
|
'commands/new_window.c',
|
||||||
|
'commands/no_focus.c',
|
||||||
|
'commands/nop.c',
|
||||||
|
'commands/output.c',
|
||||||
|
'commands/popup_during_fullscreen.c',
|
||||||
|
'commands/reload.c',
|
||||||
|
'commands/rename.c',
|
||||||
|
'commands/resize.c',
|
||||||
|
'commands/saturation.c',
|
||||||
|
'commands/scratchpad.c',
|
||||||
|
'commands/seat.c',
|
||||||
|
'commands/seat/attach.c',
|
||||||
|
'commands/seat/cursor.c',
|
||||||
|
'commands/seat/fallback.c',
|
||||||
|
'commands/seat/hide_cursor.c',
|
||||||
|
'commands/seat/idle.c',
|
||||||
|
'commands/seat/keyboard_grouping.c',
|
||||||
|
'commands/seat/pointer_constraint.c',
|
||||||
|
'commands/seat/shortcuts_inhibitor.c',
|
||||||
|
'commands/seat/xcursor_theme.c',
|
||||||
|
'commands/set.c',
|
||||||
|
'commands/show_marks.c',
|
||||||
|
'commands/shortcuts_inhibitor.c',
|
||||||
|
'commands/smart_borders.c',
|
||||||
|
'commands/smart_gaps.c',
|
||||||
|
'commands/split.c',
|
||||||
|
'commands/sticky.c',
|
||||||
|
'commands/swaybg_command.c',
|
||||||
|
'commands/swaynag_command.c',
|
||||||
|
'commands/swap.c',
|
||||||
|
'commands/tiling_drag.c',
|
||||||
|
'commands/tiling_drag_threshold.c',
|
||||||
|
'commands/title_align.c',
|
||||||
|
'commands/title_format.c',
|
||||||
|
'commands/titlebar_border_thickness.c',
|
||||||
|
'commands/titlebar_padding.c',
|
||||||
|
'commands/unmark.c',
|
||||||
|
'commands/urgent.c',
|
||||||
|
'commands/workspace.c',
|
||||||
|
'commands/workspace_layout.c',
|
||||||
|
'commands/ws_auto_back_and_forth.c',
|
||||||
|
'commands/xwayland.c',
|
||||||
|
|
||||||
'commands/assign.c',
|
'commands/bar/bind.c',
|
||||||
'commands/bar.c',
|
'commands/bar/binding_mode_indicator.c',
|
||||||
'commands/bind.c',
|
'commands/bar/colors.c',
|
||||||
'commands/border.c',
|
'commands/bar/font.c',
|
||||||
'commands/client.c',
|
'commands/bar/gaps.c',
|
||||||
'commands/corner_radius.c',
|
'commands/bar/height.c',
|
||||||
'commands/create_output.c',
|
'commands/bar/hidden_state.c',
|
||||||
'commands/default_border.c',
|
'commands/bar/icon_theme.c',
|
||||||
'commands/default_floating_border.c',
|
'commands/bar/id.c',
|
||||||
'commands/default_orientation.c',
|
'commands/bar/mode.c',
|
||||||
'commands/dim_inactive.c',
|
'commands/bar/modifier.c',
|
||||||
'commands/dim_inactive_colors.c',
|
'commands/bar/output.c',
|
||||||
'commands/exit.c',
|
'commands/bar/pango_markup.c',
|
||||||
'commands/exec.c',
|
'commands/bar/position.c',
|
||||||
'commands/exec_always.c',
|
'commands/bar/separator_symbol.c',
|
||||||
'commands/floating.c',
|
'commands/bar/status_command.c',
|
||||||
'commands/floating_minmax_size.c',
|
'commands/bar/status_edge_padding.c',
|
||||||
'commands/floating_modifier.c',
|
'commands/bar/status_padding.c',
|
||||||
'commands/focus.c',
|
'commands/bar/strip_workspace_numbers.c',
|
||||||
'commands/focus_follows_mouse.c',
|
'commands/bar/strip_workspace_name.c',
|
||||||
'commands/focus_on_window_activation.c',
|
'commands/bar/swaybar_command.c',
|
||||||
'commands/focus_wrapping.c',
|
'commands/bar/tray_bind.c',
|
||||||
'commands/font.c',
|
'commands/bar/tray_output.c',
|
||||||
'commands/for_window.c',
|
'commands/bar/tray_padding.c',
|
||||||
'commands/force_display_urgency_hint.c',
|
'commands/bar/workspace_buttons.c',
|
||||||
'commands/force_focus_wrapping.c',
|
'commands/bar/workspace_min_width.c',
|
||||||
'commands/fullscreen.c',
|
'commands/bar/wrap_scroll.c',
|
||||||
'commands/gaps.c',
|
|
||||||
'commands/hide_edge_borders.c',
|
|
||||||
'commands/inhibit_idle.c',
|
|
||||||
'commands/kill.c',
|
|
||||||
'commands/mark.c',
|
|
||||||
'commands/max_render_time.c',
|
|
||||||
'commands/opacity.c',
|
|
||||||
'commands/saturation.c',
|
|
||||||
'commands/include.c',
|
|
||||||
'commands/input.c',
|
|
||||||
'commands/layout.c',
|
|
||||||
'commands/mode.c',
|
|
||||||
'commands/mouse_warping.c',
|
|
||||||
'commands/move.c',
|
|
||||||
'commands/new_float.c',
|
|
||||||
'commands/new_window.c',
|
|
||||||
'commands/no_focus.c',
|
|
||||||
'commands/nop.c',
|
|
||||||
'commands/output.c',
|
|
||||||
'commands/popup_during_fullscreen.c',
|
|
||||||
'commands/reload.c',
|
|
||||||
'commands/rename.c',
|
|
||||||
'commands/resize.c',
|
|
||||||
'commands/scratchpad.c',
|
|
||||||
'commands/seat.c',
|
|
||||||
'commands/seat/attach.c',
|
|
||||||
'commands/seat/cursor.c',
|
|
||||||
'commands/seat/fallback.c',
|
|
||||||
'commands/seat/hide_cursor.c',
|
|
||||||
'commands/seat/idle.c',
|
|
||||||
'commands/seat/keyboard_grouping.c',
|
|
||||||
'commands/seat/pointer_constraint.c',
|
|
||||||
'commands/seat/shortcuts_inhibitor.c',
|
|
||||||
'commands/seat/xcursor_theme.c',
|
|
||||||
'commands/set.c',
|
|
||||||
'commands/show_marks.c',
|
|
||||||
'commands/shortcuts_inhibitor.c',
|
|
||||||
'commands/smart_borders.c',
|
|
||||||
'commands/smart_gaps.c',
|
|
||||||
'commands/split.c',
|
|
||||||
'commands/sticky.c',
|
|
||||||
'commands/swaybg_command.c',
|
|
||||||
'commands/swaynag_command.c',
|
|
||||||
'commands/swap.c',
|
|
||||||
'commands/tiling_drag.c',
|
|
||||||
'commands/tiling_drag_threshold.c',
|
|
||||||
'commands/title_align.c',
|
|
||||||
'commands/title_format.c',
|
|
||||||
'commands/titlebar_border_thickness.c',
|
|
||||||
'commands/titlebar_padding.c',
|
|
||||||
'commands/unmark.c',
|
|
||||||
'commands/urgent.c',
|
|
||||||
'commands/workspace.c',
|
|
||||||
'commands/workspace_layout.c',
|
|
||||||
'commands/ws_auto_back_and_forth.c',
|
|
||||||
'commands/xwayland.c',
|
|
||||||
|
|
||||||
'commands/bar/bind.c',
|
'commands/input/accel_profile.c',
|
||||||
'commands/bar/binding_mode_indicator.c',
|
'commands/input/calibration_matrix.c',
|
||||||
'commands/bar/colors.c',
|
'commands/input/click_method.c',
|
||||||
'commands/bar/font.c',
|
'commands/input/drag.c',
|
||||||
'commands/bar/gaps.c',
|
'commands/input/drag_lock.c',
|
||||||
'commands/bar/height.c',
|
'commands/input/dwt.c',
|
||||||
'commands/bar/hidden_state.c',
|
'commands/input/dwtp.c',
|
||||||
'commands/bar/icon_theme.c',
|
'commands/input/events.c',
|
||||||
'commands/bar/id.c',
|
'commands/input/left_handed.c',
|
||||||
'commands/bar/mode.c',
|
'commands/input/map_from_region.c',
|
||||||
'commands/bar/modifier.c',
|
'commands/input/map_to_output.c',
|
||||||
'commands/bar/output.c',
|
'commands/input/map_to_region.c',
|
||||||
'commands/bar/pango_markup.c',
|
'commands/input/middle_emulation.c',
|
||||||
'commands/bar/position.c',
|
'commands/input/natural_scroll.c',
|
||||||
'commands/bar/separator_symbol.c',
|
'commands/input/pointer_accel.c',
|
||||||
'commands/bar/status_command.c',
|
'commands/input/repeat_delay.c',
|
||||||
'commands/bar/status_edge_padding.c',
|
'commands/input/repeat_rate.c',
|
||||||
'commands/bar/status_padding.c',
|
'commands/input/scroll_button.c',
|
||||||
'commands/bar/strip_workspace_numbers.c',
|
'commands/input/scroll_factor.c',
|
||||||
'commands/bar/strip_workspace_name.c',
|
'commands/input/scroll_method.c',
|
||||||
'commands/bar/swaybar_command.c',
|
'commands/input/tap.c',
|
||||||
'commands/bar/tray_bind.c',
|
'commands/input/tap_button_map.c',
|
||||||
'commands/bar/tray_output.c',
|
'commands/input/tool_mode.c',
|
||||||
'commands/bar/tray_padding.c',
|
'commands/input/xkb_capslock.c',
|
||||||
'commands/bar/workspace_buttons.c',
|
'commands/input/xkb_file.c',
|
||||||
'commands/bar/workspace_min_width.c',
|
'commands/input/xkb_layout.c',
|
||||||
'commands/bar/wrap_scroll.c',
|
'commands/input/xkb_model.c',
|
||||||
|
'commands/input/xkb_numlock.c',
|
||||||
|
'commands/input/xkb_options.c',
|
||||||
|
'commands/input/xkb_rules.c',
|
||||||
|
'commands/input/xkb_switch_layout.c',
|
||||||
|
'commands/input/xkb_variant.c',
|
||||||
|
|
||||||
'commands/input/accel_profile.c',
|
'commands/output/adaptive_sync.c',
|
||||||
'commands/input/calibration_matrix.c',
|
'commands/output/background.c',
|
||||||
'commands/input/click_method.c',
|
'commands/output/disable.c',
|
||||||
'commands/input/drag.c',
|
'commands/output/dpms.c',
|
||||||
'commands/input/drag_lock.c',
|
'commands/output/enable.c',
|
||||||
'commands/input/dwt.c',
|
'commands/output/max_render_time.c',
|
||||||
'commands/input/events.c',
|
'commands/output/mode.c',
|
||||||
'commands/input/left_handed.c',
|
'commands/output/position.c',
|
||||||
'commands/input/map_from_region.c',
|
'commands/output/power.c',
|
||||||
'commands/input/map_to_output.c',
|
'commands/output/render_bit_depth.c',
|
||||||
'commands/input/map_to_region.c',
|
'commands/output/scale.c',
|
||||||
'commands/input/middle_emulation.c',
|
'commands/output/scale_filter.c',
|
||||||
'commands/input/natural_scroll.c',
|
'commands/output/subpixel.c',
|
||||||
'commands/input/pointer_accel.c',
|
'commands/output/toggle.c',
|
||||||
'commands/input/repeat_delay.c',
|
'commands/output/transform.c',
|
||||||
'commands/input/repeat_rate.c',
|
'commands/output/unplug.c',
|
||||||
'commands/input/scroll_button.c',
|
|
||||||
'commands/input/scroll_factor.c',
|
|
||||||
'commands/input/scroll_method.c',
|
|
||||||
'commands/input/tap.c',
|
|
||||||
'commands/input/tap_button_map.c',
|
|
||||||
'commands/input/tool_mode.c',
|
|
||||||
'commands/input/xkb_capslock.c',
|
|
||||||
'commands/input/xkb_file.c',
|
|
||||||
'commands/input/xkb_layout.c',
|
|
||||||
'commands/input/xkb_model.c',
|
|
||||||
'commands/input/xkb_numlock.c',
|
|
||||||
'commands/input/xkb_options.c',
|
|
||||||
'commands/input/xkb_rules.c',
|
|
||||||
'commands/input/xkb_switch_layout.c',
|
|
||||||
'commands/input/xkb_variant.c',
|
|
||||||
|
|
||||||
'commands/output/adaptive_sync.c',
|
'tree/arrange.c',
|
||||||
'commands/output/background.c',
|
'tree/container.c',
|
||||||
'commands/output/disable.c',
|
'tree/node.c',
|
||||||
'commands/output/dpms.c',
|
'tree/root.c',
|
||||||
'commands/output/enable.c',
|
'tree/view.c',
|
||||||
'commands/output/max_render_time.c',
|
'tree/workspace.c',
|
||||||
'commands/output/mode.c',
|
'tree/output.c',
|
||||||
'commands/output/position.c',
|
|
||||||
'commands/output/render_bit_depth.c',
|
|
||||||
'commands/output/scale.c',
|
|
||||||
'commands/output/scale_filter.c',
|
|
||||||
'commands/output/subpixel.c',
|
|
||||||
'commands/output/toggle.c',
|
|
||||||
'commands/output/transform.c',
|
|
||||||
|
|
||||||
'tree/arrange.c',
|
|
||||||
'tree/container.c',
|
|
||||||
'tree/node.c',
|
|
||||||
'tree/root.c',
|
|
||||||
'tree/view.c',
|
|
||||||
'tree/workspace.c',
|
|
||||||
'tree/output.c',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
subdir('desktop/shaders')
|
subdir('desktop/shaders')
|
||||||
|
|
||||||
sway_deps = [
|
sway_deps = [
|
||||||
cairo,
|
cairo,
|
||||||
drm,
|
drm,
|
||||||
jsonc,
|
jsonc,
|
||||||
libevdev,
|
libevdev,
|
||||||
libinput,
|
libinput,
|
||||||
libudev,
|
libudev,
|
||||||
math,
|
math,
|
||||||
pango,
|
pango,
|
||||||
pcre,
|
pcre2,
|
||||||
glesv2,
|
glesv2,
|
||||||
pixman,
|
pixman,
|
||||||
server_protos,
|
threads,
|
||||||
wayland_server,
|
wayland_server,
|
||||||
wlroots,
|
wlroots,
|
||||||
xkbcommon,
|
xkbcommon,
|
||||||
egl,
|
xcb_icccm,
|
||||||
|
egl,
|
||||||
]
|
]
|
||||||
|
|
||||||
if have_xwayland
|
if have_xwayland
|
||||||
sway_sources += 'desktop/xwayland.c'
|
sway_sources += 'desktop/xwayland.c'
|
||||||
sway_deps += xcb
|
sway_deps += xcb
|
||||||
endif
|
endif
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'sway',
|
'sway',
|
||||||
sway_sources,
|
sway_sources + wl_protos_src,
|
||||||
include_directories: [sway_inc],
|
include_directories: [sway_inc],
|
||||||
dependencies: sway_deps,
|
dependencies: sway_deps,
|
||||||
link_with: [lib_sway_common],
|
link_with: [lib_sway_common],
|
||||||
install: true
|
install: true
|
||||||
)
|
)
|
||||||
|
|
40
sway/realtime.c
Normal file
40
sway/realtime.c
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "sway/server.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
static void child_fork_callback(void) {
|
||||||
|
struct sched_param param;
|
||||||
|
|
||||||
|
param.sched_priority = 0;
|
||||||
|
|
||||||
|
int ret = pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m);
|
||||||
|
if (ret != 0) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to reset scheduler policy on fork");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_rr_scheduling(void) {
|
||||||
|
int prio = sched_get_priority_min(SCHED_RR);
|
||||||
|
int old_policy;
|
||||||
|
int ret;
|
||||||
|
struct sched_param param;
|
||||||
|
|
||||||
|
ret = pthread_getschedparam(pthread_self(), &old_policy, ¶m);
|
||||||
|
if (ret != 0) {
|
||||||
|
sway_log(SWAY_DEBUG, "Failed to get old scheduling priority");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
param.sched_priority = prio;
|
||||||
|
|
||||||
|
ret = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
|
||||||
|
if (ret != 0) {
|
||||||
|
sway_log(SWAY_INFO, "Failed to set scheduling priority to %d", prio);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_atfork(NULL, NULL, child_fork_callback);
|
||||||
|
}
|
|
@ -18,13 +18,16 @@
|
||||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||||
#include <wlr/types/wlr_idle.h>
|
#include <wlr/types/wlr_idle.h>
|
||||||
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||||
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||||
#include <wlr/types/wlr_primary_selection_v1.h>
|
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||||
#include <wlr/types/wlr_relative_pointer_v1.h>
|
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||||
#include <wlr/types/wlr_screencopy_v1.h>
|
#include <wlr/types/wlr_screencopy_v1.h>
|
||||||
|
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
|
||||||
#include <wlr/types/wlr_server_decoration.h>
|
#include <wlr/types/wlr_server_decoration.h>
|
||||||
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
#include <wlr/types/wlr_tablet_v2.h>
|
#include <wlr/types/wlr_tablet_v2.h>
|
||||||
#include <wlr/types/wlr_viewporter.h>
|
#include <wlr/types/wlr_viewporter.h>
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
|
@ -48,19 +51,6 @@
|
||||||
#include "sway/xwayland.h"
|
#include "sway/xwayland.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool server_privileged_prepare(struct sway_server *server) {
|
|
||||||
sway_log(SWAY_DEBUG, "Preparing Wayland server initialization");
|
|
||||||
server->wl_display = wl_display_create();
|
|
||||||
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
|
|
||||||
server->backend = wlr_backend_autocreate(server->wl_display);
|
|
||||||
|
|
||||||
if (!server->backend) {
|
|
||||||
sway_log(SWAY_ERROR, "Unable to create backend");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
|
static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
|
||||||
/* We only offer non-desktop outputs, but in the future we might want to do
|
/* We only offer non-desktop outputs, but in the future we might want to do
|
||||||
* more logic here. */
|
* more logic here. */
|
||||||
|
@ -73,8 +63,18 @@ static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SWAY_XDG_SHELL_VERSION 2
|
||||||
|
|
||||||
bool server_init(struct sway_server *server) {
|
bool server_init(struct sway_server *server) {
|
||||||
sway_log(SWAY_DEBUG, "Initializing Wayland server");
|
sway_log(SWAY_DEBUG, "Initializing Wayland server");
|
||||||
|
server->wl_display = wl_display_create();
|
||||||
|
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
|
||||||
|
server->backend = wlr_backend_autocreate(server->wl_display);
|
||||||
|
|
||||||
|
if (!server->backend) {
|
||||||
|
sway_log(SWAY_ERROR, "Unable to create backend");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
server->wlr_renderer = wlr_renderer_autocreate(server->backend);
|
server->wlr_renderer = wlr_renderer_autocreate(server->backend);
|
||||||
if (!server->wlr_renderer) {
|
if (!server->wlr_renderer) {
|
||||||
|
@ -109,6 +109,8 @@ bool server_init(struct sway_server *server) {
|
||||||
wl_signal_add(&server->compositor->events.new_surface,
|
wl_signal_add(&server->compositor->events.new_surface,
|
||||||
&server->compositor_new_surface);
|
&server->compositor_new_surface);
|
||||||
|
|
||||||
|
wlr_subcompositor_create(server->wl_display);
|
||||||
|
|
||||||
server->data_device_manager =
|
server->data_device_manager =
|
||||||
wlr_data_device_manager_create(server->wl_display);
|
wlr_data_device_manager_create(server->wl_display);
|
||||||
|
|
||||||
|
@ -123,6 +125,7 @@ bool server_init(struct sway_server *server) {
|
||||||
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
|
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
|
||||||
|
|
||||||
server->idle = wlr_idle_create(server->wl_display);
|
server->idle = wlr_idle_create(server->wl_display);
|
||||||
|
server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display);
|
||||||
server->idle_inhibit_manager_v1 =
|
server->idle_inhibit_manager_v1 =
|
||||||
sway_idle_inhibit_manager_v1_create(server->wl_display, server->idle);
|
sway_idle_inhibit_manager_v1_create(server->wl_display, server->idle);
|
||||||
|
|
||||||
|
@ -131,7 +134,8 @@ bool server_init(struct sway_server *server) {
|
||||||
&server->layer_shell_surface);
|
&server->layer_shell_surface);
|
||||||
server->layer_shell_surface.notify = handle_layer_shell_surface;
|
server->layer_shell_surface.notify = handle_layer_shell_surface;
|
||||||
|
|
||||||
server->xdg_shell = wlr_xdg_shell_create(server->wl_display);
|
server->xdg_shell = wlr_xdg_shell_create(server->wl_display,
|
||||||
|
SWAY_XDG_SHELL_VERSION);
|
||||||
wl_signal_add(&server->xdg_shell->events.new_surface,
|
wl_signal_add(&server->xdg_shell->events.new_surface,
|
||||||
&server->xdg_shell_surface);
|
&server->xdg_shell_surface);
|
||||||
server->xdg_shell_surface.notify = handle_xdg_shell_surface;
|
server->xdg_shell_surface.notify = handle_xdg_shell_surface;
|
||||||
|
@ -188,6 +192,8 @@ bool server_init(struct sway_server *server) {
|
||||||
server->foreign_toplevel_manager =
|
server->foreign_toplevel_manager =
|
||||||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||||
|
|
||||||
|
sway_session_lock_init();
|
||||||
|
|
||||||
server->drm_lease_manager=
|
server->drm_lease_manager=
|
||||||
wlr_drm_lease_v1_manager_create(server->wl_display, server->backend);
|
wlr_drm_lease_v1_manager_create(server->wl_display, server->backend);
|
||||||
if (server->drm_lease_manager) {
|
if (server->drm_lease_manager) {
|
||||||
|
@ -204,6 +210,7 @@ bool server_init(struct sway_server *server) {
|
||||||
wlr_data_control_manager_v1_create(server->wl_display);
|
wlr_data_control_manager_v1_create(server->wl_display);
|
||||||
wlr_primary_selection_v1_device_manager_create(server->wl_display);
|
wlr_primary_selection_v1_device_manager_create(server->wl_display);
|
||||||
wlr_viewporter_create(server->wl_display);
|
wlr_viewporter_create(server->wl_display);
|
||||||
|
wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
|
||||||
|
|
||||||
struct wlr_xdg_foreign_registry *foreign_registry =
|
struct wlr_xdg_foreign_registry *foreign_registry =
|
||||||
wlr_xdg_foreign_registry_create(server->wl_display);
|
wlr_xdg_foreign_registry_create(server->wl_display);
|
||||||
|
@ -216,10 +223,12 @@ bool server_init(struct sway_server *server) {
|
||||||
wl_signal_add(&server->xdg_activation_v1->events.request_activate,
|
wl_signal_add(&server->xdg_activation_v1->events.request_activate,
|
||||||
&server->xdg_activation_v1_request_activate);
|
&server->xdg_activation_v1_request_activate);
|
||||||
|
|
||||||
|
wl_list_init(&server->pending_launcher_ctxs);
|
||||||
|
|
||||||
// Avoid using "wayland-0" as display socket
|
// Avoid using "wayland-0" as display socket
|
||||||
char name_candidate[16];
|
char name_candidate[16];
|
||||||
for (int i = 1; i <= 32; ++i) {
|
for (unsigned int i = 1; i <= 32; ++i) {
|
||||||
sprintf(name_candidate, "wayland-%d", i);
|
snprintf(name_candidate, sizeof(name_candidate), "wayland-%u", i);
|
||||||
if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) {
|
if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) {
|
||||||
server->socket = strdup(name_candidate);
|
server->socket = strdup(name_candidate);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -147,6 +147,10 @@ The following commands may only be used in the configuration file.
|
||||||
*input* <identifier> dwt enabled|disabled
|
*input* <identifier> dwt enabled|disabled
|
||||||
Enables or disables disable-while-typing for the specified input device.
|
Enables or disables disable-while-typing for the specified input device.
|
||||||
|
|
||||||
|
*input* <identifier> dwtp enabled|disabled
|
||||||
|
Enables or disables disable-while-trackpointing for the specified input
|
||||||
|
device.
|
||||||
|
|
||||||
*input* <identifier> events enabled|disabled|disabled_on_external_mouse|toggle [<toggle-modes>]
|
*input* <identifier> events enabled|disabled|disabled_on_external_mouse|toggle [<toggle-modes>]
|
||||||
Enables or disables send_events for specified input device. Disabling
|
Enables or disables send_events for specified input device. Disabling
|
||||||
send_events disables the input device.
|
send_events disables the input device.
|
||||||
|
|
|
@ -213,7 +213,10 @@ following properties:
|
||||||
: Whether this output is active/enabled
|
: Whether this output is active/enabled
|
||||||
|- dpms
|
|- dpms
|
||||||
: boolean
|
: boolean
|
||||||
: Whether this output is on/off (via DPMS)
|
: (Deprecated, use _power_ instead) Whether this output is on/off (via DPMS)
|
||||||
|
|- power
|
||||||
|
: boolean
|
||||||
|
: Whether this output is on/off
|
||||||
|- primary
|
|- primary
|
||||||
: boolean
|
: boolean
|
||||||
: For i3 compatibility, this will be false. It does not make sense in Wayland
|
: For i3 compatibility, this will be false. It does not make sense in Wayland
|
||||||
|
@ -1194,6 +1197,10 @@ following properties will be included for devices that support them:
|
||||||
|- dwt
|
|- dwt
|
||||||
: string
|
: string
|
||||||
: Whether disable-while-typing is enabled. It can be _enabled_ or _disabled_
|
: Whether disable-while-typing is enabled. It can be _enabled_ or _disabled_
|
||||||
|
|- dwtp
|
||||||
|
: string
|
||||||
|
: Whether disable-while-trackpointing is enabled. It can be _enabled_ or
|
||||||
|
_disabled_
|
||||||
|- calibration_matrix
|
|- calibration_matrix
|
||||||
: array
|
: array
|
||||||
: An array of 6 floats representing the calibration matrix for absolute
|
: An array of 6 floats representing the calibration matrix for absolute
|
||||||
|
@ -1233,7 +1240,8 @@ following properties will be included for devices that support them:
|
||||||
"click_method": "button_areas",
|
"click_method": "button_areas",
|
||||||
"middle_emulation": "disabled",
|
"middle_emulation": "disabled",
|
||||||
"scroll_method": "edge",
|
"scroll_method": "edge",
|
||||||
"dwt": "enabled"
|
"dwt": "enabled",
|
||||||
|
"dwtp": "enabled"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1360,7 +1368,8 @@ one seat. Each object has the following properties:
|
||||||
"click_method": "button_areas",
|
"click_method": "button_areas",
|
||||||
"middle_emulation": "disabled",
|
"middle_emulation": "disabled",
|
||||||
"scroll_method": "edge",
|
"scroll_method": "edge",
|
||||||
"dwt": "enabled"
|
"dwt": "enabled",
|
||||||
|
"dwtp": "enabled"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@ must be separated by one space. For example:
|
||||||
|
|
||||||
# COMMANDS
|
# COMMANDS
|
||||||
|
|
||||||
*output* <name> mode|resolution|res [--custom] <WIDTHxHEIGHT>[@<RATE>Hz]
|
*output* <name> mode|resolution|res [--custom] <width>x<height>[@<rate>Hz]
|
||||||
Configures the specified output to use the given mode. Modes are a
|
Configures the specified output to use the given mode. Modes are a
|
||||||
combination of width and height (in pixels) and a refresh rate that your
|
combination of width and height (in pixels) and a refresh rate that your
|
||||||
display can be configured to use. For a list of available modes for each
|
display can be configured to use. For a list of available modes for each
|
||||||
|
@ -119,12 +119,20 @@ must be separated by one space. For example:
|
||||||
Enables or disables the specified output (all outputs are enabled by
|
Enables or disables the specified output (all outputs are enabled by
|
||||||
default).
|
default).
|
||||||
|
|
||||||
|
As opposed to the _power_ command, the output will loose its current
|
||||||
|
workspace and windows.
|
||||||
|
|
||||||
*output* <name> toggle
|
*output* <name> toggle
|
||||||
Toggle the specified output.
|
Toggle the specified output.
|
||||||
|
|
||||||
|
*output* <name> power on|off|toggle
|
||||||
|
Turns on or off the specified output.
|
||||||
|
|
||||||
|
As opposed to the _enable_ and _disable_ commands, the output keeps its
|
||||||
|
current workspaces and windows.
|
||||||
|
|
||||||
*output* <name> dpms on|off|toggle
|
*output* <name> dpms on|off|toggle
|
||||||
Enables or disables the specified output via DPMS. To turn an output off
|
Deprecated. Alias for _power_.
|
||||||
(ie. blank the screen but keep workspaces as-is), one can set DPMS to off.
|
|
||||||
|
|
||||||
*output* <name> max_render_time off|<msec>
|
*output* <name> max_render_time off|<msec>
|
||||||
Controls when sway composites the output, as a positive number of
|
Controls when sway composites the output, as a positive number of
|
||||||
|
|
101
sway/sway.5.scd
101
sway/sway.5.scd
|
@ -176,6 +176,12 @@ set|plus|minus|toggle <amount>
|
||||||
*layout* default|splith|splitv|stacking|tabbed
|
*layout* default|splith|splitv|stacking|tabbed
|
||||||
Sets the layout mode of the focused container.
|
Sets the layout mode of the focused container.
|
||||||
|
|
||||||
|
When using the _stacking_ layout, only the focused window in the container is
|
||||||
|
displayed, with the opened windows' list on the top of the container.
|
||||||
|
|
||||||
|
The _tabbed_ layout is similar to _stacking_, but the windows’ list is vertically
|
||||||
|
split.
|
||||||
|
|
||||||
*layout* toggle [split|all]
|
*layout* toggle [split|all]
|
||||||
Cycles the layout mode of the focused container though a preset list of
|
Cycles the layout mode of the focused container though a preset list of
|
||||||
layouts. If no argument is given, then it cycles through stacking, tabbed
|
layouts. If no argument is given, then it cycles through stacking, tabbed
|
||||||
|
@ -210,15 +216,14 @@ set|plus|minus|toggle <amount>
|
||||||
further details.
|
further details.
|
||||||
|
|
||||||
*move* left|right|up|down [<px> px]
|
*move* left|right|up|down [<px> px]
|
||||||
Moves the focused container in the direction specified. If the container,
|
Moves the focused container in the direction specified. The optional _px_
|
||||||
the optional _px_ argument specifies how many pixels to move the container.
|
argument specifies how many pixels to move the container. If unspecified,
|
||||||
If unspecified, the default is 10 pixels. Pixels are ignored when moving
|
the default is 10 pixels. Pixels are ignored when moving tiled containers.
|
||||||
tiled containers.
|
|
||||||
|
|
||||||
*move* [absolute] position <pos_x> [px|ppt] <pos_y> [px|ppt]
|
*move* [absolute] position <pos_x> [px|ppt] <pos_y> [px|ppt]
|
||||||
Moves the focused container to the specified position in the workspace.
|
Moves the focused container to the specified position in the workspace.
|
||||||
The position can be specified in pixels or percentage points, omitting
|
The position can be specified in pixels or percentage points, omitting
|
||||||
the unit defaults to pixels. If _absolute_ is used, the position is
|
the unit defaults to pixels. If _absolute_ is used, the position is
|
||||||
relative to all outputs. _absolute_ can not be used with percentage points.
|
relative to all outputs. _absolute_ can not be used with percentage points.
|
||||||
|
|
||||||
*move* [absolute] position center
|
*move* [absolute] position center
|
||||||
|
@ -482,6 +487,62 @@ runtime.
|
||||||
bindswitch lid:toggle exec echo "Lid moved"
|
bindswitch lid:toggle exec echo "Lid moved"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
*bindgesture* [--exact] [--input-device=<device>] [--no-warn] \
|
||||||
|
<gesture>[:<fingers>][:directions] <command>
|
||||||
|
Binds _gesture_ to execute the sway command _command_ when detected.
|
||||||
|
Currently supports the _hold_, _pinch_ or _swipe_ gesture. Optionally
|
||||||
|
can be limited to bind to a certain number of _fingers_ or, for a
|
||||||
|
_pinch_ or _swipe_ gesture, to certain _directions_.
|
||||||
|
|
||||||
|
[[ *type*
|
||||||
|
:[ *fingers*
|
||||||
|
:< *direction*
|
||||||
|
| hold
|
||||||
|
:- 1 - 5
|
||||||
|
: none
|
||||||
|
| swipe
|
||||||
|
: 3 - 5
|
||||||
|
: up, down, left, right
|
||||||
|
| pinch
|
||||||
|
: 2 - 5
|
||||||
|
: all above + inward, outward, clockwise, counterclockwise
|
||||||
|
|
||||||
|
The _fingers_ can be limited to any sensible number or left empty to accept
|
||||||
|
any finger counts.
|
||||||
|
Valid directions are _up_, _down_, _left_ and _right_, as well as _inward_,
|
||||||
|
_outward_, _clockwise_, _counterclockwise_ for the _pinch_ gesture.
|
||||||
|
Multiple directions can be combined by a plus.
|
||||||
|
|
||||||
|
If a _input-device_ is given, the binding will only be executed for
|
||||||
|
that input device and will be executed instead of any binding that is
|
||||||
|
generic to all devices. By default, if you overwrite a binding,
|
||||||
|
swaynag will give you a warning. To silence this, use the _--no-warn_ flag.
|
||||||
|
|
||||||
|
The _--exact_ flag can be used to ensure a binding only matches when exactly
|
||||||
|
all specified directions are matched and nothing more. If there is matching
|
||||||
|
binding with _--exact_, it will be preferred.
|
||||||
|
|
||||||
|
The priority for matching bindings is as follows: input device, then
|
||||||
|
exact matches followed by matches with the highest number of matching
|
||||||
|
directions.
|
||||||
|
|
||||||
|
Gestures executed while the pointer is above a bar are not handled by sway.
|
||||||
|
See the respective documentation, e.g. *bindgesture* in *sway-bar*(5).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
# Allow switching between workspaces with left and right swipes
|
||||||
|
bindgesture swipe:right workspace prev
|
||||||
|
bindgesture swipe:left workspace next
|
||||||
|
|
||||||
|
# Allow container movements by pinching them
|
||||||
|
bindgesture pinch:inward+up move up
|
||||||
|
bindgesture pinch:inward+down move down
|
||||||
|
bindgesture pinch:inward+left move left
|
||||||
|
bindgesture pinch:inward+right move right
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
*client.background* <color>
|
*client.background* <color>
|
||||||
This command is ignored and is only present for i3 compatibility.
|
This command is ignored and is only present for i3 compatibility.
|
||||||
|
|
||||||
|
@ -632,11 +693,11 @@ The default colors are:
|
||||||
after switching between workspaces.
|
after switching between workspaces.
|
||||||
|
|
||||||
*focus_on_window_activation* smart|urgent|focus|none
|
*focus_on_window_activation* smart|urgent|focus|none
|
||||||
This option determines what to do when an xwayland client requests
|
This option determines what to do when a client requests window activation.
|
||||||
window activation. If set to _urgent_, the urgent state will be set
|
If set to _urgent_, the urgent state will be set for that window. If set to
|
||||||
for that window. If set to _focus_, the window will become focused.
|
_focus_, the window will become focused. If set to _smart_, the window will
|
||||||
If set to _smart_, the window will become focused only if it is already
|
become focused only if it is already visible, otherwise the urgent state
|
||||||
visible, otherwise the urgent state will be set. Default is _urgent_.
|
will be set. Default is _urgent_.
|
||||||
|
|
||||||
*focus_wrapping* yes|no|force|workspace
|
*focus_wrapping* yes|no|force|workspace
|
||||||
This option determines what to do when attempting to focus over the edge
|
This option determines what to do when attempting to focus over the edge
|
||||||
|
@ -805,6 +866,11 @@ The default colors are:
|
||||||
*unbindswitch* <switch>:<state>
|
*unbindswitch* <switch>:<state>
|
||||||
Removes a binding for when <switch> changes to <state>.
|
Removes a binding for when <switch> changes to <state>.
|
||||||
|
|
||||||
|
*unbindgesture* [--exact] [--input-device=<device>] \
|
||||||
|
<gesture>[:<fingers>][:directions]
|
||||||
|
Removes a binding for the specified _gesture_, _fingers_
|
||||||
|
and _directions_ combination.
|
||||||
|
|
||||||
*unbindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \
|
*unbindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \
|
||||||
[--to-code] [--input-device=<device>] <key combo>
|
[--to-code] [--input-device=<device>] <key combo>
|
||||||
Removes the binding for _key combo_ that was previously bound with the
|
Removes the binding for _key combo_ that was previously bound with the
|
||||||
|
@ -918,7 +984,8 @@ The following attributes may be matched with:
|
||||||
*class*
|
*class*
|
||||||
Compare value against the window class. Can be a regular expression. If
|
Compare value against the window class. Can be a regular expression. If
|
||||||
value is \_\_focused\_\_, then the window class must be the same as that of
|
value is \_\_focused\_\_, then the window class must be the same as that of
|
||||||
the currently focused window. _class_ are specific to X11 applications.
|
the currently focused window. _class_ are specific to X11 applications and
|
||||||
|
require XWayland.
|
||||||
|
|
||||||
*con_id*
|
*con_id*
|
||||||
Compare against the internal container ID, which you can find via IPC. If
|
Compare against the internal container ID, which you can find via IPC. If
|
||||||
|
@ -932,12 +999,14 @@ The following attributes may be matched with:
|
||||||
Matches floating windows.
|
Matches floating windows.
|
||||||
|
|
||||||
*id*
|
*id*
|
||||||
Compare value against the X11 window ID. Must be numeric.
|
Compare value against the X11 window ID. Must be numeric. id is specific to
|
||||||
|
X11 applications and requires XWayland.
|
||||||
|
|
||||||
*instance*
|
*instance*
|
||||||
Compare value against the window instance. Can be a regular expression. If
|
Compare value against the window instance. Can be a regular expression. If
|
||||||
value is \_\_focused\_\_, then the window instance must be the same as that
|
value is \_\_focused\_\_, then the window instance must be the same as that
|
||||||
of the currently focused window.
|
of the currently focused window. instance is specific to X11 applications and
|
||||||
|
requires XWayland.
|
||||||
|
|
||||||
*pid*
|
*pid*
|
||||||
Compare value against the window's process ID. Must be numeric.
|
Compare value against the window's process ID. Must be numeric.
|
||||||
|
@ -962,12 +1031,14 @@ The following attributes may be matched with:
|
||||||
*window_role*
|
*window_role*
|
||||||
Compare against the window role (WM_WINDOW_ROLE). Can be a regular
|
Compare against the window role (WM_WINDOW_ROLE). Can be a regular
|
||||||
expression. If value is \_\_focused\_\_, then the window role must be the
|
expression. If value is \_\_focused\_\_, then the window role must be the
|
||||||
same as that of the currently focused window.
|
same as that of the currently focused window. window_role is specific to X11
|
||||||
|
applications and requires XWayland.
|
||||||
|
|
||||||
*window_type*
|
*window_type*
|
||||||
Compare against the window type (\_NET_WM_WINDOW_TYPE). Possible values
|
Compare against the window type (\_NET_WM_WINDOW_TYPE). Possible values
|
||||||
are normal, dialog, utility, toolbar, splash, menu, dropdown_menu,
|
are normal, dialog, utility, toolbar, splash, menu, dropdown_menu,
|
||||||
popup_menu, tooltip and notification.
|
popup_menu, tooltip and notification. window_type is specific to X11
|
||||||
|
applications and requires XWayland.
|
||||||
|
|
||||||
*workspace*
|
*workspace*
|
||||||
Compare against the workspace name for this view. Can be a regular
|
Compare against the workspace name for this view. Can be a regular
|
||||||
|
|
|
@ -311,12 +311,13 @@ void arrange_output(struct sway_output *output) {
|
||||||
if (config->reloading) {
|
if (config->reloading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const struct wlr_box *output_box = wlr_output_layout_get_box(
|
struct wlr_box output_box;
|
||||||
root->output_layout, output->wlr_output);
|
wlr_output_layout_get_box(root->output_layout,
|
||||||
output->lx = output_box->x;
|
output->wlr_output, &output_box);
|
||||||
output->ly = output_box->y;
|
output->lx = output_box.x;
|
||||||
output->width = output_box->width;
|
output->ly = output_box.y;
|
||||||
output->height = output_box->height;
|
output->width = output_box.width;
|
||||||
|
output->height = output_box.height;
|
||||||
|
|
||||||
for (int i = 0; i < output->workspaces->length; ++i) {
|
for (int i = 0; i < output->workspaces->length; ++i) {
|
||||||
struct sway_workspace *workspace = output->workspaces->items[i];
|
struct sway_workspace *workspace = output->workspaces->items[i];
|
||||||
|
@ -328,12 +329,12 @@ void arrange_root(void) {
|
||||||
if (config->reloading) {
|
if (config->reloading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const struct wlr_box *layout_box =
|
struct wlr_box layout_box;
|
||||||
wlr_output_layout_get_box(root->output_layout, NULL);
|
wlr_output_layout_get_box(root->output_layout, NULL, &layout_box);
|
||||||
root->x = layout_box->x;
|
root->x = layout_box.x;
|
||||||
root->y = layout_box->y;
|
root->y = layout_box.y;
|
||||||
root->width = layout_box->width;
|
root->width = layout_box.width;
|
||||||
root->height = layout_box->height;
|
root->height = layout_box.height;
|
||||||
|
|
||||||
if (root->fullscreen_global) {
|
if (root->fullscreen_global) {
|
||||||
struct sway_container *fs = root->fullscreen_global;
|
struct sway_container *fs = root->fullscreen_global;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue