Compare commits

..

54 Commits
v0.43.0 ... nix

Author SHA1 Message Date
Mihai Fufezan
48f2f490d0 Nix: drop ninja for CMake build 2024-09-22 12:43:17 +03:00
Mihai Fufezan
94c7996b87 Revert "nix: use meson"
This reverts commit d505b33665.
2024-09-22 12:43:17 +03:00
Mihai Fufezan
674e7df000 Revert "nix: adapt cmake options"
This reverts commit c35ed8363f.
2024-09-22 12:43:17 +03:00
Mihai Fufezan
cb7f9140da CMake: print pch messages based on var 2024-09-22 12:30:18 +03:00
Mihai Fufezan
8579066c7a Nix: clean up derivation 2024-09-21 14:27:13 +03:00
Vaxry
9232bc2c00 internal: move to hyprutils' scopeguard
bumps hyprutils dep to 0.2.2
2024-09-21 00:37:17 +01:00
Vaxry
db0b764a5a shm: send a static list of shm formats
fixes #7733
2024-09-20 22:56:15 +01:00
Mihai Fufezan
278583b8a1 flake.lock: update 2024-09-20 20:16:13 +03:00
Jasson
4414cd07e2 xwm: Minor cleanup, add wrappers for basic types (#7856) 2024-09-20 12:32:04 +01:00
Vaxry
9e98fb0167 dmabuffer: attempt importing failed dmabufs as implicit
don't ask me why, vulkan doesn't like this.

funny note, broken on wlroots :P

fixes #7037
2024-09-20 10:47:41 +01:00
Mihai Fufezan
9856378384 Nix: use mold linker 2024-09-19 18:53:34 +03:00
Mihai Fufezan
dfa1bd0cd4 Meson: pass AQUAMARINE_VERSION argument 2024-09-19 13:48:31 +00:00
vaxerski
92df6b0dce version: log build aquamarine version
log the built against aq version, might be useful when it's mismatched to identify the problem
2024-09-19 11:40:00 +01:00
vaxerski
71963972bf args: add --version to binary args 2024-09-19 11:40:00 +01:00
Arisa Snowbell
1bc05b1f9f xwayland: use proper path for the XWayland sockets (#7852)
fixes #7849
2024-09-19 11:08:02 +01:00
Vaxry
e6cf643f5a pointermgr: Hide hardware cursor on leave (#7806) 2024-09-18 18:47:53 +01:00
Jasson
94140e886e xwayland: Some readability improvements (#7807)
* Readability improvements xwayland server

* Made requested changes

* removed braces

* fix

* Ok this time is fixed

* Formatting
2024-09-18 18:12:26 +01:00
Mihai Fufezan
b248d59713 Nix: fix meson PCH flag 2024-09-18 19:43:56 +03:00
Mihai Fufezan
cbc0ff6ec0 Nix: disable PCH 2024-09-18 18:54:00 +03:00
Mihai Fufezan
6b6554adb8 flake.nix: inherit stdenv from package
Means we no longer have to change the base stdenv in two places.
2024-09-18 18:43:39 +03:00
Mihai Fufezan
d936eb437b flake.lock: update aquamarine 2024-09-18 17:26:51 +03:00
vaxerski
883d01084c userchecks: add an xdg_current_desktop check
ref https://github.com/hyprwm/xdg-desktop-portal-hyprland/issues/251

if the XDG_CURRENT_DESKTOP is externally managed (e.g. DE, DM, etc) Hyprland will not overwrite it. In those cases, if that's undesired, portals and other apps depending on it might break.
2024-09-18 11:22:12 +01:00
Aqa-Ib
0564b46a5e dispatchers: allow moveintogroup when floating (#7818)
This allows to use the moveintogroup dispatcher when windows are floating. I don't know why was this disabled in the first place though.

Cheers!
2024-09-18 11:05:17 +01:00
André Silva
3c9716acfd gammactrl: fix potential crash on monitor removed (#7828) 2024-09-17 14:37:20 +01:00
vaxerski
581f6659f8 data-device: conform to reported source actions
fixes #7815
2024-09-17 12:55:48 +01:00
vaxerski
e72ae6b25f hyprctl: allow parsing empty value
fixes #7821
2024-09-17 11:24:54 +01:00
Leiser Fernández Gallo
9e35656244 internal: Delay monitor events/hooks (#7797)
* Delay monitor messages

* Format
2024-09-15 21:03:42 +01:00
AlvinaNancy
e87758529e internal: Fix change group current fullscreen state query (#7802) 2024-09-15 18:25:06 +01:00
Sungyoon Cho
eb97d949aa textinput: don't reset if ti isn't enabled (#7798) 2024-09-15 17:31:38 +01:00
Ikalco
e74efd87e5 internal: fix initial cursor warping (#7793) 2024-09-14 23:37:18 +01:00
Vaxry
4dbdb556fe data-device: don't send default action of move
gtk doesn't like it?
2024-09-14 23:36:06 +01:00
Vaxry
5ee4b19691 data-device: send clock time in motion events
remove hack
2024-09-14 23:35:45 +01:00
Vaxry
d35e70a8c6 cmake: drop ninja dep 2024-09-13 17:56:44 +01:00
diniamo
c35ed8363f nix: adapt cmake options 2024-09-13 19:44:38 +03:00
diniamo
d505b33665 nix: use meson 2024-09-13 17:54:49 +03:00
Sungyoon Cho
118be4dea0 textinput: fix tiv3 leave (#7761) 2024-09-12 17:41:24 +01:00
trianta
73b9756b8d xwayland: remove extra x11 deactivation (#7755) 2024-09-12 10:15:01 +01:00
fufexan
8b9e385943 [gha] Nix: update inputs 2024-09-11 16:10:51 +00:00
Mihai Fufezan
e01da1fd7a Meson: format 2024-09-11 19:09:17 +03:00
Mihai Fufezan
7a8c013edc Meson: fix protocols, clean up 2024-09-11 19:09:16 +03:00
Vaxry
518399a95b pointermgr: avoid derefing null outputs 2024-09-11 09:30:21 +01:00
Sungyoon Cho
155d44016d textinput: handle IME resetting (#7731) 2024-09-10 14:49:10 +01:00
Alexandre Acebedo
13f90bb87a update xdph commit in flake.lock 2024-09-10 16:38:47 +03:00
davc0n
c67b257e51 build: Set cmake_minimum_required to version 3.30 (#7709)
* build: Set cmake_minimum_required to version 3.30

* Nix: add patch for CMake min ver

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-09-10 11:06:37 +01:00
Maximilian Seidler
8237d7e1a4 input: move dmps activation to input listeners (#7721) 2024-09-09 21:29:00 +01:00
vaxerski
85da1a17d8 [gha] build man pages 2024-09-09 15:19:44 +00:00
justmessingaround
9609b04ff9 man: Fixed the man page to show the new information (#7713)
* Update Hyprland.1.rst

* Update Hyprland.1
2024-09-09 16:19:17 +01:00
darkwater
04421063af config: add order rule for layers (#7697) 2024-09-09 10:10:08 +01:00
davc0n
43e1415e71 assets: Remove execute permission from lockdead.png (#7715) 2024-09-09 10:01:26 +01:00
Sungyoon Cho
e1448732b3 tiv1: fix deleting first character (#7716) 2024-09-09 09:58:44 +01:00
Richard Ayotte
7c4c402bd7 config: include XF86Audio* key bindings to default cfg (#7695) 2024-09-08 22:04:07 +01:00
Aqa-Ib
6179b17903 github: improve issue template (#7699)
* github: improve issue template

Require to check that you have searched through open and closed issues before committing.

* fix yaml syntax

* clarify text

* validation

* revert validation

* markdown

* done
2024-09-08 21:12:01 +01:00
Davide Conti
05b48d48d9 config: Limit max volume to 100% 2024-09-08 22:53:28 +03:00
diniamo
07a21fdfa9 github(nix-build): switch to better nix installer, attempt at fixing hash mismatch (#7701)
* github(nix-build): switch to DeterminateSystems/nix-installer-action

* github(nix-build): switch to a direct git reference instead of cloning

* github(nix-ci): attempt to fix CI for pull requests
2024-09-08 21:20:45 +03:00
61 changed files with 846 additions and 563 deletions

View File

@@ -2,12 +2,13 @@ name: Bug Report
description: Something is not working right description: Something is not working right
labels: ["bug"] labels: ["bug"]
body: body:
- type: markdown - type: checkboxes
attributes: attributes:
value: | label: Already reported ? *
## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists. description: Before opening a new bug report, please take a moment to search through the current open and closed issues to check if it already exists.
options:
--- - label: I have searched the existing open and closed issues.
required: true
- type: dropdown - type: dropdown
id: type id: type

View File

@@ -16,17 +16,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone repository - uses: DeterminateSystems/nix-installer-action@main
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
submodules: recursive
- uses: cachix/install-nix-action@v27
- uses: DeterminateSystems/magic-nix-cache-action@main - uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v15 - uses: cachix/cachix-action@v15
with: with:
name: hyprland name: hyprland
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"

View File

@@ -9,7 +9,6 @@ jobs:
secrets: inherit secrets: inherit
build: build:
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure') if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
needs: update-inputs
uses: ./.github/workflows/nix-build.yml uses: ./.github/workflows/nix-build.yml
secrets: inherit secrets: inherit

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.27) cmake_minimum_required(VERSION 3.30)
# Get version # Get version
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
@@ -91,11 +91,14 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
pkg_check_modules( pkg_check_modules(
deps deps
REQUIRED REQUIRED
IMPORTED_TARGET IMPORTED_TARGET
aquamarine
xkbcommon xkbcommon
uuid uuid
wayland-server wayland-server
@@ -111,7 +114,7 @@ pkg_check_modules(
gio-2.0 gio-2.0
hyprlang>=0.3.2 hyprlang>=0.3.2
hyprcursor>=0.1.7 hyprcursor>=0.1.7
hyprutils>=0.2.1) hyprutils>=0.2.2)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -213,14 +216,17 @@ set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack) include(CPack)
message(STATUS "Setting precompiled headers") if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
message(STATUS "Not using precompiled headers")
target_precompile_headers(Hyprland PRIVATE else()
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>) message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
endif()
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::deps) target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
# used by `make installheaders`, to ensure the headers are generated # used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers) add_custom_target(generate-protocol-headers)

View File

@@ -1,28 +1,24 @@
PREFIX = /usr/local PREFIX = /usr/local
legacyrenderer: legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ
cmake --build ./build --config Release --target all cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
legacyrendererdebug: legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
cmake --build ./build --config Release --target all cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
release: release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
cmake --build ./build --config Release --target all cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
debug: debug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
cmake --build ./build --config Debug --target all cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
nopch: nopch:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build
cmake --build ./build --config Release --target all cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
clear: clear:
rm -rf build rm -rf build

0
assets/install/lockdead.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

@@ -2,5 +2,9 @@ globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check:
files = globber.stdout().strip().split('\n') files = globber.stdout().strip().split('\n')
foreach file : files foreach file : files
install_data(file, install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') install_data(
file,
install_dir: join_paths(get_option('datadir'), 'hypr'),
install_tag: 'runtime',
)
endforeach endforeach

View File

@@ -1,2 +1,7 @@
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') install_data(
'hyprland-portals.conf',
install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'),
install_tag: 'runtime',
)
subdir('install') subdir('install')

View File

@@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]]. \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on \f[B]Hyprland\f[R] is an independent, highly customizable, dynamic
wlroots that doesn\[aq]t sacrifice on its looks. tiling Wayland compositor that doesn\[aq]t sacrifice on its looks.
.PP .PP
You can launch Hyprland by either going into a TTY and executing You can launch Hyprland by either going into a TTY and executing
\f[B]Hyprland\f[R], or with a login manager. \f[B]Hyprland\f[R], or with a login manager.

View File

@@ -14,8 +14,8 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
=========== ===========
**Hyprland** is a dynamic tiling Wayland compositor based on **Hyprland** is an independent, highly customizable,
wlroots that doesn't sacrifice on its looks. dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
You can launch Hyprland by either going into a TTY and You can launch Hyprland by either going into a TTY and
executing **Hyprland**, or with a login manager. executing **Hyprland**, or with a login manager.

View File

@@ -1,2 +1,2 @@
install_man ('Hyprland.1') install_man('Hyprland.1')
install_man ('hyprctl.1') install_man('hyprctl.1')

View File

@@ -229,13 +229,18 @@ bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness # Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
############################## ##############################
### WINDOWS AND WORKSPACES ### ### WINDOWS AND WORKSPACES ###

View File

@@ -1,2 +1,10 @@
install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') install_data(
install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime') 'hyprland.conf',
install_dir: join_paths(get_option('datadir'), 'hypr'),
install_tag: 'runtime',
)
install_data(
'hyprland.desktop',
install_dir: join_paths(get_option('datadir'), 'wayland-sessions'),
install_tag: 'runtime',
)

42
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1725199881, "lastModified": 1726665257,
"narHash": "sha256-jsmipf/u1GFZE5tBUkr56CHMN6VpUWCAjfLIhvQijU0=", "narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "f8a687dd29ff019657498f1bd14da2fbbf0e604b", "rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -93,11 +93,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1725188252, "lastModified": 1725997860,
"narHash": "sha256-yBH8c4GDaEAtBrh+BqIlrx5vp6gG/Gu8fQQK63KAQgs=", "narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "c12ab785ce1982f82594aff03b3104c598186ddd", "rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -116,11 +116,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1724966483, "lastModified": 1726874949,
"narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=", "narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2", "rev": "d97af4f6bd068c03a518b597675e598f57ea2291",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -139,11 +139,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1721324119, "lastModified": 1726840673,
"narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=", "narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30", "rev": "b68dab23fc922eae99306988133ee80a40b39ca5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -154,11 +154,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1725103162, "lastModified": 1726755586,
"narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", "narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", "rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -201,6 +201,12 @@
"hyprlang": [ "hyprlang": [
"hyprlang" "hyprlang"
], ],
"hyprutils": [
"hyprutils"
],
"hyprwayland-scanner": [
"hyprwayland-scanner"
],
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
@@ -209,11 +215,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1725203932, "lastModified": 1726851729,
"narHash": "sha256-VLULC/OnI+6R9KEP2OIGk+uLJJsfRlaLouZ5gyFd2+Y=", "narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "2425e8f541525fa7409d9f26a8ffaf92a3767251", "rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -46,6 +46,8 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprlang.follows = "hyprlang"; inputs.hyprlang.follows = "hyprlang";
inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
}; };
}; };
@@ -95,13 +97,9 @@
devShells = eachSystem (system: { devShells = eachSystem (system: {
default = default =
pkgsFor.${system}.mkShell.override { pkgsFor.${system}.mkShell.override {
stdenv = pkgsFor.${system}.gcc14Stdenv; inherit (self.packages.${system}.default) stdenv;
} { } {
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [
expat
libxml2
];
hardeningDisable = ["fortify"]; hardeningDisable = ["fortify"];
inputsFrom = [pkgsFor.${system}.hyprland]; inputsFrom = [pkgsFor.${system}.hyprland];
packages = [pkgsFor.${system}.clang-tools]; packages = [pkgsFor.${system}.clang-tools];

View File

@@ -1,10 +1,26 @@
executable('hyprctl', 'main.cpp', executable(
'hyprctl',
'main.cpp',
dependencies: [ dependencies: [
dependency('hyprutils', version: '>= 0.1.1'), dependency('hyprutils', version: '>= 0.1.1'),
], ],
install: true install: true,
) )
install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprctl') install_data(
install_data('hyprctl.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime') 'hyprctl.bash',
install_data('hyprctl.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprctl') install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'),
install_tag: 'runtime',
rename: 'hyprctl',
)
install_data(
'hyprctl.fish',
install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'),
install_tag: 'runtime',
)
install_data(
'hyprctl.zsh',
install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'),
install_tag: 'runtime',
rename: '_hyprctl',
)

View File

@@ -1,15 +1,31 @@
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
src = globber.stdout().strip().split('\n') src = globber.stdout().strip().split('\n')
executable('hyprpm', src, executable(
'hyprpm',
src,
dependencies: [ dependencies: [
dependency('hyprutils', version: '>= 0.1.1'), dependency('hyprutils', version: '>= 0.1.1'),
dependency('threads'), dependency('threads'),
dependency('tomlplusplus') dependency('tomlplusplus'),
], ],
install : true install: true,
) )
install_data('../hyprpm.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprpm') install_data(
install_data('../hyprpm.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime') '../hyprpm.bash',
install_data('../hyprpm.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprpm') install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'),
install_tag: 'runtime',
rename: 'hyprpm',
)
install_data(
'../hyprpm.fish',
install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'),
install_tag: 'runtime',
)
install_data(
'../hyprpm.zsh',
install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'),
install_tag: 'runtime',
rename: '_hyprpm',
)

View File

@@ -1,13 +1,17 @@
project('Hyprland', 'cpp', 'c', project(
version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(), 'Hyprland',
default_options : [ 'cpp',
'c',
version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(),
default_options: [
'warning_level=2', 'warning_level=2',
'default_library=static', 'default_library=static',
'optimization=3', 'optimization=3',
'buildtype=release', 'buildtype=release',
'debug=false', 'debug=false',
'cpp_std=c++26', 'cpp_std=c++26',
]) ],
)
datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"' datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"'
add_project_arguments( add_project_arguments(
@@ -16,16 +20,19 @@ add_project_arguments(
'-Wno-unused-value', '-Wno-unused-value',
'-Wno-missing-field-initializers', '-Wno-missing-field-initializers',
'-Wno-narrowing', '-Wno-narrowing',
'-Wno-pointer-arith', '-Wno-pointer-arith', datarootdir,
datarootdir,
], ],
language: 'cpp') language: 'cpp',
)
cpp_compiler = meson.get_compiler('cpp') cpp_compiler = meson.get_compiler('cpp')
if cpp_compiler.check_header('execinfo.h') if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
aquamarine = dependency('aquamarine')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland'))
@@ -34,7 +41,7 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland'))
xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) xcb_res_dep = dependency('xcb-res', required: get_option('xwayland'))
xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
gio_dep = dependency('gio-2.0', required:true) gio_dep = dependency('gio-2.0', required: true)
cmake = import('cmake') cmake = import('cmake')
udis = cmake.subproject('udis86') udis = cmake.subproject('udis86')
@@ -47,6 +54,7 @@ endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false) backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
# Handle options
if get_option('systemd').enabled() if get_option('systemd').enabled()
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
endif endif
@@ -59,8 +67,10 @@ if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp') add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif endif
version_h = run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) # Generate hyprland version and populate version.h
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Install headers
globber = run_command('find', 'src', '-name', '*.h*', check: true) globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n') headers = globber.stdout().strip().split('\n')
foreach file : headers foreach file : headers
@@ -75,6 +85,7 @@ subdir('assets')
subdir('example') subdir('example')
subdir('docs') subdir('docs')
# Generate hyprland.pc
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
import('pkgconfig').generate( import('pkgconfig').generate(

10
nix/cmake-version.patch Normal file
View File

@@ -0,0 +1,10 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6fdf98db..d8424d91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.30)
+cmake_minimum_required(VERSION 3.27)
# Get version
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)

View File

@@ -1,11 +1,11 @@
{ {
lib, lib,
stdenv, stdenv,
stdenvAdapters,
pkg-config, pkg-config,
pkgconf, pkgconf,
makeWrapper, makeWrapper,
cmake, cmake,
ninja,
aquamarine, aquamarine,
binutils, binutils,
cairo, cairo,
@@ -45,133 +45,142 @@
enableNvidiaPatches ? false, enableNvidiaPatches ? false,
nvidiaPatches ? false, nvidiaPatches ? false,
hidpiXWayland ? false, hidpiXWayland ? false,
}: }: let
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; inherit (builtins) baseNameOf foldl';
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; inherit (lib.asserts) assertMsg;
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; inherit (lib.attrsets) mapAttrsToList;
stdenv.mkDerivation { inherit (lib.lists) flatten concatLists optional optionals;
pname = "hyprland${lib.optionalString debug "-debug"}"; inherit (lib.sources) cleanSourceWith cleanSource;
inherit version; inherit (lib.strings) cmakeBool hasSuffix makeBinPath optionalString;
src = lib.cleanSourceWith { adapters = flatten [
filter = name: type: let stdenvAdapters.useMoldLinker
baseName = baseNameOf (toString name); ];
in
! (lib.hasSuffix ".nix" baseName);
src = lib.cleanSource ../.;
};
patches = [ customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters;
# forces GCC to use -std=c++26 in
./stdcxx.patch assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
]; assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
customStdenv.mkDerivation {
pname = "hyprland${optionalString debug "-debug"}";
inherit version;
postPatch = '' src = cleanSourceWith {
# Fix hardcoded paths to /usr installation filter = name: type: let
sed -i "s#/usr#$out#" src/render/OpenGL.cpp baseName = baseNameOf (toString name);
in
! (hasSuffix ".nix" baseName);
src = cleanSource ../.;
};
# Remove extra @PREFIX@ to fix pkg-config paths patches = [
sed -i "s#@PREFIX@/##g" hyprland.pc.in # forces GCC to use -std=c++26
''; ./stdcxx.patch
COMMITS = revCount; # Nix does not have CMake 3.30 yet, so override the minimum version
DATE = date; ./cmake-version.patch
DIRTY = lib.optionalString (commit == "") "dirty"; ];
HASH = commit;
depsBuildBuild = [ postPatch = ''
pkg-config # Fix hardcoded paths to /usr installation
]; sed -i "s#/usr#$out#" src/render/OpenGL.cpp
nativeBuildInputs = [ # Remove extra @PREFIX@ to fix pkg-config paths
hyprwayland-scanner sed -i "s#@PREFIX@/##g" hyprland.pc.in
jq '';
makeWrapper
cmake
ninja
pkg-config
python3 # for udis86
wayland-scanner
];
outputs = [ COMMITS = revCount;
"out" DATE = date;
"man" DIRTY = optionalString (commit == "") "dirty";
"dev" HASH = commit;
];
buildInputs = lib.concatLists [ depsBuildBuild = [
[ pkg-config
aquamarine ];
cairo
# expat
# fribidi
git
hyprcursor
hyprlang
hyprutils
# libdatrie
libdrm
libGL
libinput
# libselinux
# libsepol
# libthai
libuuid
libxkbcommon
mesa
pango
pciutils
# pcre2
tomlplusplus
wayland
wayland-protocols
xorg.libXcursor
]
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
(lib.optionals enableXWayland [
xorg.libxcb
xorg.libXdmcp
xorg.xcbutilerrors
xorg.xcbutilrenderutil
xorg.xcbutilwm
xwayland
])
(lib.optionals withSystemd [systemd])
];
cmakeBuildType = nativeBuildInputs = [
if debug hyprwayland-scanner
then "Debug" jq
else "RelWithDebInfo"; makeWrapper
cmake
pkg-config
python3 # for udis86
wayland-scanner
];
# we want as much debug info as possible outputs = [
dontStrip = debug; "out"
"man"
"dev"
];
cmakeFlags = [ buildInputs = concatLists [
(lib.cmakeBool "NO_XWAYLAND" (!enableXWayland)) [
(lib.cmakeBool "LEGACY_RENDERER" legacyRenderer) aquamarine
(lib.cmakeBool "NO_SYSTEMD" (!withSystemd)) cairo
]; git
hyprcursor
postInstall = '' hyprlang
${lib.optionalString wrapRuntimeDeps '' hyprutils
wrapProgram $out/bin/Hyprland \ libdrm
--suffix PATH : ${lib.makeBinPath [ libGL
binutils libinput
libuuid
libxkbcommon
mesa
pango
pciutils pciutils
pkgconf tomlplusplus
]} wayland
''} wayland-protocols
''; xorg.libXcursor
]
(optionals customStdenv.hostPlatform.isMusl [libexecinfo])
(optionals enableXWayland [
xorg.libxcb
xorg.libXdmcp
xorg.xcbutilerrors
xorg.xcbutilrenderutil
xorg.xcbutilwm
xwayland
])
(optional withSystemd systemd)
];
passthru.providedSessions = ["hyprland"]; cmakeBuildType =
if debug
then "Debug"
else "RelWithDebInfo";
meta = { # we want as much debug info as possible
homepage = "https://github.com/hyprwm/Hyprland"; dontStrip = debug;
description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = lib.licenses.bsd3; cmakeFlags = mapAttrsToList cmakeBool {
platforms = lib.platforms.linux; "NO_XWAYLAND" = !enableXWayland;
mainProgram = "Hyprland"; "LEGACY_RENDERER" = legacyRenderer;
}; "NO_SYSTEMD" = !withSystemd;
} "CMAKE_DISABLE_PRECOMPILE_HEADERS" = true;
};
postInstall = ''
${optionalString wrapRuntimeDeps ''
wrapProgram $out/bin/Hyprland \
--suffix PATH : ${makeBinPath [
binutils
pciutils
pkgconf
]}
''}
'';
passthru.providedSessions = ["hyprland"];
meta = {
homepage = "https://github.com/hyprwm/Hyprland";
description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = lib.licenses.bsd3;
platforms = lib.platforms.linux;
mainProgram = "Hyprland";
};
}

View File

@@ -1,77 +1,75 @@
wayland_protos = dependency('wayland-protocols', wayland_protos = dependency(
'wayland-protocols',
version: '>=1.32', version: '>=1.32',
fallback: 'wayland-protocols', fallback: 'wayland-protocols',
default_options: ['tests=false'], default_options: ['tests=false'],
) )
hyprland_protos = dependency('hyprland-protocols', hyprland_protos = dependency(
'hyprland-protocols',
version: '>=0.2', version: '>=0.2',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') wayland_protocol_dir = wayland_protos.get_variable('pkgdatadir')
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir') hyprland_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.10', native: true)
hyprwayland_scanner = find_program( hyprwayland_scanner = find_program(
hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'),
native: true, native: true,
) )
new_protocols = [ protocols = [
['wlr-gamma-control-unstable-v1.xml'], 'wlr-gamma-control-unstable-v1.xml',
['wlr-foreign-toplevel-management-unstable-v1.xml'], 'wlr-foreign-toplevel-management-unstable-v1.xml',
['wlr-output-power-management-unstable-v1.xml'], 'wlr-output-power-management-unstable-v1.xml',
['input-method-unstable-v2.xml'], 'input-method-unstable-v2.xml',
['virtual-keyboard-unstable-v1.xml'], 'virtual-keyboard-unstable-v1.xml',
['wlr-virtual-pointer-unstable-v1.xml'], 'wlr-virtual-pointer-unstable-v1.xml',
['wlr-output-management-unstable-v1.xml'], 'wlr-output-management-unstable-v1.xml',
['kde-server-decoration.xml'], 'kde-server-decoration.xml',
['wlr-layer-shell-unstable-v1.xml'], 'wlr-layer-shell-unstable-v1.xml',
['wayland-drm.xml'], 'wayland-drm.xml',
['wlr-data-control-unstable-v1.xml'], 'wlr-data-control-unstable-v1.xml',
['wlr-screencopy-unstable-v1.xml'], 'wlr-screencopy-unstable-v1.xml',
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'], hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'], wayland_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], wayland_protocol_dir / 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml',
[wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'], wayland_protocol_dir / 'unstable/relative-pointer/relative-pointer-unstable-v1.xml',
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'], wayland_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml',
[wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'], wayland_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml',
[wl_protocol_dir, 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml'], wayland_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
[wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], wayland_protocol_dir / 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml',
[wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], wayland_protocol_dir / 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml',
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml',
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v1.xml',
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], wayland_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
[wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], wayland_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml',
[wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], wayland_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml',
[wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], wayland_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml',
[wl_protocol_dir, 'stable/tablet/tablet-v2.xml'], wayland_protocol_dir / 'stable/tablet/tablet-v2.xml',
[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], wayland_protocol_dir / 'stable/presentation-time/presentation-time.xml',
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], wayland_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
[wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'], wayland_protocol_dir / 'unstable/primary-selection/primary-selection-unstable-v1.xml',
[wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], wayland_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'], wayland_protocol_dir / 'stable/viewporter/viewporter.xml',
[wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], wayland_protocol_dir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml',
[wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'], wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
[wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'], wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
[wl_protocol_dir, 'staging/xdg-dialog/xdg-dialog-v1.xml'], wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
] ]
wl_protos_src = [] wl_protocols = []
wl_protos_headers = [] foreach protocol : protocols
wl_protocols += custom_target(
new_wl_protos = [] protocol.underscorify(),
foreach p : new_protocols input: protocol,
xml = join_paths(p)
new_wl_protos += custom_target(
xml.underscorify(),
input: xml,
install: true, install: true,
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
@@ -79,31 +77,26 @@ foreach p : new_protocols
) )
endforeach endforeach
wayland_server_dep = dependency('wayland-server', version: '>=1.20.0') # wayland.xml generation
wayland_server_dir = wayland_server_dep.get_variable('pkgdatadir') wayland_scanner = dependency('wayland-scanner')
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
wl_server_protos = [ wayland_xml = wayland_scanner_datadir / 'wayland.xml'
wayland_server_dir / 'wayland.xml' wayland_protocol = custom_target(
] wayland_xml.underscorify(),
wl_server_protos_gen = [] input: wayland_xml,
foreach p : wl_server_protos install: true,
wl_server_protos_gen += custom_target( install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
p.underscorify(), output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
input: p, command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
install: true, )
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
)
endforeach
lib_server_protos = static_library( lib_server_protos = static_library(
'server_protos', 'server_protos',
wl_protos_src + wl_protos_headers + new_wl_protos + wl_server_protos_gen, wl_protocols + wayland_protocol,
dependencies: wayland_server_dep.partial_dependency(compile_args: true),
) )
server_protos = declare_dependency( server_protos = declare_dependency(
link_with: lib_server_protos, link_with: lib_server_protos,
sources: wl_protos_headers + new_wl_protos, sources: wl_protocols + wayland_protocol,
) )

View File

@@ -2696,7 +2696,17 @@ WORKSPACEID CCompositor::getNewSpecialID() {
} }
void CCompositor::performUserChecks() { void CCompositor::performUserChecks() {
; // intentional static auto PNOCHECKXDG = CConfigValue<Hyprlang::INT>("misc:disable_xdg_env_checks");
if (!*PNOCHECKXDG) {
const auto CURRENT_DESKTOP_ENV = getenv("XDG_CURRENT_DESKTOP");
if (!CURRENT_DESKTOP_ENV || std::string{CURRENT_DESKTOP_ENV} != "Hyprland") {
g_pHyprNotificationOverlay->addNotification(
std::format("Your XDG_CURRENT_DESKTOP environment seems to be managed externally, and the current value is {}.\nThis might cause issues unless it's intentional.",
CURRENT_DESKTOP_ENV ? CURRENT_DESKTOP_ENV : "unset"),
CColor{}, 15000, ICON_WARNING);
}
}
} }
void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) { void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) {
@@ -2943,6 +2953,38 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
return {}; return {};
} }
static void checkDefaultCursorWarp(SP<CMonitor> monitor) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
const auto POS = monitor->middle();
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if (firstLaunch) {
firstLaunch = false;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
return;
}
if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) {
if (*PCURSORMONITOR == monitor->szName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
return;
}
}
// modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed.
if (g_pCompositor->getMonitorFromCursor() == monitor.get()) {
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) { void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
// add it to real // add it to real
auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>(output)); auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>(output));
@@ -2977,6 +3019,8 @@ void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR);
checkDefaultCursorWarp(PNEWMONITOR);
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) { if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = MONITOR_INVALID; w->m_iLastSurfaceMonitorID = MONITOR_INVALID;

View File

@@ -1049,6 +1049,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{15, 1, 120}, .data = SConfigOptionDescription::SRangeData{15, 1, 120},
}, },
SConfigOptionDescription{
.value = "misc:disable_xdg_env_checks",
.description = "disable the warning if XDG environment is externally managed",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* binds: * binds:

View File

@@ -371,6 +371,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15}); m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15});
m_pConfig->addConfigValue("misc:disable_xdg_env_checks", Hyprlang::INT{0});
m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1});
@@ -2239,7 +2240,7 @@ bool windowRuleValid(const std::string& RULE) {
bool layerRuleValid(const std::string& RULE) { bool layerRuleValid(const std::string& RULE) {
static const auto rules = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"}; static const auto rules = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
static const auto rulesPrefix = std::vector<std::string>{"ignorealpha", "ignorezero", "xray", "animation"}; static const auto rulesPrefix = std::vector<std::string>{"ignorealpha", "ignorezero", "xray", "animation", "order"};
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }); return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); });
} }

View File

@@ -249,6 +249,12 @@ bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
############################## ##############################
### WINDOWS AND WORKSPACES ### ### WINDOWS AND WORKSPACES ###
############################## ##############################

View File

@@ -858,7 +858,8 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n"; ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" +
"\n\nflags: (if any)\n";
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
@@ -881,8 +882,10 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
"commit_date": "{}", "commit_date": "{}",
"tag": "{}", "tag": "{}",
"commits": "{}", "commits": "{}",
"buildAquamarine": "{}",
"flags": [)#", "flags": [)#",
GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS); GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS,
AQUAMARINE_VERSION);
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "\"legacyrenderer\","; result += "\"legacyrenderer\",";
@@ -987,9 +990,9 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
const auto COMMAND = in.substr(0, secondSpacePos); const auto COMMAND = in.substr(0, secondSpacePos);
const auto VALUE = in.substr(secondSpacePos + 1); const auto VALUE = in.substr(secondSpacePos + 1);
// If either COMMAND or VALUE is empty, handle accordingly // If COMMAND is empty, handle accordingly
if (COMMAND.empty() || VALUE.empty()) if (COMMAND.empty())
return "Invalid input: command or value is empty"; return "Invalid input: command is empty";
std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE); std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE);

View File

@@ -394,6 +394,11 @@ void CLayerSurface::applyRules() {
} else if (rule.rule.starts_with("animation")) { } else if (rule.rule.starts_with("animation")) {
CVarList vars{rule.rule, 2, 's'}; CVarList vars{rule.rule, 2, 's'};
animationStyle = vars[1]; animationStyle = vars[1];
} else if (rule.rule.starts_with("order")) {
CVarList vars{rule.rule, 2, 's'};
try {
order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
} }
} }
} }

View File

@@ -55,6 +55,7 @@ class CLayerSurface {
bool ignoreAlpha = false; bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f; float ignoreAlphaValue = 0.f;
bool dimAround = false; bool dimAround = false;
int64_t order = 0;
std::optional<std::string> animationStyle; std::optional<std::string> animationStyle;

View File

@@ -991,7 +991,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
const auto PCURRENT = getGroupCurrent(); const auto PCURRENT = getGroupCurrent();
const bool FULLSCREEN = PCURRENT->isFullscreen(); const bool FULLSCREEN = PCURRENT->isFullscreen();
const auto WORKSPACE = PCURRENT->m_pWorkspace; const auto WORKSPACE = PCURRENT->m_pWorkspace;
const auto MODE = PCURRENT->m_sFullscreenState.client; const auto MODE = PCURRENT->m_sFullscreenState.internal;
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();

View File

@@ -2,7 +2,6 @@
#include "MiscFunctions.hpp" #include "MiscFunctions.hpp"
#include "math/Math.hpp" #include "math/Math.hpp"
#include "sync/SyncReleaser.hpp" #include "sync/SyncReleaser.hpp"
#include "ScopeGuard.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/GammaControl.hpp" #include "../protocols/GammaControl.hpp"
@@ -17,7 +16,9 @@
#include "sync/SyncTimeline.hpp" #include "sync/SyncTimeline.hpp"
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::Utils;
int ratHandler(void* data) { int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor((CMonitor*)data); g_pHyprRenderer->renderMonitor((CMonitor*)data);
@@ -192,10 +193,6 @@ void CMonitor::onConnect(bool noRule) {
if (!activeMonitorRule.mirrorOf.empty()) if (!activeMonitorRule.mirrorOf.empty())
setMirror(activeMonitorRule.mirrorOf); setMirror(activeMonitorRule.mirrorOf);
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", this);
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->setActiveMonitor(this); g_pCompositor->setActiveMonitor(this);
@@ -224,6 +221,10 @@ void CMonitor::onConnect(bool noRule) {
PROTO::gamma->applyGammaToState(this); PROTO::gamma->applyGammaToState(this);
events.connect.emit(); events.connect.emit();
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", this);
} }
void CMonitor::onDisconnect(bool destroy) { void CMonitor::onDisconnect(bool destroy) {
@@ -281,9 +282,6 @@ void CMonitor::onDisconnect(bool destroy) {
Debug::log(LOG, "Removed monitor {}!", szName); Debug::log(LOG, "Removed monitor {}!", szName);
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
if (!BACKUPMON) { if (!BACKUPMON) {
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend."); Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
g_pCompositor->enterUnsafeState(); g_pCompositor->enterUnsafeState();
@@ -342,6 +340,9 @@ void CMonitor::onDisconnect(bool destroy) {
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
} }
std::erase_if(g_pCompositor->m_vMonitors, [&](SP<CMonitor>& el) { return el.get() == this; }); std::erase_if(g_pCompositor->m_vMonitors, [&](SP<CMonitor>& el) { return el.get() == this; });
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
} }
void CMonitor::addDamage(const pixman_region32_t* rg) { void CMonitor::addDamage(const pixman_region32_t* rg) {

View File

@@ -1,10 +0,0 @@
#include "ScopeGuard.hpp"
CScopeGuard::CScopeGuard(const std::function<void()>& fn_) : fn(fn_) {
;
}
CScopeGuard::~CScopeGuard() {
if (fn)
fn();
}

View File

@@ -1,13 +0,0 @@
#pragma once
#include <functional>
// calls a function when it goes out of scope
class CScopeGuard {
public:
CScopeGuard(const std::function<void()>& fn_);
~CScopeGuard();
private:
std::function<void()> fn;
};

View File

@@ -4,6 +4,9 @@
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp" #include "init/initHelpers.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
#include <fcntl.h> #include <fcntl.h>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
@@ -20,6 +23,7 @@ void help() {
std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n";
std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n";
std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n";
std::cout << " --version -v - Print this binary's version\n";
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
@@ -109,6 +113,25 @@ int main(int argc, char** argv) {
} else if (it->compare("-h") == 0 || it->compare("--help") == 0) { } else if (it->compare("-h") == 0 || it->compare("--help") == 0) {
help(); help();
return 0;
} else if (it->compare("-v") == 0 || it->compare("--version") == 0) {
auto commitMsg = trim(GIT_COMMIT_MESSAGE);
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" +
"\n\nflags: (if any)\n";
#ifdef LEGACY_RENDERER
result += "legacyrenderer\n";
#endif
#ifndef ISDEBUG
result += "debug\n";
#endif
#ifdef NO_XWAYLAND
result += "no xwayland\n";
#endif
std::cout << result;
return 0; return 0;
} else { } else {
std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n";

View File

@@ -2730,7 +2730,7 @@ SDispatchResult CKeybindManager::moveIntoGroup(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny) if (!PWINDOW || PWINDOW->m_sGroupData.deny)
return {}; return {};
auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg);

View File

@@ -221,6 +221,7 @@ class CKeybindManager {
friend class CInputManager; friend class CInputManager;
friend class CConfigManager; friend class CConfigManager;
friend class CWorkspace; friend class CWorkspace;
friend class CPointerManager;
}; };
inline std::unique_ptr<CKeybindManager> g_pKeybindManager; inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -18,13 +18,7 @@ CPointerManager::CPointerManager() {
onMonitorLayoutChange(); onMonitorLayoutChange();
PMONITOR->events.modeChanged.registerStaticListener( PMONITOR->events.modeChanged.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
g_pEventLoopManager->doLater([this, PMONITOR]() {
onMonitorLayoutChange();
checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name);
});
},
nullptr);
PMONITOR->events.disconnect.registerStaticListener( PMONITOR->events.disconnect.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.destroy.registerStaticListener( PMONITOR->events.destroy.registerStaticListener(
@@ -44,38 +38,6 @@ CPointerManager::CPointerManager() {
}); });
} }
void CPointerManager::checkDefaultCursorWarp(SP<CMonitor> monitor, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
const auto POS = monitor->middle();
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if (firstLaunch) {
firstLaunch = false;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
return;
}
if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) {
if (*PCURSORMONITOR == monitorName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
return;
}
}
// modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed.
if (g_pCompositor->getMonitorFromCursor() == monitor.get()) {
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void CPointerManager::lockSoftwareAll() { void CPointerManager::lockSoftwareAll() {
for (auto const& state : monitorStates) for (auto const& state : monitorStates)
state->softwareLocks++; state->softwareLocks++;
@@ -246,9 +208,8 @@ void CPointerManager::recheckEnteredOutputs() {
// if we are using hw cursors, prevent // if we are using hw cursors, prevent
// the cursor from being stuck at the last point. // the cursor from being stuck at the last point.
// if we are leaving it, move it to narnia.
if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
s->monitor->output->moveCursor({-1337, -420}); setHWCursorBuffer(s, nullptr);
if (!currentCursorImage.surface) if (!currentCursorImage.surface)
continue; continue;
@@ -307,6 +268,8 @@ void CPointerManager::resetCursorImage(bool apply) {
void CPointerManager::updateCursorBackend() { void CPointerManager::updateCursorBackend() {
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors"); static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
const auto CURSORBOX = getCursorBoxGlobal();
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
auto state = stateFor(m); auto state = stateFor(m);
@@ -315,6 +278,15 @@ void CPointerManager::updateCursorBackend() {
continue; continue;
} }
auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty();
if (!CROSSES) {
if (state->cursorFrontBuffer)
setHWCursorBuffer(state, nullptr);
continue;
}
if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) {
Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName);
state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock());
@@ -335,17 +307,34 @@ void CPointerManager::onCursorMoved() {
if (!hasCursor()) if (!hasCursor())
return; return;
const auto CURSORBOX = getCursorBoxGlobal();
bool recalc = false;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
auto state = stateFor(m); auto state = stateFor(m);
state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock());
auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty();
if (!CROSSES && state->cursorFrontBuffer) {
Debug::log(TRACE, "onCursorMoved for output {}: cursor left the viewport, removing it from the backend", m->szName);
setHWCursorBuffer(state, nullptr);
continue;
} else if (CROSSES && !state->cursorFrontBuffer) {
Debug::log(TRACE, "onCursorMoved for output {}: cursor entered the output, but no front buffer, forcing recalc", m->szName);
recalc = true;
}
if (state->hardwareFailed || !state->entered) if (state->hardwareFailed || !state->entered)
continue; continue;
const auto CURSORPOS = getCursorPosForMonitor(m); const auto CURSORPOS = getCursorPosForMonitor(m);
m->output->moveCursor(CURSORPOS); m->output->moveCursor(CURSORPOS);
} }
if (recalc)
updateCursorBackend();
} }
bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerState> state) { bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerState> state) {
@@ -675,7 +664,7 @@ void CPointerManager::damageIfSoftware() {
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors"); static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
for (auto const& mw : monitorStates) { for (auto const& mw : monitorStates) {
if (mw->monitor.expired()) if (mw->monitor.expired() || !mw->monitor->output)
continue; continue;
if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) {
@@ -789,7 +778,7 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
void CPointerManager::onMonitorLayoutChange() { void CPointerManager::onMonitorLayoutChange() {
currentMonitorLayout.monitorBoxes.clear(); currentMonitorLayout.monitorBoxes.clear();
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_vMonitors) {
if (m->isMirror() || !m->m_bEnabled) if (m->isMirror() || !m->m_bEnabled || !m->output)
continue; continue;
currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize}); currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize});
@@ -821,6 +810,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
if (!pointer) if (!pointer)
return; return;
static auto PMOUSEDPMS = CConfigValue<Hyprlang::INT>("misc:mouse_move_enables_dpms");
//
auto listener = pointerListeners.emplace_back(makeShared<SPointerListener>()); auto listener = pointerListeners.emplace_back(makeShared<SPointerListener>());
listener->pointer = pointer; listener->pointer = pointer;
@@ -836,6 +828,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
g_pInputManager->onMouseMoved(E); g_pInputManager->onMouseMoved(E);
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
g_pKeybindManager->dpms("on");
}); });
listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) { listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) {
@@ -844,6 +839,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
g_pInputManager->onMouseWarp(E); g_pInputManager->onMouseWarp(E);
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
g_pKeybindManager->dpms("on");
}); });
listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) { listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) {
@@ -872,6 +870,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
g_pInputManager->onSwipeBegin(E); g_pInputManager->onSwipeBegin(E);
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
g_pKeybindManager->dpms("on");
}); });
listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) { listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) {
@@ -896,6 +897,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers); PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers);
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
g_pKeybindManager->dpms("on");
}); });
listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) { listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) {
@@ -938,6 +942,9 @@ void CPointerManager::attachTouch(SP<ITouch> touch) {
if (!touch) if (!touch)
return; return;
static auto PMOUSEDPMS = CConfigValue<Hyprlang::INT>("misc:mouse_move_enables_dpms");
//
auto listener = touchListeners.emplace_back(makeShared<STouchListener>()); auto listener = touchListeners.emplace_back(makeShared<STouchListener>());
listener->touch = touch; listener->touch = touch;
@@ -953,6 +960,9 @@ void CPointerManager::attachTouch(SP<ITouch> touch) {
g_pInputManager->onTouchDown(E); g_pInputManager->onTouchDown(E);
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
g_pKeybindManager->dpms("on");
}); });
listener->up = touch->touchEvents.up.registerListener([this] (std::any e) { listener->up = touch->touchEvents.up.registerListener([this] (std::any e) {
@@ -987,6 +997,9 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) {
if (!tablet) if (!tablet)
return; return;
static auto PMOUSEDPMS = CConfigValue<Hyprlang::INT>("misc:mouse_move_enables_dpms");
//
auto listener = tabletListeners.emplace_back(makeShared<STabletListener>()); auto listener = tabletListeners.emplace_back(makeShared<STabletListener>());
listener->tablet = tablet; listener->tablet = tablet;
@@ -1002,6 +1015,9 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) {
g_pInputManager->onTabletAxis(E); g_pInputManager->onTabletAxis(E);
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
g_pKeybindManager->dpms("on");
}); });
listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) { listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) {
@@ -1018,6 +1034,9 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) {
g_pInputManager->onTabletTip(E); g_pInputManager->onTabletTip(E);
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
g_pKeybindManager->dpms("on");
}); });
listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) { listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) {

View File

@@ -26,7 +26,6 @@ class CPointerManager {
public: public:
CPointerManager(); CPointerManager();
void checkDefaultCursorWarp(SP<CMonitor> monitor, std::string monitorName);
void attachPointer(SP<IPointer> pointer); void attachPointer(SP<IPointer> pointer);
void attachTouch(SP<ITouch> touch); void attachTouch(SP<ITouch> touch);
void attachTablet(SP<CTablet> tablet); void attachTablet(SP<CTablet> tablet);

View File

@@ -46,11 +46,8 @@ void CHyprXWaylandManager::activateSurface(SP<CWLSurfaceResource> pSurface, bool
PWINDOW->m_pXWaylandSurface->restackToTop(); PWINDOW->m_pXWaylandSurface->restackToTop();
} }
PWINDOW->m_pXWaylandSurface->activate(activate); PWINDOW->m_pXWaylandSurface->activate(activate);
} else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) { } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface)
PWINDOW->m_pXDGSurface->toplevel->setActive(activate); PWINDOW->m_pXDGSurface->toplevel->setActive(activate);
if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11)
activateSurface(g_pCompositor->m_pLastFocus.lock(), false);
}
} }
void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) {

View File

@@ -28,6 +28,7 @@
#include "../../managers/PointerManager.hpp" #include "../../managers/PointerManager.hpp"
#include "../../managers/SeatManager.hpp" #include "../../managers/SeatManager.hpp"
#include "../../managers/KeybindManager.hpp"
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
@@ -135,7 +136,6 @@ void CInputManager::sendMotionEventsToFocused() {
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PMOUSEREFOCUS = CConfigValue<Hyprlang::INT>("input:mouse_refocus"); static auto PMOUSEREFOCUS = CConfigValue<Hyprlang::INT>("input:mouse_refocus");
static auto PMOUSEDPMS = CConfigValue<Hyprlang::INT>("misc:mouse_move_enables_dpms");
static auto PFOLLOWONDND = CConfigValue<Hyprlang::INT>("misc:always_follow_on_dnd"); static auto PFOLLOWONDND = CConfigValue<Hyprlang::INT>("misc:always_follow_on_dnd");
static auto PFLOATBEHAVIOR = CConfigValue<Hyprlang::INT>("input:float_switch_override_focus"); static auto PFLOATBEHAVIOR = CConfigValue<Hyprlang::INT>("input:float_switch_override_focus");
static auto PMOUSEFOCUSMON = CConfigValue<Hyprlang::INT>("misc:mouse_move_focuses_monitor"); static auto PMOUSEFOCUSMON = CConfigValue<Hyprlang::INT>("misc:mouse_move_focuses_monitor");
@@ -157,11 +157,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState)
return; return;
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) {
// enable dpms
g_pKeybindManager->dpms("on");
}
Vector2D mouseCoords = getMouseCoordsInternal(); Vector2D mouseCoords = getMouseCoordsInternal();
const auto MOUSECOORDSFLOORED = mouseCoords.floor(); const auto MOUSECOORDSFLOORED = mouseCoords.floor();
@@ -854,6 +849,8 @@ void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard)
} }
void CInputManager::setupKeyboard(SP<IKeyboard> keeb) { void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
static auto PDPMS = CConfigValue<Hyprlang::INT>("misc:key_press_enables_dpms");
m_vHIDs.push_back(keeb); m_vHIDs.push_back(keeb);
try { try {
@@ -882,6 +879,9 @@ void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
if (PKEEB->enabled) if (PKEEB->enabled)
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON)
g_pKeybindManager->dpms("on");
}, },
keeb.get()); keeb.get());
@@ -893,6 +893,9 @@ void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
if (PKEEB->enabled) if (PKEEB->enabled)
PROTO::idle->onActivity(); PROTO::idle->onActivity();
if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON)
g_pKeybindManager->dpms("on");
}, },
keeb.get()); keeb.get());
@@ -1284,12 +1287,6 @@ void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {
const auto EMAP = std::unordered_map<std::string, std::any>{{"keyboard", pKeyboard}, {"event", event}}; const auto EMAP = std::unordered_map<std::string, std::any>{{"keyboard", pKeyboard}, {"event", event}};
EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP); EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP);
static auto PDPMS = CConfigValue<Hyprlang::INT>("misc:key_press_enables_dpms");
if (*PDPMS && !g_pCompositor->m_bDPMSStateON) {
// enable dpms
g_pKeybindManager->dpms("on");
}
bool passEvent = DISALLOWACTION || g_pKeybindManager->onKeyEvent(event, pKeyboard); bool passEvent = DISALLOWACTION || g_pKeybindManager->onKeyEvent(event, pKeyboard);
auto e = std::any_cast<IKeyboard::SKeyEvent>(event); auto e = std::any_cast<IKeyboard::SKeyEvent>(event);

View File

@@ -106,20 +106,22 @@ void CInputMethodRelay::updateAllPopups() {
} }
} }
void CInputMethodRelay::activateIME(CTextInput* pInput) { void CInputMethodRelay::activateIME(CTextInput* pInput, bool shouldCommit) {
if (m_pIME.expired()) if (m_pIME.expired())
return; return;
m_pIME->activate(); m_pIME->activate();
commitIMEState(pInput); if (shouldCommit)
commitIMEState(pInput);
} }
void CInputMethodRelay::deactivateIME(CTextInput* pInput) { void CInputMethodRelay::deactivateIME(CTextInput* pInput, bool shouldCommit) {
if (m_pIME.expired()) if (m_pIME.expired())
return; return;
m_pIME->deactivate(); m_pIME->deactivate();
commitIMEState(pInput); if (shouldCommit)
commitIMEState(pInput);
} }
void CInputMethodRelay::commitIMEState(CTextInput* pInput) { void CInputMethodRelay::commitIMEState(CTextInput* pInput) {

View File

@@ -21,8 +21,8 @@ class CInputMethodRelay {
void onNewTextInput(WP<CTextInputV3> tiv3); void onNewTextInput(WP<CTextInputV3> tiv3);
void onNewTextInput(WP<CTextInputV1> pTIV1); void onNewTextInput(WP<CTextInputV1> pTIV1);
void activateIME(CTextInput* pInput); void activateIME(CTextInput* pInput, bool shouldCommit = true);
void deactivateIME(CTextInput* pInput); void deactivateIME(CTextInput* pInput, bool shouldCommit = true);
void commitIMEState(CTextInput* pInput); void commitIMEState(CTextInput* pInput);
void removeTextInput(CTextInput* pInput); void removeTextInput(CTextInput* pInput);

View File

@@ -22,6 +22,7 @@ void CTextInput::initCallbacks() {
listeners.enable = INPUT->events.enable.registerListener([this](std::any p) { onEnabled(); }); listeners.enable = INPUT->events.enable.registerListener([this](std::any p) { onEnabled(); });
listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); });
listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); });
listeners.reset = INPUT->events.reset.registerListener([this](std::any p) { onReset(); });
listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) {
listeners.surfaceUnmap.reset(); listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset(); listeners.surfaceDestroy.reset();
@@ -41,6 +42,7 @@ void CTextInput::initCallbacks() {
}); });
listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); });
listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); });
listeners.reset = INPUT->events.reset.registerListener([this](std::any p) { onReset(); });
listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) {
listeners.surfaceUnmap.reset(); listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset(); listeners.surfaceDestroy.reset();
@@ -93,13 +95,28 @@ void CTextInput::onDisabled() {
g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.deactivateIME(this);
} }
void CTextInput::onReset() {
if (g_pInputManager->m_sIMERelay.m_pIME.expired())
return;
if (!focusedSurface())
return;
const auto PFOCUSEDTI = g_pInputManager->m_sIMERelay.getFocusedTextInput();
if (!PFOCUSEDTI || PFOCUSEDTI != this)
return;
g_pInputManager->m_sIMERelay.deactivateIME(this, false);
g_pInputManager->m_sIMERelay.activateIME(this);
}
void CTextInput::onCommit() { void CTextInput::onCommit() {
if (g_pInputManager->m_sIMERelay.m_pIME.expired()) { if (g_pInputManager->m_sIMERelay.m_pIME.expired()) {
// Debug::log(WARN, "Committing TextInput on no IME!"); // Debug::log(WARN, "Committing TextInput on no IME!");
return; return;
} }
if (!(isV3() ? pV3Input->current.enabled : pV1Input->active)) { if (!(isV3() ? pV3Input->current.enabled.value : pV1Input->active)) {
Debug::log(WARN, "Disabled TextInput commit?"); Debug::log(WARN, "Disabled TextInput commit?");
return; return;
} }
@@ -128,8 +145,12 @@ void CTextInput::setFocusedSurface(SP<CWLSurfaceResource> pSurface) {
listeners.surfaceUnmap.reset(); listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset(); listeners.surfaceDestroy.reset();
if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) {
pV3Input->current.enabled = false; pV3Input->pending.enabled.value = false;
pV3Input->pending.enabled.isDisablePending = false;
pV3Input->pending.enabled.isEnablePending = false;
pV3Input->current.enabled.value = false;
}
if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) if (!g_pInputManager->m_sIMERelay.getFocusedTextInput())
g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.deactivateIME(this);
@@ -144,8 +165,12 @@ void CTextInput::setFocusedSurface(SP<CWLSurfaceResource> pSurface) {
listeners.surfaceUnmap.reset(); listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset(); listeners.surfaceDestroy.reset();
if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) {
pV3Input->current.enabled = false; pV3Input->pending.enabled.value = false;
pV3Input->pending.enabled.isDisablePending = false;
pV3Input->pending.enabled.isEnablePending = false;
pV3Input->current.enabled.value = false;
}
if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) if (!g_pInputManager->m_sIMERelay.getFocusedTextInput())
g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.deactivateIME(this);
@@ -192,13 +217,9 @@ void CTextInput::leave() {
enterLocks = 0; enterLocks = 0;
} }
if (isV3()) { if (isV3())
pV3Input->leave(focusedSurface()); pV3Input->leave(focusedSurface());
if (pV3Input->current.enabled) { else
pV3Input->current.enabled = false;
onDisabled();
}
} else
pV1Input->leave(); pV1Input->leave();
setFocusedSurface(nullptr); setFocusedSurface(nullptr);
@@ -264,7 +285,7 @@ void CTextInput::updateIMEState(SP<CInputMethodV2> ime) {
INPUT->preeditStyling(0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditStyling(0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
INPUT->preeditString(pV1Input->serial, ime->current.preeditString.string.c_str(), ""); INPUT->preeditString(pV1Input->serial, ime->current.preeditString.string.c_str(), "");
} else { } else {
INPUT->preeditCursor(ime->current.preeditString.begin); INPUT->preeditCursor(0);
INPUT->preeditStyling(0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditStyling(0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
INPUT->preeditString(pV1Input->serial, "", ""); INPUT->preeditString(pV1Input->serial, "", "");
} }

View File

@@ -29,6 +29,7 @@ class CTextInput {
void onEnabled(SP<CWLSurfaceResource> surfV1 = nullptr); void onEnabled(SP<CWLSurfaceResource> surfV1 = nullptr);
void onDisabled(); void onDisabled();
void onCommit(); void onCommit();
void onReset();
bool hasCursorRectangle(); bool hasCursorRectangle();
CBox cursorBox(); CBox cursorBox();
@@ -47,6 +48,7 @@ class CTextInput {
struct { struct {
CHyprSignalListener enable; CHyprSignalListener enable;
CHyprSignalListener disable; CHyprSignalListener disable;
CHyprSignalListener reset;
CHyprSignalListener commit; CHyprSignalListener commit;
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener surfaceUnmap; CHyprSignalListener surfaceUnmap;

View File

@@ -1,12 +1,14 @@
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
src = globber.stdout().strip().split('\n') src = globber.stdout().strip().split('\n')
executable('Hyprland', src, executable(
'Hyprland',
src,
link_args: '-rdynamic', link_args: '-rdynamic',
cpp_pch: 'pch/pch.hpp', cpp_pch: 'pch/pch.hpp',
dependencies: [ dependencies: [
server_protos, server_protos,
dependency('aquamarine'), aquamarine,
dependency('gbm'), dependency('gbm'),
dependency('xcursor'), dependency('xcursor'),
dependency('wayland-server'), dependency('wayland-server'),
@@ -38,5 +40,5 @@ executable('Hyprland', src,
dependency('pangocairo'), dependency('pangocairo'),
dependency('uuid'), dependency('uuid'),
], ],
install : true install: true,
) )

View File

@@ -19,7 +19,7 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out
pMonitor = OUTPUTRES->monitor; pMonitor = OUTPUTRES->monitor;
if (!pMonitor) { if (!pMonitor || !pMonitor->output) {
LOGM(ERR, "No CMonitor"); LOGM(ERR, "No CMonitor");
resource->sendFailed(); resource->sendFailed();
return; return;

View File

@@ -31,6 +31,7 @@ CTextInputV1::CTextInputV1(SP<CZwpTextInputV1> resource_) : resource(resource_)
resource->setReset([this](CZwpTextInputV1* pMgr) { resource->setReset([this](CZwpTextInputV1* pMgr) {
pendingSurrounding.isPending = false; pendingSurrounding.isPending = false;
pendingContentType.isPending = false; pendingContentType.isPending = false;
events.reset.emit();
}); });
resource->setSetSurroundingText( resource->setSetSurroundingText(

View File

@@ -37,6 +37,7 @@ class CTextInputV1 {
CSignal onCommit; CSignal onCommit;
CSignal enable; CSignal enable;
CSignal disable; CSignal disable;
CSignal reset;
CSignal destroy; CSignal destroy;
} events; } events;

View File

@@ -19,17 +19,22 @@ CTextInputV3::CTextInputV3(SP<CZwpTextInputV3> resource_) : resource(resource_)
resource->setOnDestroy([this](CZwpTextInputV3* r) { PROTO::textInputV3->destroyTextInput(this); }); resource->setOnDestroy([this](CZwpTextInputV3* r) { PROTO::textInputV3->destroyTextInput(this); });
resource->setCommit([this](CZwpTextInputV3* r) { resource->setCommit([this](CZwpTextInputV3* r) {
bool wasEnabled = current.enabled; bool wasEnabled = current.enabled.value;
current = pending; current = pending;
serial++; serial++;
if (wasEnabled && !current.enabled) if (wasEnabled && !current.enabled.value)
events.disable.emit(); events.disable.emit();
else if (!wasEnabled && current.enabled) else if (!wasEnabled && current.enabled.value)
events.enable.emit(); events.enable.emit();
else if (current.enabled.value && current.enabled.isEnablePending && current.enabled.isDisablePending)
events.reset.emit();
else else
events.onCommit.emit(); events.onCommit.emit();
pending.enabled.isEnablePending = false;
pending.enabled.isDisablePending = false;
}); });
resource->setSetSurroundingText([this](CZwpTextInputV3* r, const char* text, int32_t cursor, int32_t anchor) { resource->setSetSurroundingText([this](CZwpTextInputV3* r, const char* text, int32_t cursor, int32_t anchor) {
@@ -54,10 +59,14 @@ CTextInputV3::CTextInputV3(SP<CZwpTextInputV3> resource_) : resource(resource_)
resource->setEnable([this](CZwpTextInputV3* r) { resource->setEnable([this](CZwpTextInputV3* r) {
pending.reset(); pending.reset();
pending.enabled = true; pending.enabled.value = true;
pending.enabled.isEnablePending = true;
}); });
resource->setDisable([this](CZwpTextInputV3* r) { pending.enabled = false; }); resource->setDisable([this](CZwpTextInputV3* r) {
pending.enabled.value = false;
pending.enabled.isDisablePending = true;
});
} }
CTextInputV3::~CTextInputV3() { CTextInputV3::~CTextInputV3() {

View File

@@ -31,6 +31,7 @@ class CTextInputV3 {
CSignal onCommit; CSignal onCommit;
CSignal enable; CSignal enable;
CSignal disable; CSignal disable;
CSignal reset;
CSignal destroy; CSignal destroy;
} events; } events;
@@ -53,7 +54,11 @@ class CTextInputV3 {
CBox cursorBox; CBox cursorBox;
} box; } box;
bool enabled = false; struct {
bool isEnablePending = false;
bool isDisablePending = false;
bool value = false;
} enabled;
zwpTextInputV3ChangeCause cause = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD; zwpTextInputV3ChangeCause cause = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD;

View File

@@ -82,9 +82,18 @@ void CWLDataOfferResource::sendData() {
if (!source) if (!source)
return; return;
if (resource->version() >= 3) { const auto SOURCEACTIONS = source->actions();
resource->sendSourceActions(7);
resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); if (resource->version() >= 3 && SOURCEACTIONS > 0) {
resource->sendSourceActions(SOURCEACTIONS);
if (SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
else if (SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
else {
LOGM(ERR, "Client bug? dnd source has no action move or copy. Sending move, f this.");
resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
}
} }
for (auto const& m : source->mimes()) { for (auto const& m : source->mimes()) {
@@ -113,7 +122,7 @@ CWLDataSourceResource::CWLDataSourceResource(SP<CWlDataSource> resource_, SP<CWL
resource->setOffer([this](CWlDataSource* r, const char* mime) { mimeTypes.push_back(mime); }); resource->setOffer([this](CWlDataSource* r, const char* mime) { mimeTypes.push_back(mime); });
resource->setSetActions([this](CWlDataSource* r, uint32_t a) { resource->setSetActions([this](CWlDataSource* r, uint32_t a) {
LOGM(LOG, "DataSource {:x} actions {}", (uintptr_t)this, a); LOGM(LOG, "DataSource {:x} actions {}", (uintptr_t)this, a);
actions = (wl_data_device_manager_dnd_action)a; supportedActions = a;
}); });
} }
@@ -195,6 +204,10 @@ void CWLDataSourceResource::sendDndAction(wl_data_device_manager_dnd_action a) {
resource->sendAction(a); resource->sendAction(a);
} }
uint32_t CWLDataSourceResource::actions() {
return supportedActions;
}
CWLDataDeviceResource::CWLDataDeviceResource(SP<CWlDataDevice> resource_) : resource(resource_) { CWLDataDeviceResource::CWLDataDeviceResource(SP<CWlDataDevice> resource_) : resource(resource_) {
if (!good()) if (!good())
return; return;
@@ -513,7 +526,10 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
if (!box.has_value()) if (!box.has_value())
return; return;
dnd.focusedDevice->sendMotion(0 /* this is a hack */, V - box->pos()); timespec timeNow;
clock_gettime(CLOCK_MONOTONIC, &timeNow);
dnd.focusedDevice->sendMotion(timeNow.tv_sec * 1000 + timeNow.tv_nsec / 1000000, V - box->pos());
LOGM(LOG, "Drag motion {}", V - box->pos()); LOGM(LOG, "Drag motion {}", V - box->pos());
} }
}); });

View File

@@ -65,6 +65,7 @@ class CWLDataSourceResource : public IDataSource {
virtual bool dndDone(); virtual bool dndDone();
virtual void error(uint32_t code, const std::string& msg); virtual void error(uint32_t code, const std::string& msg);
virtual void sendDndFinished(); virtual void sendDndFinished();
virtual uint32_t actions(); // wl_data_device_manager.dnd_action
void sendDndDropPerformed(); void sendDndDropPerformed();
void sendDndAction(wl_data_device_manager_dnd_action a); void sendDndAction(wl_data_device_manager_dnd_action a);
@@ -78,7 +79,7 @@ class CWLDataSourceResource : public IDataSource {
WP<CWLDataSourceResource> self; WP<CWLDataSourceResource> self;
std::vector<std::string> mimeTypes; std::vector<std::string> mimeTypes;
uint32_t actions = 0; uint32_t supportedActions = 0;
private: private:
SP<CWlDataSource> resource; SP<CWlDataSource> resource;

View File

@@ -193,11 +193,8 @@ void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, ui
DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010,
}; };
for (auto const& fmt : g_pHyprOpenGL->getDRMFormats()) { for (auto const& fmt : supportedShmFourccFormats) {
if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) shmFormats.push_back(fmt);
continue;
shmFormats.push_back(fmt.drmFormat);
} }
} }

View File

@@ -16,8 +16,15 @@ CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs
auto eglImage = g_pHyprOpenGL->createEGLImage(attrs); auto eglImage = g_pHyprOpenGL->createEGLImage(attrs);
if (!eglImage) if (!eglImage) {
return; Debug::log(ERR, "CDMABuffer: failed to import EGLImage, retrying as implicit");
attrs.modifier = DRM_FORMAT_MOD_INVALID;
eglImage = g_pHyprOpenGL->createEGLImage(attrs);
if (!eglImage) {
Debug::log(ERR, "CDMABuffer: failed to import EGLImage");
return;
}
}
texture = makeShared<CTexture>(attrs, eglImage); // texture takes ownership of the eglImage texture = makeShared<CTexture>(attrs, eglImage); // texture takes ownership of the eglImage
opaque = FormatUtils::isFormatOpaque(attrs.format); opaque = FormatUtils::isFormatOpaque(attrs.format);

View File

@@ -23,3 +23,7 @@ eDataSourceType IDataSource::type() {
void IDataSource::sendDndFinished() { void IDataSource::sendDndFinished() {
; ;
} }
uint32_t IDataSource::actions() {
return 7; // all
}

View File

@@ -26,6 +26,7 @@ class IDataSource {
virtual void markUsed(); virtual void markUsed();
virtual void error(uint32_t code, const std::string& msg) = 0; virtual void error(uint32_t code, const std::string& msg) = 0;
virtual eDataSourceType type(); virtual eDataSourceType type();
virtual uint32_t actions(); // wl_data_device_manager.dnd_action
struct { struct {
CSignal destroy; CSignal destroy;

View File

@@ -1,7 +1,6 @@
#include "Renderer.hpp" #include "Renderer.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/ScopeGuard.hpp"
#include "../helpers/sync/SyncReleaser.hpp" #include "../helpers/sync/SyncReleaser.hpp"
#include <algorithm> #include <algorithm>
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
@@ -23,6 +22,9 @@
#include "../helpers/sync/SyncTimeline.hpp" #include "../helpers/sync/SyncTimeline.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
extern "C" { extern "C" {
#include <xf86drm.h> #include <xf86drm.h>
} }
@@ -1742,6 +1744,10 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) {
CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
for (auto& la : PMONITOR->m_aLayerSurfaceLayers) {
std::stable_sort(la.begin(), la.end(), [](const PHLLSREF& a, const PHLLSREF& b) { return a->order > b->order; });
}
for (auto const& la : PMONITOR->m_aLayerSurfaceLayers) for (auto const& la : PMONITOR->m_aLayerSurfaceLayers)
arrangeLayerArray(PMONITOR, la, true, &usableArea); arrangeLayerArray(PMONITOR, la, true, &usableArea);

View File

@@ -1,105 +1,115 @@
#include <cstdint>
#ifndef NO_XWAYLAND #ifndef NO_XWAYLAND
#include "Server.hpp" #include <format>
#include "../defines.hpp" #include <string>
#include "../Compositor.hpp"
#include "../managers/CursorManager.hpp"
#include "XWayland.hpp"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h>
#include <cstring>
#include <signal.h> #include <signal.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <exception>
#include <filesystem> #include <filesystem>
#include <cstring> #include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
// TODO: cleanup #include "Server.hpp"
static bool set_cloexec(int fd, bool cloexec) { #include "XWayland.hpp"
#include "debug/Log.hpp"
#include "../defines.hpp"
#include "../Compositor.hpp"
#include "../managers/CursorManager.hpp"
// Constants
constexpr int SOCKET_DIR_PERMISSIONS = 0755;
constexpr int SOCKET_BACKLOG = 1;
constexpr int MAX_SOCKET_RETRIES = 32;
constexpr int LOCK_FILE_MODE = 044;
static bool setCloseOnExec(int fd, bool cloexec) {
int flags = fcntl(fd, F_GETFD); int flags = fcntl(fd, F_GETFD);
if (flags == -1) { if (flags == -1) {
Debug::log(ERR, "fcntl failed"); Debug::log(ERR, "fcntl failed");
return false; return false;
} }
if (cloexec) {
if (cloexec)
flags = flags | FD_CLOEXEC; flags = flags | FD_CLOEXEC;
} else { else
flags = flags & ~FD_CLOEXEC; flags = flags & ~FD_CLOEXEC;
}
if (fcntl(fd, F_SETFD, flags) == -1) { if (fcntl(fd, F_SETFD, flags) == -1) {
Debug::log(ERR, "fcntl failed"); Debug::log(ERR, "fcntl failed");
return false; return false;
} }
return true; return true;
} }
static int openSocket(struct sockaddr_un* addr, size_t path_size) { void cleanUpSocket(int fd, const char* path) {
int fd, rc; close(fd);
socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; if (path[0])
unlink(path);
}
fd = socket(AF_UNIX, SOCK_STREAM, 0); static int createSocket(struct sockaddr_un* addr, size_t path_size) {
socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1;
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) { if (fd < 0) {
Debug::log(ERR, "failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
return -1; return -1;
} }
if (!set_cloexec(fd, true)) {
if (!setCloseOnExec(fd, true)) {
close(fd); close(fd);
return -1; return -1;
} }
if (addr->sun_path[0]) { if (addr->sun_path[0])
unlink(addr->sun_path); unlink(addr->sun_path);
}
if (bind(fd, (struct sockaddr*)addr, size) < 0) { if (bind(fd, (struct sockaddr*)addr, size) < 0) {
rc = errno; Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
Debug::log(ERR, "failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); cleanUpSocket(fd, addr->sun_path);
goto cleanup; return -1;
} }
if (listen(fd, 1) < 0) {
rc = errno; if (listen(fd, SOCKET_BACKLOG) < 0) {
Debug::log(ERR, "failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
goto cleanup; cleanUpSocket(fd, addr->sun_path);
return -1;
} }
return fd; return fd;
cleanup:
close(fd);
if (addr->sun_path[0]) {
unlink(addr->sun_path);
}
errno = rc;
return -1;
} }
static bool checkPermissionsForSocketDir(void) { static bool checkPermissionsForSocketDir(void) {
struct stat buf; struct stat buf;
if (lstat("/tmp/.X11-unix", &buf)) { if (lstat("/tmp/.X11-unix", &buf)) {
Debug::log(ERR, "Failed statting X11 socket dir"); Debug::log(ERR, "Failed to stat X11 socket dir");
return false; return false;
} }
if (!(buf.st_mode & S_IFDIR)) { if (!(buf.st_mode & S_IFDIR)) {
Debug::log(ERR, "X11 socket dir is not a dir"); Debug::log(ERR, "X11 socket dir is not a directory");
return false; return false;
} }
if (!((buf.st_uid == 0) || (buf.st_uid == getuid()))) { if (!((buf.st_uid == 0) || (buf.st_uid == getuid()))) {
Debug::log(ERR, "X11 socket dir is not ours"); Debug::log(ERR, "X11 socket dir is not owned by root or current user");
return false; return false;
} }
if (!(buf.st_mode & S_ISVTX)) { if (!(buf.st_mode & S_ISVTX)) {
if ((buf.st_mode & (S_IWGRP | S_IWOTH))) { if ((buf.st_mode & (S_IWGRP | S_IWOTH))) {
Debug::log(ERR, "X11 socket dir is sticky by others"); Debug::log(ERR, "X11 socket dir is writable by others");
return false; return false;
} }
} }
@@ -107,38 +117,51 @@ static bool checkPermissionsForSocketDir(void) {
return true; return true;
} }
static bool openSockets(std::array<int, 2>& sockets, int display) { static bool ensureSocketDirExists() {
auto ret = mkdir("/tmp/.X11-unix", 755); if (mkdir("/tmp/.X11-unix", SOCKET_DIR_PERMISSIONS) != 0) {
if (errno == EEXIST)
if (ret != 0) { return checkPermissionsForSocketDir();
if (errno == EEXIST) { else {
if (!checkPermissionsForSocketDir()) Debug::log(ERR, "XWayland: Couldn't create socket dir");
return false;
} else {
Debug::log(ERR, "XWayland: couldn't create socket dir");
return false; return false;
} }
} }
std::string path; return true;
}
static std::string getSocketPath(int display, bool isLinux) {
if (isLinux)
return std::format("/tmp/.X11-unix/X{}", display);
return std::format("/tmp/.X11-unix/X{}_", display);
}
static bool openSockets(std::array<int, 2>& sockets, int display) {
if (!ensureSocketDirExists())
return false;
sockaddr_un addr = {.sun_family = AF_UNIX}; sockaddr_un addr = {.sun_family = AF_UNIX};
std::string path;
#ifdef __linux__ #ifdef __linux__
// cursed... // cursed...
addr.sun_path[0] = 0; addr.sun_path[0] = 0;
path = std::format("/tmp/.X11-unix/X{}", display); path = getSocketPath(display, true);
strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1); strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1);
#else #else
path = std::format("/tmp/.X11-unix/X{}_", display); path = getSocketPath(display, false);
strncpy(addr.sun_path, path.c_str(), path.length() + 1); strncpy(addr.sun_path, path.c_str(), path.length() + 1);
#endif #endif
sockets[0] = openSocket(&addr, path.length());
sockets[0] = createSocket(&addr, path.length());
if (sockets[0] < 0) if (sockets[0] < 0)
return false; return false;
path = std::format("/tmp/.X11-unix/X{}", display); path = getSocketPath(display, true);
strncpy(addr.sun_path, path.c_str(), path.length() + 1); strncpy(addr.sun_path, path.c_str(), path.length() + 1);
sockets[1] = openSocket(&addr, path.length());
sockets[1] = createSocket(&addr, path.length());
if (sockets[1] < 0) { if (sockets[1] < 0) {
close(sockets[0]); close(sockets[0]);
sockets[0] = -1; sockets[0] = -1;
@@ -160,39 +183,37 @@ static int xwaylandReady(int fd, uint32_t mask, void* data) {
static bool safeRemove(const std::string& path) { static bool safeRemove(const std::string& path) {
try { try {
return std::filesystem::remove(path); return std::filesystem::remove(path);
} catch (std::exception& e) { Debug::log(ERR, "[XWayland] failed to remove {}", path); } } catch (const std::exception& e) { Debug::log(ERR, "[XWayland] Failed to remove {}", path); }
return false; return false;
} }
bool CXWaylandServer::tryOpenSockets() { bool CXWaylandServer::tryOpenSockets() {
for (size_t i = 0; i <= 32; ++i) { for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) {
auto LOCK = std::format("/tmp/.X{}-lock", i); std::string lockPath = std::format("/tmp/.X{}-lock", i);
if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) { int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE);
if (fd >= 0) {
// we managed to open the lock // we managed to open the lock
if (!openSockets(xFDs, i)) { if (!openSockets(xFDs, i)) {
safeRemove(LOCK); safeRemove(lockPath);
close(fd); close(fd);
continue; continue;
} }
const auto PIDSTR = std::format("{}", getpid()); const std::string pidStr = std::to_string(getpid());
if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) {
if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) { safeRemove(lockPath);
safeRemove(LOCK);
close(fd); close(fd);
continue; continue;
} }
close(fd); close(fd);
display = i; display = i;
displayName = std::format(":{}", display); displayName = std::format(":{}", display);
break; break;
} }
int fd = open(LOCK.c_str(), O_RDONLY | O_CLOEXEC); fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC);
if (fd < 0) if (fd < 0)
continue; continue;
@@ -201,21 +222,20 @@ bool CXWaylandServer::tryOpenSockets() {
read(fd, pidstr, sizeof(pidstr) - 1); read(fd, pidstr, sizeof(pidstr) - 1);
close(fd); close(fd);
uint64_t pid = 0; int32_t pid = 0;
try { try {
pid = std::stoi(std::string{pidstr, 11}); pid = std::stoi(std::string{pidstr, 11});
} catch (...) { continue; } } catch (...) { continue; }
if (kill(pid, 0) != 0 && errno == ESRCH) { if (kill(pid, 0) != 0 && errno == ESRCH) {
if (!safeRemove(LOCK)) if (!safeRemove(lockPath))
continue; continue;
i--; i--;
} }
} }
if (display < 0) { if (display < 0) {
Debug::log(ERR, "Failed to find a suitable socket for xwayland"); Debug::log(ERR, "Failed to find a suitable socket for XWayland");
return false; return false;
} }
@@ -232,19 +252,17 @@ CXWaylandServer::~CXWaylandServer() {
if (display < 0) if (display < 0)
return; return;
if (xFDs[0]) close(xFDs[0]);
close(xFDs[0]); close(xFDs[1]);
if (xFDs[1])
close(xFDs[1]);
auto LOCK = std::format("/tmp/.X{}-lock", display); std::string lockPath = std::format("/tmp/.X{}-lock", display);
safeRemove(LOCK); safeRemove(lockPath);
std::string path; std::string path;
#ifdef __linux__ #ifdef __linux__
path = std::format("/tmp/.X11-unix/X{}", display); path = getSocketPath(display, true);
#else #else
path = std::format("/tmp/.X11-unix/X{}_", display); path = getSocketPath(display, false);
#endif #endif
safeRemove(path); safeRemove(path);
} }
@@ -256,7 +274,6 @@ void CXWaylandServer::die() {
if (xFDReadEvents[0]) { if (xFDReadEvents[0]) {
wl_event_source_remove(xFDReadEvents[0]); wl_event_source_remove(xFDReadEvents[0]);
wl_event_source_remove(xFDReadEvents[1]); wl_event_source_remove(xFDReadEvents[1]);
xFDReadEvents = {nullptr, nullptr}; xFDReadEvents = {nullptr, nullptr};
} }
@@ -298,7 +315,7 @@ bool CXWaylandServer::create() {
} }
void CXWaylandServer::runXWayland(int notifyFD) { void CXWaylandServer::runXWayland(int notifyFD) {
if (!set_cloexec(xFDs[0], false) || !set_cloexec(xFDs[1], false) || !set_cloexec(waylandFDs[1], false) || !set_cloexec(xwmFDs[1], false)) { if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) {
Debug::log(ERR, "Failed to unset cloexec on fds"); Debug::log(ERR, "Failed to unset cloexec on fds");
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
@@ -325,7 +342,7 @@ bool CXWaylandServer::start() {
return false; return false;
} }
if (!set_cloexec(waylandFDs[0], true) || !set_cloexec(waylandFDs[1], true)) { if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) {
Debug::log(ERR, "set_cloexec failed (1)"); Debug::log(ERR, "set_cloexec failed (1)");
die(); die();
return false; return false;
@@ -337,7 +354,7 @@ bool CXWaylandServer::start() {
return false; return false;
} }
if (!set_cloexec(xwmFDs[0], true) || !set_cloexec(xwmFDs[1], true)) { if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) {
Debug::log(ERR, "set_cloexec failed (2)"); Debug::log(ERR, "set_cloexec failed (2)");
die(); die();
return false; return false;
@@ -359,7 +376,7 @@ bool CXWaylandServer::start() {
return false; return false;
} }
if (!set_cloexec(notify[0], true)) { if (!setCloseOnExec(notify[0], true)) {
Debug::log(ERR, "set_cloexec failed (3)"); Debug::log(ERR, "set_cloexec failed (3)");
close(notify[0]); close(notify[0]);
close(notify[1]); close(notify[1]);
@@ -382,9 +399,8 @@ bool CXWaylandServer::start() {
if (pid < 0) { if (pid < 0) {
Debug::log(ERR, "second fork failed"); Debug::log(ERR, "second fork failed");
_exit(1); _exit(1);
} else if (pid == 0) { } else if (pid == 0)
runXWayland(notify[1]); runXWayland(notify[1]);
}
_exit(0); _exit(0);
} }

View File

@@ -1,8 +1,8 @@
#ifndef NO_XWAYLAND #ifndef NO_XWAYLAND
#include "XDataSource.hpp"
#include "XWayland.hpp" #include "XWayland.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "XDataSource.hpp"
#include <fcntl.h> #include <fcntl.h>

View File

@@ -5,8 +5,8 @@
#ifndef NO_XWAYLAND #ifndef NO_XWAYLAND
#include "../Compositor.hpp"
#include <ranges> #include <ranges>
#include "../Compositor.hpp"
CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) { CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) {
xcb_res_query_client_ids_cookie_t client_id_cookie = {0}; xcb_res_query_client_ids_cookie_t client_id_cookie = {0};
@@ -196,12 +196,11 @@ void CXWaylandSurface::restackToTop() {
xcb_configure_window(g_pXWayland->pWM->connection, xID, XCB_CONFIG_WINDOW_STACK_MODE, values); xcb_configure_window(g_pXWayland->pWM->connection, xID, XCB_CONFIG_WINDOW_STACK_MODE, values);
for (auto it = g_pXWayland->pWM->mappedSurfacesStacking.begin(); it != g_pXWayland->pWM->mappedSurfacesStacking.end(); ++it) { auto& stack = g_pXWayland->pWM->mappedSurfacesStacking;
if (*it == self) { auto it = std::find(stack.begin(), stack.end(), self);
std::rotate(it, it + 1, g_pXWayland->pWM->mappedSurfacesStacking.end());
break; if (it != stack.end())
} std::rotate(it, it + 1, stack.end());
}
g_pXWayland->pWM->updateClientList(); g_pXWayland->pWM->updateClientList();

View File

@@ -1,20 +1,21 @@
#include "helpers/math/Math.hpp" #include "helpers/math/Math.hpp"
#include <cstdint>
#ifndef NO_XWAYLAND #ifndef NO_XWAYLAND
#include <ranges>
#include <fcntl.h>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <xcb/xcb_icccm.h>
#include "XWayland.hpp" #include "XWayland.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include <unordered_map>
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../protocols/core/Seat.hpp"
#include "../managers/SeatManager.hpp"
#include "../protocols/XWaylandShell.hpp" #include "../protocols/XWaylandShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "../protocols/core/Seat.hpp"
#include <ranges>
#include <algorithm>
#include <fcntl.h>
#include <cstring>
#include <xcb/xcb_icccm.h>
#define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f
#define INCR_CHUNK_SIZE (64 * 1024) #define INCR_CHUNK_SIZE (64 * 1024)
@@ -830,15 +831,15 @@ void CXWM::getRenderFormat() {
free(reply); free(reply);
} }
CXWM::CXWM() { CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) {
connection = xcb_connect_to_fd(g_pXWayland->pServer->xwmFDs[0], nullptr);
if (int ret = xcb_connection_has_error(connection); ret) { if (connection.hasError()) {
Debug::log(ERR, "[xwm] Couldn't start, error {}", ret); Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError());
return; return;
} }
if (xcb_errors_context_new(connection, &errors)) { CXCBErrorContext xcbErrCtx(connection);
if (!xcbErrCtx.isValid()) {
Debug::log(ERR, "[xwm] Couldn't allocate errors context"); Debug::log(ERR, "[xwm] Couldn't allocate errors context");
return; return;
} }
@@ -867,10 +868,7 @@ CXWM::CXWM() {
}; };
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_SUPPORTED"], XCB_ATOM_ATOM, 32, sizeof(supported) / sizeof(*supported), supported); xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_SUPPORTED"], XCB_ATOM_ATOM, 32, sizeof(supported) / sizeof(*supported), supported);
xcb_flush(connection);
setActiveWindow(XCB_WINDOW_NONE); setActiveWindow(XCB_WINDOW_NONE);
initSelection(); initSelection();
listeners.newWLSurface = PROTO::compositor->events.newSurface.registerListener([this](std::any d) { onNewSurface(std::any_cast<SP<CWLSurfaceResource>>(d)); }); listeners.newWLSurface = PROTO::compositor->events.newSurface.registerListener([this](std::any d) { onNewSurface(std::any_cast<SP<CWLSurfaceResource>>(d)); });
@@ -882,11 +880,6 @@ CXWM::CXWM() {
} }
CXWM::~CXWM() { CXWM::~CXWM() {
if (errors)
xcb_errors_context_free(errors);
if (connection)
xcb_disconnect(connection);
if (eventSource) if (eventSource)
wl_event_source_remove(eventSource); wl_event_source_remove(eventSource);

View File

@@ -1,17 +1,16 @@
#pragma once #pragma once
#include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "XDataSource.hpp" #include "XDataSource.hpp"
#include "../helpers/WLListener.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../helpers/signal/Signal.hpp"
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/xcb_errors.h>
#include <xcb/composite.h>
#include <xcb/xfixes.h>
#include <xcb/res.h> #include <xcb/res.h>
#include <xcb/xfixes.h>
#include <xcb/composite.h>
#include <xcb/xcb_errors.h>
struct wl_event_source; struct wl_event_source;
class CXWaylandSurfaceResource; class CXWaylandSurfaceResource;
@@ -58,6 +57,49 @@ struct SXSelection {
std::unique_ptr<SXTransfer> transfer; std::unique_ptr<SXTransfer> transfer;
}; };
class CXCBConnection {
public:
CXCBConnection(int fd) {
connection = xcb_connect_to_fd(fd, nullptr);
}
~CXCBConnection() {
if (connection)
xcb_disconnect(connection);
}
bool hasError() const {
return xcb_connection_has_error(connection);
}
operator xcb_connection_t*() const {
return connection;
}
private:
xcb_connection_t* connection = nullptr;
};
class CXCBErrorContext {
public:
explicit CXCBErrorContext(xcb_connection_t* connection) {
if (xcb_errors_context_new(connection, &errors) != 0)
errors = nullptr;
}
~CXCBErrorContext() {
if (errors)
xcb_errors_context_free(errors);
}
bool isValid() const {
return errors != nullptr;
}
private:
xcb_errors_context_t* errors = nullptr;
};
class CXWM { class CXWM {
public: public:
CXWM(); CXWM();
@@ -123,9 +165,9 @@ class CXWM {
void readProp(SP<CXWaylandSurface> XSURF, uint32_t atom, xcb_get_property_reply_t* reply); void readProp(SP<CXWaylandSurface> XSURF, uint32_t atom, xcb_get_property_reply_t* reply);
// //
xcb_connection_t* connection = nullptr; CXCBConnection connection;
xcb_errors_context_t* errors = nullptr; xcb_errors_context_t* errors = nullptr;
xcb_screen_t* screen = nullptr; xcb_screen_t* screen = nullptr;
xcb_window_t wmWindow; xcb_window_t wmWindow;