mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-23 13:05:57 +01:00
Merge branch 'main' into main
This commit is contained in:
commit
b16d2e2c51
121 changed files with 3175 additions and 2490 deletions
5
.github/workflows/ci.yaml
vendored
5
.github/workflows/ci.yaml
vendored
|
@ -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:
|
||||||
|
|
6
.github/workflows/nix-build.yml
vendored
6
.github/workflows/nix-build.yml
vendored
|
@ -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 }}'
|
||||||
|
|
2
.github/workflows/nix-ci.yml
vendored
2
.github/workflows/nix-ci.yml
vendored
|
@ -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
|
||||||
|
|
1
.github/workflows/security-checks.yml
vendored
1
.github/workflows/security-checks.yml
vendored
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -115,7 +113,7 @@ pkg_check_modules(
|
||||||
gbm
|
gbm
|
||||||
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 +230,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,17 +262,12 @@ 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("protocols/wlr-screencopy-unstable-v1.xml"
|
protocolnew("subprojects/hyprland-protocols/protocols"
|
||||||
"wlr-screencopy-unstable-v1" true)
|
|
||||||
protocol(
|
|
||||||
"subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml"
|
|
||||||
"hyprland-global-shortcuts-v1" true)
|
"hyprland-global-shortcuts-v1" true)
|
||||||
protocol(
|
protocolnew("unstable/text-input" "text-input-unstable-v1" false)
|
||||||
"subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml"
|
protocolnew("subprojects/hyprland-protocols/protocols"
|
||||||
"hyprland-toplevel-export-v1" true)
|
"hyprland-toplevel-export-v1" true)
|
||||||
protocol("unstable/text-input/text-input-unstable-v1.xml"
|
protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
|
||||||
"text-input-unstable-v1" false)
|
|
||||||
|
|
||||||
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)
|
||||||
protocolnew("protocols" "wlr-output-power-management-unstable-v1" true)
|
protocolnew("protocols" "wlr-output-power-management-unstable-v1" true)
|
||||||
|
@ -359,19 +328,22 @@ install(
|
||||||
|
|
||||||
# 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")
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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')
|
||||||
|
|
30
flake.lock
30
flake.lock
|
@ -16,11 +16,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721571743,
|
"lastModified": 1722347739,
|
||||||
"narHash": "sha256-hat7wggtDISBJD8kTo5MTrT+IsY/Ha2MwgjmqqijoCA=",
|
"narHash": "sha256-rAoh+K6KG+b1DwSWtqRVocdojnH6nGk6q07mNltoUSM=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "aquamarine",
|
"repo": "aquamarine",
|
||||||
"rev": "601f6cf95cbe4fef02dc7faf34bba58566c914e9",
|
"rev": "7c3565f9bedc7cb601cc0baa14792247e4dc1d5a",
|
||||||
"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": 1722098849,
|
||||||
"narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=",
|
"narHash": "sha256-D3wIZlBNh7LuZ0NaoCpY/Pvu+xHxIVtSN+KkWZYvvVs=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprutils",
|
"repo": "hyprutils",
|
||||||
"rev": "962582a090bc233c4de9d9897f46794280288989",
|
"rev": "5dcbbc1e3de40b2cecfd2007434d86e924468f1f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -154,11 +154,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721379653,
|
"lastModified": 1722185531,
|
||||||
"narHash": "sha256-8MUgifkJ7lkZs3u99UDZMB4kbOxvMEXQZ31FO3SopZ0=",
|
"narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "1d9c2c9b3e71b9ee663d11c5d298727dace8d374",
|
"rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -209,11 +209,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720194466,
|
"lastModified": 1722365976,
|
||||||
"narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=",
|
"narHash": "sha256-Khdm+mDzYA//XaU0M+hftod+rKr5q9SSHSEuiQ0/9ow=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "xdg-desktop-portal-hyprland",
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
"rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6",
|
"rev": "7f2a77ddf60390248e2a3de2261d7102a13e5341",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -141,7 +141,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(), ' ');
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 = "";
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ project('Hyprland', 'cpp', 'c',
|
||||||
'cpp_std=c++23',
|
'cpp_std=c++23',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
libuuid,
|
libuuid,
|
||||||
libxkbcommon,
|
libxkbcommon,
|
||||||
mesa,
|
mesa,
|
||||||
meson,
|
|
||||||
pango,
|
pango,
|
||||||
pciutils,
|
pciutils,
|
||||||
pcre2,
|
pcre2,
|
||||||
|
@ -90,7 +89,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||||
jq
|
jq
|
||||||
makeWrapper
|
makeWrapper
|
||||||
cmake
|
cmake
|
||||||
meson # for wlroots
|
|
||||||
ninja
|
ninja
|
||||||
pkg-config
|
pkg-config
|
||||||
python3 # for udis86
|
python3 # for udis86
|
||||||
|
@ -114,10 +112,12 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||||
hyprcursor
|
hyprcursor
|
||||||
hyprlang
|
hyprlang
|
||||||
hyprutils
|
hyprutils
|
||||||
libGL
|
|
||||||
libdrm
|
|
||||||
libdatrie
|
libdatrie
|
||||||
|
libdisplay-info
|
||||||
|
libdrm
|
||||||
|
libGL
|
||||||
libinput
|
libinput
|
||||||
|
libliftoff
|
||||||
libselinux
|
libselinux
|
||||||
libsepol
|
libsepol
|
||||||
libthai
|
libthai
|
||||||
|
@ -127,13 +127,10 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
||||||
pango
|
pango
|
||||||
pciutils
|
pciutils
|
||||||
pcre2
|
pcre2
|
||||||
|
seatd
|
||||||
tomlplusplus
|
tomlplusplus
|
||||||
wayland
|
wayland
|
||||||
wayland-protocols
|
wayland-protocols
|
||||||
# for wlroots
|
|
||||||
seatd
|
|
||||||
libdisplay-info
|
|
||||||
libliftoff
|
|
||||||
]
|
]
|
||||||
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
|
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
|
||||||
(lib.optionals enableXWayland [
|
(lib.optionals enableXWayland [
|
||||||
|
|
|
@ -12,24 +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'],
|
|
||||||
['wlr-screencopy-unstable-v1.xml'],
|
|
||||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-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'],
|
||||||
|
@ -42,6 +30,9 @@ new_protocols = [
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
['wlr-layer-shell-unstable-v1.xml'],
|
||||||
['wayland-drm.xml'],
|
['wayland-drm.xml'],
|
||||||
['wlr-data-control-unstable-v1.xml'],
|
['wlr-data-control-unstable-v1.xml'],
|
||||||
|
['wlr-screencopy-unstable-v1.xml'],
|
||||||
|
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'],
|
||||||
|
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
|
||||||
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
|
[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'],
|
||||||
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
|
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-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)
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -43,7 +44,7 @@ int handleCritSignal(int signo, void* data) {
|
||||||
Debug::log(LOG, "Hyprland received signal {}", signo);
|
Debug::log(LOG, "Hyprland received signal {}", signo);
|
||||||
|
|
||||||
if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL)
|
if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL)
|
||||||
g_pCompositor->cleanup();
|
g_pCompositor->stopCompositor();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -193,6 +194,7 @@ CCompositor::CCompositor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CCompositor::~CCompositor() {
|
CCompositor::~CCompositor() {
|
||||||
|
if (!m_bIsShuttingDown)
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +209,7 @@ void CCompositor::setRandomSplash() {
|
||||||
static std::vector<SP<Aquamarine::IOutput>> pendingOutputs;
|
static std::vector<SP<Aquamarine::IOutput>> pendingOutputs;
|
||||||
|
|
||||||
//
|
//
|
||||||
void CCompositor::initServer() {
|
void CCompositor::initServer(std::string socketName, int socketFd) {
|
||||||
|
|
||||||
m_sWLDisplay = wl_display_create();
|
m_sWLDisplay = wl_display_create();
|
||||||
|
|
||||||
|
@ -246,7 +248,7 @@ void CCompositor::initServer() {
|
||||||
|
|
||||||
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!");
|
||||||
}
|
}
|
||||||
|
@ -257,7 +259,7 @@ void CCompositor::initServer() {
|
||||||
|
|
||||||
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!");
|
||||||
}
|
}
|
||||||
|
@ -267,6 +269,15 @@ void CCompositor::initServer() {
|
||||||
m_iDRMFD = m_pAqBackend->drmFD();
|
m_iDRMFD = m_pAqBackend->drmFD();
|
||||||
Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD);
|
Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD);
|
||||||
|
|
||||||
|
if (!socketName.empty() && socketFd != -1) {
|
||||||
|
fcntl(socketFd, F_SETFD, FD_CLOEXEC);
|
||||||
|
const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd);
|
||||||
|
if (RETVAL >= 0) {
|
||||||
|
m_szWLDisplaySocket = socketName;
|
||||||
|
Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL);
|
||||||
|
} else
|
||||||
|
Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL);
|
||||||
|
} else {
|
||||||
// get socket, avoid using 0
|
// get socket, avoid using 0
|
||||||
for (int candidate = 1; candidate <= 32; candidate++) {
|
for (int candidate = 1; candidate <= 32; candidate++) {
|
||||||
const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
|
const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
|
||||||
|
@ -275,7 +286,7 @@ void CCompositor::initServer() {
|
||||||
m_szWLDisplaySocket = CANDIDATESTR;
|
m_szWLDisplaySocket = CANDIDATESTR;
|
||||||
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
|
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else
|
||||||
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
|
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,7 +303,6 @@ void CCompositor::initServer() {
|
||||||
throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
|
throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug::log(LOG, "Setting WAYLAND_DISPLAY to {}", m_szWLDisplaySocket);
|
|
||||||
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
|
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
|
||||||
setenv("XDG_SESSION_TYPE", "wayland", 1);
|
setenv("XDG_SESSION_TYPE", "wayland", 1);
|
||||||
|
|
||||||
|
@ -424,8 +434,16 @@ void CCompositor::cleanEnvironment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCompositor::stopCompositor() {
|
||||||
|
Debug::log(LOG, "Hyprland is stopping!");
|
||||||
|
|
||||||
|
// this stops the wayland loop, wl_display_run
|
||||||
|
wl_display_terminate(m_sWLDisplay);
|
||||||
|
m_bIsShuttingDown = true;
|
||||||
|
}
|
||||||
|
|
||||||
void CCompositor::cleanup() {
|
void CCompositor::cleanup() {
|
||||||
if (!m_sWLDisplay || m_bIsShuttingDown)
|
if (!m_sWLDisplay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
signal(SIGABRT, SIG_DFL);
|
signal(SIGABRT, SIG_DFL);
|
||||||
|
@ -499,13 +517,10 @@ void CCompositor::cleanup() {
|
||||||
if (m_critSigSource)
|
if (m_critSigSource)
|
||||||
wl_event_source_remove(m_critSigSource);
|
wl_event_source_remove(m_critSigSource);
|
||||||
|
|
||||||
wl_event_loop_destroy(m_sWLEventLoop);
|
// this frees all wayland resources, including sockets
|
||||||
wl_display_terminate(m_sWLDisplay);
|
wl_display_destroy(m_sWLDisplay);
|
||||||
m_sWLDisplay = nullptr;
|
|
||||||
|
|
||||||
std::string waylandSocket = std::string{getenv("XDG_RUNTIME_DIR")} + "/" + m_szWLDisplaySocket;
|
Debug::close();
|
||||||
std::filesystem::remove(waylandSocket);
|
|
||||||
std::filesystem::remove(waylandSocket + ".lock");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCompositor::initManagers(eManagersInitStage stage) {
|
void CCompositor::initManagers(eManagersInitStage stage) {
|
||||||
|
@ -631,44 +646,7 @@ void CCompositor::prepareFallbackOutput() {
|
||||||
headless->createOutput();
|
headless->createOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCompositor::startCompositor(std::string socketName, int socketFd) {
|
void CCompositor::startCompositor() {
|
||||||
if (!socketName.empty() && socketFd != -1) {
|
|
||||||
fcntl(socketFd, F_SETFD, FD_CLOEXEC);
|
|
||||||
const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd);
|
|
||||||
if (RETVAL >= 0) {
|
|
||||||
m_szWLDisplaySocket = socketName;
|
|
||||||
Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL);
|
|
||||||
} else
|
|
||||||
Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL);
|
|
||||||
} else {
|
|
||||||
// get socket, avoid using 0
|
|
||||||
for (int candidate = 1; candidate <= 32; candidate++) {
|
|
||||||
const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate));
|
|
||||||
const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str());
|
|
||||||
if (RETVAL >= 0) {
|
|
||||||
m_szWLDisplaySocket = CANDIDATESTR;
|
|
||||||
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_szWLDisplaySocket.empty()) {
|
|
||||||
Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto");
|
|
||||||
const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay);
|
|
||||||
if (SOCKETSTR)
|
|
||||||
m_szWLDisplaySocket = SOCKETSTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_szWLDisplaySocket.empty()) {
|
|
||||||
Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
|
|
||||||
throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
|
|
||||||
}
|
|
||||||
|
|
||||||
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
|
|
||||||
setenv("XDG_SESSION_TYPE", "wayland", 1);
|
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
|
if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
|
||||||
|
@ -1129,7 +1107,7 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) {
|
if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) {
|
||||||
Debug::log(LOG, "surface {:x} won't receive kb focus becuase grab rejected it", (uintptr_t)pSurface);
|
Debug::log(LOG, "surface {:x} won't receive kb focus becuase grab rejected it", (uintptr_t)pSurface.get());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1152,9 +1130,9 @@ void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindo
|
||||||
g_pSeatManager->setKeyboardFocus(pSurface);
|
g_pSeatManager->setKeyboardFocus(pSurface);
|
||||||
|
|
||||||
if (pWindowOwner)
|
if (pWindowOwner)
|
||||||
Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface, pWindowOwner);
|
Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface.get(), pWindowOwner);
|
||||||
else
|
else
|
||||||
Debug::log(LOG, "Set keyboard focus to surface {:x}", (uintptr_t)pSurface);
|
Debug::log(LOG, "Set keyboard focus to surface {:x}", (uintptr_t)pSurface.get());
|
||||||
|
|
||||||
g_pXWaylandManager->activateSurface(pSurface, true);
|
g_pXWaylandManager->activateSurface(pSurface, true);
|
||||||
m_pLastFocus = pSurface;
|
m_pLastFocus = pSurface;
|
||||||
|
@ -1213,15 +1191,10 @@ SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, st
|
||||||
}
|
}
|
||||||
|
|
||||||
PHLWINDOW CCompositor::getWindowFromSurface(SP<CWLSurfaceResource> pSurface) {
|
PHLWINDOW CCompositor::getWindowFromSurface(SP<CWLSurfaceResource> pSurface) {
|
||||||
for (auto& w : m_vWindows) {
|
if (!pSurface || !pSurface->hlSurface)
|
||||||
if (!w->m_bIsMapped || w->m_bFadingOut)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (w->m_pWLSurface->resource() == pSurface)
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
return pSurface->hlSurface->getWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) {
|
PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) {
|
||||||
|
@ -1236,7 +1209,7 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) {
|
||||||
|
|
||||||
PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const int& ID) {
|
PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const int& 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1524,7 +1497,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);
|
||||||
|
@ -1537,13 +1510,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)
|
||||||
|
@ -1629,13 +1602,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)
|
||||||
|
@ -1917,7 +1890,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)
|
||||||
|
@ -1987,7 +1960,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;
|
||||||
}
|
}
|
||||||
|
@ -2012,7 +1985,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;
|
||||||
}
|
}
|
||||||
|
@ -2189,7 +2162,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;
|
||||||
}
|
}
|
||||||
|
@ -2264,12 +2237,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2279,52 +2252,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) {
|
||||||
if (!validMapped(pWindow) || g_pCompositor->m_bUnsafeState)
|
setWindowFullscreenInternal(
|
||||||
|
PWINDOW, (eFullscreenMode)(ON ? (uint8_t)PWINDOW->m_sFullscreenState.internal | (uint8_t)MODE : ((uint8_t)PWINDOW->m_sFullscreenState.internal & (uint8_t)~MODE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 PNODIRECTSCANOUT = CConfigValue<Hyprlang::INT>("misc:no_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();
|
||||||
|
|
||||||
|
@ -2333,7 +2341,9 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 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.
|
||||||
g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr);
|
// ignore if DS is disabled.
|
||||||
|
if (!*PNODIRECTSCANOUT)
|
||||||
|
g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr);
|
||||||
|
|
||||||
g_pConfigManager->ensureVRR(PMONITOR);
|
g_pConfigManager->ensureVRR(PMONITOR);
|
||||||
}
|
}
|
||||||
|
@ -2665,11 +2675,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);
|
||||||
|
@ -2702,7 +2712,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());
|
||||||
|
@ -2861,7 +2871,7 @@ void CCompositor::setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, d
|
||||||
|
|
||||||
const auto PSURFACE = CWLSurface::fromResource(pSurface);
|
const auto PSURFACE = CWLSurface::fromResource(pSurface);
|
||||||
if (!PSURFACE) {
|
if (!PSURFACE) {
|
||||||
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface);
|
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface.get());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2874,7 +2884,7 @@ void CCompositor::setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurfac
|
||||||
|
|
||||||
const auto PSURFACE = CWLSurface::fromResource(pSurface);
|
const auto PSURFACE = CWLSurface::fromResource(pSurface);
|
||||||
if (!PSURFACE) {
|
if (!PSURFACE) {
|
||||||
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface);
|
Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface.get());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,9 @@ class CCompositor {
|
||||||
|
|
||||||
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
|
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
|
||||||
|
|
||||||
void initServer();
|
void initServer(std::string socketName, int socketFd);
|
||||||
void startCompositor(std::string socketName, int socketFd);
|
void startCompositor();
|
||||||
|
void stopCompositor();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void createLockFile();
|
void createLockFile();
|
||||||
void removeLockFile();
|
void removeLockFile();
|
||||||
|
@ -145,7 +146,11 @@ class CCompositor {
|
||||||
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 int64_t&);
|
||||||
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);
|
||||||
|
|
|
@ -669,7 +669,7 @@ std::string CConfigManager::getConfigDir() {
|
||||||
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.");
|
||||||
|
@ -1141,7 +1141,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;
|
||||||
|
@ -1340,12 +1340,14 @@ void CConfigManager::dispatchExecOnce() {
|
||||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS");
|
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS");
|
||||||
|
|
||||||
firstExecDispatched = true;
|
firstExecDispatched = true;
|
||||||
|
isLaunchingExecOnce = true;
|
||||||
|
|
||||||
for (auto& c : firstExecRequests) {
|
for (auto& c : firstExecRequests) {
|
||||||
handleRawExec("", c);
|
handleRawExec("", c);
|
||||||
}
|
}
|
||||||
|
|
||||||
firstExecRequests.clear(); // free some kb of memory :P
|
firstExecRequests.clear(); // free some kb of memory :P
|
||||||
|
isLaunchingExecOnce = false;
|
||||||
|
|
||||||
// set input, fixes some certain issues
|
// set input, fixes some certain issues
|
||||||
g_pInputManager->setKeyboardLayout();
|
g_pInputManager->setKeyboardLayout();
|
||||||
|
@ -1487,7 +1489,7 @@ 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->setAdaptiveSync(true);
|
m->output->state->setAdaptiveSync(true);
|
||||||
|
@ -2024,6 +2026,7 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
||||||
bool ignoreMods = false;
|
bool ignoreMods = false;
|
||||||
bool multiKey = false;
|
bool multiKey = false;
|
||||||
bool hasDescription = false;
|
bool hasDescription = false;
|
||||||
|
bool dontInhibit = false;
|
||||||
const auto BINDARGS = command.substr(4);
|
const auto BINDARGS = command.substr(4);
|
||||||
|
|
||||||
for (auto& arg : BINDARGS) {
|
for (auto& arg : BINDARGS) {
|
||||||
|
@ -2045,6 +2048,8 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
||||||
multiKey = true;
|
multiKey = true;
|
||||||
} else if (arg == 'd') {
|
} else if (arg == 'd') {
|
||||||
hasDescription = true;
|
hasDescription = true;
|
||||||
|
} else if (arg == 'p') {
|
||||||
|
dontInhibit = true;
|
||||||
} else {
|
} else {
|
||||||
return "bind: invalid flag";
|
return "bind: invalid flag";
|
||||||
}
|
}
|
||||||
|
@ -2113,8 +2118,9 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
||||||
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
|
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION,
|
g_pKeybindManager->addKeybind(SKeybind{
|
||||||
release, repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription});
|
parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release,
|
||||||
|
repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -2134,11 +2140,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, ' ');
|
||||||
|
|
|
@ -158,9 +158,6 @@ class CConfigManager {
|
||||||
void performMonitorReload();
|
void performMonitorReload();
|
||||||
void appendMonitorRule(const SMonitorRule&);
|
void appendMonitorRule(const SMonitorRule&);
|
||||||
bool replaceMonitorRule(const SMonitorRule&);
|
bool replaceMonitorRule(const SMonitorRule&);
|
||||||
bool m_bWantsMonitorReload = false;
|
|
||||||
bool m_bForceReload = false;
|
|
||||||
bool m_bNoMonitorReload = false;
|
|
||||||
void ensureMonitorStatus();
|
void ensureMonitorStatus();
|
||||||
void ensureVRR(CMonitor* pMonitor = nullptr);
|
void ensureVRR(CMonitor* pMonitor = nullptr);
|
||||||
|
|
||||||
|
@ -212,8 +209,10 @@ class CConfigManager {
|
||||||
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
|
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
|
||||||
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
|
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
|
||||||
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
|
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
|
||||||
|
{"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; }},
|
||||||
};
|
};
|
||||||
|
@ -222,6 +221,12 @@ class CConfigManager {
|
||||||
{"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
|
{"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
|
||||||
|
|
||||||
|
|
||||||
|
bool m_bWantsMonitorReload = false;
|
||||||
|
bool m_bForceReload = false;
|
||||||
|
bool m_bNoMonitorReload = false;
|
||||||
|
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
|
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||||
finalCrashReport += GIT_COMMIT_HASH;
|
finalCrashReport += GIT_COMMIT_HASH;
|
||||||
finalCrashReport += "\nTag: ";
|
finalCrashReport += "\nTag: ";
|
||||||
finalCrashReport += GIT_TAG;
|
finalCrashReport += GIT_TAG;
|
||||||
finalCrashReport += "\n\n";
|
finalCrashReport += "\nDate: ";
|
||||||
|
finalCrashReport += GIT_COMMIT_DATE;
|
||||||
|
finalCrashReport += "\nFlags:\n";
|
||||||
|
#ifdef LEGACY_RENDERER
|
||||||
|
finalCrashReport += "legacyrenderer\n";
|
||||||
|
#endif
|
||||||
|
#ifndef ISDEBUG
|
||||||
|
finalCrashReport += "debug\n";
|
||||||
|
#endif
|
||||||
|
#ifdef NO_XWAYLAND
|
||||||
|
finalCrashReport += "no xwayland\n";
|
||||||
|
#endif
|
||||||
|
finalCrashReport += "\n";
|
||||||
|
|
||||||
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
|
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
|
||||||
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
|
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debug::close() {
|
||||||
|
logOfs.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debug::log(LogLevel level, std::string str) {
|
void Debug::log(LogLevel level, std::string str) {
|
||||||
|
@ -55,11 +60,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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -66,5 +72,6 @@ namespace Debug {
|
||||||
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
|
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
|
||||||
|
|
||||||
log(level, logMsg);
|
log(level, logMsg);
|
||||||
|
logMutex.unlock();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,7 +74,7 @@ CLayerSurface::~CLayerSurface() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLayerSurface::onDestroy() {
|
void CLayerSurface::onDestroy() {
|
||||||
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface);
|
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||||
|
|
||||||
|
@ -111,14 +111,21 @@ 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() {
|
||||||
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface);
|
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get());
|
||||||
|
|
||||||
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;
|
||||||
|
@ -177,7 +184,7 @@ void CLayerSurface::onMap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLayerSurface::onUnmap() {
|
void CLayerSurface::onUnmap() {
|
||||||
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface);
|
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface.get());
|
||||||
|
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace});
|
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace});
|
||||||
EMIT_HOOK_EVENT("closeLayer", self.lock());
|
EMIT_HOOK_EVENT("closeLayer", self.lock());
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -212,8 +223,11 @@ void CLayerSurface::onUnmap() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// refocus if needed
|
// refocus if needed
|
||||||
if (WASLASTFOCUS)
|
// 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 && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
|
||||||
g_pInputManager->refocusLastWindow(PMONITOR);
|
g_pInputManager->refocusLastWindow(PMONITOR);
|
||||||
|
else if (g_pCompositor->m_pLastFocus)
|
||||||
|
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
|
||||||
|
|
||||||
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);
|
||||||
|
@ -233,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);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -74,7 +74,7 @@ class CPopup {
|
||||||
} listeners;
|
} listeners;
|
||||||
|
|
||||||
void initAllSignals();
|
void initAllSignals();
|
||||||
void unconstrain();
|
void reposition();
|
||||||
void recheckChildrenRecursive();
|
void recheckChildrenRecursive();
|
||||||
void sendScale();
|
void sendScale();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "WLSurface.hpp"
|
#include "WLSurface.hpp"
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
#include "../protocols/LayerShell.hpp"
|
||||||
|
|
||||||
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
|
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
|
||||||
m_pResource = pSurface;
|
m_pResource = pSurface;
|
||||||
|
@ -56,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 {
|
||||||
|
@ -74,33 +75,52 @@ Vector2D CWLSurface::correctSmallVec() const {
|
||||||
return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize);
|
return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D CWLSurface::getViewporterCorrectedSize() const {
|
Vector2D CWLSurface::correctSmallVecBuf() const {
|
||||||
if (!exists() || !m_pResource->current.buffer)
|
if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size;
|
const auto SIZE = getViewporterCorrectedSize();
|
||||||
|
const auto BS = m_pResource->current.bufferSize;
|
||||||
|
|
||||||
|
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
|
||||||
}
|
}
|
||||||
|
|
||||||
CRegion CWLSurface::logicalDamage() const {
|
Vector2D CWLSurface::getViewporterCorrectedSize() const {
|
||||||
if (!m_pResource->current.buffer)
|
if (!exists() || !m_pResource->current.texture)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRegion CWLSurface::computeDamage() const {
|
||||||
|
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);
|
||||||
damage.scale(1.0 / m_pResource->current.scale);
|
|
||||||
|
|
||||||
const auto VPSIZE = getViewporterCorrectedSize();
|
const auto BUFSIZE = m_pResource->current.bufferSize;
|
||||||
const auto CORRECTVEC = correctSmallVec();
|
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({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y});
|
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
|
||||||
damage.translate(CORRECTVEC);
|
damage.translate(CORRECTVEC);
|
||||||
|
|
||||||
|
// go from buffer coords in the damage to hl logical
|
||||||
|
|
||||||
|
const auto BOX = getSurfaceBoxGlobal();
|
||||||
|
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 */};
|
||||||
|
|
||||||
|
damage.scale(SCALE);
|
||||||
|
|
||||||
|
if (m_pWindowOwner)
|
||||||
|
damage.scale(m_pWindowOwner->m_fX11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit
|
||||||
|
|
||||||
return damage;
|
return damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,27 +161,27 @@ void CWLSurface::init() {
|
||||||
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
|
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PHLWINDOW CWLSurface::getWindow() {
|
PHLWINDOW CWLSurface::getWindow() const {
|
||||||
return m_pWindowOwner.lock();
|
return m_pWindowOwner.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
PHLLS CWLSurface::getLayer() {
|
PHLLS CWLSurface::getLayer() const {
|
||||||
return m_pLayerOwner.lock();
|
return m_pLayerOwner.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
CPopup* CWLSurface::getPopup() {
|
CPopup* CWLSurface::getPopup() const {
|
||||||
return m_pPopupOwner;
|
return m_pPopupOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSubsurface* CWLSurface::getSubsurface() {
|
CSubsurface* CWLSurface::getSubsurface() const {
|
||||||
return m_pSubsurfaceOwner;
|
return m_pSubsurfaceOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWLSurface::desktopComponent() {
|
bool CWLSurface::desktopComponent() const {
|
||||||
return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner;
|
return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
|
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
|
||||||
if (!desktopComponent())
|
if (!desktopComponent())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -181,7 +201,7 @@ void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
|
||||||
m_pConstraint = constraint;
|
m_pConstraint = constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
SP<CPointerConstraint> CWLSurface::constraint() {
|
SP<CPointerConstraint> CWLSurface::constraint() const {
|
||||||
return m_pConstraint.lock();
|
return m_pConstraint.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,3 +222,11 @@ SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return pSurface->hlSurface.lock();
|
return pSurface->hlSurface.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWLSurface::keyboardFocusable() const {
|
||||||
|
if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner)
|
||||||
|
return true;
|
||||||
|
if (m_pLayerOwner && m_pLayerOwner->layerSurface)
|
||||||
|
return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -35,20 +35,22 @@ class CWLSurface {
|
||||||
bool exists() const;
|
bool exists() const;
|
||||||
bool small() const; // means surface is smaller than the requested size
|
bool small() const; // means surface is smaller than the requested size
|
||||||
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
|
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
|
||||||
|
Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords
|
||||||
Vector2D getViewporterCorrectedSize() const;
|
Vector2D getViewporterCorrectedSize() const;
|
||||||
CRegion logicalDamage() const;
|
CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
|
||||||
bool visible();
|
bool visible();
|
||||||
|
bool keyboardFocusable() const;
|
||||||
|
|
||||||
// getters for owners.
|
// getters for owners.
|
||||||
PHLWINDOW getWindow();
|
PHLWINDOW getWindow() const;
|
||||||
PHLLS getLayer();
|
PHLLS getLayer() const;
|
||||||
CPopup* getPopup();
|
CPopup* getPopup() const;
|
||||||
CSubsurface* getSubsurface();
|
CSubsurface* getSubsurface() const;
|
||||||
|
|
||||||
// desktop components misc utils
|
// desktop components misc utils
|
||||||
std::optional<CBox> getSurfaceBoxGlobal();
|
std::optional<CBox> getSurfaceBoxGlobal() const;
|
||||||
void appendConstraint(WP<CPointerConstraint> constraint);
|
void appendConstraint(WP<CPointerConstraint> constraint);
|
||||||
SP<CPointerConstraint> constraint();
|
SP<CPointerConstraint> constraint() const;
|
||||||
|
|
||||||
// allow stretching. Useful for plugins.
|
// allow stretching. Useful for plugins.
|
||||||
bool m_bFillIgnoreSmall = false;
|
bool m_bFillIgnoreSmall = false;
|
||||||
|
@ -107,7 +109,7 @@ class CWLSurface {
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
void init();
|
void init();
|
||||||
bool desktopComponent();
|
bool desktopComponent() const;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
CHyprSignalListener destroy;
|
CHyprSignalListener destroy;
|
||||||
|
|
|
@ -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,12 +478,6 @@ 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");
|
||||||
|
|
||||||
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");
|
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
|
||||||
|
|
||||||
if (!m_szInitialWorkspaceToken.empty()) {
|
if (!m_szInitialWorkspaceToken.empty()) {
|
||||||
|
@ -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,6 +1235,14 @@ int CWindow::surfacesCount() {
|
||||||
return no;
|
return no;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
int CWindow::workspaceID() {
|
int 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());
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -167,8 +168,10 @@ struct SWindowData {
|
||||||
CWindowOverridableVar<bool> noMaxSize = false;
|
CWindowOverridableVar<bool> noMaxSize = false;
|
||||||
CWindowOverridableVar<bool> noRounding = false;
|
CWindowOverridableVar<bool> noRounding = false;
|
||||||
CWindowOverridableVar<bool> noShadow = false;
|
CWindowOverridableVar<bool> noShadow = 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;
|
||||||
|
|
||||||
|
@ -207,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>);
|
||||||
|
@ -260,9 +268,8 @@ class CWindow {
|
||||||
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_bDontSendFullscreen = false;
|
|
||||||
bool m_bWasMaximized = false;
|
bool m_bWasMaximized = false;
|
||||||
|
sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
|
||||||
uint64_t m_iMonitorID = -1;
|
uint64_t m_iMonitorID = -1;
|
||||||
std::string m_szTitle = "";
|
std::string m_szTitle = "";
|
||||||
std::string m_szClass = "";
|
std::string m_szClass = "";
|
||||||
|
@ -321,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;
|
||||||
|
|
||||||
|
@ -415,7 +419,6 @@ 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();
|
int workspaceID();
|
||||||
|
@ -423,6 +426,9 @@ class CWindow {
|
||||||
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&);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
#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;
|
||||||
|
@ -31,7 +32,7 @@ class CWorkspace {
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,11 @@ void IKeyboard::clearManuallyAllocd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
||||||
|
if (keymapOverridden) {
|
||||||
|
Debug::log(LOG, "Ignoring setKeymap: keymap is overridden");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
currentRules = rules;
|
currentRules = rules;
|
||||||
xkb_rule_names XKBRULES = {
|
xkb_rule_names XKBRULES = {
|
||||||
.rules = rules.rules.c_str(),
|
.rules = rules.rules.c_str(),
|
||||||
|
@ -103,10 +108,6 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
||||||
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set internal translation state
|
|
||||||
// demo sunao ni ienai
|
|
||||||
xkbStaticState = xkb_state_new(xkbKeymap);
|
|
||||||
|
|
||||||
updateXKBTranslationState(xkbKeymap);
|
updateXKBTranslationState(xkbKeymap);
|
||||||
|
|
||||||
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
|
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
|
||||||
|
@ -131,6 +132,20 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
||||||
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
|
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateKeymapFD();
|
||||||
|
|
||||||
|
xkb_context_unref(CONTEXT);
|
||||||
|
|
||||||
|
g_pSeatManager->updateActiveKeyboardData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IKeyboard::updateKeymapFD() {
|
||||||
|
Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName);
|
||||||
|
|
||||||
|
if (xkbKeymapFD >= 0)
|
||||||
|
close(xkbKeymapFD);
|
||||||
|
xkbKeymapFD = -1;
|
||||||
|
|
||||||
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
|
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
|
||||||
xkbKeymapString = cKeymapStr;
|
xkbKeymapString = cKeymapStr;
|
||||||
free(cKeymapStr);
|
free(cKeymapStr);
|
||||||
|
@ -151,20 +166,23 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xkb_context_unref(CONTEXT);
|
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD);
|
||||||
|
|
||||||
g_pSeatManager->updateActiveKeyboardData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
|
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
|
||||||
|
|
||||||
|
if (xkbStaticState)
|
||||||
|
xkb_state_unref(xkbStaticState);
|
||||||
|
|
||||||
if (xkbState)
|
if (xkbState)
|
||||||
xkb_state_unref(xkbState);
|
xkb_state_unref(xkbState);
|
||||||
|
|
||||||
xkbState = nullptr;
|
xkbState = nullptr;
|
||||||
|
xkbStaticState = nullptr;
|
||||||
|
|
||||||
if (keymap) {
|
if (keymap) {
|
||||||
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
|
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
|
||||||
|
xkbStaticState = xkb_state_new(keymap);
|
||||||
xkbState = xkb_state_new(keymap);
|
xkbState = xkb_state_new(keymap);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -210,6 +228,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
xkbState = xkb_state_new(KEYMAP);
|
xkbState = xkb_state_new(KEYMAP);
|
||||||
|
xkbStaticState = xkb_state_new(KEYMAP);
|
||||||
|
|
||||||
xkb_keymap_unref(KEYMAP);
|
xkb_keymap_unref(KEYMAP);
|
||||||
xkb_context_unref(PCONTEXT);
|
xkb_context_unref(PCONTEXT);
|
||||||
|
@ -231,6 +250,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
|
||||||
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
|
|
||||||
xkbState = xkb_state_new(NEWKEYMAP);
|
xkbState = xkb_state_new(NEWKEYMAP);
|
||||||
|
xkbStaticState = xkb_state_new(NEWKEYMAP);
|
||||||
|
|
||||||
xkb_keymap_unref(NEWKEYMAP);
|
xkb_keymap_unref(NEWKEYMAP);
|
||||||
xkb_context_unref(PCONTEXT);
|
xkb_context_unref(PCONTEXT);
|
||||||
|
@ -254,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) {
|
||||||
|
@ -264,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) {
|
||||||
|
@ -305,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -64,16 +65,23 @@ class IKeyboard : public IHID {
|
||||||
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();
|
||||||
|
std::optional<uint32_t> getLEDs();
|
||||||
void updateLEDs();
|
void updateLEDs();
|
||||||
void updateLEDs(uint32_t leds);
|
void updateLEDs(uint32_t leds);
|
||||||
uint32_t getModifiers();
|
uint32_t getModifiers();
|
||||||
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
|
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
|
||||||
bool updateModifiersState(); // rets whether changed
|
bool updateModifiersState(); // rets whether changed
|
||||||
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
|
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,
|
||||||
|
// don't try to set keyboard rules anymore, to avoid overwriting the requested one.
|
||||||
|
// e.g. Virtual keyboards with custom maps.
|
||||||
|
bool keymapOverridden = false;
|
||||||
|
|
||||||
xkb_layout_index_t activeLayout = 0;
|
xkb_layout_index_t activeLayout = 0;
|
||||||
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
|
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
|
||||||
xkb_keymap* xkbKeymap = nullptr;
|
xkb_keymap* xkbKeymap = nullptr;
|
||||||
|
|
|
@ -107,6 +107,7 @@ class IPointer : public IHID {
|
||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,13 +32,13 @@ CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
|
||||||
listeners.key = keeb->events.key.registerListener([this](std::any d) {
|
listeners.key = keeb->events.key.registerListener([this](std::any d) {
|
||||||
auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
|
auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
|
||||||
|
|
||||||
updateXkbStateWithKey(E.key + 8, E.pressed);
|
|
||||||
|
|
||||||
keyboardEvents.key.emit(SKeyEvent{
|
keyboardEvents.key.emit(SKeyEvent{
|
||||||
.timeMs = E.timeMs,
|
.timeMs = E.timeMs,
|
||||||
.keycode = E.key,
|
.keycode = E.key,
|
||||||
.state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
|
.state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateXkbStateWithKey(E.key + 8, E.pressed);
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
|
listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
|
||||||
|
|
|
@ -32,7 +32,12 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keybo
|
||||||
});
|
});
|
||||||
listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) {
|
listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) {
|
||||||
auto E = std::any_cast<SKeymapEvent>(d);
|
auto E = std::any_cast<SKeymapEvent>(d);
|
||||||
|
if (xkbKeymap)
|
||||||
|
xkb_keymap_unref(xkbKeymap);
|
||||||
xkbKeymap = xkb_keymap_ref(E.keymap);
|
xkbKeymap = xkb_keymap_ref(E.keymap);
|
||||||
|
keymapOverridden = true;
|
||||||
|
updateXKBTranslationState(xkbKeymap);
|
||||||
|
updateKeymapFD();
|
||||||
keyboardEvents.keymap.emit(d);
|
keyboardEvents.keymap.emit(d);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,12 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
|
listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
|
||||||
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { pointerEvents.motionAbsolute.emit(d); });
|
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) {
|
||||||
|
// we need to unpack the event and add our device here because it's required to calculate the position correctly
|
||||||
|
auto E = std::any_cast<SMotionAbsoluteEvent>(d);
|
||||||
|
E.device = self.lock();
|
||||||
|
pointerEvents.motionAbsolute.emit(E);
|
||||||
|
});
|
||||||
listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); });
|
listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); });
|
||||||
listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); });
|
listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); });
|
||||||
listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
|
listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
|
||||||
|
@ -33,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "Events.hpp"
|
#include "Events.hpp"
|
||||||
#include "../debug/HyprCtl.hpp"
|
#include "../debug/HyprCtl.hpp"
|
||||||
#include "../config/ConfigValue.hpp"
|
#include "../config/ConfigValue.hpp"
|
||||||
|
#include "../protocols/Screencopy.hpp"
|
||||||
|
#include "../protocols/ToplevelExport.hpp"
|
||||||
#include <aquamarine/output/Output.hpp>
|
#include <aquamarine/output/Output.hpp>
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
// --------------------------------------------------------- //
|
||||||
|
@ -118,8 +120,8 @@ void Events::listener_monitorCommit(void* owner, void* data) {
|
||||||
const auto PMONITOR = (CMonitor*)owner;
|
const auto PMONITOR = (CMonitor*)owner;
|
||||||
|
|
||||||
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
|
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR);
|
PROTO::screencopy->onOutputCommit(PMONITOR);
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR);
|
PROTO::toplevelExport->onOutputCommit(PMONITOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../protocols/LayerShell.hpp"
|
#include "../protocols/LayerShell.hpp"
|
||||||
#include "../protocols/XDGShell.hpp"
|
#include "../protocols/XDGShell.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
#include "../protocols/ToplevelExport.hpp"
|
||||||
#include "../xwayland/XSurface.hpp"
|
#include "../xwayland/XSurface.hpp"
|
||||||
|
|
||||||
#include <hyprutils/string/String.hpp>
|
#include <hyprutils/string/String.hpp>
|
||||||
|
@ -133,11 +134,10 @@ 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")) {
|
||||||
|
@ -198,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) {
|
||||||
|
@ -212,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")) {
|
||||||
|
@ -460,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 &&
|
||||||
|
@ -484,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 (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) {
|
||||||
}
|
// fix fullscreen on requested (basically do a switcheroo)
|
||||||
|
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow)
|
||||||
|
g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
|
||||||
|
|
||||||
if (requestsFakeFullscreen && !PWINDOW->m_bFakeFullscreenState) {
|
|
||||||
PWINDOW->m_bFakeFullscreenState = !PWINDOW->m_bFakeFullscreenState;
|
|
||||||
g_pXWaylandManager->setWindowFullscreen(PWINDOW, true);
|
|
||||||
} else {
|
|
||||||
overridingNoFullscreen = false;
|
|
||||||
overridingNoMaximize = false;
|
|
||||||
PWINDOW->m_vRealPosition.warp();
|
PWINDOW->m_vRealPosition.warp();
|
||||||
PWINDOW->m_vRealSize.warp();
|
PWINDOW->m_vRealSize.warp();
|
||||||
g_pCompositor->setWindowFullscreen(PWINDOW, true, requestsFullscreen ? FULLSCREEN_FULL : FULLSCREEN_MAXIMIZED);
|
if (requestedFSState.has_value()) {
|
||||||
}
|
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
|
||||||
|
@ -557,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);
|
||||||
|
@ -582,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);
|
||||||
|
@ -601,10 +607,10 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
|
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
|
||||||
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
|
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
|
||||||
|
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->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);
|
||||||
|
@ -626,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);
|
||||||
|
@ -646,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)
|
||||||
|
@ -702,14 +711,9 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
|
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (PWINDOW->m_bIsX11)
|
|
||||||
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.
|
||||||
else if (PWINDOW->m_pPendingSizeAck.has_value()) {
|
|
||||||
PWINDOW->m_vReportedSize = PWINDOW->m_pPendingSizeAck->second;
|
|
||||||
PWINDOW->m_pPendingSizeAck.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -748,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()) {
|
||||||
|
@ -786,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) {
|
||||||
|
@ -836,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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -148,7 +148,7 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
|
|
||||||
damage.setSize(vecTransformedSize);
|
damage.setSize(vecTransformedSize);
|
||||||
|
|
||||||
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output);
|
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output.get());
|
||||||
|
|
||||||
setupDefaultWS(monitorRule);
|
setupDefaultWS(monitorRule);
|
||||||
|
|
||||||
|
@ -354,7 +354,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) {
|
||||||
|
@ -801,18 +801,18 @@ 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;
|
||||||
|
|
||||||
// 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->setBuffer(PSURFACE->current.buffer);
|
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
|
||||||
output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
|
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
|
||||||
|
|
||||||
if (!state.test())
|
if (!state.test())
|
||||||
return false;
|
return false;
|
||||||
|
@ -822,6 +822,8 @@ bool CMonitor::attemptDirectScanout() {
|
||||||
Debug::log(TRACE, "presentFeedback for DS");
|
Debug::log(TRACE, "presentFeedback for DS");
|
||||||
PSURFACE->presentFeedback(&now, this, true);
|
PSURFACE->presentFeedback(&now, this, true);
|
||||||
|
|
||||||
|
output->state->addDamage(CBox{{}, vecPixelSize});
|
||||||
|
|
||||||
if (state.commit()) {
|
if (state.commit()) {
|
||||||
if (lastScanout.expired()) {
|
if (lastScanout.expired()) {
|
||||||
lastScanout = PCANDIDATE;
|
lastScanout = PCANDIDATE;
|
||||||
|
@ -863,6 +865,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();
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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]);
|
||||||
|
|
|
@ -52,7 +52,7 @@ class CHyprDwindleLayout : public IHyprLayout {
|
||||||
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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ class CHyprMasterLayout : public IHyprLayout {
|
||||||
virtual void recalculateMonitor(const int&);
|
virtual void recalculateMonitor(const int&);
|
||||||
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);
|
||||||
|
|
10
src/main.cpp
10
src/main.cpp
|
@ -147,7 +147,7 @@ int main(int argc, char** argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pCompositor->initServer();
|
g_pCompositor->initServer(socketName, socketFd);
|
||||||
|
|
||||||
if (!envEnabled("HYPRLAND_NO_RT"))
|
if (!envEnabled("HYPRLAND_NO_RT"))
|
||||||
Init::gainRealTime();
|
Init::gainRealTime();
|
||||||
|
@ -155,13 +155,11 @@ int main(int argc, char** argv) {
|
||||||
Debug::log(LOG, "Hyprland init finished.");
|
Debug::log(LOG, "Hyprland init finished.");
|
||||||
|
|
||||||
// If all's good to go, start.
|
// If all's good to go, start.
|
||||||
g_pCompositor->startCompositor(socketName, socketFd);
|
g_pCompositor->startCompositor();
|
||||||
|
|
||||||
g_pCompositor->m_bIsShuttingDown = true;
|
g_pCompositor->cleanup();
|
||||||
|
|
||||||
// If we are here it means we got yote.
|
Debug::log(LOG, "Hyprland has reached the end.");
|
||||||
Debug::log(LOG, "Hyprland reached the end.");
|
|
||||||
g_pCompositor.reset();
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ CCursorManager::CCursorManager() {
|
||||||
if (m_iSize == 0)
|
if (m_iSize == 0)
|
||||||
m_iSize = 24;
|
m_iSize = 24;
|
||||||
|
|
||||||
xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale));
|
xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale));
|
||||||
|
|
||||||
m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
|
m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
|
||||||
|
|
||||||
|
@ -135,14 +135,20 @@ void CCursorManager::setXCursor(const std::string& name) {
|
||||||
|
|
||||||
if (!xcursor.themeLoaded) {
|
if (!xcursor.themeLoaded) {
|
||||||
Debug::log(ERR, "XCursor failed to find theme in setXCursor");
|
Debug::log(ERR, "XCursor failed to find theme in setXCursor");
|
||||||
|
if (!xcursor.defaultCursor) {
|
||||||
g_pPointerManager->resetCursorImage();
|
g_pPointerManager->resetCursorImage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto& icon = xcursor.defaultCursor;
|
auto& icon = xcursor.defaultCursor;
|
||||||
// try to get an icon we know if we have one
|
// try to get an icon we know if we have one
|
||||||
if (xcursor.cursors.contains(name))
|
for (auto const& c : xcursor.cursors) {
|
||||||
icon = xcursor.cursors.at(name);
|
if (c.first != name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
icon = c.second;
|
||||||
|
}
|
||||||
|
|
||||||
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot));
|
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot));
|
||||||
|
|
||||||
|
@ -305,87 +311,86 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
|
// 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
|
// clang-format off
|
||||||
static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
|
static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
|
||||||
"X_cursor",
|
"X_cursor",
|
||||||
"default", // arrow
|
"arrow",
|
||||||
"ns-resize", // based-arrow-down
|
"based_arrow_down",
|
||||||
"ns-resize", // based-arrow-up
|
"based_arrow_up",
|
||||||
"boat",
|
"boat",
|
||||||
"bogosity",
|
"bogosity",
|
||||||
"sw-resize", // bottom-left-corner
|
"bottom_left_corner",
|
||||||
"se-resize", // bottom-right-corner
|
"bottom_right_corner",
|
||||||
"s-resize", // bottom-side
|
"bottom_side",
|
||||||
"bottom-tee",
|
"bottom_tee",
|
||||||
"box-spiral",
|
"box_spiral",
|
||||||
"center-ptr",
|
"center_ptr",
|
||||||
"circle",
|
"circle",
|
||||||
"clock",
|
"clock",
|
||||||
"coffee-mug",
|
"coffee_mug",
|
||||||
"cross",
|
"cross",
|
||||||
"cross-reverse",
|
"cross_reverse",
|
||||||
"crosshair",
|
"crosshair",
|
||||||
"diamond-cross",
|
"diamond_cross",
|
||||||
"dot",
|
"dot",
|
||||||
"dotbox",
|
"dotbox",
|
||||||
"double-arrow",
|
"double_arrow",
|
||||||
"draft-large",
|
"draft_large",
|
||||||
"draft-small",
|
"draft_small",
|
||||||
"draped-box",
|
"draped_box",
|
||||||
"exchange",
|
"exchange",
|
||||||
"move", // fleur
|
"fleur",
|
||||||
"gobbler",
|
"gobbler",
|
||||||
"gumby",
|
"gumby",
|
||||||
"pointer", // hand1
|
"hand1",
|
||||||
"grabbing", // hand2
|
"hand2",
|
||||||
"heart",
|
"heart",
|
||||||
"icon",
|
"icon",
|
||||||
"iron-cross",
|
"iron_cross",
|
||||||
"default", // left-ptr
|
"left_ptr",
|
||||||
"w-resize", // left-side
|
"left_side",
|
||||||
"left-tee",
|
"left_tee",
|
||||||
"leftbutton",
|
"leftbutton",
|
||||||
"ll-angle",
|
"ll_angle",
|
||||||
"lr-angle",
|
"lr_angle",
|
||||||
"man",
|
"man",
|
||||||
"middlebutton",
|
"middlebutton",
|
||||||
"mouse",
|
"mouse",
|
||||||
"pencil",
|
"pencil",
|
||||||
"pirate",
|
"pirate",
|
||||||
"plus",
|
"plus",
|
||||||
"help", // question-arrow
|
"question_arrow",
|
||||||
"right-ptr",
|
"right_ptr",
|
||||||
"e-resize", // right-side
|
"right_side",
|
||||||
"right-tee",
|
"right_tee",
|
||||||
"rightbutton",
|
"rightbutton",
|
||||||
"rtl-logo",
|
"rtl_logo",
|
||||||
"sailboat",
|
"sailboat",
|
||||||
"ns-resize", // sb-down-arrow
|
"sb_down_arrow",
|
||||||
"ew-resize", // sb-h-double-arrow
|
"sb_h_double_arrow",
|
||||||
"ew-resize", // sb-left-arrow
|
"sb_left_arrow",
|
||||||
"ew-resize", // sb-right-arrow
|
"sb_right_arrow",
|
||||||
"n-resize", // sb-up-arrow
|
"sb_up_arrow",
|
||||||
"s-resize", // sb-v-double-arrow
|
"sb_v_double_arrow",
|
||||||
"shuttle",
|
"shuttle",
|
||||||
"sizing",
|
"sizing",
|
||||||
"spider",
|
"spider",
|
||||||
"spraycan",
|
"spraycan",
|
||||||
"star",
|
"star",
|
||||||
"target",
|
"target",
|
||||||
"cell", // tcross
|
"tcross",
|
||||||
"nw-resize", // top-left-arrow
|
"top_left_arrow",
|
||||||
"nw-resize", // top-left-corner
|
"top_left_corner",
|
||||||
"ne-resize", // top-right-corner
|
"top_right_corner",
|
||||||
"n-resize", // top-side
|
"top_side",
|
||||||
"top-tee",
|
"top_tee",
|
||||||
"trek",
|
"trek",
|
||||||
"ul-angle",
|
"ul_angle",
|
||||||
"umbrella",
|
"umbrella",
|
||||||
"ur-angle",
|
"ur_angle",
|
||||||
"wait", // watch
|
"watch",
|
||||||
"text", // xterm
|
"xterm",
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
@ -397,52 +402,22 @@ void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int siz
|
||||||
themeLoaded = false;
|
themeLoaded = false;
|
||||||
themeName = name.empty() ? "default" : name;
|
themeName = name.empty() ? "default" : name;
|
||||||
|
|
||||||
auto img = XcursorShapeLoadImage(2, themeName.c_str(), size);
|
std::vector<std::pair<std::string, SP<SXCursor>>> newCursors;
|
||||||
|
|
||||||
if (!img) {
|
// load the default xcursor shapes that exist in the theme
|
||||||
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) {
|
for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
|
||||||
if (XCURSOR_STANDARD_NAMES.at(i) == std::string{shape}) {
|
auto shape = XCURSOR_STANDARD_NAMES.at(i);
|
||||||
id = i;
|
auto xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), size);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id < 0) {
|
if (!xImage) {
|
||||||
Debug::log(LOG, "XCursor has no shape {}, skipping", shape);
|
Debug::log(LOG, "XCursor failed to find a shape with name {}, trying size 24.", shape);
|
||||||
continue;
|
xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), 24);
|
||||||
}
|
|
||||||
|
|
||||||
auto xImage = XcursorShapeLoadImage(id << 1 /* wtf xcursor? */, themeName.c_str(), size);
|
|
||||||
|
|
||||||
if (!xImage) {
|
if (!xImage) {
|
||||||
Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape);
|
Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto xcursor = makeShared<SXCursor>();
|
auto xcursor = makeShared<SXCursor>();
|
||||||
xcursor->size = {(int)xImage->width, (int)xImage->height};
|
xcursor->size = {(int)xImage->width, (int)xImage->height};
|
||||||
|
@ -451,8 +426,214 @@ void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int siz
|
||||||
xcursor->pixels.resize(xImage->width * xImage->height);
|
xcursor->pixels.resize(xImage->width * xImage->height);
|
||||||
std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
|
std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
|
||||||
|
|
||||||
cursors.emplace(std::string{shape}, xcursor);
|
newCursors.emplace_back(std::string{shape}, xcursor);
|
||||||
|
|
||||||
XcursorImageDestroy(xImage);
|
XcursorImageDestroy(xImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newCursors.empty()) {
|
||||||
|
Debug::log(ERR, "XCursor failed finding any shapes in theme \"{}\".", themeName);
|
||||||
|
if (!defaultCursor) {
|
||||||
|
defaultCursor = createDefaultCursor();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursors.clear();
|
||||||
|
cursors = std::move(newCursors);
|
||||||
|
defaultCursor.reset();
|
||||||
|
themeLoaded = true;
|
||||||
|
|
||||||
|
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.first == legacyName; });
|
||||||
|
|
||||||
|
if (it == cursors.end()) {
|
||||||
|
Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursors.emplace_back(shape, it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default cursor
|
||||||
|
for (auto const& c : cursors) {
|
||||||
|
if (c.first == "left_ptr" || c.first == "arrow") {
|
||||||
|
defaultCursor = c.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just assign the first one then.
|
||||||
|
if (!defaultCursor)
|
||||||
|
defaultCursor = cursors.at(0).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CCursorManager::SXCursorManager::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();
|
||||||
|
}
|
||||||
|
|
||||||
|
SP<CCursorManager::SXCursor> CCursorManager::SXCursorManager::createDefaultCursor() {
|
||||||
|
int cursorWidth = 32;
|
||||||
|
int cursorHeight = 32;
|
||||||
|
int cursorHotspotX = 3;
|
||||||
|
int cursorHotspotY = 2;
|
||||||
|
|
||||||
|
static const uint32_t 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};
|
||||||
|
|
||||||
|
auto hackcursor = makeShared<SXCursor>();
|
||||||
|
hackcursor->size = {cursorWidth, cursorHeight};
|
||||||
|
hackcursor->hotspot = {cursorHotspotX, cursorHotspotY};
|
||||||
|
hackcursor->pixels.resize(cursorWidth * cursorHeight);
|
||||||
|
std::memcpy(hackcursor->pixels.data(), pixels, cursorWidth * cursorHeight * sizeof(uint32_t));
|
||||||
|
|
||||||
|
return hackcursor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,13 +84,14 @@ class CCursorManager {
|
||||||
|
|
||||||
struct SXCursorManager {
|
struct SXCursorManager {
|
||||||
void loadTheme(const std::string& name, int size);
|
void loadTheme(const std::string& name, int size);
|
||||||
|
std::string getLegacyShapeName(std::string const& shape);
|
||||||
|
SP<SXCursor> createDefaultCursor();
|
||||||
|
|
||||||
int lastLoadSize = 0;
|
int lastLoadSize = 0;
|
||||||
|
|
||||||
bool themeLoaded = false;
|
bool themeLoaded = false;
|
||||||
std::string themeName = "";
|
std::string themeName = "";
|
||||||
SP<SXCursor> defaultCursor;
|
SP<SXCursor> defaultCursor;
|
||||||
std::unordered_map<std::string, SP<SXCursor>> cursors;
|
std::vector<std::pair<std::string, SP<SXCursor>>> cursors;
|
||||||
} xcursor;
|
} xcursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -36,7 +37,7 @@ using namespace Hyprutils::String;
|
||||||
static std::vector<std::pair<std::string, std::string>> getHyprlandLaunchEnv() {
|
static std::vector<std::pair<std::string, std::string>> getHyprlandLaunchEnv() {
|
||||||
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
|
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
|
||||||
|
|
||||||
if (!*PINITIALWSTRACKING)
|
if (!*PINITIALWSTRACKING || g_pConfigManager->isLaunchingExecOnce)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||||
|
@ -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;
|
||||||
|
@ -101,7 +102,6 @@ CKeybindManager::CKeybindManager() {
|
||||||
m_mDispatchers["pass"] = pass;
|
m_mDispatchers["pass"] = pass;
|
||||||
m_mDispatchers["sendshortcut"] = sendshortcut;
|
m_mDispatchers["sendshortcut"] = sendshortcut;
|
||||||
m_mDispatchers["layoutmsg"] = layoutmsg;
|
m_mDispatchers["layoutmsg"] = layoutmsg;
|
||||||
m_mDispatchers["toggleopaque"] = toggleOpaque;
|
|
||||||
m_mDispatchers["dpms"] = dpms;
|
m_mDispatchers["dpms"] = dpms;
|
||||||
m_mDispatchers["movewindowpixel"] = moveWindow;
|
m_mDispatchers["movewindowpixel"] = moveWindow;
|
||||||
m_mDispatchers["resizewindowpixel"] = resizeWindow;
|
m_mDispatchers["resizewindowpixel"] = resizeWindow;
|
||||||
|
@ -243,27 +243,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,11 +269,16 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get();
|
const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get();
|
||||||
|
if (!LASTMONITOR)
|
||||||
|
return false;
|
||||||
if (LASTMONITOR == monitor) {
|
if (LASTMONITOR == monitor) {
|
||||||
Debug::log(LOG, "Tried to move to active monitor");
|
Debug::log(LOG, "Tried to move to active monitor");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
|
||||||
|
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");
|
||||||
|
|
||||||
const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
||||||
const auto PNEWMAINWORKSPACE = monitor->activeWorkspace;
|
const auto PNEWMAINWORKSPACE = monitor->activeWorkspace;
|
||||||
|
|
||||||
|
@ -301,9 +293,11 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
|
||||||
g_pCompositor->focusWindow(PNEWWINDOW);
|
g_pCompositor->focusWindow(PNEWWINDOW);
|
||||||
PNEWWINDOW->warpCursor();
|
PNEWWINDOW->warpCursor();
|
||||||
|
|
||||||
|
if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) {
|
||||||
g_pInputManager->m_pForcedFocus = PNEWWINDOW;
|
g_pInputManager->m_pForcedFocus = PNEWWINDOW;
|
||||||
g_pInputManager->simulateMouseMovement();
|
g_pInputManager->simulateMouseMovement();
|
||||||
g_pInputManager->m_pForcedFocus.reset();
|
g_pInputManager->m_pForcedFocus.reset();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g_pCompositor->focusWindow(nullptr);
|
g_pCompositor->focusWindow(nullptr);
|
||||||
g_pCompositor->warpCursorTo(monitor->middle());
|
g_pCompositor->warpCursorTo(monitor->middle());
|
||||||
|
@ -314,6 +308,9 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
|
void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
|
||||||
|
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
|
||||||
|
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");
|
||||||
|
|
||||||
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
|
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
|
||||||
|
|
||||||
if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO)
|
if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO)
|
||||||
|
@ -322,25 +319,28 @@ 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);
|
||||||
PWINDOWTOCHANGETO->warpCursor();
|
PWINDOWTOCHANGETO->warpCursor();
|
||||||
|
|
||||||
|
// Move mouse focus to the new window if required by current follow_mouse and warp modes
|
||||||
|
if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) {
|
||||||
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
|
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
|
||||||
g_pInputManager->simulateMouseMovement();
|
g_pInputManager->simulateMouseMovement();
|
||||||
g_pInputManager->m_pForcedFocus.reset();
|
g_pInputManager->m_pForcedFocus.reset();
|
||||||
|
}
|
||||||
|
|
||||||
if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
|
if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
|
||||||
// event
|
// event
|
||||||
|
@ -528,10 +528,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) {
|
||||||
|
@ -607,10 +604,8 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
|
||||||
|
|
||||||
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
|
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
|
||||||
|
|
||||||
if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) {
|
if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited())
|
||||||
Debug::log(LOG, "Keybind handling is disabled due to an inhibitor");
|
Debug::log(LOG, "Keybind handling is disabled due to an inhibitor");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& k : m_lKeybinds) {
|
for (auto& k : m_lKeybinds) {
|
||||||
const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse";
|
const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse";
|
||||||
|
@ -619,6 +614,9 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
|
||||||
const bool IGNORECONDITIONS =
|
const bool IGNORECONDITIONS =
|
||||||
SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released.
|
SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released.
|
||||||
|
|
||||||
|
if (!k.dontInhibit && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!k.locked && g_pSessionLockManager->isSessionLocked())
|
if (!k.locked && g_pSessionLockManager->isSessionLocked())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -958,7 +956,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();
|
||||||
|
@ -997,7 +996,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);
|
||||||
|
@ -1023,7 +1022,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1150,10 +1149,52 @@ 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;
|
||||||
|
|
||||||
|
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 = PWINDOW->m_sFullscreenState.client, .client = PWINDOW->m_sFullscreenState.client});
|
||||||
|
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) {
|
||||||
|
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = PWINDOW->m_sFullscreenState.internal});
|
||||||
|
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP);
|
||||||
|
g_pCompositor->setWindowFullscreenState(PWINDOW, STATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
void CKeybindManager::moveActiveToWorkspace(std::string args) {
|
||||||
|
@ -1278,7 +1319,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);
|
||||||
|
|
||||||
|
@ -1335,7 +1376,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);
|
||||||
|
@ -1373,7 +1414,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) {
|
||||||
|
@ -1428,7 +1469,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();
|
||||||
|
@ -1662,7 +1704,7 @@ void CKeybindManager::renameWorkspace(std::string args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKeybindManager::exitHyprland(std::string argz) {
|
void CKeybindManager::exitHyprland(std::string argz) {
|
||||||
g_pEventLoopManager->doLater([]() { g_pCompositor->cleanup(); });
|
g_pCompositor->stopCompositor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
|
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
|
||||||
|
@ -1820,7 +1862,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());
|
||||||
|
@ -1837,7 +1879,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());
|
||||||
|
@ -1857,7 +1899,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());
|
||||||
|
@ -1877,7 +1919,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());
|
||||||
|
@ -1954,12 +1996,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);
|
||||||
|
@ -2236,17 +2278,6 @@ void CKeybindManager::layoutmsg(std::string msg) {
|
||||||
g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg);
|
g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKeybindManager::toggleOpaque(std::string unused) {
|
|
||||||
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock();
|
|
||||||
|
|
||||||
if (!PWINDOW)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PWINDOW->m_sWindowData.opaque = CWindowOverridableVar(!PWINDOW->m_sWindowData.opaque.valueOrDefault(), PRIORITY_SET_PROP);
|
|
||||||
|
|
||||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CKeybindManager::dpms(std::string arg) {
|
void CKeybindManager::dpms(std::string arg) {
|
||||||
bool enable = arg.starts_with("on");
|
bool enable = arg.starts_with("on");
|
||||||
std::string port = "";
|
std::string port = "";
|
||||||
|
@ -2342,11 +2373,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);
|
||||||
|
@ -2363,54 +2402,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) {
|
changeMouseBindMode(MBIND_MOVE);
|
||||||
g_pKeybindManager->m_bIsMouseBindActive = true;
|
|
||||||
|
|
||||||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
|
||||||
PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
|
||||||
|
|
||||||
if (pWindow && !pWindow->m_bIsFullscreen)
|
|
||||||
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 {
|
} else {
|
||||||
g_pKeybindManager->m_bIsMouseBindActive = false;
|
|
||||||
|
|
||||||
if (!g_pInputManager->currentlyDraggedWindow.expired()) {
|
|
||||||
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
|
|
||||||
g_pInputManager->currentlyDraggedWindow.reset();
|
|
||||||
g_pInputManager->dragMode = MBIND_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ARGS[0] == "resizewindow") {
|
|
||||||
if (PRESSED) {
|
|
||||||
g_pKeybindManager->m_bIsMouseBindActive = true;
|
|
||||||
|
|
||||||
g_pInputManager->currentlyDraggedWindow =
|
|
||||||
g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (std::stoi(ARGS[1])) {
|
switch (std::stoi(ARGS[1])) {
|
||||||
case 1: g_pInputManager->dragMode = MBIND_RESIZE_FORCE_RATIO; break;
|
case 1: changeMouseBindMode(MBIND_RESIZE_FORCE_RATIO); break;
|
||||||
case 2: g_pInputManager->dragMode = MBIND_RESIZE_BLOCK_RATIO; break;
|
case 2: changeMouseBindMode(MBIND_RESIZE_BLOCK_RATIO); break;
|
||||||
default: g_pInputManager->dragMode = MBIND_RESIZE;
|
default: changeMouseBindMode(MBIND_RESIZE);
|
||||||
}
|
}
|
||||||
} catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; }
|
} catch (std::exception& e) { changeMouseBindMode(MBIND_RESIZE); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) {
|
||||||
|
if (MODE != MBIND_INVALID) {
|
||||||
|
if (!g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode != MBIND_INVALID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||||
|
const PHLWINDOW PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||||
|
|
||||||
|
if (!PWINDOW)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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();
|
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
|
||||||
} else {
|
} else {
|
||||||
g_pKeybindManager->m_bIsMouseBindActive = false;
|
if (g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode == MBIND_INVALID)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!g_pInputManager->currentlyDraggedWindow.expired()) {
|
|
||||||
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
|
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
|
||||||
g_pInputManager->currentlyDraggedWindow.reset();
|
g_pInputManager->dragMode = MODE;
|
||||||
g_pInputManager->dragMode = MBIND_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2444,14 +2479,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;
|
||||||
|
@ -2489,6 +2516,11 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn
|
||||||
|
|
||||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property!
|
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property!
|
||||||
|
|
||||||
|
if (pWindow->m_iMonitorID != pWindowInDirection->m_iMonitorID) {
|
||||||
|
pWindow->moveToWorkspace(pWindowInDirection->m_pWorkspace);
|
||||||
|
pWindow->m_iMonitorID = pWindowInDirection->m_iMonitorID;
|
||||||
|
}
|
||||||
|
|
||||||
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
|
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
|
||||||
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();
|
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();
|
||||||
|
|
||||||
|
@ -2606,7 +2638,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) {
|
||||||
|
@ -2676,10 +2708,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) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ struct SKeybind {
|
||||||
bool ignoreMods = false;
|
bool ignoreMods = false;
|
||||||
bool multiKey = false;
|
bool multiKey = false;
|
||||||
bool hasDescription = false;
|
bool hasDescription = false;
|
||||||
|
bool dontInhibit = false;
|
||||||
|
|
||||||
// DO NOT INITIALIZE
|
// DO NOT INITIALIZE
|
||||||
bool shadowed = false;
|
bool shadowed = false;
|
||||||
|
@ -104,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;
|
||||||
|
|
||||||
|
@ -115,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
|
||||||
|
@ -153,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);
|
||||||
|
@ -189,7 +191,6 @@ class CKeybindManager {
|
||||||
static void pass(std::string);
|
static void pass(std::string);
|
||||||
static void sendshortcut(std::string);
|
static void sendshortcut(std::string);
|
||||||
static void layoutmsg(std::string);
|
static void layoutmsg(std::string);
|
||||||
static void toggleOpaque(std::string);
|
|
||||||
static void dpms(std::string);
|
static void dpms(std::string);
|
||||||
static void swapnext(std::string);
|
static void swapnext(std::string);
|
||||||
static void swapActiveWorkspaces(std::string);
|
static void swapActiveWorkspaces(std::string);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#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>
|
||||||
|
@ -24,6 +25,14 @@ CPointerManager::CPointerManager() {
|
||||||
},
|
},
|
||||||
nullptr);
|
nullptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hooks.monitorPreRender = g_pHookSystem->hookDynamic("preMonitorCommit", [this](void* self, SCallbackInfo& info, std::any data) {
|
||||||
|
auto state = stateFor(std::any_cast<CMonitor*>(data)->self.lock());
|
||||||
|
if (!state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
state->cursorRendered = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPointerManager::lockSoftwareAll() {
|
void CPointerManager::lockSoftwareAll() {
|
||||||
|
@ -143,18 +152,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);
|
||||||
|
@ -214,6 +225,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();
|
||||||
|
@ -386,6 +399,14 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we already rendered the cursor, revert the swapchain to avoid rendering the cursor over
|
||||||
|
// the current front buffer
|
||||||
|
// this flag will be reset in the preRender hook, so when we commit this buffer to KMS
|
||||||
|
if (state->cursorRendered)
|
||||||
|
state->monitor->cursorSwapchain->rollback();
|
||||||
|
|
||||||
|
state->cursorRendered = true;
|
||||||
|
|
||||||
auto buf = state->monitor->cursorSwapchain->next(nullptr);
|
auto buf = state->monitor->cursorSwapchain->next(nullptr);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
|
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
|
||||||
|
@ -410,16 +431,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 texData = currentCursorImage.pBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE);
|
||||||
auto texPtr = std::get<0>(texData);
|
auto texPtr = std::get<0>(texData);
|
||||||
Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride);
|
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();
|
||||||
|
@ -620,7 +664,7 @@ void CPointerManager::move(const Vector2D& deltaLogical) {
|
||||||
void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
|
void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
|
||||||
|
|
||||||
SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock();
|
SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock();
|
||||||
if (!currentMonitor)
|
if (!currentMonitor || !dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!std::isnan(abs.x))
|
if (!std::isnan(abs.x))
|
||||||
|
@ -658,6 +702,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +764,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) {
|
||||||
|
@ -703,7 +773,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) {
|
||||||
|
|
|
@ -165,6 +165,7 @@ class CPointerManager {
|
||||||
CBox box; // logical
|
CBox box; // logical
|
||||||
bool entered = false;
|
bool entered = false;
|
||||||
bool hwApplied = false;
|
bool hwApplied = false;
|
||||||
|
bool cursorRendered = false;
|
||||||
|
|
||||||
SP<Aquamarine::IBuffer> cursorFrontBuffer;
|
SP<Aquamarine::IBuffer> cursorFrontBuffer;
|
||||||
};
|
};
|
||||||
|
@ -177,6 +178,7 @@ class CPointerManager {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
SP<HOOK_CALLBACK_FN> monitorAdded;
|
SP<HOOK_CALLBACK_FN> monitorAdded;
|
||||||
|
SP<HOOK_CALLBACK_FN> monitorPreRender;
|
||||||
} hooks;
|
} hooks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,10 @@
|
||||||
#include "../protocols/LinuxDMABUF.hpp"
|
#include "../protocols/LinuxDMABUF.hpp"
|
||||||
#include "../protocols/DRMLease.hpp"
|
#include "../protocols/DRMLease.hpp"
|
||||||
#include "../protocols/DRMSyncobj.hpp"
|
#include "../protocols/DRMSyncobj.hpp"
|
||||||
|
#include "../protocols/Screencopy.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"
|
||||||
|
@ -66,8 +70,7 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
|
||||||
else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) {
|
else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) {
|
||||||
if (PROTO::outputs.contains(pMonitor->szName))
|
if (PROTO::outputs.contains(pMonitor->szName))
|
||||||
PROTO::outputs.erase(pMonitor->szName);
|
PROTO::outputs.erase(pMonitor->szName);
|
||||||
PROTO::outputs.emplace(pMonitor->szName,
|
PROTO::outputs.emplace(pMonitor->szName, makeShared<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
|
||||||
std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +89,10 @@ CProtocolManager::CProtocolManager() {
|
||||||
|
|
||||||
if (PROTO::outputs.contains(M->szName))
|
if (PROTO::outputs.contains(M->szName))
|
||||||
PROTO::outputs.erase(M->szName);
|
PROTO::outputs.erase(M->szName);
|
||||||
PROTO::outputs.emplace(M->szName, std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock()));
|
|
||||||
|
auto ref = makeShared<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock());
|
||||||
|
PROTO::outputs.emplace(M->szName, ref);
|
||||||
|
ref->self = ref;
|
||||||
|
|
||||||
m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); });
|
m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); });
|
||||||
});
|
});
|
||||||
|
@ -121,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");
|
||||||
|
@ -140,6 +147,9 @@ CProtocolManager::CProtocolManager() {
|
||||||
PROTO::dataWlr = std::make_unique<CDataDeviceWLRProtocol>(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr");
|
PROTO::dataWlr = std::make_unique<CDataDeviceWLRProtocol>(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr");
|
||||||
PROTO::primarySelection = std::make_unique<CPrimarySelectionProtocol>(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection");
|
PROTO::primarySelection = std::make_unique<CPrimarySelectionProtocol>(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection");
|
||||||
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::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)
|
||||||
|
@ -156,11 +166,62 @@ 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.
|
CProtocolManager::~CProtocolManager() {
|
||||||
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
|
// this is dumb but i don't want to replace all 600 PROTO with the right thing
|
||||||
m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>();
|
|
||||||
m_pGlobalShortcutsProtocolManager = std::make_unique<CGlobalShortcutsProtocolManager>();
|
// Output
|
||||||
m_pScreencopyProtocolManager = std::make_unique<CScreencopyProtocolManager>();
|
PROTO::outputs.clear();
|
||||||
|
|
||||||
|
// Core
|
||||||
|
PROTO::seat.reset();
|
||||||
|
PROTO::data.reset();
|
||||||
|
PROTO::compositor.reset();
|
||||||
|
PROTO::subcompositor.reset();
|
||||||
|
PROTO::shm.reset();
|
||||||
|
|
||||||
|
// Extensions
|
||||||
|
PROTO::viewport.reset();
|
||||||
|
PROTO::tearing.reset();
|
||||||
|
PROTO::fractional.reset();
|
||||||
|
PROTO::xdgOutput.reset();
|
||||||
|
PROTO::cursorShape.reset();
|
||||||
|
PROTO::idleInhibit.reset();
|
||||||
|
PROTO::relativePointer.reset();
|
||||||
|
PROTO::xdgDecoration.reset();
|
||||||
|
PROTO::alphaModifier.reset();
|
||||||
|
PROTO::gamma.reset();
|
||||||
|
PROTO::foreignToplevel.reset();
|
||||||
|
PROTO::pointerGestures.reset();
|
||||||
|
PROTO::foreignToplevelWlr.reset();
|
||||||
|
PROTO::shortcutsInhibit.reset();
|
||||||
|
PROTO::textInputV1.reset();
|
||||||
|
PROTO::textInputV3.reset();
|
||||||
|
PROTO::constraints.reset();
|
||||||
|
PROTO::outputPower.reset();
|
||||||
|
PROTO::activation.reset();
|
||||||
|
PROTO::idle.reset();
|
||||||
|
PROTO::sessionLock.reset();
|
||||||
|
PROTO::ime.reset();
|
||||||
|
PROTO::virtualKeyboard.reset();
|
||||||
|
PROTO::virtualPointer.reset();
|
||||||
|
PROTO::outputManagement.reset();
|
||||||
|
PROTO::serverDecorationKDE.reset();
|
||||||
|
PROTO::focusGrab.reset();
|
||||||
|
PROTO::tablet.reset();
|
||||||
|
PROTO::layerShell.reset();
|
||||||
|
PROTO::presentation.reset();
|
||||||
|
PROTO::xdgShell.reset();
|
||||||
|
PROTO::dataWlr.reset();
|
||||||
|
PROTO::primarySelection.reset();
|
||||||
|
PROTO::xwaylandShell.reset();
|
||||||
|
PROTO::screencopy.reset();
|
||||||
|
PROTO::toplevelExport.reset();
|
||||||
|
PROTO::globalShortcuts.reset();
|
||||||
|
|
||||||
|
PROTO::lease.reset();
|
||||||
|
PROTO::sync.reset();
|
||||||
|
PROTO::mesaDRM.reset();
|
||||||
|
PROTO::linuxDma.reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "../protocols/ToplevelExport.hpp"
|
#include "../helpers/Monitor.hpp"
|
||||||
#include "../protocols/TextInputV1.hpp"
|
|
||||||
#include "../protocols/GlobalShortcuts.hpp"
|
|
||||||
#include "../protocols/Screencopy.hpp"
|
|
||||||
#include "../helpers/memory/Memory.hpp"
|
#include "../helpers/memory/Memory.hpp"
|
||||||
#include "../helpers/signal/Signal.hpp"
|
#include "../helpers/signal/Signal.hpp"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -12,12 +9,7 @@
|
||||||
class CProtocolManager {
|
class CProtocolManager {
|
||||||
public:
|
public:
|
||||||
CProtocolManager();
|
CProtocolManager();
|
||||||
|
~CProtocolManager();
|
||||||
// TODO: rewrite to use the new protocol framework
|
|
||||||
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
|
|
||||||
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
|
|
||||||
std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager;
|
|
||||||
std::unique_ptr<CScreencopyProtocolManager> m_pScreencopyProtocolManager;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners;
|
std::unordered_map<std::string, CHyprSignalListener> m_mModeChangeListeners;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,16 @@ CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventLoopManager::~CEventLoopManager() {
|
CEventLoopManager::~CEventLoopManager() {
|
||||||
|
for (auto& eventSource : m_sWayland.aqEventSources) {
|
||||||
|
wl_event_source_remove(eventSource);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_sWayland.eventSource)
|
if (m_sWayland.eventSource)
|
||||||
wl_event_source_remove(m_sWayland.eventSource);
|
wl_event_source_remove(m_sWayland.eventSource);
|
||||||
|
if (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) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) {
|
||||||
const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique<SIdleInhibitor>()).get();
|
const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique<SIdleInhibitor>()).get();
|
||||||
PINHIBIT->inhibitor = std::any_cast<SP<CIdleInhibitor>>(inhibitor);
|
PINHIBIT->inhibitor = std::any_cast<SP<CIdleInhibitor>>(inhibitor);
|
||||||
|
|
||||||
Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface);
|
Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface.get());
|
||||||
|
|
||||||
PINHIBIT->inhibitor->listeners.destroy = PINHIBIT->inhibitor->resource->events.destroy.registerListener([this, PINHIBIT](std::any data) {
|
PINHIBIT->inhibitor->listeners.destroy = PINHIBIT->inhibitor->resource->events.destroy.registerListener([this, PINHIBIT](std::any data) {
|
||||||
std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; });
|
std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; });
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -228,7 +229,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else
|
} else
|
||||||
Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF, (uintptr_t)CONSTRAINT.get());
|
Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF.get(), (uintptr_t)CONSTRAINT.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are holding a pointer button,
|
// if we are holding a pointer button,
|
||||||
|
@ -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();
|
||||||
|
@ -570,7 +571,7 @@ void CInputManager::processMouseRequest(std::any E) {
|
||||||
|
|
||||||
auto e = std::any_cast<CSeatManager::SSetCursorEvent>(E);
|
auto e = std::any_cast<CSeatManager::SSetCursorEvent>(E);
|
||||||
|
|
||||||
Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf);
|
Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf.get());
|
||||||
|
|
||||||
if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) {
|
if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) {
|
||||||
m_sCursorSurfaceInfo.wlSurface->unassign();
|
m_sCursorSurfaceInfo.wlSurface->unassign();
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -850,7 +851,7 @@ void CInputManager::newKeyboard(SP<Aquamarine::IKeyboard> keyboard) {
|
||||||
|
|
||||||
setupKeyboard(PNEWKEYBOARD);
|
setupKeyboard(PNEWKEYBOARD);
|
||||||
|
|
||||||
Debug::log(LOG, "New keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard);
|
Debug::log(LOG, "New keyboard created, pointers Hypr: {:x} and AQ: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard) {
|
void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard) {
|
||||||
|
@ -992,7 +993,7 @@ void CInputManager::newMouse(SP<Aquamarine::IPointer> mouse) {
|
||||||
|
|
||||||
setupMouse(PMOUSE);
|
setupMouse(PMOUSE);
|
||||||
|
|
||||||
Debug::log(LOG, "New mouse created, pointer WLR: {:x}", (uintptr_t)mouse);
|
Debug::log(LOG, "New mouse created, pointer AQ: {:x}", (uintptr_t)mouse.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInputManager::setupMouse(SP<IPointer> mauz) {
|
void CInputManager::setupMouse(SP<IPointer> mauz) {
|
||||||
|
@ -1264,7 +1265,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 +1390,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 +1684,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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
hyprListener_textInputDestroy.removeCallback();
|
|
||||||
hyprListener_textInputDisable.removeCallback();
|
|
||||||
hyprListener_textInputEnable.removeCallback();
|
|
||||||
listeners.surfaceUnmap.reset();
|
listeners.surfaceUnmap.reset();
|
||||||
listeners.surfaceDestroy.reset();
|
listeners.surfaceDestroy.reset();
|
||||||
|
|
||||||
g_pInputManager->m_sIMERelay.removeTextInput(this);
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -6,13 +6,15 @@
|
||||||
#include "../SeatManager.hpp"
|
#include "../SeatManager.hpp"
|
||||||
|
|
||||||
void CInputManager::onTouchDown(ITouch::SDownEvent e) {
|
void CInputManager::onTouchDown(ITouch::SDownEvent e) {
|
||||||
|
m_bLastInputTouch = true;
|
||||||
|
|
||||||
static auto PSWIPETOUCH = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch");
|
static auto PSWIPETOUCH = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch");
|
||||||
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
|
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
|
||||||
auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData();
|
auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData();
|
||||||
// TODO: WORKSPACERULE.gapsOut.value_or()
|
// TODO: WORKSPACERULE.gapsOut.value_or()
|
||||||
auto gapsOut = *PGAPSOUT;
|
auto gapsOut = *PGAPSOUT;
|
||||||
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
|
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
|
||||||
static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert");
|
static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch_invert");
|
||||||
EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e);
|
EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e);
|
||||||
|
|
||||||
auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : "");
|
auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : "");
|
||||||
|
@ -54,8 +56,6 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bLastInputTouch = true;
|
|
||||||
|
|
||||||
m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus;
|
m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus;
|
||||||
m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus;
|
m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus;
|
||||||
m_sTouchData.touchFocusLS = m_pFoundLSToFocus;
|
m_sTouchData.touchFocusLS = m_pFoundLSToFocus;
|
||||||
|
@ -83,6 +83,8 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInputManager::onTouchUp(ITouch::SUpEvent e) {
|
void CInputManager::onTouchUp(ITouch::SUpEvent e) {
|
||||||
|
m_bLastInputTouch = true;
|
||||||
|
|
||||||
EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e);
|
EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e);
|
||||||
if (m_sActiveSwipe.pWorkspaceBegin) {
|
if (m_sActiveSwipe.pWorkspaceBegin) {
|
||||||
// If there was a swipe from this finger, end it.
|
// If there was a swipe from this finger, end it.
|
||||||
|
@ -96,6 +98,8 @@ void CInputManager::onTouchUp(ITouch::SUpEvent e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInputManager::onTouchMove(ITouch::SMotionEvent e) {
|
void CInputManager::onTouchMove(ITouch::SMotionEvent e) {
|
||||||
|
m_bLastInputTouch = true;
|
||||||
|
|
||||||
EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e);
|
EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e);
|
||||||
if (m_sActiveSwipe.pWorkspaceBegin) {
|
if (m_sActiveSwipe.pWorkspaceBegin) {
|
||||||
// Do nothing if this is using a different finger.
|
// Do nothing if this is using a different finger.
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) {
|
||||||
|
|
||||||
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
|
void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
|
||||||
if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) {
|
if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) {
|
||||||
LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface);
|
LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface.get());
|
||||||
pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present");
|
pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) {
|
if ((acquireTimeline || releaseTimeline) && !surface->pending.texture) {
|
||||||
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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -28,7 +28,7 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) {
|
||||||
void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
|
void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) {
|
||||||
for (auto& [k, v] : m_mAddons) {
|
for (auto& [k, v] : m_mAddons) {
|
||||||
if (k == surface) {
|
if (k == surface) {
|
||||||
LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface);
|
LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface.get());
|
||||||
pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists");
|
pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,110 +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) {
|
|
||||||
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->displayDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGlobalShortcutsProtocolManager::displayDestroy() {
|
|
||||||
wl_global_destroy(m_pGlobal);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
||||||
}
|
|
||||||
|
|
||||||
static void handleRegisterShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description,
|
|
||||||
const char* trigger_description) {
|
const char* trigger_description) {
|
||||||
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->registerShortcut(client, resource, shortcut, id, app_id, description, trigger_description);
|
if (PROTO::globalShortcuts->isTaken(id, app_id)) {
|
||||||
}
|
resource->error(HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken");
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onShortcutDestroy(wl_resource* pResource) {
|
|
||||||
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->destroyShortcut(pResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& c : m_vClients) {
|
const auto PSHORTCUT = shortcuts.emplace_back(makeShared<SShortcut>(makeShared<CHyprlandGlobalShortcutV1>(resource->client(), resource->version(), shortcut)));
|
||||||
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->id = id;
|
PSHORTCUT->id = id;
|
||||||
PSHORTCUT->description = description;
|
PSHORTCUT->description = description;
|
||||||
PSHORTCUT->appid = app_id;
|
PSHORTCUT->appid = app_id;
|
||||||
PSHORTCUT->shortcut = shortcut;
|
PSHORTCUT->shortcut = shortcut;
|
||||||
|
|
||||||
PSHORTCUT->resource = wl_resource_create(client, &hyprland_global_shortcut_v1_interface, 1, shortcut);
|
if (!PSHORTCUT->resource->resource()) {
|
||||||
if (!PSHORTCUT->resource) {
|
PSHORTCUT->resource->noMemory();
|
||||||
wl_client_post_no_memory(client);
|
shortcuts.pop_back();
|
||||||
std::erase_if(PCLIENT->shortcuts, [&](const auto& other) { return other.get() == PSHORTCUT; });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_resource_set_implementation(PSHORTCUT->resource, &shortcutImpl, this, &onShortcutDestroy);
|
PSHORTCUT->resource->setDestroy([this](CHyprlandGlobalShortcutV1* pMgr) { std::erase_if(shortcuts, [&](const auto& other) { return other->resource.get() == pMgr; }); });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, std::string trigger) {
|
bool CShortcutClient::good() {
|
||||||
|
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);
|
||||||
|
m_vClients.pop_back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
@ -116,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) {
|
||||||
|
@ -125,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) {
|
||||||
|
@ -143,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; });
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +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;
|
public:
|
||||||
std::vector<std::unique_ptr<SShortcut>> shortcuts;
|
CShortcutClient(SP<CHyprlandGlobalShortcutsManagerV1> resource);
|
||||||
|
|
||||||
|
bool good();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SP<CHyprlandGlobalShortcutsManagerV1> resource;
|
||||||
|
std::vector<SP<SShortcut>> shortcuts;
|
||||||
|
|
||||||
|
friend class CGlobalShortcutsProtocol;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CGlobalShortcutsProtocolManager {
|
class CGlobalShortcutsProtocol : IWaylandProtocol {
|
||||||
public:
|
public:
|
||||||
CGlobalShortcutsProtocolManager();
|
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 bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||||
void displayDestroy();
|
void destroyResource(CShortcutClient* client);
|
||||||
|
|
||||||
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);
|
void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed);
|
||||||
|
bool isTaken(std::string id, std::string app_id);
|
||||||
std::vector<SShortcut> getAllShortcuts();
|
std::vector<SShortcut> getAllShortcuts();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<SShortcutClient>> m_vClients;
|
std::vector<SP<CShortcutClient>> m_vClients;
|
||||||
|
};
|
||||||
SShortcutClient* clientFromWlClient(wl_client* client);
|
|
||||||
|
namespace PROTO {
|
||||||
wl_global* m_pGlobal = nullptr;
|
inline UP<CGlobalShortcutsProtocol> globalShortcuts;
|
||||||
wl_listener m_liDisplayDestroy;
|
|
||||||
};
|
};
|
|
@ -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();
|
||||||
|
|
|
@ -11,7 +11,7 @@ void CLayerShellResource::SState::reset() {
|
||||||
exclusive = 0;
|
exclusive = 0;
|
||||||
interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
|
interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
|
||||||
layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||||
exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
exclusiveEdge = (zwlrLayerSurfaceV1Anchor)0;
|
||||||
desiredSize = {};
|
desiredSize = {};
|
||||||
margin = {0, 0, 0, 0};
|
margin = {0, 0, 0, 0};
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,13 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<C
|
||||||
PROTO::layerShell->destroyResource(this);
|
PROTO::layerShell->destroyResource(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
listeners.unmapSurface = surf_->events.unmap.registerListener([this](std::any d) { events.unmap.emit(); });
|
||||||
|
|
||||||
listeners.commitSurface = surf_->events.commit.registerListener([this](std::any d) {
|
listeners.commitSurface = surf_->events.commit.registerListener([this](std::any d) {
|
||||||
current = pending;
|
current = pending;
|
||||||
pending.committed = 0;
|
pending.committed = 0;
|
||||||
|
|
||||||
bool attachedBuffer = surface->current.buffer;
|
bool attachedBuffer = surface->current.texture;
|
||||||
|
|
||||||
if (attachedBuffer && !configured) {
|
if (attachedBuffer && !configured) {
|
||||||
surface->error(-1, "layerSurface was not configured, but a buffer was attached");
|
surface->error(-1, "layerSurface was not configured, but a buffer was attached");
|
||||||
|
@ -71,8 +73,8 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<C
|
||||||
|
|
||||||
if (!attachedBuffer && mapped) {
|
if (!attachedBuffer && mapped) {
|
||||||
mapped = false;
|
mapped = false;
|
||||||
surface->unmap();
|
|
||||||
events.unmap.emit();
|
events.unmap.emit();
|
||||||
|
surface->unmap();
|
||||||
configured = false;
|
configured = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +154,16 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<C
|
||||||
});
|
});
|
||||||
|
|
||||||
resource->setSetExclusiveEdge([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) {
|
resource->setSetExclusiveEdge([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) {
|
||||||
|
if (anchor > (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
|
||||||
|
r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_EXCLUSIVE_EDGE, "Invalid exclusive edge");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anchor && (!pending.anchor || !(pending.anchor & anchor))) {
|
||||||
|
r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_EXCLUSIVE_EDGE, "Exclusive edge doesn't align with anchor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pending.committed |= STATE_EDGE;
|
pending.committed |= STATE_EDGE;
|
||||||
pending.exclusiveEdge = anchor;
|
pending.exclusiveEdge = anchor;
|
||||||
});
|
});
|
||||||
|
@ -163,10 +175,6 @@ CLayerShellResource::~CLayerShellResource() {
|
||||||
surface->resetRole();
|
surface->resetRole();
|
||||||
}
|
}
|
||||||
|
|
||||||
eSurfaceRole CLayerShellResource::role() {
|
|
||||||
return SURFACE_ROLE_LAYER_SHELL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CLayerShellResource::good() {
|
bool CLayerShellResource::good() {
|
||||||
return resource->resource();
|
return resource->resource();
|
||||||
}
|
}
|
||||||
|
@ -233,8 +241,12 @@ void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SURF->role = RESOURCE;
|
SURF->role = makeShared<CLayerShellRole>(RESOURCE);
|
||||||
g_pCompositor->m_vLayers.emplace_back(CLayerSurface::create(RESOURCE));
|
g_pCompositor->m_vLayers.emplace_back(CLayerSurface::create(RESOURCE));
|
||||||
|
|
||||||
LOGM(LOG, "New wlr_layer_surface {:x}", (uintptr_t)RESOURCE.get());
|
LOGM(LOG, "New wlr_layer_surface {:x}", (uintptr_t)RESOURCE.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayerShellRole::CLayerShellRole(SP<CLayerShellResource> ls) : layerSurface(ls) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
|
@ -12,8 +12,19 @@
|
||||||
|
|
||||||
class CMonitor;
|
class CMonitor;
|
||||||
class CWLSurfaceResource;
|
class CWLSurfaceResource;
|
||||||
|
class CLayerShellResource;
|
||||||
|
|
||||||
class CLayerShellResource : public ISurfaceRole {
|
class CLayerShellRole : public ISurfaceRole {
|
||||||
|
public:
|
||||||
|
CLayerShellRole(SP<CLayerShellResource> ls);
|
||||||
|
|
||||||
|
virtual eSurfaceRole role() {
|
||||||
|
return SURFACE_ROLE_LAYER_SHELL;
|
||||||
|
}
|
||||||
|
|
||||||
|
WP<CLayerShellResource> layerSurface;
|
||||||
|
};
|
||||||
|
class CLayerShellResource {
|
||||||
public:
|
public:
|
||||||
CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<CWLSurfaceResource> surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer);
|
CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<CWLSurfaceResource> surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer);
|
||||||
~CLayerShellResource();
|
~CLayerShellResource();
|
||||||
|
@ -21,7 +32,6 @@ class CLayerShellResource : public ISurfaceRole {
|
||||||
bool good();
|
bool good();
|
||||||
void configure(const Vector2D& size);
|
void configure(const Vector2D& size);
|
||||||
void sendClosed();
|
void sendClosed();
|
||||||
virtual eSurfaceRole role();
|
|
||||||
|
|
||||||
enum eCommittedState {
|
enum eCommittedState {
|
||||||
STATE_SIZE = (1 << 0),
|
STATE_SIZE = (1 << 0),
|
||||||
|
@ -47,7 +57,7 @@ class CLayerShellResource : public ISurfaceRole {
|
||||||
Vector2D desiredSize;
|
Vector2D desiredSize;
|
||||||
zwlrLayerSurfaceV1KeyboardInteractivity interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
|
zwlrLayerSurfaceV1KeyboardInteractivity interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
|
||||||
zwlrLayerShellV1Layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
zwlrLayerShellV1Layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||||
zwlrLayerSurfaceV1Anchor exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
zwlrLayerSurfaceV1Anchor exclusiveEdge = (zwlrLayerSurfaceV1Anchor)0;
|
||||||
uint32_t committed = 0;
|
uint32_t committed = 0;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -70,6 +80,7 @@ class CLayerShellResource : public ISurfaceRole {
|
||||||
struct {
|
struct {
|
||||||
CHyprSignalListener commitSurface;
|
CHyprSignalListener commitSurface;
|
||||||
CHyprSignalListener destroySurface;
|
CHyprSignalListener destroySurface;
|
||||||
|
CHyprSignalListener unmapSurface;
|
||||||
} listeners;
|
} listeners;
|
||||||
|
|
||||||
bool closed = false;
|
bool closed = false;
|
||||||
|
|
|
@ -60,7 +60,7 @@ void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespe
|
||||||
if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION)
|
if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION)
|
||||||
flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
|
flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
|
||||||
|
|
||||||
if (data->wasPresented && when)
|
if (data->wasPresented)
|
||||||
resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32),
|
resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32),
|
||||||
(uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags);
|
(uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags);
|
||||||
else
|
else
|
||||||
|
@ -104,6 +104,14 @@ void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* su
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
|
void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
|
||||||
|
timespec now;
|
||||||
|
timespec* presentedAt = when;
|
||||||
|
if (!presentedAt) {
|
||||||
|
// just put the current time, we don't have anything better
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
when = &now;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& feedback : m_vFeedbacks) {
|
for (auto& feedback : m_vFeedbacks) {
|
||||||
if (!feedback->surface)
|
if (!feedback->surface)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -9,238 +9,39 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#define SCREENCOPY_VERSION 3
|
#define LOGM PROTO::screencopy->protoLog
|
||||||
|
|
||||||
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
CScreencopyFrame::~CScreencopyFrame() {
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->bindManager(client, data, version, id);
|
if (buffer && buffer->locked())
|
||||||
|
buffer->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
|
CScreencopyFrame::CScreencopyFrame(SP<CZwlrScreencopyFrameV1> resource_, int32_t overlay_cursor, wl_resource* output, CBox box_) : resource(resource_) {
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->displayDestroy();
|
if (!good())
|
||||||
}
|
return;
|
||||||
|
|
||||||
void CScreencopyProtocolManager::displayDestroy() {
|
overlayCursor = !!overlay_cursor;
|
||||||
wl_global_destroy(m_pGlobal);
|
pMonitor = CWLOutputResource::fromResource(output)->monitor.get();
|
||||||
}
|
|
||||||
|
|
||||||
static SScreencopyFrame* frameFromResource(wl_resource*);
|
if (!pMonitor) {
|
||||||
|
LOGM(ERR, "Client requested sharing of a monitor that doesnt exist");
|
||||||
CScreencopyProtocolManager::CScreencopyProtocolManager() {
|
resource->sendFailed();
|
||||||
|
PROTO::screencopy->destroyResource(this);
|
||||||
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &zwlr_screencopy_manager_v1_interface, SCREENCOPY_VERSION, this, bindManagerInt);
|
|
||||||
|
|
||||||
if (!m_pGlobal) {
|
|
||||||
Debug::log(ERR, "ScreencopyProtocolManager could not start! Screensharing will not work!");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
resource->setOnDestroy([this](CZwlrScreencopyFrameV1* pMgr) { PROTO::screencopy->destroyResource(this); });
|
||||||
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
resource->setDestroy([this](CZwlrScreencopyFrameV1* pFrame) { PROTO::screencopy->destroyResource(this); });
|
||||||
|
resource->setCopy([this](CZwlrScreencopyFrameV1* pFrame, wl_resource* res) { this->copy(pFrame, res); });
|
||||||
Debug::log(LOG, "ScreencopyProtocolManager started successfully!");
|
resource->setCopyWithDamage([this](CZwlrScreencopyFrameV1* pFrame, wl_resource* res) {
|
||||||
|
withDamage = true;
|
||||||
m_pSoftwareCursorTimer = makeShared<CEventLoopTimer>(
|
this->copy(pFrame, res);
|
||||||
std::nullopt,
|
});
|
||||||
[this](SP<CEventLoopTimer> self, void* data) {
|
|
||||||
// TODO: make it per-monitor
|
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
|
||||||
g_pPointerManager->unlockSoftwareForMonitor(m);
|
|
||||||
}
|
|
||||||
m_bTimerArmed = false;
|
|
||||||
|
|
||||||
Debug::log(LOG, "[screencopy] Releasing software cursor lock");
|
|
||||||
},
|
|
||||||
nullptr);
|
|
||||||
g_pEventLoopManager->addTimer(m_pSoftwareCursorTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCaptureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output) {
|
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->captureOutput(client, resource, frame, overlay_cursor, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCaptureRegion(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, int32_t x, int32_t y, int32_t width,
|
|
||||||
int32_t height) {
|
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->captureOutput(client, resource, frame, overlay_cursor, output, {x, y, width, height});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDestroy(wl_client* client, wl_resource* resource) {
|
|
||||||
wl_resource_destroy(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer) {
|
|
||||||
const auto PFRAME = frameFromResource(resource);
|
|
||||||
|
|
||||||
if (!PFRAME)
|
|
||||||
return;
|
|
||||||
|
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->copyFrame(client, resource, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCopyWithDamage(wl_client* client, wl_resource* resource, wl_resource* buffer) {
|
|
||||||
const auto PFRAME = frameFromResource(resource);
|
|
||||||
|
|
||||||
if (!PFRAME)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PFRAME->withDamage = true;
|
|
||||||
handleCopyFrame(client, resource, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDestroyFrame(wl_client* client, wl_resource* resource) {
|
|
||||||
wl_resource_destroy(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct zwlr_screencopy_manager_v1_interface screencopyMgrImpl = {
|
|
||||||
.capture_output = handleCaptureOutput,
|
|
||||||
.capture_output_region = handleCaptureRegion,
|
|
||||||
.destroy = handleDestroy,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct zwlr_screencopy_frame_v1_interface screencopyFrameImpl = {
|
|
||||||
.copy = handleCopyFrame,
|
|
||||||
.destroy = handleDestroyFrame,
|
|
||||||
.copy_with_damage = handleCopyWithDamage,
|
|
||||||
};
|
|
||||||
|
|
||||||
static CScreencopyClient* clientFromResource(wl_resource* resource) {
|
|
||||||
ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_manager_v1_interface, &screencopyMgrImpl));
|
|
||||||
return (CScreencopyClient*)wl_resource_get_user_data(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static SScreencopyFrame* frameFromResource(wl_resource* resource) {
|
|
||||||
ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_frame_v1_interface, &screencopyFrameImpl));
|
|
||||||
return (SScreencopyFrame*)wl_resource_get_user_data(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CScreencopyProtocolManager::removeClient(CScreencopyClient* client, bool force) {
|
|
||||||
if (!client)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!force) {
|
|
||||||
if (!client || client->ref <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (--client->ref != 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits???
|
|
||||||
|
|
||||||
for (auto& f : m_lFrames) {
|
|
||||||
// avoid dangling ptrs
|
|
||||||
if (f.client == client)
|
|
||||||
f.client = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleManagerResourceDestroy(wl_resource* resource) {
|
|
||||||
const auto PCLIENT = clientFromResource(resource);
|
|
||||||
|
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->removeClient(PCLIENT, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
CScreencopyClient::~CScreencopyClient() {
|
|
||||||
g_pHookSystem->unhook(tickCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
CScreencopyClient::CScreencopyClient() {
|
|
||||||
lastMeasure.reset();
|
|
||||||
lastFrame.reset();
|
|
||||||
tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, SCallbackInfo& info, std::any data) { onTick(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void CScreencopyClient::onTick() {
|
|
||||||
if (lastMeasure.getMillis() < 500)
|
|
||||||
return;
|
|
||||||
|
|
||||||
framesInLastHalfSecond = frameCounter;
|
|
||||||
frameCounter = 0;
|
|
||||||
lastMeasure.reset();
|
|
||||||
|
|
||||||
const auto LASTFRAMEDELTA = lastFrame.getMillis() / 1000.0;
|
|
||||||
const bool FRAMEAWAITING = std::ranges::any_of(g_pProtocolManager->m_pScreencopyProtocolManager->m_lFrames, [&](const auto& frame) { return frame.client == this; }) ||
|
|
||||||
std::ranges::any_of(g_pProtocolManager->m_pToplevelExportProtocolManager->m_lFrames, [&](const auto& frame) { return frame.client == this; });
|
|
||||||
|
|
||||||
if (framesInLastHalfSecond > 3 && !sentScreencast) {
|
|
||||||
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)});
|
|
||||||
sentScreencast = true;
|
|
||||||
} else if (framesInLastHalfSecond < 4 && sentScreencast && LASTFRAMEDELTA > 1.0 && !FRAMEAWAITING) {
|
|
||||||
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
|
||||||
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)});
|
|
||||||
sentScreencast = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CScreencopyProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
|
||||||
const auto PCLIENT = &m_lClients.emplace_back();
|
|
||||||
|
|
||||||
PCLIENT->resource = wl_resource_create(client, &zwlr_screencopy_manager_v1_interface, version, id);
|
|
||||||
|
|
||||||
if (!PCLIENT->resource) {
|
|
||||||
Debug::log(ERR, "ScreencopyProtocolManager could not bind! (out of memory?)");
|
|
||||||
m_lClients.remove(*PCLIENT);
|
|
||||||
wl_client_post_no_memory(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PCLIENT->ref = 1;
|
|
||||||
|
|
||||||
wl_resource_set_implementation(PCLIENT->resource, &screencopyMgrImpl, PCLIENT, handleManagerResourceDestroy);
|
|
||||||
|
|
||||||
Debug::log(LOG, "ScreencopyProtocolManager bound successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleFrameResourceDestroy(wl_resource* resource) {
|
|
||||||
const auto PFRAME = frameFromResource(resource);
|
|
||||||
|
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->removeFrame(PFRAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force) {
|
|
||||||
if (!frame)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; });
|
|
||||||
|
|
||||||
wl_resource_set_user_data(frame->resource, nullptr);
|
|
||||||
if (frame->buffer && frame->buffer->locked())
|
|
||||||
frame->buffer->unlock();
|
|
||||||
removeClient(frame->client, force);
|
|
||||||
m_lFrames.remove(*frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, CBox box) {
|
|
||||||
const auto PCLIENT = clientFromResource(resource);
|
|
||||||
|
|
||||||
const auto PFRAME = &m_lFrames.emplace_back();
|
|
||||||
PFRAME->overlayCursor = !!overlay_cursor;
|
|
||||||
PFRAME->resource = wl_resource_create(client, &zwlr_screencopy_frame_v1_interface, wl_resource_get_version(resource), frame);
|
|
||||||
PFRAME->pMonitor = CWLOutputResource::fromResource(output)->monitor.get();
|
|
||||||
|
|
||||||
if (!PFRAME->pMonitor) {
|
|
||||||
Debug::log(ERR, "client requested sharing of a monitor that doesnt exist");
|
|
||||||
zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
|
|
||||||
removeFrame(PFRAME);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PFRAME->resource) {
|
|
||||||
Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)");
|
|
||||||
removeFrame(PFRAME);
|
|
||||||
wl_client_post_no_memory(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_resource_set_implementation(PFRAME->resource, &screencopyFrameImpl, PFRAME, handleFrameResourceDestroy);
|
|
||||||
|
|
||||||
PFRAME->client = PCLIENT;
|
|
||||||
PCLIENT->ref++;
|
|
||||||
|
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
g_pHyprRenderer->makeEGLCurrent();
|
||||||
|
|
||||||
if (g_pHyprOpenGL->m_mMonitorRenderResources.contains(PFRAME->pMonitor)) {
|
if (g_pHyprOpenGL->m_mMonitorRenderResources.contains(pMonitor)) {
|
||||||
const auto& RDATA = g_pHyprOpenGL->m_mMonitorRenderResources.at(PFRAME->pMonitor);
|
const auto& RDATA = g_pHyprOpenGL->m_mMonitorRenderResources.at(pMonitor);
|
||||||
// bind the fb for its format. Suppress gl errors.
|
// bind the fb for its format. Suppress gl errors.
|
||||||
#ifndef GLES2
|
#ifndef GLES2
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, RDATA.offloadFB.m_iFb);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, RDATA.offloadFB.m_iFb);
|
||||||
|
@ -248,246 +49,212 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, RDATA.offloadFB.m_iFb);
|
glBindFramebuffer(GL_FRAMEBUFFER, RDATA.offloadFB.m_iFb);
|
||||||
#endif
|
#endif
|
||||||
} else
|
} else
|
||||||
Debug::log(ERR, "No RDATA in screencopy???");
|
LOGM(ERR, "No RDATA in screencopy???");
|
||||||
|
|
||||||
PFRAME->shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PFRAME->pMonitor);
|
shmFormat = g_pHyprOpenGL->getPreferredReadFormat(pMonitor);
|
||||||
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
|
if (shmFormat == DRM_FORMAT_INVALID) {
|
||||||
Debug::log(ERR, "No format supported by renderer in capture output");
|
LOGM(ERR, "No format supported by renderer in capture output");
|
||||||
zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat);
|
const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(shmFormat);
|
||||||
if (!PSHMINFO) {
|
if (!PSHMINFO) {
|
||||||
Debug::log(ERR, "No pixel format supported by renderer in capture output");
|
LOGM(ERR, "No pixel format supported by renderer in capture output");
|
||||||
zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PFRAME->dmabufFormat = PFRAME->pMonitor->output->state->state().drmFormat;
|
dmabufFormat = pMonitor->output->state->state().drmFormat;
|
||||||
|
|
||||||
if (box.width == 0 && box.height == 0)
|
if (box_.width == 0 && box_.height == 0)
|
||||||
PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x), (int)(PFRAME->pMonitor->vecSize.y)};
|
box = {0, 0, (int)(pMonitor->vecSize.x), (int)(pMonitor->vecSize.y)};
|
||||||
else {
|
else {
|
||||||
PFRAME->box = box;
|
box = box_;
|
||||||
}
|
}
|
||||||
|
|
||||||
PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), PFRAME->pMonitor->vecTransformedSize.x, PFRAME->pMonitor->vecTransformedSize.y)
|
box.transform(wlTransformToHyprutils(pMonitor->transform), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y).scale(pMonitor->scale).round();
|
||||||
.scale(PFRAME->pMonitor->scale)
|
|
||||||
.round();
|
|
||||||
|
|
||||||
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
|
shmStride = FormatUtils::minStride(PSHMINFO, box.w);
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
|
resource->sendBuffer(FormatUtils::drmToShm(shmFormat), box.width, box.height, shmStride);
|
||||||
|
|
||||||
if (wl_resource_get_version(resource) >= 3) {
|
if (resource->version() >= 3) {
|
||||||
if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) {
|
if (dmabufFormat != DRM_FORMAT_INVALID) {
|
||||||
zwlr_screencopy_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height);
|
resource->sendLinuxDmabuf(dmabufFormat, box.width, box.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_send_buffer_done(PFRAME->resource);
|
resource->sendBufferDone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer) {
|
void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_) {
|
||||||
const auto PFRAME = frameFromResource(resource);
|
if (!good()) {
|
||||||
|
LOGM(ERR, "No frame in copyFrame??");
|
||||||
if (!PFRAME) {
|
|
||||||
Debug::log(ERR, "No frame in copyFrame??");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_pCompositor->monitorExists(PFRAME->pMonitor)) {
|
if (!g_pCompositor->monitorExists(pMonitor)) {
|
||||||
Debug::log(ERR, "client requested sharing of a monitor that is gone");
|
LOGM(ERR, "Client requested sharing of a monitor that is gone");
|
||||||
zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto PBUFFER = CWLBufferResource::fromResource(buffer);
|
const auto PBUFFER = CWLBufferResource::fromResource(buffer_);
|
||||||
if (!PBUFFER) {
|
if (!PBUFFER) {
|
||||||
Debug::log(ERR, "[sc] invalid buffer in {:x}", (uintptr_t)PFRAME);
|
LOGM(ERR, "Invalid buffer in {:x}", (uintptr_t)this);
|
||||||
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PBUFFER->buffer->lock();
|
PBUFFER->buffer->lock();
|
||||||
|
|
||||||
if (PBUFFER->buffer->size != PFRAME->box.size()) {
|
if (PBUFFER->buffer->size != box.size()) {
|
||||||
Debug::log(ERR, "[sc] invalid dimensions in {:x}", (uintptr_t)PFRAME);
|
LOGM(ERR, "Invalid dimensions in {:x}", (uintptr_t)this);
|
||||||
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PFRAME->buffer) {
|
if (buffer) {
|
||||||
Debug::log(ERR, "[sc] buffer used in {:x}", (uintptr_t)PFRAME);
|
LOGM(ERR, "Buffer used in {:x}", (uintptr_t)this);
|
||||||
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) {
|
if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) {
|
||||||
PFRAME->bufferDMA = true;
|
bufferDMA = true;
|
||||||
|
|
||||||
if (attrs.format != PFRAME->dmabufFormat) {
|
if (attrs.format != dmabufFormat) {
|
||||||
Debug::log(ERR, "[sc] invalid buffer dma format in {:x}", (uintptr_t)PFRAME);
|
LOGM(ERR, "Invalid buffer dma format in {:x}", (uintptr_t)pFrame);
|
||||||
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) {
|
} else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) {
|
||||||
if (attrs.format != PFRAME->shmFormat) {
|
if (attrs.format != shmFormat) {
|
||||||
Debug::log(ERR, "[sc] invalid buffer shm format in {:x}", (uintptr_t)PFRAME);
|
LOGM(ERR, "Invalid buffer shm format in {:x}", (uintptr_t)pFrame);
|
||||||
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
} else if ((int)attrs.stride != PFRAME->shmStride) {
|
} else if ((int)attrs.stride != shmStride) {
|
||||||
Debug::log(ERR, "[sc] invalid buffer shm stride in {:x}", (uintptr_t)PFRAME);
|
LOGM(ERR, "Invalid buffer shm stride in {:x}", (uintptr_t)pFrame);
|
||||||
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Debug::log(ERR, "[sc] invalid buffer type in {:x}", (uintptr_t)PFRAME);
|
LOGM(ERR, "Invalid buffer type in {:x}", (uintptr_t)pFrame);
|
||||||
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
|
resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
|
||||||
removeFrame(PFRAME);
|
PROTO::screencopy->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PFRAME->buffer = PBUFFER->buffer;
|
buffer = PBUFFER->buffer;
|
||||||
|
|
||||||
m_vFramesAwaitingWrite.emplace_back(PFRAME);
|
PROTO::screencopy->m_vFramesAwaitingWrite.emplace_back(self);
|
||||||
|
|
||||||
g_pHyprRenderer->m_bDirectScanoutBlocked = true;
|
g_pHyprRenderer->m_bDirectScanoutBlocked = true;
|
||||||
if (PFRAME->overlayCursor && !PFRAME->lockedSWCursors) {
|
if (overlayCursor && !lockedSWCursors) {
|
||||||
PFRAME->lockedSWCursors = true;
|
lockedSWCursors = true;
|
||||||
// TODO: make it per-monitor
|
// TODO: make it per-monitor
|
||||||
if (!m_bTimerArmed) {
|
if (!PROTO::screencopy->m_bTimerArmed) {
|
||||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||||
g_pPointerManager->lockSoftwareForMonitor(m);
|
g_pPointerManager->lockSoftwareForMonitor(m);
|
||||||
}
|
}
|
||||||
m_bTimerArmed = true;
|
PROTO::screencopy->m_bTimerArmed = true;
|
||||||
Debug::log(LOG, "[screencopy] Locking sw cursors due to screensharing");
|
LOGM(LOG, "Locking sw cursors due to screensharing");
|
||||||
}
|
}
|
||||||
m_pSoftwareCursorTimer->updateTimeout(std::chrono::seconds(1));
|
PROTO::screencopy->m_pSoftwareCursorTimer->updateTimeout(std::chrono::seconds(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PFRAME->withDamage)
|
if (!withDamage)
|
||||||
g_pHyprRenderer->damageMonitor(PFRAME->pMonitor);
|
g_pHyprRenderer->damageMonitor(pMonitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor) {
|
void CScreencopyFrame::share() {
|
||||||
m_pLastMonitorBackBuffer = pMonitor->output->state->state().buffer;
|
if (!buffer || !pMonitor)
|
||||||
shareAllFrames(pMonitor);
|
|
||||||
m_pLastMonitorBackBuffer.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) {
|
|
||||||
if (m_vFramesAwaitingWrite.empty())
|
|
||||||
return; // nothing to share
|
|
||||||
|
|
||||||
std::vector<SScreencopyFrame*> framesToRemove;
|
|
||||||
|
|
||||||
// share frame if correct output
|
|
||||||
for (auto& f : m_vFramesAwaitingWrite) {
|
|
||||||
if (!f->pMonitor || !f->buffer) {
|
|
||||||
framesToRemove.push_back(f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->pMonitor != pMonitor)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
shareFrame(f);
|
|
||||||
|
|
||||||
f->client->lastFrame.reset();
|
|
||||||
++f->client->frameCounter;
|
|
||||||
|
|
||||||
framesToRemove.push_back(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& f : framesToRemove) {
|
|
||||||
removeFrame(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_vFramesAwaitingWrite.empty()) {
|
|
||||||
g_pHyprRenderer->m_bDirectScanoutBlocked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) {
|
|
||||||
if (!frame->buffer)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
timespec now;
|
timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
uint32_t flags = 0;
|
if (bufferDMA) {
|
||||||
if (frame->bufferDMA) {
|
if (!copyDmabuf()) {
|
||||||
if (!copyFrameDmabuf(frame)) {
|
LOGM(ERR, "Dmabuf copy failed in {:x}", (uintptr_t)this);
|
||||||
Debug::log(ERR, "[sc] dmabuf copy failed in {:x}", (uintptr_t)frame);
|
resource->sendFailed();
|
||||||
zwlr_screencopy_frame_v1_send_failed(frame->resource);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!copyFrameShm(frame, &now)) {
|
if (!copyShm()) {
|
||||||
Debug::log(ERR, "[sc] shm copy failed in {:x}", (uintptr_t)frame);
|
LOGM(ERR, "Shm copy failed in {:x}", (uintptr_t)this);
|
||||||
zwlr_screencopy_frame_v1_send_failed(frame->resource);
|
resource->sendFailed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_send_flags(frame->resource, flags);
|
resource->sendFlags((zwlrScreencopyFrameV1Flags)0);
|
||||||
sendFrameDamage(frame);
|
if (withDamage) {
|
||||||
|
// TODO: add a damage ring for this.
|
||||||
|
resource->sendDamage(0, 0, buffer->size.x, buffer->size.y);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
zwlr_screencopy_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
resource->sendReady(tvSecHi, tvSecLo, now.tv_nsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
|
bool CScreencopyFrame::copyDmabuf() {
|
||||||
if (!frame->withDamage)
|
auto TEXTURE = makeShared<CTexture>(pMonitor->output->state->state().buffer);
|
||||||
return;
|
|
||||||
|
|
||||||
// TODO:
|
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
||||||
// add a damage ring for this.
|
|
||||||
|
|
||||||
// for (auto& RECT : frame->pMonitor->lastFrameDamage.getRects()) {
|
if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock(), nullptr, true)) {
|
||||||
|
LOGM(ERR, "Can't copy: failed to begin rendering to dma frame");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// if (frame->buffer->width < 1 || frame->buffer->height < 1 || frame->buffer->width - RECT.x1 < 1 || frame->buffer->height - RECT.y1 < 1) {
|
CBox monbox = CBox{0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}
|
||||||
// Debug::log(ERR, "[sc] Failed to send damage");
|
.translate({-box.x, -box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
|
||||||
// break;
|
.transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
|
||||||
// }
|
g_pHyprOpenGL->setMonitorTransformEnabled(true);
|
||||||
|
g_pHyprOpenGL->setRenderModifEnabled(false);
|
||||||
|
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
|
||||||
|
g_pHyprOpenGL->setRenderModifEnabled(true);
|
||||||
|
g_pHyprOpenGL->setMonitorTransformEnabled(false);
|
||||||
|
|
||||||
// zwlr_screencopy_frame_v1_send_damage(frame->resource, std::clamp(RECT.x1, 0, frame->buffer->width), std::clamp(RECT.y1, 0, frame->buffer->height),
|
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
|
||||||
// std::clamp(RECT.x2 - RECT.x1, 0, frame->buffer->width - RECT.x1), std::clamp(RECT.y2 - RECT.y1, 0, frame->buffer->height - RECT.y1));
|
g_pHyprRenderer->endRender();
|
||||||
// }
|
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->size.x, frame->buffer->size.y);
|
LOGM(TRACE, "Copied frame via dma");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
|
bool CScreencopyFrame::copyShm() {
|
||||||
auto TEXTURE = makeShared<CTexture>(m_pLastMonitorBackBuffer);
|
auto TEXTURE = makeShared<CTexture>(pMonitor->output->state->state().buffer);
|
||||||
|
|
||||||
auto shm = frame->buffer->shm();
|
auto shm = buffer->shm();
|
||||||
auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm
|
auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); // no need for end, cuz it's shm
|
||||||
|
|
||||||
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
||||||
|
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
g_pHyprRenderer->makeEGLCurrent();
|
||||||
|
|
||||||
CFramebuffer fb;
|
CFramebuffer fb;
|
||||||
fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->output->state->state().drmFormat);
|
fb.alloc(box.w, box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : pMonitor->output->state->state().drmFormat);
|
||||||
|
|
||||||
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) {
|
if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) {
|
||||||
Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering");
|
LOGM(ERR, "Can't copy: failed to begin rendering");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y});
|
CBox monbox = CBox{0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}.translate({-box.x, -box.y});
|
||||||
g_pHyprOpenGL->setMonitorTransformEnabled(true);
|
g_pHyprOpenGL->setMonitorTransformEnabled(true);
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(false);
|
g_pHyprOpenGL->setRenderModifEnabled(false);
|
||||||
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
|
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
|
||||||
|
@ -502,7 +269,7 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
|
||||||
|
|
||||||
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
|
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
|
||||||
if (!PFORMAT) {
|
if (!PFORMAT) {
|
||||||
Debug::log(ERR, "Screencopy: can't copy: failed to find a pixel format");
|
LOGM(ERR, "Can't copy: failed to find a pixel format");
|
||||||
g_pHyprRenderer->endRender();
|
g_pHyprRenderer->endRender();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -513,53 +280,164 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
|
||||||
g_pHyprRenderer->endRender();
|
g_pHyprRenderer->endRender();
|
||||||
|
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
g_pHyprRenderer->makeEGLCurrent();
|
||||||
g_pHyprOpenGL->m_RenderData.pMonitor = frame->pMonitor;
|
g_pHyprOpenGL->m_RenderData.pMonitor = pMonitor;
|
||||||
fb.bind();
|
fb.bind();
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
const auto drmFmt = FormatUtils::getPixelFormatFromDRM(shm.format);
|
const auto drmFmt = FormatUtils::getPixelFormatFromDRM(shm.format);
|
||||||
uint32_t packStride = FormatUtils::minStride(drmFmt, frame->box.w);
|
uint32_t packStride = FormatUtils::minStride(drmFmt, box.w);
|
||||||
|
|
||||||
if (packStride == (uint32_t)shm.stride) {
|
if (packStride == (uint32_t)shm.stride) {
|
||||||
glReadPixels(0, 0, frame->box.w, frame->box.h, glFormat, PFORMAT->glType, pixelData);
|
glReadPixels(0, 0, box.w, box.h, glFormat, PFORMAT->glType, pixelData);
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < frame->box.h; ++i) {
|
for (size_t i = 0; i < box.h; ++i) {
|
||||||
uint32_t y = i;
|
uint32_t y = i;
|
||||||
glReadPixels(0, y, frame->box.w, 1, glFormat, PFORMAT->glType, ((unsigned char*)pixelData) + i * shm.stride);
|
glReadPixels(0, y, box.w, 1, glFormat, PFORMAT->glType, ((unsigned char*)pixelData) + i * shm.stride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
|
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
|
||||||
|
|
||||||
Debug::log(TRACE, "Screencopy: copied frame via shm");
|
LOGM(TRACE, "Copied frame via shm");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
|
bool CScreencopyFrame::good() {
|
||||||
auto TEXTURE = makeShared<CTexture>(m_pLastMonitorBackBuffer);
|
return resource->resource();
|
||||||
|
}
|
||||||
|
|
||||||
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
CScreencopyClient::~CScreencopyClient() {
|
||||||
|
g_pHookSystem->unhook(tickCallback);
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) {
|
CScreencopyClient::CScreencopyClient(SP<CZwlrScreencopyManagerV1> resource_) : resource(resource_) {
|
||||||
Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering to dma frame");
|
if (!good())
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
|
resource->setDestroy([this](CZwlrScreencopyManagerV1* pMgr) { PROTO::screencopy->destroyResource(this); });
|
||||||
|
resource->setOnDestroy([this](CZwlrScreencopyManagerV1* pMgr) { PROTO::screencopy->destroyResource(this); });
|
||||||
|
resource->setCaptureOutput(
|
||||||
|
[this](CZwlrScreencopyManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, wl_resource* output) { this->captureOutput(frame, overlayCursor, output, {}); });
|
||||||
|
resource->setCaptureOutputRegion([this](CZwlrScreencopyManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, wl_resource* output, int32_t x, int32_t y, int32_t w,
|
||||||
|
int32_t h) { this->captureOutput(frame, overlayCursor, output, {x, y, w, h}); });
|
||||||
|
|
||||||
|
lastMeasure.reset();
|
||||||
|
lastFrame.reset();
|
||||||
|
tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, SCallbackInfo& info, std::any data) { onTick(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScreencopyClient::captureOutput(uint32_t frame, int32_t overlayCursor_, wl_resource* output, CBox box) {
|
||||||
|
const auto FRAME = PROTO::screencopy->m_vFrames.emplace_back(
|
||||||
|
makeShared<CScreencopyFrame>(makeShared<CZwlrScreencopyFrameV1>(resource->client(), resource->version(), frame), overlayCursor_, output, box));
|
||||||
|
|
||||||
|
if (!FRAME->good()) {
|
||||||
|
LOGM(ERR, "Couldn't alloc frame for sharing! (no memory)");
|
||||||
|
resource->noMemory();
|
||||||
|
PROTO::screencopy->destroyResource(FRAME.get());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}
|
FRAME->self = FRAME;
|
||||||
.translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
|
FRAME->client = self;
|
||||||
.transform(wlTransformToHyprutils(invertTransform(frame->pMonitor->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
|
}
|
||||||
g_pHyprOpenGL->setMonitorTransformEnabled(true);
|
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(false);
|
void CScreencopyClient::onTick() {
|
||||||
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
|
if (lastMeasure.getMillis() < 500)
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(true);
|
return;
|
||||||
g_pHyprOpenGL->setMonitorTransformEnabled(false);
|
|
||||||
|
framesInLastHalfSecond = frameCounter;
|
||||||
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
|
frameCounter = 0;
|
||||||
g_pHyprRenderer->endRender();
|
lastMeasure.reset();
|
||||||
|
|
||||||
Debug::log(TRACE, "Screencopy: copied frame via dma");
|
const auto LASTFRAMEDELTA = lastFrame.getMillis() / 1000.0;
|
||||||
|
const bool FRAMEAWAITING = std::ranges::any_of(PROTO::screencopy->m_vFrames, [&](const auto& frame) { return frame->client.get() == this; });
|
||||||
return true;
|
|
||||||
|
if (framesInLastHalfSecond > 3 && !sentScreencast) {
|
||||||
|
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)});
|
||||||
|
sentScreencast = true;
|
||||||
|
} else if (framesInLastHalfSecond < 4 && sentScreencast && LASTFRAMEDELTA > 1.0 && !FRAMEAWAITING) {
|
||||||
|
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)});
|
||||||
|
sentScreencast = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CScreencopyClient::good() {
|
||||||
|
return resource->resource();
|
||||||
|
}
|
||||||
|
|
||||||
|
CScreencopyProtocol::CScreencopyProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||||
|
m_pSoftwareCursorTimer = makeShared<CEventLoopTimer>(
|
||||||
|
std::nullopt,
|
||||||
|
[this](SP<CEventLoopTimer> self, void* data) {
|
||||||
|
// TODO: make it per-monitor
|
||||||
|
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||||
|
g_pPointerManager->unlockSoftwareForMonitor(m);
|
||||||
|
}
|
||||||
|
m_bTimerArmed = false;
|
||||||
|
|
||||||
|
LOGM(LOG, "Releasing software cursor lock");
|
||||||
|
},
|
||||||
|
nullptr);
|
||||||
|
g_pEventLoopManager->addTimer(m_pSoftwareCursorTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScreencopyProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||||
|
const auto CLIENT = m_vClients.emplace_back(makeShared<CScreencopyClient>(makeShared<CZwlrScreencopyManagerV1>(client, ver, id)));
|
||||||
|
|
||||||
|
if (!CLIENT->good()) {
|
||||||
|
LOGM(LOG, "Failed to bind client! (out of memory)");
|
||||||
|
CLIENT->resource->noMemory();
|
||||||
|
m_vClients.pop_back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIENT->self = CLIENT;
|
||||||
|
|
||||||
|
LOGM(LOG, "Bound client successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScreencopyProtocol::destroyResource(CScreencopyClient* client) {
|
||||||
|
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
|
||||||
|
std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; });
|
||||||
|
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) {
|
||||||
|
std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; });
|
||||||
|
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) {
|
||||||
|
if (m_vFramesAwaitingWrite.empty()) {
|
||||||
|
g_pHyprRenderer->m_bDirectScanoutBlocked = false;
|
||||||
|
return; // nothing to share
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<WP<CScreencopyFrame>> framesToRemove;
|
||||||
|
|
||||||
|
// share frame if correct output
|
||||||
|
for (auto& f : m_vFramesAwaitingWrite) {
|
||||||
|
if (!f->pMonitor || !f->buffer) {
|
||||||
|
framesToRemove.push_back(f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->pMonitor != pMonitor)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
f->share();
|
||||||
|
|
||||||
|
f->client->lastFrame.reset();
|
||||||
|
++f->client->frameCounter;
|
||||||
|
|
||||||
|
framesToRemove.push_back(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& f : framesToRemove) {
|
||||||
|
destroyResource(f.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "wlr-screencopy-unstable-v1-protocol.h"
|
#include "wlr-screencopy-unstable-v1.hpp"
|
||||||
|
#include "WaylandProtocol.hpp"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -20,87 +21,93 @@ enum eClientOwners {
|
||||||
|
|
||||||
class CScreencopyClient {
|
class CScreencopyClient {
|
||||||
public:
|
public:
|
||||||
CScreencopyClient();
|
CScreencopyClient(SP<CZwlrScreencopyManagerV1> resource_);
|
||||||
~CScreencopyClient();
|
~CScreencopyClient();
|
||||||
|
|
||||||
int ref = 0;
|
bool good();
|
||||||
wl_resource* resource = nullptr;
|
|
||||||
|
|
||||||
|
WP<CScreencopyClient> self;
|
||||||
eClientOwners clientOwner = CLIENT_SCREENCOPY;
|
eClientOwners clientOwner = CLIENT_SCREENCOPY;
|
||||||
|
|
||||||
|
CTimer lastFrame;
|
||||||
int frameCounter = 0;
|
int frameCounter = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SP<CZwlrScreencopyManagerV1> resource;
|
||||||
|
|
||||||
int framesInLastHalfSecond = 0;
|
int framesInLastHalfSecond = 0;
|
||||||
CTimer lastMeasure;
|
CTimer lastMeasure;
|
||||||
CTimer lastFrame;
|
|
||||||
bool sentScreencast = false;
|
bool sentScreencast = false;
|
||||||
|
|
||||||
void onTick();
|
|
||||||
SP<HOOK_CALLBACK_FN> tickCallback;
|
SP<HOOK_CALLBACK_FN> tickCallback;
|
||||||
|
void onTick();
|
||||||
|
|
||||||
bool operator==(const CScreencopyClient& other) const {
|
void captureOutput(uint32_t frame, int32_t overlayCursor, wl_resource* output, CBox box);
|
||||||
return resource == other.resource;
|
|
||||||
}
|
friend class CScreencopyProtocol;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SScreencopyFrame {
|
class CScreencopyFrame {
|
||||||
wl_resource* resource = nullptr;
|
public:
|
||||||
CScreencopyClient* client = nullptr;
|
CScreencopyFrame(SP<CZwlrScreencopyFrameV1> resource, int32_t overlay_cursor, wl_resource* output, CBox box);
|
||||||
|
~CScreencopyFrame();
|
||||||
|
|
||||||
uint32_t shmFormat = 0;
|
bool good();
|
||||||
uint32_t dmabufFormat = 0;
|
|
||||||
CBox box = {};
|
|
||||||
int shmStride = 0;
|
|
||||||
|
|
||||||
|
SP<CScreencopyFrame> self;
|
||||||
|
WP<CScreencopyClient> client;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SP<CZwlrScreencopyFrameV1> resource;
|
||||||
|
|
||||||
|
CMonitor* pMonitor = nullptr;
|
||||||
bool overlayCursor = false;
|
bool overlayCursor = false;
|
||||||
bool withDamage = false;
|
bool withDamage = false;
|
||||||
bool lockedSWCursors = false;
|
bool lockedSWCursors = false;
|
||||||
|
|
||||||
bool bufferDMA = false;
|
|
||||||
|
|
||||||
WP<IHLBuffer> buffer;
|
WP<IHLBuffer> buffer;
|
||||||
|
bool bufferDMA = false;
|
||||||
|
uint32_t shmFormat = 0;
|
||||||
|
uint32_t dmabufFormat = 0;
|
||||||
|
int shmStride = 0;
|
||||||
|
CBox box = {};
|
||||||
|
|
||||||
CMonitor* pMonitor = nullptr;
|
void copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer);
|
||||||
PHLWINDOWREF pWindow;
|
bool copyDmabuf();
|
||||||
|
bool copyShm();
|
||||||
|
void share();
|
||||||
|
|
||||||
bool operator==(const SScreencopyFrame& other) const {
|
friend class CScreencopyProtocol;
|
||||||
return resource == other.resource && client == other.client;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CScreencopyProtocolManager {
|
class CScreencopyProtocol : public IWaylandProtocol {
|
||||||
public:
|
public:
|
||||||
CScreencopyProtocolManager();
|
CScreencopyProtocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||||
|
|
||||||
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
virtual void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||||
void removeClient(CScreencopyClient* client, bool force = false);
|
void destroyResource(CScreencopyClient* resource);
|
||||||
void removeFrame(SScreencopyFrame* frame, bool force = false);
|
void destroyResource(CScreencopyFrame* resource);
|
||||||
void displayDestroy();
|
|
||||||
|
|
||||||
void captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, CBox box = {0, 0, 0, 0});
|
|
||||||
|
|
||||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer);
|
|
||||||
|
|
||||||
void onOutputCommit(CMonitor* pMonitor);
|
void onOutputCommit(CMonitor* pMonitor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wl_global* m_pGlobal = nullptr;
|
std::vector<SP<CScreencopyFrame>> m_vFrames;
|
||||||
std::list<SScreencopyFrame> m_lFrames;
|
std::vector<SP<CScreencopyFrame>> m_vFramesAwaitingWrite;
|
||||||
std::list<CScreencopyClient> m_lClients;
|
std::vector<SP<CScreencopyClient>> m_vClients;
|
||||||
|
|
||||||
SP<CEventLoopTimer> m_pSoftwareCursorTimer;
|
SP<CEventLoopTimer> m_pSoftwareCursorTimer;
|
||||||
bool m_bTimerArmed = false;
|
bool m_bTimerArmed = false;
|
||||||
|
|
||||||
wl_listener m_liDisplayDestroy;
|
|
||||||
|
|
||||||
std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
|
|
||||||
|
|
||||||
SP<Aquamarine::IBuffer> m_pLastMonitorBackBuffer;
|
|
||||||
|
|
||||||
void shareAllFrames(CMonitor* pMonitor);
|
void shareAllFrames(CMonitor* pMonitor);
|
||||||
void shareFrame(SScreencopyFrame* frame);
|
void shareFrame(CScreencopyFrame* frame);
|
||||||
void sendFrameDamage(SScreencopyFrame* frame);
|
void sendFrameDamage(CScreencopyFrame* frame);
|
||||||
bool copyFrameDmabuf(SScreencopyFrame* frame);
|
bool copyFrameDmabuf(CScreencopyFrame* frame);
|
||||||
bool copyFrameShm(SScreencopyFrame* frame, timespec* now);
|
bool copyFrameShm(CScreencopyFrame* frame, timespec* now);
|
||||||
|
|
||||||
|
friend class CScreencopyFrame;
|
||||||
friend class CScreencopyClient;
|
friend class CScreencopyClient;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace PROTO {
|
||||||
|
inline UP<CScreencopyProtocol> screencopy;
|
||||||
|
};
|
||||||
|
|
|
@ -24,7 +24,7 @@ CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_,
|
||||||
resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; });
|
resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; });
|
||||||
|
|
||||||
listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) {
|
listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) {
|
||||||
if (!pSurface->current.buffer) {
|
if (!pSurface->current.texture) {
|
||||||
LOGM(ERR, "SessionLock attached a null buffer");
|
LOGM(ERR, "SessionLock attached a null buffer");
|
||||||
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached");
|
resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -73,6 +73,9 @@ bool CKeyboardShortcutsInhibitProtocol::isInhibited() {
|
||||||
if (!g_pCompositor->m_pLastFocus)
|
if (!g_pCompositor->m_pLastFocus)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock()); PWINDOW && PWINDOW->m_sWindowData.noShortcutsInhibit.valueOrDefault())
|
||||||
|
return false;
|
||||||
|
|
||||||
for (auto& in : m_vInhibitors) {
|
for (auto& in : m_vInhibitors) {
|
||||||
if (in->surface() != g_pCompositor->m_pLastFocus)
|
if (in->surface() != g_pCompositor->m_pLastFocus)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -3,221 +3,125 @@
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
#include "core/Compositor.hpp"
|
#include "core/Compositor.hpp"
|
||||||
|
|
||||||
#define TEXT_INPUT_VERSION 1
|
#define LOGM PROTO::textInputV1->protoLog
|
||||||
|
|
||||||
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
CTextInputV1::~CTextInputV1() {
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->bindManager(client, data, version, id);
|
events.destroy.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
|
CTextInputV1::CTextInputV1(SP<CZwpTextInputV1> resource_) : resource(resource_) {
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->displayDestroy();
|
if (!good())
|
||||||
}
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::displayDestroy() {
|
|
||||||
wl_global_destroy(m_pGlobal);
|
|
||||||
}
|
|
||||||
|
|
||||||
CTextInputV1ProtocolManager::CTextInputV1ProtocolManager() {
|
|
||||||
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &zwp_text_input_manager_v1_interface, TEXT_INPUT_VERSION, this, bindManagerInt);
|
|
||||||
|
|
||||||
if (!m_pGlobal) {
|
|
||||||
Debug::log(ERR, "TextInputV1Manager could not start!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
|
||||||
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
|
||||||
|
|
||||||
Debug::log(LOG, "TextInputV1Manager started successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void createTI(wl_client* client, wl_resource* resource, uint32_t id) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->createTI(client, resource, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct zwp_text_input_manager_v1_interface textInputManagerImpl = {
|
|
||||||
.create_text_input = createTI,
|
|
||||||
};
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
|
||||||
const auto RESOURCE = wl_resource_create(client, &zwp_text_input_manager_v1_interface, version, id);
|
|
||||||
wl_resource_set_implementation(RESOURCE, &textInputManagerImpl, this, nullptr);
|
|
||||||
|
|
||||||
Debug::log(LOG, "TextInputV1Manager bound successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
static void handleActivate(wl_client* client, wl_resource* resource, wl_resource* seat, wl_resource* surface) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleActivate(client, resource, seat, surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleDeactivate(client, resource, seat);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleShowInputPanel(wl_client* client, wl_resource* resource) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleShowInputPanel(client, resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleHideInputPanel(wl_client* client, wl_resource* resource) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleHideInputPanel(client, resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleReset(wl_client* client, wl_resource* resource) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleReset(client, resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleSetSurroundingText(wl_client* client, wl_resource* resource, const char* text, uint32_t cursor, uint32_t anchor) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetSurroundingText(client, resource, text, cursor, anchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleSetContentType(wl_client* client, wl_resource* resource, uint32_t hint, uint32_t purpose) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetContentType(client, resource, hint, purpose);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetCursorRectangle(client, resource, x, y, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetPreferredLanguage(client, resource, language);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCommitState(wl_client* client, wl_resource* resource, uint32_t serial) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleCommitState(client, resource, serial);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index) {
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->handleInvokeAction(client, resource, button, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct zwp_text_input_v1_interface textInputImpl = {
|
|
||||||
.activate = handleActivate,
|
|
||||||
.deactivate = handleDeactivate,
|
|
||||||
.show_input_panel = handleShowInputPanel,
|
|
||||||
.hide_input_panel = handleHideInputPanel,
|
|
||||||
.reset = handleReset,
|
|
||||||
.set_surrounding_text = handleSetSurroundingText,
|
|
||||||
.set_content_type = handleSetContentType,
|
|
||||||
.set_cursor_rectangle = handleSetCursorRectangle,
|
|
||||||
.set_preferred_language = handleSetPreferredLanguage,
|
|
||||||
.commit_state = handleCommitState,
|
|
||||||
.invoke_action = handleInvokeAction,
|
|
||||||
};
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::removeTI(STextInputV1* pTI) {
|
|
||||||
const auto TI = std::find_if(m_pClients.begin(), m_pClients.end(), [&](const auto& other) { return other->resourceCaller == pTI->resourceCaller; });
|
|
||||||
if (TI == m_pClients.end())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// if ((*TI)->resourceImpl)
|
resource->setOnDestroy([this](CZwpTextInputV1* pMgr) { PROTO::textInputV1->destroyResource(this); });
|
||||||
// wl_resource_destroy((*TI)->resourceImpl);
|
|
||||||
|
|
||||||
std::erase_if(m_pClients, [&](const auto& other) { return other.get() == pTI; });
|
resource->setActivate([this](CZwpTextInputV1* pMgr, wl_resource* seat, wl_resource* surface) {
|
||||||
}
|
|
||||||
|
|
||||||
STextInputV1* tiFromResource(wl_resource* resource) {
|
|
||||||
ASSERT(wl_resource_instance_of(resource, &zwp_text_input_v1_interface, &textInputImpl));
|
|
||||||
return (STextInputV1*)wl_resource_get_user_data(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroyTI(wl_resource* resource) {
|
|
||||||
const auto TI = tiFromResource(resource);
|
|
||||||
|
|
||||||
if (!TI)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (TI->resourceImpl) {
|
|
||||||
wl_resource_set_user_data(resource, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
TI->pTextInput->tiV1Destroyed();
|
|
||||||
|
|
||||||
g_pProtocolManager->m_pTextInputV1ProtocolManager->removeTI(TI);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::createTI(wl_client* client, wl_resource* resource, uint32_t id) {
|
|
||||||
const auto PTI = m_pClients.emplace_back(std::make_unique<STextInputV1>()).get();
|
|
||||||
Debug::log(LOG, "New TI V1 at {:x}", (uintptr_t)PTI);
|
|
||||||
|
|
||||||
PTI->client = client;
|
|
||||||
PTI->resourceCaller = resource;
|
|
||||||
PTI->resourceImpl = wl_resource_create(client, &zwp_text_input_v1_interface, TEXT_INPUT_VERSION, id);
|
|
||||||
|
|
||||||
if (!PTI->resourceImpl) {
|
|
||||||
Debug::log(ERR, "Could not alloc wl_resource for TIV1");
|
|
||||||
removeTI(PTI);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_resource_set_implementation(PTI->resourceImpl, &textInputImpl, PTI, &destroyTI);
|
|
||||||
wl_resource_set_user_data(PTI->resourceImpl, PTI);
|
|
||||||
|
|
||||||
wl_signal_init(&PTI->sEnable);
|
|
||||||
wl_signal_init(&PTI->sDisable);
|
|
||||||
wl_signal_init(&PTI->sDestroy);
|
|
||||||
wl_signal_init(&PTI->sCommit);
|
|
||||||
|
|
||||||
g_pInputManager->m_sIMERelay.onNewTextInput(PTI);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleActivate(wl_client* client, wl_resource* resource, wl_resource* seat, wl_resource* surface) {
|
|
||||||
const auto PTI = tiFromResource(resource);
|
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
Debug::log(WARN, "Text-input-v1 PTI{:x}: No surface to activate text input on!", (uintptr_t)PTI);
|
LOGM(WARN, "Text-input-v1 PTI{:x}: No surface to activate text input on!", (uintptr_t)this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PTI->active = true;
|
|
||||||
PTI->pTextInput->onEnabled(CWLSurfaceResource::fromResource(surface));
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat) {
|
active = true;
|
||||||
const auto PTI = tiFromResource(resource);
|
events.enable.emit(CWLSurfaceResource::fromResource(surface));
|
||||||
PTI->active = false;
|
});
|
||||||
PTI->pTextInput->onDisabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleShowInputPanel(wl_client* client, wl_resource* resource) {
|
resource->setDeactivate([this](CZwpTextInputV1* pMgr, wl_resource* seat) {
|
||||||
;
|
active = false;
|
||||||
}
|
events.disable.emit();
|
||||||
|
});
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleHideInputPanel(wl_client* client, wl_resource* resource) {
|
resource->setReset([this](CZwpTextInputV1* pMgr) {
|
||||||
;
|
pendingSurrounding.isPending = false;
|
||||||
}
|
pendingContentType.isPending = false;
|
||||||
|
});
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleReset(wl_client* client, wl_resource* resource) {
|
resource->setSetSurroundingText(
|
||||||
const auto PTI = tiFromResource(resource);
|
[this](CZwpTextInputV1* pMgr, const char* text, uint32_t cursor, uint32_t anchor) { pendingSurrounding = {true, std::string(text), cursor, anchor}; });
|
||||||
PTI->pendingSurrounding.isPending = false;
|
|
||||||
PTI->pendingContentType.isPending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleSetSurroundingText(wl_client* client, wl_resource* resource, const char* text, uint32_t cursor, uint32_t anchor) {
|
resource->setSetContentType([this](CZwpTextInputV1* pMgr, uint32_t hint, uint32_t purpose) {
|
||||||
const auto PTI = tiFromResource(resource);
|
pendingContentType = {true, hint == (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_DEFAULT ? (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE : hint,
|
||||||
PTI->pendingSurrounding = {true, std::string(text), cursor, anchor};
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleSetContentType(wl_client* client, wl_resource* resource, uint32_t hint, uint32_t purpose) {
|
|
||||||
const auto PTI = tiFromResource(resource);
|
|
||||||
PTI->pendingContentType = {true, hint == (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_DEFAULT ? (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE : hint,
|
|
||||||
purpose > (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PASSWORD ? hint + 1 : hint};
|
purpose > (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PASSWORD ? hint + 1 : hint};
|
||||||
|
});
|
||||||
|
|
||||||
|
resource->setSetCursorRectangle([this](CZwpTextInputV1* pMgr, int32_t x, int32_t y, int32_t width, int32_t height) { cursorRectangle = CBox{x, y, width, height}; });
|
||||||
|
|
||||||
|
resource->setCommitState([this](CZwpTextInputV1* pMgr, uint32_t serial_) {
|
||||||
|
serial = serial_;
|
||||||
|
events.onCommit.emit();
|
||||||
|
});
|
||||||
|
|
||||||
|
// nothing
|
||||||
|
resource->setShowInputPanel([this](CZwpTextInputV1* pMgr) {});
|
||||||
|
resource->setHideInputPanel([this](CZwpTextInputV1* pMgr) {});
|
||||||
|
resource->setSetPreferredLanguage([this](CZwpTextInputV1* pMgr, const char* language) {});
|
||||||
|
resource->setInvokeAction([this](CZwpTextInputV1* pMgr, uint32_t button, uint32_t index) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height) {
|
bool CTextInputV1::good() {
|
||||||
const auto PTI = tiFromResource(resource);
|
return resource->resource();
|
||||||
PTI->cursorRectangle = CBox{x, y, width, height};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language) {
|
wl_client* CTextInputV1::client() {
|
||||||
|
return resource->client();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1::enter(SP<CWLSurfaceResource> surface) {
|
||||||
|
resource->sendEnter(surface->getResource()->resource());
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1::leave() {
|
||||||
|
resource->sendLeave();
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1::preeditCursor(int32_t index) {
|
||||||
|
resource->sendPreeditCursor(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1::preeditStyling(uint32_t index, uint32_t length, zwpTextInputV1PreeditStyle style) {
|
||||||
|
resource->sendPreeditStyling(index, length, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1::preeditString(uint32_t serial, const char* text, const char* commit) {
|
||||||
|
resource->sendPreeditString(serial, text, commit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1::commitString(uint32_t serial, const char* text) {
|
||||||
|
resource->sendCommitString(serial, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1::deleteSurroundingText(int32_t index, uint32_t length) {
|
||||||
|
resource->sendDeleteSurroundingText(index, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
CTextInputV1Protocol::CTextInputV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleCommitState(wl_client* client, wl_resource* resource, uint32_t serial) {
|
void CTextInputV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||||
const auto PTI = tiFromResource(resource);
|
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CZwpTextInputManagerV1>(client, ver, id));
|
||||||
PTI->serial = serial;
|
|
||||||
PTI->pTextInput->onCommit();
|
RESOURCE->setOnDestroy([this](CZwpTextInputManagerV1* pMgr) { PROTO::textInputV1->destroyResource(pMgr); });
|
||||||
|
RESOURCE->setCreateTextInput([this](CZwpTextInputManagerV1* pMgr, uint32_t id) {
|
||||||
|
const auto PTI = m_vClients.emplace_back(makeShared<CTextInputV1>(makeShared<CZwpTextInputV1>(pMgr->client(), pMgr->version(), id)));
|
||||||
|
LOGM(LOG, "New TI V1 at {:x}", (uintptr_t)PTI.get());
|
||||||
|
|
||||||
|
if (!PTI->good()) {
|
||||||
|
LOGM(ERR, "Could not alloc wl_resource for TIV1");
|
||||||
|
pMgr->noMemory();
|
||||||
|
PROTO::textInputV1->destroyResource(PTI.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.newTextInput.emit(WP<CTextInputV1>(PTI));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTextInputV1ProtocolManager::handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index) {
|
void CTextInputV1Protocol::destroyResource(CTextInputV1* client) {
|
||||||
;
|
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextInputV1Protocol::destroyResource(CZwpTextInputManagerV1* client) {
|
||||||
|
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == client; });
|
||||||
}
|
}
|
|
@ -1,29 +1,45 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "text-input-unstable-v1-protocol.h"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
#include "text-input-unstable-v1.hpp"
|
||||||
|
#include "WaylandProtocol.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class CTextInput;
|
class CTextInput;
|
||||||
|
|
||||||
struct STextInputV1 {
|
class CTextInputV1 {
|
||||||
wl_client* client = nullptr;
|
public:
|
||||||
wl_resource* resourceCaller = nullptr;
|
CTextInputV1(SP<CZwpTextInputV1> resource);
|
||||||
|
~CTextInputV1();
|
||||||
|
|
||||||
wl_resource* resourceImpl = nullptr;
|
void enter(SP<CWLSurfaceResource> surface);
|
||||||
|
void leave();
|
||||||
|
|
||||||
CTextInput* pTextInput = nullptr;
|
void preeditCursor(int32_t index);
|
||||||
|
void preeditStyling(uint32_t index, uint32_t length, zwpTextInputV1PreeditStyle style);
|
||||||
|
void preeditString(uint32_t serial, const char* text, const char* commit);
|
||||||
|
void commitString(uint32_t serial, const char* text);
|
||||||
|
void deleteSurroundingText(int32_t index, uint32_t length);
|
||||||
|
|
||||||
wl_signal sEnable;
|
bool good();
|
||||||
wl_signal sDisable;
|
wl_client* client();
|
||||||
wl_signal sCommit;
|
|
||||||
wl_signal sDestroy;
|
private:
|
||||||
|
SP<CZwpTextInputV1> resource;
|
||||||
|
WP<CTextInputV1> self;
|
||||||
|
|
||||||
uint32_t serial = 0;
|
uint32_t serial = 0;
|
||||||
|
|
||||||
bool active = false;
|
bool active = false;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
CSignal onCommit;
|
||||||
|
CSignal enable;
|
||||||
|
CSignal disable;
|
||||||
|
CSignal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
struct SPendingSurr {
|
struct SPendingSurr {
|
||||||
bool isPending = false;
|
bool isPending = false;
|
||||||
std::string text = "";
|
std::string text = "";
|
||||||
|
@ -39,37 +55,29 @@ struct STextInputV1 {
|
||||||
|
|
||||||
CBox cursorRectangle = {0, 0, 0, 0};
|
CBox cursorRectangle = {0, 0, 0, 0};
|
||||||
|
|
||||||
bool operator==(const STextInputV1& other) {
|
friend class CTextInput;
|
||||||
return other.client == client && other.resourceCaller == resourceCaller && other.resourceImpl == resourceImpl;
|
friend class CTextInputV1Protocol;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CTextInputV1ProtocolManager {
|
class CTextInputV1Protocol : IWaylandProtocol {
|
||||||
public:
|
public:
|
||||||
CTextInputV1ProtocolManager();
|
CTextInputV1Protocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||||
|
|
||||||
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
virtual void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||||
void createTI(wl_client* client, wl_resource* resource, uint32_t id);
|
void destroyResource(CTextInputV1* resource);
|
||||||
void removeTI(STextInputV1* pTI);
|
void destroyResource(CZwpTextInputManagerV1* client);
|
||||||
|
|
||||||
void displayDestroy();
|
struct {
|
||||||
|
CSignal newTextInput; // WP<CTextInputV3>
|
||||||
// handlers for tiv1
|
} events;
|
||||||
void handleActivate(wl_client* client, wl_resource* resource, wl_resource* seat, wl_resource* surface);
|
|
||||||
void handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat);
|
|
||||||
void handleShowInputPanel(wl_client* client, wl_resource* resource);
|
|
||||||
void handleHideInputPanel(wl_client* client, wl_resource* resource);
|
|
||||||
void handleReset(wl_client* client, wl_resource* resource);
|
|
||||||
void handleSetSurroundingText(wl_client* client, wl_resource* resource, const char* text, uint32_t cursor, uint32_t anchor);
|
|
||||||
void handleSetContentType(wl_client* client, wl_resource* resource, uint32_t hint, uint32_t purpose);
|
|
||||||
void handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height);
|
|
||||||
void handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language);
|
|
||||||
void handleCommitState(wl_client* client, wl_resource* resource, uint32_t serial);
|
|
||||||
void handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wl_global* m_pGlobal = nullptr;
|
std::vector<SP<CZwpTextInputManagerV1>> m_vManagers;
|
||||||
wl_listener m_liDisplayDestroy;
|
std::vector<SP<CTextInputV1>> m_vClients;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<STextInputV1>> m_pClients;
|
friend class CTextInputV1;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace PROTO {
|
||||||
|
inline UP<CTextInputV1Protocol> textInputV1;
|
||||||
};
|
};
|
|
@ -8,356 +8,240 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#define TOPLEVEL_EXPORT_VERSION 2
|
#define LOGM PROTO::toplevelExport->protoLog
|
||||||
|
|
||||||
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
CToplevelExportClient::CToplevelExportClient(SP<CHyprlandToplevelExportManagerV1> resource_) : resource(resource_) {
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->bindManager(client, data, version, id);
|
if (!good())
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
|
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->displayDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::displayDestroy() {
|
|
||||||
wl_global_destroy(m_pGlobal);
|
|
||||||
}
|
|
||||||
|
|
||||||
CToplevelExportProtocolManager::CToplevelExportProtocolManager() {
|
|
||||||
|
|
||||||
#ifndef GLES32
|
|
||||||
Debug::log(WARN, "Toplevel sharing is not supported on LEGACY_RENDERER!");
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_toplevel_export_manager_v1_interface, TOPLEVEL_EXPORT_VERSION, this, bindManagerInt);
|
|
||||||
|
|
||||||
if (!m_pGlobal) {
|
|
||||||
Debug::log(ERR, "ToplevelExportManager could not start! Sharing windows will not work!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
|
||||||
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
|
||||||
|
|
||||||
Debug::log(LOG, "ToplevelExportManager started successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
|
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromHandle(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCaptureToplevelWithWlr(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* handle) {
|
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, PROTO::foreignToplevelWlr->windowFromHandleResource(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDestroy(wl_client* client, wl_resource* resource) {
|
|
||||||
wl_resource_destroy(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
|
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->copyFrame(client, resource, buffer, ignore_damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleDestroyFrame(wl_client* client, wl_resource* resource) {
|
|
||||||
wl_resource_destroy(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct hyprland_toplevel_export_manager_v1_interface toplevelExportManagerImpl = {
|
|
||||||
.capture_toplevel = handleCaptureToplevel,
|
|
||||||
.destroy = handleDestroy,
|
|
||||||
.capture_toplevel_with_wlr_toplevel_handle = handleCaptureToplevelWithWlr,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {.copy = handleCopyFrame, .destroy = handleDestroyFrame};
|
|
||||||
|
|
||||||
//
|
|
||||||
static CScreencopyClient* clientFromResource(wl_resource* resource) {
|
|
||||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl));
|
|
||||||
return (CScreencopyClient*)wl_resource_get_user_data(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
static SScreencopyFrame* frameFromResource(wl_resource* resource) {
|
|
||||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl));
|
|
||||||
return (SScreencopyFrame*)wl_resource_get_user_data(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::removeClient(CScreencopyClient* client, bool force) {
|
|
||||||
if (!force) {
|
|
||||||
if (!client || client->ref <= 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (--client->ref != 0)
|
resource->setOnDestroy([this](CHyprlandToplevelExportManagerV1* pMgr) { PROTO::toplevelExport->destroyResource(this); });
|
||||||
return;
|
resource->setDestroy([this](CHyprlandToplevelExportManagerV1* pMgr) { PROTO::toplevelExport->destroyResource(this); });
|
||||||
}
|
resource->setCaptureToplevel([this](CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, uint32_t handle) {
|
||||||
|
this->captureToplevel(pMgr, frame, overlayCursor, g_pCompositor->getWindowFromHandle(handle));
|
||||||
|
});
|
||||||
|
resource->setCaptureToplevelWithWlrToplevelHandle([this](CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, wl_resource* handle) {
|
||||||
|
this->captureToplevel(pMgr, frame, overlayCursor, PROTO::foreignToplevelWlr->windowFromHandleResource(handle));
|
||||||
|
});
|
||||||
|
|
||||||
m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits???
|
lastMeasure.reset();
|
||||||
|
lastFrame.reset();
|
||||||
|
tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, SCallbackInfo& info, std::any data) { onTick(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleManagerResourceDestroy(wl_resource* resource) {
|
void CToplevelExportClient::captureToplevel(CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor_, PHLWINDOW handle) {
|
||||||
const auto PCLIENT = clientFromResource(resource);
|
|
||||||
|
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->removeClient(PCLIENT, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
|
||||||
const auto PCLIENT = &m_lClients.emplace_back();
|
|
||||||
|
|
||||||
PCLIENT->clientOwner = CLIENT_TOPLEVEL_EXPORT;
|
|
||||||
PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface, version, id);
|
|
||||||
|
|
||||||
if (!PCLIENT->resource) {
|
|
||||||
Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)");
|
|
||||||
m_lClients.remove(*PCLIENT);
|
|
||||||
wl_client_post_no_memory(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PCLIENT->ref = 1;
|
|
||||||
|
|
||||||
wl_resource_set_implementation(PCLIENT->resource, &toplevelExportManagerImpl, PCLIENT, handleManagerResourceDestroy);
|
|
||||||
|
|
||||||
Debug::log(LOG, "ToplevelExportManager bound successfully!");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handleFrameResourceDestroy(wl_resource* resource) {
|
|
||||||
const auto PFRAME = frameFromResource(resource);
|
|
||||||
|
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool force) {
|
|
||||||
if (!frame)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; });
|
|
||||||
|
|
||||||
wl_resource_set_user_data(frame->resource, nullptr);
|
|
||||||
if (frame->buffer && frame->buffer->locked() > 0)
|
|
||||||
frame->buffer->unlock();
|
|
||||||
removeClient(frame->client, force);
|
|
||||||
m_lFrames.remove(*frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, PHLWINDOW pWindow) {
|
|
||||||
const auto PCLIENT = clientFromResource(resource);
|
|
||||||
|
|
||||||
// create a frame
|
// create a frame
|
||||||
const auto PFRAME = &m_lFrames.emplace_back();
|
const auto FRAME = PROTO::toplevelExport->m_vFrames.emplace_back(
|
||||||
PFRAME->overlayCursor = !!overlay_cursor;
|
makeShared<CToplevelExportFrame>(makeShared<CHyprlandToplevelExportFrameV1>(resource->client(), resource->version(), frame), overlayCursor_, handle));
|
||||||
PFRAME->resource = wl_resource_create(client, &hyprland_toplevel_export_frame_v1_interface, wl_resource_get_version(resource), frame);
|
|
||||||
PFRAME->pWindow = pWindow;
|
if (!FRAME->good()) {
|
||||||
|
LOGM(ERR, "Couldn't alloc frame for sharing! (no memory)");
|
||||||
|
resource->noMemory();
|
||||||
|
PROTO::toplevelExport->destroyResource(FRAME.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRAME->self = FRAME;
|
||||||
|
FRAME->client = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CToplevelExportClient::onTick() {
|
||||||
|
if (lastMeasure.getMillis() < 500)
|
||||||
|
return;
|
||||||
|
|
||||||
|
framesInLastHalfSecond = frameCounter;
|
||||||
|
frameCounter = 0;
|
||||||
|
lastMeasure.reset();
|
||||||
|
|
||||||
|
const auto LASTFRAMEDELTA = lastFrame.getMillis() / 1000.0;
|
||||||
|
const bool FRAMEAWAITING = std::ranges::any_of(PROTO::toplevelExport->m_vFrames, [&](const auto& frame) { return frame->client.get() == this; });
|
||||||
|
|
||||||
|
if (framesInLastHalfSecond > 3 && !sentScreencast) {
|
||||||
|
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)});
|
||||||
|
sentScreencast = true;
|
||||||
|
} else if (framesInLastHalfSecond < 4 && sentScreencast && LASTFRAMEDELTA > 1.0 && !FRAMEAWAITING) {
|
||||||
|
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)});
|
||||||
|
sentScreencast = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CToplevelExportClient::good() {
|
||||||
|
return resource->resource();
|
||||||
|
}
|
||||||
|
|
||||||
|
CToplevelExportFrame::~CToplevelExportFrame() {
|
||||||
|
if (buffer && buffer->locked())
|
||||||
|
buffer->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
CToplevelExportFrame::CToplevelExportFrame(SP<CHyprlandToplevelExportFrameV1> resource_, int32_t overlayCursor_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) {
|
||||||
|
if (!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
overlayCursor = !!overlayCursor_;
|
||||||
|
|
||||||
if (!pWindow) {
|
if (!pWindow) {
|
||||||
Debug::log(ERR, "Client requested sharing of window handle {:x} which does not exist!", pWindow);
|
LOGM(ERR, "Client requested sharing of window handle {:x} which does not exist!", pWindow);
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pWindow->m_bIsMapped || pWindow->isHidden()) {
|
if (!pWindow->m_bIsMapped || pWindow->isHidden()) {
|
||||||
Debug::log(ERR, "Client requested sharing of window handle {:x} which is not shareable!", pWindow);
|
LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable!", pWindow);
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PFRAME->resource) {
|
resource->setOnDestroy([this](CHyprlandToplevelExportFrameV1* pFrame) { PROTO::toplevelExport->destroyResource(this); });
|
||||||
Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)");
|
resource->setDestroy([this](CHyprlandToplevelExportFrameV1* pFrame) { PROTO::toplevelExport->destroyResource(this); });
|
||||||
m_lFrames.remove(*PFRAME);
|
resource->setCopy([this](CHyprlandToplevelExportFrameV1* pFrame, wl_resource* res, int32_t ignoreDamage) { this->copy(pFrame, res, ignoreDamage); });
|
||||||
wl_client_post_no_memory(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wl_resource_set_implementation(PFRAME->resource, &toplevelFrameImpl, PFRAME, handleFrameResourceDestroy);
|
|
||||||
|
|
||||||
PFRAME->client = PCLIENT;
|
|
||||||
PCLIENT->ref++;
|
|
||||||
|
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||||
|
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
g_pHyprRenderer->makeEGLCurrent();
|
||||||
|
|
||||||
PFRAME->shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PMONITOR);
|
shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PMONITOR);
|
||||||
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
|
if (shmFormat == DRM_FORMAT_INVALID) {
|
||||||
Debug::log(ERR, "No format supported by renderer in capture toplevel");
|
LOGM(ERR, "No format supported by renderer in capture toplevel");
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat);
|
const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(shmFormat);
|
||||||
if (!PSHMINFO) {
|
if (!PSHMINFO) {
|
||||||
Debug::log(ERR, "No pixel format supported by renderer in capture toplevel");
|
LOGM(ERR, "No pixel format supported by renderer in capture toplevel");
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PFRAME->dmabufFormat = PMONITOR->output->state->state().drmFormat;
|
dmabufFormat = PMONITOR->output->state->state().drmFormat;
|
||||||
|
|
||||||
PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)};
|
box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)};
|
||||||
|
|
||||||
PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round();
|
box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round();
|
||||||
|
|
||||||
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
|
shmStride = FormatUtils::minStride(PSHMINFO, box.w);
|
||||||
|
|
||||||
hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
|
resource->sendBuffer(FormatUtils::drmToShm(shmFormat), box.width, box.height, shmStride);
|
||||||
|
|
||||||
if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) {
|
if (dmabufFormat != DRM_FORMAT_INVALID) {
|
||||||
hyprland_toplevel_export_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height);
|
resource->sendLinuxDmabuf(dmabufFormat, box.width, box.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
hyprland_toplevel_export_frame_v1_send_buffer_done(PFRAME->resource);
|
resource->sendBufferDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
|
void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resource* buffer_, int32_t ignoreDamage) {
|
||||||
const auto PFRAME = frameFromResource(resource);
|
if (!good()) {
|
||||||
|
LOGM(ERR, "No frame in copyFrame??");
|
||||||
if (!PFRAME) {
|
|
||||||
Debug::log(ERR, "No frame in copyFrame??");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto PWINDOW = PFRAME->pWindow.lock();
|
if (!validMapped(pWindow)) {
|
||||||
|
LOGM(ERR, "Client requested sharing of window handle {:x} which is gone!", pWindow);
|
||||||
if (!validMapped(PWINDOW)) {
|
resource->sendFailed();
|
||||||
Debug::log(ERR, "Client requested sharing of window handle {:x} which is gone!", (uintptr_t)PWINDOW.get());
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
|
||||||
removeFrame(PFRAME);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) {
|
if (!pWindow->m_bIsMapped || pWindow->isHidden()) {
|
||||||
Debug::log(ERR, "Client requested sharing of window handle {:x} which is not shareable (2)!", PWINDOW);
|
LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable (2)!", pWindow);
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
|
resource->sendFailed();
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto PBUFFER = CWLBufferResource::fromResource(buffer);
|
const auto PBUFFER = CWLBufferResource::fromResource(buffer_);
|
||||||
if (!PBUFFER) {
|
if (!PBUFFER) {
|
||||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PBUFFER->buffer->lock();
|
PBUFFER->buffer->lock();
|
||||||
|
|
||||||
if (PBUFFER->buffer->size != PFRAME->box.size()) {
|
if (PBUFFER->buffer->size != box.size()) {
|
||||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PFRAME->buffer) {
|
if (buffer) {
|
||||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) {
|
if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) {
|
||||||
PFRAME->bufferDMA = true;
|
bufferDMA = true;
|
||||||
|
|
||||||
if (attrs.format != PFRAME->dmabufFormat) {
|
if (attrs.format != dmabufFormat) {
|
||||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) {
|
} else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) {
|
||||||
if (attrs.format != PFRAME->shmFormat) {
|
if (attrs.format != shmFormat) {
|
||||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
} else if ((int)attrs.stride != PFRAME->shmStride) {
|
} else if ((int)attrs.stride != shmStride) {
|
||||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
|
resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
|
||||||
removeFrame(PFRAME);
|
PROTO::toplevelExport->destroyResource(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PFRAME->buffer = PBUFFER->buffer;
|
buffer = PBUFFER->buffer;
|
||||||
|
|
||||||
m_vFramesAwaitingWrite.emplace_back(PFRAME);
|
PROTO::toplevelExport->m_vFramesAwaitingWrite.emplace_back(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor) {
|
void CToplevelExportFrame::share() {
|
||||||
if (m_vFramesAwaitingWrite.empty())
|
if (!buffer || !validMapped(pWindow))
|
||||||
return; // nothing to share
|
|
||||||
|
|
||||||
std::vector<SScreencopyFrame*> framesToRemove;
|
|
||||||
|
|
||||||
// share frame if correct output
|
|
||||||
for (auto& f : m_vFramesAwaitingWrite) {
|
|
||||||
const auto PWINDOW = f->pWindow.lock();
|
|
||||||
|
|
||||||
if (!validMapped(PWINDOW)) {
|
|
||||||
framesToRemove.push_back(f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y};
|
|
||||||
|
|
||||||
if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
shareFrame(f);
|
|
||||||
|
|
||||||
f->client->lastFrame.reset();
|
|
||||||
++f->client->frameCounter;
|
|
||||||
|
|
||||||
framesToRemove.push_back(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& f : framesToRemove) {
|
|
||||||
removeFrame(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) {
|
|
||||||
if (!frame->buffer || !validMapped(frame->pWindow))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
timespec now;
|
timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
uint32_t flags = 0;
|
if (bufferDMA) {
|
||||||
if (frame->bufferDMA) {
|
if (!copyDmabuf(&now)) {
|
||||||
if (!copyFrameDmabuf(frame, &now)) {
|
resource->sendFailed();
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!copyFrameShm(frame, &now)) {
|
if (!copyShm(&now)) {
|
||||||
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
|
resource->sendFailed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hyprland_toplevel_export_frame_v1_send_flags(frame->resource, flags);
|
resource->sendFlags((hyprlandToplevelExportFrameV1Flags)0);
|
||||||
sendDamage(frame);
|
|
||||||
|
if (!ignoreDamage) {
|
||||||
|
resource->sendDamage(0, 0, box.width, box.height);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
resource->sendReady(tvSecHi, tvSecLo, now.tv_nsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::sendDamage(SScreencopyFrame* frame) {
|
bool CToplevelExportFrame::copyShm(timespec* now) {
|
||||||
// TODO: send proper dmg
|
auto shm = buffer->shm();
|
||||||
hyprland_toplevel_export_frame_v1_send_damage(frame->resource, 0, 0, frame->box.width, frame->box.height);
|
auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); // no need for end, cuz it's shm
|
||||||
}
|
|
||||||
|
|
||||||
bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
|
|
||||||
auto shm = frame->buffer->shm();
|
|
||||||
auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm
|
|
||||||
|
|
||||||
// render the client
|
// render the client
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||||
CRegion fakeDamage{0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10};
|
CRegion fakeDamage{0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10};
|
||||||
|
|
||||||
g_pHyprRenderer->makeEGLCurrent();
|
g_pHyprRenderer->makeEGLCurrent();
|
||||||
|
@ -365,7 +249,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
||||||
CFramebuffer outFB;
|
CFramebuffer outFB;
|
||||||
outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat);
|
outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat);
|
||||||
|
|
||||||
if (frame->overlayCursor) {
|
if (overlayCursor) {
|
||||||
g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock());
|
g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock());
|
||||||
g_pPointerManager->damageCursor(PMONITOR->self.lock());
|
g_pPointerManager->damageCursor(PMONITOR->self.lock());
|
||||||
}
|
}
|
||||||
|
@ -376,12 +260,12 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
||||||
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
|
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
|
||||||
|
|
||||||
// render client at 0,0
|
// render client at 0,0
|
||||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow.lock()); // block the feedback to avoid spamming the surface if it's visible
|
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible
|
||||||
g_pHyprRenderer->renderWindow(frame->pWindow.lock(), PMONITOR, now, false, RENDER_PASS_ALL, true, true);
|
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
|
||||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
|
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
|
||||||
|
|
||||||
if (frame->overlayCursor)
|
if (overlayCursor)
|
||||||
g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value());
|
g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value());
|
||||||
|
|
||||||
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
|
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
|
||||||
if (!PFORMAT) {
|
if (!PFORMAT) {
|
||||||
|
@ -403,9 +287,9 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA;
|
auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA;
|
||||||
glReadPixels(0, 0, frame->box.width, frame->box.height, glFormat, PFORMAT->glType, pixelData);
|
glReadPixels(0, 0, box.width, box.height, glFormat, PFORMAT->glType, pixelData);
|
||||||
|
|
||||||
if (frame->overlayCursor) {
|
if (overlayCursor) {
|
||||||
g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock());
|
g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock());
|
||||||
g_pPointerManager->damageCursor(PMONITOR->self.lock());
|
g_pPointerManager->damageCursor(PMONITOR->self.lock());
|
||||||
}
|
}
|
||||||
|
@ -413,31 +297,112 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, timespec* now) {
|
bool CToplevelExportFrame::copyDmabuf(timespec* now) {
|
||||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||||
|
|
||||||
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
|
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
|
||||||
|
|
||||||
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock()))
|
if (overlayCursor) {
|
||||||
|
g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock());
|
||||||
|
g_pPointerManager->damageCursor(PMONITOR->self.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
|
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
|
||||||
|
|
||||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow.lock()); // block the feedback to avoid spamming the surface if it's visible
|
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible
|
||||||
g_pHyprRenderer->renderWindow(frame->pWindow.lock(), PMONITOR, now, false, RENDER_PASS_ALL, true, true);
|
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
|
||||||
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
|
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
|
||||||
|
|
||||||
if (frame->overlayCursor)
|
if (overlayCursor)
|
||||||
g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value());
|
g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value());
|
||||||
|
|
||||||
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
|
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
|
||||||
g_pHyprRenderer->endRender();
|
g_pHyprRenderer->endRender();
|
||||||
|
|
||||||
|
if (overlayCursor) {
|
||||||
|
g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock());
|
||||||
|
g_pPointerManager->damageCursor(PMONITOR->self.lock());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::onWindowUnmap(PHLWINDOW pWindow) {
|
bool CToplevelExportFrame::good() {
|
||||||
for (auto& f : m_lFrames) {
|
return resource->resource();
|
||||||
if (f.pWindow.lock() == pWindow)
|
}
|
||||||
f.pWindow.reset();
|
|
||||||
|
CToplevelExportProtocol::CToplevelExportProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CToplevelExportProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||||
|
const auto CLIENT = m_vClients.emplace_back(makeShared<CToplevelExportClient>(makeShared<CHyprlandToplevelExportManagerV1>(client, ver, id)));
|
||||||
|
|
||||||
|
if (!CLIENT->good()) {
|
||||||
|
LOGM(LOG, "Failed to bind client! (out of memory)");
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
m_vClients.pop_back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIENT->self = CLIENT;
|
||||||
|
|
||||||
|
LOGM(LOG, "Bound client successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CToplevelExportProtocol::destroyResource(CToplevelExportClient* client) {
|
||||||
|
std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; });
|
||||||
|
std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; });
|
||||||
|
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) {
|
||||||
|
std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; });
|
||||||
|
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) {
|
||||||
|
if (m_vFramesAwaitingWrite.empty())
|
||||||
|
return; // nothing to share
|
||||||
|
|
||||||
|
std::vector<WP<CToplevelExportFrame>> framesToRemove;
|
||||||
|
|
||||||
|
// share frame if correct output
|
||||||
|
for (auto& f : m_vFramesAwaitingWrite) {
|
||||||
|
if (!f->pWindow || !validMapped(f->pWindow)) {
|
||||||
|
framesToRemove.push_back(f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto PWINDOW = f->pWindow;
|
||||||
|
|
||||||
|
if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y};
|
||||||
|
|
||||||
|
if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
f->share();
|
||||||
|
|
||||||
|
f->client->lastFrame.reset();
|
||||||
|
++f->client->frameCounter;
|
||||||
|
|
||||||
|
framesToRemove.push_back(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& f : framesToRemove) {
|
||||||
|
destroyResource(f.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CToplevelExportProtocol::onWindowUnmap(PHLWINDOW pWindow) {
|
||||||
|
for (auto& f : m_vFrames) {
|
||||||
|
if (f->pWindow == pWindow)
|
||||||
|
f->pWindow.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "hyprland-toplevel-export-v1-protocol.h"
|
#include "hyprland-toplevel-export-v1.hpp"
|
||||||
|
#include "WaylandProtocol.hpp"
|
||||||
#include "Screencopy.hpp"
|
#include "Screencopy.hpp"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -10,32 +11,91 @@
|
||||||
class CMonitor;
|
class CMonitor;
|
||||||
class CWindow;
|
class CWindow;
|
||||||
|
|
||||||
class CToplevelExportProtocolManager {
|
class CToplevelExportClient {
|
||||||
public:
|
public:
|
||||||
CToplevelExportProtocolManager();
|
CToplevelExportClient(SP<CHyprlandToplevelExportManagerV1> resource_);
|
||||||
|
|
||||||
|
bool good();
|
||||||
|
|
||||||
|
WP<CToplevelExportClient> self;
|
||||||
|
eClientOwners clientOwner = CLIENT_TOPLEVEL_EXPORT;
|
||||||
|
|
||||||
|
CTimer lastFrame;
|
||||||
|
int frameCounter = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SP<CHyprlandToplevelExportManagerV1> resource;
|
||||||
|
|
||||||
|
int framesInLastHalfSecond = 0;
|
||||||
|
CTimer lastMeasure;
|
||||||
|
bool sentScreencast = false;
|
||||||
|
|
||||||
|
SP<HOOK_CALLBACK_FN> tickCallback;
|
||||||
|
void onTick();
|
||||||
|
|
||||||
|
void captureToplevel(CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, PHLWINDOW handle);
|
||||||
|
|
||||||
|
friend class CToplevelExportProtocol;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CToplevelExportFrame {
|
||||||
|
public:
|
||||||
|
CToplevelExportFrame(SP<CHyprlandToplevelExportFrameV1> resource_, int32_t overlayCursor, PHLWINDOW pWindow);
|
||||||
|
~CToplevelExportFrame();
|
||||||
|
|
||||||
|
bool good();
|
||||||
|
|
||||||
|
SP<CToplevelExportFrame> self;
|
||||||
|
WP<CToplevelExportClient> client;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SP<CHyprlandToplevelExportFrameV1> resource;
|
||||||
|
|
||||||
|
PHLWINDOW pWindow;
|
||||||
|
bool overlayCursor = false;
|
||||||
|
bool ignoreDamage = false;
|
||||||
|
bool lockedSWCursors = false;
|
||||||
|
|
||||||
|
WP<IHLBuffer> buffer;
|
||||||
|
bool bufferDMA = false;
|
||||||
|
uint32_t shmFormat = 0;
|
||||||
|
uint32_t dmabufFormat = 0;
|
||||||
|
int shmStride = 0;
|
||||||
|
CBox box = {};
|
||||||
|
|
||||||
|
void copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resource* buffer, int32_t ignoreDamage);
|
||||||
|
bool copyDmabuf(timespec* now);
|
||||||
|
bool copyShm(timespec* now);
|
||||||
|
void share();
|
||||||
|
|
||||||
|
friend class CToplevelExportProtocol;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CToplevelExportProtocol : IWaylandProtocol {
|
||||||
|
public:
|
||||||
|
CToplevelExportProtocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||||
|
|
||||||
|
void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
|
||||||
|
void destroyResource(CToplevelExportClient* client);
|
||||||
|
void destroyResource(CToplevelExportFrame* frame);
|
||||||
|
|
||||||
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
|
||||||
void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, PHLWINDOW handle);
|
|
||||||
void removeClient(CScreencopyClient* client, bool force = false);
|
|
||||||
void removeFrame(SScreencopyFrame* frame, bool force = false);
|
|
||||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
|
||||||
void displayDestroy();
|
|
||||||
void onWindowUnmap(PHLWINDOW pWindow);
|
void onWindowUnmap(PHLWINDOW pWindow);
|
||||||
void onOutputCommit(CMonitor* pMonitor);
|
void onOutputCommit(CMonitor* pMonitor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wl_global* m_pGlobal = nullptr;
|
std::vector<SP<CToplevelExportClient>> m_vClients;
|
||||||
std::list<SScreencopyFrame> m_lFrames;
|
std::vector<SP<CToplevelExportFrame>> m_vFrames;
|
||||||
std::list<CScreencopyClient> m_lClients;
|
std::vector<SP<CToplevelExportFrame>> m_vFramesAwaitingWrite;
|
||||||
|
|
||||||
wl_listener m_liDisplayDestroy;
|
void shareFrame(CToplevelExportFrame* frame);
|
||||||
|
bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now);
|
||||||
|
bool copyFrameShm(CToplevelExportFrame* frame, timespec* now);
|
||||||
|
void sendDamage(CToplevelExportFrame* frame);
|
||||||
|
|
||||||
std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
|
friend class CToplevelExportClient;
|
||||||
|
friend class CToplevelExportFrame;
|
||||||
void shareFrame(SScreencopyFrame* frame);
|
};
|
||||||
bool copyFrameDmabuf(SScreencopyFrame* frame, timespec* now);
|
|
||||||
bool copyFrameShm(SScreencopyFrame* frame, timespec* now);
|
namespace PROTO {
|
||||||
void sendDamage(SScreencopyFrame* frame);
|
inline UP<CToplevelExportProtocol> toplevelExport;
|
||||||
|
|
||||||
friend class CScreencopyClient;
|
|
||||||
};
|
};
|
|
@ -54,13 +54,13 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
|
||||||
});
|
});
|
||||||
|
|
||||||
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
||||||
if (!surface || !surface->pending.buffer)
|
if (!surface || !surface->pending.texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (surface->pending.viewport.hasSource) {
|
if (surface->pending.viewport.hasSource) {
|
||||||
auto& src = surface->pending.viewport.source;
|
auto& src = surface->pending.viewport.source;
|
||||||
|
|
||||||
if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) {
|
if (src.w + src.x > surface->pending.bufferSize.x || src.h + src.y > surface->pending.bufferSize.y) {
|
||||||
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit");
|
||||||
surface->pending.rejected = true;
|
surface->pending.rejected = true;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "VirtualPointer.hpp"
|
#include "VirtualPointer.hpp"
|
||||||
|
#include "core/Output.hpp"
|
||||||
|
|
||||||
#define LOGM PROTO::virtualPointer->protoLog
|
#define LOGM PROTO::virtualPointer->protoLog
|
||||||
|
|
||||||
CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> resource_) : resource(resource_) {
|
CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> resource_, WP<CMonitor> boundOutput_) : boundOutput(boundOutput_), resource(resource_) {
|
||||||
if (!good())
|
if (!good())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -112,10 +113,18 @@ void CVirtualPointerProtocol::bindManager(wl_client* client, void* data, uint32_
|
||||||
RESOURCE->setOnDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); });
|
RESOURCE->setOnDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); });
|
||||||
RESOURCE->setDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); });
|
RESOURCE->setDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); });
|
||||||
|
|
||||||
RESOURCE->setCreateVirtualPointer([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { this->onCreatePointer(pMgr, seat, id); });
|
RESOURCE->setCreateVirtualPointer([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { this->onCreatePointer(pMgr, seat, id, {}); });
|
||||||
RESOURCE->setCreateVirtualPointerWithOutput([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, wl_resource* output, uint32_t id) {
|
RESOURCE->setCreateVirtualPointerWithOutput([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, wl_resource* output, uint32_t id) {
|
||||||
LOGM(WARN, "TODO: CreateWithOutput is not supported yet. Ignoring for now.");
|
if (output) {
|
||||||
this->onCreatePointer(pMgr, seat, id);
|
auto RES = CWLOutputResource::fromResource(output);
|
||||||
|
if (!RES) {
|
||||||
|
this->onCreatePointer(pMgr, seat, id, {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->onCreatePointer(pMgr, seat, id, RES->monitor);
|
||||||
|
} else
|
||||||
|
this->onCreatePointer(pMgr, seat, id, {});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,9 +136,9 @@ void CVirtualPointerProtocol::destroyResource(CVirtualPointerV1Resource* pointer
|
||||||
std::erase_if(m_vPointers, [&](const auto& other) { return other.get() == pointer; });
|
std::erase_if(m_vPointers, [&](const auto& other) { return other.get() == pointer; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) {
|
void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, WP<CMonitor> output) {
|
||||||
|
|
||||||
const auto RESOURCE = m_vPointers.emplace_back(makeShared<CVirtualPointerV1Resource>(makeShared<CZwlrVirtualPointerV1>(pMgr->client(), pMgr->version(), id)));
|
const auto RESOURCE = m_vPointers.emplace_back(makeShared<CVirtualPointerV1Resource>(makeShared<CZwlrVirtualPointerV1>(pMgr->client(), pMgr->version(), id), output));
|
||||||
|
|
||||||
if (!RESOURCE->good()) {
|
if (!RESOURCE->good()) {
|
||||||
pMgr->noMemory();
|
pMgr->noMemory();
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
#include "wlr-virtual-pointer-unstable-v1.hpp"
|
#include "wlr-virtual-pointer-unstable-v1.hpp"
|
||||||
#include "../helpers/signal/Signal.hpp"
|
#include "../helpers/signal/Signal.hpp"
|
||||||
#include "../devices/IPointer.hpp"
|
#include "../devices/IPointer.hpp"
|
||||||
|
#include "../helpers/Monitor.hpp"
|
||||||
|
|
||||||
class CVirtualPointerV1Resource {
|
class CVirtualPointerV1Resource {
|
||||||
public:
|
public:
|
||||||
CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> resource_);
|
CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> resource_, WP<CMonitor> boundOutput_);
|
||||||
~CVirtualPointerV1Resource();
|
~CVirtualPointerV1Resource();
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -39,6 +40,8 @@ class CVirtualPointerV1Resource {
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
WP<CMonitor> boundOutput;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SP<CZwlrVirtualPointerV1> resource;
|
SP<CZwlrVirtualPointerV1> resource;
|
||||||
|
|
||||||
|
@ -60,7 +63,7 @@ class CVirtualPointerProtocol : public IWaylandProtocol {
|
||||||
private:
|
private:
|
||||||
void onManagerResourceDestroy(wl_resource* res);
|
void onManagerResourceDestroy(wl_resource* res);
|
||||||
void destroyResource(CVirtualPointerV1Resource* pointer);
|
void destroyResource(CVirtualPointerV1Resource* pointer);
|
||||||
void onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id);
|
void onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, WP<CMonitor> output);
|
||||||
|
|
||||||
//
|
//
|
||||||
std::vector<UP<CZwlrVirtualPointerManagerV1>> m_vManagers;
|
std::vector<UP<CZwlrVirtualPointerManagerV1>> m_vManagers;
|
||||||
|
|
|
@ -6,12 +6,14 @@ static void bindManagerInternal(wl_client* client, void* data, uint32_t ver, uin
|
||||||
}
|
}
|
||||||
|
|
||||||
static void displayDestroyInternal(struct wl_listener* listener, void* data) {
|
static void displayDestroyInternal(struct wl_listener* listener, void* data) {
|
||||||
((IWaylandProtocol*)data)->onDisplayDestroy();
|
IWaylandProtocolDestroyWrapper* wrap = wl_container_of(listener, wrap, listener);
|
||||||
|
IWaylandProtocol* proto = wrap->parent;
|
||||||
|
proto->onDisplayDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IWaylandProtocol::onDisplayDestroy() {
|
void IWaylandProtocol::onDisplayDestroy() {
|
||||||
wl_list_remove(&m_liDisplayDestroy.link);
|
wl_list_remove(&m_liDisplayDestroy.listener.link);
|
||||||
wl_list_init(&m_liDisplayDestroy.link);
|
wl_list_init(&m_liDisplayDestroy.listener.link);
|
||||||
wl_global_destroy(m_pGlobal);
|
wl_global_destroy(m_pGlobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +25,10 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_liDisplayDestroy.notify = displayDestroyInternal;
|
wl_list_init(&m_liDisplayDestroy.listener.link);
|
||||||
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
m_liDisplayDestroy.listener.notify = displayDestroyInternal;
|
||||||
|
m_liDisplayDestroy.parent = this;
|
||||||
|
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener);
|
||||||
|
|
||||||
protoLog(LOG, "Registered global");
|
protoLog(LOG, "Registered global");
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,12 @@
|
||||||
|
|
||||||
#define PROTO NProtocols
|
#define PROTO NProtocols
|
||||||
|
|
||||||
|
class IWaylandProtocol;
|
||||||
|
struct IWaylandProtocolDestroyWrapper {
|
||||||
|
wl_listener listener;
|
||||||
|
IWaylandProtocol* parent = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class IWaylandProtocol {
|
class IWaylandProtocol {
|
||||||
public:
|
public:
|
||||||
IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name);
|
IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||||
|
@ -26,8 +32,9 @@ class IWaylandProtocol {
|
||||||
Debug::log(level, std::format("[{}] ", m_szName) + std::vformat(fmt.get(), std::make_format_args(args...)));
|
Debug::log(level, std::format("[{}] ", m_szName) + std::vformat(fmt.get(), std::make_format_args(args...)));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IWaylandProtocolDestroyWrapper m_liDisplayDestroy;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_szName;
|
std::string m_szName;
|
||||||
wl_global* m_pGlobal = nullptr;
|
wl_global* m_pGlobal = nullptr;
|
||||||
wl_listener m_liDisplayDestroy;
|
|
||||||
};
|
};
|
|
@ -8,6 +8,20 @@
|
||||||
|
|
||||||
#define LOGM PROTO::xdgShell->protoLog
|
#define LOGM PROTO::xdgShell->protoLog
|
||||||
|
|
||||||
|
void SXDGPositionerState::setAnchor(xdgPositionerAnchor edges) {
|
||||||
|
anchor.setTop(edges == XDG_POSITIONER_ANCHOR_TOP || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT);
|
||||||
|
anchor.setLeft(edges == XDG_POSITIONER_ANCHOR_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT);
|
||||||
|
anchor.setBottom(edges == XDG_POSITIONER_ANCHOR_BOTTOM || edges == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT);
|
||||||
|
anchor.setRight(edges == XDG_POSITIONER_ANCHOR_RIGHT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SXDGPositionerState::setGravity(xdgPositionerGravity edges) {
|
||||||
|
gravity.setTop(edges == XDG_POSITIONER_GRAVITY_TOP || edges == XDG_POSITIONER_GRAVITY_TOP_LEFT || edges == XDG_POSITIONER_GRAVITY_TOP_RIGHT);
|
||||||
|
gravity.setLeft(edges == XDG_POSITIONER_GRAVITY_LEFT || edges == XDG_POSITIONER_GRAVITY_TOP_LEFT || edges == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT);
|
||||||
|
gravity.setBottom(edges == XDG_POSITIONER_GRAVITY_BOTTOM || edges == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT || edges == XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
|
||||||
|
gravity.setRight(edges == XDG_POSITIONER_GRAVITY_RIGHT || edges == XDG_POSITIONER_GRAVITY_TOP_RIGHT || edges == XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
CXDGPopupResource::CXDGPopupResource(SP<CXdgPopup> resource_, SP<CXDGSurfaceResource> owner_, SP<CXDGSurfaceResource> surface_, SP<CXDGPositionerResource> positioner) :
|
CXDGPopupResource::CXDGPopupResource(SP<CXdgPopup> resource_, SP<CXDGSurfaceResource> owner_, SP<CXDGSurfaceResource> surface_, SP<CXDGPositionerResource> positioner) :
|
||||||
surface(surface_), parent(owner_), resource(resource_), positionerRules(positioner) {
|
surface(surface_), parent(owner_), resource(resource_), positionerRules(positioner) {
|
||||||
if (!good())
|
if (!good())
|
||||||
|
@ -333,12 +347,12 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
|
||||||
if (toplevel)
|
if (toplevel)
|
||||||
toplevel->current = toplevel->pending;
|
toplevel->current = toplevel->pending;
|
||||||
|
|
||||||
if (initialCommit && surface->pending.buffer) {
|
if (initialCommit && surface->pending.texture) {
|
||||||
resource->error(-1, "Buffer attached before initial commit");
|
resource->error(-1, "Buffer attached before initial commit");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface->current.buffer && !mapped) {
|
if (surface->current.texture && !mapped) {
|
||||||
// this forces apps to not draw CSD.
|
// this forces apps to not draw CSD.
|
||||||
if (toplevel)
|
if (toplevel)
|
||||||
toplevel->setMaximized(true);
|
toplevel->setMaximized(true);
|
||||||
|
@ -349,10 +363,10 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!surface->current.buffer && mapped) {
|
if (!surface->current.texture && mapped) {
|
||||||
mapped = false;
|
mapped = false;
|
||||||
surface->unmap();
|
|
||||||
events.unmap.emit();
|
events.unmap.emit();
|
||||||
|
surface->unmap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,10 +443,6 @@ CXDGSurfaceResource::~CXDGSurfaceResource() {
|
||||||
surface->resetRole();
|
surface->resetRole();
|
||||||
}
|
}
|
||||||
|
|
||||||
eSurfaceRole CXDGSurfaceResource::role() {
|
|
||||||
return SURFACE_ROLE_XDG_SHELL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CXDGSurfaceResource::good() {
|
bool CXDGSurfaceResource::good() {
|
||||||
return resource->resource();
|
return resource->resource();
|
||||||
}
|
}
|
||||||
|
@ -490,9 +500,9 @@ CXDGPositionerResource::CXDGPositionerResource(SP<CXdgPositioner> resource_, SP<
|
||||||
|
|
||||||
resource->setSetOffset([this](CXdgPositioner* r, int32_t x, int32_t y) { state.offset = {x, y}; });
|
resource->setSetOffset([this](CXdgPositioner* r, int32_t x, int32_t y) { state.offset = {x, y}; });
|
||||||
|
|
||||||
resource->setSetAnchor([this](CXdgPositioner* r, xdgPositionerAnchor a) { state.anchor = a; });
|
resource->setSetAnchor([this](CXdgPositioner* r, xdgPositionerAnchor a) { state.setAnchor(a); });
|
||||||
|
|
||||||
resource->setSetGravity([this](CXdgPositioner* r, xdgPositionerGravity g) { state.gravity = g; });
|
resource->setSetGravity([this](CXdgPositioner* r, xdgPositionerGravity g) { state.setGravity(g); });
|
||||||
|
|
||||||
resource->setSetConstraintAdjustment([this](CXdgPositioner* r, xdgPositionerConstraintAdjustment a) { state.constraintAdjustment = (uint32_t)a; });
|
resource->setSetConstraintAdjustment([this](CXdgPositioner* r, xdgPositionerConstraintAdjustment a) { state.constraintAdjustment = (uint32_t)a; });
|
||||||
|
|
||||||
|
@ -513,125 +523,96 @@ CXDGPositionerRules::CXDGPositionerRules(SP<CXDGPositionerResource> positioner)
|
||||||
state = positioner->state;
|
state = positioner->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector2D pointForAnchor(const CBox& box, const Vector2D& predictionSize, xdgPositionerAnchor anchor) {
|
CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoord) {
|
||||||
switch (anchor) {
|
|
||||||
case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.0 - predictionSize.x / 2.0, 0.0};
|
|
||||||
case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.0 - predictionSize.x / 2.0, box.size().y};
|
|
||||||
case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0.0, box.size().y / 2.0 - predictionSize.y / 2.0};
|
|
||||||
case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F - predictionSize.y / 2.0};
|
|
||||||
case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos();
|
|
||||||
case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0.0, box.size().y};
|
|
||||||
case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0.0};
|
|
||||||
case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y};
|
|
||||||
default: return box.pos();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& parentCoord) {
|
|
||||||
|
|
||||||
Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord);
|
Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord);
|
||||||
|
|
||||||
CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.requestedSize, state.anchor) + state.offset, state.requestedSize};
|
// padding
|
||||||
|
constraint.expand(-4);
|
||||||
|
|
||||||
bool success = predictedBox.inside(constraint);
|
auto anchorRect = state.anchorRect.copy().translate(parentCoord);
|
||||||
|
|
||||||
if (success)
|
auto width = state.requestedSize.x;
|
||||||
return predictedBox.translate(-parentCoord - constraint.pos());
|
auto height = state.requestedSize.y;
|
||||||
|
|
||||||
CBox test = predictedBox;
|
auto anchorX = state.anchor.left() ? anchorRect.x : state.anchor.right() ? anchorRect.extent().x : anchorRect.middle().x;
|
||||||
|
auto anchorY = state.anchor.top() ? anchorRect.y : state.anchor.bottom() ? anchorRect.extent().y : anchorRect.middle().y;
|
||||||
|
|
||||||
if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)) {
|
auto calcEffectiveX = [&]() { return state.gravity.left() ? anchorX - width : state.gravity.right() ? anchorX : anchorX - width / 2; };
|
||||||
// attempt to flip
|
auto calcEffectiveY = [&]() { return state.gravity.top() ? anchorY - height : state.gravity.bottom() ? anchorY : anchorY - height / 2; };
|
||||||
const bool flipX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X;
|
|
||||||
const bool flipY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
|
|
||||||
auto countEdges = [constraint](const CBox& test) -> int {
|
|
||||||
int edgeCount = 0;
|
|
||||||
edgeCount += test.x < constraint.x ? 1 : 0;
|
|
||||||
edgeCount += test.x + test.w > constraint.x + constraint.w ? 1 : 0;
|
|
||||||
edgeCount += test.y < constraint.y ? 1 : 0;
|
|
||||||
edgeCount += test.y + test.h > constraint.y + constraint.h ? 1 : 0;
|
|
||||||
return edgeCount;
|
|
||||||
};
|
|
||||||
int edgeCount = countEdges(test);
|
|
||||||
|
|
||||||
if (flipX && edgeCount > countEdges(test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0.0})))
|
auto effectiveX = calcEffectiveX();
|
||||||
test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0.0});
|
auto effectiveY = calcEffectiveY();
|
||||||
if (flipY && edgeCount > countEdges(test.copy().translate(Vector2D{0.0, -predictedBox.h - state.anchorRect.h})))
|
|
||||||
test.translate(Vector2D{0.0, -predictedBox.h - state.anchorRect.h});
|
|
||||||
|
|
||||||
success = test.copy().expand(-1).inside(constraint);
|
// Note: the usage of offset is a guess which maintains compatibility with other compositors that were tested.
|
||||||
|
// It considers the offset when deciding whether or not to flip but does not actually flip the offset, instead
|
||||||
|
// applying it after the flip step.
|
||||||
|
|
||||||
if (success)
|
if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) {
|
||||||
return test.translate(-parentCoord - constraint.pos());
|
auto flip = (state.gravity.left() && effectiveX + state.offset.x < constraint.x) || (state.gravity.right() && effectiveX + state.offset.x + width > constraint.extent().x);
|
||||||
|
|
||||||
|
if (flip) {
|
||||||
|
state.gravity ^= CEdges::LEFT | CEdges::RIGHT;
|
||||||
|
anchorX = state.anchor.left() ? anchorRect.extent().x : state.anchor.right() ? anchorRect.x : anchorX;
|
||||||
|
effectiveX = calcEffectiveX();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for slide and resize, defines the padding around the edge for the positioned
|
if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y) {
|
||||||
// surface.
|
auto flip = (state.gravity.top() && effectiveY + state.offset.y < constraint.y) || (state.gravity.bottom() && effectiveY + state.offset.y + height > constraint.extent().y);
|
||||||
constexpr int EDGE_PADDING = 4;
|
|
||||||
|
|
||||||
if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y)) {
|
if (flip) {
|
||||||
// attempt to slide
|
state.gravity ^= CEdges::TOP | CEdges::BOTTOM;
|
||||||
const bool slideX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X;
|
anchorY = state.anchor.top() ? anchorRect.extent().y : state.anchor.bottom() ? anchorRect.y : anchorY;
|
||||||
const bool slideY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
|
effectiveY = calcEffectiveY();
|
||||||
|
}
|
||||||
//const bool gravityLeft = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
|
|
||||||
//const bool gravityTop = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_TOP || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_RIGHT;
|
|
||||||
|
|
||||||
const bool leftEdgeOut = test.x < constraint.x;
|
|
||||||
const bool topEdgeOut = test.y < constraint.y;
|
|
||||||
const bool rightEdgeOut = test.x + test.w > constraint.x + constraint.w;
|
|
||||||
const bool bottomEdgeOut = test.y + test.h > constraint.y + constraint.h;
|
|
||||||
|
|
||||||
// TODO: this isn't truly conformant.
|
|
||||||
if (leftEdgeOut && slideX)
|
|
||||||
test.x = constraint.x + EDGE_PADDING;
|
|
||||||
if (rightEdgeOut && slideX)
|
|
||||||
test.x = std::clamp((double)(constraint.x + constraint.w - test.w), (double)(constraint.x + EDGE_PADDING), (double)INFINITY);
|
|
||||||
if (topEdgeOut && slideY)
|
|
||||||
test.y = constraint.y + EDGE_PADDING;
|
|
||||||
if (bottomEdgeOut && slideY)
|
|
||||||
test.y = std::clamp((double)(constraint.y + constraint.h - test.h), (double)(constraint.y + EDGE_PADDING), (double)INFINITY);
|
|
||||||
|
|
||||||
success = test.copy().expand(-1).inside(constraint);
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
return test.translate(-parentCoord - constraint.pos());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)) {
|
effectiveX += state.offset.x;
|
||||||
const bool resizeX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X;
|
effectiveY += state.offset.y;
|
||||||
const bool resizeY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
|
|
||||||
|
|
||||||
const bool leftEdgeOut = test.x < constraint.x;
|
// Slide order is important for the case where the window is too large to fit on screen.
|
||||||
const bool topEdgeOut = test.y < constraint.y;
|
|
||||||
const bool rightEdgeOut = test.x + test.w > constraint.x + constraint.w;
|
|
||||||
const bool bottomEdgeOut = test.y + test.h > constraint.y + constraint.h;
|
|
||||||
|
|
||||||
// TODO: this isn't truly conformant.
|
if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) {
|
||||||
if (leftEdgeOut && resizeX) {
|
if (effectiveX + width > constraint.extent().x)
|
||||||
test.w = test.x + test.w - constraint.x - EDGE_PADDING;
|
effectiveX = constraint.extent().x - width;
|
||||||
test.x = constraint.x + EDGE_PADDING;
|
|
||||||
}
|
|
||||||
if (rightEdgeOut && resizeX)
|
|
||||||
test.w = constraint.w - (test.x - constraint.w) - EDGE_PADDING;
|
|
||||||
if (topEdgeOut && resizeY) {
|
|
||||||
test.h = test.y + test.h - constraint.y - EDGE_PADDING;
|
|
||||||
test.y = constraint.y + EDGE_PADDING;
|
|
||||||
}
|
|
||||||
if (bottomEdgeOut && resizeY)
|
|
||||||
test.h = constraint.h - (test.y - constraint.y) - EDGE_PADDING;
|
|
||||||
|
|
||||||
success = test.copy().expand(-1).inside(constraint);
|
if (effectiveX < constraint.x)
|
||||||
|
effectiveX = constraint.x;
|
||||||
if (success)
|
|
||||||
return test.translate(-parentCoord - constraint.pos());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place");
|
if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) {
|
||||||
|
if (effectiveY + height > constraint.extent().y)
|
||||||
|
effectiveY = constraint.extent().y - height;
|
||||||
|
|
||||||
return test.translate(-parentCoord - constraint.pos());
|
if (effectiveY < constraint.y)
|
||||||
|
effectiveY = constraint.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) {
|
||||||
|
if (effectiveX < constraint.x) {
|
||||||
|
auto diff = constraint.x - effectiveX;
|
||||||
|
effectiveX = constraint.x;
|
||||||
|
width -= diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto effectiveX2 = effectiveX + width;
|
||||||
|
if (effectiveX2 > constraint.extent().x)
|
||||||
|
width -= effectiveX2 - constraint.extent().x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) {
|
||||||
|
if (effectiveY < constraint.y) {
|
||||||
|
auto diff = constraint.y - effectiveY;
|
||||||
|
effectiveY = constraint.y;
|
||||||
|
height -= diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto effectiveY2 = effectiveY + height;
|
||||||
|
if (effectiveY2 > constraint.extent().y)
|
||||||
|
height -= effectiveY2 - constraint.extent().y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {effectiveX - parentCoord.x, effectiveY - parentCoord.y, width, height};
|
||||||
}
|
}
|
||||||
|
|
||||||
CXDGWMBase::CXDGWMBase(SP<CXdgWmBase> resource_) : resource(resource_) {
|
CXDGWMBase::CXDGWMBase(SP<CXdgWmBase> resource_) : resource(resource_) {
|
||||||
|
@ -682,7 +663,8 @@ CXDGWMBase::CXDGWMBase(SP<CXdgWmBase> resource_) : resource(resource_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RESOURCE->self = RESOURCE;
|
RESOURCE->self = RESOURCE;
|
||||||
SURF->role = RESOURCE;
|
RESOURCE->surface = SURF;
|
||||||
|
SURF->role = makeShared<CXDGSurfaceRole>(RESOURCE);
|
||||||
|
|
||||||
surfaces.emplace_back(RESOURCE);
|
surfaces.emplace_back(RESOURCE);
|
||||||
|
|
||||||
|
@ -779,3 +761,7 @@ void CXDGShellProtocol::onPopupDestroy(WP<CXDGPopupResource> popup) {
|
||||||
if (popup->surface)
|
if (popup->surface)
|
||||||
grab->remove(popup->surface->surface.lock());
|
grab->remove(popup->surface->surface.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CXDGSurfaceRole::CXDGSurfaceRole(SP<CXDGSurfaceResource> xdg) : xdgSurface(xdg) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <hyprutils/math/Edges.hpp>
|
||||||
#include "WaylandProtocol.hpp"
|
#include "WaylandProtocol.hpp"
|
||||||
#include "xdg-shell.hpp"
|
#include "xdg-shell.hpp"
|
||||||
#include "../helpers/math/Math.hpp"
|
#include "../helpers/math/Math.hpp"
|
||||||
#include "../helpers/math/Math.hpp"
|
|
||||||
#include "../helpers/signal/Signal.hpp"
|
#include "../helpers/signal/Signal.hpp"
|
||||||
#include "types/SurfaceRole.hpp"
|
#include "types/SurfaceRole.hpp"
|
||||||
|
|
||||||
|
@ -22,19 +22,22 @@ class CWLSurfaceResource;
|
||||||
struct SXDGPositionerState {
|
struct SXDGPositionerState {
|
||||||
Vector2D requestedSize;
|
Vector2D requestedSize;
|
||||||
CBox anchorRect;
|
CBox anchorRect;
|
||||||
xdgPositionerAnchor anchor = XDG_POSITIONER_ANCHOR_NONE;
|
CEdges anchor;
|
||||||
xdgPositionerGravity gravity = XDG_POSITIONER_GRAVITY_NONE;
|
CEdges gravity;
|
||||||
uint32_t constraintAdjustment = 0;
|
uint32_t constraintAdjustment = 0;
|
||||||
Vector2D offset;
|
Vector2D offset;
|
||||||
bool reactive = false;
|
bool reactive = false;
|
||||||
Vector2D parentSize;
|
Vector2D parentSize;
|
||||||
|
|
||||||
|
void setAnchor(xdgPositionerAnchor edges);
|
||||||
|
void setGravity(xdgPositionerGravity edges);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CXDGPositionerRules {
|
class CXDGPositionerRules {
|
||||||
public:
|
public:
|
||||||
CXDGPositionerRules(SP<CXDGPositionerResource> positioner);
|
CXDGPositionerRules(SP<CXDGPositionerResource> positioner);
|
||||||
|
|
||||||
CBox getPosition(const CBox& constraint, const Vector2D& parentPos);
|
CBox getPosition(CBox constraint, const Vector2D& parentPos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SXDGPositionerState state;
|
SXDGPositionerState state;
|
||||||
|
@ -138,15 +141,24 @@ class CXDGToplevelResource {
|
||||||
void applyState();
|
void applyState();
|
||||||
};
|
};
|
||||||
|
|
||||||
class CXDGSurfaceResource : public ISurfaceRole {
|
class CXDGSurfaceRole : public ISurfaceRole {
|
||||||
|
public:
|
||||||
|
CXDGSurfaceRole(SP<CXDGSurfaceResource> xdg);
|
||||||
|
|
||||||
|
virtual eSurfaceRole role() {
|
||||||
|
return SURFACE_ROLE_XDG_SHELL;
|
||||||
|
}
|
||||||
|
|
||||||
|
WP<CXDGSurfaceResource> xdgSurface;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CXDGSurfaceResource {
|
||||||
public:
|
public:
|
||||||
CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, SP<CWLSurfaceResource> surface_);
|
CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, SP<CWLSurfaceResource> surface_);
|
||||||
~CXDGSurfaceResource();
|
~CXDGSurfaceResource();
|
||||||
|
|
||||||
static SP<CXDGSurfaceResource> fromResource(wl_resource*);
|
static SP<CXDGSurfaceResource> fromResource(wl_resource*);
|
||||||
|
|
||||||
virtual eSurfaceRole role();
|
|
||||||
|
|
||||||
bool good();
|
bool good();
|
||||||
|
|
||||||
WP<CXDGWMBase> owner;
|
WP<CXDGWMBase> owner;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Compositor.hpp"
|
#include "Compositor.hpp"
|
||||||
#include "Output.hpp"
|
#include "Output.hpp"
|
||||||
|
#include "Seat.hpp"
|
||||||
#include "../types/WLBuffer.hpp"
|
#include "../types/WLBuffer.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
#include "../PresentationTime.hpp"
|
#include "../PresentationTime.hpp"
|
||||||
#include "../DRMSyncobj.hpp"
|
#include "../DRMSyncobj.hpp"
|
||||||
#include "../../render/Renderer.hpp"
|
#include "../../render/Renderer.hpp"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#define LOGM PROTO::compositor->protoLog
|
#define LOGM PROTO::compositor->protoLog
|
||||||
|
|
||||||
|
@ -19,8 +21,6 @@ class CDefaultSurfaceRole : public ISurfaceRole {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SP<CDefaultSurfaceRole> defaultRole = makeShared<CDefaultSurfaceRole>();
|
|
||||||
|
|
||||||
CWLCallbackResource::CWLCallbackResource(SP<CWlCallback> resource_) : resource(resource_) {
|
CWLCallbackResource::CWLCallbackResource(SP<CWlCallback> resource_) : resource(resource_) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||||
|
|
||||||
resource->setData(this);
|
resource->setData(this);
|
||||||
|
|
||||||
role = defaultRole;
|
role = makeShared<CDefaultSurfaceRole>();
|
||||||
|
|
||||||
resource->setDestroy([this](CWlSurface* r) { destroy(); });
|
resource->setDestroy([this](CWlSurface* r) { destroy(); });
|
||||||
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
|
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
|
||||||
|
@ -76,40 +76,41 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||||
pending.texture.reset();
|
pending.texture.reset();
|
||||||
} else {
|
} else {
|
||||||
auto res = CWLBufferResource::fromResource(buffer);
|
auto res = CWLBufferResource::fromResource(buffer);
|
||||||
pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr;
|
pending.buffer = res && res->buffer ? makeShared<CHLBufferReference>(res->buffer.lock(), self.lock()) : nullptr;
|
||||||
pending.size = res && res->buffer ? res->buffer->size : Vector2D{};
|
pending.size = res && res->buffer ? res->buffer->size : Vector2D{};
|
||||||
pending.texture = res && res->buffer ? res->buffer->texture : nullptr;
|
pending.texture = res && res->buffer ? res->buffer->texture : nullptr;
|
||||||
|
pending.bufferSize = res && res->buffer ? res->buffer->size : Vector2D{};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{};
|
Vector2D oldBufSize = current.buffer ? current.bufferSize : Vector2D{};
|
||||||
Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{};
|
Vector2D newBufSize = pending.buffer ? pending.bufferSize : Vector2D{};
|
||||||
|
|
||||||
if (oldBufSize != newBufSize)
|
if (oldBufSize != newBufSize || current.buffer != pending.buffer)
|
||||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||||
|
|
||||||
bufferReleased = false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
resource->setCommit([this](CWlSurface* r) {
|
resource->setCommit([this](CWlSurface* r) {
|
||||||
if (pending.buffer)
|
if (pending.texture)
|
||||||
pending.bufferDamage.intersect(CBox{{}, pending.buffer->size});
|
pending.bufferDamage.intersect(CBox{{}, pending.bufferSize});
|
||||||
|
|
||||||
if (!pending.buffer)
|
if (!pending.texture)
|
||||||
pending.size = {};
|
pending.size = {};
|
||||||
else if (pending.viewport.hasDestination)
|
else if (pending.viewport.hasDestination)
|
||||||
pending.size = pending.viewport.destination;
|
pending.size = pending.viewport.destination;
|
||||||
else if (pending.viewport.hasSource)
|
else if (pending.viewport.hasSource)
|
||||||
pending.size = pending.viewport.source.size();
|
pending.size = pending.viewport.source.size();
|
||||||
else {
|
else {
|
||||||
Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.buffer->size.y, pending.buffer->size.x} : pending.buffer->size;
|
Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.bufferSize.y, pending.bufferSize.x} : pending.bufferSize;
|
||||||
pending.size = tfs / pending.scale;
|
pending.size = tfs / pending.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
pending.damage.intersect(CBox{{}, pending.size});
|
pending.damage.intersect(CBox{{}, pending.size});
|
||||||
|
|
||||||
events.precommit.emit();
|
events.precommit.emit();
|
||||||
if (pending.rejected)
|
if (pending.rejected) {
|
||||||
|
dropPendingBuffer();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (stateLocks <= 0)
|
if (stateLocks <= 0)
|
||||||
commitPendingState();
|
commitPendingState();
|
||||||
|
@ -151,12 +152,23 @@ CWLSurfaceResource::~CWLSurfaceResource() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::destroy() {
|
void CWLSurfaceResource::destroy() {
|
||||||
if (mapped)
|
if (mapped) {
|
||||||
|
events.unmap.emit();
|
||||||
unmap();
|
unmap();
|
||||||
|
}
|
||||||
events.destroy.emit();
|
events.destroy.emit();
|
||||||
|
releaseBuffers(false);
|
||||||
PROTO::compositor->destroyResource(this);
|
PROTO::compositor->destroyResource(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CWLSurfaceResource::dropPendingBuffer() {
|
||||||
|
pending.buffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWLSurfaceResource::dropCurrentBuffer() {
|
||||||
|
current.buffer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) {
|
SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) {
|
||||||
auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data());
|
auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data());
|
||||||
return data ? data->self.lock() : nullptr;
|
return data ? data->self.lock() : nullptr;
|
||||||
|
@ -237,7 +249,7 @@ void CWLSurfaceResource::frame(timespec* now) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::resetRole() {
|
void CWLSurfaceResource::resetRole() {
|
||||||
role = defaultRole;
|
role = makeShared<CDefaultSurfaceRole>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
|
void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) {
|
||||||
|
@ -251,6 +263,8 @@ void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std
|
||||||
for (auto& c : n->subsurfaces) {
|
for (auto& c : n->subsurfaces) {
|
||||||
if (c->zIndex >= 0)
|
if (c->zIndex >= 0)
|
||||||
break;
|
break;
|
||||||
|
if (c->surface.expired())
|
||||||
|
continue;
|
||||||
nodes2.push_back(c->surface.lock());
|
nodes2.push_back(c->surface.lock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,7 +277,7 @@ void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std
|
||||||
for (auto& n : nodes) {
|
for (auto& n : nodes) {
|
||||||
Vector2D offset = {};
|
Vector2D offset = {};
|
||||||
if (n->role->role() == SURFACE_ROLE_SUBSURFACE) {
|
if (n->role->role() == SURFACE_ROLE_SUBSURFACE) {
|
||||||
auto subsurface = (CWLSubsurfaceResource*)n->role.get();
|
auto subsurface = ((CSubsurfaceRole*)n->role.get())->subsurface.lock();
|
||||||
offset = subsurface->posRelativeToParent();
|
offset = subsurface->posRelativeToParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +288,8 @@ void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std
|
||||||
for (auto& c : n->subsurfaces) {
|
for (auto& c : n->subsurfaces) {
|
||||||
if (c->zIndex < 0)
|
if (c->zIndex < 0)
|
||||||
continue;
|
continue;
|
||||||
|
if (c->surface.expired())
|
||||||
|
continue;
|
||||||
nodes2.push_back(c->surface.lock());
|
nodes2.push_back(c->surface.lock());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,8 +335,6 @@ void CWLSurfaceResource::map() {
|
||||||
|
|
||||||
mapped = true;
|
mapped = true;
|
||||||
|
|
||||||
events.map.emit();
|
|
||||||
|
|
||||||
timespec now;
|
timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
frame(&now);
|
frame(&now);
|
||||||
|
@ -335,7 +349,16 @@ void CWLSurfaceResource::unmap() {
|
||||||
|
|
||||||
mapped = false;
|
mapped = false;
|
||||||
|
|
||||||
events.unmap.emit();
|
// release the buffers.
|
||||||
|
// this is necessary for XWayland to function correctly,
|
||||||
|
// as it does not unmap via the traditional commit(null buffer) method, but via the X11 protocol.
|
||||||
|
releaseBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWLSurfaceResource::releaseBuffers(bool onlyCurrent) {
|
||||||
|
if (!onlyCurrent)
|
||||||
|
dropPendingBuffer();
|
||||||
|
dropCurrentBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::error(int code, const std::string& str) {
|
void CWLSurfaceResource::error(int code, const std::string& str) {
|
||||||
|
@ -360,18 +383,18 @@ CBox CWLSurfaceResource::extends() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D CWLSurfaceResource::sourceSize() {
|
Vector2D CWLSurfaceResource::sourceSize() {
|
||||||
if (!current.buffer)
|
if (!current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (current.viewport.hasSource)
|
if (current.viewport.hasSource)
|
||||||
return current.viewport.source.size();
|
return current.viewport.source.size();
|
||||||
|
|
||||||
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size;
|
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
|
||||||
return trc / current.scale;
|
return trc / current.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
|
CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
|
||||||
if (!current.buffer)
|
if (!current.texture)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
CRegion surfaceDamage = current.damage;
|
CRegion surfaceDamage = current.damage;
|
||||||
|
@ -383,7 +406,7 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
|
||||||
if (current.viewport.hasSource)
|
if (current.viewport.hasSource)
|
||||||
surfaceDamage.translate(current.viewport.source.pos());
|
surfaceDamage.translate(current.viewport.source.pos());
|
||||||
|
|
||||||
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size;
|
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
|
||||||
|
|
||||||
return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage);
|
return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage);
|
||||||
}
|
}
|
||||||
|
@ -406,23 +429,26 @@ void CWLSurfaceResource::commitPendingState() {
|
||||||
pending.damage.clear();
|
pending.damage.clear();
|
||||||
pending.bufferDamage.clear();
|
pending.bufferDamage.clear();
|
||||||
|
|
||||||
if (current.buffer && !bufferReleased) {
|
if (current.texture)
|
||||||
// without previous dolphin et al are weird vvv
|
current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
|
||||||
//CRegion surfaceDamage =
|
|
||||||
// current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage);
|
if (current.buffer && current.buffer->buffer) {
|
||||||
current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this.
|
current.buffer->buffer->update(accumulateCurrentBufferDamage());
|
||||||
|
|
||||||
|
// if the surface is a cursor, update the shm buffer
|
||||||
|
// TODO: don't update the entire texture
|
||||||
|
if (role->role() == SURFACE_ROLE_CURSOR)
|
||||||
|
updateCursorShm();
|
||||||
|
|
||||||
// release the buffer if it's synchronous as update() has done everything thats needed
|
// release the buffer if it's synchronous as update() has done everything thats needed
|
||||||
// so we can let the app know we're done.
|
// so we can let the app know we're done.
|
||||||
if (current.buffer->isSynchronous()) {
|
if (current.buffer->buffer->isSynchronous())
|
||||||
current.buffer->sendReleaseWithSurface(self.lock());
|
dropCurrentBuffer();
|
||||||
bufferReleased = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we should _accumulate_ and not replace above if sync
|
// TODO: we should _accumulate_ and not replace above if sync
|
||||||
if (role->role() == SURFACE_ROLE_SUBSURFACE) {
|
if (role->role() == SURFACE_ROLE_SUBSURFACE) {
|
||||||
auto subsurface = (CWLSubsurfaceResource*)role.get();
|
auto subsurface = ((CSubsurfaceRole*)role.get())->subsurface.lock();
|
||||||
if (subsurface->sync)
|
if (subsurface->sync)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -432,7 +458,7 @@ void CWLSurfaceResource::commitPendingState() {
|
||||||
breadthfirst(
|
breadthfirst(
|
||||||
[](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) {
|
[](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) {
|
||||||
if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) {
|
if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) {
|
||||||
auto subsurface = (CWLSubsurfaceResource*)surf->role.get();
|
auto subsurface = ((CSubsurfaceRole*)surf->role.get())->subsurface.lock();
|
||||||
if (!subsurface->sync)
|
if (!subsurface->sync)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -442,28 +468,44 @@ void CWLSurfaceResource::commitPendingState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// for async buffers, we can only release the buffer once we are unrefing it from current.
|
// for async buffers, we can only release the buffer once we are unrefing it from current.
|
||||||
if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) {
|
// if the backend took it, ref it with the lambda. Otherwise, the end of this scope will release it.
|
||||||
if (previousBuffer->lockedByBackend) {
|
if (previousBuffer && previousBuffer->buffer && !previousBuffer->buffer->isSynchronous()) {
|
||||||
previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) {
|
if (previousBuffer->buffer->lockedByBackend && !previousBuffer->buffer->hlEvents.backendRelease) {
|
||||||
if (!self.expired()) // could be dead in the dtor
|
previousBuffer->buffer->lock();
|
||||||
previousBuffer->sendReleaseWithSurface(self.lock());
|
previousBuffer->buffer->unlockOnBufferRelease(self);
|
||||||
else
|
|
||||||
previousBuffer->sendRelease();
|
|
||||||
previousBuffer->hlEvents.backendRelease.reset();
|
|
||||||
bufferReleased = true;
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
previousBuffer->sendReleaseWithSurface(self.lock());
|
|
||||||
|
|
||||||
bufferReleased = true;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastBuffer = current.buffer ? current.buffer->buffer : WP<IHLBuffer>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWLSurfaceResource::updateCursorShm() {
|
||||||
|
auto buf = current.buffer ? current.buffer->buffer : lastBuffer;
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: actually use damage
|
||||||
|
auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock());
|
||||||
|
auto shmAttrs = buf->shm();
|
||||||
|
|
||||||
|
if (!shmAttrs.success) {
|
||||||
|
LOGM(TRACE, "updateCursorShm: ignoring, not a shm buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to end, shm.
|
||||||
|
auto [pixelData, fmt, bufLen] = buf->beginDataPtr(0);
|
||||||
|
|
||||||
|
shmData.resize(bufLen);
|
||||||
|
memcpy(shmData.data(), pixelData, bufLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) {
|
void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) {
|
||||||
frame(when);
|
frame(when);
|
||||||
auto FEEDBACK = makeShared<CQueuedPresentationData>(self.lock());
|
auto FEEDBACK = makeShared<CQueuedPresentationData>(self.lock());
|
||||||
FEEDBACK->attachMonitor(pMonitor);
|
FEEDBACK->attachMonitor(pMonitor);
|
||||||
FEEDBACK->discarded();
|
FEEDBACK->presented();
|
||||||
PROTO::presentation->queueData(FEEDBACK);
|
PROTO::presentation->queueData(FEEDBACK);
|
||||||
|
|
||||||
if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync)
|
if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync)
|
||||||
|
|
|
@ -87,10 +87,10 @@ class CWLSurfaceResource {
|
||||||
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
|
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
|
||||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
int scale = 1;
|
int scale = 1;
|
||||||
SP<IHLBuffer> buffer;
|
SP<CHLBufferReference> buffer; // buffer ref will be released once the buffer is no longer locked. For checking if a buffer is attached to this state, check texture.
|
||||||
SP<CTexture> texture;
|
SP<CTexture> texture;
|
||||||
Vector2D offset;
|
Vector2D offset;
|
||||||
Vector2D size;
|
Vector2D size, bufferSize;
|
||||||
struct {
|
struct {
|
||||||
bool hasDestination = false;
|
bool hasDestination = false;
|
||||||
bool hasSource = false;
|
bool hasSource = false;
|
||||||
|
@ -116,7 +116,7 @@ class CWLSurfaceResource {
|
||||||
std::vector<WP<CMonitor>> enteredOutputs;
|
std::vector<WP<CMonitor>> enteredOutputs;
|
||||||
bool mapped = false;
|
bool mapped = false;
|
||||||
std::vector<WP<CWLSubsurfaceResource>> subsurfaces;
|
std::vector<WP<CWLSubsurfaceResource>> subsurfaces;
|
||||||
WP<ISurfaceRole> role;
|
SP<ISurfaceRole> role;
|
||||||
WP<CViewportResource> viewportResource;
|
WP<CViewportResource> viewportResource;
|
||||||
WP<CDRMSyncobjSurfaceResource> syncobj; // may not be present
|
WP<CDRMSyncobjSurfaceResource> syncobj; // may not be present
|
||||||
|
|
||||||
|
@ -134,14 +134,21 @@ class CWLSurfaceResource {
|
||||||
SP<CWlSurface> resource;
|
SP<CWlSurface> resource;
|
||||||
wl_client* pClient = nullptr;
|
wl_client* pClient = nullptr;
|
||||||
|
|
||||||
// tracks whether we should release the buffer
|
// this is for cursor dumb copy. Due to our (and wayland's...) architecture,
|
||||||
bool bufferReleased = false;
|
// this stupid-ass hack is used
|
||||||
|
WP<IHLBuffer> lastBuffer;
|
||||||
|
|
||||||
int stateLocks = 0;
|
int stateLocks = 0;
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
void releaseBuffers(bool onlyCurrent = true);
|
||||||
|
void dropPendingBuffer();
|
||||||
|
void dropCurrentBuffer();
|
||||||
void commitPendingState();
|
void commitPendingState();
|
||||||
void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
|
void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
|
||||||
|
void updateCursorShm();
|
||||||
|
|
||||||
|
friend class CWLPointerResource;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CWLCompositorResource {
|
class CWLCompositorResource {
|
||||||
|
|
|
@ -469,12 +469,12 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
|
||||||
if (dragSurface) {
|
if (dragSurface) {
|
||||||
dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); });
|
dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); });
|
||||||
dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) {
|
dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) {
|
||||||
if (dnd.dndSurface->current.buffer && !dnd.dndSurface->mapped) {
|
if (dnd.dndSurface->current.texture && !dnd.dndSurface->mapped) {
|
||||||
dnd.dndSurface->map();
|
dnd.dndSurface->map();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dnd.dndSurface->current.buffer <= 0 && dnd.dndSurface->mapped) {
|
if (dnd.dndSurface->current.texture <= 0 && dnd.dndSurface->mapped) {
|
||||||
dnd.dndSurface->unmap();
|
dnd.dndSurface->unmap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -660,13 +660,13 @@ void CWLDataDeviceProtocol::abortDrag() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
|
void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
|
||||||
if (!dnd.dndSurface || !dnd.dndSurface->current.buffer || !dnd.dndSurface->current.buffer->texture)
|
if (!dnd.dndSurface || !dnd.dndSurface->current.texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto POS = g_pInputManager->getMouseCoordsInternal();
|
const auto POS = g_pInputManager->getMouseCoordsInternal();
|
||||||
|
|
||||||
CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale);
|
CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale);
|
||||||
g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.buffer->texture, &box, 1.F);
|
g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.texture, &box, 1.F);
|
||||||
|
|
||||||
box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F);
|
box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F);
|
||||||
g_pHyprRenderer->damageBox(&box);
|
g_pHyprRenderer->damageBox(&box);
|
||||||
|
|
|
@ -49,7 +49,7 @@ SP<CWlOutput> CWLOutputResource::getResource() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLOutputResource::updateState() {
|
void CWLOutputResource::updateState() {
|
||||||
if (!monitor)
|
if (!monitor || (owner && owner->defunct))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (resource->version() >= 2)
|
if (resource->version() >= 2)
|
||||||
|
@ -84,6 +84,7 @@ void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver,
|
||||||
}
|
}
|
||||||
|
|
||||||
RESOURCE->self = RESOURCE;
|
RESOURCE->self = RESOURCE;
|
||||||
|
RESOURCE->owner = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) {
|
void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "../../helpers/signal/Signal.hpp"
|
#include "../../helpers/signal/Signal.hpp"
|
||||||
|
|
||||||
class CMonitor;
|
class CMonitor;
|
||||||
|
class CWLOutputProtocol;
|
||||||
|
|
||||||
class CWLOutputResource {
|
class CWLOutputResource {
|
||||||
public:
|
public:
|
||||||
|
@ -20,7 +21,7 @@ class CWLOutputResource {
|
||||||
void updateState();
|
void updateState();
|
||||||
|
|
||||||
WP<CMonitor> monitor;
|
WP<CMonitor> monitor;
|
||||||
|
WP<CWLOutputProtocol> owner;
|
||||||
WP<CWLOutputResource> self;
|
WP<CWLOutputResource> self;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -40,6 +41,7 @@ class CWLOutputProtocol : public IWaylandProtocol {
|
||||||
void sendDone();
|
void sendDone();
|
||||||
|
|
||||||
WP<CMonitor> monitor;
|
WP<CMonitor> monitor;
|
||||||
|
WP<CWLOutputProtocol> self;
|
||||||
|
|
||||||
// will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global)
|
// will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global)
|
||||||
void remove();
|
void remove();
|
||||||
|
@ -61,5 +63,5 @@ class CWLOutputProtocol : public IWaylandProtocol {
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace PROTO {
|
namespace PROTO {
|
||||||
inline std::unordered_map<std::string, UP<CWLOutputProtocol>> outputs;
|
inline std::unordered_map<std::string, SP<CWLOutputProtocol>> outputs;
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue