Merge branch 'hyprwm:main' into main

This commit is contained in:
Amrit Srivastava 2024-08-13 00:50:42 +05:30 committed by GitHub
commit 7263d8cec7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
140 changed files with 3586 additions and 2193 deletions

View file

@ -3,6 +3,7 @@ name: Build Hyprland
on: [push, pull_request, workflow_dispatch] on: [push, pull_request, workflow_dispatch]
jobs: jobs:
gcc: gcc:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland (Arch)" name: "Build Hyprland (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@ -44,6 +45,7 @@ jobs:
path: Hyprland.tar.xz path: Hyprland.tar.xz
meson: meson:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland with Meson (Arch)" name: "Build Hyprland with Meson (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@ -64,6 +66,7 @@ jobs:
run: ninja -C build run: ninja -C build
no-pch: no-pch:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland without precompiled headers (Arch)" name: "Build Hyprland without precompiled headers (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@ -83,6 +86,7 @@ jobs:
run: make nopch run: make nopch
noxwayland: noxwayland:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland in pure Wayland (Arch)" name: "Build Hyprland in pure Wayland (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@ -103,6 +107,7 @@ jobs:
run: make release run: make release
clang-format: clang-format:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Code Style (Arch)" name: "Code Style (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:

View file

@ -15,14 +15,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
ref: ${{ github.ref }} ref: ${{ github.ref }}
submodules: recursive submodules: recursive
- uses: cachix/install-nix-action@v26 - uses: cachix/install-nix-action@v27
- uses: DeterminateSystems/magic-nix-cache-action@main - uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v12 - uses: cachix/cachix-action@v15
with: with:
name: hyprland name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

View file

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

View file

@ -4,6 +4,7 @@ on: [push, pull_request]
jobs: jobs:
flawfinder: flawfinder:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: Flawfinder Checks name: Flawfinder Checks
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:

View file

@ -1,8 +1,5 @@
cmake_minimum_required(VERSION 3.27) cmake_minimum_required(VERSION 3.27)
include(CheckIncludeFile)
include(GNUInstallDirs)
# Get version # Get version
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
string(STRIP ${VER_RAW} VER) string(STRIP ${VER_RAW} VER)
@ -12,6 +9,9 @@ project(
DESCRIPTION "A Modern C++ Wayland Compositor" DESCRIPTION "A Modern C++ Wayland Compositor"
VERSION ${VER}) VERSION ${VER})
include(CheckIncludeFile)
include(GNUInstallDirs)
set(HYPRLAND_VERSION ${VER}) set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(PREFIX ${CMAKE_INSTALL_PREFIX})
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
@ -49,8 +49,6 @@ endif()
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner)
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir)
@ -64,7 +62,7 @@ else()
endif() endif()
include_directories(. "src/" "subprojects/udis86/" "protocols/") include_directories(. "src/" "subprojects/udis86/" "protocols/")
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 26)
add_compile_options( add_compile_options(
-Wall -Wall
-Wextra -Wextra
@ -89,6 +87,12 @@ else()
endif() endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(
hyprctl_deps
REQUIRED
IMPORTED_TARGET
hyprutils>=0.2.1)
pkg_check_modules( pkg_check_modules(
deps deps
REQUIRED REQUIRED
@ -113,9 +117,10 @@ pkg_check_modules(
libliftoff libliftoff
libudev libudev
gbm gbm
gio-2.0
hyprlang>=0.3.2 hyprlang>=0.3.2
hyprcursor>=0.1.7 hyprcursor>=0.1.7
hyprutils>=0.2.0) hyprutils>=0.2.1)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@ -232,30 +237,6 @@ target_link_libraries(Hyprland rt PkgConfig::deps)
# used by `make installheaders`, to ensure the headers are generated # used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers) add_custom_target(generate-protocol-headers)
function(protocol protoPath protoName external)
if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif()
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
COMMAND ${WaylandScanner} server-header ${path}
protocols/${protoName}-protocol.h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c
COMMAND ${WaylandScanner} private-code ${path}
protocols/${protoName}-protocol.c
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(
Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c)
target_sources(generate-protocol-headers
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h)
endfunction()
function(protocolnew protoPath protoName external) function(protocolnew protoPath protoName external)
if(external) if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath}) set(path ${CMAKE_SOURCE_DIR}/${protoPath})
@ -288,15 +269,11 @@ endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
libudis86 uuid) libudis86 uuid)
protocol( protocolnew("subprojects/hyprland-protocols/protocols"
"subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
"hyprland-global-shortcuts-v1" true) protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocolnew("subprojects/hyprland-protocols/protocols"
protocol( "hyprland-toplevel-export-v1" true)
"unstable/text-input/text-input-unstable-v1.xml"
"text-input-unstable-v1" false)
protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-toplevel-export-v1" true)
protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
@ -353,24 +330,27 @@ install(
CODE "execute_process( \ CODE "execute_process( \
COMMAND ${CMAKE_COMMAND} -E create_symlink \ COMMAND ${CMAKE_COMMAND} -E create_symlink \
${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
${CMAKE_INSTALL_FULL_BINDIR}/hyprland \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \
)") )")
# session file # session file
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/wayland-sessions) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
# allow Hyprland to find wallpapers
add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}")
# wallpapers # wallpapers
file(GLOB_RECURSE WALLPAPERS "assets/wall*") file(GLOB_RECURSE WALLPAPERS "assets/wall*")
install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# default config # default config
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# portal config # portal config
install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf
DESTINATION ${CMAKE_INSTALL_DATADIR}/xdg-desktop-portal) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/xdg-desktop-portal)
# man pages # man pages
file(GLOB_RECURSE MANPAGES "docs/*.1") file(GLOB_RECURSE MANPAGES "docs/*.1")

View file

@ -1 +1 @@
0.41.2 0.42.0

View file

@ -1,7 +1,7 @@
wallpapers = ['0', '1', '2'] wallpapers = ['0', '1', '2']
foreach type : wallpapers foreach type : wallpapers
install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime') install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime')
endforeach endforeach
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')

View file

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

View file

@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1721992626, "lastModified": 1723405438,
"narHash": "sha256-GFDSPWxOqEkNrbuSfyoQHGIaRhJNapn2Rv0EEmBGR9A=", "narHash": "sha256-bpmC2m7OhlDvqgQZdZ2jBLyeIkq/Jld3X4bqRAxBSp8=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "f95d1509370b7f40ef356ff69a332bd0356ab044", "rev": "9312aa28271c91e5d67ecb9def527b2bbcff0e66",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -42,11 +42,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1721330371, "lastModified": 1722623071,
"narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=", "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc", "rev": "912d56025f03d41b1ad29510c423757b4379eb1c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -67,11 +67,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1718746314, "lastModified": 1721326555,
"narHash": "sha256-HUklK5u86w2Yh9dOkk4FdsL8eehcOZ95jPhLixGDRQY=", "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "1b61f0093afff20ab44d88ad707aed8bf2215290", "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -116,11 +116,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1721324102, "lastModified": 1722869141,
"narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "962582a090bc233c4de9d9897f46794280288989", "rev": "0252fd13e78e60fb0da512a212e56007515a49f7",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -154,11 +154,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1721924956, "lastModified": 1723175592,
"narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=", "narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "5ad6a14c6bf098e98800b091668718c336effc95", "rev": "5e0ca22929f3342b19569b21b2f3462f053e497b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -209,11 +209,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1721755049, "lastModified": 1722365976,
"narHash": "sha256-O17b38bQnmfxv7It3OnVYx7fp1seEdI7xxnw5vJFv30=", "narHash": "sha256-Khdm+mDzYA//XaU0M+hftod+rKr5q9SSHSEuiQ0/9ow=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "5555f467f68ce7cdf1060991c24263073b95e9da", "rev": "7f2a77ddf60390248e2a3de2261d7102a13e5341",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -95,7 +95,7 @@
devShells = eachSystem (system: { devShells = eachSystem (system: {
default = default =
pkgsFor.${system}.mkShell.override { pkgsFor.${system}.mkShell.override {
stdenv = pkgsFor.${system}.gcc13Stdenv; stdenv = pkgsFor.${system}.gcc14Stdenv;
} { } {
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [ nativeBuildInputs = with pkgsFor.${system}; [

View file

@ -9,7 +9,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
add_executable(hyprctl "main.cpp") add_executable(hyprctl "main.cpp")
target_link_libraries(hyprctl PUBLIC PkgConfig::deps) target_link_libraries(hyprctl PUBLIC PkgConfig::hyprctl_deps)
# binary # binary
install(TARGETS hyprctl) install(TARGETS hyprctl)

View file

@ -26,6 +26,7 @@
#include <regex> #include <regex>
#include <sys/socket.h> #include <sys/socket.h>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <cstring>
using namespace Hyprutils::String; using namespace Hyprutils::String;
#include "Strings.hpp" #include "Strings.hpp"
@ -113,7 +114,7 @@ int rollingRead(const int socket) {
constexpr size_t BUFFER_SIZE = 8192; constexpr size_t BUFFER_SIZE = 8192;
std::array<char, BUFFER_SIZE> buffer = {0}; std::array<char, BUFFER_SIZE> buffer = {0};
int sizeWritten = 0; long sizeWritten = 0;
std::cout << "[hyprctl] reading from socket following up log:" << std::endl; std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
while (!sigintReceived) { while (!sigintReceived) {
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
@ -141,7 +142,7 @@ int rollingRead(const int socket) {
int request(std::string arg, int minArgs = 0, bool needRoll = false) { int request(std::string arg, int minArgs = 0, bool needRoll = false) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
auto t = timeval{.tv_sec = 1, .tv_usec = 0}; auto t = timeval{.tv_sec = 5, .tv_usec = 0};
setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)); setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
const auto ARGS = std::count(arg.begin(), arg.end(), ' '); const auto ARGS = std::count(arg.begin(), arg.end(), ' ');

363
hyprpm/Makefile Normal file
View file

@ -0,0 +1,363 @@
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.29
# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:
#=============================================================================
# Special targets provided by cmake.
# Disable implicit rules so canonical targets will work.
.SUFFIXES:
# Disable VCS-based implicit rules.
% : %,v
# Disable VCS-based implicit rules.
% : RCS/%
# Disable VCS-based implicit rules.
% : RCS/%,v
# Disable VCS-based implicit rules.
% : SCCS/s.%
# Disable VCS-based implicit rules.
% : s.%
.SUFFIXES: .hpux_make_needs_suffix_list
# Command-line flag to silence nested $(MAKE).
$(VERBOSE)MAKESILENT = -s
#Suppress display of executed commands.
$(VERBOSE).SILENT:
# A target that is always out of date.
cmake_force:
.PHONY : cmake_force
#=============================================================================
# Set environment variables for the build.
# The shell in which to execute make rules.
SHELL = /bin/sh
# The CMake executable.
CMAKE_COMMAND = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake
# The command to remove a file.
RM = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E rm -f
# Escaping for special characters.
EQUALS = =
# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/mihai/Documents/code/git/Hyprland
# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/mihai/Documents/code/git/Hyprland
#=============================================================================
# Targets provided globally by CMake.
# Special rule for the target package
package: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool..."
cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackConfig.cmake
.PHONY : package
# Special rule for the target package
package/fast: package
.PHONY : package/fast
# Special rule for the target package_source
package_source:
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool for source..."
cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackSourceConfig.cmake /home/mihai/Documents/code/git/Hyprland/CPackSourceConfig.cmake
.PHONY : package_source
# Special rule for the target package_source
package_source/fast: package_source
.PHONY : package_source/fast
# Special rule for the target edit_cache
edit_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "No interactive CMake dialog available..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
.PHONY : edit_cache
# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast
# Special rule for the target rebuild_cache
rebuild_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache
# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast
# Special rule for the target list_install_components
list_install_components:
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Available install components are: \"Unspecified\""
.PHONY : list_install_components
# Special rule for the target list_install_components
list_install_components/fast: list_install_components
.PHONY : list_install_components/fast
# Special rule for the target install
install: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake
.PHONY : install
# Special rule for the target install
install/fast: preinstall/fast
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake
.PHONY : install/fast
# Special rule for the target install/local
install/local: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
.PHONY : install/local
# Special rule for the target install/local
install/local/fast: preinstall/fast
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
.PHONY : install/local/fast
# Special rule for the target install/strip
install/strip: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
.PHONY : install/strip
# Special rule for the target install/strip
install/strip/fast: preinstall/fast
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..."
/nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
.PHONY : install/strip/fast
# The main all target
all: cmake_check_build_system
cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles /home/mihai/Documents/code/git/Hyprland/hyprpm//CMakeFiles/progress.marks
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/all
$(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles 0
.PHONY : all
# The main clean target
clean:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/clean
.PHONY : clean
# The main clean target
clean/fast: clean
.PHONY : clean/fast
# Prepare targets for installation.
preinstall: all
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall
.PHONY : preinstall
# Prepare targets for installation.
preinstall/fast:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall
.PHONY : preinstall/fast
# clear depends
depend:
cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake
cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
.PHONY : depend
# Convenience name for target.
hyprpm/CMakeFiles/hyprpm.dir/rule:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/CMakeFiles/hyprpm.dir/rule
.PHONY : hyprpm/CMakeFiles/hyprpm.dir/rule
# Convenience name for target.
hyprpm: hyprpm/CMakeFiles/hyprpm.dir/rule
.PHONY : hyprpm
# fast build rule for target.
hyprpm/fast:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/build
.PHONY : hyprpm/fast
src/core/DataState.o: src/core/DataState.cpp.o
.PHONY : src/core/DataState.o
# target to build an object file
src/core/DataState.cpp.o:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.o
.PHONY : src/core/DataState.cpp.o
src/core/DataState.i: src/core/DataState.cpp.i
.PHONY : src/core/DataState.i
# target to preprocess a source file
src/core/DataState.cpp.i:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.i
.PHONY : src/core/DataState.cpp.i
src/core/DataState.s: src/core/DataState.cpp.s
.PHONY : src/core/DataState.s
# target to generate assembly for a file
src/core/DataState.cpp.s:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.s
.PHONY : src/core/DataState.cpp.s
src/core/Manifest.o: src/core/Manifest.cpp.o
.PHONY : src/core/Manifest.o
# target to build an object file
src/core/Manifest.cpp.o:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.o
.PHONY : src/core/Manifest.cpp.o
src/core/Manifest.i: src/core/Manifest.cpp.i
.PHONY : src/core/Manifest.i
# target to preprocess a source file
src/core/Manifest.cpp.i:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.i
.PHONY : src/core/Manifest.cpp.i
src/core/Manifest.s: src/core/Manifest.cpp.s
.PHONY : src/core/Manifest.s
# target to generate assembly for a file
src/core/Manifest.cpp.s:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.s
.PHONY : src/core/Manifest.cpp.s
src/core/PluginManager.o: src/core/PluginManager.cpp.o
.PHONY : src/core/PluginManager.o
# target to build an object file
src/core/PluginManager.cpp.o:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.o
.PHONY : src/core/PluginManager.cpp.o
src/core/PluginManager.i: src/core/PluginManager.cpp.i
.PHONY : src/core/PluginManager.i
# target to preprocess a source file
src/core/PluginManager.cpp.i:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.i
.PHONY : src/core/PluginManager.cpp.i
src/core/PluginManager.s: src/core/PluginManager.cpp.s
.PHONY : src/core/PluginManager.s
# target to generate assembly for a file
src/core/PluginManager.cpp.s:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.s
.PHONY : src/core/PluginManager.cpp.s
src/main.o: src/main.cpp.o
.PHONY : src/main.o
# target to build an object file
src/main.cpp.o:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.o
.PHONY : src/main.cpp.o
src/main.i: src/main.cpp.i
.PHONY : src/main.i
# target to preprocess a source file
src/main.cpp.i:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.i
.PHONY : src/main.cpp.i
src/main.s: src/main.cpp.s
.PHONY : src/main.s
# target to generate assembly for a file
src/main.cpp.s:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.s
.PHONY : src/main.cpp.s
src/progress/CProgressBar.o: src/progress/CProgressBar.cpp.o
.PHONY : src/progress/CProgressBar.o
# target to build an object file
src/progress/CProgressBar.cpp.o:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.o
.PHONY : src/progress/CProgressBar.cpp.o
src/progress/CProgressBar.i: src/progress/CProgressBar.cpp.i
.PHONY : src/progress/CProgressBar.i
# target to preprocess a source file
src/progress/CProgressBar.cpp.i:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.i
.PHONY : src/progress/CProgressBar.cpp.i
src/progress/CProgressBar.s: src/progress/CProgressBar.cpp.s
.PHONY : src/progress/CProgressBar.s
# target to generate assembly for a file
src/progress/CProgressBar.cpp.s:
cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.s
.PHONY : src/progress/CProgressBar.cpp.s
# Help Target
help:
@echo "The following are some of the valid targets for this Makefile:"
@echo "... all (the default if no target is provided)"
@echo "... clean"
@echo "... depend"
@echo "... edit_cache"
@echo "... install"
@echo "... install/local"
@echo "... install/strip"
@echo "... list_install_components"
@echo "... package"
@echo "... package_source"
@echo "... rebuild_cache"
@echo "... hyprpm"
@echo "... src/core/DataState.o"
@echo "... src/core/DataState.i"
@echo "... src/core/DataState.s"
@echo "... src/core/Manifest.o"
@echo "... src/core/Manifest.i"
@echo "... src/core/Manifest.s"
@echo "... src/core/PluginManager.o"
@echo "... src/core/PluginManager.i"
@echo "... src/core/PluginManager.s"
@echo "... src/main.o"
@echo "... src/main.i"
@echo "... src/main.s"
@echo "... src/progress/CProgressBar.o"
@echo "... src/progress/CProgressBar.i"
@echo "... src/progress/CProgressBar.s"
.PHONY : help
#=============================================================================
# Special targets to cleanup operation of make.
# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake
cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system

View file

@ -464,12 +464,22 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Checking out sources"; progress.m_szCurrentMessage = "Checking out sources";
progress.print(); progress.print();
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.branch + " 2>&1"); if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
if (ret.contains("fatal: unable to read tree")) {
std::cerr << "\n"
<< Colors::RED << "" << Colors::RESET
<< " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n";
return false;
}
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret);
ret = execAndGet("cd " + WORKINGDIR + " && git rm subprojects/tracy && git submodule update --init 2>&1 && git reset --hard --recurse-submodules " + HLVER.hash); ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret);
@ -529,7 +539,8 @@ bool CPluginManager::updateHeaders(bool force) {
std::cout << "\n"; std::cout << "\n";
} else { } else {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID)); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" +
headerErrorShort(HEADERSVALID) + ")");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
@ -880,6 +891,18 @@ std::string CPluginManager::headerError(const eHeadersErrors err) {
return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n"; return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
} }
std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {
switch (err) {
case HEADERS_CORRUPTED: return "Headers corrupted";
case HEADERS_MISMATCHED: return "Headers version mismatched";
case HEADERS_NOT_HYPRLAND: return "Not running on Hyprland";
case HEADERS_MISSING: return "Headers missing";
case HEADERS_DUPLICATED: return "Headers duplicated";
default: break;
}
return "?";
}
bool CPluginManager::hasDeps() { bool CPluginManager::hasDeps() {
std::vector<std::string> deps = {"meson", "cpio", "cmake"}; std::vector<std::string> deps = {"meson", "cpio", "cmake"};
for (auto& d : deps) { for (auto& d : deps) {

View file

@ -66,6 +66,7 @@ class CPluginManager {
private: private:
std::string headerError(const eHeadersErrors err); std::string headerError(const eHeadersErrors err);
std::string headerErrorShort(const eHeadersErrors err);
std::string m_szWorkingPluginDirectory = ""; std::string m_szWorkingPluginDirectory = "";
}; };

View file

@ -6,9 +6,10 @@ project('Hyprland', 'cpp', 'c',
'optimization=3', 'optimization=3',
'buildtype=release', 'buildtype=release',
'debug=false', 'debug=false',
'cpp_std=c++23', 'cpp_std=c++26',
]) ])
datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"'
add_project_arguments( add_project_arguments(
[ [
'-Wno-unused-parameter', '-Wno-unused-parameter',
@ -16,6 +17,7 @@ add_project_arguments(
'-Wno-missing-field-initializers', '-Wno-missing-field-initializers',
'-Wno-narrowing', '-Wno-narrowing',
'-Wno-pointer-arith', '-Wno-pointer-arith',
datarootdir,
], ],
language: 'cpp') language: 'cpp')
@ -32,6 +34,8 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland'))
xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) xcb_res_dep = dependency('xcb-res', required: get_option('xwayland'))
xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
gio_dep = dependency('gio-2.0', required:true)
cmake = import('cmake') cmake = import('cmake')
udis = cmake.subproject('udis86') udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86') udis86 = udis.dependency('libudis86')

View file

@ -71,6 +71,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
src = lib.cleanSource ../.; src = lib.cleanSource ../.;
}; };
patches = [
# forces GCC to use -std=c++26
./stdcxx.patch
];
postPatch = '' postPatch = ''
# Fix hardcoded paths to /usr installation # Fix hardcoded paths to /usr installation
sed -i "s#/usr#$out#" src/render/OpenGL.cpp sed -i "s#/usr#$out#" src/render/OpenGL.cpp

View file

@ -31,7 +31,7 @@ in {
date = mkDate (self.lastModifiedDate or "19700101"); date = mkDate (self.lastModifiedDate or "19700101");
in { in {
hyprland = final.callPackage ./default.nix { hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv; stdenv = final.gcc14Stdenv;
version = "${version}+date=${date}_${self.shortRev or "dirty"}"; version = "${version}+date=${date}_${self.shortRev or "dirty"}";
commit = self.rev or ""; commit = self.rev or "";
inherit date; inherit date;

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

@ -12,22 +12,12 @@ hyprland_protos = dependency('hyprland-protocols',
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir') hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
wayland_scanner_dep = dependency('wayland-scanner', native: true)
wayland_scanner = find_program(
wayland_scanner_dep.get_variable('wayland_scanner'),
native: true,
)
hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true)
hyprwayland_scanner = find_program( hyprwayland_scanner = find_program(
hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'),
native: true, native: true,
) )
protocols = [
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
]
new_protocols = [ new_protocols = [
['wlr-gamma-control-unstable-v1.xml'], ['wlr-gamma-control-unstable-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'],
@ -41,6 +31,7 @@ new_protocols = [
['wayland-drm.xml'], ['wayland-drm.xml'],
['wlr-data-control-unstable-v1.xml'], ['wlr-data-control-unstable-v1.xml'],
['wlr-screencopy-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
@ -55,6 +46,7 @@ new_protocols = [
[wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'],
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
[wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
[wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'],
@ -73,24 +65,6 @@ new_protocols = [
wl_protos_src = [] wl_protos_src = []
wl_protos_headers = [] wl_protos_headers = []
foreach p : protocols
xml = join_paths(p)
wl_protos_src += custom_target(
xml.underscorify() + '_server_c',
input: xml,
output: '@BASENAME@-protocol.c',
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
)
wl_protos_headers += custom_target(
xml.underscorify() + '_server_h',
input: xml,
install: true,
install_dir: join_paths(get_option('includedir'), 'hyprland/protocols'),
output: '@BASENAME@-protocol.h',
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
)
endforeach
new_wl_protos = [] new_wl_protos = []
foreach p : new_protocols foreach p : new_protocols
xml = join_paths(p) xml = join_paths(p)

View file

@ -7,6 +7,7 @@
#include "managers/SeatManager.hpp" #include "managers/SeatManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp"
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
#include <bit>
#include <random> #include <random>
#include <cstring> #include <cstring>
#include <filesystem> #include <filesystem>
@ -247,7 +248,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
if (!m_pAqBackend) { if (!m_pAqBackend) {
Debug::log(CRIT, Debug::log(CRIT,
"m_pAqBackend was null! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a Wayland " "m_pAqBackend was null! This usually means aquamarine could not find a GPU or encountered some issues. Make sure you're running either on a tty or on a Wayland "
"session, NOT an X11 one."); "session, NOT an X11 one.");
throwError("CBackend::create() failed!"); throwError("CBackend::create() failed!");
} }
@ -258,7 +259,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
if (!m_pAqBackend->start()) { if (!m_pAqBackend->start()) {
Debug::log(CRIT, Debug::log(CRIT,
"m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a " "m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or encountered some issues. Make sure you're running either on a tty or on a "
"Wayland session, NOT an X11 one."); "Wayland session, NOT an X11 one.");
throwError("CBackend::create() failed!"); throwError("CBackend::create() failed!");
} }
@ -518,6 +519,8 @@ void CCompositor::cleanup() {
// this frees all wayland resources, including sockets // this frees all wayland resources, including sockets
wl_display_destroy(m_sWLDisplay); wl_display_destroy(m_sWLDisplay);
Debug::close();
} }
void CCompositor::initManagers(eManagersInitStage stage) { void CCompositor::initManagers(eManagersInitStage stage) {
@ -549,6 +552,10 @@ void CCompositor::initManagers(eManagersInitStage stage) {
g_pConfigManager->init(); g_pConfigManager->init();
g_pWatchdog = std::make_unique<CWatchdog>(); // requires config g_pWatchdog = std::make_unique<CWatchdog>(); // requires config
// wait for watchdog to initialize to not hit data races in reading config values.
while (!g_pWatchdog->m_bWatchdogInitialized) {
std::this_thread::yield();
}
Debug::log(LOG, "Creating the PointerManager!"); Debug::log(LOG, "Creating the PointerManager!");
g_pPointerManager = std::make_unique<CPointerManager>(); g_pPointerManager = std::make_unique<CPointerManager>();
@ -680,9 +687,9 @@ void CCompositor::startCompositor() {
g_pEventLoopManager->enterLoop(); g_pEventLoopManager->enterLoop();
} }
CMonitor* CCompositor::getMonitorFromID(const int& id) { CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
if (m->ID == (uint64_t)id) { if (m->ID == id) {
return m.get(); return m.get();
} }
} }
@ -774,7 +781,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (properties & ALLOW_FLOATING) { if (properties & ALLOW_FLOATING) {
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowBoxUnified(properties); const auto BB = w->getWindowBoxUnified(properties);
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0);
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow) { w != pIgnoreWindow) {
if (box.containsPoint(g_pPointerManager->position())) if (box.containsPoint(g_pPointerManager->position()))
@ -804,7 +811,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y)
continue; continue;
CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0);
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent // OR windows should add focus to parent
@ -842,8 +849,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (properties & FLOATING_ONLY) if (properties & FLOATING_ONLY)
return floating(false); return floating(false);
const int64_t WORKSPACEID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID(); const WORKSPACEID WSPID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID();
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID); const auto PWORKSPACE = getWorkspaceByID(WSPID);
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
@ -857,7 +864,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (special != w->onSpecialWorkspace()) if (special != w->onSpecialWorkspace())
continue; continue;
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) {
if (w->hasPopupAt(pos)) if (w->hasPopupAt(pos))
return w; return w;
@ -869,7 +876,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
continue; continue;
CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow)
return w; return w;
} }
@ -1204,9 +1211,9 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) {
return nullptr; return nullptr;
} }
PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->workspaceID() == ID && w->m_bIsFullscreen) if (w->workspaceID() == ID && w->isFullscreen())
return w; return w;
} }
@ -1228,7 +1235,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) {
return PMONITOR->activeWorkspace->m_iID == w->m_iID; return PMONITOR->activeWorkspace->m_iID == w->m_iID;
} }
PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) { PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) {
for (auto& w : m_vWorkspaces) { for (auto& w : m_vWorkspaces) {
if (w->m_iID == id && !w->inert()) if (w->m_iID == id && !w->inert())
return w; return w;
@ -1252,7 +1259,7 @@ void CCompositor::sanityCheckWorkspaces() {
} }
} }
int CCompositor::getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) { int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->workspaceID() != id || !w->m_bIsMapped) if (w->workspaceID() != id || !w->m_bIsMapped)
@ -1267,7 +1274,7 @@ int CCompositor::getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTi
return no; return no;
} }
int CCompositor::getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) { int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->workspaceID() != id || !w->m_bIsMapped) if (w->workspaceID() != id || !w->m_bIsMapped)
@ -1292,7 +1299,7 @@ PHLWINDOW CCompositor::getUrgentWindow() {
return nullptr; return nullptr;
} }
bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) { bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent) if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent)
return true; return true;
@ -1301,7 +1308,7 @@ bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) {
return false; return false;
} }
PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) { PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden()) if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden())
return w; return w;
@ -1310,7 +1317,7 @@ PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) {
return nullptr; return nullptr;
} }
PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const int& id) { PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) {
const auto PWORKSPACE = getWorkspaceByID(id); const auto PWORKSPACE = getWorkspaceByID(id);
if (!PWORKSPACE) if (!PWORKSPACE)
@ -1398,12 +1405,12 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
} }
} }
void CCompositor::cleanupFadingOut(const int& monid) { void CCompositor::cleanupFadingOut(const MONITORID& monid) {
for (auto& ww : m_vWindowsFadingOut) { for (auto& ww : m_vWindowsFadingOut) {
auto w = ww.lock(); auto w = ww.lock();
if (w->m_iMonitorID != (long unsigned int)monid) if (w->m_iMonitorID != monid)
continue; continue;
if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) { if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) {
@ -1422,12 +1429,16 @@ void CCompositor::cleanupFadingOut(const int& monid) {
} }
} }
bool layersDirty = false;
for (auto& lsr : m_vSurfacesFadingOut) { for (auto& lsr : m_vSurfacesFadingOut) {
auto ls = lsr.lock(); auto ls = lsr.lock();
if (!ls) if (!ls) {
layersDirty = true;
continue; continue;
}
if (ls->monitorID != monid) if (ls->monitorID != monid)
continue; continue;
@ -1440,7 +1451,7 @@ void CCompositor::cleanupFadingOut(const int& monid) {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLayers) { for (auto& lsl : m->m_aLayerSurfaceLayers) {
if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) {
std::erase_if(lsl, [&](auto& other) { return other == ls; }); std::erase_if(lsl, [&](auto& other) { return other == ls || !other; });
} }
} }
} }
@ -1456,6 +1467,9 @@ void CCompositor::cleanupFadingOut(const int& monid) {
return; return;
} }
} }
if (layersDirty)
std::erase_if(m_vSurfacesFadingOut, [](const auto& el) { return el.expired(); });
} }
void CCompositor::addToFadingOutSafe(PHLLS pLS) { void CCompositor::addToFadingOutSafe(PHLLS pLS) {
@ -1494,7 +1508,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
if (!PMONITOR) if (!PMONITOR)
return nullptr; // ?? return nullptr; // ??
const auto WINDOWIDEALBB = pWindow->m_bIsFullscreen ? CBox{PMONITOR->vecPosition, PMONITOR->vecSize} : pWindow->getWindowIdealBoundingBoxIgnoreReserved(); const auto WINDOWIDEALBB = pWindow->isFullscreen() ? CBox{PMONITOR->vecPosition, PMONITOR->vecSize} : pWindow->getWindowIdealBoundingBoxIgnoreReserved();
const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y); const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
@ -1507,13 +1521,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
// for tiled windows, we calc edges // for tiled windows, we calc edges
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->m_bIsFullscreen && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace)
continue; continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen)
continue; continue;
if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID)
@ -1599,13 +1613,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
constexpr float THRESHOLD = 0.3 * M_PI; constexpr float THRESHOLD = 0.3 * M_PI;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->m_bIsFullscreen && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace)
continue; continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen)
continue; continue;
if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID)
@ -1692,8 +1706,8 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
return nullptr; return nullptr;
} }
int CCompositor::getNextAvailableNamedWorkspace() { WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() {
int lowest = -1337 + 1; WORKSPACEID lowest = -1337 + 1;
for (auto& w : m_vWorkspaces) { for (auto& w : m_vWorkspaces) {
if (w->m_iID < -1 && w->m_iID < lowest) if (w->m_iID < -1 && w->m_iID < lowest)
lowest = w->m_iID; lowest = w->m_iID;
@ -1887,7 +1901,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
// opacity // opacity
const auto PWORKSPACE = pWindow->m_pWorkspace; const auto PWORKSPACE = pWindow->m_pWorkspace;
if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { if (pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) {
pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA);
} else { } else {
if (pWindow == m_pLastWindow) if (pWindow == m_pLastWindow)
@ -1917,18 +1931,18 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
pWindow->updateWindowDecos(); pWindow->updateWindowDecos();
} }
int CCompositor::getNextAvailableMonitorID(std::string const& name) { MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) {
// reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor // reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor
if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; }))
return m_mMonitorIDMap[name]; return m_mMonitorIDMap[name];
// otherwise, find minimum available ID that is not in the map // otherwise, find minimum available ID that is not in the map
std::unordered_set<uint64_t> usedIDs; std::unordered_set<MONITORID> usedIDs;
for (auto const& monitor : m_vRealMonitors) { for (auto const& monitor : m_vRealMonitors) {
usedIDs.insert(monitor->ID); usedIDs.insert(monitor->ID);
} }
uint64_t nextID = 0; MONITORID nextID = 0;
while (usedIDs.count(nextID) > 0) { while (usedIDs.count(nextID) > 0) {
nextID++; nextID++;
} }
@ -1957,7 +1971,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
if (w->m_bIsFloating) if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorA->vecPosition + pMonitorB->vecPosition; w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorA->vecPosition + pMonitorB->vecPosition;
if (w->m_bIsFullscreen) { if (w->isFullscreen()) {
w->m_vRealPosition = pMonitorB->vecPosition; w->m_vRealPosition = pMonitorB->vecPosition;
w->m_vRealSize = pMonitorB->vecSize; w->m_vRealSize = pMonitorB->vecSize;
} }
@ -1982,7 +1996,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
if (w->m_bIsFloating) if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorB->vecPosition + pMonitorA->vecPosition; w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorB->vecPosition + pMonitorA->vecPosition;
if (w->m_bIsFullscreen) { if (w->isFullscreen()) {
w->m_vRealPosition = pMonitorA->vecPosition; w->m_vRealPosition = pMonitorA->vecPosition;
w->m_vRealSize = pMonitorA->vecSize; w->m_vRealSize = pMonitorA->vecSize;
} }
@ -2068,7 +2082,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
return m_vMonitors[currentPlace].get(); return m_vMonitors[currentPlace].get();
} else if (isNumber(name)) { } else if (isNumber(name)) {
// change by ID // change by ID
int monID = -1; MONITORID monID = MONITOR_INVALID;
try { try {
monID = std::stoi(name); monID = std::stoi(name);
} catch (std::exception& e) { } catch (std::exception& e) {
@ -2077,7 +2091,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
return nullptr; return nullptr;
} }
if (monID > -1 && monID < (int)m_vMonitors.size()) { if (monID > -1 && monID < (MONITORID)m_vMonitors.size()) {
return getMonitorFromID(monID); return getMonitorFromID(monID);
} else { } else {
Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1"); Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1");
@ -2111,7 +2125,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false; const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false;
// fix old mon // fix old mon
int nextWorkspaceOnMonitorID = -1; WORKSPACEID nextWorkspaceOnMonitorID = WORKSPACE_INVALID;
if (!SWITCHINGISACTIVE) if (!SWITCHINGISACTIVE)
nextWorkspaceOnMonitorID = pWorkspace->m_iID; nextWorkspaceOnMonitorID = pWorkspace->m_iID;
else { else {
@ -2122,7 +2136,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
} }
} }
if (nextWorkspaceOnMonitorID == -1) { if (nextWorkspaceOnMonitorID == WORKSPACE_INVALID) {
nextWorkspaceOnMonitorID = 1; nextWorkspaceOnMonitorID = 1;
while (getWorkspaceByID(nextWorkspaceOnMonitorID) || [&]() -> bool { while (getWorkspaceByID(nextWorkspaceOnMonitorID) || [&]() -> bool {
@ -2159,7 +2173,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
if (w->m_bIsFloating) if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.goal() - POLDMON->vecPosition + pMonitor->vecPosition; w->m_vRealPosition = w->m_vRealPosition.goal() - POLDMON->vecPosition + pMonitor->vecPosition;
if (w->m_bIsFullscreen) { if (w->isFullscreen()) {
w->m_vRealPosition = pMonitor->vecPosition; w->m_vRealPosition = pMonitor->vecPosition;
w->m_vRealSize = pMonitor->vecSize; w->m_vRealSize = pMonitor->vecSize;
} }
@ -2209,9 +2223,9 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{pWorkspace, pMonitor})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{pWorkspace, pMonitor}));
} }
bool CCompositor::workspaceIDOutOfBounds(const int64_t& id) { bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) {
int64_t lowestID = INT64_MAX; WORKSPACEID lowestID = INT64_MAX;
int64_t highestID = INT64_MIN; WORKSPACEID highestID = INT64_MIN;
for (auto& w : m_vWorkspaces) { for (auto& w : m_vWorkspaces) {
if (w->m_bIsSpecialWorkspace) if (w->m_bIsSpecialWorkspace)
@ -2234,12 +2248,12 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == pWorkspace) { if (w->m_pWorkspace == pWorkspace) {
if (w->m_bFadingOut || w->m_bPinned || w->m_bIsFullscreen) if (w->m_bFadingOut || w->m_bPinned || w->isFullscreen())
continue; continue;
if (!FULLSCREEN) if (!FULLSCREEN)
w->m_fAlpha = 1.f; w->m_fAlpha = 1.f;
else if (!w->m_bIsFullscreen) else if (!w->isFullscreen())
w->m_fAlpha = !w->m_bCreatedOverFullscreen ? 0.f : 1.f; w->m_fAlpha = !w->m_bCreatedOverFullscreen ? 0.f : 1.f;
} }
} }
@ -2249,54 +2263,87 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) {
if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) {
for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
if (!ls->fadingOut) if (!ls->fadingOut)
ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f; ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f;
} }
} }
} }
void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMode mode) { void CCompositor::changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON) {
static auto PNODIRECTSCANOUT = CConfigValue<Hyprlang::INT>("misc:no_direct_scanout"); setWindowFullscreenInternal(
PWINDOW, (eFullscreenMode)(ON ? (uint8_t)PWINDOW->m_sFullscreenState.internal | (uint8_t)MODE : ((uint8_t)PWINDOW->m_sFullscreenState.internal & (uint8_t)~MODE)));
}
if (!validMapped(pWindow) || g_pCompositor->m_bUnsafeState) void CCompositor::changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON) {
setWindowFullscreenClient(PWINDOW,
(eFullscreenMode)(ON ? (uint8_t)PWINDOW->m_sFullscreenState.client | (uint8_t)MODE : ((uint8_t)PWINDOW->m_sFullscreenState.client & (uint8_t)~MODE)));
}
void CCompositor::setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE) {
if (PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = MODE});
else
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = PWINDOW->m_sFullscreenState.client});
}
void CCompositor::setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE) {
if (PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = MODE});
else
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = MODE});
}
void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenState state) {
static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
if (!validMapped(PWINDOW) || g_pCompositor->m_bUnsafeState)
return; return;
if (pWindow->m_bPinned) { state.internal = std::clamp(state.internal, (eFullscreenMode)0, FSMODE_MAX);
Debug::log(LOG, "Pinned windows cannot be fullscreen'd"); state.client = std::clamp(state.client, (eFullscreenMode)0, FSMODE_MAX);
const auto PMONITOR = getMonitorFromID(PWINDOW->m_iMonitorID);
const auto PWORKSPACE = PWINDOW->m_pWorkspace;
const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal);
const eFullscreenMode EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)state.internal);
const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE || (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen()));
// TODO: update the state on syncFullscreen changes
if (!CHANGEINTERNAL && PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
return; return;
}
if (pWindow->m_bIsFullscreen == on) { PWINDOW->m_sFullscreenState.client = state.client;
Debug::log(LOG, "Window is already in the required fullscreen state"); g_pXWaylandManager->setWindowFullscreen(PWINDOW, state.client & FSMODE_FULLSCREEN);
if (!CHANGEINTERNAL)
return; return;
}
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, CURRENT_EFFECTIVE_MODE, EFFECTIVE_MODE);
const auto PWORKSPACE = pWindow->m_pWorkspace; PWINDOW->m_sFullscreenState.internal = state.internal;
PWORKSPACE->m_efFullscreenMode = EFFECTIVE_MODE;
PWORKSPACE->m_bHasFullscreenWindow = EFFECTIVE_MODE != FSMODE_NONE;
const auto MODE = mode == FULLSCREEN_INVALID ? PWORKSPACE->m_efFullscreenMode : mode; g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)});
EMIT_HOOK_EVENT("fullscreen", PWINDOW);
if (PWORKSPACE->m_bHasFullscreenWindow && on) { PWINDOW->updateDynamicRules();
Debug::log(LOG, "Rejecting fullscreen ON on a fullscreen workspace"); PWINDOW->updateWindowDecos();
return; updateWindowAnimatedDecorationValues(PWINDOW);
} g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, MODE, on);
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState());
updateWindowAnimatedDecorationValues(pWindow);
// make all windows on the same workspace under the fullscreen window // make all windows on the same workspace under the fullscreen window
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_pWorkspace == PWORKSPACE && !w->m_bIsFullscreen && !w->m_bFadingOut && !w->m_bPinned) if (w->m_pWorkspace == PWORKSPACE && !w->isFullscreen() && !w->m_bFadingOut && !w->m_bPinned)
w->m_bCreatedOverFullscreen = false; w->m_bCreatedOverFullscreen = false;
} }
updateFullscreenFadeOnWorkspace(PWORKSPACE); updateFullscreenFadeOnWorkspace(PWORKSPACE);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal(), true); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
forceReportSizesToWindowsOnWorkspace(pWindow->workspaceID()); forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID());
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
@ -2306,8 +2353,8 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod
// send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't.
// ignore if DS is disabled. // ignore if DS is disabled.
if (!*PNODIRECTSCANOUT) if (*PDIRECTSCANOUT)
g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr); g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr);
g_pConfigManager->ensureVRR(PMONITOR); g_pConfigManager->ensureVRR(PMONITOR);
} }
@ -2327,7 +2374,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) {
return nullptr; return nullptr;
} }
void CCompositor::updateWorkspaceWindowDecos(const int& id) { void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->workspaceID() != id) if (w->workspaceID() != id)
continue; continue;
@ -2336,7 +2383,7 @@ void CCompositor::updateWorkspaceWindowDecos(const int& id) {
} }
} }
void CCompositor::updateWorkspaceWindowData(const int& id) { void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) {
const auto PWORKSPACE = getWorkspaceByID(id); const auto PWORKSPACE = getWorkspaceByID(id);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
@ -2556,7 +2603,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
return Vector2D(X, Y); return Vector2D(X, Y);
} }
void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) { if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) {
g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
@ -2564,7 +2611,7 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
} }
} }
PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name, bool isEmtpy) { PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmtpy) {
const auto NAME = name == "" ? std::to_string(id) : name; const auto NAME = name == "" ? std::to_string(id) : name;
auto monID = monid; auto monID = monid;
@ -2582,7 +2629,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, co
return PWORKSPACE; return PWORKSPACE;
} }
void CCompositor::renameWorkspace(const int& id, const std::string& name) { void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name) {
const auto PWORKSPACE = getWorkspaceByID(id); const auto PWORKSPACE = getWorkspaceByID(id);
if (!PWORKSPACE) if (!PWORKSPACE)
@ -2613,12 +2660,12 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
m_pLastMonitor = pMonitor->self; m_pLastMonitor = pMonitor->self;
} }
bool CCompositor::isWorkspaceSpecial(const int& id) { bool CCompositor::isWorkspaceSpecial(const WORKSPACEID& id) {
return id >= SPECIAL_WORKSPACE_START && id <= -2; return id >= SPECIAL_WORKSPACE_START && id <= -2;
} }
int CCompositor::getNewSpecialID() { WORKSPACEID CCompositor::getNewSpecialID() {
int highest = SPECIAL_WORKSPACE_START; WORKSPACEID highest = SPECIAL_WORKSPACE_START;
for (auto& ws : m_vWorkspaces) { for (auto& ws : m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) { if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) {
highest = ws->m_iID; highest = ws->m_iID;
@ -2639,11 +2686,11 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor
if (pWindow->m_bPinned && pWorkspace->m_bIsSpecialWorkspace) if (pWindow->m_bPinned && pWorkspace->m_bIsSpecialWorkspace)
return; return;
const bool FULLSCREEN = pWindow->m_bIsFullscreen; const bool FULLSCREEN = pWindow->isFullscreen();
const auto FULLSCREENMODE = pWindow->m_pWorkspace->m_efFullscreenMode; const auto FULLSCREENMODE = pWindow->m_sFullscreenState.internal;
if (FULLSCREEN) if (FULLSCREEN)
setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); setWindowFullscreenInternal(pWindow, FSMODE_NONE);
if (!pWindow->m_bIsFloating) { if (!pWindow->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow);
@ -2676,7 +2723,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor
} }
if (FULLSCREEN) if (FULLSCREEN)
setWindowFullscreen(pWindow, true, FULLSCREENMODE); setWindowFullscreenInternal(pWindow, FULLSCREENMODE);
g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID); g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID);
g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID()); g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID());
@ -2875,39 +2922,6 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
return {}; return {};
} }
static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static auto firstMonitorAdded = std::chrono::system_clock::now();
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
const auto POS = PNEWMONITOR->middle();
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if (firstLaunch) {
firstLaunch = false;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY)
return;
// after 10s, don't set cursor to default monitor
auto timePassedSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - firstMonitorAdded);
if (timePassedSec.count() > 10) {
cursorDefaultDone = true;
return;
}
if (*PCURSORMONITOR == monitorName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) { void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
// add it to real // add it to real
auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>()); auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>());
@ -2922,7 +2936,7 @@ void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
PNEWMONITOR->output = output; PNEWMONITOR->output = output;
PNEWMONITOR->self = PNEWMONITOR; PNEWMONITOR->self = PNEWMONITOR;
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false; const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false;
PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(output->name); PNEWMONITOR->ID = FALLBACK ? MONITOR_INVALID : g_pCompositor->getNextAvailableMonitorID(output->name);
PNEWMONITOR->isUnsafeFallback = FALLBACK; PNEWMONITOR->isUnsafeFallback = FALLBACK;
EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR);
@ -2943,11 +2957,9 @@ void CCompositor::onNewMonitor(SP<Aquamarine::IOutput> output) {
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR);
checkDefaultCursorWarp(PNEWMONITOR, output->name);
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) { if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = -1; w->m_iLastSurfaceMonitorID = MONITOR_INVALID;
w->updateSurfaceScaleTransformDetails(); w->updateSurfaceScaleTransformDetails();
} }
} }

View file

@ -46,55 +46,55 @@ class CCompositor {
CCompositor(); CCompositor();
~CCompositor(); ~CCompositor();
wl_display* m_sWLDisplay; wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop; wl_event_loop* m_sWLEventLoop;
int m_iDRMFD = -1; int m_iDRMFD = -1;
bool m_bInitialized = false; bool m_bInitialized = false;
SP<Aquamarine::CBackend> m_pAqBackend; SP<Aquamarine::CBackend> m_pAqBackend;
std::string m_szHyprTempDataRoot = ""; std::string m_szHyprTempDataRoot = "";
std::string m_szWLDisplaySocket = ""; std::string m_szWLDisplaySocket = "";
std::string m_szInstanceSignature = ""; std::string m_szInstanceSignature = "";
std::string m_szInstancePath = ""; std::string m_szInstancePath = "";
std::string m_szCurrentSplash = "error"; std::string m_szCurrentSplash = "error";
std::vector<SP<CMonitor>> m_vMonitors; std::vector<SP<CMonitor>> m_vMonitors;
std::vector<SP<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off std::vector<SP<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
std::vector<PHLWINDOW> m_vWindows; std::vector<PHLWINDOW> m_vWindows;
std::vector<PHLLS> m_vLayers; std::vector<PHLLS> m_vLayers;
std::vector<PHLWORKSPACE> m_vWorkspaces; std::vector<PHLWORKSPACE> m_vWorkspaces;
std::vector<PHLWINDOWREF> m_vWindowsFadingOut; std::vector<PHLWINDOWREF> m_vWindowsFadingOut;
std::vector<PHLLSREF> m_vSurfacesFadingOut; std::vector<PHLLSREF> m_vSurfacesFadingOut;
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap; std::unordered_map<std::string, MONITORID> m_mMonitorIDMap;
void initServer(std::string socketName, int socketFd); void initServer(std::string socketName, int socketFd);
void startCompositor(); void startCompositor();
void stopCompositor(); void stopCompositor();
void cleanup(); void cleanup();
void createLockFile(); void createLockFile();
void removeLockFile(); void removeLockFile();
void bumpNofile(); void bumpNofile();
void restoreNofile(); void restoreNofile();
WP<CWLSurfaceResource> m_pLastFocus; WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_pLastWindow; PHLWINDOWREF m_pLastWindow;
WP<CMonitor> m_pLastMonitor; WP<CMonitor> m_pLastMonitor;
std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused. std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused.
bool m_bReadyToProcess = false; bool m_bReadyToProcess = false;
bool m_bSessionActive = true; bool m_bSessionActive = true;
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; bool m_bNextIsUnsafe = false;
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
// ------------------------------------------------- // // ------------------------------------------------- //
CMonitor* getMonitorFromID(const int&); CMonitor* getMonitorFromID(const MONITORID&);
CMonitor* getMonitorFromName(const std::string&); CMonitor* getMonitorFromName(const std::string&);
CMonitor* getMonitorFromDesc(const std::string&); CMonitor* getMonitorFromDesc(const std::string&);
CMonitor* getMonitorFromCursor(); CMonitor* getMonitorFromCursor();
@ -114,39 +114,43 @@ class CCompositor {
PHLWINDOW getWindowFromHandle(uint32_t); PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE); bool isWorkspaceVisible(PHLWORKSPACE);
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE); bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const int&); PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&);
PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces(); void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&); void updateWorkspaceWindowDecos(const WORKSPACEID&);
void updateWorkspaceWindowData(const int&); void updateWorkspaceWindowData(const WORKSPACEID&);
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow(); PHLWINDOW getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const int&); bool hasUrgentWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFirstWindowOnWorkspace(const int&); PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getTopLeftWindowOnWorkspace(const int&); PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFullscreenWindowOnWorkspace(const int&); PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&);
bool isWindowActive(PHLWINDOW); bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool); void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const int& monid); void cleanupFadingOut(const MONITORID& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
int getNextAvailableNamedWorkspace(); WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
CMonitor* getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(CMonitor*, const char&); CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues(); void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const int64_t& id); void updateWorkspaceWindows(const WORKSPACEID& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW); void updateWindowAnimatedDecorationValues(PHLWINDOW);
int getNextAvailableMonitorID(std::string const& name); MONITORID getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*); void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&); CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&); bool workspaceIDOutOfBounds(const WORKSPACEID&);
void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state);
void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW); PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
@ -158,12 +162,13 @@ class CCompositor {
PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>); PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>);
void closeWindow(PHLWINDOW); void closeWindow(PHLWINDOW);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&); void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&);
PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
void renameWorkspace(const int&, const std::string& name = ""); bool isEmtpy = true); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
void setActiveMonitor(CMonitor*); void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const int&); bool isWorkspaceSpecial(const WORKSPACEID&);
int getNewSpecialID(); WORKSPACEID getNewSpecialID();
void performUserChecks(); void performUserChecks();
void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
PHLWINDOW getForceFocus(); PHLWINDOW getForceFocus();

View file

@ -52,4 +52,8 @@ struct SHyprCtlCommand {
std::function<std::string(eHyprCtlOutputFormat, std::string)> fn; std::function<std::string(eHyprCtlOutputFormat, std::string)> fn;
}; };
typedef int64_t WINDOWID;
typedef int64_t MONITORID;
typedef int64_t WORKSPACEID;
typedef std::function<void(void*, SCallbackInfo&, std::any)> HOOK_CALLBACK_FN; typedef std::function<void(void*, SCallbackInfo&, std::any)> HOOK_CALLBACK_FN;

View file

@ -3,6 +3,7 @@
#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "config/ConfigDataValues.hpp" #include "config/ConfigDataValues.hpp"
#include "config/ConfigValue.hpp"
#include "helpers/varlist/VarList.hpp" #include "helpers/varlist/VarList.hpp"
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
@ -346,7 +347,6 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY});
m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY});
m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:no_direct_scanout", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1});
@ -533,7 +533,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24});
m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:inactive_timeout", {0.f});
m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0});
@ -541,6 +541,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); m_pConfig->addConfigValue("cursor:zoom_factor", {1.f});
m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1});
m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1});
m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1});
m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0});
@ -562,7 +563,9 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"});
m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"});
m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0}); m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2});
m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2});
m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0});
// devices // devices
m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialCategory("device", {"name"});
@ -644,7 +647,7 @@ std::optional<std::string> CConfigManager::generateConfig(std::string configPath
Debug::log(WARN, "Creating config home directory"); Debug::log(WARN, "Creating config home directory");
try { try {
std::filesystem::create_directories(parentPath); std::filesystem::create_directories(parentPath);
} catch (std::exception e) { throw e; } } catch (std::exception& e) { throw e; }
} }
Debug::log(WARN, "No config file found; attempting to generate."); Debug::log(WARN, "No config file found; attempting to generate.");
@ -800,6 +803,9 @@ std::optional<std::string> CConfigManager::resetHLConfig() {
} }
void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
static int prevEnabledExplicit = *PENABLEEXPLICIT;
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
w->uncacheWindowDecos(); w->uncacheWindowDecos();
} }
@ -830,6 +836,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1) else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1)
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", 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)); 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 else
g_pHyprError->destroy(); g_pHyprError->destroy();
@ -918,7 +926,10 @@ void CConfigManager::init() {
} }
std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE) { std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE) {
const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str()); static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
static int prevEnabledExplicit = *PENABLEEXPLICIT;
const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str());
// invalidate layouts if they changed // invalidate layouts if they changed
if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) { if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) {
@ -926,6 +937,13 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
} }
if (COMMAND.contains("explicit")) {
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
g_pHyprError->destroy();
}
// Update window border colors // Update window border colors
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@ -1102,7 +1120,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
// since some rules will be applied later, we need to store some flags // since some rules will be applied later, we need to store some flags
bool hasFloating = pWindow->m_bIsFloating; bool hasFloating = pWindow->m_bIsFloating;
bool hasFullscreen = pWindow->m_bIsFullscreen; bool hasFullscreen = pWindow->isFullscreen();
// local tags for dynamic tag rule match // local tags for dynamic tag rule match
auto tags = pWindow->m_tags; auto tags = pWindow->m_tags;
@ -1419,7 +1437,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
if (USEVRR == 0) { if (USEVRR == 0) {
if (m->vrrActive) { if (m->vrrActive) {
m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(false); m->output->state->setAdaptiveSync(false);
if (!m->state.commit()) if (!m->state.commit())
@ -1429,6 +1447,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
return; return;
} else if (USEVRR == 1) { } else if (USEVRR == 1) {
if (!m->vrrActive) { if (!m->vrrActive) {
m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(true); m->output->state->setAdaptiveSync(true);
if (!m->state.test()) { if (!m->state.test()) {
@ -1450,9 +1469,10 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
if (!PWORKSPACE) if (!PWORKSPACE)
return; // ??? return; // ???
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN);
if (WORKSPACEFULL) { if (WORKSPACEFULL) {
m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(true); m->output->state->setAdaptiveSync(true);
if (!m->state.test()) { if (!m->state.test()) {
@ -1464,6 +1484,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL) { } else if (!WORKSPACEFULL) {
m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(false); m->output->state->setAdaptiveSync(false);
if (!m->state.commit()) if (!m->state.commit())
@ -2101,11 +2122,11 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
bool windowRuleValid(const std::string& RULE) { bool windowRuleValid(const std::string& RULE) {
static const auto rules = std::unordered_set<std::string>{ static const auto rules = std::unordered_set<std::string>{
"fakefullscreen", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile",
}; };
static const auto rulesPrefix = std::vector<std::string>{ static const auto rulesPrefix = std::vector<std::string>{
"animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor",
"opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray", "move", "opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray",
}; };
const auto VALS = CVarList(RULE, 2, ' '); const auto VALS = CVarList(RULE, 2, ' ');
@ -2416,7 +2437,7 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
// } // }
const static std::string ruleOnCreatedEmpty = "on-created-empty:"; const static std::string ruleOnCreatedEmpty = "on-created-empty:";
const static int ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length(); const static auto ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length();
auto assignRule = [&](std::string rule) -> std::optional<std::string> { auto assignRule = [&](std::string rule) -> std::optional<std::string> {
size_t delim = std::string::npos; size_t delim = std::string::npos;

View file

@ -33,7 +33,7 @@ struct SWorkspaceRule {
std::string monitor = ""; std::string monitor = "";
std::string workspaceString = ""; std::string workspaceString = "";
std::string workspaceName = ""; std::string workspaceName = "";
int workspaceId = -1; WORKSPACEID workspaceId = -1;
bool isDefault = false; bool isDefault = false;
bool isPersistent = false; bool isPersistent = false;
std::optional<CCssGapData> gapsIn; std::optional<CCssGapData> gapsIn;
@ -182,6 +182,7 @@ class CConfigManager {
{"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }}, {"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }}, {"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }}, {"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }}, {"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }}, {"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
}; };

View file

@ -32,6 +32,7 @@ using namespace Hyprutils::String;
#include "../devices/IKeyboard.hpp" #include "../devices/IKeyboard.hpp"
#include "../devices/ITouch.hpp" #include "../devices/ITouch.hpp"
#include "../devices/Tablet.hpp" #include "../devices/Tablet.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "debug/RollingLogFollow.hpp" #include "debug/RollingLogFollow.hpp"
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "helpers/MiscFunctions.hpp" #include "helpers/MiscFunctions.hpp"
@ -70,7 +71,7 @@ static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFor
std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) { std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
std::string result; std::string result;
if (!m->output || m->ID == -1ull) if (!m->output || m->ID == -1)
return ""; return "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@ -154,7 +155,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
result += "]"; result += "]";
} else { } else {
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
if (!m->output || m->ID == -1ull) if (!m->output || m->ID == -1)
continue; continue;
result += result +=
@ -239,8 +240,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"xwayland": {}, "xwayland": {},
"pinned": {}, "pinned": {},
"fullscreen": {}, "fullscreen": {},
"fullscreenMode": {}, "fullscreenClient": {},
"fakeFullscreen": {},
"grouped": [{}], "grouped": [{}],
"tags": [{}], "tags": [{}],
"swallowing": "0x{:x}", "swallowing": "0x{:x}",
@ -251,19 +251,19 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"),
(int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), (int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass),
escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
(w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} else { } else {
return std::format( return std::format(
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " "Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: " "{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName),
(int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(),
(int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(int)w->m_bFakeFullscreenState, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} }
} }
@ -776,7 +776,7 @@ std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request)
std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) { std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts(); const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts();
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& sh : SHORTCUTS) for (auto& sh : SHORTCUTS)
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
@ -1604,6 +1604,10 @@ CHyprCtl::CHyprCtl() {
CHyprCtl::~CHyprCtl() { CHyprCtl::~CHyprCtl() {
if (m_eventSource) if (m_eventSource)
wl_event_source_remove(m_eventSource); wl_event_source_remove(m_eventSource);
if (m_iSocketFD >= 0)
close(m_iSocketFD);
if (!m_socketPath.empty())
unlink(m_socketPath.c_str());
} }
SP<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) { SP<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
@ -1821,9 +1825,9 @@ void CHyprCtl::startHyprCtlSocket() {
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
std::string socketPath = g_pCompositor->m_szInstancePath + "/.socket.sock"; m_socketPath = g_pCompositor->m_szInstancePath + "/.socket.sock";
strcpy(SERVERADDRESS.sun_path, socketPath.c_str()); strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str());
if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
@ -1833,7 +1837,7 @@ void CHyprCtl::startHyprCtlSocket() {
// 10 max queued. // 10 max queued.
listen(m_iSocketFD, 10); listen(m_iSocketFD, 10);
Debug::log(LOG, "Hypr socket started at {}", socketPath); Debug::log(LOG, "Hypr socket started at {}", m_socketPath);
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
} }

View file

@ -31,6 +31,7 @@ class CHyprCtl {
std::vector<SP<SHyprCtlCommand>> m_vCommands; std::vector<SP<SHyprCtlCommand>> m_vCommands;
wl_event_source* m_eventSource = nullptr; wl_event_source* m_eventSource = nullptr;
std::string m_socketPath;
}; };
inline std::unique_ptr<CHyprCtl> g_pHyprCtl; inline std::unique_ptr<CHyprCtl> g_pHyprCtl;

View file

@ -7,8 +7,8 @@ CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>(); m_pTexture = makeShared<CTexture>();
} }
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
m_dLastRenderTimes.push_back(µs / 1000.f); m_dLastRenderTimes.push_back(durationUs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimes.pop_front(); m_dLastRenderTimes.pop_front();
@ -17,8 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
m_dLastRenderTimesNoOverlay.push_back(µs / 1000.f); m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimesNoOverlay.pop_front(); m_dLastRenderTimesNoOverlay.pop_front();
@ -188,12 +188,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
return posY - offset; return posY - offset;
} }
void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) { void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs); m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
} }
void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, µs); m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
} }
void CHyprDebugOverlay::frameData(CMonitor* pMonitor) { void CHyprDebugOverlay::frameData(CMonitor* pMonitor) {

View file

@ -13,8 +13,8 @@ class CHyprMonitorDebugOverlay {
public: public:
int draw(int offset); int draw(int offset);
void renderData(CMonitor* pMonitor, float µs); void renderData(CMonitor* pMonitor, float durationUs);
void renderDataNoOverlay(CMonitor* pMonitor, float µs); void renderDataNoOverlay(CMonitor* pMonitor, float durationUs);
void frameData(CMonitor* pMonitor); void frameData(CMonitor* pMonitor);
private: private:
@ -33,8 +33,8 @@ class CHyprDebugOverlay {
public: public:
CHyprDebugOverlay(); CHyprDebugOverlay();
void draw(); void draw();
void renderData(CMonitor*, float µs); void renderData(CMonitor*, float durationUs);
void renderDataNoOverlay(CMonitor*, float µs); void renderDataNoOverlay(CMonitor*, float durationUs);
void frameData(CMonitor*); void frameData(CMonitor*);
private: private:

View file

@ -5,9 +5,17 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <fcntl.h>
void Debug::init(const std::string& IS) { void Debug::init(const std::string& IS) {
logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
logOfs.open(logFile, std::ios::out | std::ios::app);
auto handle = logOfs.native_handle();
fcntl(handle, F_SETFD, FD_CLOEXEC);
}
void Debug::close() {
logOfs.close();
} }
void Debug::log(LogLevel level, std::string str) { void Debug::log(LogLevel level, std::string str) {
@ -55,11 +63,8 @@ void Debug::log(LogLevel level, std::string str) {
if (!disableLogs || !**disableLogs) { if (!disableLogs || !**disableLogs) {
// log to a file // log to a file
std::ofstream ofs; logOfs << str << "\n";
ofs.open(logFile, std::ios::out | std::ios::app); logOfs.flush();
ofs << str << "\n";
ofs.close();
} }
// log it to the stdout too. // log it to the stdout too.

View file

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <chrono> #include <chrono>
#include <mutex>
#include "../includes.hpp" #include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
@ -22,6 +23,7 @@ enum LogLevel {
namespace Debug { namespace Debug {
inline std::string logFile; inline std::string logFile;
inline std::ofstream logOfs;
inline int64_t* const* disableLogs = nullptr; inline int64_t* const* disableLogs = nullptr;
inline int64_t* const* disableTime = nullptr; inline int64_t* const* disableTime = nullptr;
inline bool disableStdout = false; inline bool disableStdout = false;
@ -30,14 +32,18 @@ namespace Debug {
inline int64_t* const* coloredLogs = nullptr; inline int64_t* const* coloredLogs = nullptr;
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
inline std::mutex logMutex;
void init(const std::string& IS); void init(const std::string& IS);
void close();
// //
void log(LogLevel level, std::string str); void log(LogLevel level, std::string str);
template <typename... Args> template <typename... Args>
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) { void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(logMutex);
if (level == TRACE && !trace) if (level == TRACE && !trace)
return; return;

View file

@ -111,6 +111,11 @@ void CLayerSurface::onDestroy() {
layerSurface.reset(); layerSurface.reset();
if (surface) if (surface)
surface->unassign(); surface->unassign();
listeners.unmap.reset();
listeners.destroy.reset();
listeners.map.reset();
listeners.commit.reset();
} }
void CLayerSurface::onMap() { void CLayerSurface::onMap() {
@ -119,6 +124,8 @@ void CLayerSurface::onMap() {
mapped = true; mapped = true;
interactivity = layerSurface->current.interactivity; interactivity = layerSurface->current.interactivity;
layerSurface->surface->map();
// this layer might be re-mapped. // this layer might be re-mapped.
fadingOut = false; fadingOut = false;
g_pCompositor->removeFromFadingOutSafe(self.lock()); g_pCompositor->removeFromFadingOutSafe(self.lock());
@ -163,7 +170,7 @@ void CLayerSurface::onMap() {
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
const auto WORKSPACE = PMONITOR->activeWorkspace; const auto WORKSPACE = PMONITOR->activeWorkspace;
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
readyToDelete = false; readyToDelete = false;
@ -190,6 +197,8 @@ void CLayerSurface::onUnmap() {
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
mapped = false; mapped = false;
if (layerSurface && layerSurface->surface)
layerSurface->surface->unmap();
startAnimation(false); startAnimation(false);
return; return;
@ -201,6 +210,8 @@ void CLayerSurface::onUnmap() {
startAnimation(false); startAnimation(false);
mapped = false; mapped = false;
if (layerSurface && layerSurface->surface)
layerSurface->surface->unmap();
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
@ -213,7 +224,7 @@ void CLayerSurface::onUnmap() {
// refocus if needed // refocus if needed
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR); g_pInputManager->refocusLastWindow(PMONITOR);
else if (g_pCompositor->m_pLastFocus) else if (g_pCompositor->m_pLastFocus)
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
@ -236,7 +247,7 @@ void CLayerSurface::onCommit() {
if (!mapped) { if (!mapped) {
// we're re-mapping if this is the case // we're re-mapping if this is the case
if (layerSurface->surface && !layerSurface->surface->current.buffer) { if (layerSurface->surface && !layerSurface->surface->current.texture) {
fadingOut = false; fadingOut = false;
geometry = {}; geometry = {};
g_pHyprRenderer->arrangeLayersForMonitor(monitorID); g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
@ -421,8 +432,8 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
}; };
float closest = std::numeric_limits<float>::max(); float closest = std::numeric_limits<float>::max();
int leader = force; size_t leader = force;
if (leader == -1) { if (leader == -1) {
for (size_t i = 0; i < 4; ++i) { for (size_t i = 0; i < 4; ++i) {
float dist = MIDDLE.distance(edgePoints[i]); float dist = MIDDLE.distance(edgePoints[i]);

View file

@ -42,7 +42,7 @@ class CLayerSurface {
bool mapped = false; bool mapped = false;
uint32_t layer = 0; uint32_t layer = 0;
int monitorID = -1; MONITORID monitorID = -1;
bool fadingOut = false; bool fadingOut = false;
bool readyToDelete = false; bool readyToDelete = false;
@ -51,7 +51,7 @@ class CLayerSurface {
bool forceBlur = false; bool forceBlur = false;
bool forceBlurPopups = false; bool forceBlurPopups = false;
int xray = -1; int64_t xray = -1;
bool ignoreAlpha = false; bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f; float ignoreAlphaValue = 0.f;
bool dimAround = false; bool dimAround = false;

View file

@ -22,7 +22,7 @@ CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner),
m_pWindowOwner = pOwner->m_pWindowOwner; m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = popup->surface->current.geometry.size(); m_vLastSize = popup->surface->current.geometry.size();
unconstrain(); reposition();
initAllSignals(); initAllSignals();
} }
@ -188,18 +188,18 @@ void CPopup::onReposition() {
m_vLastPos = coordsRelativeToParent(); m_vLastPos = coordsRelativeToParent();
unconstrain(); reposition();
} }
void CPopup::unconstrain() { void CPopup::reposition() {
const auto COORDS = t1ParentCoords(); const auto COORDS = t1ParentCoords();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
if (!PMONITOR) if (!PMONITOR)
return; return;
CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; CBox box = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
m_pResource->applyPositioning(box, COORDS - PMONITOR->vecPosition); m_pResource->applyPositioning(box, COORDS);
} }
Vector2D CPopup::coordsRelativeToParent() { Vector2D CPopup::coordsRelativeToParent() {

View file

@ -74,11 +74,11 @@ class CPopup {
} listeners; } listeners;
void initAllSignals(); void initAllSignals();
void unconstrain(); void reposition();
void recheckChildrenRecursive(); void recheckChildrenRecursive();
void sendScale(); void sendScale();
Vector2D localToGlobal(const Vector2D& rel); Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords(); Vector2D t1ParentCoords();
static void bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data); static void bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data);
}; };

View file

@ -57,12 +57,12 @@ bool CWLSurface::small() const {
if (!validMapped(m_pWindowOwner) || !exists()) if (!validMapped(m_pWindowOwner) || !exists())
return false; return false;
if (!m_pResource->current.buffer) if (!m_pResource->current.texture)
return false; return false;
const auto O = m_pWindowOwner.lock(); const auto O = m_pWindowOwner.lock();
return O->m_vReportedSize.x > m_pResource->current.buffer->size.x + 1 || O->m_vReportedSize.y > m_pResource->current.buffer->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 { Vector2D CWLSurface::correctSmallVec() const {
@ -76,37 +76,36 @@ Vector2D CWLSurface::correctSmallVec() const {
} }
Vector2D CWLSurface::correctSmallVecBuf() const { Vector2D CWLSurface::correctSmallVecBuf() const {
if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.buffer) if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture)
return {}; return {};
const auto SIZE = getViewporterCorrectedSize(); const auto SIZE = getViewporterCorrectedSize();
const auto BS = m_pResource->current.buffer->size; const auto BS = m_pResource->current.bufferSize;
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}); return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
} }
Vector2D CWLSurface::getViewporterCorrectedSize() const { Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists() || !m_pResource->current.buffer) if (!exists() || !m_pResource->current.texture)
return {}; return {};
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size; return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.bufferSize;
} }
CRegion CWLSurface::computeDamage() const { CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.buffer) if (!m_pResource->current.texture)
return {}; return {};
CRegion damage = m_pResource->accumulateCurrentBufferDamage(); CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
const auto BUFSIZE = m_pResource->current.buffer->size; const auto BUFSIZE = m_pResource->current.bufferSize;
const auto CORRECTVEC = correctSmallVecBuf(); const auto CORRECTVEC = correctSmallVecBuf();
if (m_pResource->current.viewport.hasSource) if (m_pResource->current.viewport.hasSource)
damage.intersect(m_pResource->current.viewport.source); damage.intersect(m_pResource->current.viewport.source);
const auto SCALEDSRCSIZE = const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.bufferSize;
m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size;
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y}); damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC); damage.translate(CORRECTVEC);
@ -114,7 +113,7 @@ CRegion CWLSurface::computeDamage() const {
// go from buffer coords in the damage to hl logical // go from buffer coords in the damage to hl logical
const auto BOX = getSurfaceBoxGlobal(); const auto BOX = getSurfaceBoxGlobal();
const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.buffer->size : const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.bufferSize :
Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */}; Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */};
damage.scale(SCALE); damage.scale(SCALE);
@ -227,7 +226,7 @@ SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
bool CWLSurface::keyboardFocusable() const { bool CWLSurface::keyboardFocusable() const {
if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner) if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner)
return true; return true;
if (m_pLayerOwner) if (m_pLayerOwner && m_pLayerOwner->layerSurface)
return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
return false; return false;
} }

View file

@ -1,4 +1,5 @@
#include <any> #include <any>
#include <bit>
#include <string_view> #include <string_view>
#include <algorithm> #include <algorithm>
#include "Window.hpp" #include "Window.hpp"
@ -192,7 +193,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
auto POS = m_vPosition; auto POS = m_vPosition;
auto SIZE = m_vSize; auto SIZE = m_vSize;
if (m_bIsFullscreen) { if (isFullscreen()) {
POS = PMONITOR->vecPosition; POS = PMONITOR->vecPosition;
SIZE = PMONITOR->vecSize; SIZE = PMONITOR->vecSize;
@ -477,13 +478,7 @@ void unregisterVar(void* ptr) {
void CWindow::onUnmap() { void CWindow::onUnmap() {
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty"); static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
if (g_pCompositor->m_pLastWindow.lock().get() == this)
g_pCompositor->m_pLastWindow.reset();
if (g_pInputManager->currentlyDraggedWindow.lock().get() == this)
g_pInputManager->currentlyDraggedWindow.reset();
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
if (!m_szInitialWorkspaceToken.empty()) { if (!m_szInitialWorkspaceToken.empty()) {
const auto TOKEN = g_pTokenManager->getToken(m_szInitialWorkspaceToken); const auto TOKEN = g_pTokenManager->getToken(m_szInitialWorkspaceToken);
@ -976,8 +971,9 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
return; return;
const auto PCURRENT = getGroupCurrent(); const auto PCURRENT = getGroupCurrent();
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen; const bool FULLSCREEN = PCURRENT->isFullscreen();
const auto WORKSPACE = PCURRENT->m_pWorkspace; const auto WORKSPACE = PCURRENT->m_pWorkspace;
const auto MODE = PCURRENT->m_sFullscreenState.client;
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
@ -985,7 +981,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock(); const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock();
if (FULLSCREEN) if (FULLSCREEN)
g_pCompositor->setWindowFullscreen(PCURRENT, false, WORKSPACE->m_efFullscreenMode); g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE);
PCURRENT->setHidden(true); PCURRENT->setHidden(true);
pWindow->setHidden(false); // can remove m_pLastWindow pWindow->setHidden(false); // can remove m_pLastWindow
@ -1003,7 +999,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
g_pCompositor->focusWindow(pWindow); g_pCompositor->focusWindow(pWindow);
if (FULLSCREEN) if (FULLSCREEN)
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode); g_pCompositor->setWindowFullscreenInternal(pWindow, MODE);
g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow);
@ -1102,18 +1098,18 @@ bool CWindow::opaque() {
if (PWORKSPACE->m_fAlpha.value() != 1.f) if (PWORKSPACE->m_fAlpha.value() != 1.f)
return false; return false;
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer) if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture)
return m_pXWaylandSurface->surface->current.buffer->opaque; return m_pXWaylandSurface->surface->current.texture->m_bOpaque;
if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.buffer) if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.texture)
return false; return false;
// TODO: this is wrong // TODO: this is wrong
const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents(); const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents();
if (EXTENTS.w >= m_pXDGSurface->surface->current.buffer->size.x && EXTENTS.h >= m_pXDGSurface->surface->current.buffer->size.y) if (EXTENTS.w >= m_pXDGSurface->surface->current.bufferSize.x && EXTENTS.h >= m_pXDGSurface->surface->current.bufferSize.y)
return true; return true;
return m_pWLSurface->resource()->current.buffer->opaque; return m_pWLSurface->resource()->current.texture->m_bOpaque;
} }
float CWindow::rounding() { float CWindow::rounding() {
@ -1146,7 +1142,7 @@ void CWindow::updateWindowData(const SWorkspaceRule& workspaceRule) {
} }
int CWindow::getRealBorderSize() { int CWindow::getRealBorderSize() {
if (m_sWindowData.noBorder.valueOrDefault() || (m_pWorkspace && m_bIsFullscreen && (m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL))) if (m_sWindowData.noBorder.valueOrDefault() || (m_pWorkspace && isEffectiveInternalFSMode(FSMODE_FULLSCREEN)))
return 0; return 0;
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size"); static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
@ -1159,11 +1155,6 @@ bool CWindow::canBeTorn() {
return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING; return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
} }
bool CWindow::shouldSendFullscreenState() {
const auto MODE = m_pWorkspace->m_efFullscreenMode;
return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
}
void CWindow::setSuspended(bool suspend) { void CWindow::setSuspended(bool suspend) {
if (suspend == m_bSuspended) if (suspend == m_bSuspended)
return; return;
@ -1190,7 +1181,7 @@ void CWindow::setAnimationsToMove() {
void CWindow::onWorkspaceAnimUpdate() { void CWindow::onWorkspaceAnimUpdate() {
// clip box for animated offsets // clip box for animated offsets
if (!m_bIsFloating || m_bPinned || m_bIsFullscreen) { if (!m_bIsFloating || m_bPinned || isFullscreen()) {
m_vFloatingOffset = Vector2D(0, 0); m_vFloatingOffset = Vector2D(0, 0);
return; return;
} }
@ -1244,7 +1235,15 @@ int CWindow::surfacesCount() {
return no; return no;
} }
int CWindow::workspaceID() { bool CWindow::isFullscreen() {
return m_sFullscreenState.internal != FSMODE_NONE;
}
bool CWindow::isEffectiveInternalFSMode(const eFullscreenMode MODE) {
return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE;
}
WORKSPACEID CWindow::workspaceID() {
return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
} }
@ -1321,19 +1320,17 @@ void CWindow::onUpdateState() {
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
bool fs = requestsFS.value(); bool fs = requestsFS.value();
if (m_bIsMapped) {
if (fs != m_bIsFullscreen && m_bIsMapped) g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value());
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL); }
if (!m_bIsMapped) if (!m_bIsMapped)
m_bWantsInitialFullscreen = fs; m_bWantsInitialFullscreen = fs;
} }
if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) { if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) {
bool fs = requestsMX.value(); if (m_bIsMapped)
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_MAXIMIZED, requestsMX.value());
if (fs != m_bIsFullscreen && m_bIsMapped)
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED);
} }
} }
@ -1438,7 +1435,7 @@ void CWindow::onX11Configure(CBox box) {
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
if (!m_bIsFloating || m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == m_pSelf) { if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) {
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true);
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());

View file

@ -16,6 +16,7 @@
#include "Popup.hpp" #include "Popup.hpp"
#include "Subsurface.hpp" #include "Subsurface.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp"
class CXDGSurfaceResource; class CXDGSurfaceResource;
class CXWaylandSurface; class CXWaylandSurface;
@ -170,6 +171,7 @@ struct SWindowData {
CWindowOverridableVar<bool> noShortcutsInhibit = false; CWindowOverridableVar<bool> noShortcutsInhibit = false;
CWindowOverridableVar<bool> opaque = false; CWindowOverridableVar<bool> opaque = false;
CWindowOverridableVar<bool> RGBX = false; CWindowOverridableVar<bool> RGBX = false;
CWindowOverridableVar<bool> syncFullscreen = true;
CWindowOverridableVar<bool> tearing = false; CWindowOverridableVar<bool> tearing = false;
CWindowOverridableVar<bool> xray = false; CWindowOverridableVar<bool> xray = false;
@ -208,6 +210,11 @@ struct SInitialWorkspaceToken {
std::string workspace; std::string workspace;
}; };
struct sFullscreenState {
eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE;
};
class CWindow { class CWindow {
public: public:
static PHLWINDOW create(SP<CXDGSurfaceResource>); static PHLWINDOW create(SP<CXDGSurfaceResource>);
@ -256,24 +263,23 @@ class CWindow {
Vector2D m_vPseudoSize = Vector2D(1280, 720); Vector2D m_vPseudoSize = Vector2D(1280, 720);
// for recovering relative cursor position // for recovering relative cursor position
Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1); Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1);
bool m_bFirstMap = false; // for layouts bool m_bFirstMap = false; // for layouts
bool m_bIsFloating = false; bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bIsFullscreen = false; bool m_bWasMaximized = false;
bool m_bDontSendFullscreen = false; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
bool m_bWasMaximized = false; MONITORID m_iMonitorID = -1;
uint64_t m_iMonitorID = -1; std::string m_szTitle = "";
std::string m_szTitle = ""; std::string m_szClass = "";
std::string m_szClass = ""; std::string m_szInitialTitle = "";
std::string m_szInitialTitle = ""; std::string m_szInitialClass = "";
std::string m_szInitialClass = ""; PHLWORKSPACE m_pWorkspace;
PHLWORKSPACE m_pWorkspace;
bool m_bIsMapped = false; bool m_bIsMapped = false;
bool m_bRequestsFloat = false; bool m_bRequestsFloat = false;
// This is for fullscreen apps // This is for fullscreen apps
bool m_bCreatedOverFullscreen = false; bool m_bCreatedOverFullscreen = false;
@ -322,9 +328,6 @@ class CWindow {
// urgency hint // urgency hint
bool m_bIsUrgent = false; bool m_bIsUrgent = false;
// fakefullscreen
bool m_bFakeFullscreenState = false;
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window. // for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
PHLWINDOWREF m_pLastCycledWindow; PHLWINDOWREF m_pLastCycledWindow;
@ -355,8 +358,8 @@ class CWindow {
bool m_bStayFocused = false; bool m_bStayFocused = false;
// for toplevel monitor events // for toplevel monitor events
uint64_t m_iLastToplevelMonitorID = -1; MONITORID m_iLastToplevelMonitorID = -1;
uint64_t m_iLastSurfaceMonitorID = -1; MONITORID m_iLastSurfaceMonitorID = -1;
// for idle inhibiting windows // for idle inhibiting windows
eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE; eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
@ -416,14 +419,16 @@ class CWindow {
bool opaque(); bool opaque();
float rounding(); float rounding();
bool canBeTorn(); bool canBeTorn();
bool shouldSendFullscreenState();
void setSuspended(bool suspend); void setSuspended(bool suspend);
bool visibleOnMonitor(CMonitor* pMonitor); bool visibleOnMonitor(CMonitor* pMonitor);
int workspaceID(); WORKSPACEID workspaceID();
bool onSpecialWorkspace(); bool onSpecialWorkspace();
void activate(bool force = false); void activate(bool force = false);
int surfacesCount(); int surfacesCount();
bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize(); int getRealBorderSize();
void updateWindowData(); void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&); void updateWindowData(const struct SWorkspaceRule&);
@ -485,9 +490,9 @@ class CWindow {
private: private:
// For hidden windows and stuff // For hidden windows and stuff
bool m_bHidden = false; bool m_bHidden = false;
bool m_bSuspended = false; bool m_bSuspended = false;
int m_iLastWorkspace = WORKSPACE_INVALID; WORKSPACEID m_iLastWorkspace = WORKSPACE_INVALID;
}; };
inline bool valid(PHLWINDOW w) { inline bool valid(PHLWINDOW w) {

View file

@ -5,13 +5,13 @@
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) { PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) {
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmtpy); PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmtpy);
workspace->init(workspace); workspace->init(workspace);
return workspace; return workspace;
} }
CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special, bool isEmtpy) { CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) {
m_iMonitorID = monitorID; m_iMonitorID = monitorID;
m_iID = id; m_iID = id;
m_szName = name; m_szName = name;
@ -190,7 +190,7 @@ void CWorkspace::setActive(bool on) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40 ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
} }
void CWorkspace::moveToMonitor(const int& id) { void CWorkspace::moveToMonitor(const MONITORID& id) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40 ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
} }
@ -275,7 +275,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
i = std::min(NEXTSPACE, std::string::npos - 1); i = std::min(NEXTSPACE, std::string::npos - 1);
if (cur == 'r') { if (cur == 'r') {
int from = 0, to = 0; WORKSPACEID from = 0, to = 0;
if (!prop.starts_with("r[") || !prop.ends_with("]")) { if (!prop.starts_with("r[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector); Debug::log(LOG, "Invalid selector {}", selector);
return false; return false;
@ -365,7 +365,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} }
if (cur == 'w') { if (cur == 'w') {
int from = 0, to = 0; WORKSPACEID from = 0, to = 0;
if (!prop.starts_with("w[") || !prop.ends_with("]")) { if (!prop.starts_with("w[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector); Debug::log(LOG, "Invalid selector {}", selector);
return false; return false;
@ -446,7 +446,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false; return false;
} }
int count; WORKSPACEID count;
if (wantsCountGroup) if (wantsCountGroup)
count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled), count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt); wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
@ -480,16 +480,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false; return false;
break; break;
case 0: // fullscreen full case 0: // fullscreen full
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_FULL) if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_FULLSCREEN)
return false; return false;
break; break;
case 1: // maximized case 1: // maximized
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_MAXIMIZED) if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_MAXIMIZED)
return false;
break;
case 2: // fullscreen without sending fullscreen state to window
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_FULL || !g_pCompositor->getFullscreenWindowOnWorkspace(m_iID) ||
!g_pCompositor->getFullscreenWindowOnWorkspace(m_iID)->m_bDontSendFullscreen)
return false; return false;
break; break;
default: break; default: break;
@ -511,7 +506,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
void CWorkspace::markInert() { void CWorkspace::markInert() {
m_bInert = true; m_bInert = true;
m_iID = WORKSPACE_INVALID; m_iID = WORKSPACE_INVALID;
m_iMonitorID = -1; m_iMonitorID = MONITOR_INVALID;
m_bVisible = false; m_bVisible = false;
} }

View file

@ -7,31 +7,32 @@
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
enum eFullscreenMode : int8_t { enum eFullscreenMode : int8_t {
FULLSCREEN_INVALID = -1, FSMODE_NONE = 0,
FULLSCREEN_FULL = 0, FSMODE_MAXIMIZED = 1 << 0,
FULLSCREEN_MAXIMIZED FSMODE_FULLSCREEN = 1 << 1,
FSMODE_MAX = (1 << 2) - 1
}; };
class CWindow; class CWindow;
class CWorkspace { class CWorkspace {
public: public:
static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false, bool isEmtpy = true); static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmtpy = true);
// use create() don't use this // use create() don't use this
CWorkspace(int id, int monitorID, std::string name, bool special = false, bool isEmpty = true); CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
~CWorkspace(); ~CWorkspace();
// Workspaces ID-based have IDs > 0 // Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337 // and workspaces name-based have IDs starting with -1337
int m_iID = -1; WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_szName = ""; std::string m_szName = "";
uint64_t m_iMonitorID = -1; MONITORID m_iMonitorID = MONITOR_INVALID;
// Previous workspace ID and name is stored during a workspace change, allowing travel // Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace. // to the previous workspace.
SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
bool m_bHasFullscreenWindow = false; bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL; eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
wl_array m_wlrCoordinateArr; wl_array m_wlrCoordinateArr;
@ -66,7 +67,7 @@ class CWorkspace {
void startAnim(bool in, bool left, bool instant = false); void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on); void setActive(bool on);
void moveToMonitor(const int&); void moveToMonitor(const MONITORID&);
PHLWINDOW getLastFocusedWindow(); PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);

View file

@ -274,9 +274,9 @@ std::string IKeyboard::getActiveLayout() {
return "none"; return "none";
} }
void IKeyboard::updateLEDs() { std::optional<uint32_t> IKeyboard::getLEDs() {
if (xkbState == nullptr) if (xkbState == nullptr)
return; return {};
uint32_t leds = 0; uint32_t leds = 0;
for (uint32_t i = 0; i < LED_COUNT; ++i) { for (uint32_t i = 0; i < LED_COUNT; ++i) {
@ -284,7 +284,16 @@ void IKeyboard::updateLEDs() {
leds |= (1 << i); leds |= (1 << i);
} }
updateLEDs(leds); return leds;
}
void IKeyboard::updateLEDs() {
std::optional<uint32_t> leds = getLEDs();
if (!leds.has_value())
return;
updateLEDs(leds.value());
} }
void IKeyboard::updateLEDs(uint32_t leds) { void IKeyboard::updateLEDs(uint32_t leds) {
@ -325,6 +334,13 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l
if (!updateModifiersState()) if (!updateModifiersState())
return; return;
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,
.locked = modifiersState.locked,
.group = modifiersState.group,
});
updateLEDs(); updateLEDs();
} }

View file

@ -5,6 +5,7 @@
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include <optional>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
AQUAMARINE_FORWARD(IKeyboard); AQUAMARINE_FORWARD(IKeyboard);
@ -61,19 +62,20 @@ class IKeyboard : public IHID {
std::string rules = ""; std::string rules = "";
}; };
void setKeymap(const SStringRuleNames& rules); void setKeymap(const SStringRuleNames& rules);
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
std::string getActiveLayout(); std::string getActiveLayout();
void updateLEDs(); std::optional<uint32_t> getLEDs();
void updateLEDs(uint32_t leds); void updateLEDs();
uint32_t getModifiers(); void updateLEDs(uint32_t leds);
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); uint32_t getModifiers();
bool updateModifiersState(); // rets whether changed void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); bool updateModifiersState(); // rets whether changed
void updateKeymapFD(); void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
void updateKeymapFD();
bool active = false; bool active = false;
bool enabled = true; bool enabled = true;
// if the keymap is overridden by the implementation, // if the keymap is overridden by the implementation,
// don't try to set keyboard rules anymore, to avoid overwriting the requested one. // don't try to set keyboard rules anymore, to avoid overwriting the requested one.

View file

@ -106,7 +106,8 @@ class IPointer : public IHID {
} pointerEvents; } pointerEvents;
std::string hlName; std::string hlName;
bool connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string boundOutput = "";
WP<IPointer> self; WP<IPointer> self;
}; };

View file

@ -38,6 +38,8 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); });
listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); });
boundOutput = resource->boundOutput ? resource->boundOutput->szName : "entire";
deviceName = pointer->name; deviceName = pointer->name;
} }

View file

@ -133,12 +133,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
// window rules // window rules
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen); std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode;
bool requestsFakeFullscreen = false; std::optional<sFullscreenState> requestedFSState;
bool requestsMaximize = false; if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen))
bool overridingNoFullscreen = false; requestedClientFSMode = FSMODE_FULLSCREEN;
bool overridingNoMaximize = false;
for (auto& r : PWINDOW->m_vMatchedRules) { for (auto& r : PWINDOW->m_vMatchedRules) {
if (r.szRule.starts_with("monitor")) { if (r.szRule.starts_with("monitor")) {
@ -149,7 +148,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
} else { } else {
if (isNumber(MONITORSTR)) { if (isNumber(MONITORSTR)) {
const long int MONITOR = std::stoi(MONITORSTR); const MONITORID MONITOR = std::stoi(MONITORSTR);
if (!g_pCompositor->getMonitorFromID(MONITOR)) if (!g_pCompositor->getMonitorFromID(MONITOR))
PWINDOW->m_iMonitorID = 0; PWINDOW->m_iMonitorID = 0;
else else
@ -199,6 +198,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("noinitialfocus")) { } else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.starts_with("fullscreenstate")) {
const auto ARGS = CVarList(r.szRule.substr(r.szRule.find_first_of(' ') + 1), 2, ' ');
int internalMode, clientMode;
try {
internalMode = std::stoi(ARGS[0]);
} catch (std::exception& e) { internalMode = 0; }
try {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = 0; }
requestedFSState = sFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
} else if (r.szRule.starts_with("suppressevent")) { } else if (r.szRule.starts_with("suppressevent")) {
CVarList vars(r.szRule, 0, 's', true); CVarList vars(r.szRule, 0, 's', true);
for (size_t i = 1; i < vars.size(); ++i) { for (size_t i = 1; i < vars.size(); ++i) {
@ -213,16 +222,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
else else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]); Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
} }
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
overridingNoFullscreen = true;
} else if (r.szRule == "fakefullscreen") {
requestsFakeFullscreen = true;
} else if (r.szRule == "pin") { } else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true; PWINDOW->m_bPinned = true;
} else if (r.szRule == "fullscreen") {
requestedInternalFSMode = FSMODE_FULLSCREEN;
} else if (r.szRule == "maximize") { } else if (r.szRule == "maximize") {
requestsMaximize = true; requestedInternalFSMode = FSMODE_MAXIMIZED;
overridingNoMaximize = true;
} else if (r.szRule == "stayfocused") { } else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true; PWINDOW->m_bStayFocused = true;
} else if (r.szRule.starts_with("group")) { } else if (r.szRule.starts_with("group")) {
@ -461,17 +466,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock());
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE)
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestedInternalFSMode.has_value() && !requestedClientFSMode.has_value() && !PWINDOW->m_bIsFloating) {
if (*PNEWTAKESOVERFS == 0) if (*PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 1)
requestedInternalFSMode = PWINDOW->m_pWorkspace->m_efFullscreenMode;
else if (*PNEWTAKESOVERFS == 2) else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID); g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
requestsMaximize = true;
if (*PNEWTAKESOVERFS == 1)
overridingNoMaximize = true;
} else
requestsFullscreen = true;
} }
if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus && if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus &&
@ -485,24 +487,27 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_fDimPercent.setValueAndWarp(0); PWINDOW->m_fDimPercent.setValueAndWarp(0);
} }
if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) || if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
(requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) { requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_FULLSCREEN);
// fix fullscreen on requested (basically do a switcheroo) if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE))
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) { requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_MAXIMIZED);
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID);
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
}
if (requestsFakeFullscreen && !PWINDOW->m_bFakeFullscreenState) { if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) {
PWINDOW->m_bFakeFullscreenState = !PWINDOW->m_bFakeFullscreenState; // fix fullscreen on requested (basically do a switcheroo)
g_pXWaylandManager->setWindowFullscreen(PWINDOW, true); if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow)
} else { g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
overridingNoFullscreen = false;
overridingNoMaximize = false; PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealPosition.warp(); PWINDOW->m_vRealSize.warp();
PWINDOW->m_vRealSize.warp(); if (requestedFSState.has_value()) {
g_pCompositor->setWindowFullscreen(PWINDOW, true, requestsFullscreen ? FULLSCREEN_FULL : FULLSCREEN_MAXIMIZED); PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE);
} g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value());
} else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()});
else if (requestedInternalFSMode.has_value())
g_pCompositor->setWindowFullscreenInternal(PWINDOW, requestedInternalFSMode.value());
else if (requestedClientFSMode.has_value())
g_pCompositor->setWindowFullscreenClient(PWINDOW, requestedClientFSMode.value());
} }
// recheck idle inhibitors // recheck idle inhibitors
@ -558,7 +563,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recalc the values for this window // recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// avoid this window being visible // avoid this window being visible
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating) if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating)
PWINDOW->m_fAlpha.setValueAndWarp(0.f); PWINDOW->m_fAlpha.setValueAndWarp(0.f);
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale);
@ -583,8 +588,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
static auto PEXITRETAINSFS = CConfigValue<Hyprlang::INT>("misc:exit_window_retains_fullscreen"); static auto PEXITRETAINSFS = CConfigValue<Hyprlang::INT>("misc:exit_window_retains_fullscreen");
const auto CURRENTWINDOWFSSTATE = PWINDOW->m_bIsFullscreen; const auto CURRENTWINDOWFSSTATE = PWINDOW->isFullscreen();
const auto CURRENTWINDOWFSMODE = PWINDOW->m_pWorkspace->m_efFullscreenMode; const auto CURRENTFSMODE = PWINDOW->m_sFullscreenState.internal;
if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) { if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) {
Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW);
@ -604,8 +609,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PROTO::toplevelExport->onWindowUnmap(PWINDOW); PROTO::toplevelExport->onWindowUnmap(PWINDOW);
if (PWINDOW->m_bIsFullscreen) if (PWINDOW->isFullscreen())
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
// Allow the renderer to catch the last frame. // Allow the renderer to catch the last frame.
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW); g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
@ -627,10 +632,13 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
} }
if (PWINDOW == g_pInputManager->currentlyDraggedWindow.lock())
g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
// remove the fullscreen window status from workspace if we closed it // remove the fullscreen window status from workspace if we closed it
const auto PWORKSPACE = PWINDOW->m_pWorkspace; const auto PWORKSPACE = PWINDOW->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->m_bIsFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->isFullscreen())
PWORKSPACE->m_bHasFullscreenWindow = false; PWORKSPACE->m_bHasFullscreenWindow = false;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
@ -647,7 +655,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) { if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) {
g_pCompositor->focusWindow(PWINDOWCANDIDATE); g_pCompositor->focusWindow(PWINDOWCANDIDATE);
if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE) if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE)
g_pCompositor->setWindowFullscreen(PWINDOWCANDIDATE, true, CURRENTWINDOWFSMODE); g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE);
} }
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0) if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0)
@ -705,7 +713,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) { if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) {
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize;
const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize;
@ -744,7 +752,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
// tearing: if solitary, redraw it. This still might be a single surface window // tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) { if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
if (!damageBox.empty()) { if (!damageBox.empty()) {
@ -782,6 +790,11 @@ void Events::listener_destroyWindow(void* owner, void* data) {
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW); Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
} }
PWINDOW->listeners.unmap.reset();
PWINDOW->listeners.destroy.reset();
PWINDOW->listeners.map.reset();
PWINDOW->listeners.commit.reset();
} }
void Events::listener_setTitleWindow(void* owner, void* data) { void Events::listener_setTitleWindow(void* owner, void* data) {
@ -832,7 +845,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
else else
PWINDOW->setHidden(true); PWINDOW->setHidden(true);
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) { if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
return; return;

View file

@ -30,8 +30,10 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f; const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f;
const auto BEGINCALC = std::chrono::high_resolution_clock::now(); const auto BEGINCALC = std::chrono::high_resolution_clock::now();
for (float i = 0.1f; i < 1.f; i += 0.1f) for (int j = 1; j < 10; ++j) {
float i = j / 10.0f;
getYForPoint(i); getYForPoint(i);
}
const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f; const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f;
Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE, Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE,

View file

@ -249,7 +249,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
} }
std::set<int> invalidWSes; std::set<WORKSPACEID> invalidWSes;
if (same_mon) { if (same_mon) {
for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) {
const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor);
@ -258,8 +258,8 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} }
} }
int id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0;
while (++id < INT_MAX) { while (++id < LONG_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) { if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) {
result.id = id; result.id = id;
@ -296,9 +296,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
result.id = (int)PLUSMINUSRESULT.value(); result.id = (int)PLUSMINUSRESULT.value();
int remains = (int)result.id; WORKSPACEID remains = result.id;
std::set<int> invalidWSes; std::set<WORKSPACEID> invalidWSes;
// Collect all the workspaces we can't jump to. // Collect all the workspaces we can't jump to.
for (auto& ws : g_pCompositor->m_vWorkspaces) { for (auto& ws : g_pCompositor->m_vWorkspaces) {
@ -318,7 +318,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} }
// Prepare all named workspaces in case when we need them // Prepare all named workspaces in case when we need them
std::vector<int> namedWSes; std::vector<WORKSPACEID> namedWSes;
for (auto& ws : g_pCompositor->m_vWorkspaces) { for (auto& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0) if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0)
continue; continue;
@ -347,18 +347,18 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} else { } else {
// Just take a blind guess at where we'll probably end up // Just take a blind guess at where we'll probably end up
int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
int predictedWSID = activeWSID + remains; WORKSPACEID predictedWSID = activeWSID + remains;
int remainingWSes = 0; int remainingWSes = 0;
char walkDir = in[1]; char walkDir = in[1];
// sanitize. 0 means invalid oob in - // sanitize. 0 means invalid oob in -
predictedWSID = std::max(predictedWSID, 0); predictedWSID = std::max(predictedWSID, 0L);
// Count how many invalidWSes are in between (how bad the prediction was) // Count how many invalidWSes are in between (how bad the prediction was)
int beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID; WORKSPACEID beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID;
int endID = in[1] == '+' ? predictedWSID : activeWSID; WORKSPACEID endID = in[1] == '+' ? predictedWSID : activeWSID;
auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
remainingWSes++; remainingWSes++;
} }
@ -367,7 +367,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
if (activeWSID < 0) { if (activeWSID < 0) {
// Behaviour similar to 'm' // Behaviour similar to 'm'
// Find current // Find current
int currentItem = -1; size_t currentItem = -1;
for (size_t i = 0; i < namedWSes.size(); i++) { for (size_t i = 0; i < namedWSes.size(); i++) {
if (namedWSes[i] == activeWSID) { if (namedWSes[i] == activeWSID) {
currentItem = i; currentItem = i;
@ -376,14 +376,14 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} }
currentItem += remains; currentItem += remains;
currentItem = std::max(currentItem, 0); currentItem = std::max(currentItem, 0UL);
if (currentItem >= (int)namedWSes.size()) { if (currentItem >= namedWSes.size()) {
// At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0 // At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0
int diff = currentItem - (namedWSes.size() - 1); size_t diff = currentItem - (namedWSes.size() - 1);
predictedWSID = diff; predictedWSID = diff;
int beginID = 1; WORKSPACEID beginID = 1;
int endID = predictedWSID; WORKSPACEID endID = predictedWSID;
auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
remainingWSes++; remainingWSes++;
} }
@ -397,10 +397,10 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// Go in the search direction for remainingWSes // Go in the search direction for remainingWSes
// The performance impact is directly proportional to the number of open and bound workspaces // The performance impact is directly proportional to the number of open and bound workspaces
int finalWSID = predictedWSID; WORKSPACEID finalWSID = predictedWSID;
if (walkDir == '-') { if (walkDir == '-') {
int beginID = finalWSID; WORKSPACEID beginID = finalWSID;
int curID = finalWSID; WORKSPACEID curID = finalWSID;
while (--curID > 0 && remainingWSes > 0) { while (--curID > 0 && remainingWSes > 0) {
if (!invalidWSes.contains(curID)) { if (!invalidWSes.contains(curID)) {
remainingWSes--; remainingWSes--;
@ -411,9 +411,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
if (namedWSes.size()) { if (namedWSes.size()) {
// Go to the named workspaces // Go to the named workspaces
// Need remainingWSes more // Need remainingWSes more
int namedWSIdx = namedWSes.size() - remainingWSes; auto namedWSIdx = namedWSes.size() - remainingWSes;
// Sanitze // Sanitze
namedWSIdx = std::clamp(namedWSIdx, 0, (int)namedWSes.size() - 1); namedWSIdx = std::clamp(namedWSIdx, 0UL, namedWSes.size() - 1);
finalWSID = namedWSes[namedWSIdx]; finalWSID = namedWSes[namedWSIdx];
} else { } else {
// Couldn't find valid workspace in negative direction, search last first one back up positive direction // Couldn't find valid workspace in negative direction, search last first one back up positive direction
@ -425,7 +425,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} }
} }
if (walkDir == '+') { if (walkDir == '+') {
int curID = finalWSID; WORKSPACEID curID = finalWSID;
while (++curID < INT32_MAX && remainingWSes > 0) { while (++curID < INT32_MAX && remainingWSes > 0) {
if (!invalidWSes.contains(curID)) { if (!invalidWSes.contains(curID)) {
remainingWSes--; remainingWSes--;
@ -460,9 +460,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
result.id = (int)PLUSMINUSRESULT.value(); result.id = (int)PLUSMINUSRESULT.value();
// result now has +/- what we should move on mon // result now has +/- what we should move on mon
int remains = (int)result.id; int remains = (int)result.id;
std::vector<int> validWSes; std::vector<WORKSPACEID> validWSes;
for (auto& ws : g_pCompositor->m_vWorkspaces) { for (auto& ws : g_pCompositor->m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors)) if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors))
continue; continue;
@ -472,7 +472,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
std::sort(validWSes.begin(), validWSes.end()); std::sort(validWSes.begin(), validWSes.end());
int currentItem = -1; size_t currentItem = -1;
if (absolute) { if (absolute) {
// 1-index // 1-index
@ -481,7 +481,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// clamp // clamp
if (currentItem < 0) { if (currentItem < 0) {
currentItem = 0; currentItem = 0;
} else if (currentItem >= (int)validWSes.size()) { } else if (currentItem >= validWSes.size()) {
currentItem = validWSes.size() - 1; currentItem = validWSes.size() - 1;
} }
} else { } else {
@ -489,7 +489,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size(); remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size();
// get the current item // get the current item
int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
for (size_t i = 0; i < validWSes.size(); i++) { for (size_t i = 0; i < validWSes.size(); i++) {
if (validWSes[i] == activeWSID) { if (validWSes[i] == activeWSID) {
currentItem = i; currentItem = i;
@ -501,7 +501,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
currentItem += remains; currentItem += remains;
// sanitize // sanitize
if (currentItem >= (int)validWSes.size()) { if (currentItem >= validWSes.size()) {
currentItem = currentItem % validWSes.size(); currentItem = currentItem % validWSes.size();
} else if (currentItem < 0) { } else if (currentItem < 0) {
currentItem = validWSes.size() + currentItem; currentItem = validWSes.size() + currentItem;
@ -547,9 +547,9 @@ std::optional<std::string> cleanCmdForWorkspace(const std::string& inWorkspaceNa
const std::string workspaceRule = "workspace " + inWorkspaceName; const std::string workspaceRule = "workspace " + inWorkspaceName;
if (cmd[0] == '[') { if (cmd[0] == '[') {
const int closingBracketIdx = cmd.find_last_of(']'); const auto closingBracketIdx = cmd.find_last_of(']');
auto tmpRules = cmd.substr(1, closingBracketIdx - 1); auto tmpRules = cmd.substr(1, closingBracketIdx - 1);
cmd = cmd.substr(closingBracketIdx + 1); cmd = cmd.substr(closingBracketIdx + 1);
auto rulesList = CVarList(tmpRules, 0, ';'); auto rulesList = CVarList(tmpRules, 0, ';');
@ -785,13 +785,13 @@ std::vector<SCallstackFrameInfo> getBacktrace() {
#ifdef HAS_EXECINFO #ifdef HAS_EXECINFO
void* bt[1024]; void* bt[1024];
size_t btSize; int btSize;
char** btSymbols; char** btSymbols;
btSize = backtrace(bt, 1024); btSize = backtrace(bt, 1024);
btSymbols = backtrace_symbols(bt, btSize); btSymbols = backtrace_symbols(bt, btSize);
for (size_t i = 0; i < btSize; ++i) { for (auto i = 0; i < btSize; ++i) {
callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}}); callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}});
} }
#else #else

View file

@ -6,6 +6,8 @@
#include "math/Math.hpp" #include "math/Math.hpp"
#include <vector> #include <vector>
#include <format> #include <format>
#include "../SharedDefs.hpp"
#include "../macros.hpp"
struct SCallstackFrameInfo { struct SCallstackFrameInfo {
void* adr = nullptr; void* adr = nullptr;
@ -13,7 +15,7 @@ struct SCallstackFrameInfo {
}; };
struct SWorkspaceIDName { struct SWorkspaceIDName {
int id = -1; WORKSPACEID id = WORKSPACE_INVALID;
std::string name; std::string name;
}; };

View file

@ -1,6 +1,8 @@
#include "Monitor.hpp" #include "Monitor.hpp"
#include "MiscFunctions.hpp" #include "MiscFunctions.hpp"
#include "math/Math.hpp" #include "math/Math.hpp"
#include "sync/SyncReleaser.hpp"
#include "ScopeGuard.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/GammaControl.hpp" #include "../protocols/GammaControl.hpp"
@ -8,6 +10,7 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/PresentationTime.hpp" #include "../protocols/PresentationTime.hpp"
#include "../protocols/DRMLease.hpp" #include "../protocols/DRMLease.hpp"
#include "../protocols/DRMSyncobj.hpp"
#include "../protocols/core/Output.hpp" #include "../protocols/core/Output.hpp"
#include "../managers/PointerManager.hpp" #include "../managers/PointerManager.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
@ -77,6 +80,7 @@ void CMonitor::onConnect(bool noRule) {
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
if (m_bEnabled) { if (m_bEnabled) {
output->state->resetExplicitFences();
output->state->setEnabled(true); output->state->setEnabled(true);
state.commit(); state.commit();
return; return;
@ -101,6 +105,7 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
output->state->resetExplicitFences();
output->state->setEnabled(false); output->state->setEnabled(false);
if (!state.commit()) if (!state.commit())
@ -137,6 +142,7 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true; m_bEnabled = true;
output->state->resetExplicitFences();
output->state->setEnabled(true); output->state->setEnabled(true);
// set mode, also applies // set mode, also applies
@ -300,6 +306,7 @@ void CMonitor::onDisconnect(bool destroy) {
activeWorkspace->m_bVisible = false; activeWorkspace->m_bVisible = false;
activeWorkspace.reset(); activeWorkspace.reset();
output->state->resetExplicitFences();
output->state->setEnabled(false); output->state->setEnabled(false);
if (!state.commit()) if (!state.commit())
@ -354,7 +361,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
// skip scheduling extra frames for fullsreen apps with vrr // skip scheduling extra frames for fullsreen apps with vrr
bool shouldSkip = bool shouldSkip =
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
// keep requested minimum refresh rate // keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
@ -382,8 +389,8 @@ bool CMonitor::matchesStaticSelector(const std::string& selector) const {
} }
} }
int CMonitor::findAvailableDefaultWS() { WORKSPACEID CMonitor::findAvailableDefaultWS() {
for (size_t i = 1; i < INT32_MAX; ++i) { for (WORKSPACEID i = 1; i < LONG_MAX; ++i) {
if (g_pCompositor->getWorkspaceByID(i)) if (g_pCompositor->getWorkspaceByID(i))
continue; continue;
@ -393,7 +400,7 @@ int CMonitor::findAvailableDefaultWS() {
return i; return i;
} }
return INT32_MAX; // shouldn't be reachable return LONG_MAX; // shouldn't be reachable
} }
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
@ -631,7 +638,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
g_pCompositor->updateFullscreenFadeOnWorkspace(activeSpecialWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(activeSpecialWorkspace);
} }
void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) { void CMonitor::changeWorkspace(const WORKSPACEID& id, bool internal, bool noMouseMove, bool noFocus) {
changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus); changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus);
} }
@ -738,7 +745,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
} }
void CMonitor::setSpecialWorkspace(const int& id) { void CMonitor::setSpecialWorkspace(const WORKSPACEID& id) {
setSpecialWorkspace(g_pCompositor->getWorkspaceByID(id)); setSpecialWorkspace(g_pCompositor->getWorkspaceByID(id));
} }
@ -759,11 +766,11 @@ void CMonitor::updateMatrix() {
} }
} }
int64_t CMonitor::activeWorkspaceID() { WORKSPACEID CMonitor::activeWorkspaceID() {
return activeWorkspace ? activeWorkspace->m_iID : 0; return activeWorkspace ? activeWorkspace->m_iID : 0;
} }
int64_t CMonitor::activeSpecialWorkspaceID() { WORKSPACEID CMonitor::activeSpecialWorkspaceID() {
return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0; return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0;
} }
@ -801,33 +808,84 @@ bool CMonitor::attemptDirectScanout() {
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform) if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
return false; return false;
// we can't scanout shm buffers. // we can't scanout shm buffers.
if (!PSURFACE->current.buffer->dmabuf().success) if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
return false; return false;
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get());
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats // FIXME: make sure the buffer actually follows the available scanout dmabuf formats
// and comes from the appropriate device. This may implode on multi-gpu!! // and comes from the appropriate device. This may implode on multi-gpu!!
output->state->setBuffer(PSURFACE->current.buffer->buffer.lock());
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
output->state->setBuffer(PSURFACE->current.buffer); if (!state.test()) {
output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); Debug::log(TRACE, "attemptDirectScanout: failed basic test");
if (!state.test())
return false; return false;
}
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings();
// wait for the explicit fence if present, and if kms explicit is allowed
bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled;
int explicitWaitFD = -1;
if (DOEXPLICIT) {
explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint);
if (explicitWaitFD < 0)
Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd");
}
DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0;
auto cleanup = CScopeGuard([explicitWaitFD, this]() {
output->state->resetExplicitFences();
if (explicitWaitFD >= 0)
close(explicitWaitFD);
});
timespec now; timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
Debug::log(TRACE, "presentFeedback for DS"); PSURFACE->presentFeedback(&now, this);
PSURFACE->presentFeedback(&now, this, true);
if (state.commit()) { output->state->addDamage(CBox{{}, vecPixelSize});
output->state->resetExplicitFences();
if (DOEXPLICIT) {
Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD);
output->state->setExplicitInFence(explicitWaitFD);
}
bool ok = output->commit();
if (!ok && DOEXPLICIT) {
Debug::log(TRACE, "attemptDirectScanout: EXPLICIT SYNC FAILED: commit() returned false. Resetting fences and retrying, might result in glitches.");
output->state->resetExplicitFences();
ok = output->commit();
}
if (ok) {
if (lastScanout.expired()) { if (lastScanout.expired()) {
lastScanout = PCANDIDATE; lastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
} }
// delay explicit sync feedback until kms release of the buffer
if (DOEXPLICIT) {
Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release");
PSURFACE->current.buffer->releaser->drop();
PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) {
const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline;
if (DOEXPLICIT)
PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint);
});
}
} else { } else {
Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
lastScanout.reset(); lastScanout.reset();
return false; return false;
} }
@ -863,6 +921,8 @@ bool CMonitorState::commit() {
if (!updateSwapchain()) if (!updateSwapchain())
return false; return false;
EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner);
ensureBufferPresent(); ensureBufferPresent();
bool ret = m_pOwner->output->commit(); bool ret = m_pOwner->output->commit();

View file

@ -70,7 +70,7 @@ class CMonitor {
bool primary = false; bool primary = false;
uint64_t ID = -1; MONITORID ID = MONITOR_INVALID;
PHLWORKSPACE activeWorkspace = nullptr; PHLWORKSPACE activeWorkspace = nullptr;
PHLWORKSPACE activeSpecialWorkspace = nullptr; PHLWORKSPACE activeSpecialWorkspace = nullptr;
float setScale = 1; // scale set by cfg float setScale = 1; // scale set by cfg
@ -121,8 +121,7 @@ class CMonitor {
// explicit sync // explicit sync
SP<CSyncTimeline> inTimeline; SP<CSyncTimeline> inTimeline;
SP<CSyncTimeline> outTimeline; SP<CSyncTimeline> outTimeline;
uint64_t lastWaitPoint = 0; uint64_t commitSeq = 0;
uint64_t commitSeq = 0;
WP<CMonitor> self; WP<CMonitor> self;
@ -156,31 +155,31 @@ class CMonitor {
std::array<std::vector<PHLLSREF>, 4> m_aLayerSurfaceLayers; std::array<std::vector<PHLLSREF>, 4> m_aLayerSurfaceLayers;
// methods // methods
void onConnect(bool noRule); void onConnect(bool noRule);
void onDisconnect(bool destroy = false); void onDisconnect(bool destroy = false);
void addDamage(const pixman_region32_t* rg); void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg); void addDamage(const CRegion* rg);
void addDamage(const CBox* box); void addDamage(const CBox* box);
bool shouldSkipScheduleFrameOnMouseEvent(); bool shouldSkipScheduleFrameOnMouseEvent();
void setMirror(const std::string&); void setMirror(const std::string&);
bool isMirror(); bool isMirror();
bool matchesStaticSelector(const std::string& selector) const; bool matchesStaticSelector(const std::string& selector) const;
float getDefaultScale(); float getDefaultScale();
void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false); void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false); void changeWorkspace(const WORKSPACEID& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace); void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace);
void setSpecialWorkspace(const int& id); void setSpecialWorkspace(const WORKSPACEID& id);
void moveTo(const Vector2D& pos); void moveTo(const Vector2D& pos);
Vector2D middle(); Vector2D middle();
void updateMatrix(); void updateMatrix();
int64_t activeWorkspaceID(); WORKSPACEID activeWorkspaceID();
int64_t activeSpecialWorkspaceID(); WORKSPACEID activeSpecialWorkspaceID();
CBox logicalBox(); CBox logicalBox();
void scheduleDone(); void scheduleDone();
bool attemptDirectScanout(); bool attemptDirectScanout();
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;
// For the list lookup // For the list lookup
@ -190,7 +189,7 @@ class CMonitor {
private: private:
void setupDefaultWS(const SMonitorRule&); void setupDefaultWS(const SMonitorRule&);
int findAvailableDefaultWS(); WORKSPACEID findAvailableDefaultWS();
wl_event_source* doneSource = nullptr; wl_event_source* doneSource = nullptr;

View file

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

View file

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

View file

@ -8,6 +8,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <string.h> #include <string.h>
#include <cstring>
namespace Systemd { namespace Systemd {
int SdBooted(void) { int SdBooted(void) {

View file

@ -8,7 +8,7 @@ std::chrono::steady_clock::duration CTimer::getDuration() {
return std::chrono::steady_clock::now() - m_tpLastReset; return std::chrono::steady_clock::now() - m_tpLastReset;
} }
int CTimer::getMillis() { long CTimer::getMillis() {
return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count(); return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count();
} }

View file

@ -6,7 +6,7 @@ class CTimer {
public: public:
void reset(); void reset();
float getSeconds(); float getSeconds();
int getMillis(); long getMillis();
const std::chrono::steady_clock::time_point& chrono() const; const std::chrono::steady_clock::time_point& chrono() const;
private: private:

View file

@ -18,15 +18,14 @@ CWatchdog::CWatchdog() {
m_pWatchdog = std::make_unique<std::thread>([this] { m_pWatchdog = std::make_unique<std::thread>([this] {
static auto PTIMEOUT = CConfigValue<Hyprlang::INT>("debug:watchdog_timeout"); static auto PTIMEOUT = CConfigValue<Hyprlang::INT>("debug:watchdog_timeout");
while (1337) { m_bWatchdogInitialized = true;
std::unique_lock lk(m_mWatchdogMutex); while (!m_bExitThread) {
std::unique_lock<std::mutex> lk(m_mWatchdogMutex);
if (!m_bWillWatch) if (!m_bWillWatch)
m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; }); m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified || m_bExitThread; });
else { else if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified || m_bExitThread; }) == false)
if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false) pthread_kill(m_iMainThreadPID, SIGUSR1);
pthread_kill(m_iMainThreadPID, SIGUSR1);
}
if (m_bExitThread) if (m_bExitThread)
break; break;

View file

@ -11,21 +11,23 @@ class CWatchdog {
CWatchdog(); CWatchdog();
~CWatchdog(); ~CWatchdog();
void startWatching(); void startWatching();
void endWatching(); void endWatching();
std::atomic<bool> m_bWatchdogInitialized{false};
private: private:
std::chrono::high_resolution_clock::time_point m_tTriggered; std::chrono::high_resolution_clock::time_point m_tTriggered;
pthread_t m_iMainThreadPID = 0; pthread_t m_iMainThreadPID = 0;
bool m_bWatching = false; std::atomic<bool> m_bWatching = false;
bool m_bWillWatch = false; std::atomic<bool> m_bWillWatch = false;
std::unique_ptr<std::thread> m_pWatchdog; std::unique_ptr<std::thread> m_pWatchdog;
std::mutex m_mWatchdogMutex; std::mutex m_mWatchdogMutex;
bool m_bNotified = false; std::atomic<bool> m_bNotified = false;
bool m_bExitThread = false; std::atomic<bool> m_bExitThread = false;
std::condition_variable m_cvWatchdogCondition; std::condition_variable m_cvWatchdogCondition;
}; };

View file

@ -0,0 +1,25 @@
#include "SyncReleaser.hpp"
#include "SyncTimeline.hpp"
#include "../../render/OpenGL.hpp"
CSyncReleaser::CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_) : timeline(timeline_), point(point_) {
;
}
CSyncReleaser::~CSyncReleaser() {
if (timeline.expired())
return;
if (sync)
timeline->importFromSyncFileFD(point, sync->fd());
else
timeline->signal(point);
}
void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync_) {
sync = sync_;
}
void CSyncReleaser::drop() {
timeline.reset();
}

View file

@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <optional>
#include <vector>
#include <functional>
#include "../memory/Memory.hpp"
/*
A helper (inspired by KDE's KWin) that will release the timeline point in the dtor
*/
class CSyncTimeline;
class CEGLSync;
class CSyncReleaser {
public:
CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_);
~CSyncReleaser();
// drops the releaser, will never signal anymore
void drop();
// wait for this gpu job to finish before releasing
void addReleaseSync(SP<CEGLSync> sync);
private:
WP<CSyncTimeline> timeline;
uint64_t point = 0;
SP<CEGLSync> sync;
};

View file

@ -188,3 +188,8 @@ bool CSyncTimeline::transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_
return true; return true;
} }
void CSyncTimeline::signal(uint64_t point) {
if (drmSyncobjTimelineSignal(drmFD, &handle, &point, 1))
Debug::log(ERR, "CSyncTimeline::signal: drmSyncobjTimelineSignal failed");
}

View file

@ -35,6 +35,7 @@ class CSyncTimeline {
int exportAsSyncFileFD(uint64_t src); int exportAsSyncFileFD(uint64_t src);
bool importFromSyncFileFD(uint64_t dst, int fd); bool importFromSyncFileFD(uint64_t dst, int fd);
bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint); bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint);
void signal(uint64_t point);
int drmFD = -1; int drmFD = -1;
uint32_t handle = 0; uint32_t handle = 0;

View file

@ -88,14 +88,14 @@ void CHyprError::createQueued() {
cairo_arc(CAIRO, X + RADIUS, Y + RADIUS, RADIUS, 180 * DEGREES, 270 * DEGREES); cairo_arc(CAIRO, X + RADIUS, Y + RADIUS, RADIUS, 180 * DEGREES, 270 * DEGREES);
cairo_close_path(CAIRO); cairo_close_path(CAIRO);
cairo_set_source_rgba(CAIRO, m_cQueued.r, m_cQueued.g, m_cQueued.b, m_cQueued.a); cairo_set_source_rgba(CAIRO, 0.06, 0.06, 0.06, 1.0);
cairo_fill_preserve(CAIRO); cairo_fill_preserve(CAIRO);
cairo_set_source_rgba(CAIRO, 0, 0, 0, 1); cairo_set_source_rgba(CAIRO, m_cQueued.r, m_cQueued.g, m_cQueued.b, m_cQueued.a);
cairo_set_line_width(CAIRO, 2); cairo_set_line_width(CAIRO, 2);
cairo_stroke(CAIRO); cairo_stroke(CAIRO);
// draw the text with a common font // draw the text with a common font
const CColor textColor = m_cQueued.r + m_cQueued.g + m_cQueued.b < 0.2f ? CColor(1.0, 1.0, 1.0, 1.0) : CColor(0, 0, 0, 1.0); const CColor textColor = CColor(0.9, 0.9, 0.9, 1.0);
cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a); cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a);
static auto fontFamily = CConfigValue<std::string>("misc:font_family"); static auto fontFamily = CConfigValue<std::string>("misc:font_family");

View file

@ -47,7 +47,7 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque<SDwindleNodeData*>* pD
} }
} }
int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) { int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) {
int no = 0; int no = 0;
for (auto& n : m_lDwindleNodesData) { for (auto& n : m_lDwindleNodesData) {
if (n.workspaceID == id && n.valid) if (n.workspaceID == id && n.valid)
@ -56,7 +56,7 @@ int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) {
return no; return no;
} }
SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) { SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const WORKSPACEID& id) {
for (auto& n : m_lDwindleNodesData) { for (auto& n : m_lDwindleNodesData) {
if (n.workspaceID == id && validMapped(n.pWindow)) if (n.workspaceID == id && validMapped(n.pWindow))
return &n; return &n;
@ -64,7 +64,7 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) {
return nullptr; return nullptr;
} }
SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) { SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const WORKSPACEID& id, const Vector2D& point) {
SDwindleNodeData* res = nullptr; SDwindleNodeData* res = nullptr;
double distClosest = -1; double distClosest = -1;
for (auto& n : m_lDwindleNodesData) { for (auto& n : m_lDwindleNodesData) {
@ -88,7 +88,7 @@ SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(PHLWINDOW pWindow) {
return nullptr; return nullptr;
} }
SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const int& id) { SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const WORKSPACEID& id) {
for (auto& n : m_lDwindleNodesData) { for (auto& n : m_lDwindleNodesData) {
if (!n.pParent && n.workspaceID == id) if (!n.pParent && n.workspaceID == id)
return &n; return &n;
@ -136,7 +136,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
return; return;
} }
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) if (PWINDOW->isFullscreen() && !pNode->ignoreFullscreenChecks)
return; return;
PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
@ -158,8 +158,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->workspaceID()); const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->workspaceID());
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (NODESONWORKSPACE == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) {
(NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
@ -178,6 +177,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
return; return;
} }
PWINDOW->updateWindowDecos();
auto calcPos = PWINDOW->m_vPosition; auto calcPos = PWINDOW->m_vPosition;
auto calcSize = PWINDOW->m_vSize; auto calcSize = PWINDOW->m_vSize;
@ -216,7 +217,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
calcPos = calcPos + RESERVED.topLeft; calcPos = calcPos + RESERVED.topLeft;
calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight);
if (PWINDOW->onSpecialWorkspace() && !PWINDOW->m_bIsFullscreen) { if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) {
// if special, we adjust the coords a bit // if special, we adjust the coords a bit
static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("dwindle:special_scale_factor"); static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("dwindle:special_scale_factor");
@ -245,8 +246,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} }
PWINDOW->updateWindowDecos();
} }
void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection direction) { void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection direction) {
@ -500,8 +499,8 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData(); pWindow->updateWindowData();
if (pWindow->m_bIsFullscreen) if (pWindow->isFullscreen())
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE);
const auto PPARENT = PNODE->pParent; const auto PPARENT = PNODE->pParent;
@ -536,7 +535,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
m_lDwindleNodesData.remove(*PNODE); m_lDwindleNodesData.remove(*PNODE);
} }
void CHyprDwindleLayout::recalculateMonitor(const int& monid) { void CHyprDwindleLayout::recalculateMonitor(const MONITORID& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
if (!PMONITOR || !PMONITOR->activeWorkspace) if (!PMONITOR || !PMONITOR->activeWorkspace)
@ -560,10 +559,10 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) {
// massive hack from the fullscreen func // massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID);
if (pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) { if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
} else if (pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) {
SDwindleNodeData fakeNode; SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW; fakeNode.pWindow = PFULLWINDOW;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight}; fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
@ -788,41 +787,19 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
} }
} }
void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscreenMode fullscreenMode, bool on) { void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) {
if (!validMapped(pWindow))
return;
if (on == pWindow->m_bIsFullscreen)
return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = pWindow->m_pWorkspace; const auto PWORKSPACE = pWindow->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && on) {
// if the window wants to be fullscreen but there already is one,
// ignore the request.
return;
}
// save position and size if floating // save position and size if floating
if (pWindow->m_bIsFloating && on) { if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vSize = pWindow->m_vRealSize.goal(); pWindow->m_vSize = pWindow->m_vRealSize.goal();
} }
// otherwise, accept it. if (EFFECTIVE_MODE == FSMODE_NONE) {
pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
pWindow->updateDynamicRules();
pWindow->updateWindowDecos();
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
EMIT_HOOK_EVENT("fullscreen", pWindow);
if (!pWindow->m_bIsFullscreen) {
// if it got its fullscreen disabled, set back its node if it had one // if it got its fullscreen disabled, set back its node if it had one
const auto PNODE = getNodeFromWindow(pWindow); const auto PNODE = getNodeFromWindow(pWindow);
if (PNODE) if (PNODE)
@ -836,12 +813,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscre
pWindow->updateWindowData(); pWindow->updateWindowData();
} }
} else { } else {
// if it now got fullscreen, make it fullscreen
PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// apply new pos and size being monitors' box // apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) { if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) {
pWindow->m_vRealPosition = PMONITOR->vecPosition; pWindow->m_vRealPosition = PMONITOR->vecPosition;
pWindow->m_vRealSize = PMONITOR->vecSize; pWindow->m_vRealSize = PMONITOR->vecSize;
} else { } else {
@ -861,13 +834,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscre
} }
} }
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal());
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
recalculateMonitor(PMONITOR->ID);
} }
void CHyprDwindleLayout::recalculateWindow(PHLWINDOW pWindow) { void CHyprDwindleLayout::recalculateWindow(PHLWINDOW pWindow) {
@ -905,7 +872,7 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir,
return; return;
const auto PNODE = getNodeFromWindow(pWindow); const auto PNODE = getNodeFromWindow(pWindow);
const int originalWorkspaceID = pWindow->workspaceID(); const auto originalWorkspaceID = pWindow->workspaceID();
const Vector2D originalPos = pWindow->middle(); const Vector2D originalPos = pWindow->middle();
if (!PNODE) if (!PNODE)
@ -957,13 +924,11 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) {
if (!PNODE2 || !PNODE) if (!PNODE2 || !PNODE)
return; return;
const bool FS1 = pWindow->m_bIsFullscreen; const eFullscreenMode MODE1 = pWindow->m_sFullscreenState.internal;
const bool FS2 = pWindow2->m_bIsFullscreen; const eFullscreenMode MODE2 = pWindow2->m_sFullscreenState.internal;
if (FS1) g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE);
g_pCompositor->setWindowFullscreen(pWindow, false); g_pCompositor->setWindowFullscreenInternal(pWindow2, FSMODE_NONE);
if (FS2)
g_pCompositor->setWindowFullscreen(pWindow2, false);
SDwindleNodeData* ACTIVE1 = nullptr; SDwindleNodeData* ACTIVE1 = nullptr;
SDwindleNodeData* ACTIVE2 = nullptr; SDwindleNodeData* ACTIVE2 = nullptr;
@ -1001,10 +966,8 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) {
g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow);
g_pHyprRenderer->damageWindow(pWindow2); g_pHyprRenderer->damageWindow(pWindow2);
if (FS1) g_pCompositor->setWindowFullscreenInternal(pWindow2, MODE1);
g_pCompositor->setWindowFullscreen(pWindow2, true); g_pCompositor->setWindowFullscreenInternal(pWindow, MODE2);
if (FS2)
g_pCompositor->setWindowFullscreen(pWindow, true);
} }
void CHyprDwindleLayout::alterSplitRatio(PHLWINDOW pWindow, float ratio, bool exact) { void CHyprDwindleLayout::alterSplitRatio(PHLWINDOW pWindow, float ratio, bool exact) {
@ -1072,7 +1035,7 @@ void CHyprDwindleLayout::toggleSplit(PHLWINDOW pWindow) {
if (!PNODE || !PNODE->pParent) if (!PNODE || !PNODE->pParent)
return; return;
if (pWindow->m_bIsFullscreen) if (pWindow->isFullscreen())
return; return;
PNODE->pParent->splitTop = !PNODE->pParent->splitTop; PNODE->pParent->splitTop = !PNODE->pParent->splitTop;
@ -1086,7 +1049,7 @@ void CHyprDwindleLayout::swapSplit(PHLWINDOW pWindow) {
if (!PNODE || !PNODE->pParent) if (!PNODE || !PNODE->pParent)
return; return;
if (pWindow->m_bIsFullscreen) if (pWindow->isFullscreen())
return; return;
std::swap(PNODE->pParent->children[0], PNODE->pParent->children[1]); std::swap(PNODE->pParent->children[0], PNODE->pParent->children[1]);

View file

@ -24,7 +24,7 @@ struct SDwindleNodeData {
CBox box = {0}; CBox box = {0};
int workspaceID = -1; WORKSPACEID workspaceID = WORKSPACE_INVALID;
float splitRatio = 1.f; float splitRatio = 1.f;
@ -48,11 +48,11 @@ class CHyprDwindleLayout : public IHyprLayout {
virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowRemovedTiling(PHLWINDOW); virtual void onWindowRemovedTiling(PHLWINDOW);
virtual bool isWindowTiled(PHLWINDOW); virtual bool isWindowTiled(PHLWINDOW);
virtual void recalculateMonitor(const int&); virtual void recalculateMonitor(const MONITORID&);
virtual void recalculateWindow(PHLWINDOW); virtual void recalculateWindow(PHLWINDOW);
virtual void onBeginDragWindow(); virtual void onBeginDragWindow();
virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr);
virtual void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool); virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE);
virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW); virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW);
virtual void switchWindows(PHLWINDOW, PHLWINDOW); virtual void switchWindows(PHLWINDOW, PHLWINDOW);
@ -77,13 +77,13 @@ class CHyprDwindleLayout : public IHyprLayout {
std::optional<Vector2D> m_vOverrideFocalPoint; // for onWindowCreatedTiling. std::optional<Vector2D> m_vOverrideFocalPoint; // for onWindowCreatedTiling.
int getNodesOnWorkspace(const int&); int getNodesOnWorkspace(const WORKSPACEID&);
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false); void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
void calculateWorkspace(const PHLWORKSPACE& pWorkspace); void calculateWorkspace(const PHLWORKSPACE& pWorkspace);
SDwindleNodeData* getNodeFromWindow(PHLWINDOW); SDwindleNodeData* getNodeFromWindow(PHLWINDOW);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&); SDwindleNodeData* getFirstNodeOnWorkspace(const WORKSPACEID&);
SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&); SDwindleNodeData* getClosestNodeOnWorkspace(const WORKSPACEID&, const Vector2D&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&); SDwindleNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&);
void toggleSplit(PHLWINDOW); void toggleSplit(PHLWINDOW);
void swapSplit(PHLWINDOW); void swapSplit(PHLWINDOW);

View file

@ -29,8 +29,8 @@ void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
} }
void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
if (pWindow->m_bIsFullscreen) if (pWindow->isFullscreen())
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE);
if (!pWindow->m_sGroupData.pNextWindow.expired()) { if (!pWindow->m_sGroupData.pNextWindow.expired()) {
if (pWindow->m_sGroupData.pNextWindow.lock() == pWindow) if (pWindow->m_sGroupData.pNextWindow.lock() == pWindow)
@ -187,20 +187,20 @@ void IHyprLayout::onBeginDragWindow() {
// Window will be floating. Let's check if it's valid. It should be, but I don't like crashing. // Window will be floating. Let's check if it's valid. It should be, but I don't like crashing.
if (!validMapped(DRAGGINGWINDOW)) { if (!validMapped(DRAGGINGWINDOW)) {
Debug::log(ERR, "Dragging attempted on an invalid window!"); Debug::log(ERR, "Dragging attempted on an invalid window!");
g_pInputManager->currentlyDraggedWindow.reset(); g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
return; return;
} }
if (DRAGGINGWINDOW->m_bIsFullscreen) { if (DRAGGINGWINDOW->isFullscreen()) {
Debug::log(LOG, "Dragging a fullscreen window"); Debug::log(LOG, "Dragging a fullscreen window");
g_pCompositor->setWindowFullscreen(DRAGGINGWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(DRAGGINGWINDOW, FSMODE_NONE);
} }
const auto PWORKSPACE = DRAGGINGWINDOW->m_pWorkspace; const auto PWORKSPACE = DRAGGINGWINDOW->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && (!DRAGGINGWINDOW->m_bCreatedOverFullscreen || !DRAGGINGWINDOW->m_bIsFloating)) { if (PWORKSPACE->m_bHasFullscreenWindow && (!DRAGGINGWINDOW->m_bCreatedOverFullscreen || !DRAGGINGWINDOW->m_bIsFloating)) {
Debug::log(LOG, "Rejecting drag on a fullscreen workspace. (window under fullscreen)"); Debug::log(LOG, "Rejecting drag on a fullscreen workspace. (window under fullscreen)");
g_pInputManager->currentlyDraggedWindow.reset(); g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
return; return;
} }
@ -288,7 +288,6 @@ void IHyprLayout::onEndDragWindow() {
} }
g_pInputManager->unsetCursorImage(); g_pInputManager->unsetCursorImage();
g_pInputManager->currentlyDraggedWindow.reset(); g_pInputManager->currentlyDraggedWindow.reset();
g_pInputManager->m_bWasDraggingWindow = true; g_pInputManager->m_bWasDraggingWindow = true;
@ -325,12 +324,14 @@ void IHyprLayout::onEndDragWindow() {
} }
void IHyprLayout::onMouseMove(const Vector2D& mousePos) { void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->currentlyDraggedWindow.expired())
return;
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock(); const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock();
// Window invalid or drag begin size 0,0 meaning we rejected it. // Window invalid or drag begin size 0,0 meaning we rejected it.
if (!validMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) { if ((!validMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D())) {
onEndDragWindow(); g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
g_pInputManager->currentlyDraggedWindow.reset();
return; return;
} }
@ -474,9 +475,9 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
if (pWindow->m_bIsFullscreen) { if (pWindow->isFullscreen()) {
Debug::log(LOG, "changeWindowFloatingMode: fullscreen"); Debug::log(LOG, "changeWindowFloatingMode: fullscreen");
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE);
} }
pWindow->m_bPinned = false; pWindow->m_bPinned = false;
@ -496,7 +497,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
const auto PWORKSPACE = PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace; const auto PWORKSPACE = PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false); g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FSMODE_NONE);
// save real pos cuz the func applies the default 5,5 mid // save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.goal(); const auto PSAVEDPOS = pWindow->m_vRealPosition.goal();

View file

@ -63,7 +63,7 @@ class IHyprLayout {
Called when the monitor requires a layout recalculation Called when the monitor requires a layout recalculation
this usually means reserved area changes this usually means reserved area changes
*/ */
virtual void recalculateMonitor(const int&) = 0; virtual void recalculateMonitor(const MONITORID&) = 0;
/* /*
Called when the compositor requests a window Called when the compositor requests a window
@ -110,7 +110,7 @@ class IHyprLayout {
The layout sets all the fullscreen flags. The layout sets all the fullscreen flags.
It can either accept or ignore. It can either accept or ignore.
*/ */
virtual void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool) = 0; virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) = 0;
/* /*
Called when a dispatcher requests a custom message Called when a dispatcher requests a custom message

View file

@ -14,7 +14,7 @@ SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(PHLWINDOW pWindow) {
return nullptr; return nullptr;
} }
int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) { int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) {
int no = 0; int no = 0;
for (auto& n : m_lMasterNodesData) { for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == ws) if (n.workspaceID == ws)
@ -24,7 +24,7 @@ int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
return no; return no;
} }
int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) { int CHyprMasterLayout::getMastersOnWorkspace(const WORKSPACEID& ws) {
int no = 0; int no = 0;
for (auto& n : m_lMasterNodesData) { for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == ws && n.isMaster) if (n.workspaceID == ws && n.isMaster)
@ -34,7 +34,7 @@ int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) {
return no; return no;
} }
SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) { SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const WORKSPACEID& ws) {
for (auto& n : m_lMasterWorkspacesData) { for (auto& n : m_lMasterWorkspacesData) {
if (n.workspaceID == ws) if (n.workspaceID == ws)
return &n; return &n;
@ -63,7 +63,7 @@ std::string CHyprMasterLayout::getLayoutName() {
return "Master"; return "Master";
} }
SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) { SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const WORKSPACEID& ws) {
for (auto& n : m_lMasterNodesData) { for (auto& n : m_lMasterNodesData) {
if (n.isMaster && n.workspaceID == ws) if (n.isMaster && n.workspaceID == ws)
return &n; return &n;
@ -267,7 +267,8 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->unsetWindowData(PRIORITY_LAYOUT);
pWindow->updateWindowData(); pWindow->updateWindowData();
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); if (pWindow->isFullscreen())
g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE);
if (PNODE->isMaster && (MASTERSLEFT <= 1 || *SMALLSPLIT == 1)) { if (PNODE->isMaster && (MASTERSLEFT <= 1 || *SMALLSPLIT == 1)) {
// find a new master from top of the list // find a new master from top of the list
@ -303,7 +304,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->m_iMonitorID);
} }
void CHyprMasterLayout::recalculateMonitor(const int& monid) { void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
if (!PMONITOR || !PMONITOR->activeWorkspace) if (!PMONITOR || !PMONITOR->activeWorkspace)
@ -327,10 +328,10 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
// massive hack from the fullscreen func // massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID);
if (pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) { if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
} else if (pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) {
SMasterNodeData fakeNode; SMasterNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW; fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@ -644,7 +645,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
// if user specified them in config // if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(PWINDOW->m_pWorkspace); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(PWINDOW->m_pWorkspace);
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) if (PWINDOW->isFullscreen() && !pNode->ignoreFullscreenChecks)
return; return;
PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->unsetWindowData(PRIORITY_LAYOUT);
@ -668,8 +669,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->m_vSize = pNode->size; PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position; PWINDOW->m_vPosition = pNode->position;
if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) {
(getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT);
PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT);
@ -688,6 +688,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
return; return;
} }
PWINDOW->updateWindowDecos();
auto calcPos = PWINDOW->m_vPosition; auto calcPos = PWINDOW->m_vPosition;
auto calcSize = PWINDOW->m_vSize; auto calcSize = PWINDOW->m_vSize;
@ -702,7 +704,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
calcPos = calcPos + RESERVED.topLeft; calcPos = calcPos + RESERVED.topLeft;
calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight);
if (PWINDOW->onSpecialWorkspace() && !PWINDOW->m_bIsFullscreen) { if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) {
static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("master:special_scale_factor"); static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("master:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
@ -730,8 +732,6 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} }
PWINDOW->updateWindowDecos();
} }
bool CHyprMasterLayout::isWindowTiled(PHLWINDOW pWindow) { bool CHyprMasterLayout::isWindowTiled(PHLWINDOW pWindow) {
@ -880,41 +880,19 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
m_bForceWarps = false; m_bForceWarps = false;
} }
void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscreenMode fullscreenMode, bool on) { void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) {
if (!validMapped(pWindow))
return;
if (on == pWindow->m_bIsFullscreen)
return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = pWindow->m_pWorkspace; const auto PWORKSPACE = pWindow->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && on) {
// if the window wants to be fullscreen but there already is one,
// ignore the request.
return;
}
// save position and size if floating // save position and size if floating
if (pWindow->m_bIsFloating && on) { if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vSize = pWindow->m_vRealSize.goal(); pWindow->m_vSize = pWindow->m_vRealSize.goal();
} }
// otherwise, accept it. if (EFFECTIVE_MODE == FSMODE_NONE) {
pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
pWindow->updateDynamicRules();
pWindow->updateWindowDecos();
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
EMIT_HOOK_EVENT("fullscreen", pWindow);
if (!pWindow->m_bIsFullscreen) {
// if it got its fullscreen disabled, set back its node if it had one // if it got its fullscreen disabled, set back its node if it had one
const auto PNODE = getNodeFromWindow(pWindow); const auto PNODE = getNodeFromWindow(pWindow);
if (PNODE) if (PNODE)
@ -928,12 +906,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree
pWindow->updateWindowData(); pWindow->updateWindowData();
} }
} else { } else {
// if it now got fullscreen, make it fullscreen
PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// apply new pos and size being monitors' box // apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) { if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) {
pWindow->m_vRealPosition = PMONITOR->vecPosition; pWindow->m_vRealPosition = PMONITOR->vecPosition;
pWindow->m_vRealSize = PMONITOR->vecSize; pWindow->m_vRealSize = PMONITOR->vecSize;
} else { } else {
@ -954,13 +928,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree
} }
} }
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal());
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
recalculateMonitor(PMONITOR->ID);
} }
void CHyprMasterLayout::recalculateWindow(PHLWINDOW pWindow) { void CHyprMasterLayout::recalculateWindow(PHLWINDOW pWindow) {
@ -1081,14 +1049,14 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!validMapped(PWINDOWTOCHANGETO)) if (!validMapped(PWINDOWTOCHANGETO))
return; return;
if (header.pWindow->m_bIsFullscreen) { if (header.pWindow->isFullscreen()) {
const auto PWORKSPACE = header.pWindow->m_pWorkspace; const auto PWORKSPACE = header.pWindow->m_pWorkspace;
const auto FSMODE = PWORKSPACE->m_efFullscreenMode; const auto FSMODE = header.pWindow->m_sFullscreenState.internal;
static auto INHERITFULLSCREEN = CConfigValue<Hyprlang::INT>("master:inherit_fullscreen"); static auto INHERITFULLSCREEN = CConfigValue<Hyprlang::INT>("master:inherit_fullscreen");
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
if (*INHERITFULLSCREEN) if (*INHERITFULLSCREEN)
g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE); g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, FSMODE);
} else { } else {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->middle()); g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->middle());
@ -1208,7 +1176,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true); const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true);
if (PWINDOWTOSWAPWITH) { if (PWINDOWTOSWAPWITH) {
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE);
switchWindows(header.pWindow, PWINDOWTOSWAPWITH); switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
switchToWindow(header.pWindow); switchToWindow(header.pWindow);
} }
@ -1224,7 +1192,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false); const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false);
if (PWINDOWTOSWAPWITH) { if (PWINDOWTOSWAPWITH) {
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenClient(header.pWindow, FSMODE_NONE);
switchWindows(header.pWindow, PWINDOWTOSWAPWITH); switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
switchToWindow(header.pWindow); switchToWindow(header.pWindow);
} }
@ -1243,7 +1211,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (MASTERS + 2 > WINDOWS && *SMALLSPLIT == 0) if (MASTERS + 2 > WINDOWS && *SMALLSPLIT == 0)
return 0; return 0;
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL);
g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE);
if (!PNODE || PNODE->isMaster) { if (!PNODE || PNODE->isMaster) {
// first non-master node // first non-master node
@ -1275,7 +1244,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (WINDOWS < 2 || MASTERS < 2) if (WINDOWS < 2 || MASTERS < 2)
return 0; return 0;
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE);
if (!PNODE || !PNODE->isMaster) { if (!PNODE || !PNODE->isMaster) {
// first non-master node // first non-master node
@ -1296,7 +1265,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!PWINDOW) if (!PWINDOW)
return 0; return 0;
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID()); const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID());
@ -1392,7 +1361,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi
if (!PWINDOW) if (!PWINDOW)
return; return;
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID()); const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID());

View file

@ -30,7 +30,7 @@ struct SMasterNodeData {
float percSize = 1.f; // size multiplier for resizing children float percSize = 1.f; // size multiplier for resizing children
int workspaceID = -1; WORKSPACEID workspaceID = WORKSPACE_INVALID;
bool ignoreFullscreenChecks = false; bool ignoreFullscreenChecks = false;
@ -41,7 +41,7 @@ struct SMasterNodeData {
}; };
struct SMasterWorkspaceData { struct SMasterWorkspaceData {
int workspaceID = -1; WORKSPACEID workspaceID = WORKSPACE_INVALID;
eOrientation orientation = ORIENTATION_LEFT; eOrientation orientation = ORIENTATION_LEFT;
// //
@ -55,10 +55,10 @@ class CHyprMasterLayout : public IHyprLayout {
virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowRemovedTiling(PHLWINDOW); virtual void onWindowRemovedTiling(PHLWINDOW);
virtual bool isWindowTiled(PHLWINDOW); virtual bool isWindowTiled(PHLWINDOW);
virtual void recalculateMonitor(const int&); virtual void recalculateMonitor(const MONITORID&);
virtual void recalculateWindow(PHLWINDOW); virtual void recalculateWindow(PHLWINDOW);
virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr);
virtual void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool); virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE);
virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW); virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW);
virtual void switchWindows(PHLWINDOW, PHLWINDOW); virtual void switchWindows(PHLWINDOW, PHLWINDOW);
@ -81,14 +81,14 @@ class CHyprMasterLayout : public IHyprLayout {
void buildOrientationCycleVectorFromEOperation(std::vector<eOrientation>& cycle); void buildOrientationCycleVectorFromEOperation(std::vector<eOrientation>& cycle);
void runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int next); void runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int next);
eOrientation getDynamicOrientation(PHLWORKSPACE); eOrientation getDynamicOrientation(PHLWORKSPACE);
int getNodesOnWorkspace(const int&); int getNodesOnWorkspace(const WORKSPACEID&);
void applyNodeDataToWindow(SMasterNodeData*); void applyNodeDataToWindow(SMasterNodeData*);
SMasterNodeData* getNodeFromWindow(PHLWINDOW); SMasterNodeData* getNodeFromWindow(PHLWINDOW);
SMasterNodeData* getMasterNodeOnWorkspace(const int&); SMasterNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&);
SMasterWorkspaceData* getMasterWorkspaceData(const int&); SMasterWorkspaceData* getMasterWorkspaceData(const WORKSPACEID&);
void calculateWorkspace(PHLWORKSPACE); void calculateWorkspace(PHLWORKSPACE);
PHLWINDOW getNextWindow(PHLWINDOW, bool); PHLWINDOW getNextWindow(PHLWINDOW, bool);
int getMastersOnWorkspace(const int&); int getMastersOnWorkspace(const WORKSPACEID&);
friend struct SMasterNodeData; friend struct SMasterNodeData;
friend struct SMasterWorkspaceData; friend struct SMasterWorkspaceData;

View file

@ -27,6 +27,8 @@
#define WORKSPACE_INVALID -1L #define WORKSPACE_INVALID -1L
#define WORKSPACE_NOT_CHANGED -101 #define WORKSPACE_NOT_CHANGED -101
#define MONITOR_INVALID -1L
#define LISTENER(name) \ #define LISTENER(name) \
void listener_##name(wl_listener*, void*); \ void listener_##name(wl_listener*, void*); \
inline wl_listener listen_##name = {.notify = listener_##name} inline wl_listener listen_##name = {.notify = listener_##name}

View file

@ -3,15 +3,10 @@
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "PointerManager.hpp" #include "PointerManager.hpp"
#include "../xwayland/XWayland.hpp" #include "../xwayland/XWayland.hpp"
#include <cstring>
#include "../helpers/CursorShapes.hpp"
extern "C" { static int cursorAnimTimer(SP<CEventLoopTimer> self, void* data) {
#include <X11/Xcursor/Xcursor.h> const auto cursorMgr = reinterpret_cast<CCursorManager*>(data);
} cursorMgr->tickAnimatedCursor();
static int cursorAnimTimer(void* data) {
g_pCursorManager->tickAnimatedCursor();
return 1; return 1;
} }
@ -22,85 +17,39 @@ static void hcLogger(enum eHyprcursorLogLevel level, char* message) {
Debug::log(NONE, "[hc] {}", message); Debug::log(NONE, "[hc] {}", message);
} }
CCursorManager::CCursorManager() { CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger);
if (!m_pHyprcursor->valid())
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme);
// find default size. First, HYPRCURSOR_SIZE, then XCURSOR_SIZE, then 24
auto SIZE = getenv("HYPRCURSOR_SIZE");
if (SIZE) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
SIZE = getenv("XCURSOR_SIZE");
if (SIZE && m_iSize == 0) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
if (m_iSize == 0)
m_iSize = 24;
xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale));
m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
updateTheme();
static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateTheme(); });
}
CCursorManager::~CCursorManager() {
if (m_pAnimationTimer)
wl_event_source_remove(m_pAnimationTimer);
}
void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; });
}
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
surface = surf; surface = surf;
size = size_; size = size_;
stride = cairo_image_surface_get_stride(surf); stride = cairo_image_surface_get_stride(surf);
} }
CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
pixelData = pixelData_; pixelData = pixelData_;
size = size_; size = size_;
stride = 4 * size_.x; stride = 4 * size_.x;
} }
CCursorManager::CCursorBuffer::~CCursorBuffer() { Aquamarine::eBufferCapability CCursorBuffer::caps() {
;
}
Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() {
return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
} }
Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() { Aquamarine::eBufferType CCursorBuffer::type() {
return Aquamarine::eBufferType::BUFFER_TYPE_SHM; return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
} }
void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) { void CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) {
; ;
} }
bool CCursorManager::CCursorBuffer::isSynchronous() { bool CCursorBuffer::isSynchronous() {
return true; return true;
} }
bool CCursorManager::CCursorBuffer::good() { bool CCursorBuffer::good() {
return true; return true;
} }
Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() { Aquamarine::SSHMAttrs CCursorBuffer::shm() {
Aquamarine::SSHMAttrs attrs; Aquamarine::SSHMAttrs attrs;
attrs.success = true; attrs.success = true;
attrs.format = DRM_FORMAT_ARGB8888; attrs.format = DRM_FORMAT_ARGB8888;
@ -109,14 +58,70 @@ Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() {
return attrs; return attrs;
} }
std::tuple<uint8_t*, uint32_t, size_t> CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) { std::tuple<uint8_t*, uint32_t, size_t> CCursorBuffer::beginDataPtr(uint32_t flags) {
return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride}; return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride};
} }
void CCursorManager::CCursorBuffer::endDataPtr() { void CCursorBuffer::endDataPtr() {
; ;
} }
CCursorManager::CCursorManager() {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger);
m_pXcursor = std::make_unique<CXCursorManager>();
static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("cursor:enable_hyprcursor");
if (m_pHyprcursor->valid() && *PUSEHYPRCURSOR) {
// find default size. First, HYPRCURSOR_SIZE then default to 24
auto const* SIZE = getenv("HYPRCURSOR_SIZE");
if (SIZE) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
if (m_iSize <= 0) {
Debug::log(WARN, "HYPRCURSOR_SIZE size not set, defaulting to size 24");
m_iSize = 24;
}
} else {
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to Xcursor.", m_szTheme);
auto const* SIZE = getenv("XCURSOR_SIZE");
if (SIZE) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
if (m_iSize <= 0) {
Debug::log(WARN, "XCURSOR_SIZE size not set, defaulting to size 24");
m_iSize = 24;
}
}
// since we fallback to xcursor always load it on startup. otherwise we end up with a empty theme if hyprcursor is enabled in the config
// and then later is disabled.
m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale));
m_pAnimationTimer = makeShared<CEventLoopTimer>(std::nullopt, cursorAnimTimer, this);
g_pEventLoopManager->addTimer(m_pAnimationTimer);
updateTheme();
static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateTheme(); });
}
CCursorManager::~CCursorManager() {
if (m_pAnimationTimer && g_pEventLoopManager) {
g_pEventLoopManager->removeTimer(m_pAnimationTimer);
m_pAnimationTimer.reset();
}
if (m_pHyprcursor->valid() && m_sCurrentStyleInfo.size > 0)
m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo);
}
SP<Aquamarine::IBuffer> CCursorManager::getCursorBuffer() { SP<Aquamarine::IBuffer> CCursorManager::getCursorBuffer() {
return !m_vCursorBuffers.empty() ? m_vCursorBuffers.back() : nullptr; return !m_vCursorBuffers.empty() ? m_vCursorBuffers.back() : nullptr;
} }
@ -130,106 +135,126 @@ void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotsp
m_bOurBufferConnected = false; m_bOurBufferConnected = false;
} }
void CCursorManager::setXCursor(const std::string& name) { void CCursorManager::setCursorBuffer(SP<CCursorBuffer> buf, const Vector2D& hotspot, const float& scale) {
float scale = std::ceil(m_fCursorScale); m_vCursorBuffers.emplace_back(buf);
g_pPointerManager->setCursorBuffer(getCursorBuffer(), hotspot, scale);
if (!xcursor.themeLoaded) {
Debug::log(ERR, "XCursor failed to find theme in setXCursor");
g_pPointerManager->resetCursorImage();
return;
}
auto& icon = xcursor.defaultCursor;
// try to get an icon we know if we have one
if (xcursor.cursors.contains(name))
icon = xcursor.cursors.at(name);
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot));
g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon->hotspot / scale, scale);
if (m_vCursorBuffers.size() > 1) if (m_vCursorBuffers.size() > 1)
dropBufferRef(m_vCursorBuffers.at(0).get()); std::erase_if(m_vCursorBuffers, [this](const auto& buf) { return buf.get() == m_vCursorBuffers.front().get(); });
m_bOurBufferConnected = true; m_bOurBufferConnected = true;
} }
void CCursorManager::setAnimationTimer(const int& frame, const int& delay) {
if (delay > 0) {
// arm
m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(delay));
} else {
// disarm
m_pAnimationTimer->updateTimeout(std::nullopt);
}
m_iCurrentAnimationFrame = frame;
}
void CCursorManager::setCursorFromName(const std::string& name) { void CCursorManager::setCursorFromName(const std::string& name) {
static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("cursor:enable_hyprcursor"); static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("cursor:enable_hyprcursor");
if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) { auto setXCursor = [this](auto const& name) {
setXCursor(name); float scale = std::ceil(m_fCursorScale);
return;
}
m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo); auto xcursor = m_pXcursor->getShape(name, m_iSize * scale);
auto& icon = xcursor->images.front();
auto buf = makeShared<CCursorBuffer>((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot);
setCursorBuffer(buf, icon.hotspot / scale, scale);
if (m_sCurrentCursorShapeData.images.size() < 1) { m_currentXcursor = xcursor;
// try with '_' first (old hc, etc)
std::string newName = name;
std::replace(newName.begin(), newName.end(), '-', '_');
m_sCurrentCursorShapeData = m_pHyprcursor->getShape(newName.c_str(), m_sCurrentStyleInfo); int delay = 0;
} int frame = 0;
if (m_currentXcursor->images.size() > 1)
delay = m_currentXcursor->images[frame].delay;
if (m_sCurrentCursorShapeData.images.size() < 1) { setAnimationTimer(frame, delay);
// fallback to a default if available };
constexpr const std::array<const char*, 3> fallbackShapes = {"default", "left_ptr", "left-ptr"};
for (auto& s : fallbackShapes) { auto setHyprCursor = [this](auto const& name) {
m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo); m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo);
if (m_sCurrentCursorShapeData.images.size() > 0) if (m_sCurrentCursorShapeData.images.size() < 1) {
break; // try with '_' first (old hc, etc)
std::string newName = name;
std::replace(newName.begin(), newName.end(), '-', '_');
m_sCurrentCursorShapeData = m_pHyprcursor->getShape(newName.c_str(), m_sCurrentStyleInfo);
} }
if (m_sCurrentCursorShapeData.images.size() < 1) { if (m_sCurrentCursorShapeData.images.size() < 1) {
Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); // fallback to a default if available
setXCursor(name); constexpr const std::array<const char*, 3> fallbackShapes = {"default", "left_ptr", "left-ptr"};
return;
for (auto& s : fallbackShapes) {
m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo);
if (m_sCurrentCursorShapeData.images.size() > 0)
break;
}
if (m_sCurrentCursorShapeData.images.size() < 1) {
Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName");
return false;
}
} }
}
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface, auto buf =
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, makeShared<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface, Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY});
auto hotspot = Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale;
setCursorBuffer(buf, hotspot, m_fCursorScale);
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale, int delay = 0;
m_fCursorScale); int frame = 0;
if (m_vCursorBuffers.size() > 1) if (m_sCurrentCursorShapeData.images.size() > 1)
dropBufferRef(m_vCursorBuffers.at(0).get()); delay = m_sCurrentCursorShapeData.images[frame].delay;
m_bOurBufferConnected = true; setAnimationTimer(frame, delay);
return true;
};
if (m_sCurrentCursorShapeData.images.size() > 1) { if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR || !setHyprCursor(name))
// animated setXCursor(name);
wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[0].delay);
m_iCurrentAnimationFrame = 0;
} else {
// disarm
wl_event_source_timer_update(m_pAnimationTimer, 0);
}
} }
void CCursorManager::tickAnimatedCursor() { void CCursorManager::tickAnimatedCursor() {
if (m_sCurrentCursorShapeData.images.size() < 2 || !m_bOurBufferConnected) if (!m_bOurBufferConnected)
return; return;
m_iCurrentAnimationFrame++; if (!m_pHyprcursor->valid() && m_currentXcursor->images.size() > 1) {
if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) m_iCurrentAnimationFrame++;
m_iCurrentAnimationFrame = 0;
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>( if ((size_t)m_iCurrentAnimationFrame >= m_currentXcursor->images.size())
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, m_iCurrentAnimationFrame = 0;
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size},
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));
g_pPointerManager->setCursorBuffer( float scale = std::ceil(m_fCursorScale);
getCursorBuffer(), auto& icon = m_currentXcursor->images.at(m_iCurrentAnimationFrame);
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale, auto buf = makeShared<CCursorBuffer>((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot);
m_fCursorScale); setCursorBuffer(buf, icon.hotspot / scale, scale);
setAnimationTimer(m_iCurrentAnimationFrame, m_currentXcursor->images[m_iCurrentAnimationFrame].delay);
} else if (m_sCurrentCursorShapeData.images.size() > 1) {
m_iCurrentAnimationFrame++;
wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay); if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size())
m_iCurrentAnimationFrame = 0;
auto hotspot =
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale;
auto buf = makeShared<CCursorBuffer>(
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface,
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size},
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY});
setCursorBuffer(buf, hotspot, m_fCursorScale);
setAnimationTimer(m_iCurrentAnimationFrame, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay);
}
} }
SCursorImageData CCursorManager::dataFor(const std::string& name) { SCursorImageData CCursorManager::dataFor(const std::string& name) {
@ -246,32 +271,39 @@ SCursorImageData CCursorManager::dataFor(const std::string& name) {
} }
void CCursorManager::setXWaylandCursor() { void CCursorManager::setXWaylandCursor() {
const auto CURSOR = dataFor("left_ptr"); static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("cursor:enable_hyprcursor");
if (CURSOR.surface) { const auto CURSOR = dataFor("left_ptr");
if (CURSOR.surface && *PUSEHYPRCURSOR)
g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size},
{CURSOR.hotspotX, CURSOR.hotspotY}); {CURSOR.hotspotX, CURSOR.hotspotY});
} else if (xcursor.themeLoaded) else {
g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot); auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale));
else auto& icon = xcursor->images.front();
Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
g_pXWayland->setCursor((uint8_t*)icon.pixels.data(), icon.size.x * 4, icon.size, icon.hotspot);
}
} }
void CCursorManager::updateTheme() { void CCursorManager::updateTheme() {
float highestScale = 1.0; static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("cursor:enable_hyprcursor");
float highestScale = 1.0;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->scale > highestScale) if (m->scale > highestScale)
highestScale = m->scale; highestScale = m->scale;
} }
if (m_sCurrentStyleInfo.size && m_pHyprcursor->valid()) m_fCursorScale = highestScale;
m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo);
m_sCurrentStyleInfo.size = std::round(m_iSize * highestScale); if (*PUSEHYPRCURSOR) {
m_fCursorScale = highestScale; if (m_sCurrentStyleInfo.size > 0 && m_pHyprcursor->valid())
m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo);
if (m_pHyprcursor->valid()) m_sCurrentStyleInfo.size = std::round(m_iSize * highestScale);
m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo);
if (m_pHyprcursor->valid())
m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo);
}
setCursorFromName("left_ptr"); setCursorFromName("left_ptr");
@ -282,177 +314,27 @@ void CCursorManager::updateTheme() {
} }
bool CCursorManager::changeTheme(const std::string& name, const int size) { bool CCursorManager::changeTheme(const std::string& name, const int size) {
auto options = Hyprcursor::SManagerOptions(); static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("cursor:enable_hyprcursor");
options.logFn = hcLogger; m_szTheme = name.empty() ? "" : name;
options.allowDefaultFallback = false; m_iSize = size <= 0 ? 24 : size;
auto xcursor_theme = getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default";
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str(), options); if (*PUSEHYPRCURSOR) {
if (m_pHyprcursor->valid()) { auto options = Hyprcursor::SManagerOptions();
m_szTheme = name; options.logFn = hcLogger;
m_iSize = size; options.allowDefaultFallback = false;
updateTheme(); m_szTheme = name.empty() ? "" : name;
return true; m_iSize = size;
}
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name); m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options);
if (!m_pHyprcursor->valid()) {
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", m_szTheme);
m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize);
}
} else
m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize);
xcursor.loadTheme(name, size);
m_szTheme = name;
m_iSize = size;
updateTheme(); updateTheme();
return true; return true;
} }
// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
// however modified to fit wayland cursor shape names better.
// _ -> -
// clang-format off
static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
"X_cursor",
"default", // arrow
"ns-resize", // based-arrow-down
"ns-resize", // based-arrow-up
"boat",
"bogosity",
"sw-resize", // bottom-left-corner
"se-resize", // bottom-right-corner
"s-resize", // bottom-side
"bottom-tee",
"box-spiral",
"center-ptr",
"circle",
"clock",
"coffee-mug",
"cross",
"cross-reverse",
"crosshair",
"diamond-cross",
"dot",
"dotbox",
"double-arrow",
"draft-large",
"draft-small",
"draped-box",
"exchange",
"move", // fleur
"gobbler",
"gumby",
"pointer", // hand1
"grabbing", // hand2
"heart",
"icon",
"iron-cross",
"default", // left-ptr
"w-resize", // left-side
"left-tee",
"leftbutton",
"ll-angle",
"lr-angle",
"man",
"middlebutton",
"mouse",
"pencil",
"pirate",
"plus",
"help", // question-arrow
"right-ptr",
"e-resize", // right-side
"right-tee",
"rightbutton",
"rtl-logo",
"sailboat",
"ns-resize", // sb-down-arrow
"ew-resize", // sb-h-double-arrow
"ew-resize", // sb-left-arrow
"ew-resize", // sb-right-arrow
"n-resize", // sb-up-arrow
"s-resize", // sb-v-double-arrow
"shuttle",
"sizing",
"spider",
"spraycan",
"star",
"target",
"cell", // tcross
"nw-resize", // top-left-arrow
"nw-resize", // top-left-corner
"ne-resize", // top-right-corner
"n-resize", // top-side
"top-tee",
"trek",
"ul-angle",
"umbrella",
"ur-angle",
"wait", // watch
"text", // xterm
};
// clang-format on
void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) {
if (lastLoadSize == size && themeName == name)
return;
lastLoadSize = size;
themeLoaded = false;
themeName = name.empty() ? "default" : name;
auto img = XcursorShapeLoadImage(2, themeName.c_str(), size);
if (!img) {
Debug::log(ERR, "XCursor failed finding theme \"{}\". Trying size 24.", themeName);
size = 24;
img = XcursorShapeLoadImage(2, themeName.c_str(), size);
if (!img) {
Debug::log(ERR, "XCursor failed finding theme \"{}\".", themeName);
return;
}
}
defaultCursor = makeShared<SXCursor>();
defaultCursor->size = {(int)img->width, (int)img->height};
defaultCursor->hotspot = {(int)img->xhot, (int)img->yhot};
defaultCursor->pixels.resize(img->width * img->height);
std::memcpy(defaultCursor->pixels.data(), img->pixels, img->width * img->height * sizeof(uint32_t));
themeLoaded = true;
XcursorImageDestroy(img);
// gather as many shapes as we can find.
cursors.clear();
for (auto& shape : CURSOR_SHAPE_NAMES) {
int id = -1;
for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
if (XCURSOR_STANDARD_NAMES.at(i) == std::string{shape}) {
id = i;
break;
}
}
if (id < 0) {
Debug::log(LOG, "XCursor has no shape {}, skipping", shape);
continue;
}
auto xImage = XcursorShapeLoadImage(id << 1 /* wtf xcursor? */, themeName.c_str(), size);
if (!xImage) {
Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape);
continue;
}
auto xcursor = makeShared<SXCursor>();
xcursor->size = {(int)xImage->width, (int)xImage->height};
xcursor->hotspot = {(int)xImage->xhot, (int)xImage->yhot};
xcursor->pixels.resize(xImage->width * xImage->height);
std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
cursors.emplace(std::string{shape}, xcursor);
XcursorImageDestroy(xImage);
}
}

View file

@ -7,12 +7,36 @@
#include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include "managers/XCursorManager.hpp"
#include <aquamarine/buffer/Buffer.hpp> #include <aquamarine/buffer/Buffer.hpp>
class CWLSurface; class CWLSurface;
AQUAMARINE_FORWARD(IBuffer); AQUAMARINE_FORWARD(IBuffer);
class CCursorBuffer : public Aquamarine::IBuffer {
public:
CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot);
CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot);
~CCursorBuffer() = default;
virtual Aquamarine::eBufferCapability caps();
virtual Aquamarine::eBufferType type();
virtual void update(const Hyprutils::Math::CRegion& damage);
virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu
virtual bool good();
virtual Aquamarine::SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
private:
Vector2D hotspot;
cairo_surface_t* surface = nullptr;
uint8_t* pixelData = nullptr;
size_t stride = 0;
};
class CCursorManager { class CCursorManager {
public: public:
CCursorManager(); CCursorManager();
@ -22,7 +46,8 @@ class CCursorManager {
void setCursorFromName(const std::string& name); void setCursorFromName(const std::string& name);
void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot); void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot);
void setXCursor(const std::string& name); void setCursorBuffer(SP<CCursorBuffer> buf, const Vector2D& hotspot, const float& scale);
void setAnimationTimer(const int& frame, const int& delay);
bool changeTheme(const std::string& name, const int size); bool changeTheme(const std::string& name, const int size);
void updateTheme(); void updateTheme();
@ -31,38 +56,13 @@ class CCursorManager {
void tickAnimatedCursor(); void tickAnimatedCursor();
class CCursorBuffer : public Aquamarine::IBuffer {
public:
CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot);
CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot);
~CCursorBuffer();
virtual Aquamarine::eBufferCapability caps();
virtual Aquamarine::eBufferType type();
virtual void update(const Hyprutils::Math::CRegion& damage);
virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu
virtual bool good();
virtual Aquamarine::SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
private:
Vector2D hotspot;
cairo_surface_t* surface = nullptr;
uint8_t* pixelData = nullptr;
size_t stride = 0;
friend class CCursorManager;
};
void dropBufferRef(CCursorBuffer* ref);
bool m_bOurBufferConnected = false;
private: private:
bool m_bOurBufferConnected = false;
std::vector<SP<CCursorBuffer>> m_vCursorBuffers; std::vector<SP<CCursorBuffer>> m_vCursorBuffers;
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor; std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;
std::unique_ptr<CXCursorManager> m_pXcursor;
SP<SXCursors> m_currentXcursor;
std::string m_szTheme = ""; std::string m_szTheme = "";
int m_iSize = 0; int m_iSize = 0;
@ -70,28 +70,9 @@ class CCursorManager {
Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo; Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo;
wl_event_source* m_pAnimationTimer = nullptr; SP<CEventLoopTimer> m_pAnimationTimer;
int m_iCurrentAnimationFrame = 0; int m_iCurrentAnimationFrame = 0;
Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData;
// gangsta bootleg XCursor impl. Whenever Hyprland has to use
// an xcursor, just use the pointer.
struct SXCursor {
Vector2D size;
Vector2D hotspot;
std::vector<uint32_t> pixels; // XPixel is a u32
};
struct SXCursorManager {
void loadTheme(const std::string& name, int size);
int lastLoadSize = 0;
bool themeLoaded = false;
std::string themeName = "";
SP<SXCursor> defaultCursor;
std::unordered_map<std::string, SP<SXCursor>> cursors;
} xcursor;
}; };
inline std::unique_ptr<CCursorManager> g_pCursorManager; inline std::unique_ptr<CCursorManager> g_pCursorManager;

View file

@ -8,6 +8,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <cstring>
CEventManager::CEventManager() { CEventManager::CEventManager() {
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);

View file

@ -3,6 +3,7 @@
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/ShortcutsInhibit.hpp" #include "../protocols/ShortcutsInhibit.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../devices/IKeyboard.hpp" #include "../devices/IKeyboard.hpp"
#include "KeybindManager.hpp" #include "KeybindManager.hpp"
@ -67,7 +68,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["workspace"] = changeworkspace; m_mDispatchers["workspace"] = changeworkspace;
m_mDispatchers["renameworkspace"] = renameWorkspace; m_mDispatchers["renameworkspace"] = renameWorkspace;
m_mDispatchers["fullscreen"] = fullscreenActive; m_mDispatchers["fullscreen"] = fullscreenActive;
m_mDispatchers["fakefullscreen"] = fakeFullscreenActive; m_mDispatchers["fullscreenstate"] = fullscreenStateActive;
m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace; m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace;
m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent; m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent;
m_mDispatchers["pseudo"] = toggleActivePseudo; m_mDispatchers["pseudo"] = toggleActivePseudo;
@ -179,6 +180,9 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
} }
uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) { uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) {
if (keycode == 0)
return 0;
switch (keycode - 8) { switch (keycode - 8) {
case KEY_LEFTMETA: return HL_MODIFIER_META; case KEY_LEFTMETA: return HL_MODIFIER_META;
case KEY_RIGHTMETA: return HL_MODIFIER_META; case KEY_RIGHTMETA: return HL_MODIFIER_META;
@ -242,27 +246,14 @@ void CKeybindManager::updateXKBTranslationState() {
} }
bool CKeybindManager::ensureMouseBindState() { bool CKeybindManager::ensureMouseBindState() {
if (!m_bIsMouseBindActive) if (!g_pInputManager->currentlyDraggedWindow)
return false; return false;
if (!g_pInputManager->currentlyDraggedWindow.expired()) { if (!g_pInputManager->currentlyDraggedWindow.expired()) {
PHLWINDOW lastDraggedWindow = g_pInputManager->currentlyDraggedWindow.lock(); changeMouseBindMode(MBIND_INVALID);
m_bIsMouseBindActive = false;
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
g_pInputManager->currentlyDraggedWindow.reset();
g_pInputManager->dragMode = MBIND_INVALID;
g_pCompositor->updateWorkspaceWindows(lastDraggedWindow->workspaceID());
g_pCompositor->updateWorkspaceWindowData(lastDraggedWindow->workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(lastDraggedWindow->m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
return true; return true;
} }
m_bIsMouseBindActive = false;
return false; return false;
} }
@ -331,17 +322,17 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
// remove constraints // remove constraints
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
if (PLASTWINDOW && PLASTWINDOW->m_pWorkspace == PWINDOWTOCHANGETO->m_pWorkspace && PLASTWINDOW->m_bIsFullscreen) { if (PLASTWINDOW && PLASTWINDOW->m_pWorkspace == PWINDOWTOCHANGETO->m_pWorkspace && PLASTWINDOW->isFullscreen()) {
const auto PWORKSPACE = PLASTWINDOW->m_pWorkspace; const auto PWORKSPACE = PLASTWINDOW->m_pWorkspace;
const auto FSMODE = PWORKSPACE->m_efFullscreenMode; const auto MODE = PWORKSPACE->m_efFullscreenMode;
if (!PWINDOWTOCHANGETO->m_bPinned) if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreen(PLASTWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(PLASTWINDOW, FSMODE_NONE);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
if (!PWINDOWTOCHANGETO->m_bPinned) if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE); g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE);
} else { } else {
updateRelativeCursorCoords(); updateRelativeCursorCoords();
g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
@ -540,10 +531,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) {
} }
void CKeybindManager::resizeWithBorder(const IPointer::SButtonEvent& e) { void CKeybindManager::resizeWithBorder(const IPointer::SButtonEvent& e) {
if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) changeMouseBindMode(e.state == WL_POINTER_BUTTON_STATE_PRESSED ? MBIND_RESIZE : MBIND_INVALID);
mouse("1resizewindow");
else
mouse("0resizewindow");
} }
void CKeybindManager::onSwitchEvent(const std::string& switchName) { void CKeybindManager::onSwitchEvent(const std::string& switchName) {
@ -654,18 +642,17 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
if (found || key.submapAtPress != m_szCurrentSelectedSubmap) if (found || key.submapAtPress != m_szCurrentSelectedSubmap)
continue; continue;
} else { } else {
// in this case, we only have the keysym to go off. // in this case, we only have the keysym to go off of for this keybind, and it's invalid
// if the keysym failed resolving, we can't do anything. It's likely missing // since there might be something like keycode to match with other keybinds, try the next
// from the keymap. if (key.keysym == XKB_KEY_NoSymbol)
if (key.keysym == 0) continue;
return false;
// oMg such performance hit!!11! // oMg such performance hit!!11!
// this little maneouver is gonna cost us 4µs // this little maneouver is gonna cost us 4µs
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS); const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS);
const auto KBKEYLOWER = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); const auto KBKEYLOWER = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
if (KBKEY == 0 && KBKEYLOWER == 0) { if (KBKEY == XKB_KEY_NoSymbol && KBKEYLOWER == XKB_KEY_NoSymbol) {
// Keysym failed to resolve from the key name of the currently iterated bind. // Keysym failed to resolve from the key name of the currently iterated bind.
// This happens for names such as `switch:off:Lid Switch` as well as some keys // This happens for names such as `switch:off:Lid Switch` as well as some keys
// (such as yen and ro). // (such as yen and ro).
@ -971,7 +958,8 @@ static void toggleActiveFloatingCore(std::string args, std::optional<bool> float
return; return;
// remove drag status // remove drag status
g_pInputManager->currentlyDraggedWindow.reset(); if (!g_pInputManager->currentlyDraggedWindow.expired())
g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
if (PWINDOW->m_sGroupData.pNextWindow.lock() && PWINDOW->m_sGroupData.pNextWindow.lock() != PWINDOW) { if (PWINDOW->m_sGroupData.pNextWindow.lock() && PWINDOW->m_sGroupData.pNextWindow.lock() != PWINDOW) {
const auto PCURRENT = PWINDOW->getGroupCurrent(); const auto PCURRENT = PWINDOW->getGroupCurrent();
@ -1010,7 +998,7 @@ void CKeybindManager::setActiveTiled(std::string args) {
void CKeybindManager::centerWindow(std::string args) { void CKeybindManager::centerWindow(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->isFullscreen())
return; return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
@ -1036,7 +1024,7 @@ void CKeybindManager::toggleActivePseudo(std::string args) {
PWINDOW->m_bIsPseudotiled = !PWINDOW->m_bIsPseudotiled; PWINDOW->m_bIsPseudotiled = !PWINDOW->m_bIsPseudotiled;
if (!PWINDOW->m_bIsFullscreen) if (!PWINDOW->isFullscreen())
g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW);
} }
@ -1163,10 +1151,51 @@ void CKeybindManager::fullscreenActive(std::string args) {
if (!PWINDOW) if (!PWINDOW)
return; return;
PWINDOW->m_bDontSendFullscreen = false; const eFullscreenMode MODE = args == "1" ? FSMODE_MAXIMIZED : FSMODE_FULLSCREEN;
if (args == "2")
PWINDOW->m_bDontSendFullscreen = true; if (PWINDOW->isEffectiveInternalFSMode(MODE))
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
else
g_pCompositor->setWindowFullscreenInternal(PWINDOW, MODE);
}
void CKeybindManager::fullscreenStateActive(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
const auto ARGS = CVarList(args, 2, ' ');
if (!PWINDOW)
return;
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP);
int internalMode, clientMode;
try {
internalMode = std::stoi(ARGS[0]);
} catch (std::exception& e) { internalMode = -1; }
try {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = -1; }
const sFullscreenState STATE = sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal),
.client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)};
if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) {
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE});
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP);
return;
}
if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) {
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client});
return;
}
if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) {
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE});
return;
}
g_pCompositor->setWindowFullscreenState(PWINDOW, STATE);
} }
void CKeybindManager::moveActiveToWorkspace(std::string args) { void CKeybindManager::moveActiveToWorkspace(std::string args) {
@ -1291,7 +1320,7 @@ void CKeybindManager::moveFocusTo(std::string args) {
return; return;
} }
const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->m_bIsFullscreen ? const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ?
(arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) : (arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) :
g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
@ -1348,7 +1377,7 @@ void CKeybindManager::swapActive(std::string args) {
Debug::log(LOG, "Swapping active window in direction {}", arg); Debug::log(LOG, "Swapping active window in direction {}", arg);
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) if (!PLASTWINDOW || PLASTWINDOW->isFullscreen())
return; return;
const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
@ -1386,7 +1415,7 @@ void CKeybindManager::moveActiveTo(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) if (!PLASTWINDOW || PLASTWINDOW->isFullscreen())
return; return;
if (PLASTWINDOW->m_bIsFloating) { if (PLASTWINDOW->m_bIsFloating) {
@ -1441,7 +1470,8 @@ void CKeybindManager::toggleGroup(std::string args) {
if (!PWINDOW) if (!PWINDOW)
return; return;
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); if (PWINDOW->isFullscreen())
g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
if (PWINDOW->m_sGroupData.pNextWindow.expired()) if (PWINDOW->m_sGroupData.pNextWindow.expired())
PWINDOW->createGroup(); PWINDOW->createGroup();
@ -1710,7 +1740,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
return; return;
} }
const int WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; const auto WORKSPACEID = getWorkspaceIDNameFromString(workspace).id;
if (WORKSPACEID == WORKSPACE_INVALID) { if (WORKSPACEID == WORKSPACE_INVALID) {
Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!"); Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!");
@ -1728,7 +1758,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
} }
void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
int workspaceID = getWorkspaceIDNameFromString(args).id; auto workspaceID = getWorkspaceIDNameFromString(args).id;
if (workspaceID == WORKSPACE_INVALID) { if (workspaceID == WORKSPACE_INVALID) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
return; return;
@ -1788,7 +1818,7 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) {
bool requestedWorkspaceIsAlreadyOpen = false; bool requestedWorkspaceIsAlreadyOpen = false;
const auto PMONITOR = g_pCompositor->m_pLastMonitor; const auto PMONITOR = g_pCompositor->m_pLastMonitor;
int specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID(); auto specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID();
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->activeSpecialWorkspaceID() == workspaceID) { if (m->activeSpecialWorkspaceID() == workspaceID) {
@ -1833,7 +1863,7 @@ void CKeybindManager::forceRendererReload(std::string args) {
void CKeybindManager::resizeActive(std::string args) { void CKeybindManager::resizeActive(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) if (!PLASTWINDOW || PLASTWINDOW->isFullscreen())
return; return;
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize.goal()); const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize.goal());
@ -1850,7 +1880,7 @@ void CKeybindManager::resizeActive(std::string args) {
void CKeybindManager::moveActive(std::string args) { void CKeybindManager::moveActive(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) if (!PLASTWINDOW || PLASTWINDOW->isFullscreen())
return; return;
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition.goal()); const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition.goal());
@ -1870,7 +1900,7 @@ void CKeybindManager::moveWindow(std::string args) {
return; return;
} }
if (PWINDOW->m_bIsFullscreen) if (PWINDOW->isFullscreen())
return; return;
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal()); const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal());
@ -1890,7 +1920,7 @@ void CKeybindManager::resizeWindow(std::string args) {
return; return;
} }
if (PWINDOW->m_bIsFullscreen) if (PWINDOW->isFullscreen())
return; return;
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal()); const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal());
@ -1967,12 +1997,12 @@ void CKeybindManager::focusWindow(std::string regexp) {
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
} else { } else {
if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned) if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned)
g_pCompositor->setWindowFullscreen(FSWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenClient(FSWINDOW, FSMODE_NONE);
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned) if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned)
g_pCompositor->setWindowFullscreen(PWINDOW, true, FSMODE); g_pCompositor->setWindowFullscreenClient(PWINDOW, FSMODE);
} }
} else } else
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
@ -2264,6 +2294,7 @@ void CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port) if (!port.empty() && m->szName != port)
continue; continue;
m->output->state->resetExplicitFences();
m->output->state->setEnabled(enable); m->output->state->setEnabled(enable);
m->dpmsStatus = enable; m->dpmsStatus = enable;
@ -2344,11 +2375,19 @@ void CKeybindManager::pinActive(std::string args) {
return; return;
} }
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen())
return; return;
PWINDOW->m_bPinned = !PWINDOW->m_bPinned; PWINDOW->m_bPinned = !PWINDOW->m_bPinned;
PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (!PMONITOR) {
Debug::log(ERR, "pin: monitor not found");
return;
}
PWINDOW->m_pWorkspace = PMONITOR->activeWorkspace;
PWINDOW->updateDynamicRules(); PWINDOW->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
@ -2365,55 +2404,50 @@ void CKeybindManager::mouse(std::string args) {
const auto ARGS = CVarList(args.substr(1), 2, ' '); const auto ARGS = CVarList(args.substr(1), 2, ' ');
const auto PRESSED = args[0] == '1'; const auto PRESSED = args[0] == '1';
if (!PRESSED) {
changeMouseBindMode(MBIND_INVALID);
return;
}
if (ARGS[0] == "movewindow") { if (ARGS[0] == "movewindow") {
if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) { changeMouseBindMode(MBIND_MOVE);
g_pKeybindManager->m_bIsMouseBindActive = true; } else {
try {
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); switch (std::stoi(ARGS[1])) {
PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); case 1: changeMouseBindMode(MBIND_RESIZE_FORCE_RATIO); break;
case 2: changeMouseBindMode(MBIND_RESIZE_BLOCK_RATIO); break;
if (pWindow && !pWindow->m_bIsFullscreen) default: changeMouseBindMode(MBIND_RESIZE);
pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_START, mouseCoords);
if (g_pInputManager->currentlyDraggedWindow.expired())
g_pInputManager->currentlyDraggedWindow = pWindow;
g_pInputManager->dragMode = MBIND_MOVE;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
} else if (!PRESSED && g_pInputManager->dragMode == MBIND_MOVE) {
g_pKeybindManager->m_bIsMouseBindActive = false;
if (!g_pInputManager->currentlyDraggedWindow.expired()) {
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
g_pInputManager->currentlyDraggedWindow.reset();
g_pInputManager->dragMode = MBIND_INVALID;
} }
} } catch (std::exception& e) { changeMouseBindMode(MBIND_RESIZE); }
} else if (ARGS[0] == "resizewindow") { }
if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) { }
g_pKeybindManager->m_bIsMouseBindActive = true;
g_pInputManager->currentlyDraggedWindow = void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) {
g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (MODE != MBIND_INVALID) {
if (!g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode != MBIND_INVALID)
return;
try { const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
switch (std::stoi(ARGS[1])) { const PHLWINDOW PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
case 1: g_pInputManager->dragMode = MBIND_RESIZE_FORCE_RATIO; break;
case 2: g_pInputManager->dragMode = MBIND_RESIZE_BLOCK_RATIO; break;
default: g_pInputManager->dragMode = MBIND_RESIZE;
}
} catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; }
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
} else if (!PRESSED &&
(g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO || g_pInputManager->dragMode == MBIND_RESIZE)) {
g_pKeybindManager->m_bIsMouseBindActive = false;
if (!g_pInputManager->currentlyDraggedWindow.expired()) { if (!PWINDOW)
g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); return;
g_pInputManager->currentlyDraggedWindow.reset();
g_pInputManager->dragMode = MBIND_INVALID; if (!PWINDOW->isFullscreen() && MODE == MBIND_MOVE)
} PWINDOW->checkInputOnDecos(INPUT_TYPE_DRAG_START, MOUSECOORDS);
}
if (g_pInputManager->currentlyDraggedWindow.expired())
g_pInputManager->currentlyDraggedWindow = PWINDOW;
g_pInputManager->dragMode = MODE;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
} else {
if (g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode == MBIND_INVALID)
return;
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
g_pInputManager->dragMode = MODE;
} }
} }
@ -2447,14 +2481,6 @@ void CKeybindManager::alterZOrder(std::string args) {
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
} }
void CKeybindManager::fakeFullscreenActive(std::string args) {
if (!g_pCompositor->m_pLastWindow.expired()) {
// will also set the flag
g_pCompositor->m_pLastWindow->m_bFakeFullscreenState = !g_pCompositor->m_pLastWindow->m_bFakeFullscreenState;
g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow.lock(), g_pCompositor->m_pLastWindow->shouldSendFullscreenState());
}
}
void CKeybindManager::lockGroups(std::string args) { void CKeybindManager::lockGroups(std::string args) {
if (args == "lock" || args.empty() || args == "lockgroups") if (args == "lock" || args.empty() || args == "lockgroups")
g_pKeybindManager->m_bGroupsLocked = true; g_pKeybindManager->m_bGroupsLocked = true;
@ -2614,7 +2640,7 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
} }
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
if (!PWINDOW || PWINDOW->m_bIsFullscreen) if (!PWINDOW || PWINDOW->isFullscreen())
return; return;
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) { if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) {
@ -2684,10 +2710,10 @@ void CKeybindManager::global(std::string args) {
if (NAME.empty()) if (NAME.empty())
return; return;
if (!g_pProtocolManager->m_pGlobalShortcutsProtocolManager->globalShortcutExists(APPID, NAME)) if (!PROTO::globalShortcuts->isTaken(APPID, NAME))
return; return;
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed); PROTO::globalShortcuts->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed);
} }
void CKeybindManager::moveGroupWindow(std::string args) { void CKeybindManager::moveGroupWindow(std::string args) {

View file

@ -105,6 +105,8 @@ class CKeybindManager {
//we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts) //we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts)
std::unordered_map<std::string, xkb_keycode_t> m_mKeyToCodeCache; std::unordered_map<std::string, xkb_keycode_t> m_mKeyToCodeCache;
static void changeMouseBindMode(const eMouseBindMode mode);
private: private:
std::deque<SPressedKeyWithMods> m_dPressedKeys; std::deque<SPressedKeyWithMods> m_dPressedKeys;
@ -116,7 +118,6 @@ class CKeybindManager {
uint32_t m_uLastCode = 0; uint32_t m_uLastCode = 0;
uint32_t m_uLastMouseCode = 0; uint32_t m_uLastMouseCode = 0;
bool m_bIsMouseBindActive = false;
std::vector<SKeybind*> m_vPressedSpecialBinds; std::vector<SKeybind*> m_vPressedSpecialBinds;
int m_iPassPressed = -1; // used for pass int m_iPassPressed = -1; // used for pass
@ -154,7 +155,7 @@ class CKeybindManager {
static void setActiveTiled(std::string); static void setActiveTiled(std::string);
static void changeworkspace(std::string); static void changeworkspace(std::string);
static void fullscreenActive(std::string); static void fullscreenActive(std::string);
static void fakeFullscreenActive(std::string); static void fullscreenStateActive(std::string args);
static void moveActiveToWorkspace(std::string); static void moveActiveToWorkspace(std::string);
static void moveActiveToWorkspaceSilent(std::string); static void moveActiveToWorkspaceSilent(std::string);
static void moveFocusTo(std::string); static void moveFocusTo(std::string);

View file

@ -4,19 +4,28 @@
#include "../protocols/PointerGestures.hpp" #include "../protocols/PointerGestures.hpp"
#include "../protocols/FractionalScale.hpp" #include "../protocols/FractionalScale.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/core/Seat.hpp"
#include "eventLoop/EventLoopManager.hpp" #include "eventLoop/EventLoopManager.hpp"
#include "SeatManager.hpp" #include "SeatManager.hpp"
#include <cstring> #include <cstring>
#include <gbm.h> #include <gbm.h>
CPointerManager::CPointerManager() { CPointerManager::CPointerManager() {
hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) {
auto PMONITOR = std::any_cast<SP<CMonitor>>(data); auto PMONITOR = std::any_cast<CMonitor*>(data)->self.lock();
onMonitorLayoutChange(); onMonitorLayoutChange();
PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.modeChanged.registerStaticListener(
PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); [this, PMONITOR](void* owner, std::any data) {
g_pEventLoopManager->doLater([this, PMONITOR]() {
onMonitorLayoutChange();
checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name);
});
},
nullptr);
PMONITOR->events.disconnect.registerStaticListener(
[this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr);
PMONITOR->events.destroy.registerStaticListener( PMONITOR->events.destroy.registerStaticListener(
[this](void* owner, std::any data) { [this](void* owner, std::any data) {
if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown)
@ -25,7 +34,7 @@ CPointerManager::CPointerManager() {
nullptr); nullptr);
}); });
hooks.monitorPreRender = g_pHookSystem->hookDynamic("preRender", [this](void* self, SCallbackInfo& info, std::any data) { hooks.monitorPreRender = g_pHookSystem->hookDynamic("preMonitorCommit", [this](void* self, SCallbackInfo& info, std::any data) {
auto state = stateFor(std::any_cast<CMonitor*>(data)->self.lock()); auto state = stateFor(std::any_cast<CMonitor*>(data)->self.lock());
if (!state) if (!state)
return; return;
@ -34,6 +43,38 @@ CPointerManager::CPointerManager() {
}); });
} }
void CPointerManager::checkDefaultCursorWarp(SP<CMonitor> monitor, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
const auto POS = monitor->middle();
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if (firstLaunch) {
firstLaunch = false;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
return;
}
if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) {
if (*PCURSORMONITOR == monitorName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
return;
}
}
// modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed.
if (g_pCompositor->getMonitorFromCursor() == monitor.get()) {
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void CPointerManager::lockSoftwareAll() { void CPointerManager::lockSoftwareAll() {
for (auto& state : monitorStates) for (auto& state : monitorStates)
state->softwareLocks++; state->softwareLocks++;
@ -151,18 +192,20 @@ void CPointerManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hots
currentCursorImage.surface = surf; currentCursorImage.surface = surf;
currentCursorImage.scale = surf->resource()->current.scale; currentCursorImage.scale = surf->resource()->current.scale;
surf->resource()->map();
currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); }); currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); });
currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) { currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) {
damageIfSoftware(); damageIfSoftware();
currentCursorImage.size = currentCursorImage.surface->resource()->current.buffer ? currentCursorImage.surface->resource()->current.buffer->size : Vector2D{}; currentCursorImage.size = currentCursorImage.surface->resource()->current.texture ? currentCursorImage.surface->resource()->current.bufferSize : Vector2D{};
currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F; currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F;
recheckEnteredOutputs(); recheckEnteredOutputs();
updateCursorBackend(); updateCursorBackend();
damageIfSoftware(); damageIfSoftware();
}); });
if (surf->resource()->current.buffer) { if (surf->resource()->current.texture) {
currentCursorImage.size = surf->resource()->current.buffer->size; currentCursorImage.size = surf->resource()->current.bufferSize;
timespec now; timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
surf->resource()->frame(&now); surf->resource()->frame(&now);
@ -222,6 +265,8 @@ void CPointerManager::resetCursorImage(bool apply) {
currentCursorImage.surface->resource()->leave(m); currentCursorImage.surface->resource()->leave(m);
} }
currentCursorImage.surface->resource()->unmap();
currentCursorImage.destroySurface.reset(); currentCursorImage.destroySurface.reset();
currentCursorImage.commitSurface.reset(); currentCursorImage.commitSurface.reset();
currentCursorImage.surface.reset(); currentCursorImage.surface.reset();
@ -426,16 +471,39 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
// clear buffer // clear buffer
memset(bufPtr, 0, std::get<2>(bufData)); memset(bufPtr, 0, std::get<2>(bufData));
auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; if (currentCursorImage.pBuffer) {
auto texAttrs = currentCursorImage.pBuffer->shm();
if (texBuffer) { if (!texAttrs.success) {
auto textAttrs = texBuffer->shm(); Debug::log(TRACE, "Cannot use dumb copy on dmabuf cursor buffers");
auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); return nullptr;
auto texPtr = std::get<0>(texData); }
Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride);
auto texData = currentCursorImage.pBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE);
auto texPtr = std::get<0>(texData);
Debug::log(TRACE, "cursor texture {}x{} {} {} {}", texAttrs.size.x, texAttrs.size.y, (void*)texPtr, texAttrs.format, texAttrs.stride);
// copy cursor texture // copy cursor texture
for (int i = 0; i < texBuffer->shm().size.y; i++) for (int i = 0; i < texAttrs.size.y; i++)
memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride); memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * texAttrs.stride, texAttrs.stride);
} else if (currentCursorImage.surface && currentCursorImage.surface->resource()->role->role() == SURFACE_ROLE_CURSOR) {
const auto SURFACE = currentCursorImage.surface->resource();
auto& shmBuffer = CCursorSurfaceRole::cursorPixelData(SURFACE);
Debug::log(TRACE, "cursor texture pixel data length: {}B", shmBuffer.size());
if (shmBuffer.data()) {
// copy cursor texture
// assume format is 32bpp
size_t STRIDE = 4 * SURFACE->current.bufferSize.x;
for (int i = 0; i < SURFACE->current.bufferSize.y; i++)
memcpy(bufPtr + i * buf->dmabuf().strides[0], shmBuffer.data() + i * STRIDE, STRIDE);
} else {
// if there is no data, hide the cursor
memset(bufPtr, '\0', buf->size.x * buf->size.y * 4 /* assume 32bpp */);
}
} else {
Debug::log(TRACE, "Unsupported cursor buffer/surface, falling back to sw (can't dumb copy)");
return nullptr;
} }
buf->endDataPtr(); buf->endDataPtr();
@ -674,6 +742,32 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
} }
break; break;
} }
case HID_TYPE_POINTER: {
IPointer* POINTER = reinterpret_cast<IPointer*>(dev.get());
if (!POINTER->boundOutput.empty()) {
if (POINTER->boundOutput == "entire") {
// find x and y size of the entire space
Vector2D bottomRight = {-9999999, -9999999}, topLeft = {9999999, 9999999};
for (auto& m : g_pCompositor->m_vMonitors) {
const auto EXTENT = m->logicalBox().extent();
const auto POS = m->logicalBox().pos();
if (EXTENT.x > bottomRight.x)
bottomRight.x = EXTENT.x;
if (EXTENT.y > bottomRight.y)
bottomRight.y = EXTENT.y;
if (POS.x < topLeft.x)
topLeft.x = POS.x;
if (POS.y < topLeft.y)
topLeft.y = POS.y;
}
mappedArea = {topLeft, bottomRight - topLeft};
} else if (const auto PMONITOR = g_pCompositor->getMonitorFromString(POINTER->boundOutput); PMONITOR) {
currentMonitor = PMONITOR->self.lock();
mappedArea = currentMonitor->logicalBox();
}
}
break;
}
default: break; default: break;
} }
@ -710,7 +804,7 @@ void CPointerManager::onMonitorLayoutChange() {
} }
SP<CTexture> CPointerManager::getCurrentCursorTexture() { SP<CTexture> CPointerManager::getCurrentCursorTexture() {
if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.buffer)) if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.texture))
return nullptr; return nullptr;
if (currentCursorImage.pBuffer) { if (currentCursorImage.pBuffer) {
@ -719,7 +813,7 @@ SP<CTexture> CPointerManager::getCurrentCursorTexture() {
return currentCursorImage.bufferTex; return currentCursorImage.bufferTex;
} }
return currentCursorImage.surface->resource()->current.buffer->texture; return currentCursorImage.surface->resource()->current.texture;
} }
void CPointerManager::attachPointer(SP<IPointer> pointer) { void CPointerManager::attachPointer(SP<IPointer> pointer) {

View file

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

View file

@ -41,6 +41,8 @@
#include "../protocols/DRMSyncobj.hpp" #include "../protocols/DRMSyncobj.hpp"
#include "../protocols/Screencopy.hpp" #include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp" #include "../protocols/ToplevelExport.hpp"
#include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "../protocols/core/Seat.hpp" #include "../protocols/core/Seat.hpp"
#include "../protocols/core/DataDevice.hpp" #include "../protocols/core/DataDevice.hpp"
@ -74,7 +76,7 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
CProtocolManager::CProtocolManager() { CProtocolManager::CProtocolManager() {
static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("experimental:explicit_sync"); static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
// Outputs are a bit dumb, we have to agree. // Outputs are a bit dumb, we have to agree.
static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) {
@ -125,6 +127,7 @@ CProtocolManager::CProtocolManager() {
PROTO::pointerGestures = std::make_unique<CPointerGesturesProtocol>(&zwp_pointer_gestures_v1_interface, 3, "PointerGestures"); PROTO::pointerGestures = std::make_unique<CPointerGesturesProtocol>(&zwp_pointer_gestures_v1_interface, 3, "PointerGestures");
PROTO::foreignToplevelWlr = std::make_unique<CForeignToplevelWlrProtocol>(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr"); PROTO::foreignToplevelWlr = std::make_unique<CForeignToplevelWlrProtocol>(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr");
PROTO::shortcutsInhibit = std::make_unique<CKeyboardShortcutsInhibitProtocol>(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); PROTO::shortcutsInhibit = std::make_unique<CKeyboardShortcutsInhibitProtocol>(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit");
PROTO::textInputV1 = std::make_unique<CTextInputV1Protocol>(&zwp_text_input_manager_v1_interface, 1, "TextInputV1");
PROTO::textInputV3 = std::make_unique<CTextInputV3Protocol>(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); PROTO::textInputV3 = std::make_unique<CTextInputV3Protocol>(&zwp_text_input_manager_v3_interface, 1, "TextInputV3");
PROTO::constraints = std::make_unique<CPointerConstraintsProtocol>(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::constraints = std::make_unique<CPointerConstraintsProtocol>(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints");
PROTO::outputPower = std::make_unique<COutputPowerProtocol>(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); PROTO::outputPower = std::make_unique<COutputPowerProtocol>(&zwlr_output_power_manager_v1_interface, 1, "OutputPower");
@ -146,6 +149,7 @@ CProtocolManager::CProtocolManager() {
PROTO::xwaylandShell = std::make_unique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell"); PROTO::xwaylandShell = std::make_unique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell");
PROTO::screencopy = std::make_unique<CScreencopyProtocol>(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::screencopy = std::make_unique<CScreencopyProtocol>(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy");
PROTO::toplevelExport = std::make_unique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); 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");
for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) {
if (b->type() != Aquamarine::AQ_BACKEND_DRM) if (b->type() != Aquamarine::AQ_BACKEND_DRM)
@ -162,11 +166,6 @@ CProtocolManager::CProtocolManager() {
PROTO::linuxDma = std::make_unique<CLinuxDMABufV1Protocol>(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); PROTO::linuxDma = std::make_unique<CLinuxDMABufV1Protocol>(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF");
} else } else
Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available"); Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.
m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>();
m_pGlobalShortcutsProtocolManager = std::make_unique<CGlobalShortcutsProtocolManager>();
} }
CProtocolManager::~CProtocolManager() { CProtocolManager::~CProtocolManager() {
@ -197,6 +196,7 @@ CProtocolManager::~CProtocolManager() {
PROTO::pointerGestures.reset(); PROTO::pointerGestures.reset();
PROTO::foreignToplevelWlr.reset(); PROTO::foreignToplevelWlr.reset();
PROTO::shortcutsInhibit.reset(); PROTO::shortcutsInhibit.reset();
PROTO::textInputV1.reset();
PROTO::textInputV3.reset(); PROTO::textInputV3.reset();
PROTO::constraints.reset(); PROTO::constraints.reset();
PROTO::outputPower.reset(); PROTO::outputPower.reset();
@ -218,6 +218,7 @@ CProtocolManager::~CProtocolManager() {
PROTO::xwaylandShell.reset(); PROTO::xwaylandShell.reset();
PROTO::screencopy.reset(); PROTO::screencopy.reset();
PROTO::toplevelExport.reset(); PROTO::toplevelExport.reset();
PROTO::globalShortcuts.reset();
PROTO::lease.reset(); PROTO::lease.reset();
PROTO::sync.reset(); PROTO::sync.reset();

View file

@ -1,8 +1,6 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../helpers/memory/Memory.hpp" #include "../helpers/memory/Memory.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
@ -13,10 +11,6 @@ class CProtocolManager {
CProtocolManager(); CProtocolManager();
~CProtocolManager(); ~CProtocolManager();
// TODO: rewrite to use the new protocol framework
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager;
private: private:
std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners; std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners;

View file

@ -71,7 +71,8 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
g_pHyprRenderer->damageMonitor(m.get()); g_pHyprRenderer->damageMonitor(m.get());
}); });
m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([](std::any data) { m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([this](std::any data) {
m_pSessionLock.reset();
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusSurface(nullptr);
for (auto& m : g_pCompositor->m_vMonitors) for (auto& m : g_pCompositor->m_vMonitors)
@ -104,7 +105,7 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64
// We don't want the red screen to flash. // We don't want the red screen to flash.
float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) {
if (!m_pSessionLock) if (!m_pSessionLock)
return 0.F; return 1.F;
const auto& NOMAPPEDSURFACETIMER = m_pSessionLock->mMonitorsWithoutMappedSurfaceTimers.find(id); const auto& NOMAPPEDSURFACETIMER = m_pSessionLock->mMonitorsWithoutMappedSurfaceTimers.find(id);
@ -123,7 +124,7 @@ void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) {
m_pSessionLock->m_lockedMonitors.emplace(id); m_pSessionLock->m_lockedMonitors.emplace(id);
const auto MONITORS = g_pCompositor->m_vMonitors; const auto MONITORS = g_pCompositor->m_vMonitors;
const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); });
if (LOCKED) { if (LOCKED && m_pSessionLock->lock->good()) {
m_pSessionLock->lock->sendLocked(); m_pSessionLock->lock->sendLocked();
m_pSessionLock->m_hasSentLocked = true; m_pSessionLock->m_hasSentLocked = true;
} }

View file

@ -0,0 +1,603 @@
#include <cstring>
#include <dirent.h>
#include <filesystem>
#include <gio/gio.h>
#include <gio/gsettingsschema.h>
#include "config/ConfigValue.hpp"
#include "helpers/CursorShapes.hpp"
#include "debug/Log.hpp"
#include "XCursorManager.hpp"
// clang-format off
static std::vector<uint32_t> HYPR_XCURSOR_PIXELS = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1b001816, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8e008173, 0x5f00564d, 0x16001412, 0x09000807, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b002624, 0x05000404, 0x00000000, 0x35002f2b, 0xd400bead,
0xc300b09e, 0x90008275, 0x44003e37, 0x04000403, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x67005a56,
0x6f00615c, 0x00000000, 0x00000000, 0x8b007c72, 0xf200d7c6, 0xfa00e0cc, 0xe800d0bd, 0xa0009181, 0x44003e37, 0x1a001815, 0x06000505, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x8d007976, 0xd600b8b3, 0x2500201f, 0x00000000, 0x17001413, 0xbd00a79c, 0xf600dacb, 0xff00e3d1, 0xfc00e1ce, 0xe800d0bc, 0xbf00ac9b,
0x95008778, 0x51004a41, 0x0f000e0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92007b7b, 0xf500d0cf, 0x9e008685, 0x00000000, 0x00000000, 0x23001f1d, 0x64005853,
0x9b008980, 0xd900bfb3, 0xfb00dfce, 0xff00e4d0, 0xfb00e1cd, 0xec00d5c0, 0xa7009788, 0x47004139, 0x1e001b18, 0x05000504, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa200878a, 0xff00d6d9, 0xd600b4b5,
0x0e000c0c, 0x00000000, 0x00000000, 0x02000202, 0x0c000b0a, 0x30002a28, 0x8e007d75, 0xd600bdb0, 0xef00d4c4, 0xfb00e0ce, 0xff00e4d0, 0xe600cfbb, 0xb800a695, 0x5f00564d,
0x06000505, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x02000202, 0xc600a3aa, 0xff00d3da, 0xea00c3c8, 0x08000707, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x2a002523, 0x61005550, 0x9500837b,
0xd800bfb1, 0xfd00e1cf, 0xff00e5d0, 0xf500dcc7, 0x7c007065, 0x2a002622, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000505, 0xd600aeb9, 0xff00d0dc, 0xcc00a7af, 0x04000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x01000101, 0x01000101, 0x2c002724, 0xa1008e85, 0xe600ccbd, 0xf800ddcb, 0xef00d6c3, 0xc300af9f, 0x2c002824, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, 0xd800adbc, 0xff00cdde, 0xb90095a0, 0x02000202, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000e0d, 0x4b00423e, 0xa4009088, 0xfd00dfd0, 0xff00e3d1,
0xae009c8f, 0x42003b36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x14001012, 0xf400c0d6,
0xff00cadf, 0xb2008e9c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x02000202, 0x1200100f, 0xa2008e86, 0xec00cfc3, 0xfc00ded0, 0xc300ada0, 0x15001311, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x2e002429, 0xfd00c4e0, 0xff00c7e2, 0x8f00707e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1e001a19, 0x75006662, 0xfb00dbd1, 0xf700d9cc, 0x9600847c, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e002f37, 0xfc00c1e1, 0xff00c5e3, 0x60004b55, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x15001212, 0xa6008f8b, 0xff00ddd5,
0xf800d8ce, 0x36002f2d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x51003d49, 0xfe00bfe5, 0xfe00c1e4, 0x4c003a44,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x01000101, 0x1d001918, 0xf400d1cd, 0xfe00dad5, 0xb3009a96, 0x03000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x66004b5d, 0xff00bee7, 0xfd00bee5, 0x4500343f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000202, 0x82006e6e, 0xff00d8d7, 0xd800b9b6, 0x33002c2b, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70005267, 0xff00bbe9, 0xfa00b8e3, 0x29001e25, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f003536, 0xea00c3c7, 0xf800d1d3,
0x4a003e3f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5f004458, 0xff00b8eb, 0xf400b1e0, 0x29001e26, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x1b001617, 0xe100bac0, 0xff00d4da, 0x82006c6f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5a004054, 0xfe00b4eb,
0xfb00b3e8, 0x3b002a36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0a000809, 0xc900a4ad, 0xff00d1dc, 0x88007075, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x44002f3f, 0xf300aae3, 0xfc00b1ea, 0x48003343, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000404, 0xdf00b3c2, 0xff00cedd, 0x8f00747c, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x25001a23, 0xf200a6e4, 0xff00b1ef, 0x84005c7c, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708,
0xe400b5c8, 0xff00cbdf, 0x78006068, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x12000c11, 0xc00082b6, 0xff00aef1, 0xaa0075a0,
0x11000c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x1e00171b, 0xf700c1db, 0xff00c8e1, 0x4b003b42, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x05000305, 0x8d005f86, 0xfc00aaef, 0xed00a0e1, 0x26001a24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6f005463, 0xff00c4e3, 0xf500beda, 0x0c00090b, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e00293b, 0xed009de2, 0xff00aaf3, 0x8b005d84, 0x04000304, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x07000506, 0xeb00b1d4, 0xff00c1e6, 0xba008ea7,
0x02000202, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb20075ab, 0xff00a7f4, 0xf300a1e9, 0x35002333,
0x06000406, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x8900647d, 0xff00bde8, 0xfb00bce2, 0x26001d22, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x2b001c29, 0xf1009ce8, 0xfe00a5f4, 0xc60082be, 0x3b002738, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x01000101, 0x54003c4d, 0xfd00b8e8, 0xff00baea, 0x96006f89, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x78004d74, 0xe20091da, 0xff00a5f6, 0xb60077af, 0x42002b3f, 0x0c00080c, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9400688a, 0xff00b5ed, 0xff00b6ec, 0xcc0093bc, 0x02000102, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x8100527d, 0xeb0096e4, 0xf900a0f1, 0xdc008dd4,
0x9b006595, 0x32002130, 0x0a00070a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2100161f, 0x5300394e, 0xe2009cd4, 0xff00b1ef, 0xff00b2ee, 0xc8008cba, 0x17001015,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x19001018, 0x5e003b5b, 0xcb0081c5, 0xff00a2f8, 0xfc00a1f4, 0xde0090d6, 0xa9006da3, 0x8300567e, 0x6f00496a, 0x76004e71, 0xbb007db2, 0xeb009edf, 0xfb00a9ee, 0xff00adf1,
0xfd00adee, 0x9e006d95, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x34002133, 0xa60069a1, 0xd70089d1, 0xf2009bea, 0xff00a3f7, 0xfb00a1f2, 0xfb00a2f2, 0xff00a6f5,
0xff00a8f4, 0xfd00a7f2, 0xed009ee2, 0xcf008bc5, 0x14000e13, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000b11, 0x35002134, 0x5b003959,
0x8b005887, 0xb30072ae, 0xc90080c3, 0xd10086ca, 0xa6006ba0, 0x65004261, 0x3c002839, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x06000406, 0x0d00080d, 0x0f000a0f, 0x0a00060a, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000};
// clang-format on
CXCursorManager::CXCursorManager() {
hyprCursor = makeShared<SXCursors>();
SXCursorImage image;
image.size = {32, 32};
image.hotspot = {3, 2};
image.pixels = HYPR_XCURSOR_PIXELS;
image.delay = 0;
hyprCursor->images.push_back(image);
hyprCursor->shape = "left_ptr";
defaultCursor = hyprCursor;
}
void CXCursorManager::loadTheme(std::string const& name, int size) {
if (lastLoadSize == size && themeName == name)
return;
lastLoadSize = size;
themeName = name.empty() ? "default" : name;
defaultCursor.reset();
cursors.clear();
auto paths = themePaths(themeName);
if (paths.empty()) {
Debug::log(ERR, "XCursor librarypath is empty loading standard XCursors");
cursors = loadStandardCursors(themeName, lastLoadSize);
} else {
for (auto const& p : paths) {
auto dirCursors = loadAllFromDir(p, lastLoadSize);
std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(cursors),
[this](auto const& p) { return std::none_of(cursors.begin(), cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); });
}
}
if (cursors.empty()) {
Debug::log(ERR, "XCursor failed finding any shapes in theme \"{}\".", themeName);
defaultCursor = hyprCursor;
return;
}
for (auto const& shape : CURSOR_SHAPE_NAMES) {
auto legacyName = getLegacyShapeName(shape);
if (legacyName.empty())
continue;
auto it = std::find_if(cursors.begin(), cursors.end(), [&legacyName](auto const& c) { return c->shape == legacyName; });
if (it == cursors.end()) {
Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName);
continue;
}
if (std::any_of(cursors.begin(), cursors.end(), [&shape](auto const& dp) { return dp->shape == shape; })) {
Debug::log(LOG, "XCursor already has a shape {} loaded, skipping", shape);
continue;
}
auto cursor = makeShared<SXCursors>();
cursor->images = it->get()->images;
cursor->shape = shape;
cursors.emplace_back(cursor);
}
static auto SYNCGSETTINGS = CConfigValue<Hyprlang::INT>("cursor:sync_gsettings_theme");
if (*SYNCGSETTINGS)
syncGsettings();
}
SP<SXCursors> CXCursorManager::getShape(std::string const& shape, int size) {
// monitor scaling changed etc, so reload theme with new size.
if (size != lastLoadSize)
loadTheme(themeName, size);
// try to get an icon we know if we have one
for (auto const& c : cursors) {
if (c->shape != shape)
continue;
return c;
}
Debug::log(WARN, "XCursor couldn't find shape {} , using default cursor instead", shape);
return defaultCursor;
}
SP<SXCursors> CXCursorManager::createCursor(std::string const& shape, XcursorImages* xImages) {
auto xcursor = makeShared<SXCursors>();
for (int i = 0; i < xImages->nimage; i++) {
auto xImage = xImages->images[i];
SXCursorImage image;
image.size = {(int)xImage->width, (int)xImage->height};
image.hotspot = {(int)xImage->xhot, (int)xImage->yhot};
image.pixels.resize(xImage->width * xImage->height);
std::memcpy(image.pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
image.delay = xImage->delay;
xcursor->images.emplace_back(image);
}
xcursor->shape = shape;
return xcursor;
}
std::unordered_set<std::string> CXCursorManager::themePaths(std::string const& theme) {
auto const* path = XcursorLibraryPath();
auto expandTilde = [](std::string const& path) {
if (!path.empty() && path[0] == '~') {
const char* home = std::getenv("HOME");
if (home)
return std::string(home) + path.substr(1);
}
return path;
};
auto getInheritThemes = [](std::string const& indexTheme) {
std::ifstream infile(indexTheme);
std::string line;
std::vector<std::string> themes;
Debug::log(LOG, "XCursor parsing index.theme {}", indexTheme);
while (std::getline(infile, line)) {
if (line.empty())
continue;
// Trim leading and trailing whitespace
auto pos = line.find_first_not_of(" \t\n\r");
if (pos != std::string::npos)
line.erase(0, pos);
pos = line.find_last_not_of(" \t\n\r");
if (pos != std::string::npos && pos < line.length()) {
line.erase(pos + 1);
}
if (line.rfind("Inherits", 8) != std::string::npos) { // Check if line starts with "Inherits"
std::string inheritThemes = line.substr(8); // Extract the part after "Inherits"
if (inheritThemes.empty())
continue;
// Remove leading whitespace from inheritThemes and =
pos = inheritThemes.find_first_not_of(" \t\n\r");
if (pos != std::string::npos)
inheritThemes.erase(0, pos);
if (inheritThemes.empty())
continue;
if (inheritThemes.at(0) == '=')
inheritThemes.erase(0, 1);
else
continue; // not correct formatted index.theme
pos = inheritThemes.find_first_not_of(" \t\n\r");
if (pos != std::string::npos)
inheritThemes.erase(0, pos);
std::stringstream inheritStream(inheritThemes);
std::string inheritTheme;
while (std::getline(inheritStream, inheritTheme, ',')) {
if (inheritTheme.empty())
continue;
// Trim leading and trailing whitespace from each theme
pos = inheritTheme.find_first_not_of(" \t\n\r");
if (pos != std::string::npos)
inheritTheme.erase(0, pos);
pos = inheritTheme.find_last_not_of(" \t\n\r");
if (pos != std::string::npos && pos < inheritTheme.length())
inheritTheme.erase(inheritTheme.find_last_not_of(" \t\n\r") + 1);
themes.push_back(inheritTheme);
}
}
}
infile.close();
return themes;
};
std::unordered_set<std::string> paths;
std::unordered_set<std::string> inherits;
auto scanTheme = [&path, &paths, &expandTilde, &inherits, &getInheritThemes](auto const& t) {
std::stringstream ss(path);
std::string line;
Debug::log(LOG, "XCursor scanning theme {}", t);
while (std::getline(ss, line, ':')) {
auto p = expandTilde(line + "/" + t + "/cursors");
if (std::filesystem::exists(p) && std::filesystem::is_directory(p)) {
Debug::log(LOG, "XCursor using theme path {}", p);
paths.insert(p);
}
auto inherit = expandTilde(line + "/" + t + "/index.theme");
if (std::filesystem::exists(inherit) && std::filesystem::is_regular_file(inherit)) {
auto inheritThemes = getInheritThemes(inherit);
for (auto const& i : inheritThemes) {
Debug::log(LOG, "XCursor theme {} inherits {}", t, i);
inherits.insert(i);
}
}
}
};
if (path) {
scanTheme(theme);
while (!inherits.empty()) {
auto oldInherits = inherits;
for (auto& i : oldInherits)
scanTheme(i);
if (oldInherits.size() == inherits.size())
break;
}
}
return paths;
}
std::string CXCursorManager::getLegacyShapeName(std::string const& shape) {
if (shape == "invalid")
return std::string();
else if (shape == "default")
return "left_ptr";
else if (shape == "context-menu")
return "left_ptr";
else if (shape == "help")
return "left_ptr";
else if (shape == "pointer")
return "hand2";
else if (shape == "progress")
return "watch";
else if (shape == "wait")
return "watch";
else if (shape == "cell")
return "plus";
else if (shape == "crosshair")
return "cross";
else if (shape == "text")
return "xterm";
else if (shape == "vertical-text")
return "xterm";
else if (shape == "alias")
return "dnd-link";
else if (shape == "copy")
return "dnd-copy";
else if (shape == "move")
return "dnd-move";
else if (shape == "no-drop")
return "dnd-none";
else if (shape == "not-allowed")
return "crossed_circle";
else if (shape == "grab")
return "hand1";
else if (shape == "grabbing")
return "hand1";
else if (shape == "e-resize")
return "right_side";
else if (shape == "n-resize")
return "top_side";
else if (shape == "ne-resize")
return "top_right_corner";
else if (shape == "nw-resize")
return "top_left_corner";
else if (shape == "s-resize")
return "bottom_side";
else if (shape == "se-resize")
return "bottom_right_corner";
else if (shape == "sw-resize")
return "bottom_left_corner";
else if (shape == "w-resize")
return "left_side";
else if (shape == "ew-resize")
return "sb_h_double_arrow";
else if (shape == "ns-resize")
return "sb_v_double_arrow";
else if (shape == "nesw-resize")
return "fd_double_arrow";
else if (shape == "nwse-resize")
return "bd_double_arrow";
else if (shape == "col-resize")
return "sb_h_double_arrow";
else if (shape == "row-resize")
return "sb_v_double_arrow";
else if (shape == "all-scroll")
return "fleur";
else if (shape == "zoom-in")
return "left_ptr";
else if (shape == "zoom-out")
return "left_ptr";
return std::string();
};
// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
// clang-format off
static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
"X_cursor",
"arrow",
"based_arrow_down",
"based_arrow_up",
"boat",
"bogosity",
"bottom_left_corner",
"bottom_right_corner",
"bottom_side",
"bottom_tee",
"box_spiral",
"center_ptr",
"circle",
"clock",
"coffee_mug",
"cross",
"cross_reverse",
"crosshair",
"diamond_cross",
"dot",
"dotbox",
"double_arrow",
"draft_large",
"draft_small",
"draped_box",
"exchange",
"fleur",
"gobbler",
"gumby",
"hand1",
"hand2",
"heart",
"icon",
"iron_cross",
"left_ptr",
"left_side",
"left_tee",
"leftbutton",
"ll_angle",
"lr_angle",
"man",
"middlebutton",
"mouse",
"pencil",
"pirate",
"plus",
"question_arrow",
"right_ptr",
"right_side",
"right_tee",
"rightbutton",
"rtl_logo",
"sailboat",
"sb_down_arrow",
"sb_h_double_arrow",
"sb_left_arrow",
"sb_right_arrow",
"sb_up_arrow",
"sb_v_double_arrow",
"shuttle",
"sizing",
"spider",
"spraycan",
"star",
"target",
"tcross",
"top_left_arrow",
"top_left_corner",
"top_right_corner",
"top_side",
"top_tee",
"trek",
"ul_angle",
"umbrella",
"ur_angle",
"watch",
"xterm",
};
// clang-format on
std::vector<SP<SXCursors>> CXCursorManager::loadStandardCursors(std::string const& name, int size) {
std::vector<SP<SXCursors>> newCursors;
// load the default xcursor shapes that exist in the theme
for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
std::string shape{XCURSOR_STANDARD_NAMES.at(i)};
auto xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), size);
if (!xImages) {
Debug::log(WARN, "XCursor failed to find a shape with name {}, trying size 24.", shape);
xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), 24);
if (!xImages) {
Debug::log(WARN, "XCursor failed to find a shape with name {}, skipping", shape);
continue;
}
}
auto cursor = createCursor(shape, xImages);
newCursors.emplace_back(cursor);
if (!defaultCursor && (shape == "left_ptr" || shape == "arrow"))
defaultCursor = cursor;
XcursorImagesDestroy(xImages);
}
// broken theme.. just set it.
if (!newCursors.empty() && !defaultCursor)
defaultCursor = newCursors.front();
return newCursors;
}
std::vector<SP<SXCursors>> CXCursorManager::loadAllFromDir(std::string const& path, int size) {
std::vector<SP<SXCursors>> newCursors;
if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) {
for (const auto& entry : std::filesystem::directory_iterator(path)) {
if (!entry.is_regular_file() && !entry.is_symlink())
continue;
auto const& full = entry.path().string();
using PcloseType = int (*)(FILE*);
const std::unique_ptr<FILE, PcloseType> f(fopen(full.c_str(), "r"), static_cast<PcloseType>(fclose));
if (!f)
continue;
auto xImages = XcursorFileLoadImages(f.get(), size);
if (!xImages) {
Debug::log(WARN, "XCursor failed to load image {}, trying size 24.", full);
xImages = XcursorFileLoadImages(f.get(), 24);
if (!xImages) {
Debug::log(WARN, "XCursor failed to load image {}, skipping", full);
continue;
}
}
auto const& shape = entry.path().filename().string();
auto cursor = createCursor(shape, xImages);
newCursors.emplace_back(cursor);
if (!defaultCursor && (shape == "left_ptr" || shape == "arrow"))
defaultCursor = cursor;
XcursorImagesDestroy(xImages);
}
}
// broken theme.. just set it.
if (!newCursors.empty() && !defaultCursor)
defaultCursor = newCursors.front();
return newCursors;
}
void CXCursorManager::syncGsettings() {
auto checkParamExists = [](std::string const& paramName, std::string const& category) {
auto* gSettingsSchemaSource = g_settings_schema_source_get_default();
if (!gSettingsSchemaSource) {
Debug::log(WARN, "GSettings default schema source does not exist, cant sync GSettings");
return false;
}
auto* gSettingsSchema = g_settings_schema_source_lookup(gSettingsSchemaSource, category.c_str(), true);
bool hasParam = false;
if (gSettingsSchema != NULL) {
hasParam = gSettingsSchema && g_settings_schema_has_key(gSettingsSchema, paramName.c_str());
g_settings_schema_unref(gSettingsSchema);
}
return hasParam;
};
using SettingValue = std::variant<std::string, int>;
auto setValue = [&checkParamExists](std::string const& paramName, const SettingValue& paramValue, std::string const& category) {
if (!checkParamExists(paramName, category)) {
Debug::log(WARN, "GSettings parameter doesnt exist {} in {}", paramName, category);
return;
}
auto* gsettings = g_settings_new(category.c_str());
if (!gsettings) {
Debug::log(WARN, "GSettings failed to allocate new settings with category {}", category);
return;
}
std::visit(
[&](auto&& value) {
using T = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<T, std::string>)
g_settings_set_string(gsettings, paramName.c_str(), value.c_str());
else if constexpr (std::is_same_v<T, int>)
g_settings_set_int(gsettings, paramName.c_str(), value);
},
paramValue);
g_settings_sync();
g_object_unref(gsettings);
};
setValue("cursor-theme", themeName, "org.gnome.desktop.interface");
setValue("cursor-size", lastLoadSize, "org.gnome.desktop.interface");
}

View file

@ -0,0 +1,48 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_set>
#include <array>
#include <cstdint>
#include <hyprutils/math/Vector2D.hpp>
#include "helpers/memory/Memory.hpp"
extern "C" {
#include <X11/Xcursor/Xcursor.h>
}
// gangsta bootleg XCursor impl. adidas balkanized
struct SXCursorImage {
Vector2D size;
Vector2D hotspot;
std::vector<uint32_t> pixels; // XPixel is a u32
uint32_t delay; // animation delay to next frame (ms)
};
struct SXCursors {
std::vector<SXCursorImage> images;
std::string shape;
};
class CXCursorManager {
public:
CXCursorManager();
~CXCursorManager() = default;
void loadTheme(const std::string& name, int size);
SP<SXCursors> getShape(std::string const& shape, int size);
private:
SP<SXCursors> createCursor(std::string const& shape, XcursorImages* xImages);
std::unordered_set<std::string> themePaths(std::string const& theme);
std::string getLegacyShapeName(std::string const& shape);
std::vector<SP<SXCursors>> loadStandardCursors(std::string const& name, int size);
std::vector<SP<SXCursors>> loadAllFromDir(std::string const& path, int size);
void syncGsettings();
int lastLoadSize = 0;
std::string themeName = "";
SP<SXCursors> defaultCursor;
SP<SXCursors> hyprCursor;
std::vector<SP<SXCursors>> cursors;
};

View file

@ -27,6 +27,8 @@ CEventLoopManager::~CEventLoopManager() {
wl_event_source_remove(m_sWayland.eventSource); wl_event_source_remove(m_sWayland.eventSource);
if (m_sIdle.eventSource) if (m_sIdle.eventSource)
wl_event_source_remove(m_sIdle.eventSource); wl_event_source_remove(m_sIdle.eventSource);
if (m_sTimers.timerfd >= 0)
close(m_sTimers.timerfd);
} }
static int timerWrite(int fd, uint32_t mask, void* data) { static int timerWrite(int fd, uint32_t mask, void* data) {
@ -46,7 +48,6 @@ void CEventLoopManager::enterLoop() {
aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs();
for (auto& fd : aqPollFDs) { for (auto& fd : aqPollFDs) {
m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get()));
fd->onSignal(); // dispatch outstanding
} }
wl_display_run(m_sWayland.display); wl_display_run(m_sWayland.display);
@ -74,8 +75,8 @@ void CEventLoopManager::removeTimer(SP<CEventLoopTimer> timer) {
} }
static void timespecAddNs(timespec* pTimespec, int64_t delta) { static void timespecAddNs(timespec* pTimespec, int64_t delta) {
int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC; auto delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
int delta_s_high = delta / TIMESPEC_NSEC_PER_SEC; auto delta_s_high = delta / TIMESPEC_NSEC_PER_SEC;
pTimespec->tv_sec += delta_s_high; pTimespec->tv_sec += delta_s_high;

View file

@ -63,7 +63,7 @@ void CInputManager::recheckIdleInhibitorStatus() {
return; return;
} }
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) { if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->isFullscreen() && g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) {
PROTO::idle->setInhibit(true); PROTO::idle->setInhibit(true);
return; return;
} }

View file

@ -17,6 +17,7 @@
#include "../../protocols/LayerShell.hpp" #include "../../protocols/LayerShell.hpp"
#include "../../protocols/core/Seat.hpp" #include "../../protocols/core/Seat.hpp"
#include "../../protocols/core/DataDevice.hpp" #include "../../protocols/core/DataDevice.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../protocols/XDGShell.hpp" #include "../../protocols/XDGShell.hpp"
#include "../../devices/Mouse.hpp" #include "../../devices/Mouse.hpp"
@ -297,7 +298,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// then, we check if the workspace doesnt have a fullscreen window // then, we check if the workspace doesnt have a fullscreen window
const auto PWORKSPACE = PMONITOR->activeWorkspace; const auto PWORKSPACE = PMONITOR->activeWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
if (!pFoundWindow) { if (!pFoundWindow) {
@ -324,7 +325,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// then windows // then windows
if (!foundSurface) { if (!foundSurface) {
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FSMODE_MAXIMIZED) {
if (!foundSurface) { if (!foundSurface) {
if (PMONITOR->activeSpecialWorkspace) { if (PMONITOR->activeSpecialWorkspace) {
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
@ -469,7 +470,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
else if (pFoundWindow) { else if (pFoundWindow) {
// change cursor icon if hovering over border // change cursor icon if hovering over border
if (*PRESIZEONBORDER && *PRESIZECURSORICON) { if (*PRESIZEONBORDER && *PRESIZECURSORICON) {
if (!pFoundWindow->m_bIsFullscreen && !pFoundWindow->hasPopupAt(mouseCoords)) { if (!pFoundWindow->isFullscreen() && !pFoundWindow->hasPopupAt(mouseCoords)) {
setCursorIconOnBorder(pFoundWindow); setCursorIconOnBorder(pFoundWindow);
} else if (m_eBorderIconDirection != BORDERICON_NONE) { } else if (m_eBorderIconDirection != BORDERICON_NONE) {
unsetCursorImage(); unsetCursorImage();
@ -680,7 +681,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
// clicking on border triggers resize // clicking on border triggers resize
// TODO detect click on LS properly // TODO detect click on LS properly
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) { if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) {
if (w && !w->m_bIsFullscreen) { if (w && !w->isFullscreen()) {
const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y};
const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
@ -918,6 +919,8 @@ void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
applyConfigToKeyboard(keeb); applyConfigToKeyboard(keeb);
g_pSeatManager->setKeyboard(keeb); g_pSeatManager->setKeyboard(keeb);
keeb->updateLEDs();
} }
void CInputManager::setKeyboardLayout() { void CInputManager::setKeyboardLayout() {
@ -1264,7 +1267,14 @@ void CInputManager::updateKeyboardsLeds(SP<IKeyboard> pKeyboard) {
if (!pKeyboard) if (!pKeyboard)
return; return;
pKeyboard->updateLEDs(); std::optional<uint32_t> leds = pKeyboard->getLEDs();
if (!leds.has_value())
return;
for (auto& k : m_vKeyboards) {
k->updateLEDs(leds.value());
}
} }
void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) { void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {
@ -1382,6 +1392,12 @@ void CInputManager::refocusLastWindow(CMonitor* pMonitor) {
g_pCompositor->focusWindow(PLASTWINDOW); g_pCompositor->focusWindow(PLASTWINDOW);
} else { } else {
// otherwise fall back to a normal refocus. // otherwise fall back to a normal refocus.
if (foundSurface && !foundSurface->hlSurface->keyboardFocusable()) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
g_pCompositor->focusWindow(PLASTWINDOW);
}
refocus(); refocus();
} }
} }
@ -1670,7 +1686,7 @@ void CInputManager::releaseAllMouseButtons() {
void CInputManager::setCursorIconOnBorder(PHLWINDOW w) { void CInputManager::setCursorIconOnBorder(PHLWINDOW w) {
// do not override cursor icons set by mouse binds // do not override cursor icons set by mouse binds
if (g_pKeybindManager->m_bIsMouseBindActive) { if (g_pInputManager->currentlyDraggedWindow.expired()) {
m_eBorderIconDirection = BORDERICON_NONE; m_eBorderIconDirection = BORDERICON_NONE;
return; return;
} }

View file

@ -33,7 +33,7 @@ class CInputPopup {
WP<CInputMethodPopupV2> popup; WP<CInputMethodPopupV2> popup;
SP<CWLSurface> surface; SP<CWLSurface> surface;
CBox lastBoxLocal; CBox lastBoxLocal;
uint64_t lastMonitor = -1; MONITORID lastMonitor = MONITOR_INVALID;
struct { struct {
CHyprSignalListener map; CHyprSignalListener map;

View file

@ -2,6 +2,7 @@
#include "InputManager.hpp" #include "InputManager.hpp"
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
#include "../../protocols/TextInputV3.hpp" #include "../../protocols/TextInputV3.hpp"
#include "../../protocols/TextInputV1.hpp"
#include "../../protocols/InputMethodV2.hpp" #include "../../protocols/InputMethodV2.hpp"
#include "../../protocols/core/Compositor.hpp" #include "../../protocols/core/Compositor.hpp"
@ -9,7 +10,8 @@ CInputMethodRelay::CInputMethodRelay() {
static auto P = static auto P =
g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<SP<CWLSurfaceResource>>(param)); }); g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<SP<CWLSurfaceResource>>(param)); });
listeners.newTIV3 = PROTO::textInputV3->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(ti); }); listeners.newTIV3 = PROTO::textInputV3->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(std::any_cast<WP<CTextInputV3>>(ti)); });
listeners.newTIV1 = PROTO::textInputV1->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(std::any_cast<WP<CTextInputV1>>(ti)); });
listeners.newIME = PROTO::ime->events.newIME.registerListener([this](std::any ime) { onNewIME(std::any_cast<SP<CInputMethodV2>>(ime)); }); listeners.newIME = PROTO::ime->events.newIME.registerListener([this](std::any ime) { onNewIME(std::any_cast<SP<CInputMethodV2>>(ime)); });
} }
@ -86,11 +88,11 @@ CTextInput* CInputMethodRelay::getFocusedTextInput() {
return nullptr; return nullptr;
} }
void CInputMethodRelay::onNewTextInput(std::any tiv3) { void CInputMethodRelay::onNewTextInput(WP<CTextInputV3> tiv3) {
m_vTextInputs.emplace_back(std::make_unique<CTextInput>(std::any_cast<WP<CTextInputV3>>(tiv3))); m_vTextInputs.emplace_back(std::make_unique<CTextInput>(tiv3));
} }
void CInputMethodRelay::onNewTextInput(STextInputV1* pTIV1) { void CInputMethodRelay::onNewTextInput(WP<CTextInputV1> pTIV1) {
m_vTextInputs.emplace_back(std::make_unique<CTextInput>(pTIV1)); m_vTextInputs.emplace_back(std::make_unique<CTextInput>(pTIV1));
} }

View file

@ -10,7 +10,7 @@
class CInputManager; class CInputManager;
class CHyprRenderer; class CHyprRenderer;
struct STextInputV1; class CTextInputV1;
class CInputMethodV2; class CInputMethodV2;
class CInputMethodRelay { class CInputMethodRelay {
@ -18,8 +18,8 @@ class CInputMethodRelay {
CInputMethodRelay(); CInputMethodRelay();
void onNewIME(SP<CInputMethodV2>); void onNewIME(SP<CInputMethodV2>);
void onNewTextInput(std::any tiv3); void onNewTextInput(WP<CTextInputV3> tiv3);
void onNewTextInput(STextInputV1* pTIV1); void onNewTextInput(WP<CTextInputV1> pTIV1);
void activateIME(CTextInput* pInput); void activateIME(CTextInput* pInput);
void deactivateIME(CTextInput* pInput); void deactivateIME(CTextInput* pInput);
@ -48,6 +48,7 @@ class CInputMethodRelay {
struct { struct {
CHyprSignalListener newTIV3; CHyprSignalListener newTIV3;
CHyprSignalListener newTIV1;
CHyprSignalListener newIME; CHyprSignalListener newIME;
CHyprSignalListener commitIME; CHyprSignalListener commitIME;
CHyprSignalListener destroyIME; CHyprSignalListener destroyIME;

View file

@ -77,7 +77,7 @@ void CInputManager::endWorkspaceSwipe() {
// left of where we started. Instead, it's one more than the greatest // left of where we started. Instead, it's one more than the greatest
// workspace ID that currently exists. // workspace ID that currently exists.
if (workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID && *PSWIPENEW) { if (workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID && *PSWIPENEW) {
int maxWorkspace = 0; WORKSPACEID maxWorkspace = 0;
for (const auto& ws : g_pCompositor->m_vWorkspaces) { for (const auto& ws : g_pCompositor->m_vWorkspaces) {
maxWorkspace = std::max(maxWorkspace, ws->m_iID); maxWorkspace = std::max(maxWorkspace, ws->m_iID);
} }
@ -194,7 +194,7 @@ void CInputManager::endWorkspaceSwipe() {
// apply alpha // apply alpha
for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) {
ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f; ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f;
} }
} }

View file

@ -7,8 +7,7 @@
#include "../../protocols/InputMethodV2.hpp" #include "../../protocols/InputMethodV2.hpp"
#include "../../protocols/core/Compositor.hpp" #include "../../protocols/core/Compositor.hpp"
CTextInput::CTextInput(STextInputV1* ti) : pV1Input(ti) { CTextInput::CTextInput(WP<CTextInputV1> ti) : pV1Input(ti) {
ti->pTextInput = this;
initCallbacks(); initCallbacks();
} }
@ -16,17 +15,6 @@ CTextInput::CTextInput(WP<CTextInputV3> ti) : pV3Input(ti) {
initCallbacks(); initCallbacks();
} }
CTextInput::~CTextInput() {
if (pV1Input)
pV1Input->pTextInput = nullptr;
}
void CTextInput::tiV1Destroyed() {
pV1Input = nullptr;
g_pInputManager->m_sIMERelay.removeTextInput(this);
}
void CTextInput::initCallbacks() { void CTextInput::initCallbacks() {
if (isV3()) { if (isV3()) {
const auto INPUT = pV3Input.lock(); const auto INPUT = pV3Input.lock();
@ -41,25 +29,19 @@ void CTextInput::initCallbacks() {
g_pInputManager->m_sIMERelay.removeTextInput(this); g_pInputManager->m_sIMERelay.removeTextInput(this);
}); });
} else { } else {
hyprListener_textInputEnable.initCallback(&pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput"); const auto INPUT = pV1Input.lock();
hyprListener_textInputCommit.initCallback(&pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput"); listeners.enable = INPUT->events.enable.registerListener([this](std::any p) {
const auto SURFACE = std::any_cast<SP<CWLSurfaceResource>>(p);
hyprListener_textInputDisable.initCallback(&pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput"); onEnabled(SURFACE);
});
hyprListener_textInputDestroy.initCallback( listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); });
&pV1Input->sDestroy, listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); });
[this](void* owner, void* data) { listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) {
hyprListener_textInputCommit.removeCallback(); listeners.surfaceUnmap.reset();
hyprListener_textInputDestroy.removeCallback(); listeners.surfaceDestroy.reset();
hyprListener_textInputDisable.removeCallback(); g_pInputManager->m_sIMERelay.removeTextInput(this);
hyprListener_textInputEnable.removeCallback(); });
listeners.surfaceUnmap.reset();
listeners.surfaceDestroy.reset();
g_pInputManager->m_sIMERelay.removeTextInput(this);
},
this, "textInput");
} }
} }
@ -149,7 +131,7 @@ void CTextInput::setFocusedSurface(SP<CWLSurfaceResource> pSurface) {
} }
bool CTextInput::isV3() { bool CTextInput::isV3() {
return !pV1Input; return pV3Input && !pV1Input;
} }
void CTextInput::enter(SP<CWLSurfaceResource> pSurface) { void CTextInput::enter(SP<CWLSurfaceResource> pSurface) {
@ -174,8 +156,7 @@ void CTextInput::enter(SP<CWLSurfaceResource> pSurface) {
if (isV3()) if (isV3())
pV3Input->enter(pSurface); pV3Input->enter(pSurface);
else { else {
zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->getResource()->resource()); pV1Input->enter(pSurface);
pV1Input->active = true;
} }
setFocusedSurface(pSurface); setFocusedSurface(pSurface);
@ -194,8 +175,7 @@ void CTextInput::leave() {
if (isV3() && focusedSurface()) if (isV3() && focusedSurface())
pV3Input->leave(focusedSurface()); pV3Input->leave(focusedSurface());
else if (focusedSurface() && pV1Input) { else if (focusedSurface() && pV1Input) {
zwp_text_input_v1_send_leave(pV1Input->resourceImpl); pV1Input->leave();
pV1Input->active = false;
} }
setFocusedSurface(nullptr); setFocusedSurface(nullptr);
@ -208,7 +188,7 @@ SP<CWLSurfaceResource> CTextInput::focusedSurface() {
} }
wl_client* CTextInput::client() { wl_client* CTextInput::client() {
return isV3() ? pV3Input->client() : pV1Input->client; return isV3() ? pV3Input->client() : pV1Input->client();
} }
void CTextInput::commitStateToIME(SP<CInputMethodV2> ime) { void CTextInput::commitStateToIME(SP<CInputMethodV2> ime) {
@ -223,13 +203,15 @@ void CTextInput::commitStateToIME(SP<CInputMethodV2> ime) {
if (INPUT->current.contentType.updated) if (INPUT->current.contentType.updated)
ime->textContentType(INPUT->current.contentType.hint, INPUT->current.contentType.purpose); ime->textContentType(INPUT->current.contentType.hint, INPUT->current.contentType.purpose);
} else { } else {
if (pV1Input->pendingSurrounding.isPending) const auto INPUT = pV1Input.lock();
ime->surroundingText(pV1Input->pendingSurrounding.text, pV1Input->pendingSurrounding.cursor, pV1Input->pendingSurrounding.anchor);
if (INPUT->pendingSurrounding.isPending)
ime->surroundingText(INPUT->pendingSurrounding.text, INPUT->pendingSurrounding.cursor, INPUT->pendingSurrounding.anchor);
ime->textChangeCause(ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD); ime->textChangeCause(ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD);
if (pV1Input->pendingContentType.isPending) if (pV1Input->pendingContentType.isPending)
ime->textContentType((zwpTextInputV3ContentHint)pV1Input->pendingContentType.hint, (zwpTextInputV3ContentPurpose)pV1Input->pendingContentType.purpose); ime->textContentType((zwpTextInputV3ContentHint)INPUT->pendingContentType.hint, (zwpTextInputV3ContentPurpose)INPUT->pendingContentType.purpose);
} }
g_pInputManager->m_sIMERelay.updateAllPopups(); g_pInputManager->m_sIMERelay.updateAllPopups();
@ -252,25 +234,27 @@ void CTextInput::updateIMEState(SP<CInputMethodV2> ime) {
INPUT->sendDone(); INPUT->sendDone();
} else { } else {
const auto INPUT = pV1Input.lock();
if (ime->current.preeditString.committed) { if (ime->current.preeditString.committed) {
zwp_text_input_v1_send_preedit_cursor(pV1Input->resourceImpl, ime->current.preeditString.begin); INPUT->preeditCursor(ime->current.preeditString.begin);
zwp_text_input_v1_send_preedit_styling(pV1Input->resourceImpl, 0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditStyling(0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
zwp_text_input_v1_send_preedit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.preeditString.string.c_str(), ""); INPUT->preeditString(pV1Input->serial, ime->current.preeditString.string.c_str(), "");
} else { } else {
zwp_text_input_v1_send_preedit_cursor(pV1Input->resourceImpl, ime->current.preeditString.begin); INPUT->preeditCursor(ime->current.preeditString.begin);
zwp_text_input_v1_send_preedit_styling(pV1Input->resourceImpl, 0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditStyling(0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
zwp_text_input_v1_send_preedit_string(pV1Input->resourceImpl, pV1Input->serial, "", ""); INPUT->preeditString(pV1Input->serial, "", "");
} }
if (ime->current.committedString.committed) if (ime->current.committedString.committed)
zwp_text_input_v1_send_commit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.committedString.string.c_str()); INPUT->commitString(pV1Input->serial, ime->current.committedString.string.c_str());
if (ime->current.deleteSurrounding.committed) { if (ime->current.deleteSurrounding.committed) {
zwp_text_input_v1_send_delete_surrounding_text(pV1Input->resourceImpl, std::string(ime->current.preeditString.string).length() - ime->current.deleteSurrounding.before, INPUT->deleteSurroundingText(std::string(ime->current.preeditString.string).length() - ime->current.deleteSurrounding.before,
ime->current.deleteSurrounding.after + ime->current.deleteSurrounding.before); ime->current.deleteSurrounding.after + ime->current.deleteSurrounding.before);
if (ime->current.preeditString.committed) if (ime->current.preeditString.committed)
zwp_text_input_v1_send_commit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.preeditString.string.c_str()); INPUT->commitString(pV1Input->serial, ime->current.preeditString.string.c_str());
} }
} }
} }
@ -281,4 +265,4 @@ bool CTextInput::hasCursorRectangle() {
CBox CTextInput::cursorBox() { CBox CTextInput::cursorBox() {
return CBox{isV3() ? pV3Input->current.box.cursorBox : pV1Input->cursorRectangle}; return CBox{isV3() ? pV3Input->current.box.cursorBox : pV1Input->cursorRectangle};
} }

View file

@ -8,7 +8,7 @@
struct wl_client; struct wl_client;
struct STextInputV1; class CTextInputV1;
class CTextInputV3; class CTextInputV3;
class CInputMethodV2; class CInputMethodV2;
class CWLSurfaceResource; class CWLSurfaceResource;
@ -16,8 +16,7 @@ class CWLSurfaceResource;
class CTextInput { class CTextInput {
public: public:
CTextInput(WP<CTextInputV3> ti); CTextInput(WP<CTextInputV3> ti);
CTextInput(STextInputV1* ti); CTextInput(WP<CTextInputV1> ti);
~CTextInput();
bool isV3(); bool isV3();
void enter(SP<CWLSurfaceResource> pSurface); void enter(SP<CWLSurfaceResource> pSurface);
@ -43,12 +42,7 @@ class CTextInput {
WP<CWLSurfaceResource> pFocusedSurface; WP<CWLSurfaceResource> pFocusedSurface;
int enterLocks = 0; int enterLocks = 0;
WP<CTextInputV3> pV3Input; WP<CTextInputV3> pV3Input;
STextInputV1* pV1Input = nullptr; WP<CTextInputV1> pV1Input;
DYNLISTENER(textInputEnable);
DYNLISTENER(textInputDisable);
DYNLISTENER(textInputCommit);
DYNLISTENER(textInputDestroy);
struct { struct {
CHyprSignalListener enable; CHyprSignalListener enable;
@ -58,4 +52,4 @@ class CTextInput {
CHyprSignalListener surfaceUnmap; CHyprSignalListener surfaceUnmap;
CHyprSignalListener surfaceDestroy; CHyprSignalListener surfaceDestroy;
} listeners; } listeners;
}; };

View file

@ -14,7 +14,7 @@ executable('Hyprland', src,
dependency('cairo'), dependency('cairo'),
dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprcursor', version: '>=0.1.7'),
dependency('hyprlang', version: '>= 0.3.2'), dependency('hyprlang', version: '>= 0.3.2'),
dependency('hyprutils', version: '>= 0.2.0'), dependency('hyprutils', version: '>= 0.2.1'),
dependency('libdrm'), dependency('libdrm'),
dependency('egl'), dependency('egl'),
dependency('xkbcommon'), dependency('xkbcommon'),
@ -28,6 +28,7 @@ executable('Hyprland', src,
xcb_xfixes_dep, xcb_xfixes_dep,
backtrace_dep, backtrace_dep,
epoll_dep, epoll_dep,
gio_dep,
udis86, udis86,
dependency('pixman-1'), dependency('pixman-1'),

View file

@ -80,6 +80,8 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) {
PLUGIN->version = PLUGINDATA.version; PLUGIN->version = PLUGINDATA.version;
PLUGIN->name = PLUGINDATA.name; PLUGIN->name = PLUGINDATA.name;
g_pConfigManager->m_bForceReload = true;
Debug::log(LOG, " [PluginSystem] Plugin {} loaded. Handle: {:x}, path: \"{}\", author: \"{}\", description: \"{}\", version: \"{}\"", PLUGINDATA.name, (uintptr_t)MODULE, path, Debug::log(LOG, " [PluginSystem] Plugin {} loaded. Handle: {:x}, path: \"{}\", author: \"{}\", description: \"{}\", version: \"{}\"", PLUGINDATA.name, (uintptr_t)MODULE, path,
PLUGINDATA.author, PLUGINDATA.description, PLUGINDATA.version); PLUGINDATA.author, PLUGINDATA.description, PLUGINDATA.version);

View file

@ -1,5 +1,6 @@
#include "DRMLease.hpp" #include "DRMLease.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include <aquamarine/backend/DRM.hpp> #include <aquamarine/backend/DRM.hpp>
#include <fcntl.h> #include <fcntl.h>
@ -225,7 +226,7 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP<Aquamarine::CDRMBackend> drmBackend) : backe
auto fd = drm->getNonMasterFD(); auto fd = drm->getNonMasterFD();
if (fd < 0) { if (fd < 0) {
LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); Debug::log(ERR, "[DRMLease] Failed to dup fd for drm node {}", drm->gpuName);
return; return;
} }
@ -247,10 +248,8 @@ CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver,
break; break;
} }
if (!primaryDevice || primaryDevice->success) { if (!primaryDevice || !primaryDevice->success)
PROTO::lease.reset(); g_pEventLoopManager->doLater([]() { PROTO::lease.reset(); });
return;
}
} }
void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {

View file

@ -24,9 +24,9 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return; return;
} }
auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
acquireTimeline = timeline; pending.acquireTimeline = timeline;
acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo; pending.acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
}); });
resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) {
@ -35,29 +35,33 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return; return;
} }
auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
releaseTimeline = timeline; pending.releaseTimeline = timeline;
releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo; pending.releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
}); });
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) { listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
if (!!acquireTimeline != !!releaseTimeline) { if ((pending.acquireTimeline || pending.releaseTimeline) && !surface->pending.texture) {
resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline");
surface->pending.rejected = true;
return;
}
if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) {
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
surface->pending.rejected = true; surface->pending.rejected = true;
return; return;
} }
if (!acquireTimeline) if (!surface->pending.newBuffer)
return; // this commit does not change the state here
if (!!pending.acquireTimeline != !!pending.releaseTimeline) {
resource->error(pending.acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT,
"Missing timeline");
surface->pending.rejected = true;
return;
}
if (!pending.acquireTimeline)
return; return;
// wait for the acquire timeline to materialize // wait for the acquire timeline to materialize
auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
if (!materialized.has_value()) { if (!materialized.has_value()) {
LOGM(ERR, "Failed to check the acquire timeline"); LOGM(ERR, "Failed to check the acquire timeline");
resource->noMemory(); resource->noMemory();
@ -68,7 +72,24 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return; return;
surface->lockPendingState(); surface->lockPendingState();
acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
});
listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) {
// apply timelines if new ones have been attached, otherwise don't touch
// the current ones
if (pending.releaseTimeline) {
current.releaseTimeline = pending.releaseTimeline;
current.releasePoint = pending.releasePoint;
}
if (pending.acquireTimeline) {
current.acquireTimeline = pending.acquireTimeline;
current.acquirePoint = pending.acquirePoint;
}
pending.releaseTimeline.reset();
pending.acquireTimeline.reset();
}); });
} }
@ -93,6 +114,11 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP<CWpLinuxDrmSyncobjTi
} }
} }
CDRMSyncobjTimelineResource::~CDRMSyncobjTimelineResource() {
if (fd >= 0)
close(fd);
}
SP<CDRMSyncobjTimelineResource> CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { SP<CDRMSyncobjTimelineResource> CDRMSyncobjTimelineResource::fromResource(wl_resource* res) {
auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data());
return data ? data->self.lock() : nullptr; return data ? data->self.lock() : nullptr;

View file

@ -14,23 +14,27 @@ class CDRMSyncobjSurfaceResource {
public: public:
CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_); CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_);
bool good(); bool good();
WP<CWLSurfaceResource> surface; WP<CWLSurfaceResource> surface;
WP<CDRMSyncobjTimelineResource> acquireTimeline, releaseTimeline; struct {
uint64_t acquirePoint = 0, releasePoint = 0; WP<CDRMSyncobjTimelineResource> acquireTimeline, releaseTimeline;
uint64_t acquirePoint = 0, releasePoint = 0;
} current, pending;
private: private:
SP<CWpLinuxDrmSyncobjSurfaceV1> resource; SP<CWpLinuxDrmSyncobjSurfaceV1> resource;
struct { struct {
CHyprSignalListener surfacePrecommit; CHyprSignalListener surfacePrecommit;
CHyprSignalListener surfaceCommit;
} listeners; } listeners;
}; };
class CDRMSyncobjTimelineResource { class CDRMSyncobjTimelineResource {
public: public:
CDRMSyncobjTimelineResource(SP<CWpLinuxDrmSyncobjTimelineV1> resource_, int fd_); CDRMSyncobjTimelineResource(SP<CWpLinuxDrmSyncobjTimelineV1> resource_, int fd_);
~CDRMSyncobjTimelineResource();
static SP<CDRMSyncobjTimelineResource> fromResource(wl_resource*); static SP<CDRMSyncobjTimelineResource> fromResource(wl_resource*);
bool good(); bool good();

View file

@ -51,7 +51,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHand
} }
} }
g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_FULLSCREEN, true);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
}); });
@ -64,7 +64,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHand
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)
return; return;
g_pCompositor->setWindowFullscreen(PWINDOW, false); g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_FULLSCREEN, false);
}); });
resource->setSetMaximized([this](CZwlrForeignToplevelHandleV1* p) { resource->setSetMaximized([this](CZwlrForeignToplevelHandleV1* p) {
@ -81,7 +81,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHand
return; return;
} }
g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_MAXIMIZED); g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_MAXIMIZED, true);
}); });
resource->setUnsetMaximized([this](CZwlrForeignToplevelHandleV1* p) { resource->setUnsetMaximized([this](CZwlrForeignToplevelHandleV1* p) {
@ -93,7 +93,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHand
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)
return; return;
g_pCompositor->setWindowFullscreen(PWINDOW, false); g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_MAXIMIZED, false);
}); });
resource->setClose([this](CZwlrForeignToplevelHandleV1* p) { resource->setClose([this](CZwlrForeignToplevelHandleV1* p) {
@ -119,7 +119,7 @@ wl_resource* CForeignToplevelHandleWlr::res() {
} }
void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) {
if (lastMonitorID == (int64_t)pMonitor->ID) if (lastMonitorID == pMonitor->ID)
return; return;
const auto CLIENT = resource->client(); const auto CLIENT = resource->client();
@ -155,9 +155,9 @@ void CForeignToplevelHandleWlr::sendState() {
*p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED; *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED;
} }
if (PWINDOW->m_bIsFullscreen) { if (PWINDOW->isFullscreen()) {
auto p = (uint32_t*)wl_array_add(&state, sizeof(uint32_t)); auto p = (uint32_t*)wl_array_add(&state, sizeof(uint32_t));
if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) if (PWINDOW->isEffectiveInternalFSMode(FSMODE_FULLSCREEN))
*p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN; *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN;
else else
*p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED; *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED;

View file

@ -20,7 +20,7 @@ class CForeignToplevelHandleWlr {
SP<CZwlrForeignToplevelHandleV1> resource; SP<CZwlrForeignToplevelHandleV1> resource;
PHLWINDOWREF pWindow; PHLWINDOWREF pWindow;
bool closed = false; bool closed = false;
int64_t lastMonitorID = -1; MONITORID lastMonitorID = MONITOR_INVALID;
void sendMonitor(CMonitor* pMonitor); void sendMonitor(CMonitor* pMonitor);
void sendState(); void sendState();

View file

@ -1,117 +1,61 @@
#include "GlobalShortcuts.hpp" #include "GlobalShortcuts.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#define GLOBAL_SHORTCUTS_VERSION 1 #define LOGM PROTO::globalShortcuts->protoLog
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { CShortcutClient::CShortcutClient(SP<CHyprlandGlobalShortcutsManagerV1> resource_) : resource(resource_) {
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->bindManager(client, data, version, id); if (!good())
}
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
CGlobalShortcutsProtocolManager* proto = wl_container_of(listener, proto, m_liDisplayDestroy);
proto->displayDestroy();
}
void CGlobalShortcutsProtocolManager::displayDestroy() {
wl_list_remove(&m_liDisplayDestroy.link);
wl_list_init(&m_liDisplayDestroy.link);
wl_global_destroy(m_pGlobal);
}
CGlobalShortcutsProtocolManager::~CGlobalShortcutsProtocolManager() {
displayDestroy();
}
CGlobalShortcutsProtocolManager::CGlobalShortcutsProtocolManager() {
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_global_shortcuts_manager_v1_interface, GLOBAL_SHORTCUTS_VERSION, this, bindManagerInt);
if (!m_pGlobal) {
Debug::log(ERR, "GlobalShortcutsManager could not start!");
return; return;
}
m_liDisplayDestroy.notify = handleDisplayDestroy; resource->setOnDestroy([this](CHyprlandGlobalShortcutsManagerV1* pMgr) { PROTO::globalShortcuts->destroyResource(this); });
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); resource->setDestroy([this](CHyprlandGlobalShortcutsManagerV1* pMgr) { PROTO::globalShortcuts->destroyResource(this); });
Debug::log(LOG, "GlobalShortcutsManager started successfully!"); resource->setRegisterShortcut([this](CHyprlandGlobalShortcutsManagerV1* pMgr, uint32_t shortcut, const char* id, const char* app_id, const char* description,
} const char* trigger_description) {
if (PROTO::globalShortcuts->isTaken(id, app_id)) {
static void handleRegisterShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description, resource->error(HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken");
const char* trigger_description) { return;
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->registerShortcut(client, resource, shortcut, id, app_id, description, trigger_description);
}
static void handleDestroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
static const struct hyprland_global_shortcuts_manager_v1_interface globalShortcutsManagerImpl = {
.register_shortcut = handleRegisterShortcut,
.destroy = handleDestroy,
};
static const struct hyprland_global_shortcut_v1_interface shortcutImpl = {
.destroy = handleDestroy,
};
void CGlobalShortcutsProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
const auto RESOURCE = wl_resource_create(client, &hyprland_global_shortcuts_manager_v1_interface, version, id);
wl_resource_set_implementation(RESOURCE, &globalShortcutsManagerImpl, this, nullptr);
Debug::log(LOG, "GlobalShortcutsManager bound successfully!");
m_vClients.emplace_back(std::make_unique<SShortcutClient>(client));
}
SShortcutClient* CGlobalShortcutsProtocolManager::clientFromWlClient(wl_client* client) {
for (auto& c : m_vClients) {
if (c->client == client) {
return c.get();
} }
}
return nullptr; const auto PSHORTCUT = shortcuts.emplace_back(makeShared<SShortcut>(makeShared<CHyprlandGlobalShortcutV1>(resource->client(), resource->version(), shortcut)));
} PSHORTCUT->id = id;
PSHORTCUT->description = description;
PSHORTCUT->appid = app_id;
PSHORTCUT->shortcut = shortcut;
static void onShortcutDestroy(wl_resource* pResource) { if (!PSHORTCUT->resource->resource()) {
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->destroyShortcut(pResource); PSHORTCUT->resource->noMemory();
} shortcuts.pop_back();
return;
void CGlobalShortcutsProtocolManager::registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description,
const char* trigger_description) {
const auto PCLIENT = clientFromWlClient(client);
if (!PCLIENT) {
Debug::log(ERR, "Error at global shortcuts: no client in register?");
return;
}
for (auto& c : m_vClients) {
for (auto& sh : c->shortcuts) {
if (sh->appid == app_id && sh->id == id) {
wl_resource_post_error(resource, HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken");
return;
}
} }
}
const auto PSHORTCUT = PCLIENT->shortcuts.emplace_back(std::make_unique<SShortcut>()).get(); PSHORTCUT->resource->setDestroy([this](CHyprlandGlobalShortcutV1* pMgr) { std::erase_if(shortcuts, [&](const auto& other) { return other->resource.get() == pMgr; }); });
PSHORTCUT->id = id; });
PSHORTCUT->description = description; }
PSHORTCUT->appid = app_id;
PSHORTCUT->shortcut = shortcut;
PSHORTCUT->resource = wl_resource_create(client, &hyprland_global_shortcut_v1_interface, 1, shortcut); bool CShortcutClient::good() {
if (!PSHORTCUT->resource) { return resource->resource();
}
CGlobalShortcutsProtocol::CGlobalShortcutsProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CGlobalShortcutsProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESROUCE = m_vClients.emplace_back(makeShared<CShortcutClient>(makeShared<CHyprlandGlobalShortcutsManagerV1>(client, ver, id)));
if (!RESROUCE->good()) {
wl_client_post_no_memory(client); wl_client_post_no_memory(client);
std::erase_if(PCLIENT->shortcuts, [&](const auto& other) { return other.get() == PSHORTCUT; }); m_vClients.pop_back();
return; return;
} }
wl_resource_set_implementation(PSHORTCUT->resource, &shortcutImpl, this, &onShortcutDestroy);
} }
bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, std::string trigger) { void CGlobalShortcutsProtocol::destroyResource(CShortcutClient* client) {
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
}
bool CGlobalShortcutsProtocol::isTaken(std::string appid, std::string trigger) {
for (auto& c : m_vClients) { for (auto& c : m_vClients) {
for (auto& sh : c->shortcuts) { for (auto& sh : c->shortcuts) {
if (sh->appid == appid && sh->id == trigger) { if (sh->appid == appid && sh->id == trigger) {
@ -123,7 +67,7 @@ bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, st
return false; return false;
} }
void CGlobalShortcutsProtocolManager::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) { void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) {
for (auto& c : m_vClients) { for (auto& c : m_vClients) {
for (auto& sh : c->shortcuts) { for (auto& sh : c->shortcuts) {
if (sh->appid == appid && sh->id == trigger) { if (sh->appid == appid && sh->id == trigger) {
@ -132,15 +76,15 @@ void CGlobalShortcutsProtocolManager::sendGlobalShortcutEvent(std::string appid,
uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
if (pressed) if (pressed)
hyprland_global_shortcut_v1_send_pressed(sh->resource, tvSecHi, tvSecLo, now.tv_nsec); sh->resource->sendPressed(tvSecHi, tvSecLo, now.tv_nsec);
else else
hyprland_global_shortcut_v1_send_released(sh->resource, tvSecHi, tvSecLo, now.tv_nsec); sh->resource->sendReleased(tvSecHi, tvSecLo, now.tv_nsec);
} }
} }
} }
} }
std::vector<SShortcut> CGlobalShortcutsProtocolManager::getAllShortcuts() { std::vector<SShortcut> CGlobalShortcutsProtocol::getAllShortcuts() {
std::vector<SShortcut> copy; std::vector<SShortcut> copy;
for (auto& c : m_vClients) { for (auto& c : m_vClients) {
for (auto& sh : c->shortcuts) { for (auto& sh : c->shortcuts) {
@ -150,9 +94,3 @@ std::vector<SShortcut> CGlobalShortcutsProtocolManager::getAllShortcuts() {
return copy; return copy;
} }
void CGlobalShortcutsProtocolManager::destroyShortcut(wl_resource* resource) {
for (auto& c : m_vClients) {
std::erase_if(c->shortcuts, [&](const auto& other) { return other->resource == resource; });
}
}

View file

@ -1,42 +1,43 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "hyprland-global-shortcuts-v1-protocol.h" #include "hyprland-global-shortcuts-v1.hpp"
#include "../protocols/WaylandProtocol.hpp"
#include <vector> #include <vector>
struct SShortcut { struct SShortcut {
wl_resource* resource; SP<CHyprlandGlobalShortcutV1> resource;
std::string id, description, appid; std::string id, description, appid;
uint32_t shortcut = 0; uint32_t shortcut = 0;
}; };
struct SShortcutClient { class CShortcutClient {
wl_client* client = nullptr;
std::vector<std::unique_ptr<SShortcut>> shortcuts;
};
class CGlobalShortcutsProtocolManager {
public: public:
CGlobalShortcutsProtocolManager(); CShortcutClient(SP<CHyprlandGlobalShortcutsManagerV1> resource);
~CGlobalShortcutsProtocolManager();
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); bool good();
void displayDestroy();
void registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description,
const char* trigger_description);
void destroyShortcut(wl_resource* resource);
bool globalShortcutExists(std::string appid, std::string trigger);
void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed);
std::vector<SShortcut> getAllShortcuts();
wl_listener m_liDisplayDestroy;
private: private:
std::vector<std::unique_ptr<SShortcutClient>> m_vClients; SP<CHyprlandGlobalShortcutsManagerV1> resource;
std::vector<SP<SShortcut>> shortcuts;
SShortcutClient* clientFromWlClient(wl_client* client); friend class CGlobalShortcutsProtocol;
};
wl_global* m_pGlobal = nullptr;
class CGlobalShortcutsProtocol : IWaylandProtocol {
public:
CGlobalShortcutsProtocol(const wl_interface* iface, const int& ver, const std::string& name);
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
void destroyResource(CShortcutClient* client);
void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed);
bool isTaken(std::string id, std::string app_id);
std::vector<SShortcut> getAllShortcuts();
private:
std::vector<SP<CShortcutClient>> m_vClients;
};
namespace PROTO {
inline UP<CGlobalShortcutsProtocol> globalShortcuts;
}; };

View file

@ -107,14 +107,14 @@ CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_,
}); });
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
if (pSurface->current.buffer && !mapped) { if (pSurface->current.texture && !mapped) {
mapped = true; mapped = true;
pSurface->map(); pSurface->map();
events.map.emit(); events.map.emit();
return; return;
} }
if (!pSurface->current.buffer && mapped) { if (!pSurface->current.texture && mapped) {
mapped = false; mapped = false;
pSurface->unmap(); pSurface->unmap();
events.unmap.emit(); events.unmap.emit();

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