Compare commits

..

4 Commits
v0.44.1 ... nix

Author SHA1 Message Date
Mihai Fufezan
48f2f490d0 Nix: drop ninja for CMake build 2024-09-22 12:43:17 +03:00
Mihai Fufezan
94c7996b87 Revert "nix: use meson"
This reverts commit d505b33665.
2024-09-22 12:43:17 +03:00
Mihai Fufezan
674e7df000 Revert "nix: adapt cmake options"
This reverts commit c35ed8363f.
2024-09-22 12:43:17 +03:00
Mihai Fufezan
cb7f9140da CMake: print pch messages based on var 2024-09-22 12:30:18 +03:00
81 changed files with 790 additions and 1246 deletions

View File

@@ -29,10 +29,10 @@ body:
attributes:
label: System Info and Version
description: |
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.
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.
value: "<details>
<summary>System/Version info</summary>

View File

@@ -12,7 +12,6 @@ jobs:
matrix:
package:
- hyprland
- hyprland-cross
- xdg-desktop-portal-hyprland
runs-on: ubuntu-latest
@@ -25,4 +24,4 @@ jobs:
name: hyprland
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"
- run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"

View File

@@ -25,18 +25,8 @@ message(STATUS "Gathering git info")
execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
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()
# udis
add_subdirectory("subprojects/udis86")
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
@@ -57,6 +47,8 @@ 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)
@@ -71,8 +63,7 @@ else()
message(STATUS "Configuring Hyprland in Release with CMake")
endif()
include_directories(. "src/" "protocols/")
include_directories(. "src/" "subprojects/udis86/" "protocols/")
set(CMAKE_CXX_STANDARD 26)
add_compile_options(
-Wall
@@ -110,7 +101,7 @@ pkg_check_modules(
IMPORTED_TARGET
xkbcommon
uuid
wayland-server>=1.22.90
wayland-server
wayland-protocols
cairo
pango
@@ -123,7 +114,7 @@ pkg_check_modules(
gio-2.0
hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.3)
hyprutils>=0.2.2)
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -225,26 +216,24 @@ set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
message(STATUS "Not using precompiled headers")
else()
message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
endif()
message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::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 ${protoPath})
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif()
@@ -272,22 +261,14 @@ function(protocolWayland)
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
libudis86)
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("subprojects/hyprland-protocols/protocols"
"hyprland-global-shortcuts-v1" true)
protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
true)
protocolnew("subprojects/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)
@@ -298,7 +279,8 @@ 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("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
protocolnew("subprojects/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)
@@ -330,7 +312,6 @@ 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 +1 @@
0.44.1
0.43.0

View File

@@ -255,8 +255,4 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# 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
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.

62
flake.lock generated
View File

@@ -16,11 +16,11 @@
]
},
"locked": {
"lastModified": 1727261104,
"narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=",
"lastModified": 1726665257,
"narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "b82fdaff917582a9d568969e15e61b398c71e990",
"rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e",
"type": "github"
},
"original": {
@@ -42,11 +42,11 @@
]
},
"locked": {
"lastModified": 1727532803,
"narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=",
"lastModified": 1722623071,
"narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f",
"rev": "912d56025f03d41b1ad29510c423757b4379eb1c",
"type": "github"
},
"original": {
@@ -56,29 +56,6 @@
}
},
"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",
@@ -139,11 +116,11 @@
]
},
"locked": {
"lastModified": 1727300645,
"narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=",
"lastModified": 1726874949,
"narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c",
"rev": "d97af4f6bd068c03a518b597675e598f57ea2291",
"type": "github"
},
"original": {
@@ -162,11 +139,11 @@
]
},
"locked": {
"lastModified": 1726874836,
"narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
"lastModified": 1726840673,
"narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
"rev": "b68dab23fc922eae99306988133ee80a40b39ca5",
"type": "github"
},
"original": {
@@ -177,11 +154,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1727348695,
"narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
"lastModified": 1726755586,
"narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
"rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e",
"type": "github"
},
"original": {
@@ -195,7 +172,6 @@
"inputs": {
"aquamarine": "aquamarine",
"hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang",
"hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner",
@@ -221,7 +197,7 @@
},
"xdph": {
"inputs": {
"hyprland-protocols": "hyprland-protocols_2",
"hyprland-protocols": "hyprland-protocols",
"hyprlang": [
"hyprlang"
],
@@ -239,11 +215,11 @@
]
},
"locked": {
"lastModified": 1727524473,
"narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=",
"lastModified": 1726851729,
"narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26",
"rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf",
"type": "github"
},
"original": {

View File

@@ -22,12 +22,6 @@
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";
@@ -73,15 +67,6 @@
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;};
@@ -107,7 +92,6 @@
xdg-desktop-portal-hyprland
;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
});
devShells = eachSystem (system: {

View File

@@ -43,6 +43,10 @@ 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')
if not xcb_dep.found()
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif
@@ -73,12 +77,6 @@ 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')

View File

@@ -1,4 +1,3 @@
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')

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

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

View File

@@ -5,17 +5,16 @@
pkg-config,
pkgconf,
makeWrapper,
meson,
ninja,
cmake,
aquamarine,
binutils,
cairo,
git,
hyprcursor,
hyprland-protocols,
hyprlang,
hyprutils,
hyprwayland-scanner,
jq,
libGL,
libdrm,
libexecinfo,
@@ -25,9 +24,9 @@
mesa,
pango,
pciutils,
python3,
systemd,
tomlplusplus,
udis86-hyprland,
wayland,
wayland-protocols,
wayland-scanner,
@@ -52,7 +51,7 @@
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) flatten concatLists optional optionals;
inherit (lib.sources) cleanSourceWith cleanSource;
inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable;
inherit (lib.strings) cmakeBool hasSuffix makeBinPath optionalString;
adapters = flatten [
stdenvAdapters.useMoldLinker
@@ -75,6 +74,14 @@ in
src = cleanSource ../.;
};
patches = [
# forces GCC to use -std=c++26
./stdcxx.patch
# Nix does not have CMake 3.30 yet, so override the minimum version
./cmake-version.patch
];
postPatch = ''
# Fix hardcoded paths to /usr installation
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
@@ -94,10 +101,12 @@ in
nativeBuildInputs = [
hyprwayland-scanner
jq
makeWrapper
meson
ninja
cmake
pkg-config
python3 # for udis86
wayland-scanner
];
outputs = [
@@ -112,7 +121,6 @@ in
cairo
git
hyprcursor
hyprland-protocols
hyprlang
hyprutils
libdrm
@@ -124,10 +132,8 @@ in
pango
pciutils
tomlplusplus
udis86-hyprland
wayland
wayland-protocols
wayland-scanner
xorg.libXcursor
]
(optionals customStdenv.hostPlatform.isMusl [libexecinfo])
@@ -142,25 +148,20 @@ in
(optional withSystemd systemd)
];
mesonBuildType =
cmakeBuildType =
if debug
then "debugoptimized"
else "release";
then "Debug"
else "RelWithDebInfo";
# 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;
})
];
cmakeFlags = mapAttrsToList cmakeBool {
"NO_XWAYLAND" = !enableXWayland;
"LEGACY_RENDERER" = legacyRenderer;
"NO_SYSTEMD" = !withSystemd;
"CMAKE_DISABLE_PRECOMPILE_HEADERS" = true;
};
postInstall = ''
${optionalString wrapRuntimeDeps ''

View File

@@ -22,11 +22,9 @@ 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
@@ -65,20 +63,4 @@ 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 = [];
});
};
}

12
nix/stdcxx.patch Normal file
View File

@@ -0,0 +1,12 @@
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

@@ -63,7 +63,6 @@ protocols = [
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_protocols = []

View File

@@ -23,13 +23,11 @@
#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>
@@ -231,9 +229,6 @@ 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;
@@ -2870,8 +2865,6 @@ void CCompositor::arrangeMonitors() {
else
m->xwaylandScale = 1.f;
}
PROTO::xdgOutput->updateAllOutputs();
}
void CCompositor::enterUnsafeState() {

View File

@@ -772,12 +772,6 @@ 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:
@@ -1378,164 +1372,4 @@ 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,7 +7,6 @@
#include "helpers/varlist/VarList.hpp"
#include "../protocols/LayerShell.hpp"
#include "../xwayland/XWayland.hpp"
#include "../protocols/OutputManagement.hpp"
#include <cstddef>
#include <cstdint>
@@ -377,7 +376,6 @@ CConfigManager::CConfigManager() {
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});
@@ -447,7 +445,6 @@ 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});
@@ -686,10 +683,6 @@ 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();
@@ -867,10 +860,8 @@ 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 (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));
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));
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
@@ -1084,69 +1075,28 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s
return VAL;
}
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;
};
SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
for (auto const& r : m_dMonitorRules | std::views::reverse) {
if (PMONITOR->matchesStaticSelector(r.name)) {
return applyWlrOutputConfig(r);
if (PMONITOR.matchesStaticSelector(r.name)) {
return 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 applyWlrOutputConfig(r);
return r;
}
}
Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
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
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
}
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) {
@@ -1505,7 +1455,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;
@@ -1562,7 +1512,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);

View File

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

View File

@@ -268,9 +268,5 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# 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
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
)#";

View File

@@ -103,7 +103,6 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"focused": {},
"dpmsStatus": {},
"vrr": {},
"solitary": "{:x}",
"activelyTearing": {},
"disabled": {},
"currentFormat": "{}",
@@ -115,20 +114,19 @@ 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"), (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));
(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));
} 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\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
"dpmsStatus: {}\n\tvrr: {}\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, (uint64_t)m->solitaryClient.get(),
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, m->tearingState.activelyTearing,
!m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
}
return result;
@@ -160,7 +158,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!m->output || m->ID == -1)
continue;
result += CHyprCtl::getMonitorData(m, format);
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));
}
}
@@ -313,48 +320,45 @@ 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 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 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 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())) : "";
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())) : "";
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, defaultName);
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow);
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 defaultName = std::format("\tdefaultName: {}\n", r.defaultName.value_or("<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>");
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow, defaultName);
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow);
return result;
}
@@ -934,14 +938,11 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
result += "plugins:\n";
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";
for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
}
if (g_pHyprCtl && g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) {
if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) {
result += "\n======Config-Start======\n";
result += g_pConfigManager->getConfigString();
result += "\n======Config-End========\n";
@@ -1623,14 +1624,6 @@ 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});
@@ -1652,7 +1645,6 @@ 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,9 +5,6 @@
#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,5 +1,6 @@
#include "includes.hpp"
#include "debug/Log.hpp"
#include "helpers/WLListener.hpp"
#include "helpers/Color.hpp"
#include "macros.hpp"
#include "desktop/DesktopTypes.hpp"

View File

@@ -30,7 +30,13 @@ 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,6 +35,10 @@ 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.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1;
return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1;
}
Vector2D CWLSurface::correctSmallVec() const {

View File

@@ -178,18 +178,13 @@ 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;
}
@@ -235,7 +230,6 @@ 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);
@@ -258,7 +252,6 @@ 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);
@@ -339,9 +332,6 @@ 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;
@@ -392,9 +382,6 @@ 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,6 +1,7 @@
#pragma once
#include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"
@@ -82,9 +83,8 @@ 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,
*xkbSymState = nullptr /* Same as static but gets layouts */;
xkb_keymap* xkbKeymap = nullptr;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
xkb_keymap* xkbKeymap = nullptr;
struct {
uint32_t depressed = 0, latched = 0, locked = 0, group = 0;

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
#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()->onWindowCreated(PWINDOW);
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true;
// size and move rules

View File

@@ -1,54 +0,0 @@
#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,9 +8,8 @@ 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,6 +628,27 @@ 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,6 +34,7 @@ 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

@@ -12,7 +12,6 @@
#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>
@@ -36,7 +35,6 @@ CMonitor::~CMonitor() {
}
void CMonitor::onConnect(bool noRule) {
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
if (output->supportsExplicit) {
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
@@ -116,7 +114,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(self.lock());
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
@@ -230,13 +228,6 @@ void CMonitor::onConnect(bool noRule) {
}
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);
@@ -349,6 +340,9 @@ void CMonitor::onDisconnect(bool destroy) {
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
}
std::erase_if(g_pCompositor->m_vMonitors, [&](SP<CMonitor>& el) { return el.get() == this; });
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
}
void CMonitor::addDamage(const pixman_region32_t* rg) {
@@ -495,7 +489,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr;
// set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock());
const auto RULE = g_pConfigManager->getMonitorRuleFor(*this);
vecPosition = RULE.offset;
@@ -778,9 +772,12 @@ Vector2D CMonitor::middle() {
}
void CMonitor::updateMatrix() {
projMatrix = Mat3x3::identity();
if (transform != WL_OUTPUT_TRANSFORM_NORMAL)
projMatrix.translate(vecPixelSize / 2.0).transform(wlTransformToHyprutils(transform)).translate(-vecTransformedSize / 2.0);
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);
}
}
WORKSPACEID CMonitor::activeWorkspaceID() {
@@ -795,22 +792,20 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize};
}
void CMonitor::scheduleDone() {
if (doneScheduled)
static void onDoneSource(void* data) {
auto pMonitor = (CMonitor*)data;
if (!PROTO::outputs.contains(pMonitor->szName))
return;
doneScheduled = true;
PROTO::outputs.at(pMonitor->szName)->sendDone();
}
g_pEventLoopManager->doLater([M = self] {
if (!M) // if M is gone, we got destroyed, doesn't matter.
return;
void CMonitor::scheduleDone() {
if (doneSource)
return;
if (!PROTO::outputs.contains(M->szName))
return;
PROTO::outputs.at(M->szName)->sendDone();
M->doneScheduled = false;
});
doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this);
}
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;
Mat3x3 projMatrix;
std::array<float, 9> projMatrix = {0};
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();
bool doneScheduled = false;
wl_event_source* doneSource = nullptr;
struct {
CHyprSignalListener frame;

View File

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

View File

@@ -0,0 +1,62 @@
#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

@@ -0,0 +1,39 @@
#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,4 +1,6 @@
#include "Math.hpp"
#include <unordered_map>
#include <cstring>
Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) {
switch (t) {
@@ -15,6 +17,124 @@ 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,9 +4,17 @@
// 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,7 +340,26 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
return;
}
// get the node under our cursor
// 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
m_lDwindleNodesData.push_back(SDwindleNodeData());
const auto NEWPARENT = &m_lDwindleNodesData.back();
@@ -440,12 +459,6 @@ 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) {
@@ -979,10 +992,6 @@ 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];
@@ -1050,44 +1059,6 @@ 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,7 +87,6 @@ class CHyprDwindleLayout : public IHyprLayout {
void toggleSplit(PHLWINDOW);
void swapSplit(PHLWINDOW);
void moveToRoot(PHLWINDOW, bool stable = true);
eDirection overrideDirection = DIRECTION_DEFAULT;

View File

@@ -9,25 +9,23 @@
#include "../xwayland/XSurface.hpp"
void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
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)
if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow);
else
} 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;
onWindowCreatedTiling(pWindow, direction);
}
}
void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
@@ -180,48 +178,6 @@ 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();
@@ -553,10 +509,10 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
// move to narnia because we don't wanna find our own node. onWindowCreated should apply the coords back.
// move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back.
pWindow->m_vPosition = Vector2D(-999999, -999999);
onWindowCreated(pWindow);
onWindowCreatedTiling(pWindow);
pWindow->m_vRealPosition.setValue(PSAVEDPOS);
pWindow->m_vRealSize.setValue(PSAVEDSIZE);

View File

@@ -47,7 +47,6 @@ 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,6 +116,26 @@ 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,7 +3,6 @@
#include "Compositor.hpp"
#include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp"
#include "debug/HyprCtl.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
@@ -134,10 +133,6 @@ int main(int argc, char** argv) {
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";
help();

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->xkbSymState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE);
if (handleInternalKeybinds(internalKeysym))
@@ -594,10 +594,6 @@ 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;
@@ -1943,7 +1939,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;
@@ -2403,7 +2399,9 @@ SDispatchResult CKeybindManager::dpms(std::string arg) {
bool enable = arg.starts_with("on");
std::string port = "";
bool isToggle = arg.starts_with("toggle");
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
if (arg.find_first_of(' ') != std::string::npos)
port = arg.substr(arg.find_first_of(' ') + 1);
@@ -2412,9 +2410,6 @@ 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);

View File

@@ -96,7 +96,6 @@ 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;

View File

@@ -17,8 +17,10 @@ CPointerManager::CPointerManager() {
onMonitorLayoutChange();
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.modeChanged.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.disconnect.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.destroy.registerStaticListener(
[this](void* owner, std::any data) {
if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown)
@@ -657,7 +659,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) {
}
void CPointerManager::damageIfSoftware() {
auto b = getCursorBoxGlobal().expand(4);
auto b = getCursorBoxGlobal();
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");

View File

@@ -44,7 +44,6 @@
#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"
@@ -86,8 +85,7 @@ CProtocolManager::CProtocolManager() {
// ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after
// this event is emitted iirc.
// also ignore the fallback
if (M->isMirror() || M == g_pCompositor->m_pUnsafeOutput)
if (M->isMirror())
return;
if (PROTO::outputs.contains(M->szName))
@@ -154,7 +152,6 @@ 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,6 +2,7 @@
#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

@@ -50,10 +50,6 @@ 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

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

View File

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

View File

@@ -16,7 +16,7 @@ executable(
dependency('cairo'),
dependency('hyprcursor', version: '>=0.1.7'),
dependency('hyprlang', version: '>= 0.3.2'),
dependency('hyprutils', version: '>= 0.2.3'),
dependency('hyprutils', version: '>= 0.2.1'),
dependency('libdrm'),
dependency('egl'),
dependency('xkbcommon'),
@@ -31,12 +31,7 @@ executable(
backtrace_dep,
epoll_dep,
gio_dep,
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'),
udis86,
dependency('pixman-1'),
dependency('gl', 'opengl'),

View File

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

View File

@@ -307,15 +307,10 @@ COutputConfiguration::COutputConfiguration(SP<CZwlrOutputConfigurationV1> resour
LOGM(LOG, "disableHead on {}", PMONITOR->szName);
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;
PMONITOR->activeMonitorRule.disabled = true;
if (!g_pConfigManager->replaceMonitorRule(PMONITOR->activeMonitorRule))
g_pConfigManager->appendMonitorRule(PMONITOR->activeMonitorRule);
g_pHyprRenderer->applyMonitorRule(PMONITOR, &PMONITOR->activeMonitorRule, false);
});
resource->setTest([this](CZwlrOutputConfigurationV1* r) {
@@ -351,11 +346,6 @@ 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();
@@ -367,59 +357,41 @@ bool COutputConfiguration::applyTestConfiguration(bool test) {
if (!PMONITOR)
continue;
LOGM(LOG, "Saving config for monitor {}", PMONITOR->szName);
LOGM(LOG, "Applying config for monitor {}", PMONITOR->szName);
SWlrManagerSavedOutputState newState;
if (owner->monitorStates.contains(PMONITOR->szName))
newState = owner->monitorStates.at(PMONITOR->szName);
SMonitorRule newRule = PMONITOR->activeMonitorRule;
newRule.name = PMONITOR->szName;
newRule.disabled = false;
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_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;
}
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_POSITION)
newRule.offset = head->state.position;
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_ADAPTIVE_SYNC)
newRule.vrr = head->state.adaptiveSync;
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_SCALE)
newRule.scale = head->state.scale;
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);
}
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM)
newRule.transform = head->state.transform;
// reset properties for next set.
head->state.committedProperties = 0;
head->committedProperties = 0;
if (!g_pConfigManager->replaceMonitorRule(newRule))
g_pConfigManager->appendMonitorRule(newRule);
g_pConfigManager->m_bWantsMonitorReload = true;
owner->monitorStates[PMONITOR->szName] = newState;
}
LOGM(LOG, "Saved configuration");
LOGM(LOG, "Applied configuration");
return true;
}
@@ -445,12 +417,12 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_MODE) {
if (committedProperties & OUTPUT_HEAD_COMMITTED_MODE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
state.committedProperties |= OUTPUT_HEAD_COMMITTED_MODE;
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);
@@ -462,22 +434,17 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
if (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 < 0) {
if (w <= 0 || h <= 0 || refresh <= 100) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE, "Invalid mode");
return;
}
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;
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);
@@ -489,12 +456,12 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
if (committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
state.committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION;
committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION;
state.position = {x, y};
LOGM(LOG, " | configHead for {}: set pos to {}, {}", pMonitor->szName, x, y);
@@ -506,7 +473,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
if (committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
@@ -516,7 +483,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
state.committedProperties |= OUTPUT_HEAD_COMMITTED_TRANSFORM;
committedProperties |= OUTPUT_HEAD_COMMITTED_TRANSFORM;
state.transform = (wl_output_transform)transform;
LOGM(LOG, " | configHead for {}: set transform to {}", pMonitor->szName, transform);
@@ -528,7 +495,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
if (committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
@@ -540,7 +507,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
state.committedProperties |= OUTPUT_HEAD_COMMITTED_SCALE;
committedProperties |= OUTPUT_HEAD_COMMITTED_SCALE;
state.scale = scale;
LOGM(LOG, " | configHead for {}: set scale to {:.2f}", pMonitor->szName, scale);
@@ -552,7 +519,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
if (state.committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
if (committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) {
resource->error(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set");
return;
}
@@ -562,7 +529,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
return;
}
state.committedProperties |= OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC;
committedProperties |= OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC;
state.adaptiveSync = as;
LOGM(LOG, " | configHead for {}: set adaptiveSync to {}", pMonitor->szName, as);
@@ -634,14 +601,3 @@ 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,7 +3,6 @@
#include <memory>
#include <vector>
#include <cstdint>
#include <unordered_map>
#include "WaylandProtocol.hpp"
#include "wlr-output-management-unstable-v1.hpp"
#include "../helpers/signal/Signal.hpp"
@@ -14,43 +13,6 @@ 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_);
@@ -59,9 +21,6 @@ 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;
@@ -121,9 +80,30 @@ class COutputConfigurationHead {
public:
COutputConfigurationHead(SP<CZwlrOutputConfigurationHeadV1> resource_, CMonitor* pMonitor_);
bool good();
bool good();
SWlrManagerOutputState state;
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;
private:
SP<CZwlrOutputConfigurationHeadV1> resource;
@@ -156,9 +136,6 @@ 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,6 +27,8 @@ 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 || other->client.get() == client; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return 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 || other.get() == frame; });
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; });
}
void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
@@ -412,11 +412,8 @@ 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.emplace_back(f);
framesToRemove.push_back(f);
continue;
}
@@ -428,10 +425,10 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
f->client->lastFrame.reset();
++f->client->frameCounter;
framesToRemove.emplace_back(f);
framesToRemove.push_back(f);
}
for (auto const& f : framesToRemove) {
std::erase(m_vFramesAwaitingWrite, f);
destroyResource(f.get());
}
}

View File

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

View File

@@ -1,128 +0,0 @@
#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

@@ -1,79 +0,0 @@
#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

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

View File

@@ -45,7 +45,7 @@ class CToplevelExportFrame {
bool good();
WP<CToplevelExportFrame> self;
SP<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<WP<CToplevelExportFrame>> m_vFramesAwaitingWrite;
std::vector<SP<CToplevelExportFrame>> m_vFramesAwaitingWrite;
void shareFrame(CToplevelExportFrame* frame);
bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now);

View File

@@ -29,20 +29,29 @@ void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver
return;
}
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); });
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); });
}
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.lock();
const auto CLIENT = mgr->client();
const auto OUTPUT = CWLOutputResource::fromResource(outputResource);
const auto PMONITOR = OUTPUT->monitor.get();
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
@@ -51,20 +60,14 @@ 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) {
LOGM(ERR, "New xdg_output from client {:x} ({}) has no CMonitor?!", (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland");
if (!PMONITOR)
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();
@@ -81,9 +84,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
}
void CXDGOutputProtocol::updateAllOutputs() {
LOGM(LOG, "updating all xdg_output heads");
for (auto const& o : m_vXDGOutputs) {
if (!o->monitor)
continue;
@@ -95,7 +97,7 @@ void CXDGOutputProtocol::updateAllOutputs() {
//
CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, SP<CMonitor> monitor_) : monitor(monitor_), resource(resource_) {
CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, CMonitor* monitor_) : monitor(monitor_), resource(resource_) {
if (!resource->resource())
return;
@@ -106,7 +108,7 @@ CXDGOutput::CXDGOutput(SP<CZxdgOutputV1> resource_, SP<CMonitor> monitor_) : mon
void CXDGOutput::sendDetails() {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (!monitor || !outputProto || outputProto->isDefunct())
if (!monitor)
return;
const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition;

View File

@@ -6,18 +6,16 @@
class CMonitor;
class CXDGOutputProtocol;
class CWLOutputProtocol;
class CXDGOutput {
public:
CXDGOutput(SP<CZxdgOutputV1> resource, SP<CMonitor> monitor_);
CXDGOutput(SP<CZxdgOutputV1> resource, CMonitor* monitor_);
void sendDetails();
private:
WP<CMonitor> monitor;
CMonitor* monitor = nullptr;
SP<CZxdgOutputV1> resource;
WP<CWLOutputProtocol> outputProto;
std::optional<Vector2D> overridePosition;
@@ -32,12 +30,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

@@ -21,6 +21,8 @@ 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());
@@ -55,9 +57,6 @@ 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();
}
@@ -119,9 +118,6 @@ bool CWLOutputProtocol::isDefunct() {
}
void CWLOutputProtocol::sendDone() {
if (defunct)
return;
for (auto const& r : m_vOutputs) {
r->resource->sendDone();
}

View File

@@ -755,12 +755,14 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP<
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
m_RenderData.monitorProjection = Mat3x3::identity();
matrixIdentity(m_RenderData.monitorProjection.data());
if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize;
m_RenderData.monitorProjection.translate(FBO->m_vSize / 2.0).transform(wlTransformToHyprutils(pMonitor->transform)).translate(-tfmd / 2.0);
matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0);
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform));
matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0);
}
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
@@ -807,7 +809,7 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
m_RenderData.monitorProjection = pMonitor->projMatrix;
@@ -1287,17 +1289,20 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
box = &newBox;
Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(
newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float matrix[9];
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
m_RenderData.monitorProjection.data());
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix);
#endif
// premultiply the color as well as we don't work with straight alpha
@@ -1381,8 +1386,11 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
if (m_bEndFrame || TRANSFORMS_MATCH)
TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float matrix[9];
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
if (waitTimeline != nullptr) {
if (!waitForTimelinePoint(waitTimeline, waitPoint)) {
@@ -1423,9 +1431,6 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex->m_iTarget, tex->m_iTexID);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (m_RenderData.useNearestNeighbor) {
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -1437,10 +1442,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pB
glUseProgram(shader->program);
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1i(shader->tex, 0);
@@ -1551,10 +1556,13 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
// get transform
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float matrix[9];
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex->m_iTarget, tex->m_iTexID);
@@ -1562,10 +1570,10 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) {
glUseProgram(shader->program);
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1i(shader->tex, 0);
@@ -1602,18 +1610,21 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuf
// get transform
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform));
Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float matrix[9];
projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE;
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE;
glUseProgram(shader->program);
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1i(shader->tex, 0);
glUniform1i(shader->alphaMatte, 1);
@@ -1656,10 +1667,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glDisable(GL_STENCIL_TEST);
// get transforms for the full monitor
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform));
float matrix[9];
CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(MONITORBOX, TRANSFORM);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data());
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
// get the config settings
static auto PBLURSIZE = CConfigValue<Hyprlang::INT>("decoration:blur:size");
@@ -1696,10 +1710,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS);
@@ -1741,10 +1755,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
// prep two shaders
#ifndef GLES2
glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a
if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) {
@@ -1818,10 +1832,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE);
glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS);
@@ -2151,9 +2165,12 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
round += round == 0 ? 0 : scaledBorderSize;
Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(
newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float matrix[9];
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
m_RenderData.monitorProjection.data());
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
const auto BLEND = m_bBlend;
blend(true);
@@ -2161,10 +2178,10 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
#endif
static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail
@@ -2454,19 +2471,22 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
const auto col = color;
Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(
newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot);
Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix);
float matrix[9];
projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot,
m_RenderData.monitorProjection.data());
float glMatrix[9];
matrixMultiply(glMatrix, m_RenderData.projection, matrix);
glEnable(GL_BLEND);
glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix);
#else
glMatrix.transpose();
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data());
matrixTranspose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a);
@@ -2545,11 +2565,11 @@ void CHyprOpenGLImpl::renderMirrored() {
return;
// replace monitor projection to undo the mirrored monitor's projection
m_RenderData.monitorProjection = Mat3x3::identity()
.translate(monitor->vecPixelSize / 2.0)
.transform(wlTransformToHyprutils(monitor->transform))
.transform(wlTransformToHyprutils(invertTransform(mirrored->transform)))
.translate(-monitor->vecTransformedSize / 2.0);
matrixIdentity(m_RenderData.monitorProjection.data());
matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0);
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform));
matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform)));
matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0);
// clear stuff outside of mirrored area (e.g. when changing to mirrored)
clear(CColor(0, 0, 0, 0));
@@ -2900,15 +2920,16 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
}
void CHyprOpenGLImpl::saveMatrix() {
m_RenderData.savedProjection = m_RenderData.projection;
memcpy(m_RenderData.savedProjection, m_RenderData.projection, 9 * sizeof(float));
}
void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) {
m_RenderData.projection.scale(scale).translate(translate);
matrixScale(m_RenderData.projection, scale, scale);
matrixTranslate(m_RenderData.projection, translate.x, translate.y);
}
void CHyprOpenGLImpl::restoreMatrix() {
m_RenderData.projection = m_RenderData.savedProjection;
memcpy(m_RenderData.projection, m_RenderData.savedProjection, 9 * sizeof(float));
}
void CHyprOpenGLImpl::bindOffMain() {

View File

@@ -94,35 +94,35 @@ struct SMonitorRenderData {
};
struct SCurrentRenderData {
CMonitor* pMonitor = nullptr;
PHLWORKSPACE pWorkspace = nullptr;
Mat3x3 projection;
Mat3x3 savedProjection;
Mat3x3 monitorProjection;
CMonitor* pMonitor = nullptr;
PHLWORKSPACE pWorkspace = nullptr;
float projection[9];
float savedProjection[9];
std::array<float, 9> monitorProjection;
SMonitorRenderData* pCurrentMonData = nullptr;
CFramebuffer* currentFB = nullptr; // current rendering to
CFramebuffer* mainFB = nullptr; // main to render to
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
SMonitorRenderData* pCurrentMonData = nullptr;
CFramebuffer* currentFB = nullptr; // current rendering to
CFramebuffer* mainFB = nullptr; // main to render to
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool forceIntrospection = false; // cleaned in ::end()
bool blockScreenShader = false;
bool simplePass = false;
SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool forceIntrospection = false; // cleaned in ::end()
bool blockScreenShader = false;
bool simplePass = false;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
CBox clipBox = {}; // scaled coordinates
CBox clipBox = {}; // scaled coordinates
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
};
class CEGLSync {

View File

@@ -2,6 +2,7 @@
#include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../helpers/WLListener.hpp"
#include "Framebuffer.hpp"
#include <aquamarine/buffer/Buffer.hpp>

View File

@@ -150,7 +150,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
const auto& TEXTURE = surface->current.texture;
const auto RDATA = (SRenderData*)data;
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE;
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE;
// this is bad, probably has been logged elsewhere. Means the texture failed
// uploading to the GPU.
@@ -180,7 +180,6 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
// however, if surface buffer w / h < box, we need to adjust them
const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr;
// center the surface if it's smaller than the viewport we assign it
if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) {
const auto CORRECT = PSURFACE->correctSmallVec();
const auto SIZE = PSURFACE->getViewporterCorrectedSize();
@@ -196,6 +195,17 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
}
}
if (!INTERACTIVERESIZEINPROGRESS && PSURFACE && PWINDOW && PWINDOW->m_vRealSize.goal().floor() > PWINDOW->m_vReportedSize && PWINDOW->m_vReportedSize > Vector2D{1, 1}) {
Vector2D size =
Vector2D{windowBox.w * (PWINDOW->m_vReportedSize.x / PWINDOW->m_vRealSize.value().x), windowBox.h * (PWINDOW->m_vReportedSize.y / PWINDOW->m_vRealSize.value().y)};
Vector2D correct = Vector2D{windowBox.w, windowBox.h} - size;
windowBox.translate(correct / 2.0);
windowBox.w = size.x;
windowBox.h = size.y;
}
} else { // here we clamp to 2, these might be some tiny specks
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)};
if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) {
@@ -221,8 +231,6 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
return; // invisible
}
const auto PROJSIZEUNSCALED = windowBox.size();
windowBox.scale(RDATA->pMonitor->scale);
windowBox.round();
@@ -231,7 +239,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ &&
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */;
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->pMonitor->self.lock(), RDATA->surface == surface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1);
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1);
// check for fractional scale surfaces misaligning the buffer size
// in those cases it's better to just force nearest neighbor
@@ -1075,8 +1083,7 @@ void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) {
g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID);
}
void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, SP<CMonitor> pMonitor, bool main, const Vector2D& projSize,
const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) {
void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) {
if (!pWindow || !pWindow->m_bIsX11) {
Vector2D uvTL;
Vector2D uvBR = Vector2D(1, 1);
@@ -1105,22 +1112,6 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
uvBR -= MISALIGNMENT * PIXELASUV;
}
// if the surface is smaller than our viewport, extend its edges.
// this will break if later on xdg geometry is hit, but we really try
// to let the apps know to NOT add CSD. Also if source is there.
// there is no way to fix this if that's the case
const auto MONITOR_WL_SCALE = std::ceil(pMonitor->scale);
const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->current.scale && !pSurface->current.viewport.hasDestination;
const auto EXPECTED_SIZE =
((pSurface->current.viewport.hasDestination ? pSurface->current.viewport.destination : pSurface->current.bufferSize / pSurface->current.scale) * pMonitor->scale)
.round();
if (!SCALE_UNAWARE && (EXPECTED_SIZE.x < projSize.x || EXPECTED_SIZE.y < projSize.y)) {
// this will not work with shm AFAIK, idk why.
// NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much
const auto FIX = projSize / EXPECTED_SIZE;
uvBR = uvBR * FIX;
}
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
@@ -1136,17 +1127,18 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
CBox geom = pWindow->m_pXDGSurface->current.geometry;
// ignore X and Y, adjust uv
if (geom.x != 0 || geom.y != 0 || geom.width > projSizeUnscaled.x || geom.height > projSizeUnscaled.y) {
if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) {
const auto XPERC = (double)geom.x / (double)pSurface->current.size.x;
const auto YPERC = (double)geom.y / (double)pSurface->current.size.y;
const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x;
const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.size.y;
const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y));
uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y));
uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y));
uvTL = uvTL + TOADDTL;
auto maxSize = projSizeUnscaled;
// TODO: make this passed to the func. Might break in the future.
auto maxSize = pWindow->m_vRealSize.value();
if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall)
maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize();

View File

@@ -49,23 +49,22 @@ class CHyprRenderer {
CHyprRenderer();
~CHyprRenderer();
void renderMonitor(CMonitor* pMonitor);
void arrangeLayersForMonitor(const MONITORID&);
void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
void damageWindow(PHLWINDOW, bool forceFull = false);
void damageBox(CBox*, bool skipFrameSchedule = false);
void damageBox(const int& x, const int& y, const int& w, const int& h);
void damageRegion(const CRegion&);
void damageMonitor(CMonitor*);
void damageMirrorsWith(CMonitor*, const CRegion&);
bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
bool shouldRenderWindow(PHLWINDOW, CMonitor*);
bool shouldRenderWindow(PHLWINDOW);
void ensureCursorRenderingMode();
bool shouldRenderCursor();
void setCursorHidden(bool hide);
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, SP<CMonitor> pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {},
bool fixMisalignedFSV1 = false);
void renderMonitor(CMonitor* pMonitor);
void arrangeLayersForMonitor(const MONITORID&);
void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
void damageWindow(PHLWINDOW, bool forceFull = false);
void damageBox(CBox*, bool skipFrameSchedule = false);
void damageBox(const int& x, const int& y, const int& w, const int& h);
void damageRegion(const CRegion&);
void damageMonitor(CMonitor*);
void damageMirrorsWith(CMonitor*, const CRegion&);
bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
bool shouldRenderWindow(PHLWINDOW, CMonitor*);
bool shouldRenderWindow(PHLWINDOW);
void ensureCursorRenderingMode();
bool shouldRenderCursor();
void setCursorHidden(bool hide);
void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false);
std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry);
void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace);

View File

@@ -1,5 +1,6 @@
#pragma once
#include "../helpers/WLListener.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../helpers/math/Math.hpp"

View File

@@ -2,6 +2,7 @@
#include "../macros.hpp"
#include "XDataSource.hpp"
#include "../helpers/WLListener.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../helpers/signal/Signal.hpp"

View File

@@ -1 +0,0 @@
[wrap-file]

View File

@@ -1,5 +0,0 @@
[wrap-file]
method = cmake
[provide]
udis86 = libudis86_dep