Compare commits

..

113 Commits

Author SHA1 Message Date
Vaxry
4520b30d49 version: bump to 0.44.1 2024-10-09 13:54:39 +01:00
trianta
8405aa111d output: update state even if no owner exists (#8044) 2024-10-09 13:47:52 +01:00
Vaxry
ad46257cce output/xdg-output: avoid sending events to released globals
ref #6835
2024-10-09 13:47:52 +01:00
Vaxry
0cfbe618b5 keyboard: update group state on change for the sym resolve state
fixes #8038
2024-10-09 13:47:52 +01:00
Vaxry
7d0944acdf defaultConfig: add a nofocus rule for weird X windows
ref #6543
2024-10-09 13:47:52 +01:00
Vaxry
b9990468f3 pointer: expand sw cursor damage box
fixes #8031

just a bit, rounding errors I guess
2024-10-09 13:47:52 +01:00
vaxerski
736a8735b3 keybinds: fixup xkb_states for resolve_by_sym
fixes #7750
2024-10-09 13:47:52 +01:00
Vaxry
b54eecbd79 config: give simple help for super+q not working
only on default config :P
2024-10-09 13:47:52 +01:00
Ikalco
657aeb3946 screencopy: fix screencopy frames not being cleaned up (#8017)
---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-10-09 13:47:52 +01:00
Aqa-Ib
6807430b18 layout: fix auto group when opening a new window in a non-focused workspace using window rules (#8006) 2024-10-09 13:47:52 +01:00
Vaxry
0c7a7e2d56 version: bump to 0.44.0 2024-10-06 12:04:13 +01:00
Vaxry
0ec6072a29 single-pixel: set buffer size to 1,1 2024-10-05 16:36:57 +01:00
Vaxry
3ca699debf opengl: use GL_CLAMP_TO_EDGE instead of GL_CLAMP
avoid error spam on select hw
2024-10-05 14:57:18 +01:00
Vaxry
52c0919621 monitor: arrange monitors on connect and disconnect 2024-10-05 14:41:44 +01:00
Vaxry
6fbfeefc71 protocolmgr: don't expose the fallback output 2024-10-05 14:40:03 +01:00
Vaxry
46bf87c8d1 monitor: use a scope guard for disconnect events 2024-10-05 14:37:12 +01:00
Vaxry
595eb89f6e renderer: Fix resize artifacts (stretching, bumps) (#7499) 2024-10-05 01:01:21 +01:00
Vaxry
a815b14bf1 monitor: cleanup and modernize scheduleDone 2024-10-05 01:01:21 +01:00
Vaxry
3a5052a714 compositor: update all xdg outputs on arrange 2024-10-05 01:01:21 +01:00
Vaxry
8e237b006f xdg-output: minor cleanups 2024-10-05 01:01:20 +01:00
Theo Paris
1ed925b69c internal: fix missing include directive (#7984)
This should fix building with clang.
2024-10-04 09:41:27 +01:00
Maximilian Seidler
aed529f695 renderer: fix uvBR calculation (#7975) 2024-10-03 23:00:44 +01:00
Aqa-Ib
de68e065fe layout: fix dragging a window into a group after e242694 (#7976) 2024-10-02 21:25:25 +01:00
Aqa-Ib
e2426942e5 layout: add auto_group to control default grouping (#7883) 2024-10-02 10:22:19 +01:00
Vaxry
5c6c300abf wayland/output: send geometry in updateState 2024-09-30 17:42:36 +01:00
Vaxry
6bd3397141 wlr-output-management: accept 0 refresh rates
fixes #7879
2024-09-30 17:40:38 +01:00
Vaxry
68fd32c810 byteoperations: add missing header 2024-09-30 17:27:10 +01:00
Vaxry
3ddb16bd5b compositor/wayland: up the max buffer size to avoid disconnects when app hangs 2024-09-30 17:25:57 +01:00
Trianta
f6387536f6 protocol: fix missing include 2024-09-30 10:06:39 +03:00
Trianta
968f6a6013 meson: fix arch build with new protocol 2024-09-30 10:06:39 +03:00
Vaxry
488efab636 single-pixel-buffer: new protocol impl
fixes #6624
2024-09-30 00:58:16 +01:00
Gliczy
6649255d54 flake.lock: update 2024-09-29 17:56:27 +03:00
Luke Chen
4b00cba319 dwindle: add movetoroot method to layout messages (#7903) 2024-09-29 14:47:59 +01:00
Mike Will
9e418671e1 config: add descriptions for dwindle and master layout options (#7933) 2024-09-29 14:42:10 +01:00
Mihai Fufezan
d73c14751a CI/Nix: git+https -> github 2024-09-28 21:53:18 +03:00
bivsk
6f313de952 core: Fix Musl builds (#7934)
Musl does not include the internal type `__time_t`.
Use `time_t` instead.
2024-09-28 13:46:31 +01:00
Mike Will
2cf6e7862a dwindle: add config option split_bias (#7920)
If `default_split_ratio` is greater than 1.0, `split_bias` will give the
bigger half to a specific window:

0 - positional (default)
1 - current window
2 - opening window
2024-09-28 01:49:40 +01:00
Mihai Fufezan
58669fef77 flake.lock: update 2024-09-27 18:35:29 +03:00
Vaxry
e20aef7d53 opengl: remove debug log 2024-09-26 22:34:33 +01:00
Mihai Fufezan
b2143a98e2 CI/Nix: no longer build with submodules 2024-09-27 00:07:52 +03:00
Mihai Fufezan
f75f8efb1b Meson: add tracy dependency 2024-09-27 00:07:52 +03:00
Mihai Fufezan
be96787ed0 CMake: use udis86 from pkg-config, fallback to subproject
Only canihavesomecoffee's fork (the one the subproject uses) provides
a .pc file, so we either find the correct version or we use the
subproject.
2024-09-27 00:07:52 +03:00
Mihai Fufezan
89d945aabe CMake: use hyprland-protocols from pkg-config, fallback to subproject
protocolnew: fix external path, which may not be in $CMAKE_SOURCE_DIR
2024-09-27 00:07:52 +03:00
Mihai Fufezan
27211c71e9 Meson: try to find udis86 through pkgconfig, fallback to subproject
Only the fork provides a .pc file, so there's no risk of linking the wrong
lib version. If pkg-config can't find it (most cases), fall back to using
the subproject through the wrap file.
2024-09-27 00:07:52 +03:00
Mihai Fufezan
14942bca60 Nix: re-add hyprland-protocols 2024-09-27 00:07:52 +03:00
Mihai Fufezan
77f2a01304 flake.lock: update nixpkgs 2024-09-26 21:17:07 +03:00
Mihai Fufezan
7b56ce6521 CI/Nix: add cross build 2024-09-26 21:17:07 +03:00
Jörg Thalheim
32a8caf7e7 Nix: also test cross build 2024-09-26 21:17:07 +03:00
Vaxry
caaa9b11e4 wlr-output-configuration: Improve output configuration (#7571) 2024-09-26 11:10:53 +01:00
Kamikadze
b1ad2d8066 dispatchers: fixup dpms toggle (#7875)
now toggles every monitor individually
2024-09-26 00:08:50 +01:00
Vaxry
22746b3046 hyprctl: use the getMonitorData helper everywhere 2024-09-25 23:38:11 +01:00
Vaxry
49713fab04 pointermgr: avoid hogging CMonitor refs 2024-09-25 23:15:41 +01:00
vaxerski
8b86ee8bf0 github: encourage usage of --systeminfo if Hyprland won't launch 2024-09-25 10:39:33 +01:00
vaxerski
2a052c69f3 core: add a --systeminfo parameter to gather systeminfo without running 2024-09-25 10:36:51 +01:00
Vaxry
2320b2241c Internal: move to Mat3x3 from hyprutils (#7902)
* Meson: require hyprutils >= 0.2.3

* flake.lock: update hyprutils

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-09-25 10:01:13 +01:00
vaxerski
8f5188269b hyprctl: add solitary field to hyprctl monitors 2024-09-25 09:59:18 +01:00
vaxerski
00c8626863 hyprctl: add submap request
fixes #7898
2024-09-24 11:25:05 +01:00
Vaxry
0a211f29f5 hyprctl: add defaultName to workspacerules
fixes #7886
2024-09-24 01:19:05 +01:00
Vaxry
d279d7c4c6 eventloop: dispatch pending in session on start
fixes #7855 #7391
2024-09-24 00:49:29 +01:00
diniamo
6c78b03bb7 flake: update xdph 2024-09-24 00:47:34 +01:00
Vaxry
f79497087b internal: nuke wlsignal and related
old semi-wrappers for wl_signal, they are no longer used
2024-09-24 00:47:34 +01:00
Artur Manuel
508bde1f61 core: add HYPRLAND_CONFIG environment variable (#7851) 2024-09-23 16:40:19 +01:00
diniamo
e5ff19ac0f flake: update xdph 2024-09-22 11:55:13 +03:00
Mihai Fufezan
8579066c7a Nix: clean up derivation 2024-09-21 14:27:13 +03:00
Vaxry
9232bc2c00 internal: move to hyprutils' scopeguard
bumps hyprutils dep to 0.2.2
2024-09-21 00:37:17 +01:00
Vaxry
db0b764a5a shm: send a static list of shm formats
fixes #7733
2024-09-20 22:56:15 +01:00
Mihai Fufezan
278583b8a1 flake.lock: update 2024-09-20 20:16:13 +03:00
Jasson
4414cd07e2 xwm: Minor cleanup, add wrappers for basic types (#7856) 2024-09-20 12:32:04 +01:00
Vaxry
9e98fb0167 dmabuffer: attempt importing failed dmabufs as implicit
don't ask me why, vulkan doesn't like this.

funny note, broken on wlroots :P

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

* Made requested changes

* removed braces

* fix

* Ok this time is fixed

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

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

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

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

* Nix: add patch for CMake min ver

---------

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

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

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

* fix yaml syntax

* clarify text

* validation

* revert validation

* markdown

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

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

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

View File

@@ -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
@@ -28,10 +29,10 @@ body:
attributes:
label: System Info and Version
description: |
Paste the output of `hyprctl systeminfo -c` here (If you are on a
version that shows you help menu, omit the `-c` and attach config files
to the issue). If you have configs outside of the main config shown
here, please attach.
Paste the output of `hyprctl systeminfo -c` here. If you can't
launch Hyprland, paste the output of `Hyprland --systeminfo`.
If `Hyprland --systeminfo` errors out (added in 0.44.0), find
and paste the Hyprland version manually.
value: "<details>
<summary>System/Version info</summary>

View File

@@ -12,21 +12,17 @@ jobs:
matrix:
package:
- hyprland
- hyprland-cross
- xdg-desktop-portal-hyprland
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 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"

View File

@@ -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

View File

@@ -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)
@@ -25,8 +25,18 @@ message(STATUS "Gathering git info")
execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# udis
add_subdirectory("subprojects/udis86")
find_package(PkgConfig REQUIRED)
# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not
# provide a .pc file and won't be detected this way
pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2)
# Fallback to subproject
if(NOT udis_dep_FOUND)
add_subdirectory("subprojects/udis86")
include_directories("subprojects/udis86")
message(STATUS "udis86 dependency not found, falling back to subproject")
endif()
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
@@ -47,8 +57,6 @@ else()
set(BUILDTYPE_LOWER "release")
endif()
find_package(PkgConfig REQUIRED)
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
@@ -63,7 +71,8 @@ else()
message(STATUS "Configuring Hyprland in Release with CMake")
endif()
include_directories(. "src/" "subprojects/udis86/" "protocols/")
include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26)
add_compile_options(
-Wall
@@ -91,14 +100,17 @@ 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
wayland-server>=1.22.90
wayland-protocols
cairo
pango
@@ -111,7 +123,7 @@ pkg_check_modules(
gio-2.0
hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.1)
hyprutils>=0.2.3)
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -220,14 +232,19 @@ target_precompile_headers(Hyprland PRIVATE
message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::deps)
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep)
else()
target_link_libraries(Hyprland libudis86)
endif()
# used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers)
function(protocolnew protoPath protoName external)
if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
set(path ${protoPath})
else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif()
@@ -255,14 +272,22 @@ function(protocolWayland)
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
libudis86)
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
protocolnew("subprojects/hyprland-protocols/protocols"
"hyprland-global-shortcuts-v1" true)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0)
if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
else()
set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols")
message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}")
endif()
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
true)
protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocolnew("subprojects/hyprland-protocols/protocols"
"hyprland-toplevel-export-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
true)
protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
@@ -273,8 +298,7 @@ protocolnew("protocols" "input-method-unstable-v2" true)
protocolnew("protocols" "wlr-output-management-unstable-v1" true)
protocolnew("protocols" "kde-server-decoration" true)
protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1"
true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolnew("protocols" "wayland-drm" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false)
@@ -306,6 +330,7 @@ protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
protocolnew("staging/drm-lease" "drm-lease-v1" false)
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolwayland()

View File

@@ -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

View File

@@ -1 +1 @@
0.43.0
0.44.1

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

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View File

@@ -2,5 +2,9 @@ globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check:
files = globber.stdout().strip().split('\n')
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

View File

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

View File

@@ -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.

View File

@@ -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.

View File

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

View File

@@ -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 ###
@@ -250,4 +255,8 @@ bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

View File

@@ -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',
)

74
flake.lock generated
View File

@@ -16,11 +16,11 @@
]
},
"locked": {
"lastModified": 1725199881,
"narHash": "sha256-jsmipf/u1GFZE5tBUkr56CHMN6VpUWCAjfLIhvQijU0=",
"lastModified": 1727261104,
"narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "f8a687dd29ff019657498f1bd14da2fbbf0e604b",
"rev": "b82fdaff917582a9d568969e15e61b398c71e990",
"type": "github"
},
"original": {
@@ -42,11 +42,11 @@
]
},
"locked": {
"lastModified": 1722623071,
"narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=",
"lastModified": 1727532803,
"narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "912d56025f03d41b1ad29510c423757b4379eb1c",
"rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f",
"type": "github"
},
"original": {
@@ -56,6 +56,29 @@
}
},
"hyprland-protocols": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1727451107,
"narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-protocols",
"type": "github"
}
},
"hyprland-protocols_2": {
"inputs": {
"nixpkgs": [
"xdph",
@@ -93,11 +116,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 +139,11 @@
]
},
"locked": {
"lastModified": 1724966483,
"narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=",
"lastModified": 1727300645,
"narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2",
"rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c",
"type": "github"
},
"original": {
@@ -139,11 +162,11 @@
]
},
"locked": {
"lastModified": 1721324119,
"narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=",
"lastModified": 1726874836,
"narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30",
"rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
"type": "github"
},
"original": {
@@ -154,11 +177,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1725103162,
"narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=",
"lastModified": 1727348695,
"narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b",
"rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
"type": "github"
},
"original": {
@@ -172,6 +195,7 @@
"inputs": {
"aquamarine": "aquamarine",
"hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang",
"hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner",
@@ -197,10 +221,16 @@
},
"xdph": {
"inputs": {
"hyprland-protocols": "hyprland-protocols",
"hyprland-protocols": "hyprland-protocols_2",
"hyprlang": [
"hyprlang"
],
"hyprutils": [
"hyprutils"
],
"hyprwayland-scanner": [
"hyprwayland-scanner"
],
"nixpkgs": [
"nixpkgs"
],
@@ -209,11 +239,11 @@
]
},
"locked": {
"lastModified": 1725203932,
"narHash": "sha256-VLULC/OnI+6R9KEP2OIGk+uLJJsfRlaLouZ5gyFd2+Y=",
"lastModified": 1727524473,
"narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "2425e8f541525fa7409d9f26a8ffaf92a3767251",
"rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26",
"type": "github"
},
"original": {

View File

@@ -22,6 +22,12 @@
inputs.hyprlang.follows = "hyprlang";
};
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprlang = {
url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs";
@@ -46,6 +52,8 @@
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprlang.follows = "hyprlang";
inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
};
};
@@ -65,6 +73,15 @@
hyprland-extras
];
});
pkgsCrossFor = eachSystem (system: crossSystem:
import nixpkgs {
localSystem = system;
crossSystem = crossSystem;
overlays = with self.overlays; [
hyprland-packages
hyprland-extras
];
});
in {
overlays = import ./nix/overlays.nix {inherit self lib inputs;};
@@ -90,18 +107,15 @@
xdg-desktop-portal-hyprland
;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
});
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];

View File

@@ -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',
)

View File

@@ -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',
)

View File

@@ -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,11 +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)
cmake = import('cmake')
udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86')
gio_dep = dependency('gio-2.0', required: true)
if not xcb_dep.found()
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
@@ -47,6 +50,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,14 +63,22 @@ 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
install_headers(file, subdir: 'hyprland', preserve_path: true)
endforeach
tracy = dependency('tracy', static: true, required: get_option('tracy_enable'))
if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized'
warning('Profiling builds should set -- buildtype = debugoptimized')
endif
subdir('protocols')
subdir('src')
subdir('hyprctl')
@@ -75,6 +87,7 @@ subdir('assets')
subdir('example')
subdir('docs')
# Generate hyprland.pc
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
import('pkgconfig').generate(

View File

@@ -1,3 +1,4 @@
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling')

View File

@@ -1,20 +1,21 @@
{
lib,
stdenv,
stdenvAdapters,
pkg-config,
pkgconf,
makeWrapper,
cmake,
meson,
ninja,
aquamarine,
binutils,
cairo,
git,
hyprcursor,
hyprland-protocols,
hyprlang,
hyprutils,
hyprwayland-scanner,
jq,
libGL,
libdrm,
libexecinfo,
@@ -24,9 +25,9 @@
mesa,
pango,
pciutils,
python3,
systemd,
tomlplusplus,
udis86-hyprland,
wayland,
wayland-protocols,
wayland-scanner,
@@ -45,133 +46,140 @@
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) hasSuffix makeBinPath optionalString mesonBool mesonEnable;
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
'';
postPatch = ''
# Fix hardcoded paths to /usr installation
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
COMMITS = revCount;
DATE = date;
DIRTY = lib.optionalString (commit == "") "dirty";
HASH = commit;
# Remove extra @PREFIX@ to fix pkg-config paths
sed -i "s#@PREFIX@/##g" hyprland.pc.in
'';
depsBuildBuild = [
pkg-config
];
COMMITS = revCount;
DATE = date;
DIRTY = optionalString (commit == "") "dirty";
HASH = commit;
nativeBuildInputs = [
hyprwayland-scanner
jq
makeWrapper
cmake
ninja
pkg-config
python3 # for udis86
wayland-scanner
];
depsBuildBuild = [
pkg-config
];
outputs = [
"out"
"man"
"dev"
];
nativeBuildInputs = [
hyprwayland-scanner
makeWrapper
meson
ninja
pkg-config
];
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])
];
outputs = [
"out"
"man"
"dev"
];
cmakeBuildType =
if debug
then "Debug"
else "RelWithDebInfo";
# we want as much debug info as possible
dontStrip = debug;
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
hyprland-protocols
hyprlang
hyprutils
libdrm
libGL
libinput
libuuid
libxkbcommon
mesa
pango
pciutils
pkgconf
]}
''}
'';
tomlplusplus
udis86-hyprland
wayland
wayland-protocols
wayland-scanner
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"];
mesonBuildType =
if debug
then "debugoptimized"
else "release";
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;
mesonFlags = flatten [
(mapAttrsToList mesonEnable {
"xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer;
"systemd" = withSystemd;
})
(mapAttrsToList mesonBool {
"b_pch" = false;
"tracy_enable" = false;
})
];
postInstall = ''
${optionalString wrapRuntimeDeps ''
wrapProgram $out/bin/Hyprland \
--suffix PATH : ${makeBinPath [
binutils
pciutils
pkgconf
]}
''}
'';
passthru.providedSessions = ["hyprland"];
meta = {
homepage = "https://github.com/hyprwm/Hyprland";
description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = lib.licenses.bsd3;
platforms = lib.platforms.linux;
mainProgram = "Hyprland";
};
}

View File

@@ -22,9 +22,11 @@ in {
# Dependencies
inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default
inputs.hyprland-protocols.overlays.default
inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default
self.overlays.udis86
# Hyprland packages themselves
(final: prev: let
@@ -63,4 +65,20 @@ in {
hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland
];
# udis86 from nixpkgs is too old, and also does not provide a .pc file
# this version is the one used in the git submodule, and allows us to
# fetch the source without '?submodules=1'
udis86 = final: prev: {
udis86-hyprland = prev.udis86.overrideAttrs (self: super: {
src = final.fetchFromGitHub {
owner = "canihavesomecoffee";
repo = "udis86";
rev = "5336633af70f3917760a6d441ff02d93477b0c86";
hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g=";
};
patches = [];
});
};
}

View File

@@ -1,12 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfbd431f..73e8e0c2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,7 @@ endif()
include_directories(. "src/" "subprojects/udis86/" "protocols/")
set(CMAKE_CXX_STANDARD 26)
add_compile_options(
+ -std=c++26
-Wall
-Wextra
-Wno-unused-parameter

View File

@@ -1,77 +1,76 @@
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',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-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 +78,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,
)

View File

@@ -23,11 +23,13 @@
#include "protocols/PointerConstraints.hpp"
#include "protocols/LayerShell.hpp"
#include "protocols/XDGShell.hpp"
#include "protocols/XDGOutput.hpp"
#include "protocols/core/Compositor.hpp"
#include "protocols/core/Subcompositor.hpp"
#include "desktop/LayerSurface.hpp"
#include "render/Renderer.hpp"
#include "xwayland/XWayland.hpp"
#include "helpers/ByteOperations.hpp"
#include <hyprutils/string/String.hpp>
#include <aquamarine/input/Input.hpp>
@@ -229,6 +231,9 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
if (envEnabled("HYPRLAND_TRACE"))
Debug::trace = true;
// set the buffer size to 1MB to avoid disconnects due to an app hanging for a short while
wl_display_set_default_max_buffer_size(m_sWLDisplay, 1_MB);
Aquamarine::SBackendOptions options;
options.logFunction = aqLog;
@@ -2696,7 +2701,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) {
@@ -2855,6 +2870,8 @@ void CCompositor::arrangeMonitors() {
else
m->xwaylandScale = 1.f;
}
PROTO::xdgOutput->updateAllOutputs();
}
void CCompositor::enterUnsafeState() {
@@ -2943,6 +2960,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 +3026,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;

View File

@@ -772,6 +772,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_GRADIENT,
.data = SConfigOptionDescription::SGradientData{"0x66775500"},
},
SConfigOptionDescription{
.value = "group:auto_group",
.description = "automatically group new windows",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/*
* group:groupbar:
@@ -1049,6 +1055,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:
@@ -1366,4 +1378,164 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/*
* dwindle:
*/
SConfigOptionDescription{
.value = "dwindle:pseudotile",
.description = "enable pseudotiling. Pseudotiled windows retain their floating size when tiled.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:force_split",
.description = "0 -> split follows mouse, 1 -> always split to the left (new = left or top) 2 -> always split to the right (new = right or bottom)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "follow mouse,left or top,right or bottom"},
},
SConfigOptionDescription{
.value = "dwindle:preserve_split",
.description = "if enabled, the split (side/top) will not change regardless of what happens to the container.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_split",
.description = "if enabled, allows a more precise control over the window split direction based on the cursor's position. The window is conceptually divided into four "
"triangles, and cursor's triangle determines the split direction. This feature also turns on preserve_split.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:permanent_direction_override",
.description = "if enabled, makes the preselect direction persist until either this mode is turned off, another direction is specified, or a non-direction is specified "
"(anything other than l,r,u/t,d/b)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "dwindle:special_scale_factor",
.description = "specifies the scale factor of windows on the special workspace [0 - 1]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "dwindle:split_width_multiplier",
.description = "specifies the auto-split width multiplier",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 3},
},
SConfigOptionDescription{
.value = "dwindle:no_gaps_when_only",
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
},
SConfigOptionDescription{
.value = "dwindle:use_active_for_splits",
.description = "whether to prefer the active window or the mouse position for splits",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "dwindle:default_split_ratio",
.description = "the default split ratio on window open. 1 means even 50/50 split. [0.1 - 1.9]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0.1, 1.9},
},
SConfigOptionDescription{
.value = "dwindle:split_bias",
.description = "specifies which window will receive the larger half of a split. positional - 0, current window - 1, opening window - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"},
},
/*
* master:
*/
SConfigOptionDescription{
.value = "master:allow_small_split",
.description = "enable adding additional master windows in a horizontal split style",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:special_scale_factor",
.description = "the scale of the special workspace windows. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{1, 0, 1},
},
SConfigOptionDescription{
.value = "master:mfact",
.description =
"the size as a percentage of the master window, for example `mfact = 0.70` would mean 70% of the screen will be the master window, and 30% the slave [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.55, 0, 1},
},
SConfigOptionDescription{
.value = "master:new_status",
.description = "`master`: new window becomes master; `slave`: new windows are added to slave stack; `inherit`: inherit from focused window",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"slave"},
},
SConfigOptionDescription{
.value = "master:new_on_top",
.description = "whether a newly open window should be on the top of the stack",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:new_on_active",
.description = "`before`, `after`: place new window relative to the focused window; `none`: place new window according to the value of `new_on_top`. ",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"none"},
},
SConfigOptionDescription{
.value = "master:no_gaps_when_only",
.description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"},
},
SConfigOptionDescription{
.value = "master:orientation",
.description = "default placement of the master area, can be left, right, top, bottom or center",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"left"},
},
SConfigOptionDescription{
.value = "master:inherit_fullscreen",
.description = "inherit fullscreen status when cycling/swapping to another window (e.g. monocle layout)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:always_center_master",
.description = "when using orientation=center, keep the master window centered, even when it is the only window in the workspace.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:smart_resizing",
.description =
"if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "master:drop_at_cursor",
.description = "when enabled, dragging and dropping windows will put them at the cursor position. Otherwise, when dropped at the stack side, they will go to the "
"top/bottom of the stack depending on new_on_top.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
};

View File

@@ -7,6 +7,7 @@
#include "helpers/varlist/VarList.hpp"
#include "../protocols/LayerShell.hpp"
#include "../xwayland/XWayland.hpp"
#include "../protocols/OutputManagement.hpp"
#include <cstddef>
#include <cstdint>
@@ -371,10 +372,12 @@ 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});
m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY});
m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8});
@@ -444,6 +447,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1});
m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f});
m_pConfig->addConfigValue("dwindle:split_bias", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:smart_split", Hyprlang::INT{0});
m_pConfig->addConfigValue("dwindle:smart_resizing", Hyprlang::INT{1});
@@ -682,6 +686,10 @@ std::string CConfigManager::getMainConfigPath() {
if (!g_pCompositor->explicitConfigPath.empty())
return g_pCompositor->explicitConfigPath;
if (const auto CFG_ENV = getenv("HYPRLAND_CONFIG"); CFG_ENV)
return CFG_ENV;
Debug::log(TRACE, "Seems as if HYPRLAND_CONFIG isn't set, let's see what we can do with HOME.");
static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland");
if (paths.first.has_value()) {
return paths.first.value();
@@ -859,8 +867,10 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors")))
g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1)
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland",
CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
g_pHyprError->queueCreate(
"Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() +
" )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland",
CColor(1.0, 1.0, 70.0 / 255.0, 1.0));
else if (*PENABLEEXPLICIT != prevEnabledExplicit)
g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
else
@@ -1074,28 +1084,69 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s
return VAL;
}
SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
SMonitorRule CConfigManager::getMonitorRuleFor(const SP<CMonitor> PMONITOR) {
auto applyWlrOutputConfig = [PMONITOR](SMonitorRule rule) -> SMonitorRule {
const auto CONFIG = PROTO::outputManagement->getOutputStateFor(PMONITOR);
if (!CONFIG)
return rule;
Debug::log(LOG, "CConfigManager::getMonitorRuleFor: found a wlr_output_manager override for {}", PMONITOR->szName);
Debug::log(LOG, " > overriding enabled: {} -> {}", !rule.disabled, !CONFIG->enabled);
rule.disabled = !CONFIG->enabled;
if ((CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_MODE) || (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE)) {
Debug::log(LOG, " > overriding mode: {:.0f}x{:.0f}@{:.2f}Hz -> {:.0f}x{:.0f}@{:.2f}Hz", rule.resolution.x, rule.resolution.y, rule.refreshRate, CONFIG->resolution.x,
CONFIG->resolution.y, CONFIG->refresh / 1000.F);
rule.resolution = CONFIG->resolution;
rule.refreshRate = CONFIG->refresh / 1000.F;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
Debug::log(LOG, " > overriding offset: {:.0f}, {:.0f} -> {:.0f}, {:.0f}", rule.offset.x, rule.offset.y, CONFIG->position.x, CONFIG->position.y);
rule.offset = CONFIG->position;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
Debug::log(LOG, " > overriding transform: {} -> {}", (uint8_t)rule.transform, (uint8_t)CONFIG->transform);
rule.transform = CONFIG->transform;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
Debug::log(LOG, " > overriding scale: {} -> {}", (uint8_t)rule.scale, (uint8_t)CONFIG->scale);
rule.scale = CONFIG->scale;
}
if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
Debug::log(LOG, " > overriding vrr: {} -> {}", rule.vrr.value_or(0), CONFIG->adaptiveSync);
rule.vrr = (int)CONFIG->adaptiveSync;
}
return rule;
};
for (auto const& r : m_dMonitorRules | std::views::reverse) {
if (PMONITOR.matchesStaticSelector(r.name)) {
return r;
if (PMONITOR->matchesStaticSelector(r.name)) {
return applyWlrOutputConfig(r);
}
}
Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName);
Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR->szName);
for (auto const& r : m_dMonitorRules) {
if (r.name.empty()) {
return r;
return applyWlrOutputConfig(r);
}
}
Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
return SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT,
.name = "",
.resolution = Vector2D(0, 0),
.offset = Vector2D(-INT32_MAX, -INT32_MAX),
.scale = -1}; // 0, 0 is preferred and -1, -1 is auto
return applyWlrOutputConfig(SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT,
.name = "",
.resolution = Vector2D(0, 0),
.offset = Vector2D(-INT32_MAX, -INT32_MAX),
.scale = -1}); // 0, 0 is preferred and -1, -1 is auto
}
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) {
@@ -1454,7 +1505,7 @@ void CConfigManager::performMonitorReload() {
if (!m->output || m->isUnsafeFallback)
continue;
auto rule = getMonitorRuleFor(*m);
auto rule = getMonitorRuleFor(m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true;
@@ -1511,7 +1562,7 @@ void CConfigManager::ensureMonitorStatus() {
if (!rm->output || rm->isUnsafeFallback)
continue;
auto rule = getMonitorRuleFor(*rm);
auto rule = getMonitorRuleFor(rm);
if (rule.disabled == rm->m_bEnabled)
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
@@ -2239,7 +2290,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); });
}

View File

@@ -169,7 +169,7 @@ class CConfigManager {
static std::string getMainConfigPath();
const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const CMonitor&);
SMonitorRule getMonitorRuleFor(const SP<CMonitor>);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&);

View File

@@ -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 ###
##############################
@@ -262,5 +268,9 @@ bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#";

View File

@@ -103,6 +103,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"focused": {},
"dpmsStatus": {},
"vrr": {},
"solitary": "{:x}",
"activelyTearing": {},
"disabled": {},
"currentFormat": "{}",
@@ -114,19 +115,20 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"),
(m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(),
(m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat),
availableModesForOutput(m.get(), format));
} else {
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
"dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing,
!m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(),
m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
}
return result;
@@ -158,16 +160,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!m->output || m->ID == -1)
continue;
result += std::format(
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"),
(int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled,
formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
result += CHyprCtl::getMonitorData(m, format);
}
}
@@ -320,45 +313,48 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputFormat format) {
const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; };
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor));
const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
const std::string gapsIn = (bool)(r.gapsIn) ?
std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) :
const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor));
const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
const std::string gapsIn = (bool)(r.gapsIn) ?
std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) :
"";
const std::string gapsOut = (bool)(r.gapsOut) ?
std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) :
"";
const std::string gapsOut = (bool)(r.gapsOut) ?
std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) :
"";
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : "";
const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : "";
const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : "";
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : "";
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : "";
const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : "";
const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : "";
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : "";
const std::string defaultName = r.defaultName.has_value() ? std::format(",\n \"defaultName\": \"{}\"", escapeJSONStrings(r.defaultName.value())) : "";
std::string result = std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{}
std::string result =
std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{}{}{}{}
}})#",
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow);
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow, defaultName);
return result;
} else {
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor));
const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "<unset>");
const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "<unset>");
const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right),
std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) :
std::format("\tgapsIn: <unset>\n");
const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right),
std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) :
std::format("\tgapsOut: <unset>\n");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>");
const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : "<unset>");
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>");
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>");
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor));
const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "<unset>");
const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "<unset>");
const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right),
std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) :
std::format("\tgapsIn: <unset>\n");
const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right),
std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) :
std::format("\tgapsOut: <unset>\n");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>");
const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : "<unset>");
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>");
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>");
const std::string defaultName = std::format("\tdefaultName: {}\n", r.defaultName.value_or("<unset>"));
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow);
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow, defaultName);
return result;
}
@@ -858,7 +854,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 +878,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\",";
@@ -935,11 +934,14 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
result += "plugins:\n";
for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
}
if (g_pPluginSystem) {
for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
}
} else
result += "\tunknown: not runtime\n";
if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) {
if (g_pHyprCtl && g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) {
result += "\n======Config-Start======\n";
result += g_pConfigManager->getConfigString();
result += "\n======Config-End========\n";
@@ -987,9 +989,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);
@@ -1621,6 +1623,14 @@ std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) {
return json;
}
std::string submapRequest(eHyprCtlOutputFormat format, std::string request) {
std::string submap = g_pKeybindManager->getCurrentSubmap();
if (submap.empty())
submap = "default";
return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n");
}
CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
@@ -1642,6 +1652,7 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest});
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});

View File

@@ -5,6 +5,9 @@
#include "../helpers/MiscFunctions.hpp"
#include <functional>
// exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
class CHyprCtl {
public:
CHyprCtl();

View File

@@ -1,6 +1,5 @@
#include "includes.hpp"
#include "debug/Log.hpp"
#include "helpers/WLListener.hpp"
#include "helpers/Color.hpp"
#include "macros.hpp"
#include "desktop/DesktopTypes.hpp"

View File

@@ -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"); }
}
}
}

View File

@@ -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;

View File

@@ -30,13 +30,7 @@ CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner)
}
CSubsurface::~CSubsurface() {
hyprListener_newSubsurface.removeCallback();
if (!m_pSubsurface)
return;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
;
}
void CSubsurface::initSignals() {

View File

@@ -35,10 +35,6 @@ class CSubsurface {
void recheckDamageForSubsurfaces();
private:
DYNLISTENER(destroySubsurface);
DYNLISTENER(commitSubsurface);
DYNLISTENER(newSubsurface);
struct {
CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface;

View File

@@ -62,7 +62,7 @@ bool CWLSurface::small() const {
const auto O = m_pWindowOwner.lock();
return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1;
return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1;
}
Vector2D CWLSurface::correctSmallVec() const {

View File

@@ -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();

View File

@@ -178,13 +178,18 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkbState)
xkb_state_unref(xkbState);
if (xkbSymState)
xkb_state_unref(xkbSymState);
xkbState = nullptr;
xkbStaticState = nullptr;
xkbSymState = nullptr;
if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap);
xkbSymState = xkb_state_new(keymap);
return;
}
@@ -230,6 +235,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP);
xkbSymState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT);
@@ -252,6 +258,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = xkb_state_new(NEWKEYMAP);
xkbSymState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT);
@@ -332,6 +339,9 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l
xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group);
if (!updateModifiersState())
return;
@@ -382,6 +392,9 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) {
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group);
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,

View File

@@ -1,7 +1,6 @@
#pragma once
#include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"
@@ -83,8 +82,9 @@ class IKeyboard : public IHID {
bool keymapOverridden = false;
xkb_layout_index_t activeLayout = 0;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
xkb_keymap* xkbKeymap = nullptr;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr,
*xkbSymState = nullptr /* Same as static but gets layouts */;
xkb_keymap* xkbKeymap = nullptr;
struct {
uint32_t depressed = 0, latched = 0, locked = 0, group = 0;

View File

@@ -1,7 +1,6 @@
#pragma once
#include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"

View File

@@ -1,7 +1,6 @@
#pragma once
#include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"

View File

@@ -1,7 +1,6 @@
#pragma once
#include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp"

View File

@@ -322,7 +322,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->updateWindowData();
if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true;
// size and move rules

View File

@@ -0,0 +1,54 @@
#pragma once
#include <type_traits>
#define ULL unsigned long long
#define LD long double
constexpr ULL operator""_kB(const ULL BYTES) {
return BYTES * 1024;
}
constexpr ULL operator""_MB(const ULL BYTES) {
return BYTES * 1024 * 1024;
}
constexpr ULL operator""_GB(const ULL BYTES) {
return BYTES * 1024 * 1024 * 1024;
}
constexpr ULL operator""_TB(const ULL BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024;
}
constexpr LD operator""_kB(const LD BYTES) {
return BYTES * 1024;
}
constexpr LD operator""_MB(const LD BYTES) {
return BYTES * 1024 * 1024;
}
constexpr LD operator""_GB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024;
}
constexpr LD operator""_TB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024;
}
template <typename T>
using __acceptable_byte_operation_type = typename std::enable_if<std::is_trivially_constructible<T, ULL>::value || std::is_trivially_constructible<T, LD>::value>::type;
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X kBtoBytes(const X kB) {
return kB * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X MBtoBytes(const X MB) {
return MB * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X GBtoBytes(const X GB) {
return GB * 1024 * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
constexpr X TBtoBytes(const X TB) {
return TB * 1024 * 1024 * 1024 * 1024;
}
#undef ULL
#undef LD

View File

@@ -8,8 +8,9 @@ class CColor {
CColor(float r, float g, float b, float a);
CColor(uint64_t);
float r = 0, g = 0, b = 0, a = 1.f;
float r = 0, g = 0, b = 0, a = 1.f;
// AR32
uint32_t getAsHex() const;
CColor operator-(const CColor& c2) const {

View File

@@ -628,27 +628,6 @@ void logSystemInfo() {
Debug::log(NONE, "{}", execAndGet("cat /etc/os-release"));
}
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
memset(mat, 0, sizeof(*mat) * 9);
const float* t = transforms[tr];
float x = 2.0f / w;
float y = 2.0f / h;
// Rotation + reflection
mat[0] = x * t[0];
mat[1] = x * t[1];
mat[3] = y * t[3];
mat[4] = y * t[4];
// Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
// Identity
mat[8] = 1.0f;
}
int64_t getPPIDof(int64_t pid) {
#if defined(KERN_PROC_PID)
int mib[] = {

View File

@@ -34,7 +34,6 @@ int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&);
Vector2D configStringToVector2D(const std::string&);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err);

View File

@@ -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"
@@ -13,11 +12,14 @@
#include "../protocols/DRMSyncobj.hpp"
#include "../protocols/core/Output.hpp"
#include "../managers/PointerManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../protocols/core/Compositor.hpp"
#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);
@@ -34,6 +36,7 @@ CMonitor::~CMonitor() {
}
void CMonitor::onConnect(bool noRule) {
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
if (output->supportsExplicit) {
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
@@ -113,7 +116,7 @@ void CMonitor::onConnect(bool noRule) {
createdByUser = true; // should be true. WL and Headless backends should be addable / removable
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(self.lock());
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
@@ -192,10 +195,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,9 +223,20 @@ 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) {
CScopeGuard x = {[this]() {
if (g_pCompositor->m_bIsShuttingDown)
return;
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
g_pCompositor->arrangeMonitors();
}};
if (renderTimer) {
wl_event_source_remove(renderTimer);
@@ -281,9 +291,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();
@@ -488,7 +495,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr;
// set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(*this);
const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock());
vecPosition = RULE.offset;
@@ -771,12 +778,9 @@ Vector2D CMonitor::middle() {
}
void CMonitor::updateMatrix() {
matrixIdentity(projMatrix.data());
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform));
matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
projMatrix = Mat3x3::identity();
if (transform != WL_OUTPUT_TRANSFORM_NORMAL)
projMatrix.translate(vecPixelSize / 2.0).transform(wlTransformToHyprutils(transform)).translate(-vecTransformedSize / 2.0);
}
WORKSPACEID CMonitor::activeWorkspaceID() {
@@ -791,20 +795,22 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize};
}
static void onDoneSource(void* data) {
auto pMonitor = (CMonitor*)data;
if (!PROTO::outputs.contains(pMonitor->szName))
return;
PROTO::outputs.at(pMonitor->szName)->sendDone();
}
void CMonitor::scheduleDone() {
if (doneSource)
if (doneScheduled)
return;
doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this);
doneScheduled = true;
g_pEventLoopManager->doLater([M = self] {
if (!M) // if M is gone, we got destroyed, doesn't matter.
return;
if (!PROTO::outputs.contains(M->szName))
return;
PROTO::outputs.at(M->szName)->sendDone();
M->doneScheduled = false;
});
}
bool CMonitor::attemptDirectScanout() {

View File

@@ -96,7 +96,7 @@ class CMonitor {
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
Mat3x3 projMatrix;
std::optional<Vector2D> forceSize;
SP<Aquamarine::SOutputMode> currentMode;
SP<Aquamarine::CSwapchain> cursorSwapchain;
@@ -190,10 +190,10 @@ class CMonitor {
}
private:
void setupDefaultWS(const SMonitorRule&);
WORKSPACEID findAvailableDefaultWS();
void setupDefaultWS(const SMonitorRule&);
WORKSPACEID findAvailableDefaultWS();
wl_event_source* doneSource = nullptr;
bool doneScheduled = false;
struct {
CHyprSignalListener frame;

View File

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

View File

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

View File

@@ -8,6 +8,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <stdlib.h>
#include <cstring>
namespace Systemd {

View File

@@ -1,62 +0,0 @@
#include "WLListener.hpp"
#include "MiscFunctions.hpp"
#include <string>
#include "../debug/Log.hpp"
#include "Watchdog.hpp"
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
if (g_pWatchdog)
g_pWatchdog->startWatching();
try {
pWrap->m_pSelf->emit(data);
} catch (std::exception& e) { Debug::log(ERR, "Listener {} threw or timed out and was killed by Watchdog!!! This is bad. what(): {}", (uintptr_t)listener, e.what()); }
if (g_pWatchdog)
g_pWatchdog->endWatching();
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> const& callback, void* pOwner) {
initCallback(pSignal, callback, pOwner);
}
CHyprWLListener::CHyprWLListener() {
m_swWrapper.m_pSelf = this;
m_swWrapper.m_sListener.notify = &handleWrapped;
wl_list_init(&m_swWrapper.m_sListener.link);
}
CHyprWLListener::~CHyprWLListener() {
removeCallback();
}
void CHyprWLListener::removeCallback() {
if (isConnected()) {
Debug::log(LOG, "Callback {:x} -> {:x}, {} removed.", (uintptr_t)&m_pCallback, (uintptr_t)&m_pOwner, m_szAuthor);
wl_list_remove(&m_swWrapper.m_sListener.link);
wl_list_init(&m_swWrapper.m_sListener.link);
}
}
bool CHyprWLListener::isConnected() {
return !wl_list_empty(&m_swWrapper.m_sListener.link);
}
void CHyprWLListener::initCallback(wl_signal* pSignal, std::function<void(void*, void*)> const& callback, void* pOwner, std::string author) {
if (isConnected()) {
Debug::log(ERR, "Tried to connect a listener twice?!");
return;
}
m_pOwner = pOwner;
m_pCallback = callback;
m_szAuthor = author;
addWLSignal(pSignal, &m_swWrapper.m_sListener, pOwner, m_szAuthor);
}
void CHyprWLListener::emit(void* data) {
m_pCallback(m_pOwner, data);
}

View File

@@ -1,39 +0,0 @@
#pragma once
#include <string>
#include <functional>
#include <wayland-server.h>
class CHyprWLListener {
public:
CHyprWLListener(wl_signal*, std::function<void(void*, void*)> const&, void* owner);
CHyprWLListener();
~CHyprWLListener();
CHyprWLListener(const CHyprWLListener&) = delete;
CHyprWLListener(CHyprWLListener&&) = delete;
CHyprWLListener& operator=(const CHyprWLListener&) = delete;
CHyprWLListener& operator=(CHyprWLListener&&) = delete;
void initCallback(wl_signal*, std::function<void(void*, void*)> const&, void* owner, std::string author = "");
void removeCallback();
bool isConnected();
struct SWrapper {
wl_listener m_sListener;
CHyprWLListener* m_pSelf;
};
void emit(void*);
private:
SWrapper m_swWrapper;
void* m_pOwner = nullptr;
std::function<void(void*, void*)> m_pCallback = nullptr;
std::string m_szAuthor = "";
};

View File

@@ -1,6 +1,4 @@
#include "Math.hpp"
#include <unordered_map>
#include <cstring>
Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
switch (t) {
@@ -17,124 +15,6 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL;
}
void matrixIdentity(float mat[9]) {
static const float identity[9] = {
1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
};
memcpy(mat, identity, sizeof(identity));
}
void matrixMultiply(float mat[9], const float a[9], const float b[9]) {
float product[9];
product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];
product[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7];
product[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8];
product[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6];
product[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7];
product[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8];
product[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6];
product[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7];
product[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8];
memcpy(mat, product, sizeof(product));
}
void matrixTranspose(float mat[9], const float a[9]) {
float transposition[9] = {
a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8],
};
memcpy(mat, transposition, sizeof(transposition));
}
void matrixTranslate(float mat[9], float x, float y) {
float translate[9] = {
1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, translate);
}
void matrixScale(float mat[9], float x, float y) {
float scale[9] = {
x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, scale);
}
void matrixRotate(float mat[9], float rad) {
float rotate[9] = {
cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f,
};
matrixMultiply(mat, mat, rotate);
}
const std::unordered_map<eTransform, std::array<float, 9>>& getTransforms() {
static std::unordered_map<eTransform, std::array<float, 9>> transforms = {
{HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
{HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
};
return transforms;
}
void matrixTransform(float mat[9], eTransform transform) {
matrixMultiply(mat, mat, getTransforms().at(transform).data());
}
void matrixProjection(float mat[9], int width, int height, eTransform transform) {
memset(mat, 0, sizeof(*mat) * 9);
const float* t = getTransforms().at(transform).data();
float x = 2.0f / width;
float y = 2.0f / height;
// Rotation + reflection
mat[0] = x * t[0];
mat[1] = x * t[1];
mat[3] = y * -t[3];
mat[4] = y * -t[4];
// Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
// Identity
mat[8] = 1.0f;
}
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]) {
double x = box.x;
double y = box.y;
double width = box.width;
double height = box.height;
matrixIdentity(mat);
matrixTranslate(mat, x, y);
if (rotation != 0) {
matrixTranslate(mat, width / 2, height / 2);
matrixRotate(mat, rotation);
matrixTranslate(mat, -width / 2, -height / 2);
}
matrixScale(mat, width, height);
if (transform != HYPRUTILS_TRANSFORM_NORMAL) {
matrixTranslate(mat, 0.5, 0.5);
matrixTransform(mat, transform);
matrixTranslate(mat, -0.5, -0.5);
}
matrixMultiply(mat, projection, mat);
}
wl_output_transform invertTransform(wl_output_transform tr) {
if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED))
tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180);

View File

@@ -4,17 +4,9 @@
// includes box and vector as well
#include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Mat3x3.hpp>
using namespace Hyprutils::Math;
eTransform wlTransformToHyprutils(wl_output_transform t);
void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]);
void matrixProjection(float mat[9], int width, int height, eTransform transform);
void matrixTransform(float mat[9], eTransform transform);
void matrixRotate(float mat[9], float rad);
void matrixScale(float mat[9], float x, float y);
void matrixTranslate(float mat[9], float x, float y);
void matrixTranspose(float mat[9], const float a[9]);
void matrixMultiply(float mat[9], const float a[9], const float b[9]);
void matrixIdentity(float mat[9]);
wl_output_transform invertTransform(wl_output_transform tr);

View File

@@ -1,7 +1,7 @@
#include "DwindleLayout.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) {
@@ -340,26 +340,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
return;
}
// if it's a group, add the window
if (OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow.lock()) && !m_vOverrideFocalPoint) { // we are not moving window
m_lDwindleNodesData.remove(*PNODE);
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
// If it's not, get the node under our cursor
// get the node under our cursor
m_lDwindleNodesData.push_back(SDwindleNodeData());
const auto NEWPARENT = &m_lDwindleNodesData.back();
@@ -459,6 +440,12 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
}
}
// split in favor of a specific window
const auto first = NEWPARENT->children[0];
static auto PSPLITBIAS = CConfigValue<Hyprlang::INT>("dwindle:split_bias");
if ((*PSPLITBIAS == 1 && first == PNODE) || (*PSPLITBIAS == 2 && first == OPENINGON))
NEWPARENT->splitRatio = 2.f - NEWPARENT->splitRatio;
// and update the previous parent if it exists
if (OPENINGON->pParent) {
if (OPENINGON->pParent->children[0] == OPENINGON) {
@@ -992,6 +979,10 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
toggleSplit(header.pWindow);
} else if (ARGS[0] == "swapsplit") {
swapSplit(header.pWindow);
} else if (ARGS[0] == "movetoroot") {
const auto WINDOW = ARGS[1].empty() ? header.pWindow : g_pCompositor->getWindowByRegex(ARGS[1]);
const auto STABLE = ARGS[2].empty() || ARGS[2] != "unstable";
moveToRoot(WINDOW, STABLE);
} else if (ARGS[0] == "preselect") {
std::string direction = ARGS[1];
@@ -1059,6 +1050,44 @@ void CHyprDwindleLayout::swapSplit(PHLWINDOW pWindow) {
PNODE->pParent->recalcSizePosRecursive();
}
// goal: maximize the chosen window within current dwindle layout
// impl: swap the selected window with the other sub-tree below root
void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE || !PNODE->pParent)
return;
if (pWindow->isFullscreen())
return;
// already at root
if (!PNODE->pParent->pParent)
return;
auto& pNode = PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[0] : PNODE->pParent->children[1];
// instead of [getMasterNodeOnWorkspace], we walk back to root since we need
// to know which children of root is our ancestor
auto pAncestor = PNODE, pRoot = PNODE->pParent;
while (pRoot->pParent) {
pAncestor = pRoot;
pRoot = pRoot->pParent;
}
auto& pSwap = pRoot->children[0] == pAncestor ? pRoot->children[1] : pRoot->children[0];
std::swap(pNode, pSwap);
std::swap(pNode->pParent, pSwap->pParent);
// [stable] in that the focused window occupies same side of screen
if (stable)
std::swap(pRoot->children[0], pRoot->children[1]);
// if the workspace is visible, recalculate layout
if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace))
pRoot->recalcSizePosRecursive();
}
void CHyprDwindleLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) {
const auto PNODE = getNodeFromWindow(from);

View File

@@ -87,6 +87,7 @@ class CHyprDwindleLayout : public IHyprLayout {
void toggleSplit(PHLWINDOW);
void swapSplit(PHLWINDOW);
void moveToRoot(PHLWINDOW, bool stable = true);
eDirection overrideDirection = DIRECTION_DEFAULT;

View File

@@ -9,23 +9,25 @@
#include "../xwayland/XSurface.hpp"
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) {
CBox desiredGeometry = {};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f;
} else
pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize;
bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow);
if (autoGrouped)
return;
if (pWindow->m_bIsFloating)
onWindowCreatedFloating(pWindow);
} else {
CBox desiredGeometry = {};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f;
} else {
pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize;
else
onWindowCreatedTiling(pWindow, direction);
}
}
void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
@@ -178,6 +180,48 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
}
}
bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) {
static auto PAUTOGROUP = CConfigValue<Hyprlang::INT>("group:auto_group");
PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ?
g_pCompositor->m_pLastWindow.lock() :
g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID());
if ((*PAUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group.
&& OPENINGON // check if OPENINGON exists.
&& OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group.
&& OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group
&& pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON
&& !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated.
switch (pWindow->m_bIsFloating) {
case false:
if (OPENINGON->m_bIsFloating)
pWindow->m_bIsFloating = true;
break;
case true:
if (!OPENINGON->m_bIsFloating)
pWindow->m_bIsFloating = false;
break;
}
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return true;
}
return false;
}
void IHyprLayout::onBeginDragWindow() {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock();
@@ -509,10 +553,10 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
// move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back.
// move to narnia because we don't wanna find our own node. onWindowCreated should apply the coords back.
pWindow->m_vPosition = Vector2D(-999999, -999999);
onWindowCreatedTiling(pWindow);
onWindowCreated(pWindow);
pWindow->m_vRealPosition.setValue(PSAVEDPOS);
pWindow->m_vRealSize.setValue(PSAVEDSIZE);

View File

@@ -47,6 +47,7 @@ class IHyprLayout {
virtual void onWindowCreated(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT) = 0;
virtual void onWindowCreatedFloating(PHLWINDOW);
virtual bool onWindowCreatedAutoGroup(PHLWINDOW);
/*
Return tiled status

View File

@@ -116,26 +116,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
return;
}
// if it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow.lock())) {
m_lMasterNodesData.remove(*PNODE);
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
pWindow->applyGroupRules();
static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor");

View File

@@ -3,6 +3,10 @@
#include "Compositor.hpp"
#include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp"
#include "debug/HyprCtl.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
#include <fcntl.h>
#include <iostream>
@@ -20,6 +24,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 +114,29 @@ 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 if (it->compare("--systeminfo") == 0) {
const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "");
std::cout << SYSINFO << "\n";
return 0;
} else {
std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n";

View File

@@ -376,7 +376,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE);
if (handleInternalKeybinds(internalKeysym))
@@ -594,6 +594,10 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) {
return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys);
}
std::string CKeybindManager::getCurrentSubmap() {
return m_szCurrentSelectedSubmap;
}
SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) {
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
bool found = false;
@@ -1939,7 +1943,7 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) {
if (!m->output)
continue;
auto rule = g_pConfigManager->getMonitorRuleFor(*m);
auto rule = g_pConfigManager->getMonitorRuleFor(m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) {
overAgain = true;
break;
@@ -2399,9 +2403,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
bool enable = arg.starts_with("on");
std::string port = "";
if (arg.starts_with("toggle"))
enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off
bool isToggle = arg.starts_with("toggle");
if (arg.find_first_of(' ') != std::string::npos)
port = arg.substr(arg.find_first_of(' ') + 1);
@@ -2410,6 +2412,9 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port)
continue;
if (isToggle)
enable = !m->dpmsStatus;
m->output->state->resetExplicitFences();
m->output->state->setEnabled(enable);
@@ -2730,7 +2735,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);

View File

@@ -96,6 +96,7 @@ class CKeybindManager {
uint32_t keycodeToModifier(xkb_keycode_t);
void clearKeybinds();
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0);
std::string getCurrentSubmap();
std::unordered_map<std::string, std::function<SDispatchResult(std::string)>> m_mDispatchers;
@@ -221,6 +222,7 @@ class CKeybindManager {
friend class CInputManager;
friend class CConfigManager;
friend class CWorkspace;
friend class CPointerManager;
};
inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -17,16 +17,8 @@ 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);
PMONITOR->events.disconnect.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.destroy.registerStaticListener(
[this](void* owner, std::any data) {
if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown)
@@ -44,38 +36,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 +206,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 +266,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 +276,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 +305,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) {
@@ -670,12 +657,12 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) {
}
void CPointerManager::damageIfSoftware() {
auto b = getCursorBoxGlobal();
auto b = getCursorBoxGlobal().expand(4);
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 +776,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 +808,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 +826,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 +837,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 +868,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 +895,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 +940,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 +958,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 +995,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 +1013,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 +1032,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) {

View File

@@ -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);

View File

@@ -44,6 +44,7 @@
#include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "../protocols/XDGDialog.hpp"
#include "../protocols/SinglePixel.hpp"
#include "../protocols/core/Seat.hpp"
#include "../protocols/core/DataDevice.hpp"
@@ -85,7 +86,8 @@ CProtocolManager::CProtocolManager() {
// ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after
// this event is emitted iirc.
if (M->isMirror())
// also ignore the fallback
if (M->isMirror() || M == g_pCompositor->m_pUnsafeOutput)
return;
if (PROTO::outputs.contains(M->szName))
@@ -152,6 +154,7 @@ CProtocolManager::CProtocolManager() {
PROTO::toplevelExport = std::make_unique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport");
PROTO::globalShortcuts = std::make_unique<CGlobalShortcutsProtocol>(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts");
PROTO::xdgDialog = std::make_unique<CXDGDialogProtocol>(&xdg_dialog_v1_interface, 1, "XDGDialog");
PROTO::singlePixel = std::make_unique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel");
for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) {
if (b->type() != Aquamarine::AQ_BACKEND_DRM)

View File

@@ -2,7 +2,6 @@
#include <cstdint>
#include <wayland-server-protocol.h>
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/math/Math.hpp"

View File

@@ -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) {

View File

@@ -50,6 +50,10 @@ void CEventLoopManager::enterLoop() {
m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get()));
}
// if we have a session, dispatch it to get the pending input devices
if (g_pCompositor->m_pAqBackend->hasSession())
g_pCompositor->m_pAqBackend->session->dispatchPendingEventsAsync();
wl_display_run(m_sWayland.display);
Debug::log(LOG, "Kicked off the event loop! :(");

View File

@@ -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);

View File

@@ -1,6 +1,5 @@
#pragma once
#include "../../helpers/WLListener.hpp"
#include "../../desktop/WLSurface.hpp"
#include "../../macros.hpp"
#include "../../helpers/math/Math.hpp"

View File

@@ -106,20 +106,22 @@ void CInputMethodRelay::updateAllPopups() {
}
}
void CInputMethodRelay::activateIME(CTextInput* pInput) {
void CInputMethodRelay::activateIME(CTextInput* pInput, bool shouldCommit) {
if (m_pIME.expired())
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) {

View File

@@ -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);

View File

@@ -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, "", "");
}

View File

@@ -1,6 +1,5 @@
#pragma once
#include "../../helpers/WLListener.hpp"
#include "../../macros.hpp"
#include "../../helpers/math/Math.hpp"
#include "../../helpers/signal/Signal.hpp"
@@ -29,6 +28,7 @@ class CTextInput {
void onEnabled(SP<CWLSurfaceResource> surfV1 = nullptr);
void onDisabled();
void onCommit();
void onReset();
bool hasCursorRectangle();
CBox cursorBox();
@@ -47,6 +47,7 @@ class CTextInput {
struct {
CHyprSignalListener enable;
CHyprSignalListener disable;
CHyprSignalListener reset;
CHyprSignalListener commit;
CHyprSignalListener destroy;
CHyprSignalListener surfaceUnmap;

View File

@@ -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'),
@@ -14,7 +16,7 @@ executable('Hyprland', src,
dependency('cairo'),
dependency('hyprcursor', version: '>=0.1.7'),
dependency('hyprlang', version: '>= 0.3.2'),
dependency('hyprutils', version: '>= 0.2.1'),
dependency('hyprutils', version: '>= 0.2.3'),
dependency('libdrm'),
dependency('egl'),
dependency('xkbcommon'),
@@ -29,7 +31,12 @@ executable('Hyprland', src,
backtrace_dep,
epoll_dep,
gio_dep,
udis86,
tracy,
# Try to find canihavesomecoffee's udis86 using pkgconfig
# vmt/udis86 does not provide a .pc file and won't be detected this way
# Falls back to using the subproject through udis86.wrap
dependency('udis86'),
dependency('pixman-1'),
dependency('gl', 'opengl'),
@@ -38,5 +45,5 @@ executable('Hyprland', src,
dependency('pangocairo'),
dependency('uuid'),
],
install : true
install: true,
)

View File

@@ -53,9 +53,6 @@ class CFocusGrab {
bool m_bGrabActive = false;
DYNLISTENER(pointerGrabStarted);
DYNLISTENER(keyboardGrabStarted);
DYNLISTENER(touchGrabStarted);
friend class CFocusGrabSurfaceState;
};

View File

@@ -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;

View File

@@ -307,10 +307,15 @@ COutputConfiguration::COutputConfiguration(SP<CZwlrOutputConfigurationV1> resour
LOGM(LOG, "disableHead on {}", PMONITOR->szName);
PMONITOR->activeMonitorRule.disabled = true;
if (!g_pConfigManager->replaceMonitorRule(PMONITOR->activeMonitorRule))
g_pConfigManager->appendMonitorRule(PMONITOR->activeMonitorRule);
g_pHyprRenderer->applyMonitorRule(PMONITOR, &PMONITOR->activeMonitorRule, false);
SWlrManagerSavedOutputState newState;
if (owner->monitorStates.contains(PMONITOR->szName))
newState = owner->monitorStates.at(PMONITOR->szName);
newState.enabled = false;
g_pConfigManager->m_bWantsMonitorReload = true;
owner->monitorStates[PMONITOR->szName] = newState;
});
resource->setTest([this](CZwlrOutputConfigurationV1* r) {
@@ -346,6 +351,11 @@ bool COutputConfiguration::applyTestConfiguration(bool test) {
LOGM(LOG, "Applying configuration");
if (!owner) {
LOGM(ERR, "applyTestConfiguration: no owner?!");
return false;
}
for (auto const& headw : heads) {
auto head = headw.lock();
@@ -357,41 +367,59 @@ bool COutputConfiguration::applyTestConfiguration(bool test) {
if (!PMONITOR)
continue;
LOGM(LOG, "Applying config for monitor {}", PMONITOR->szName);
LOGM(LOG, "Saving config for monitor {}", PMONITOR->szName);
SMonitorRule newRule = PMONITOR->activeMonitorRule;
newRule.name = PMONITOR->szName;
newRule.disabled = false;
SWlrManagerSavedOutputState newState;
if (owner->monitorStates.contains(PMONITOR->szName))
newState = owner->monitorStates.at(PMONITOR->szName);
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) {
newRule.resolution = head->state.mode->getMode()->pixelSize;
newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F;
} else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
newRule.resolution = head->state.customMode.size;
newRule.refreshRate = head->state.customMode.refresh / 1000.F;
newState.enabled = true;
if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) {
newState.resolution = head->state.mode->getMode()->pixelSize;
newState.refresh = head->state.mode->getMode()->refreshRate;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE;
LOGM(LOG, " > Mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh);
} else if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
newState.resolution = head->state.customMode.size;
newState.refresh = head->state.customMode.refresh;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE;
LOGM(LOG, " > Custom mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION)
newRule.offset = head->state.position;
if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION) {
newState.position = head->state.position;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION;
LOGM(LOG, " > Position: {:.0f}, {:.0f}", head->state.position.x, head->state.position.y);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC)
newRule.vrr = head->state.adaptiveSync;
if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
newState.adaptiveSync = head->state.adaptiveSync;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC;
LOGM(LOG, " > vrr: {}", newState.adaptiveSync);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE)
newRule.scale = head->state.scale;
if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE) {
newState.scale = head->state.scale;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE;
LOGM(LOG, " > scale: {:.2f}", newState.scale);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM)
newRule.transform = head->state.transform;
if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM) {
newState.transform = head->state.transform;
newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM;
LOGM(LOG, " > transform: {}", (uint8_t)newState.transform);
}
// reset properties for next set.
head->committedProperties = 0;
head->state.committedProperties = 0;
if (!g_pConfigManager->replaceMonitorRule(newRule))
g_pConfigManager->appendMonitorRule(newRule);
g_pConfigManager->m_bWantsMonitorReload = true;
owner->monitorStates[PMONITOR->szName] = newState;
}
LOGM(LOG, "Applied configuration");
LOGM(LOG, "Saved configuration");
return true;
}
@@ -417,12 +445,12 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (committedProperties & OUTPUT_HEAD_COMMITTED_MODE) {
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_MODE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
committedProperties |= OUTPUT_HEAD_COMMITTED_MODE;
state.committedProperties |= OUTPUT_HEAD_COMMITTED_MODE;
state.mode = MODE;
LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate);
@@ -434,17 +462,22 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
if (w <= 0 || h <= 0 || refresh <= 100) {
if (w <= 0 || h <= 0 || refresh < 0) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE, "Invalid mode");
return;
}
committedProperties |= OUTPUT_HEAD_COMMITTED_CUSTOM_MODE;
if (refresh == 0) {
LOGM(LOG, " | configHead for {}: refreshRate 0, using old refresh rate of {:.2f}Hz", pMonitor->szName, pMonitor->refreshRate);
refresh = std::round(pMonitor->refreshRate * 1000.F);
}
state.committedProperties |= OUTPUT_HEAD_COMMITTED_CUSTOM_MODE;
state.customMode = {{w, h}, (uint32_t)refresh};
LOGM(LOG, " | configHead for {}: set custom mode to {}x{}@{}", pMonitor->szName, w, h, refresh);
@@ -456,12 +489,12 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION;
state.committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION;
state.position = {x, y};
LOGM(LOG, " | configHead for {}: set pos to {}, {}", pMonitor->szName, x, y);
@@ -473,7 +506,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
@@ -483,7 +516,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
committedProperties |= OUTPUT_HEAD_COMMITTED_TRANSFORM;
state.committedProperties |= OUTPUT_HEAD_COMMITTED_TRANSFORM;
state.transform = (wl_output_transform)transform;
LOGM(LOG, " | configHead for {}: set transform to {}", pMonitor->szName, transform);
@@ -495,7 +528,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
@@ -507,7 +540,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
committedProperties |= OUTPUT_HEAD_COMMITTED_SCALE;
state.committedProperties |= OUTPUT_HEAD_COMMITTED_SCALE;
state.scale = scale;
LOGM(LOG, " | configHead for {}: set scale to {:.2f}", pMonitor->szName, scale);
@@ -519,7 +552,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
@@ -529,7 +562,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
committedProperties |= OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC;
state.committedProperties |= OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC;
state.adaptiveSync = as;
LOGM(LOG, " | configHead for {}: set adaptiveSync to {}", pMonitor->szName, as);
@@ -601,3 +634,14 @@ SP<COutputMode> COutputManagementProtocol::modeFromResource(wl_resource* r) {
return nullptr;
}
SP<SWlrManagerSavedOutputState> COutputManagementProtocol::getOutputStateFor(SP<CMonitor> pMonitor) {
for (auto const& m : m_vManagers) {
if (!m->monitorStates.contains(pMonitor->szName))
continue;
return makeShared<SWlrManagerSavedOutputState>(m->monitorStates.at(pMonitor->szName));
}
return nullptr;
}

View File

@@ -3,6 +3,7 @@
#include <memory>
#include <vector>
#include <cstdint>
#include <unordered_map>
#include "WaylandProtocol.hpp"
#include "wlr-output-management-unstable-v1.hpp"
#include "../helpers/signal/Signal.hpp"
@@ -13,6 +14,43 @@ class CMonitor;
class COutputHead;
class COutputMode;
struct SMonitorRule;
enum eWlrOutputCommittedProperties : uint32_t {
OUTPUT_HEAD_COMMITTED_MODE = (1 << 0),
OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1),
OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2),
OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3),
OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4),
OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5),
};
struct SWlrManagerOutputState {
uint32_t committedProperties = 0;
WP<COutputMode> mode;
struct {
Vector2D size;
uint32_t refresh = 0;
} customMode;
Vector2D position;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float scale = 1.F;
bool adaptiveSync = false;
bool enabled = true;
};
struct SWlrManagerSavedOutputState {
uint32_t committedProperties = 0;
Vector2D resolution;
uint32_t refresh = 0;
Vector2D position;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float scale = 1.F;
bool adaptiveSync = false;
bool enabled = true;
};
class COutputManager {
public:
COutputManager(SP<CZwlrOutputManagerV1> resource_);
@@ -21,6 +59,9 @@ class COutputManager {
void ensureMonitorSent(CMonitor* pMonitor);
void sendDone();
// holds the states for this manager.
std::unordered_map<std::string, SWlrManagerSavedOutputState> monitorStates;
private:
SP<CZwlrOutputManagerV1> resource;
bool stopped = false;
@@ -80,30 +121,9 @@ class COutputConfigurationHead {
public:
COutputConfigurationHead(SP<CZwlrOutputConfigurationHeadV1> resource_, CMonitor* pMonitor_);
bool good();
bool good();
enum eCommittedProperties : uint32_t {
OUTPUT_HEAD_COMMITTED_MODE = (1 << 0),
OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1),
OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2),
OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3),
OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4),
OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5),
};
uint32_t committedProperties = 0;
struct {
WP<COutputMode> mode;
struct {
Vector2D size;
uint32_t refresh = 0;
} customMode;
Vector2D position;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float scale = 1.F;
bool adaptiveSync = false;
} state;
SWlrManagerOutputState state;
private:
SP<CZwlrOutputConfigurationHeadV1> resource;
@@ -136,6 +156,9 @@ class COutputManagementProtocol : public IWaylandProtocol {
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
// doesn't have to return one
SP<SWlrManagerSavedOutputState> getOutputStateFor(SP<CMonitor> pMonitor);
private:
void destroyResource(COutputManager* resource);
void destroyResource(COutputHead* resource);

View File

@@ -58,8 +58,8 @@ void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespe
if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION)
flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
__time_t tv_sec = 0;
if (sizeof(__time_t) > 4)
time_t tv_sec = 0;
if (sizeof(time_t) > 4)
tv_sec = when->tv_sec >> 32;
if (data->wasPresented)

View File

@@ -27,8 +27,6 @@ class CQueuedPresentationData {
WP<CMonitor> pMonitor;
WP<CWLSurfaceResource> surface;
DYNLISTENER(destroySurface);
friend class CPresentationFeedback;
friend class CPresentationProtocol;
};

View File

@@ -394,12 +394,12 @@ void CScreencopyProtocol::bindManager(wl_client* client, void* data, uint32_t ve
void CScreencopyProtocol::destroyResource(CScreencopyClient* client) {
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; });
}
void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) {
std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; });
}
void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
@@ -412,8 +412,11 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
// share frame if correct output
for (auto const& f : m_vFramesAwaitingWrite) {
if (!f)
continue;
if (!f->pMonitor || !f->buffer) {
framesToRemove.push_back(f);
framesToRemove.emplace_back(f);
continue;
}
@@ -425,10 +428,10 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
f->client->lastFrame.reset();
++f->client->frameCounter;
framesToRemove.push_back(f);
framesToRemove.emplace_back(f);
}
for (auto const& f : framesToRemove) {
destroyResource(f.get());
std::erase(m_vFramesAwaitingWrite, f);
}
}

View File

@@ -54,7 +54,7 @@ class CScreencopyFrame {
bool good();
SP<CScreencopyFrame> self;
WP<CScreencopyFrame> self;
WP<CScreencopyClient> client;
private:
@@ -92,7 +92,7 @@ class CScreencopyProtocol : public IWaylandProtocol {
private:
std::vector<SP<CScreencopyFrame>> m_vFrames;
std::vector<SP<CScreencopyFrame>> m_vFramesAwaitingWrite;
std::vector<WP<CScreencopyFrame>> m_vFramesAwaitingWrite;
std::vector<SP<CScreencopyClient>> m_vClients;
SP<CEventLoopTimer> m_pSoftwareCursorTimer;

View File

@@ -0,0 +1,128 @@
#include "SinglePixel.hpp"
#include <limits>
#include "render/Renderer.hpp"
CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) {
LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex());
color = col_.getAsHex();
g_pHyprRenderer->makeEGLCurrent();
opaque = col_.a >= 1.F;
texture = makeShared<CTexture>(DRM_FORMAT_ARGB8888, (uint8_t*)&color, 4, Vector2D{1, 1});
resource = CWLBufferResource::create(makeShared<CWlBuffer>(client, 1, id));
success = texture->m_iTexID;
size = {1, 1};
if (!success)
Debug::log(ERR, "Failed creating a single pixel texture: null texture id");
}
CSinglePixelBuffer::~CSinglePixelBuffer() {
;
}
Aquamarine::eBufferCapability CSinglePixelBuffer::caps() {
return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
Aquamarine::eBufferType CSinglePixelBuffer::type() {
return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
}
bool CSinglePixelBuffer::isSynchronous() {
return true;
}
void CSinglePixelBuffer::update(const CRegion& damage) {
;
}
Aquamarine::SDMABUFAttrs CSinglePixelBuffer::dmabuf() {
return {.success = false};
}
std::tuple<uint8_t*, uint32_t, size_t> CSinglePixelBuffer::beginDataPtr(uint32_t flags) {
return {(uint8_t*)&color, DRM_FORMAT_ARGB8888, 4};
}
void CSinglePixelBuffer::endDataPtr() {
;
}
bool CSinglePixelBuffer::good() {
return resource->good();
}
CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color) {
buffer = makeShared<CSinglePixelBuffer>(id, client, color);
if (!buffer->good())
return;
buffer->resource->buffer = buffer;
listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) {
listeners.bufferResourceDestroy.reset();
PROTO::singlePixel->destroyResource(this);
});
}
CSinglePixelBufferResource::~CSinglePixelBufferResource() {
;
}
bool CSinglePixelBufferResource::good() {
return buffer->good();
}
CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SP<CWpSinglePixelBufferManagerV1> resource_) : resource(resource_) {
if (!good())
return;
resource->setDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); });
resource->setOnDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); });
resource->setCreateU32RgbaBuffer([this](CWpSinglePixelBufferManagerV1* res, uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
CColor color{r / (float)std::numeric_limits<uint32_t>::max(), g / (float)std::numeric_limits<uint32_t>::max(), b / (float)std::numeric_limits<uint32_t>::max(),
a / (float)std::numeric_limits<uint32_t>::max()};
const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared<CSinglePixelBufferResource>(id, resource->client(), color));
if (!RESOURCE->good()) {
res->noMemory();
PROTO::singlePixel->m_vBuffers.pop_back();
return;
}
});
}
bool CSinglePixelBufferManagerResource::good() {
return resource->resource();
}
CSinglePixelProtocol::CSinglePixelProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CSinglePixelProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CSinglePixelBufferManagerResource>(makeShared<CWpSinglePixelBufferManagerV1>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CSinglePixelProtocol::destroyResource(CSinglePixelBufferManagerResource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; });
}
void CSinglePixelProtocol::destroyResource(CSinglePixelBufferResource* surf) {
std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == surf; });
}

View File

@@ -0,0 +1,79 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "single-pixel-buffer-v1.hpp"
#include "types/Buffer.hpp"
class CSinglePixelBuffer : public IHLBuffer {
public:
CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col);
virtual ~CSinglePixelBuffer();
virtual Aquamarine::eBufferCapability caps();
virtual Aquamarine::eBufferType type();
virtual bool isSynchronous();
virtual void update(const CRegion& damage);
virtual Aquamarine::SDMABUFAttrs dmabuf();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
//
bool good();
bool success = false;
private:
uint32_t color = 0x00000000;
struct {
CHyprSignalListener resourceDestroy;
} listeners;
};
class CSinglePixelBufferResource {
public:
CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color);
~CSinglePixelBufferResource();
bool good();
private:
SP<CSinglePixelBuffer> buffer;
struct {
CHyprSignalListener bufferResourceDestroy;
} listeners;
};
class CSinglePixelBufferManagerResource {
public:
CSinglePixelBufferManagerResource(SP<CWpSinglePixelBufferManagerV1> resource_);
bool good();
private:
SP<CWpSinglePixelBufferManagerV1> resource;
};
class CSinglePixelProtocol : public IWaylandProtocol {
public:
CSinglePixelProtocol(const wl_interface* iface, const int& ver, const std::string& name);
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
private:
void destroyResource(CSinglePixelBufferManagerResource* resource);
void destroyResource(CSinglePixelBufferResource* resource);
//
std::vector<SP<CSinglePixelBufferManagerResource>> m_vManagers;
std::vector<SP<CSinglePixelBufferResource>> m_vBuffers;
friend class CSinglePixelBufferManagerResource;
friend class CSinglePixelBufferResource;
};
namespace PROTO {
inline UP<CSinglePixelProtocol> singlePixel;
};

View File

@@ -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(

View File

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

View File

@@ -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() {

View File

@@ -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;

View File

@@ -354,12 +354,12 @@ void CToplevelExportProtocol::bindManager(wl_client* client, void* data, uint32_
void CToplevelExportProtocol::destroyResource(CToplevelExportClient* client) {
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; });
}
void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) {
std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; });
}
void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) {
@@ -370,11 +370,17 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) {
// share frame if correct output
for (auto const& f : m_vFramesAwaitingWrite) {
if (!f->pWindow || !validMapped(f->pWindow)) {
framesToRemove.push_back(f);
if (!f)
continue;
if (!validMapped(f->pWindow)) {
framesToRemove.emplace_back(f);
continue;
}
if (!f->pWindow)
continue;
const auto PWINDOW = f->pWindow;
if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
@@ -394,7 +400,7 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) {
}
for (auto const& f : framesToRemove) {
destroyResource(f.get());
std::erase(m_vFramesAwaitingWrite, f);
}
}

View File

@@ -45,7 +45,7 @@ class CToplevelExportFrame {
bool good();
SP<CToplevelExportFrame> self;
WP<CToplevelExportFrame> self;
WP<CToplevelExportClient> client;
private:
@@ -85,7 +85,7 @@ class CToplevelExportProtocol : IWaylandProtocol {
private:
std::vector<SP<CToplevelExportClient>> m_vClients;
std::vector<SP<CToplevelExportFrame>> m_vFrames;
std::vector<SP<CToplevelExportFrame>> m_vFramesAwaitingWrite;
std::vector<WP<CToplevelExportFrame>> m_vFramesAwaitingWrite;
void shareFrame(CToplevelExportFrame* frame);
bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now);

View File

@@ -29,29 +29,20 @@ void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver
return;
}
RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); });
RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); });
RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { this->onManagerGetXDGOutput(mgr, id, output); });
RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); });
RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); });
RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { onManagerGetXDGOutput(mgr, id, output); });
}
CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
static auto P3 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PMONITOR = std::any_cast<CMonitor*>(param);
for (auto const& o : m_vXDGOutputs) {
if (o->monitor == PMONITOR)
o->monitor = nullptr;
}
});
}
void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) {
const auto OUTPUT = CWLOutputResource::fromResource(outputResource);
const auto PMONITOR = OUTPUT->monitor.get();
const auto CLIENT = mgr->client();
const auto OUTPUT = CWLOutputResource::fromResource(outputResource);
const auto PMONITOR = OUTPUT->monitor.lock();
const auto CLIENT = mgr->client();
CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique<CXDGOutput>(makeShared<CZxdgOutputV1>(CLIENT, mgr->version(), id), PMONITOR)).get();
#ifndef NO_XWAYLAND
@@ -60,14 +51,20 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
#endif
pXDGOutput->client = CLIENT;
pXDGOutput->outputProto = OUTPUT->owner;
if (!pXDGOutput->resource->resource()) {
m_vXDGOutputs.pop_back();
mgr->noMemory();
return;
}
if (!PMONITOR)
if (!PMONITOR) {
LOGM(ERR, "New xdg_output from client {:x} ({}) has no CMonitor?!", (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland");
return;
}
LOGM(LOG, "New xdg_output for {}: client {:x} ({})", PMONITOR->szName, (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland");
const auto XDGVER = pXDGOutput->resource->version();
@@ -84,8 +81,9 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
}
void CXDGOutputProtocol::updateAllOutputs() {
for (auto const& o : m_vXDGOutputs) {
LOGM(LOG, "updating all xdg_output heads");
for (auto const& o : m_vXDGOutputs) {
if (!o->monitor)
continue;
@@ -97,7 +95,7 @@ void CXDGOutputProtocol::updateAllOutputs() {
//
CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, CMonitor* monitor_) : monitor(monitor_), resource(resource_) {
CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, SP<CMonitor> monitor_) : monitor(monitor_), resource(resource_) {
if (!resource->resource())
return;
@@ -108,7 +106,7 @@ CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, CMonitor* monitor_) : monito
void CXDGOutput::sendDetails() {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (!monitor)
if (!monitor || !outputProto || outputProto->isDefunct())
return;
const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition;

View File

@@ -6,16 +6,18 @@
class CMonitor;
class CXDGOutputProtocol;
class CWLOutputProtocol;
class CXDGOutput {
public:
CXDGOutput(SP<CZxdgOutputV1> resource, CMonitor* monitor_);
CXDGOutput(SP<CZxdgOutputV1> resource, SP<CMonitor> monitor_);
void sendDetails();
private:
CMonitor* monitor = nullptr;
WP<CMonitor> monitor;
SP<CZxdgOutputV1> resource;
WP<CWLOutputProtocol> outputProto;
std::optional<Vector2D> overridePosition;
@@ -30,12 +32,12 @@ class CXDGOutputProtocol : public IWaylandProtocol {
CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name);
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
void updateAllOutputs();
private:
void onManagerResourceDestroy(wl_resource* res);
void onOutputResourceDestroy(wl_resource* res);
void onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource);
void updateAllOutputs();
//
std::vector<UP<CZxdgOutputManagerV1>> m_vManagerResources;

View File

@@ -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());
}
});

View File

@@ -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;

View File

@@ -21,8 +21,6 @@ CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMoni
PROTO::outputs.at(monitor->szName)->destroyResource(this);
});
resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(),
monitor->output->model.c_str(), monitor->transform);
if (resource->version() >= 4) {
resource->sendName(monitor->szName.c_str());
resource->sendDescription(monitor->szDescription.c_str());
@@ -57,6 +55,9 @@ void CWLOutputResource::updateState() {
resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0);
resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(),
monitor->output->model.c_str(), monitor->transform);
if (resource->version() >= 2)
resource->sendDone();
}
@@ -118,6 +119,9 @@ bool CWLOutputProtocol::isDefunct() {
}
void CWLOutputProtocol::sendDone() {
if (defunct)
return;
for (auto const& r : m_vOutputs) {
r->resource->sendDone();
}

View File

@@ -193,11 +193,8 @@ void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, ui
DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010,
};
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);
}
}

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