mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-16 20:43:48 -07:00
Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
48f2f490d0 | ||
|
94c7996b87 | ||
|
674e7df000 | ||
|
cb7f9140da | ||
|
8579066c7a | ||
|
9232bc2c00 | ||
|
db0b764a5a | ||
|
278583b8a1 | ||
|
4414cd07e2 | ||
|
9e98fb0167 | ||
|
9856378384 | ||
|
dfa1bd0cd4 | ||
|
92df6b0dce | ||
|
71963972bf | ||
|
1bc05b1f9f | ||
|
e6cf643f5a | ||
|
94140e886e | ||
|
b248d59713 | ||
|
cbc0ff6ec0 | ||
|
6b6554adb8 | ||
|
d936eb437b | ||
|
883d01084c | ||
|
0564b46a5e | ||
|
3c9716acfd | ||
|
581f6659f8 | ||
|
e72ae6b25f | ||
|
9e35656244 | ||
|
e87758529e | ||
|
eb97d949aa | ||
|
e74efd87e5 | ||
|
4dbdb556fe | ||
|
5ee4b19691 | ||
|
d35e70a8c6 | ||
|
c35ed8363f | ||
|
d505b33665 | ||
|
118be4dea0 | ||
|
73b9756b8d | ||
|
8b9e385943 | ||
|
e01da1fd7a | ||
|
7a8c013edc | ||
|
518399a95b | ||
|
155d44016d | ||
|
13f90bb87a | ||
|
c67b257e51 | ||
|
8237d7e1a4 | ||
|
85da1a17d8 | ||
|
9609b04ff9 | ||
|
04421063af | ||
|
43e1415e71 | ||
|
e1448732b3 | ||
|
7c4c402bd7 | ||
|
6179b17903 | ||
|
05b48d48d9 | ||
|
07a21fdfa9 |
11
.github/ISSUE_TEMPLATE/bug.yml
vendored
11
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -2,12 +2,13 @@ name: Bug Report
|
||||
description: Something is not working right
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
value: |
|
||||
## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists.
|
||||
|
||||
---
|
||||
label: Already reported ? *
|
||||
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
|
||||
id: type
|
||||
|
11
.github/workflows/nix-build.yml
vendored
11
.github/workflows/nix-build.yml
vendored
@@ -16,17 +16,12 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
submodules: recursive
|
||||
|
||||
- uses: cachix/install-nix-action@v27
|
||||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: hyprland
|
||||
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"
|
||||
|
3
.github/workflows/nix-ci.yml
vendored
3
.github/workflows/nix-ci.yml
vendored
@@ -9,7 +9,6 @@ jobs:
|
||||
secrets: inherit
|
||||
|
||||
build:
|
||||
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure')
|
||||
needs: update-inputs
|
||||
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
|
||||
uses: ./.github/workflows/nix-build.yml
|
||||
secrets: inherit
|
||||
|
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.27)
|
||||
cmake_minimum_required(VERSION 3.30)
|
||||
|
||||
# Get version
|
||||
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(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine)
|
||||
|
||||
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
|
||||
|
||||
pkg_check_modules(
|
||||
deps
|
||||
REQUIRED
|
||||
IMPORTED_TARGET
|
||||
aquamarine
|
||||
xkbcommon
|
||||
uuid
|
||||
wayland-server
|
||||
@@ -111,7 +114,7 @@ pkg_check_modules(
|
||||
gio-2.0
|
||||
hyprlang>=0.3.2
|
||||
hyprcursor>=0.1.7
|
||||
hyprutils>=0.2.1)
|
||||
hyprutils>=0.2.2)
|
||||
|
||||
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
|
||||
|
||||
@@ -213,14 +216,17 @@ set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||
include(CPack)
|
||||
|
||||
message(STATUS "Setting precompiled headers")
|
||||
|
||||
target_precompile_headers(Hyprland PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
|
||||
if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
|
||||
message(STATUS "Not using precompiled headers")
|
||||
else()
|
||||
message(STATUS "Setting precompiled headers")
|
||||
target_precompile_headers(Hyprland PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
|
||||
endif()
|
||||
|
||||
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
|
||||
add_custom_target(generate-protocol-headers)
|
||||
|
24
Makefile
24
Makefile
@@ -1,28 +1,24 @@
|
||||
PREFIX = /usr/local
|
||||
|
||||
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 --build ./build --config Release --target all
|
||||
chmod -R 777 ./build
|
||||
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 -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
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 --build ./build --config Release --target all
|
||||
chmod -R 777 ./build
|
||||
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 -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
release:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Release --target all
|
||||
chmod -R 777 ./build
|
||||
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 -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
debug:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Debug --target all
|
||||
chmod -R 777 ./build
|
||||
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 -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
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 --build ./build --config Release --target all
|
||||
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 -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
|
||||
clear:
|
||||
rm -rf build
|
||||
|
0
assets/install/lockdead.png
Executable file → Normal file
0
assets/install/lockdead.png
Executable file → Normal file
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
@@ -2,5 +2,9 @@ globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check:
|
||||
files = globber.stdout().strip().split('\n')
|
||||
|
||||
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
|
||||
|
@@ -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')
|
||||
|
@@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor
|
||||
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
|
||||
wlroots that doesn\[aq]t sacrifice on its looks.
|
||||
\f[B]Hyprland\f[R] is an independent, highly customizable, dynamic
|
||||
tiling Wayland compositor that doesn\[aq]t sacrifice on its looks.
|
||||
.PP
|
||||
You can launch Hyprland by either going into a TTY and executing
|
||||
\f[B]Hyprland\f[R], or with a login manager.
|
||||
|
@@ -14,8 +14,8 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
===========
|
||||
|
||||
**Hyprland** is a dynamic tiling Wayland compositor based on
|
||||
wlroots that doesn't sacrifice on its looks.
|
||||
**Hyprland** is an independent, highly customizable,
|
||||
dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||
|
||||
You can launch Hyprland by either going into a TTY and
|
||||
executing **Hyprland**, or with a login manager.
|
||||
|
@@ -1,2 +1,2 @@
|
||||
install_man ('Hyprland.1')
|
||||
install_man ('hyprctl.1')
|
||||
install_man('Hyprland.1')
|
||||
install_man('hyprctl.1')
|
||||
|
@@ -59,7 +59,7 @@ env = HYPRCURSOR_SIZE,24
|
||||
# Refer to https://wiki.hyprland.org/Configuring/Variables/
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#general
|
||||
general {
|
||||
general {
|
||||
gaps_in = 5
|
||||
gaps_out = 20
|
||||
|
||||
@@ -70,7 +70,7 @@ general {
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
# Set to true enable resizing windows by clicking and dragging on borders and gaps
|
||||
resize_on_border = false
|
||||
resize_on_border = false
|
||||
|
||||
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||
allow_tearing = false
|
||||
@@ -96,7 +96,7 @@ decoration {
|
||||
enabled = true
|
||||
size = 3
|
||||
passes = 1
|
||||
|
||||
|
||||
vibrancy = 0.1696
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,7 @@ master {
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
||||
misc {
|
||||
misc {
|
||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
|
||||
}
|
||||
@@ -229,13 +229,18 @@ bindm = $mainMod, mouse:272, movewindow
|
||||
bindm = $mainMod, mouse:273, resizewindow
|
||||
|
||||
# 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 = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
||||
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
|
||||
bindel = ,XF86MonBrightnessUp, 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 ###
|
||||
|
@@ -1,2 +1,10 @@
|
||||
install_data('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')
|
||||
install_data(
|
||||
'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
42
flake.lock
generated
@@ -16,11 +16,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1725199881,
|
||||
"narHash": "sha256-jsmipf/u1GFZE5tBUkr56CHMN6VpUWCAjfLIhvQijU0=",
|
||||
"lastModified": 1726665257,
|
||||
"narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"rev": "f8a687dd29ff019657498f1bd14da2fbbf0e604b",
|
||||
"rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -93,11 +93,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1725188252,
|
||||
"narHash": "sha256-yBH8c4GDaEAtBrh+BqIlrx5vp6gG/Gu8fQQK63KAQgs=",
|
||||
"lastModified": 1725997860,
|
||||
"narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "c12ab785ce1982f82594aff03b3104c598186ddd",
|
||||
"rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -116,11 +116,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724966483,
|
||||
"narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=",
|
||||
"lastModified": 1726874949,
|
||||
"narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2",
|
||||
"rev": "d97af4f6bd068c03a518b597675e598f57ea2291",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -139,11 +139,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721324119,
|
||||
"narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=",
|
||||
"lastModified": 1726840673,
|
||||
"narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30",
|
||||
"rev": "b68dab23fc922eae99306988133ee80a40b39ca5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -154,11 +154,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1725103162,
|
||||
"narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=",
|
||||
"lastModified": 1726755586,
|
||||
"narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b",
|
||||
"rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -201,6 +201,12 @@
|
||||
"hyprlang": [
|
||||
"hyprlang"
|
||||
],
|
||||
"hyprutils": [
|
||||
"hyprutils"
|
||||
],
|
||||
"hyprwayland-scanner": [
|
||||
"hyprwayland-scanner"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
@@ -209,11 +215,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1725203932,
|
||||
"narHash": "sha256-VLULC/OnI+6R9KEP2OIGk+uLJJsfRlaLouZ5gyFd2+Y=",
|
||||
"lastModified": 1726851729,
|
||||
"narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "2425e8f541525fa7409d9f26a8ffaf92a3767251",
|
||||
"rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@@ -46,6 +46,8 @@
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprlang.follows = "hyprlang";
|
||||
inputs.hyprutils.follows = "hyprutils";
|
||||
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -95,13 +97,9 @@
|
||||
devShells = eachSystem (system: {
|
||||
default =
|
||||
pkgsFor.${system}.mkShell.override {
|
||||
stdenv = pkgsFor.${system}.gcc14Stdenv;
|
||||
inherit (self.packages.${system}.default) stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [
|
||||
expat
|
||||
libxml2
|
||||
];
|
||||
hardeningDisable = ["fortify"];
|
||||
inputsFrom = [pkgsFor.${system}.hyprland];
|
||||
packages = [pkgsFor.${system}.clang-tools];
|
||||
|
@@ -1,10 +1,26 @@
|
||||
executable('hyprctl', 'main.cpp',
|
||||
executable(
|
||||
'hyprctl',
|
||||
'main.cpp',
|
||||
dependencies: [
|
||||
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('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')
|
||||
install_data(
|
||||
'hyprctl.bash',
|
||||
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',
|
||||
)
|
||||
|
@@ -1,15 +1,31 @@
|
||||
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
|
||||
src = globber.stdout().strip().split('\n')
|
||||
|
||||
executable('hyprpm', src,
|
||||
executable(
|
||||
'hyprpm',
|
||||
src,
|
||||
dependencies: [
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
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('../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')
|
||||
install_data(
|
||||
'../hyprpm.bash',
|
||||
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',
|
||||
)
|
||||
|
29
meson.build
29
meson.build
@@ -1,13 +1,17 @@
|
||||
project('Hyprland', 'cpp', 'c',
|
||||
version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(),
|
||||
default_options : [
|
||||
project(
|
||||
'Hyprland',
|
||||
'cpp',
|
||||
'c',
|
||||
version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(),
|
||||
default_options: [
|
||||
'warning_level=2',
|
||||
'default_library=static',
|
||||
'optimization=3',
|
||||
'buildtype=release',
|
||||
'debug=false',
|
||||
'cpp_std=c++26',
|
||||
])
|
||||
],
|
||||
)
|
||||
|
||||
datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"'
|
||||
add_project_arguments(
|
||||
@@ -16,16 +20,19 @@ add_project_arguments(
|
||||
'-Wno-unused-value',
|
||||
'-Wno-missing-field-initializers',
|
||||
'-Wno-narrowing',
|
||||
'-Wno-pointer-arith',
|
||||
datarootdir,
|
||||
'-Wno-pointer-arith', datarootdir,
|
||||
],
|
||||
language: 'cpp')
|
||||
language: 'cpp',
|
||||
)
|
||||
|
||||
cpp_compiler = meson.get_compiler('cpp')
|
||||
if cpp_compiler.check_header('execinfo.h')
|
||||
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||
endif
|
||||
|
||||
aquamarine = dependency('aquamarine')
|
||||
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
|
||||
|
||||
xcb_dep = dependency('xcb', required: get_option('xwayland'))
|
||||
xcb_composite_dep = dependency('xcb-composite', 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_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')
|
||||
udis = cmake.subproject('udis86')
|
||||
@@ -47,6 +54,7 @@ endif
|
||||
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
|
||||
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
|
||||
|
||||
# Handle options
|
||||
if get_option('systemd').enabled()
|
||||
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
|
||||
endif
|
||||
@@ -59,8 +67,10 @@ if get_option('buildtype') == 'debug'
|
||||
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
|
||||
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)
|
||||
headers = globber.stdout().strip().split('\n')
|
||||
foreach file : headers
|
||||
@@ -75,6 +85,7 @@ subdir('assets')
|
||||
subdir('example')
|
||||
subdir('docs')
|
||||
|
||||
# Generate hyprland.pc
|
||||
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
|
||||
|
||||
import('pkgconfig').generate(
|
||||
|
10
nix/cmake-version.patch
Normal file
10
nix/cmake-version.patch
Normal 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)
|
241
nix/default.nix
241
nix/default.nix
@@ -1,11 +1,11 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
stdenvAdapters,
|
||||
pkg-config,
|
||||
pkgconf,
|
||||
makeWrapper,
|
||||
cmake,
|
||||
ninja,
|
||||
aquamarine,
|
||||
binutils,
|
||||
cairo,
|
||||
@@ -45,133 +45,142 @@
|
||||
enableNvidiaPatches ? false,
|
||||
nvidiaPatches ? false,
|
||||
hidpiXWayland ? false,
|
||||
}:
|
||||
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
|
||||
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
|
||||
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
|
||||
stdenv.mkDerivation {
|
||||
pname = "hyprland${lib.optionalString debug "-debug"}";
|
||||
inherit version;
|
||||
}: let
|
||||
inherit (builtins) baseNameOf foldl';
|
||||
inherit (lib.asserts) assertMsg;
|
||||
inherit (lib.attrsets) mapAttrsToList;
|
||||
inherit (lib.lists) flatten concatLists optional optionals;
|
||||
inherit (lib.sources) cleanSourceWith cleanSource;
|
||||
inherit (lib.strings) cmakeBool hasSuffix makeBinPath optionalString;
|
||||
|
||||
src = lib.cleanSourceWith {
|
||||
filter = name: type: let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
! (lib.hasSuffix ".nix" baseName);
|
||||
src = lib.cleanSource ../.;
|
||||
};
|
||||
adapters = flatten [
|
||||
stdenvAdapters.useMoldLinker
|
||||
];
|
||||
|
||||
patches = [
|
||||
# forces GCC to use -std=c++26
|
||||
./stdcxx.patch
|
||||
];
|
||||
customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters;
|
||||
in
|
||||
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 = ''
|
||||
# Fix hardcoded paths to /usr installation
|
||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||
src = cleanSourceWith {
|
||||
filter = name: type: let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
! (hasSuffix ".nix" baseName);
|
||||
src = cleanSource ../.;
|
||||
};
|
||||
|
||||
# Remove extra @PREFIX@ to fix pkg-config paths
|
||||
sed -i "s#@PREFIX@/##g" hyprland.pc.in
|
||||
'';
|
||||
patches = [
|
||||
# forces GCC to use -std=c++26
|
||||
./stdcxx.patch
|
||||
|
||||
COMMITS = revCount;
|
||||
DATE = date;
|
||||
DIRTY = lib.optionalString (commit == "") "dirty";
|
||||
HASH = commit;
|
||||
# Nix does not have CMake 3.30 yet, so override the minimum version
|
||||
./cmake-version.patch
|
||||
];
|
||||
|
||||
depsBuildBuild = [
|
||||
pkg-config
|
||||
];
|
||||
postPatch = ''
|
||||
# Fix hardcoded paths to /usr installation
|
||||
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
|
||||
|
||||
nativeBuildInputs = [
|
||||
hyprwayland-scanner
|
||||
jq
|
||||
makeWrapper
|
||||
cmake
|
||||
ninja
|
||||
pkg-config
|
||||
python3 # for udis86
|
||||
wayland-scanner
|
||||
];
|
||||
# Remove extra @PREFIX@ to fix pkg-config paths
|
||||
sed -i "s#@PREFIX@/##g" hyprland.pc.in
|
||||
'';
|
||||
|
||||
outputs = [
|
||||
"out"
|
||||
"man"
|
||||
"dev"
|
||||
];
|
||||
COMMITS = revCount;
|
||||
DATE = date;
|
||||
DIRTY = optionalString (commit == "") "dirty";
|
||||
HASH = commit;
|
||||
|
||||
buildInputs = lib.concatLists [
|
||||
[
|
||||
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])
|
||||
];
|
||||
depsBuildBuild = [
|
||||
pkg-config
|
||||
];
|
||||
|
||||
cmakeBuildType =
|
||||
if debug
|
||||
then "Debug"
|
||||
else "RelWithDebInfo";
|
||||
nativeBuildInputs = [
|
||||
hyprwayland-scanner
|
||||
jq
|
||||
makeWrapper
|
||||
cmake
|
||||
pkg-config
|
||||
python3 # for udis86
|
||||
wayland-scanner
|
||||
];
|
||||
|
||||
# we want as much debug info as possible
|
||||
dontStrip = debug;
|
||||
outputs = [
|
||||
"out"
|
||||
"man"
|
||||
"dev"
|
||||
];
|
||||
|
||||
cmakeFlags = [
|
||||
(lib.cmakeBool "NO_XWAYLAND" (!enableXWayland))
|
||||
(lib.cmakeBool "LEGACY_RENDERER" legacyRenderer)
|
||||
(lib.cmakeBool "NO_SYSTEMD" (!withSystemd))
|
||||
];
|
||||
|
||||
postInstall = ''
|
||||
${lib.optionalString wrapRuntimeDeps ''
|
||||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${lib.makeBinPath [
|
||||
binutils
|
||||
buildInputs = concatLists [
|
||||
[
|
||||
aquamarine
|
||||
cairo
|
||||
git
|
||||
hyprcursor
|
||||
hyprlang
|
||||
hyprutils
|
||||
libdrm
|
||||
libGL
|
||||
libinput
|
||||
libuuid
|
||||
libxkbcommon
|
||||
mesa
|
||||
pango
|
||||
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 = {
|
||||
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";
|
||||
};
|
||||
}
|
||||
# we want as much debug info as possible
|
||||
dontStrip = debug;
|
||||
|
||||
cmakeFlags = mapAttrsToList cmakeBool {
|
||||
"NO_XWAYLAND" = !enableXWayland;
|
||||
"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";
|
||||
};
|
||||
}
|
||||
|
@@ -1,77 +1,75 @@
|
||||
wayland_protos = dependency('wayland-protocols',
|
||||
wayland_protos = dependency(
|
||||
'wayland-protocols',
|
||||
version: '>=1.32',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
|
||||
hyprland_protos = dependency('hyprland-protocols',
|
||||
hyprland_protos = dependency(
|
||||
'hyprland-protocols',
|
||||
version: '>=0.2',
|
||||
fallback: 'hyprland-protocols',
|
||||
fallback: 'hyprland-protocols',
|
||||
)
|
||||
|
||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
|
||||
wayland_protocol_dir = wayland_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_dep.get_variable('hyprwayland_scanner'),
|
||||
native: true,
|
||||
)
|
||||
|
||||
new_protocols = [
|
||||
['wlr-gamma-control-unstable-v1.xml'],
|
||||
['wlr-foreign-toplevel-management-unstable-v1.xml'],
|
||||
['wlr-output-power-management-unstable-v1.xml'],
|
||||
['input-method-unstable-v2.xml'],
|
||||
['virtual-keyboard-unstable-v1.xml'],
|
||||
['wlr-virtual-pointer-unstable-v1.xml'],
|
||||
['wlr-output-management-unstable-v1.xml'],
|
||||
['kde-server-decoration.xml'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['wayland-drm.xml'],
|
||||
['wlr-data-control-unstable-v1.xml'],
|
||||
['wlr-screencopy-unstable-v1.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'],
|
||||
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'],
|
||||
[wl_protocol_dir, 'stable/tablet/tablet-v2.xml'],
|
||||
[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
[wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'],
|
||||
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
|
||||
[wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/xdg-dialog/xdg-dialog-v1.xml'],
|
||||
protocols = [
|
||||
'wlr-gamma-control-unstable-v1.xml',
|
||||
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
||||
'wlr-output-power-management-unstable-v1.xml',
|
||||
'input-method-unstable-v2.xml',
|
||||
'virtual-keyboard-unstable-v1.xml',
|
||||
'wlr-virtual-pointer-unstable-v1.xml',
|
||||
'wlr-output-management-unstable-v1.xml',
|
||||
'kde-server-decoration.xml',
|
||||
'wlr-layer-shell-unstable-v1.xml',
|
||||
'wayland-drm.xml',
|
||||
'wlr-data-control-unstable-v1.xml',
|
||||
'wlr-screencopy-unstable-v1.xml',
|
||||
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
|
||||
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
|
||||
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
|
||||
wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
|
||||
wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/relative-pointer/relative-pointer-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml',
|
||||
wayland_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml',
|
||||
wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml',
|
||||
wayland_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml',
|
||||
wayland_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml',
|
||||
wayland_protocol_dir / 'stable/tablet/tablet-v2.xml',
|
||||
wayland_protocol_dir / 'stable/presentation-time/presentation-time.xml',
|
||||
wayland_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
|
||||
wayland_protocol_dir / 'unstable/primary-selection/primary-selection-unstable-v1.xml',
|
||||
wayland_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
|
||||
wayland_protocol_dir / 'stable/viewporter/viewporter.xml',
|
||||
wayland_protocol_dir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml',
|
||||
wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
|
||||
wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
|
||||
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
|
||||
]
|
||||
|
||||
wl_protos_src = []
|
||||
wl_protos_headers = []
|
||||
|
||||
new_wl_protos = []
|
||||
foreach p : new_protocols
|
||||
xml = join_paths(p)
|
||||
new_wl_protos += custom_target(
|
||||
xml.underscorify(),
|
||||
input: xml,
|
||||
wl_protocols = []
|
||||
foreach protocol : protocols
|
||||
wl_protocols += custom_target(
|
||||
protocol.underscorify(),
|
||||
input: protocol,
|
||||
install: true,
|
||||
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
|
||||
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
|
||||
@@ -79,31 +77,26 @@ foreach p : new_protocols
|
||||
)
|
||||
endforeach
|
||||
|
||||
wayland_server_dep = dependency('wayland-server', version: '>=1.20.0')
|
||||
wayland_server_dir = wayland_server_dep.get_variable('pkgdatadir')
|
||||
# wayland.xml generation
|
||||
wayland_scanner = dependency('wayland-scanner')
|
||||
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
|
||||
|
||||
wl_server_protos = [
|
||||
wayland_server_dir / 'wayland.xml'
|
||||
]
|
||||
wl_server_protos_gen = []
|
||||
foreach p : wl_server_protos
|
||||
wl_server_protos_gen += custom_target(
|
||||
p.underscorify(),
|
||||
input: p,
|
||||
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
|
||||
wayland_xml = wayland_scanner_datadir / 'wayland.xml'
|
||||
wayland_protocol = custom_target(
|
||||
wayland_xml.underscorify(),
|
||||
input: wayland_xml,
|
||||
install: true,
|
||||
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
|
||||
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
|
||||
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
|
||||
)
|
||||
|
||||
lib_server_protos = static_library(
|
||||
'server_protos',
|
||||
wl_protos_src + wl_protos_headers + new_wl_protos + wl_server_protos_gen,
|
||||
dependencies: wayland_server_dep.partial_dependency(compile_args: true),
|
||||
wl_protocols + wayland_protocol,
|
||||
)
|
||||
|
||||
server_protos = declare_dependency(
|
||||
link_with: lib_server_protos,
|
||||
sources: wl_protos_headers + new_wl_protos,
|
||||
sources: wl_protocols + wayland_protocol,
|
||||
)
|
||||
|
@@ -2696,7 +2696,17 @@ WORKSPACEID CCompositor::getNewSpecialID() {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -2943,6 +2953,38 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
|
||||
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) {
|
||||
// add it to real
|
||||
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_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR);
|
||||
|
||||
checkDefaultCursorWarp(PNEWMONITOR);
|
||||
|
||||
for (auto const& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iMonitorID == PNEWMONITOR->ID) {
|
||||
w->m_iLastSurfaceMonitorID = MONITOR_INVALID;
|
||||
|
@@ -1049,6 +1049,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.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:
|
||||
|
@@ -371,6 +371,7 @@ CConfigManager::CConfigManager() {
|
||||
m_pConfig->addConfigValue("misc:initial_workspace_tracking", 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:disable_xdg_env_checks", Hyprlang::INT{0});
|
||||
|
||||
m_pConfig->addConfigValue("group:insert_after_current", 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) {
|
||||
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); });
|
||||
}
|
||||
|
@@ -72,7 +72,7 @@ env = HYPRCURSOR_SIZE,24
|
||||
# Refer to https://wiki.hyprland.org/Configuring/Variables/
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#general
|
||||
general {
|
||||
general {
|
||||
gaps_in = 5
|
||||
gaps_out = 20
|
||||
|
||||
@@ -83,7 +83,7 @@ general {
|
||||
col.inactive_border = rgba(595959aa)
|
||||
|
||||
# Set to true enable resizing windows by clicking and dragging on borders and gaps
|
||||
resize_on_border = false
|
||||
resize_on_border = false
|
||||
|
||||
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
||||
allow_tearing = false
|
||||
@@ -109,7 +109,7 @@ decoration {
|
||||
enabled = true
|
||||
size = 3
|
||||
passes = 1
|
||||
|
||||
|
||||
vibrancy = 0.1696
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ master {
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
||||
misc {
|
||||
misc {
|
||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
|
||||
}
|
||||
@@ -249,6 +249,12 @@ bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
|
||||
bindel = ,XF86MonBrightnessUp, 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 ###
|
||||
##############################
|
||||
|
@@ -858,7 +858,8 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
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
|
||||
result += "legacyrenderer\n";
|
||||
@@ -881,8 +882,10 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
"commit_date": "{}",
|
||||
"tag": "{}",
|
||||
"commits": "{}",
|
||||
"buildAquamarine": "{}",
|
||||
"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
|
||||
result += "\"legacyrenderer\",";
|
||||
@@ -987,9 +990,9 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
|
||||
const auto COMMAND = in.substr(0, secondSpacePos);
|
||||
const auto VALUE = in.substr(secondSpacePos + 1);
|
||||
|
||||
// If either COMMAND or VALUE is empty, handle accordingly
|
||||
if (COMMAND.empty() || VALUE.empty())
|
||||
return "Invalid input: command or value is empty";
|
||||
// If COMMAND is empty, handle accordingly
|
||||
if (COMMAND.empty())
|
||||
return "Invalid input: command is empty";
|
||||
|
||||
std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE);
|
||||
|
||||
|
@@ -394,6 +394,11 @@ void CLayerSurface::applyRules() {
|
||||
} else if (rule.rule.starts_with("animation")) {
|
||||
CVarList vars{rule.rule, 2, 's'};
|
||||
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"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,6 +55,7 @@ class CLayerSurface {
|
||||
bool ignoreAlpha = false;
|
||||
float ignoreAlphaValue = 0.f;
|
||||
bool dimAround = false;
|
||||
int64_t order = 0;
|
||||
|
||||
std::optional<std::string> animationStyle;
|
||||
|
||||
|
@@ -991,7 +991,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
|
||||
const auto PCURRENT = getGroupCurrent();
|
||||
const bool FULLSCREEN = PCURRENT->isFullscreen();
|
||||
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 PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
|
||||
|
@@ -2,7 +2,6 @@
|
||||
#include "MiscFunctions.hpp"
|
||||
#include "math/Math.hpp"
|
||||
#include "sync/SyncReleaser.hpp"
|
||||
#include "ScopeGuard.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/GammaControl.hpp"
|
||||
@@ -17,7 +16,9 @@
|
||||
#include "sync/SyncTimeline.hpp"
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::Utils;
|
||||
|
||||
int ratHandler(void* data) {
|
||||
g_pHyprRenderer->renderMonitor((CMonitor*)data);
|
||||
@@ -192,10 +193,6 @@ void CMonitor::onConnect(bool noRule) {
|
||||
if (!activeMonitorRule.mirrorOf.empty())
|
||||
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
|
||||
g_pCompositor->setActiveMonitor(this);
|
||||
|
||||
@@ -224,6 +221,10 @@ void CMonitor::onConnect(bool noRule) {
|
||||
PROTO::gamma->applyGammaToState(this);
|
||||
|
||||
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) {
|
||||
@@ -281,9 +282,6 @@ void CMonitor::onDisconnect(bool destroy) {
|
||||
|
||||
Debug::log(LOG, "Removed monitor {}!", szName);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
|
||||
EMIT_HOOK_EVENT("monitorRemoved", this);
|
||||
|
||||
if (!BACKUPMON) {
|
||||
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
|
||||
g_pCompositor->enterUnsafeState();
|
||||
@@ -342,6 +340,9 @@ void CMonitor::onDisconnect(bool destroy) {
|
||||
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
|
||||
}
|
||||
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) {
|
||||
|
@@ -1,10 +0,0 @@
|
||||
#include "ScopeGuard.hpp"
|
||||
|
||||
CScopeGuard::CScopeGuard(const std::function<void()>& fn_) : fn(fn_) {
|
||||
;
|
||||
}
|
||||
|
||||
CScopeGuard::~CScopeGuard() {
|
||||
if (fn)
|
||||
fn();
|
||||
}
|
@@ -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;
|
||||
};
|
23
src/main.cpp
23
src/main.cpp
@@ -4,6 +4,9 @@
|
||||
#include "config/ConfigManager.hpp"
|
||||
#include "init/initHelpers.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
@@ -20,6 +23,7 @@ void help() {
|
||||
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 << " --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) {
|
||||
@@ -109,6 +113,25 @@ int main(int argc, char** argv) {
|
||||
} else if (it->compare("-h") == 0 || it->compare("--help") == 0) {
|
||||
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;
|
||||
} else {
|
||||
std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n";
|
||||
|
@@ -2730,7 +2730,7 @@ SDispatchResult CKeybindManager::moveIntoGroup(std::string args) {
|
||||
|
||||
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
|
||||
|
||||
if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny)
|
||||
if (!PWINDOW || PWINDOW->m_sGroupData.deny)
|
||||
return {};
|
||||
|
||||
auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg);
|
||||
|
@@ -221,6 +221,7 @@ class CKeybindManager {
|
||||
friend class CInputManager;
|
||||
friend class CConfigManager;
|
||||
friend class CWorkspace;
|
||||
friend class CPointerManager;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CKeybindManager> g_pKeybindManager;
|
||||
|
@@ -18,13 +18,7 @@ CPointerManager::CPointerManager() {
|
||||
onMonitorLayoutChange();
|
||||
|
||||
PMONITOR->events.modeChanged.registerStaticListener(
|
||||
[this, PMONITOR](void* owner, std::any data) {
|
||||
g_pEventLoopManager->doLater([this, PMONITOR]() {
|
||||
onMonitorLayoutChange();
|
||||
checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name);
|
||||
});
|
||||
},
|
||||
nullptr);
|
||||
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
|
||||
PMONITOR->events.disconnect.registerStaticListener(
|
||||
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
|
||||
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() {
|
||||
for (auto const& state : monitorStates)
|
||||
state->softwareLocks++;
|
||||
@@ -246,9 +208,8 @@ void CPointerManager::recheckEnteredOutputs() {
|
||||
|
||||
// if we are using hw cursors, prevent
|
||||
// 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))
|
||||
s->monitor->output->moveCursor({-1337, -420});
|
||||
setHWCursorBuffer(s, nullptr);
|
||||
|
||||
if (!currentCursorImage.surface)
|
||||
continue;
|
||||
@@ -307,6 +268,8 @@ void CPointerManager::resetCursorImage(bool apply) {
|
||||
void CPointerManager::updateCursorBackend() {
|
||||
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
|
||||
|
||||
const auto CURSORBOX = getCursorBoxGlobal();
|
||||
|
||||
for (auto const& m : g_pCompositor->m_vMonitors) {
|
||||
auto state = stateFor(m);
|
||||
|
||||
@@ -315,6 +278,15 @@ void CPointerManager::updateCursorBackend() {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty();
|
||||
|
||||
if (!CROSSES) {
|
||||
if (state->cursorFrontBuffer)
|
||||
setHWCursorBuffer(state, nullptr);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) {
|
||||
Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName);
|
||||
state->box = getCursorBoxLogicalForMonitor(state->monitor.lock());
|
||||
@@ -335,17 +307,34 @@ void CPointerManager::onCursorMoved() {
|
||||
if (!hasCursor())
|
||||
return;
|
||||
|
||||
const auto CURSORBOX = getCursorBoxGlobal();
|
||||
bool recalc = false;
|
||||
|
||||
for (auto const& m : g_pCompositor->m_vMonitors) {
|
||||
auto state = stateFor(m);
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
const auto CURSORPOS = getCursorPosForMonitor(m);
|
||||
m->output->moveCursor(CURSORPOS);
|
||||
}
|
||||
|
||||
if (recalc)
|
||||
updateCursorBackend();
|
||||
}
|
||||
|
||||
bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerState> state) {
|
||||
@@ -675,7 +664,7 @@ void CPointerManager::damageIfSoftware() {
|
||||
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
|
||||
|
||||
for (auto const& mw : monitorStates) {
|
||||
if (mw->monitor.expired())
|
||||
if (mw->monitor.expired() || !mw->monitor->output)
|
||||
continue;
|
||||
|
||||
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() {
|
||||
currentMonitorLayout.monitorBoxes.clear();
|
||||
for (auto const& m : g_pCompositor->m_vMonitors) {
|
||||
if (m->isMirror() || !m->m_bEnabled)
|
||||
if (m->isMirror() || !m->m_bEnabled || !m->output)
|
||||
continue;
|
||||
|
||||
currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize});
|
||||
@@ -821,6 +810,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
static auto PMOUSEDPMS = CConfigValue<Hyprlang::INT>("misc:mouse_move_enables_dpms");
|
||||
|
||||
//
|
||||
auto listener = pointerListeners.emplace_back(makeShared<SPointerListener>());
|
||||
|
||||
listener->pointer = pointer;
|
||||
@@ -836,6 +828,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
||||
g_pInputManager->onMouseMoved(E);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
|
||||
g_pKeybindManager->dpms("on");
|
||||
});
|
||||
|
||||
listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) {
|
||||
@@ -844,6 +839,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
||||
g_pInputManager->onMouseWarp(E);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
|
||||
g_pKeybindManager->dpms("on");
|
||||
});
|
||||
|
||||
listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) {
|
||||
@@ -872,6 +870,9 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
|
||||
g_pInputManager->onSwipeBegin(E);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
|
||||
g_pKeybindManager->dpms("on");
|
||||
});
|
||||
|
||||
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::idle->onActivity();
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
|
||||
g_pKeybindManager->dpms("on");
|
||||
});
|
||||
|
||||
listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) {
|
||||
@@ -938,6 +942,9 @@ void CPointerManager::attachTouch(SP<ITouch> touch) {
|
||||
if (!touch)
|
||||
return;
|
||||
|
||||
static auto PMOUSEDPMS = CConfigValue<Hyprlang::INT>("misc:mouse_move_enables_dpms");
|
||||
|
||||
//
|
||||
auto listener = touchListeners.emplace_back(makeShared<STouchListener>());
|
||||
|
||||
listener->touch = touch;
|
||||
@@ -953,6 +960,9 @@ void CPointerManager::attachTouch(SP<ITouch> touch) {
|
||||
g_pInputManager->onTouchDown(E);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
|
||||
g_pKeybindManager->dpms("on");
|
||||
});
|
||||
|
||||
listener->up = touch->touchEvents.up.registerListener([this] (std::any e) {
|
||||
@@ -987,6 +997,9 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) {
|
||||
if (!tablet)
|
||||
return;
|
||||
|
||||
static auto PMOUSEDPMS = CConfigValue<Hyprlang::INT>("misc:mouse_move_enables_dpms");
|
||||
|
||||
//
|
||||
auto listener = tabletListeners.emplace_back(makeShared<STabletListener>());
|
||||
|
||||
listener->tablet = tablet;
|
||||
@@ -1002,6 +1015,9 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) {
|
||||
g_pInputManager->onTabletAxis(E);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
|
||||
g_pKeybindManager->dpms("on");
|
||||
});
|
||||
|
||||
listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) {
|
||||
@@ -1018,6 +1034,9 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) {
|
||||
g_pInputManager->onTabletTip(E);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS)
|
||||
g_pKeybindManager->dpms("on");
|
||||
});
|
||||
|
||||
listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) {
|
||||
|
@@ -26,7 +26,6 @@ class CPointerManager {
|
||||
public:
|
||||
CPointerManager();
|
||||
|
||||
void checkDefaultCursorWarp(SP<CMonitor> monitor, std::string monitorName);
|
||||
void attachPointer(SP<IPointer> pointer);
|
||||
void attachTouch(SP<ITouch> touch);
|
||||
void attachTablet(SP<CTablet> tablet);
|
||||
|
@@ -46,11 +46,8 @@ void CHyprXWaylandManager::activateSurface(SP<CWLSurfaceResource> pSurface, bool
|
||||
PWINDOW->m_pXWaylandSurface->restackToTop();
|
||||
}
|
||||
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);
|
||||
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) {
|
||||
|
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "../../managers/PointerManager.hpp"
|
||||
#include "../../managers/SeatManager.hpp"
|
||||
#include "../../managers/KeybindManager.hpp"
|
||||
|
||||
#include <aquamarine/input/Input.hpp>
|
||||
|
||||
@@ -135,7 +136,6 @@ void CInputManager::sendMotionEventsToFocused() {
|
||||
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
|
||||
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 PFLOATBEHAVIOR = CConfigValue<Hyprlang::INT>("input:float_switch_override_focus");
|
||||
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)
|
||||
return;
|
||||
|
||||
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) {
|
||||
// enable dpms
|
||||
g_pKeybindManager->dpms("on");
|
||||
}
|
||||
|
||||
Vector2D mouseCoords = getMouseCoordsInternal();
|
||||
const auto MOUSECOORDSFLOORED = mouseCoords.floor();
|
||||
|
||||
@@ -854,6 +849,8 @@ void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard)
|
||||
}
|
||||
|
||||
void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
|
||||
static auto PDPMS = CConfigValue<Hyprlang::INT>("misc:key_press_enables_dpms");
|
||||
|
||||
m_vHIDs.push_back(keeb);
|
||||
|
||||
try {
|
||||
@@ -882,6 +879,9 @@ void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
|
||||
|
||||
if (PKEEB->enabled)
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON)
|
||||
g_pKeybindManager->dpms("on");
|
||||
},
|
||||
keeb.get());
|
||||
|
||||
@@ -893,6 +893,9 @@ void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
|
||||
|
||||
if (PKEEB->enabled)
|
||||
PROTO::idle->onActivity();
|
||||
|
||||
if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON)
|
||||
g_pKeybindManager->dpms("on");
|
||||
},
|
||||
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}};
|
||||
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);
|
||||
|
||||
auto e = std::any_cast<IKeyboard::SKeyEvent>(event);
|
||||
|
@@ -106,20 +106,22 @@ void CInputMethodRelay::updateAllPopups() {
|
||||
}
|
||||
}
|
||||
|
||||
void CInputMethodRelay::activateIME(CTextInput* pInput) {
|
||||
void CInputMethodRelay::activateIME(CTextInput* pInput, bool shouldCommit) {
|
||||
if (m_pIME.expired())
|
||||
return;
|
||||
|
||||
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())
|
||||
return;
|
||||
|
||||
m_pIME->deactivate();
|
||||
commitIMEState(pInput);
|
||||
if (shouldCommit)
|
||||
commitIMEState(pInput);
|
||||
}
|
||||
|
||||
void CInputMethodRelay::commitIMEState(CTextInput* pInput) {
|
||||
|
@@ -21,8 +21,8 @@ class CInputMethodRelay {
|
||||
void onNewTextInput(WP<CTextInputV3> tiv3);
|
||||
void onNewTextInput(WP<CTextInputV1> pTIV1);
|
||||
|
||||
void activateIME(CTextInput* pInput);
|
||||
void deactivateIME(CTextInput* pInput);
|
||||
void activateIME(CTextInput* pInput, bool shouldCommit = true);
|
||||
void deactivateIME(CTextInput* pInput, bool shouldCommit = true);
|
||||
void commitIMEState(CTextInput* pInput);
|
||||
void removeTextInput(CTextInput* pInput);
|
||||
|
||||
|
@@ -22,6 +22,7 @@ void CTextInput::initCallbacks() {
|
||||
listeners.enable = INPUT->events.enable.registerListener([this](std::any p) { onEnabled(); });
|
||||
listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); });
|
||||
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.surfaceUnmap.reset();
|
||||
listeners.surfaceDestroy.reset();
|
||||
@@ -41,6 +42,7 @@ void CTextInput::initCallbacks() {
|
||||
});
|
||||
listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); });
|
||||
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.surfaceUnmap.reset();
|
||||
listeners.surfaceDestroy.reset();
|
||||
@@ -93,13 +95,28 @@ void CTextInput::onDisabled() {
|
||||
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() {
|
||||
if (g_pInputManager->m_sIMERelay.m_pIME.expired()) {
|
||||
// Debug::log(WARN, "Committing TextInput on no IME!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(isV3() ? pV3Input->current.enabled : pV1Input->active)) {
|
||||
if (!(isV3() ? pV3Input->current.enabled.value : pV1Input->active)) {
|
||||
Debug::log(WARN, "Disabled TextInput commit?");
|
||||
return;
|
||||
}
|
||||
@@ -128,8 +145,12 @@ void CTextInput::setFocusedSurface(SP<CWLSurfaceResource> pSurface) {
|
||||
listeners.surfaceUnmap.reset();
|
||||
listeners.surfaceDestroy.reset();
|
||||
|
||||
if (isV3() && !pV3Input.expired() && pV3Input->current.enabled)
|
||||
pV3Input->current.enabled = false;
|
||||
if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) {
|
||||
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())
|
||||
g_pInputManager->m_sIMERelay.deactivateIME(this);
|
||||
@@ -144,8 +165,12 @@ void CTextInput::setFocusedSurface(SP<CWLSurfaceResource> pSurface) {
|
||||
listeners.surfaceUnmap.reset();
|
||||
listeners.surfaceDestroy.reset();
|
||||
|
||||
if (isV3() && !pV3Input.expired() && pV3Input->current.enabled)
|
||||
pV3Input->current.enabled = false;
|
||||
if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) {
|
||||
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())
|
||||
g_pInputManager->m_sIMERelay.deactivateIME(this);
|
||||
@@ -192,13 +217,9 @@ void CTextInput::leave() {
|
||||
enterLocks = 0;
|
||||
}
|
||||
|
||||
if (isV3()) {
|
||||
if (isV3())
|
||||
pV3Input->leave(focusedSurface());
|
||||
if (pV3Input->current.enabled) {
|
||||
pV3Input->current.enabled = false;
|
||||
onDisabled();
|
||||
}
|
||||
} else
|
||||
else
|
||||
pV1Input->leave();
|
||||
|
||||
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->preeditString(pV1Input->serial, ime->current.preeditString.string.c_str(), "");
|
||||
} else {
|
||||
INPUT->preeditCursor(ime->current.preeditString.begin);
|
||||
INPUT->preeditCursor(0);
|
||||
INPUT->preeditStyling(0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
|
||||
INPUT->preeditString(pV1Input->serial, "", "");
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ class CTextInput {
|
||||
void onEnabled(SP<CWLSurfaceResource> surfV1 = nullptr);
|
||||
void onDisabled();
|
||||
void onCommit();
|
||||
void onReset();
|
||||
|
||||
bool hasCursorRectangle();
|
||||
CBox cursorBox();
|
||||
@@ -47,6 +48,7 @@ class CTextInput {
|
||||
struct {
|
||||
CHyprSignalListener enable;
|
||||
CHyprSignalListener disable;
|
||||
CHyprSignalListener reset;
|
||||
CHyprSignalListener commit;
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener surfaceUnmap;
|
||||
|
@@ -1,12 +1,14 @@
|
||||
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
|
||||
src = globber.stdout().strip().split('\n')
|
||||
|
||||
executable('Hyprland', src,
|
||||
executable(
|
||||
'Hyprland',
|
||||
src,
|
||||
link_args: '-rdynamic',
|
||||
cpp_pch: 'pch/pch.hpp',
|
||||
dependencies: [
|
||||
server_protos,
|
||||
dependency('aquamarine'),
|
||||
aquamarine,
|
||||
dependency('gbm'),
|
||||
dependency('xcursor'),
|
||||
dependency('wayland-server'),
|
||||
@@ -38,5 +40,5 @@ executable('Hyprland', src,
|
||||
dependency('pangocairo'),
|
||||
dependency('uuid'),
|
||||
],
|
||||
install : true
|
||||
install: true,
|
||||
)
|
||||
|
@@ -19,7 +19,7 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out
|
||||
|
||||
pMonitor = OUTPUTRES->monitor;
|
||||
|
||||
if (!pMonitor) {
|
||||
if (!pMonitor || !pMonitor->output) {
|
||||
LOGM(ERR, "No CMonitor");
|
||||
resource->sendFailed();
|
||||
return;
|
||||
|
@@ -31,6 +31,7 @@ CTextInputV1::CTextInputV1(SP<CZwpTextInputV1> resource_) : resource(resource_)
|
||||
resource->setReset([this](CZwpTextInputV1* pMgr) {
|
||||
pendingSurrounding.isPending = false;
|
||||
pendingContentType.isPending = false;
|
||||
events.reset.emit();
|
||||
});
|
||||
|
||||
resource->setSetSurroundingText(
|
||||
|
@@ -37,6 +37,7 @@ class CTextInputV1 {
|
||||
CSignal onCommit;
|
||||
CSignal enable;
|
||||
CSignal disable;
|
||||
CSignal reset;
|
||||
CSignal destroy;
|
||||
} events;
|
||||
|
||||
|
@@ -19,17 +19,22 @@ CTextInputV3::CTextInputV3(SP<CZwpTextInputV3> resource_) : resource(resource_)
|
||||
resource->setOnDestroy([this](CZwpTextInputV3* r) { PROTO::textInputV3->destroyTextInput(this); });
|
||||
|
||||
resource->setCommit([this](CZwpTextInputV3* r) {
|
||||
bool wasEnabled = current.enabled;
|
||||
bool wasEnabled = current.enabled.value;
|
||||
|
||||
current = pending;
|
||||
serial++;
|
||||
|
||||
if (wasEnabled && !current.enabled)
|
||||
if (wasEnabled && !current.enabled.value)
|
||||
events.disable.emit();
|
||||
else if (!wasEnabled && current.enabled)
|
||||
else if (!wasEnabled && current.enabled.value)
|
||||
events.enable.emit();
|
||||
else if (current.enabled.value && current.enabled.isEnablePending && current.enabled.isDisablePending)
|
||||
events.reset.emit();
|
||||
else
|
||||
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) {
|
||||
@@ -54,10 +59,14 @@ CTextInputV3::CTextInputV3(SP<CZwpTextInputV3> resource_) : resource(resource_)
|
||||
|
||||
resource->setEnable([this](CZwpTextInputV3* r) {
|
||||
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() {
|
||||
|
@@ -31,6 +31,7 @@ class CTextInputV3 {
|
||||
CSignal onCommit;
|
||||
CSignal enable;
|
||||
CSignal disable;
|
||||
CSignal reset;
|
||||
CSignal destroy;
|
||||
} events;
|
||||
|
||||
@@ -53,7 +54,11 @@ class CTextInputV3 {
|
||||
CBox cursorBox;
|
||||
} 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;
|
||||
|
||||
|
@@ -82,9 +82,18 @@ void CWLDataOfferResource::sendData() {
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
if (resource->version() >= 3) {
|
||||
resource->sendSourceActions(7);
|
||||
resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
|
||||
const auto SOURCEACTIONS = source->actions();
|
||||
|
||||
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()) {
|
||||
@@ -113,7 +122,7 @@ CWLDataSourceResource::CWLDataSourceResource(SP<CWlDataSource> resource_, SP<CWL
|
||||
resource->setOffer([this](CWlDataSource* r, const char* mime) { mimeTypes.push_back(mime); });
|
||||
resource->setSetActions([this](CWlDataSource* r, uint32_t 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);
|
||||
}
|
||||
|
||||
uint32_t CWLDataSourceResource::actions() {
|
||||
return supportedActions;
|
||||
}
|
||||
|
||||
CWLDataDeviceResource::CWLDataDeviceResource(SP<CWlDataDevice> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
@@ -513,7 +526,10 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
|
||||
if (!box.has_value())
|
||||
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());
|
||||
}
|
||||
});
|
||||
|
@@ -65,6 +65,7 @@ class CWLDataSourceResource : public IDataSource {
|
||||
virtual bool dndDone();
|
||||
virtual void error(uint32_t code, const std::string& msg);
|
||||
virtual void sendDndFinished();
|
||||
virtual uint32_t actions(); // wl_data_device_manager.dnd_action
|
||||
|
||||
void sendDndDropPerformed();
|
||||
void sendDndAction(wl_data_device_manager_dnd_action a);
|
||||
@@ -78,7 +79,7 @@ class CWLDataSourceResource : public IDataSource {
|
||||
WP<CWLDataSourceResource> self;
|
||||
|
||||
std::vector<std::string> mimeTypes;
|
||||
uint32_t actions = 0;
|
||||
uint32_t supportedActions = 0;
|
||||
|
||||
private:
|
||||
SP<CWlDataSource> resource;
|
||||
|
@@ -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,
|
||||
};
|
||||
|
||||
for (auto const& fmt : g_pHyprOpenGL->getDRMFormats()) {
|
||||
if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end())
|
||||
continue;
|
||||
|
||||
shmFormats.push_back(fmt.drmFormat);
|
||||
for (auto const& fmt : supportedShmFourccFormats) {
|
||||
shmFormats.push_back(fmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,8 +16,15 @@ CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs
|
||||
|
||||
auto eglImage = g_pHyprOpenGL->createEGLImage(attrs);
|
||||
|
||||
if (!eglImage)
|
||||
return;
|
||||
if (!eglImage) {
|
||||
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
|
||||
opaque = FormatUtils::isFormatOpaque(attrs.format);
|
||||
|
@@ -23,3 +23,7 @@ eDataSourceType IDataSource::type() {
|
||||
void IDataSource::sendDndFinished() {
|
||||
;
|
||||
}
|
||||
|
||||
uint32_t IDataSource::actions() {
|
||||
return 7; // all
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ class IDataSource {
|
||||
virtual void markUsed();
|
||||
virtual void error(uint32_t code, const std::string& msg) = 0;
|
||||
virtual eDataSourceType type();
|
||||
virtual uint32_t actions(); // wl_data_device_manager.dnd_action
|
||||
|
||||
struct {
|
||||
CSignal destroy;
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#include "Renderer.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../helpers/math/Math.hpp"
|
||||
#include "../helpers/ScopeGuard.hpp"
|
||||
#include "../helpers/sync/SyncReleaser.hpp"
|
||||
#include <algorithm>
|
||||
#include <aquamarine/output/Output.hpp>
|
||||
@@ -23,6 +22,9 @@
|
||||
#include "../helpers/sync/SyncTimeline.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
|
||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||
using namespace Hyprutils::Utils;
|
||||
|
||||
extern "C" {
|
||||
#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};
|
||||
|
||||
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)
|
||||
arrangeLayerArray(PMONITOR, la, true, &usableArea);
|
||||
|
||||
|
@@ -1,105 +1,115 @@
|
||||
#include <cstdint>
|
||||
#ifndef NO_XWAYLAND
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../managers/CursorManager.hpp"
|
||||
#include "XWayland.hpp"
|
||||
|
||||
#include <format>
|
||||
#include <string>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <cstring>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
// TODO: cleanup
|
||||
static bool set_cloexec(int fd, bool cloexec) {
|
||||
#include "Server.hpp"
|
||||
#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);
|
||||
if (flags == -1) {
|
||||
Debug::log(ERR, "fcntl failed");
|
||||
return false;
|
||||
}
|
||||
if (cloexec) {
|
||||
|
||||
if (cloexec)
|
||||
flags = flags | FD_CLOEXEC;
|
||||
} else {
|
||||
else
|
||||
flags = flags & ~FD_CLOEXEC;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETFD, flags) == -1) {
|
||||
Debug::log(ERR, "fcntl failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int openSocket(struct sockaddr_un* addr, size_t path_size) {
|
||||
int fd, rc;
|
||||
socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1;
|
||||
void cleanUpSocket(int fd, const char* path) {
|
||||
close(fd);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
if (!set_cloexec(fd, true)) {
|
||||
|
||||
if (!setCloseOnExec(fd, true)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr->sun_path[0]) {
|
||||
if (addr->sun_path[0])
|
||||
unlink(addr->sun_path);
|
||||
}
|
||||
|
||||
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);
|
||||
goto cleanup;
|
||||
Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
cleanUpSocket(fd, addr->sun_path);
|
||||
return -1;
|
||||
}
|
||||
if (listen(fd, 1) < 0) {
|
||||
rc = errno;
|
||||
Debug::log(ERR, "failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
goto cleanup;
|
||||
|
||||
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);
|
||||
cleanUpSocket(fd, addr->sun_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
cleanup:
|
||||
close(fd);
|
||||
if (addr->sun_path[0]) {
|
||||
unlink(addr->sun_path);
|
||||
}
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool checkPermissionsForSocketDir(void) {
|
||||
struct stat 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(buf.st_mode & S_ISVTX)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -107,38 +117,51 @@ static bool checkPermissionsForSocketDir(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool openSockets(std::array<int, 2>& sockets, int display) {
|
||||
auto ret = mkdir("/tmp/.X11-unix", 755);
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!checkPermissionsForSocketDir())
|
||||
return false;
|
||||
} else {
|
||||
Debug::log(ERR, "XWayland: couldn't create socket dir");
|
||||
static bool ensureSocketDirExists() {
|
||||
if (mkdir("/tmp/.X11-unix", SOCKET_DIR_PERMISSIONS) != 0) {
|
||||
if (errno == EEXIST)
|
||||
return checkPermissionsForSocketDir();
|
||||
else {
|
||||
Debug::log(ERR, "XWayland: Couldn't create socket dir");
|
||||
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};
|
||||
std::string path;
|
||||
|
||||
#ifdef __linux__
|
||||
// cursed...
|
||||
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);
|
||||
#else
|
||||
path = std::format("/tmp/.X11-unix/X{}_", display);
|
||||
path = getSocketPath(display, false);
|
||||
strncpy(addr.sun_path, path.c_str(), path.length() + 1);
|
||||
#endif
|
||||
sockets[0] = openSocket(&addr, path.length());
|
||||
|
||||
sockets[0] = createSocket(&addr, path.length());
|
||||
if (sockets[0] < 0)
|
||||
return false;
|
||||
|
||||
path = std::format("/tmp/.X11-unix/X{}", display);
|
||||
path = getSocketPath(display, true);
|
||||
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) {
|
||||
close(sockets[0]);
|
||||
sockets[0] = -1;
|
||||
@@ -160,39 +183,37 @@ static int xwaylandReady(int fd, uint32_t mask, void* data) {
|
||||
static bool safeRemove(const std::string& path) {
|
||||
try {
|
||||
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;
|
||||
}
|
||||
|
||||
bool CXWaylandServer::tryOpenSockets() {
|
||||
for (size_t i = 0; i <= 32; ++i) {
|
||||
auto LOCK = std::format("/tmp/.X{}-lock", i);
|
||||
for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++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
|
||||
if (!openSockets(xFDs, i)) {
|
||||
safeRemove(LOCK);
|
||||
safeRemove(lockPath);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto PIDSTR = std::format("{}", getpid());
|
||||
|
||||
if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) {
|
||||
safeRemove(LOCK);
|
||||
const std::string pidStr = std::to_string(getpid());
|
||||
if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) {
|
||||
safeRemove(lockPath);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
display = i;
|
||||
displayName = std::format(":{}", display);
|
||||
break;
|
||||
}
|
||||
|
||||
int fd = open(LOCK.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (fd < 0)
|
||||
continue;
|
||||
@@ -201,21 +222,20 @@ bool CXWaylandServer::tryOpenSockets() {
|
||||
read(fd, pidstr, sizeof(pidstr) - 1);
|
||||
close(fd);
|
||||
|
||||
uint64_t pid = 0;
|
||||
int32_t pid = 0;
|
||||
try {
|
||||
pid = std::stoi(std::string{pidstr, 11});
|
||||
} catch (...) { continue; }
|
||||
|
||||
if (kill(pid, 0) != 0 && errno == ESRCH) {
|
||||
if (!safeRemove(LOCK))
|
||||
if (!safeRemove(lockPath))
|
||||
continue;
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -232,19 +252,17 @@ CXWaylandServer::~CXWaylandServer() {
|
||||
if (display < 0)
|
||||
return;
|
||||
|
||||
if (xFDs[0])
|
||||
close(xFDs[0]);
|
||||
if (xFDs[1])
|
||||
close(xFDs[1]);
|
||||
close(xFDs[0]);
|
||||
close(xFDs[1]);
|
||||
|
||||
auto LOCK = std::format("/tmp/.X{}-lock", display);
|
||||
safeRemove(LOCK);
|
||||
std::string lockPath = std::format("/tmp/.X{}-lock", display);
|
||||
safeRemove(lockPath);
|
||||
|
||||
std::string path;
|
||||
#ifdef __linux__
|
||||
path = std::format("/tmp/.X11-unix/X{}", display);
|
||||
path = getSocketPath(display, true);
|
||||
#else
|
||||
path = std::format("/tmp/.X11-unix/X{}_", display);
|
||||
path = getSocketPath(display, false);
|
||||
#endif
|
||||
safeRemove(path);
|
||||
}
|
||||
@@ -256,7 +274,6 @@ void CXWaylandServer::die() {
|
||||
if (xFDReadEvents[0]) {
|
||||
wl_event_source_remove(xFDReadEvents[0]);
|
||||
wl_event_source_remove(xFDReadEvents[1]);
|
||||
|
||||
xFDReadEvents = {nullptr, nullptr};
|
||||
}
|
||||
|
||||
@@ -298,7 +315,7 @@ bool CXWaylandServer::create() {
|
||||
}
|
||||
|
||||
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");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -325,7 +342,7 @@ bool CXWaylandServer::start() {
|
||||
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)");
|
||||
die();
|
||||
return false;
|
||||
@@ -337,7 +354,7 @@ bool CXWaylandServer::start() {
|
||||
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)");
|
||||
die();
|
||||
return false;
|
||||
@@ -359,7 +376,7 @@ bool CXWaylandServer::start() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!set_cloexec(notify[0], true)) {
|
||||
if (!setCloseOnExec(notify[0], true)) {
|
||||
Debug::log(ERR, "set_cloexec failed (3)");
|
||||
close(notify[0]);
|
||||
close(notify[1]);
|
||||
@@ -382,9 +399,8 @@ bool CXWaylandServer::start() {
|
||||
if (pid < 0) {
|
||||
Debug::log(ERR, "second fork failed");
|
||||
_exit(1);
|
||||
} else if (pid == 0) {
|
||||
} else if (pid == 0)
|
||||
runXWayland(notify[1]);
|
||||
}
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#ifndef NO_XWAYLAND
|
||||
|
||||
#include "XDataSource.hpp"
|
||||
#include "XWayland.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "XDataSource.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
|
@@ -5,8 +5,8 @@
|
||||
|
||||
#ifndef NO_XWAYLAND
|
||||
|
||||
#include "../Compositor.hpp"
|
||||
#include <ranges>
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
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};
|
||||
@@ -196,12 +196,11 @@ void CXWaylandSurface::restackToTop() {
|
||||
|
||||
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) {
|
||||
if (*it == self) {
|
||||
std::rotate(it, it + 1, g_pXWayland->pWM->mappedSurfacesStacking.end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto& stack = g_pXWayland->pWM->mappedSurfacesStacking;
|
||||
auto it = std::find(stack.begin(), stack.end(), self);
|
||||
|
||||
if (it != stack.end())
|
||||
std::rotate(it, it + 1, stack.end());
|
||||
|
||||
g_pXWayland->pWM->updateClientList();
|
||||
|
||||
|
@@ -1,20 +1,21 @@
|
||||
#include "helpers/math/Math.hpp"
|
||||
#include <cstdint>
|
||||
#ifndef NO_XWAYLAND
|
||||
|
||||
#include <ranges>
|
||||
#include <fcntl.h>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
#include "XWayland.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include <unordered_map>
|
||||
#include "../Compositor.hpp"
|
||||
#include "../protocols/core/Seat.hpp"
|
||||
#include "../managers/SeatManager.hpp"
|
||||
#include "../protocols/XWaylandShell.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 INCR_CHUNK_SIZE (64 * 1024)
|
||||
@@ -830,15 +831,15 @@ void CXWM::getRenderFormat() {
|
||||
free(reply);
|
||||
}
|
||||
|
||||
CXWM::CXWM() {
|
||||
connection = xcb_connect_to_fd(g_pXWayland->pServer->xwmFDs[0], nullptr);
|
||||
CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) {
|
||||
|
||||
if (int ret = xcb_connection_has_error(connection); ret) {
|
||||
Debug::log(ERR, "[xwm] Couldn't start, error {}", ret);
|
||||
if (connection.hasError()) {
|
||||
Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (xcb_errors_context_new(connection, &errors)) {
|
||||
CXCBErrorContext xcbErrCtx(connection);
|
||||
if (!xcbErrCtx.isValid()) {
|
||||
Debug::log(ERR, "[xwm] Couldn't allocate errors context");
|
||||
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_flush(connection);
|
||||
|
||||
setActiveWindow(XCB_WINDOW_NONE);
|
||||
|
||||
initSelection();
|
||||
|
||||
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() {
|
||||
if (errors)
|
||||
xcb_errors_context_free(errors);
|
||||
|
||||
if (connection)
|
||||
xcb_disconnect(connection);
|
||||
|
||||
if (eventSource)
|
||||
wl_event_source_remove(eventSource);
|
||||
|
@@ -1,17 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../helpers/WLListener.hpp"
|
||||
#include "../macros.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_errors.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/xfixes.h>
|
||||
#include <xcb/res.h>
|
||||
#include <xcb/xfixes.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/xcb_errors.h>
|
||||
|
||||
struct wl_event_source;
|
||||
class CXWaylandSurfaceResource;
|
||||
@@ -58,6 +57,49 @@ struct SXSelection {
|
||||
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 {
|
||||
public:
|
||||
CXWM();
|
||||
@@ -123,9 +165,9 @@ class CXWM {
|
||||
void readProp(SP<CXWaylandSurface> XSURF, uint32_t atom, xcb_get_property_reply_t* reply);
|
||||
|
||||
//
|
||||
xcb_connection_t* connection = nullptr;
|
||||
xcb_errors_context_t* errors = nullptr;
|
||||
xcb_screen_t* screen = nullptr;
|
||||
CXCBConnection connection;
|
||||
xcb_errors_context_t* errors = nullptr;
|
||||
xcb_screen_t* screen = nullptr;
|
||||
|
||||
xcb_window_t wmWindow;
|
||||
|
||||
|
Reference in New Issue
Block a user