Merge branch 'hyprwm:main' into feature/cornerRadii

This commit is contained in:
Micovec 2024-02-02 17:42:36 +01:00 committed by GitHub
commit fc5d1e4aa7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
69 changed files with 998 additions and 619 deletions

View file

@ -58,7 +58,7 @@ ExternalProject_Add(
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
BUILD_COMMAND ninja -C build BUILD_COMMAND ninja -C build
BUILD_ALWAYS true BUILD_ALWAYS true
BUILD_IN_SOURCE true BUILD_IN_SOURCE true

View file

@ -1,22 +1,22 @@
PREFIX = /usr/local PREFIX = /usr/local
legacyrenderer: legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build chmod -R 777 ./build
legacyrendererdebug: legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build chmod -R 777 ./build
release: release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build chmod -R 777 ./build
debug: debug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build chmod -R 777 ./build
@ -45,7 +45,7 @@ install:
cd ${PREFIX}/bin && ln -sf Hyprland hyprland cd ${PREFIX}/bin && ln -sf Hyprland hyprland
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
mkdir -p ${PREFIX}/share/hyprland mkdir -p ${PREFIX}/share/hyprland
cp ./assets/wall_* ${PREFIX}/share/hyprland cp ./assets/wall* ${PREFIX}/share/hyprland
mkdir -p ${PREFIX}/share/xdg-desktop-portal mkdir -p ${PREFIX}/share/xdg-desktop-portal
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
@ -60,6 +60,7 @@ install:
uninstall: uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland rm -f ${PREFIX}/bin/Hyprland
rm -f ${PREFIX}/bin/hyprland
rm -f ${PREFIX}/bin/hyprctl rm -f ${PREFIX}/bin/hyprctl
rm -f ${PREFIX}/bin/hyprpm rm -f ${PREFIX}/bin/hyprpm
rm -f ${PREFIX}/lib/libwlroots.so.13032 rm -f ${PREFIX}/lib/libwlroots.so.13032

View file

@ -1,9 +1,7 @@
wallpaper_types = ['', 'anime_', 'anime2_'] wallpapers = ['0', '1', '2']
foreach type : wallpaper_types foreach type : wallpapers
foreach size : [2, 4, 8] install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
install_data(f'wall_@type@@size@K.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
endforeach
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')

BIN
assets/wall0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

BIN
assets/wall1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

BIN
assets/wall2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -112,7 +112,7 @@ gestures {
misc { misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more # See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
} }
# Example per-device config # Example per-device config

View file

@ -25,7 +25,10 @@
}, },
"hyprlang": { "hyprlang": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_2" "nixpkgs": [
"xdph",
"nixpkgs"
]
}, },
"locked": { "locked": {
"lastModified": 1704287638, "lastModified": 1704287638,
@ -43,27 +46,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1704194953, "lastModified": 1706191920,
"narHash": "sha256-RtDKd8Mynhe5CFnVT8s0/0yqtWFMM9LmCzXv/YKxnq4=", "narHash": "sha256-eLihrZAPZX0R6RyM5fYAWeKVNuQPYjAkCUBr+JNvtdE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "bd645e8668ec6612439a9ee7e71f7eac4099d4f6", "rev": "ae5c332cbb5827f6b1f02572496b141021de335f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1702645756,
"narHash": "sha256-qKI6OR3TYJYQB3Q8mAZ+DG4o/BR9ptcv9UnRV2hzljc=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "40c3c94c241286dd2243ea34d3aef8a488f9e4d0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -101,18 +88,18 @@
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"lastModified": 1703963193, "lastModified": 1706359063,
"narHash": "sha256-ke8drv6PTrdQDruWbajrRJffP9A9PU6FRyjJGNZRTs4=", "narHash": "sha256-5HUTG0p+nCJv3cn73AmFHRZdfRV5AD5N43g8xAePSKM=",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "f81c3d93cd6f61b20ae784297679283438def8df", "rev": "00b869c1a96f300a8f25da95d624524895e0ddf2",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "f81c3d93cd6f61b20ae784297679283438def8df", "rev": "00b869c1a96f300a8f25da95d624524895e0ddf2",
"type": "gitlab" "type": "gitlab"
} }
}, },
@ -130,11 +117,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1704400467, "lastModified": 1706145785,
"narHash": "sha256-IsEAKBCorRlN53FwFAMbyGLRsPVu/ZrWEJtCwykPds8=", "narHash": "sha256-j9MP4fv2U/vdRKAXXc2gyMTmYwVnHP6kHx1/y6jprrU=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "1c802128f6cc3db29a8ef01552b1a22f894eeefd", "rev": "5a592647587cd20b9692a347df6939b6d371b3bb",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -12,7 +12,7 @@
host = "gitlab.freedesktop.org"; host = "gitlab.freedesktop.org";
owner = "wlroots"; owner = "wlroots";
repo = "wlroots"; repo = "wlroots";
rev = "f81c3d93cd6f61b20ae784297679283438def8df"; rev = "00b869c1a96f300a8f25da95d624524895e0ddf2";
flake = false; flake = false;
}; };
@ -86,6 +86,7 @@
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [cmake python3]; nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
buildInputs = [self.packages.${system}.wlroots-hyprland]; buildInputs = [self.packages.${system}.wlroots-hyprland];
hardeningDisable = [ "fortify" ];
inputsFrom = [ inputsFrom = [
self.packages.${system}.wlroots-hyprland self.packages.${system}.wlroots-hyprland
self.packages.${system}.hyprland self.packages.${system}.hyprland

View file

@ -20,11 +20,18 @@ std::string DataState::getDataStatePath() {
return std::string{HOME} + "/.local/share/hyprpm"; return std::string{HOME} + "/.local/share/hyprpm";
} }
std::string DataState::getHeadersPath() {
return getDataStatePath() + "/headersRoot";
}
void DataState::ensureStateStoreExists() { void DataState::ensureStateStoreExists() {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
if (!std::filesystem::exists(PATH)) if (!std::filesystem::exists(PATH))
std::filesystem::create_directories(PATH); std::filesystem::create_directories(PATH);
if (!std::filesystem::exists(getHeadersPath()))
std::filesystem::create_directories(getHeadersPath());
} }
void DataState::addNewPluginRepo(const SPluginRepository& repo) { void DataState::addNewPluginRepo(const SPluginRepository& repo) {
@ -64,7 +71,10 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) { for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory()) if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue; continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml"); auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@ -85,7 +95,10 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) { for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory()) if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue; continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml"); auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@ -154,7 +167,10 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
std::vector<SPluginRepository> repos; std::vector<SPluginRepository> repos;
for (const auto& entry : std::filesystem::directory_iterator(PATH)) { for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory()) if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue; continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml"); auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
@ -191,7 +207,10 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
for (const auto& entry : std::filesystem::directory_iterator(PATH)) { for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
if (!entry.is_directory()) if (!entry.is_directory() || entry.path().stem() == "headersRoot")
continue;
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
continue; continue;
auto STATE = toml::parse_file(entry.path().string() + "/state.toml"); auto STATE = toml::parse_file(entry.path().string() + "/state.toml");

View file

@ -10,6 +10,7 @@ struct SGlobalState {
namespace DataState { namespace DataState {
std::string getDataStatePath(); std::string getDataStatePath();
std::string getHeadersPath();
void ensureStateStoreExists(); void ensureStateStoreExists();
void addNewPluginRepo(const SPluginRepository& repo); void addNewPluginRepo(const SPluginRepository& repo);
void removePluginRepo(const std::string& urlOrName); void removePluginRepo(const std::string& urlOrName);

View file

@ -10,6 +10,7 @@
#include <thread> #include <thread>
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include <format>
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
@ -78,6 +79,8 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
bool CPluginManager::addNewPluginRepo(const std::string& url) { bool CPluginManager::addNewPluginRepo(const std::string& url) {
const auto HLVER = getHyprlandVersion();
if (DataState::pluginRepoExists(url)) { if (DataState::pluginRepoExists(url)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n"; std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
return false; return false;
@ -170,6 +173,22 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
message += " version " + pl.version; message += " version " + pl.version;
progress.printMessageAbove(message); progress.printMessageAbove(message);
} }
if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash)
continue;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd /tmp/hyprpm/new/ && git reset --hard --recurse-submodules " + plugin);
}
}
progress.m_szCurrentMessage = "Verifying headers"; progress.m_szCurrentMessage = "Verifying headers";
progress.print(); progress.print();
@ -191,7 +210,8 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) { for (auto& bs : p.buildSteps) {
out += execAndGet("cd /tmp/hyprpm/new && " + bs) + "\n"; std::string cmd = std::format("cd /tmp/hyprpm/new && PKG_CONFIG_PATH=\"{}\" {}", DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) { if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
@ -265,8 +285,12 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
eHeadersErrors CPluginManager::headersValid() { eHeadersErrors CPluginManager::headersValid() {
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
return HEADERS_MISSING;
// find headers commit // find headers commit
auto headers = execAndGet("pkg-config --cflags --keep-system-cflags hyprland"); std::string cmd = std::format("PKG_CONFIG_PATH={}/share/pkgconfig pkg-config --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/")) if (!headers.contains("-I/"))
return HEADERS_MISSING; return HEADERS_MISSING;
@ -298,10 +322,6 @@ eHeadersErrors CPluginManager::headersValid() {
if (!ifs.good()) if (!ifs.good())
return HEADERS_CORRUPTED; return HEADERS_CORRUPTED;
if ((std::filesystem::exists("/usr/include/hyprland/src/version.h") && verHeader != "/usr/include/hyprland/src/version.h") ||
(std::filesystem::exists("/usr/local/include/hyprland/src/version.h") && verHeader != "/usr/local/include/hyprland/src/version.h"))
return HEADERS_DUPLICATED;
std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>())); std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
ifs.close(); ifs.close();
@ -316,7 +336,9 @@ eHeadersErrors CPluginManager::headersValid() {
return HEADERS_OK; return HEADERS_OK;
} }
bool CPluginManager::updateHeaders() { bool CPluginManager::updateHeaders(bool force) {
DataState::ensureStateStoreExists();
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
@ -325,11 +347,8 @@ bool CPluginManager::updateHeaders() {
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} }
if (headersValid() == HEADERS_OK) { if (!force && headersValid() == HEADERS_OK) {
std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Your headers are already up-to-date.\n"; std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Headers up to date.\n";
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
return true; return true;
} }
@ -371,23 +390,38 @@ bool CPluginManager::updateHeaders() {
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland"); progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
ret = execAndGet("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja"); if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
ret = execAndGet(
std::format("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja",
DataState::getHeadersPath()));
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
// le hack. Wlroots has to generate its build/include // le hack. Wlroots has to generate its build/include
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build"); ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build");
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland"); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland");
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
progress.printMessageAbove( // progress.printMessageAbove(
std::string{Colors::YELLOW} + "!" + Colors::RESET + // std::string{Colors::YELLOW} + "!" + Colors::RESET +
" in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running."); // " in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
ret = execAndGet("pkexec sh \"-c\" \"cd /tmp/hyprpm/hyprland && make installheaders\""); std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" /tmp/hyprpm/hyprland/Makefile && cd /tmp/hyprpm/hyprland && make installheaders",
DataState::getHeadersPath());
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
ret = execAndGet(cmd);
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "pkexec returned: " << ret << "\n"; std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
// remove build files // remove build files
std::filesystem::remove_all("/tmp/hyprpm/hyprland"); std::filesystem::remove_all("/tmp/hyprpm/hyprland");
@ -399,10 +433,6 @@ bool CPluginManager::updateHeaders() {
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
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));
@ -436,7 +466,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
CProgressBar progress; CProgressBar progress;
progress.m_iMaxSteps = REPOS.size() * 2 + 1; progress.m_iMaxSteps = REPOS.size() * 2 + 2;
progress.m_iSteps = 0; progress.m_iSteps = 0;
progress.m_szCurrentMessage = "Updating repositories"; progress.m_szCurrentMessage = "Updating repositories";
progress.print(); progress.print();
@ -530,7 +560,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) { for (auto& bs : p.buildSteps) {
out += execAndGet("cd /tmp/hyprpm/update && " + bs) + "\n"; std::string cmd = std::format("cd /tmp/hyprpm/update && PKG_CONFIG_PATH=\"{}\" {}", DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) { if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
@ -568,6 +599,14 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " updated " + repo.name); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " updated " + repo.name);
} }
progress.m_iSteps++;
progress.m_szCurrentMessage = "Updating global state...";
progress.print();
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
progress.m_iSteps++; progress.m_iSteps++;
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();

View file

@ -40,7 +40,7 @@ class CPluginManager {
bool removePluginRepo(const std::string& urlOrName); bool removePluginRepo(const std::string& urlOrName);
eHeadersErrors headersValid(); eHeadersErrors headersValid();
bool updateHeaders(); bool updateHeaders(bool force = false);
bool updatePlugins(bool forceUpdateAll); bool updatePlugins(bool forceUpdateAll);
void listAllPlugins(); void listAllPlugins();

View file

@ -1,6 +1,7 @@
#include "progress/CProgressBar.hpp" #include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp" #include "helpers/Colors.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
@ -23,6 +24,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
--notify | -n Send a hyprland notification for important events (e.g. load fail) --notify | -n Send a hyprland notification for important events (e.g. load fail)
--help | -h Show this menu --help | -h Show this menu
--verbose | -v Enable too much logging --verbose | -v Enable too much logging
--force | -f Force an operation ignoring checks (e.g. update -f)
)#"; )#";
@ -38,7 +40,7 @@ int main(int argc, char** argv, char** envp) {
} }
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, verbose = false; bool notify = false, verbose = false, force = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
@ -49,6 +51,9 @@ int main(int argc, char** argv, char** envp) {
notify = true; notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true; verbose = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else { } else {
std::cerr << "Unrecognized option " << ARGS[i]; std::cerr << "Unrecognized option " << ARGS[i];
return 1; return 1;
@ -82,9 +87,13 @@ int main(int argc, char** argv, char** envp) {
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1; return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") { } else if (command[0] == "update") {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK; bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(); bool headers = g_pPluginManager->updateHeaders(force);
if (headers) { if (headers) {
bool ret1 = g_pPluginManager->updatePlugins(!headersValid); const auto HLVER = g_pPluginManager->getHyprlandVersion();
auto GLOBALSTATE = DataState::getGlobalState();
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
if (!ret1) if (!ret1)
return 1; return 1;

View file

@ -10,19 +10,16 @@
(builtins.substring 4 2 longDate) (builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate) (builtins.substring 6 2 longDate)
]); ]);
mkJoinedOverlays = overlays: final: prev:
lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
in { in {
# Contains what a user is most likely to care about: # Contains what a user is most likely to care about:
# Hyprland itself, XDPH and the Share Picker. # Hyprland itself, XDPH and the Share Picker.
default = mkJoinedOverlays (with self.overlays; [ default = lib.composeManyExtensions (with self.overlays; [
hyprland-packages hyprland-packages
hyprland-extras hyprland-extras
]); ]);
# Packages for variations of Hyprland, dependencies included. # Packages for variations of Hyprland, dependencies included.
hyprland-packages = mkJoinedOverlays [ hyprland-packages = lib.composeManyExtensions [
# Dependencies # Dependencies
inputs.hyprland-protocols.overlays.default inputs.hyprland-protocols.overlays.default
self.overlays.wlroots-hyprland self.overlays.wlroots-hyprland
@ -34,7 +31,7 @@ in {
hyprland = final.callPackage ./default.nix { hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv; stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}"; version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
wlroots = final.wlroots-hyprland; wlroots = prev.wlroots-hyprland;
commit = self.rev or ""; commit = self.rev or "";
inherit (final) udis86 hyprland-protocols; inherit (final) udis86 hyprland-protocols;
inherit date; inherit date;
@ -59,7 +56,7 @@ in {
# Packages for extra software recommended for usage with Hyprland, # Packages for extra software recommended for usage with Hyprland,
# including forked or patched packages for compatibility. # including forked or patched packages for compatibility.
hyprland-extras = mkJoinedOverlays [ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland inputs.xdph.overlays.xdg-desktop-portal-hyprland
]; ];

View file

@ -8,7 +8,7 @@ CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
if [ "$SUB_REV" != "$CRT_REV" ]; then if [ "$SUB_REV" != "$CRT_REV" ]; then
echo "Updating wlroots..." echo "Updating wlroots..."
# update wlroots to submodule revision # update wlroots to submodule revision
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix subprojects/wlroots.wrap sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix
nix flake lock nix flake lock
echo "wlroots: $CRT_REV -> $SUB_REV" echo "wlroots: $CRT_REV -> $SUB_REV"

View file

@ -1,5 +1,5 @@
wayland_protos = dependency('wayland-protocols', wayland_protos = dependency('wayland-protocols',
version: '>=1.25', version: '>=1.32',
fallback: 'wayland-protocols', fallback: 'wayland-protocols',
default_options: ['tests=false'], default_options: ['tests=false'],
) )

View file

@ -81,26 +81,6 @@ CCompositor::CCompositor() {
CCompositor::~CCompositor() { CCompositor::~CCompositor() {
cleanup(); cleanup();
g_pDecorationPositioner.reset();
g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset();
g_pEventManager.reset();
g_pSessionLockManager.reset();
g_pProtocolManager.reset();
g_pXWaylandManager.reset();
g_pHyprRenderer.reset();
g_pHyprOpenGL.reset();
g_pInputManager.reset();
g_pThreadManager.reset();
g_pConfigManager.reset();
g_pLayoutManager.reset();
g_pHyprError.reset();
g_pConfigManager.reset();
g_pAnimationManager.reset();
g_pKeybindManager.reset();
g_pHookSystem.reset();
g_pWatchdog.reset();
} }
void CCompositor::setRandomSplash() { void CCompositor::setRandomSplash() {
@ -135,10 +115,10 @@ void CCompositor::initServer() {
else else
wlr_log_init(WLR_ERROR, Debug::wlrLog); wlr_log_init(WLR_ERROR, Debug::wlrLog);
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession); m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession);
if (!m_sWLRBackend) { if (!m_sWLRBackend) {
Debug::log(CRIT, "m_sWLRBackend was NULL!"); Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_backend_autocreate() failed!"); throwError("wlr_backend_autocreate() failed!");
} }
@ -151,7 +131,7 @@ void CCompositor::initServer() {
m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD); m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
if (!m_sWLRRenderer) { if (!m_sWLRRenderer) {
Debug::log(CRIT, "m_sWLRRenderer was NULL!"); Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!"); throwError("wlr_gles2_renderer_create_with_drm_fd() failed!");
} }
@ -259,7 +239,7 @@ void CCompositor::initServer() {
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay); m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay); m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop);
m_sWLRSessionLockMgr = wlr_session_lock_manager_v1_create(m_sWLDisplay); m_sWLRSessionLockMgr = wlr_session_lock_manager_v1_create(m_sWLDisplay);
@ -332,6 +312,59 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session"); addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
} }
void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_newOutput);
removeWLSignal(&Events::listen_newXDGToplevel);
removeWLSignal(&Events::listen_mouseMove);
removeWLSignal(&Events::listen_mouseMoveAbsolute);
removeWLSignal(&Events::listen_mouseButton);
removeWLSignal(&Events::listen_mouseAxis);
removeWLSignal(&Events::listen_mouseFrame);
removeWLSignal(&Events::listen_swipeBegin);
removeWLSignal(&Events::listen_swipeUpdate);
removeWLSignal(&Events::listen_swipeEnd);
removeWLSignal(&Events::listen_pinchBegin);
removeWLSignal(&Events::listen_pinchUpdate);
removeWLSignal(&Events::listen_pinchEnd);
removeWLSignal(&Events::listen_touchBegin);
removeWLSignal(&Events::listen_touchEnd);
removeWLSignal(&Events::listen_touchUpdate);
removeWLSignal(&Events::listen_touchFrame);
removeWLSignal(&Events::listen_holdBegin);
removeWLSignal(&Events::listen_holdEnd);
removeWLSignal(&Events::listen_newInput);
removeWLSignal(&Events::listen_requestMouse);
removeWLSignal(&Events::listen_requestSetSel);
removeWLSignal(&Events::listen_requestDrag);
removeWLSignal(&Events::listen_startDrag);
removeWLSignal(&Events::listen_requestSetSel);
removeWLSignal(&Events::listen_requestSetPrimarySel);
removeWLSignal(&Events::listen_newLayerSurface);
removeWLSignal(&Events::listen_change);
removeWLSignal(&Events::listen_outputMgrApply);
removeWLSignal(&Events::listen_outputMgrTest);
removeWLSignal(&Events::listen_newConstraint);
removeWLSignal(&Events::listen_NewXDGDeco);
removeWLSignal(&Events::listen_newVirtPtr);
removeWLSignal(&Events::listen_newVirtualKeyboard);
removeWLSignal(&Events::listen_RendererDestroy);
removeWLSignal(&Events::listen_newIdleInhibitor);
removeWLSignal(&Events::listen_powerMgrSetMode);
removeWLSignal(&Events::listen_newIME);
removeWLSignal(&Events::listen_newTextInput);
removeWLSignal(&Events::listen_activateXDG);
removeWLSignal(&Events::listen_newSessionLock);
removeWLSignal(&Events::listen_setGamma);
removeWLSignal(&Events::listen_setCursorShape);
removeWLSignal(&Events::listen_newTearingHint);
if (m_sWRLDRMLeaseMgr)
removeWLSignal(&Events::listen_leaseRequest);
if (m_sWLRSession)
removeWLSignal(&Events::listen_sessionActive);
}
void CCompositor::cleanup() { void CCompositor::cleanup() {
if (!m_sWLDisplay || m_bIsShuttingDown) if (!m_sWLDisplay || m_bIsShuttingDown)
return; return;
@ -362,8 +395,8 @@ void CCompositor::cleanup() {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
g_pHyprOpenGL->destroyMonitorResources(m.get()); g_pHyprOpenGL->destroyMonitorResources(m.get());
wlr_output_enable(m->output, false); wlr_output_state_set_enabled(m->state.wlr(), false);
wlr_output_commit(m->output); m->state.commit();
} }
m_vMonitors.clear(); m_vMonitors.clear();
@ -373,8 +406,31 @@ void CCompositor::cleanup() {
g_pXWaylandManager->m_sWLRXWayland = nullptr; g_pXWaylandManager->m_sWLRXWayland = nullptr;
} }
removeAllSignals();
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay); wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
g_pDecorationPositioner.reset();
g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset();
g_pEventManager.reset();
g_pSessionLockManager.reset();
g_pProtocolManager.reset();
g_pHyprRenderer.reset();
g_pHyprOpenGL.reset();
g_pInputManager.reset();
g_pThreadManager.reset();
g_pConfigManager.reset();
g_pLayoutManager.reset();
g_pHyprError.reset();
g_pConfigManager.reset();
g_pAnimationManager.reset();
g_pKeybindManager.reset();
g_pHookSystem.reset();
g_pWatchdog.reset();
g_pXWaylandManager.reset();
wl_display_terminate(m_sWLDisplay); wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr; m_sWLDisplay = nullptr;
@ -654,6 +710,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue; static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue; static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
static auto* const PSPECIALFALLTHRU = &g_pConfigManager->getConfigValuePtr("input:special_fallthrough")->intValue;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0; const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
// pinned windows on top of floating regardless // pinned windows on top of floating regardless
@ -735,9 +792,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
}; };
// special workspace // special workspace
if (PMONITOR->specialWorkspaceID) if (PMONITOR->specialWorkspaceID && !*PSPECIALFALLTHRU)
return windowForWorkspace(true); return windowForWorkspace(true);
if (PMONITOR->specialWorkspaceID) {
const auto PWINDOW = windowForWorkspace(true);
if (PWINDOW)
return PWINDOW;
}
return windowForWorkspace(false); return windowForWorkspace(false);
} }
@ -876,13 +940,19 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PSPECIALFALLTHROUGH = &g_pConfigManager->getConfigValuePtr("input:special_fallthrough")->intValue;
if (g_pCompositor->m_sSeat.exclusiveClient) { if (g_pCompositor->m_sSeat.exclusiveClient) {
Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer."); Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer.");
return; return;
} }
if (!g_pInputManager->m_dExclusiveLSes.empty()) {
Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls");
return;
}
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow); g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
if (!pWindow || !windowValidMapped(pWindow)) { if (!pWindow || !windowValidMapped(pWindow)) {
@ -943,7 +1013,9 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
const auto PLASTWINDOW = m_pLastWindow; const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = pWindow; m_pLastWindow = pWindow;
if (PMONITOR->specialWorkspaceID && PMONITOR->specialWorkspaceID != pWindow->m_iWorkspaceID) /* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
window focuses are "via keybinds" and which ones aren't. */
if (PMONITOR->specialWorkspaceID && PMONITOR->specialWorkspaceID != pWindow->m_iWorkspaceID && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window // we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
@ -1091,14 +1163,6 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
auto SURFACEAT = wlr_layer_surface_v1_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y); auto SURFACEAT = wlr_layer_surface_v1_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y);
if (ls->layerSurface->current.keyboard_interactive && ls->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
if (!SURFACEAT)
SURFACEAT = ls->layerSurface->surface;
*ppLayerSurfaceFound = ls.get();
return SURFACEAT;
}
if (SURFACEAT) { if (SURFACEAT) {
if (!pixman_region32_not_empty(&SURFACEAT->input_region)) if (!pixman_region32_not_empty(&SURFACEAT->input_region))
continue; continue;
@ -1881,15 +1945,13 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
if (pWindow == m_pLastWindow) { if (pWindow == m_pLastWindow) {
const auto* const ACTIVECOLOR = const auto* const ACTIVECOLOR =
!pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL); !pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying() >= 0 ? setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying().m_vColors.empty() ? *ACTIVECOLOR :
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying())) : pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying());
*ACTIVECOLOR);
} else { } else {
const auto* const INACTIVECOLOR = const auto* const INACTIVECOLOR =
!pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL); !pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying() >= 0 ? setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying().m_vColors.empty() ? *INACTIVECOLOR :
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) : pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying());
*INACTIVECOLOR);
} }
} }
@ -2113,7 +2175,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
return nullptr; return nullptr;
} }
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor) { void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor, bool noWarpCursor) {
// We trust the workspace and monitor to be correct. // We trust the workspace and monitor to be correct.
@ -2199,7 +2261,8 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
pWorkspace->startAnim(true, true, true); pWorkspace->startAnim(true, true, true);
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2); if (!noWarpCursor)
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
g_pInputManager->sendMotionEventsToFocused(); g_pInputManager->sendMotionEventsToFocused();
} }
@ -2607,11 +2670,7 @@ int CCompositor::getNewSpecialID() {
} }
void CCompositor::performUserChecks() { void CCompositor::performUserChecks() {
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && !envEnabled("WLR_DRM_NO_ATOMIC")) { ; // intentional
g_pHyprNotificationOverlay->addNotification("You have enabled tearing, but immediate presentations are not available on your configuration. Try adding "
"env = WLR_DRM_NO_ATOMIC,1 to your config.",
CColor(0), 15000, ICON_WARNING);
}
} }
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) { void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) {
@ -2786,10 +2845,27 @@ void CCompositor::leaveUnsafeState() {
void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) { void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) {
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(pSurface, scale); g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(pSurface, scale);
wlr_surface_set_preferred_buffer_scale(pSurface, static_cast<int32_t>(std::ceil(scale))); wlr_surface_set_preferred_buffer_scale(pSurface, static_cast<int32_t>(std::ceil(scale)));
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
if (!PSURFACE) {
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface);
return;
}
PSURFACE->m_fLastScale = scale;
PSURFACE->m_iLastScale = static_cast<int32_t>(std::ceil(scale));
} }
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) { void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
wlr_surface_set_preferred_buffer_transform(pSurface, transform); wlr_surface_set_preferred_buffer_transform(pSurface, transform);
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
if (!PSURFACE) {
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface);
return;
}
PSURFACE->m_eLastTransform = transform;
} }
void CCompositor::updateSuspendedStates() { void CCompositor::updateSuspendedStates() {

View file

@ -176,7 +176,7 @@ class CCompositor {
void updateWorkspaceWindows(const int64_t& id); void updateWorkspaceWindows(const int64_t& id);
void updateWindowAnimatedDecorationValues(CWindow*); void updateWindowAnimatedDecorationValues(CWindow*);
int getNextAvailableMonitorID(std::string const& name); int getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*); void moveWorkspaceToMonitor(CWorkspace*, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*); void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&); CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&); bool workspaceIDOutOfBounds(const int64_t&);
@ -214,6 +214,7 @@ class CCompositor {
private: private:
void initAllSignals(); void initAllSignals();
void removeAllSignals();
void setRandomSplash(); void setRandomSplash();
void initManagers(eManagersInitStage stage); void initManagers(eManagersInitStage stage);
void prepareFallbackOutput(); void prepareFallbackOutput();

View file

@ -318,7 +318,7 @@ void CWindow::destroyToplevelHandle() {
} }
void CWindow::updateToplevel() { void CWindow::updateToplevel() {
updateSurfaceOutputs(); updateSurfaceScaleTransformDetails();
if (!m_phForeignToplevel) if (!m_phForeignToplevel)
return; return;
@ -345,8 +345,8 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
wlr_surface_send_leave(pSurface, OUTPUT); wlr_surface_send_leave(pSurface, OUTPUT);
} }
void CWindow::updateSurfaceOutputs() { void CWindow::updateSurfaceScaleTransformDetails() {
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden) if (!m_bIsMapped || m_bHidden)
return; return;
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID); const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
@ -355,16 +355,23 @@ void CWindow::updateSurfaceOutputs() {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled) if (PNEWMONITOR != PLASTMONITOR) {
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output); if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output); wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
}
wlr_surface_for_each_surface( wlr_surface_for_each_surface(
m_pWLSurface.wlr(), m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) { [](wlr_surface* surf, int x, int y, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
return;
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform); g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
}, },
this); this);
@ -511,6 +518,14 @@ void CWindow::onMap() {
"CWindow"); "CWindow");
m_vReportedSize = m_vPendingReportedSize; m_vReportedSize = m_vPendingReportedSize;
for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
continue;
m_bTearingHint = ctrl->pWlrHint->current;
break;
}
} }
void CWindow::onBorderAngleAnimEnd(void* ptr) { void CWindow::onBorderAngleAnimEnd(void* ptr) {
@ -607,14 +622,42 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
m_sAdditionalConfigData.animationStyle = STYLE; m_sAdditionalConfigData.animationStyle = STYLE;
} else if (r.szRule.starts_with("bordercolor")) { } else if (r.szRule.starts_with("bordercolor")) {
try { try {
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); // Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
if (colorPart.contains(' ')) { // Basic form has only two colors, everything else can be parsed as a gradient
// we have a space, 2 values if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' '))); m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0])));
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1)); m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1])));
} else { return;
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart); }
for (auto& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
}
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
else {
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
} }
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "dimaround") { } else if (r.szRule == "dimaround") {
@ -644,8 +687,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} }
void CWindow::updateDynamicRules() { void CWindow::updateDynamicRules() {
m_sSpecialRenderData.activeBorderColor = -1; m_sSpecialRenderData.activeBorderColor = CGradientValueData();
m_sSpecialRenderData.inactiveBorderColor = -1; m_sSpecialRenderData.inactiveBorderColor = CGradientValueData();
m_sSpecialRenderData.alpha = 1.f; m_sSpecialRenderData.alpha = 1.f;
m_sSpecialRenderData.alphaInactive = -1.f; m_sSpecialRenderData.alphaInactive = -1.f;
m_sAdditionalConfigData.forceNoBlur = false; m_sAdditionalConfigData.forceNoBlur = false;
@ -1028,7 +1071,7 @@ int CWindow::getRealBorderSize() {
} }
bool CWindow::canBeTorn() { bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied; return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint);
} }
bool CWindow::shouldSendFullscreenState() { bool CWindow::shouldSendFullscreenState() {

View file

@ -104,13 +104,13 @@ class CWindowOverridableVar {
}; };
struct SWindowSpecialRenderData { struct SWindowSpecialRenderData {
CWindowOverridableVar<bool> alphaOverride = false; CWindowOverridableVar<bool> alphaOverride = false;
CWindowOverridableVar<float> alpha = 1.f; CWindowOverridableVar<float> alpha = 1.f;
CWindowOverridableVar<bool> alphaInactiveOverride = false; CWindowOverridableVar<bool> alphaInactiveOverride = false;
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
CWindowOverridableVar<int64_t> activeBorderColor = -1; // -1 means unset CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
// set by the layout // set by the layout
CWindowOverridableVar<int> borderSize = -1; // -1 means unset CWindowOverridableVar<int> borderSize = -1; // -1 means unset
@ -354,7 +354,7 @@ class CWindow {
void createToplevelHandle(); void createToplevelHandle();
void destroyToplevelHandle(); void destroyToplevelHandle();
void updateToplevel(); void updateToplevel();
void updateSurfaceOutputs(); void updateSurfaceScaleTransformDetails();
void moveToWorkspace(int); void moveToWorkspace(int);
CWindow* X11TransientFor(); CWindow* X11TransientFor();
void onUnmap(); void onUnmap();

View file

@ -17,6 +17,7 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData { class CGradientValueData : public ICustomConfigValueData {
public: public:
CGradientValueData(){};
CGradientValueData(CColor col) { CGradientValueData(CColor col) {
m_vColors.push_back(col); m_vColors.push_back(col);
}; };

View file

@ -101,7 +101,6 @@ void CConfigManager::setDefaultVars() {
configValues["misc:disable_hyprland_logo"].intValue = 0; configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0; configValues["misc:disable_splash_rendering"].intValue = 0;
configValues["misc:force_hypr_chan"].intValue = 0;
configValues["misc:force_default_wallpaper"].intValue = -1; configValues["misc:force_default_wallpaper"].intValue = -1;
configValues["misc:vfr"].intValue = 1; configValues["misc:vfr"].intValue = 1;
configValues["misc:vrr"].intValue = 0; configValues["misc:vrr"].intValue = 0;
@ -140,6 +139,7 @@ void CConfigManager::setDefaultVars() {
configValues["group:groupbar:font_family"].strValue = "Sans"; configValues["group:groupbar:font_family"].strValue = "Sans";
configValues["group:groupbar:font_size"].intValue = 8; configValues["group:groupbar:font_size"].intValue = 8;
configValues["group:groupbar:gradients"].intValue = 1; configValues["group:groupbar:gradients"].intValue = 1;
configValues["group:groupbar:height"].intValue = 14;
configValues["group:groupbar:priority"].intValue = 3; configValues["group:groupbar:priority"].intValue = 3;
configValues["group:groupbar:render_titles"].intValue = 1; configValues["group:groupbar:render_titles"].intValue = 1;
configValues["group:groupbar:scrolling"].intValue = 1; configValues["group:groupbar:scrolling"].intValue = 1;
@ -225,6 +225,7 @@ void CConfigManager::setDefaultVars() {
configValues["input:follow_mouse"].intValue = 1; configValues["input:follow_mouse"].intValue = 1;
configValues["input:mouse_refocus"].intValue = 1; configValues["input:mouse_refocus"].intValue = 1;
configValues["input:special_fallthrough"].intValue = 0;
configValues["input:sensitivity"].floatValue = 0.f; configValues["input:sensitivity"].floatValue = 0.f;
configValues["input:accel_profile"].strValue = STRVAL_EMPTY; configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
configValues["input:kb_file"].strValue = STRVAL_EMPTY; configValues["input:kb_file"].strValue = STRVAL_EMPTY;
@ -255,6 +256,7 @@ void CConfigManager::setDefaultVars() {
configValues["input:touchpad:scroll_factor"].floatValue = 1.f; configValues["input:touchpad:scroll_factor"].floatValue = 1.f;
configValues["input:touchdevice:transform"].intValue = 0; configValues["input:touchdevice:transform"].intValue = 0;
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY; configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
configValues["input:touchdevice:enabled"].intValue = 1;
configValues["input:tablet:transform"].intValue = 0; configValues["input:tablet:transform"].intValue = 0;
configValues["input:tablet:output"].strValue = STRVAL_EMPTY; configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
configValues["input:tablet:region_position"].vecValue = Vector2D(); configValues["input:tablet:region_position"].vecValue = Vector2D();
@ -320,7 +322,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
cfgValues["scroll_points"].strValue = STRVAL_EMPTY; cfgValues["scroll_points"].strValue = STRVAL_EMPTY;
cfgValues["transform"].intValue = 0; cfgValues["transform"].intValue = 0;
cfgValues["output"].strValue = STRVAL_EMPTY; cfgValues["output"].strValue = STRVAL_EMPTY;
cfgValues["enabled"].intValue = 1; // only for mice / touchpads cfgValues["enabled"].intValue = 1; // only for mice, touchpads, and touchdevices
cfgValues["region_position"].vecValue = Vector2D(); // only for tablets cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
cfgValues["region_size"].vecValue = Vector2D(); // only for tablets cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
cfgValues["relative_input"].intValue = 0; // only for tablets cfgValues["relative_input"].intValue = 0; // only for tablets
@ -563,7 +565,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
} }
} }
if (COMMAND == "decoration:screen_shader") { if (COMMAND == "decoration:screen_shader" && VALUE != STRVAL_EMPTY) {
const auto PATH = absolutePath(VALUE, configCurrentPath); const auto PATH = absolutePath(VALUE, configCurrentPath);
configPaths.push_back(PATH); configPaths.push_back(PATH);
@ -2321,30 +2323,30 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
static auto* const PVRR = &getConfigValuePtr("misc:vrr")->intValue; static auto* const PVRR = &getConfigValuePtr("misc:vrr")->intValue;
static auto ensureVRRForDisplay = [&](CMonitor* m) -> void { static auto ensureVRRForDisplay = [&](CMonitor* m) -> void {
if (!m->output) if (!m->output || m->createdByUser)
return; return;
const auto USEVRR = m->activeMonitorRule.vrr.has_value() ? m->activeMonitorRule.vrr.value() : *PVRR; const auto USEVRR = m->activeMonitorRule.vrr.has_value() ? m->activeMonitorRule.vrr.value() : *PVRR;
if (USEVRR == 0) { if (USEVRR == 0) {
if (m->vrrActive) { if (m->vrrActive) {
wlr_output_enable_adaptive_sync(m->output, 0); wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
if (!wlr_output_commit(m->output)) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
} }
m->vrrActive = false; m->vrrActive = false;
return; return;
} else if (USEVRR == 1) { } else if (USEVRR == 1) {
if (!m->vrrActive) { if (!m->vrrActive) {
wlr_output_enable_adaptive_sync(m->output, 1); wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
if (!wlr_output_test(m->output)) { if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_enable_adaptive_sync(m->output, 0); wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
} }
if (!wlr_output_commit(m->output)) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} }
m->vrrActive = true; m->vrrActive = true;
@ -2361,20 +2363,20 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) { if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) {
wlr_output_enable_adaptive_sync(m->output, 1); wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
if (!wlr_output_test(m->output)) { if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_enable_adaptive_sync(m->output, 0); wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
} }
if (!wlr_output_commit(m->output)) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) { } else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) {
wlr_output_enable_adaptive_sync(m->output, 0); wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
if (!wlr_output_commit(m->output)) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
} }
} }

View file

@ -119,7 +119,7 @@ gestures {
misc { misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more # See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
} }
# Example per-device config # Example per-device config

View file

@ -119,7 +119,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n"; finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += Debug::rollingLog; finalCrashReport += Debug::rollingLog.substr(Debug::rollingLog.find("\n") + 1);
const auto HOME = getenv("HOME"); const auto HOME = getenv("HOME");
const auto CACHE_HOME = getenv("XDG_CACHE_HOME"); const auto CACHE_HOME = getenv("XDG_CACHE_HOME");

View file

@ -1138,9 +1138,9 @@ std::string dispatchSetProp(std::string request) {
} else if (PROP == "alphainactive") { } else if (PROP == "alphainactive") {
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock);
} else if (PROP == "activebordercolor") { } else if (PROP == "activebordercolor") {
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
} else if (PROP == "inactivebordercolor") { } else if (PROP == "inactivebordercolor") {
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
} else if (PROP == "forcergbx") { } else if (PROP == "forcergbx") {
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "bordersize") { } else if (PROP == "bordersize") {
@ -1402,13 +1402,20 @@ std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL; auto format = HyprCtl::FORMAT_NORMAL;
// process flags for non-batch requests // process flags for non-batch requests
if (!request.contains("[[BATCH]]") && request.contains("/")) { if (!request.starts_with("[[BATCH]]") && request.contains("/")) {
long unsigned int sepIndex = 0; long unsigned int sepIndex = 0;
for (const auto& c : request) { for (const auto& c : request) {
if (c == '/') { // stop at separator if (c == '/') { // stop at separator
break; break;
} }
// after whitespace assume the first word as a keyword,
// so its value can have slashes (e.g., a path)
if (c == ' ') {
sepIndex = request.size();
break;
}
sepIndex++; sepIndex++;
if (c == 'j') if (c == 'j')

View file

@ -142,6 +142,9 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output); wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
if (layersurface->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(layersurface);
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained // don't focus if constrained
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint); (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
@ -183,6 +186,11 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")}); g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("closeLayer", layersurface); EMIT_HOOK_EVENT("closeLayer", layersurface);
std::erase(g_pInputManager->m_dExclusiveLSes, layersurface);
if (!g_pInputManager->m_dExclusiveLSes.empty())
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface);
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) { if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");

View file

@ -175,11 +175,17 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) { void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
Debug::log(LOG, "PowerMgr set mode!"); Debug::log(LOG, "PowerMgr set mode!");
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data; const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(EVENT->output);
wlr_output_enable(EVENT->output, EVENT->mode == 1); if (!PMONITOR) {
Debug::log(ERR, "Invalid powerMgrSetMode output");
return;
}
if (!wlr_output_commit(EVENT->output)) wlr_output_state_set_enabled(PMONITOR->state.wlr(), EVENT->mode == 1);
if (!PMONITOR->state.commit())
Debug::log(ERR, "Couldn't set power mode"); Debug::log(ERR, "Couldn't set power mode");
} }
@ -227,14 +233,7 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
void Events::listener_newTearingHint(wl_listener* listener, void* data) { void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto TCTL = (wlr_tearing_control_v1*)data; const auto TCTL = (wlr_tearing_control_v1*)data;
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface); Debug::log(LOG, "New tearing hint at {:x}", (uintptr_t)data);
if (!PWINDOW) {
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
return;
}
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get(); const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data; NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
@ -242,7 +241,7 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
NEWCTRL->hyprListener_destroy.initCallback( NEWCTRL->hyprListener_destroy.initCallback(
&NEWCTRL->pWlrHint->events.destroy, &NEWCTRL->pWlrHint->events.destroy,
[&](void* owner, void* data) { [&](void* owner, void* data) {
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint); Debug::log(LOG, "Destroyed {:x} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; }); std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
}, },
@ -258,7 +257,7 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
if (PWINDOW) { if (PWINDOW) {
PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current; PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current;
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current); Debug::log(LOG, "Hint {:x} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current);
} }
}, },
NEWCTRL, "TearingController"); NEWCTRL, "TearingController");

View file

@ -109,7 +109,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) { if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = -1; w->m_iLastSurfaceMonitorID = -1;
w->updateSurfaceOutputs(); w->updateSurfaceScaleTransformDetails();
} }
} }
} }
@ -209,10 +209,10 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
} }
void Events::listener_monitorStateRequest(void* owner, void* data) { void Events::listener_monitorStateRequest(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner; //const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data; //const auto E = (wlr_output_event_request_state*)data;
wlr_output_commit_state(PMONITOR->output, E->state); // TODO: maybe don't ignore?
} }
void Events::listener_monitorDamage(void* owner, void* data) { void Events::listener_monitorDamage(void* owner, void* data) {

View file

@ -639,7 +639,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform); g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
g_pInputManager->sendMotionEventsToFocused(); if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->constraintActive)
g_pInputManager->sendMotionEventsToFocused();
// fix some xwayland apps that don't behave nicely // fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
@ -803,8 +804,6 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_pPendingSizeAck.reset(); PWINDOW->m_pPendingSizeAck.reset();
} }
PWINDOW->updateSurfaceOutputs();
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
@ -1054,11 +1053,8 @@ void Events::listener_configureX11(void* owner, void* data) {
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue; static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
if (*PXWLFORCESCALEZERO) { if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale); PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
}
} }
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
@ -1139,8 +1135,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv(); PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv(); PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goalv();
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
} }
} }

View file

@ -105,6 +105,13 @@ CBox& CBox::expand(const double& value) {
return *this; return *this;
} }
CBox& CBox::noNegativeSize() {
std::clamp(w, 0.0, std::numeric_limits<double>::infinity());
std::clamp(h, 0.0, std::numeric_limits<double>::infinity());
return *this;
}
CBox CBox::roundInternal() { CBox CBox::roundInternal() {
float newW = x + w - std::floor(x); float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y); float newH = y + h - std::floor(y);

View file

@ -51,6 +51,7 @@ class CBox {
CBox& transform(const wl_output_transform t, double w, double h); CBox& transform(const wl_output_transform t, double w, double h);
CBox& addExtents(const SWindowDecorationExtents& e); CBox& addExtents(const SWindowDecorationExtents& e);
CBox& expand(const double& value); CBox& expand(const double& value);
CBox& noNegativeSize();
CBox copy() const; CBox copy() const;

View file

@ -159,6 +159,13 @@ void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString); Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
} }
void removeWLSignal(wl_listener* pListener) {
wl_list_remove(&pListener->link);
wl_list_init(&pListener->link);
Debug::log(LOG, "Removed listener {:x}", (uintptr_t)pListener);
}
void handleNoop(struct wl_listener* listener, void* data) { void handleNoop(struct wl_listener* listener, void* data) {
// Do nothing // Do nothing
} }

View file

@ -16,6 +16,7 @@ struct SCallstackFrameInfo {
std::string absolutePath(const std::string&, const std::string&); std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str); std::string escapeJSONStrings(const std::string& str);
std::string removeBeginEndSpacesTabs(std::string); std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false); bool isNumber(const std::string&, bool allowfloat = false);

View file

@ -8,7 +8,7 @@ int ratHandler(void* data) {
return 1; return 1;
} }
CMonitor::CMonitor() { CMonitor::CMonitor() : state(this) {
wlr_damage_ring_init(&damage); wlr_damage_ring_init(&damage);
} }
@ -43,8 +43,8 @@ void CMonitor::onConnect(bool noRule) {
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
if (m_bEnabled) { if (m_bEnabled) {
wlr_output_enable(output, 1); wlr_output_state_set_enabled(state.wlr(), true);
wlr_output_commit(output); state.commit();
return; return;
} }
@ -63,8 +63,8 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
wlr_output_set_scale(output, 1); wlr_output_state_set_scale(state.wlr(), 1);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output); auto PREFSTATE = wlr_output_preferred_mode(output);
@ -72,9 +72,9 @@ void CMonitor::onConnect(bool noRule) {
wlr_output_mode* mode; wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) { wl_list_for_each(mode, &output->modes, link) {
wlr_output_set_mode(output, PREFSTATE); wlr_output_state_set_mode(state.wlr(), mode);
if (!wlr_output_test(output)) if (!wlr_output_test_state(output, state.wlr()))
continue; continue;
PREFSTATE = mode; PREFSTATE = mode;
@ -83,13 +83,13 @@ void CMonitor::onConnect(bool noRule) {
} }
if (PREFSTATE) if (PREFSTATE)
wlr_output_set_mode(output, PREFSTATE); wlr_output_state_set_mode(state.wlr(), PREFSTATE);
else else
Debug::log(WARN, "No mode found for disabled output {}", output->name); Debug::log(WARN, "No mode found for disabled output {}", output->name);
wlr_output_enable(output, 0); wlr_output_state_set_enabled(state.wlr(), 0);
if (!wlr_output_commit(output)) if (!state.commit())
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name); Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false; m_bEnabled = false;
@ -130,13 +130,14 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true; m_bEnabled = true;
wlr_output_enable(output, 1); wlr_output_state_set_enabled(state.wlr(), 1);
// set mode, also applies // set mode, also applies
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
wlr_output_commit(output); if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y); wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
@ -283,9 +284,10 @@ void CMonitor::onDisconnect(bool destroy) {
if (!destroy) if (!destroy)
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_enable(output, false); wlr_output_state_set_enabled(state.wlr(), false);
wlr_output_commit(output); if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor == this) if (g_pCompositor->m_pLastMonitor == this)
g_pCompositor->setActiveMonitor(BACKUPMON); g_pCompositor->setActiveMonitor(BACKUPMON);
@ -502,7 +504,7 @@ float CMonitor::getDefaultScale() {
return 1; return 1;
} }
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) { void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove, bool noFocus) {
if (!pWorkspace) if (!pWorkspace)
return; return;
@ -533,7 +535,7 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
} }
} }
if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) { if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
CWindow* pWindow = pWorkspace->getLastFocusedWindow(); CWindow* pWindow = pWorkspace->getLastFocusedWindow();
@ -621,7 +623,7 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) { if (w->m_iWorkspaceID == pWorkspace->m_iID) {
w->m_iMonitorID = ID; w->m_iMonitorID = ID;
w->updateSurfaceOutputs(); w->updateSurfaceScaleTransformDetails();
const auto MIDDLE = w->middle(); const auto MIDDLE = w->middle();
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) { if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) {
@ -678,3 +680,32 @@ void CMonitor::updateMatrix() {
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
} }
} }
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
wlr_output_state_init(&m_state);
}
CMonitorState::~CMonitorState() {
wlr_output_state_finish(&m_state);
}
wlr_output_state* CMonitorState::wlr() {
return &m_state;
}
void CMonitorState::clear() {
wlr_output_state_finish(&m_state);
m_state = {0};
wlr_output_state_init(&m_state);
}
bool CMonitorState::commit() {
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
clear();
return ret;
}
bool CMonitorState::test() {
return wlr_output_test_state(m_pOwner->output, &m_state);
}

View file

@ -25,6 +25,25 @@ struct SMonitorRule {
std::optional<int> vrr; std::optional<int> vrr;
}; };
class CMonitor;
// Class for wrapping the wlr state
class CMonitorState {
public:
CMonitorState(CMonitor* owner);
~CMonitorState();
wlr_output_state* wlr();
void clear();
// commit() will also clear()
bool commit();
bool test();
private:
wlr_output_state m_state = {0};
CMonitor* m_pOwner;
};
class CMonitor { class CMonitor {
public: public:
CMonitor(); CMonitor();
@ -51,6 +70,8 @@ class CMonitor {
drmModeModeInfo customDrmMode = {}; drmModeModeInfo customDrmMode = {};
CMonitorState state;
// WLR stuff // WLR stuff
wlr_damage_ring damage; wlr_damage_ring damage;
wlr_output* output = nullptr; wlr_output* output = nullptr;
@ -120,7 +141,7 @@ class CMonitor {
void setMirror(const std::string&); void setMirror(const std::string&);
bool isMirror(); bool isMirror();
float getDefaultScale(); float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false); void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const int& id, bool internal = false); void changeWorkspace(const int& id, bool internal = false);
void setSpecialWorkspace(CWorkspace* const pWorkspace); void setSpecialWorkspace(CWorkspace* const pWorkspace);
void setSpecialWorkspace(const int& id); void setSpecialWorkspace(const int& id);

View file

@ -19,6 +19,21 @@ inline const std::vector<std::string> SPLASHES = {
"Compile, wait for 20 minutes, notice a new commit, compile again.", "Compile, wait for 20 minutes, notice a new commit, compile again.",
"To rice, or not to rice, that is the question.", "To rice, or not to rice, that is the question.",
"Now available on Fedora!", "Now available on Fedora!",
"\"Hyprland is so good it starts with a capital letter\" - Hazel",
"\"please make this message a splash\" - eriedaberrie",
"\"the only wayland compositor powered by fried chicken\" - raf",
"\"This will never get into Hyprland\" - Flafy",
"\"Hyprland only gives you up on -git\" - fazzi",
"Segmentation fault (core dumped)",
"\"disabling hyprland logo is a war crime\" - vaxry",
"some basic startup code",
"\"I think I am addicted to hyprland\" - mathisbuilder",
"\"hyprland is the most important package in the arch repos\" - jacekpoz",
"Thanks Brodie!",
"Thanks fufexan!",
"Thanks raf!",
"You can't use --splash to change this message :)",
"Hyprland will overtake Gnome in popularity by [insert year]",
// music reference / quote section // music reference / quote section
"J'remue le ciel, le jour, la nuit.", "J'remue le ciel, le jour, la nuit.",
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!", "aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",

View file

@ -178,6 +178,9 @@ void Events::listener_mapSubsurface(void* owner, void* data) {
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface); Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner); subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
if (subsurface->pWindowOwner)
subsurface->pWindowOwner->updateSurfaceScaleTransformDetails();
} }
void Events::listener_unmapSubsurface(void* owner, void* data) { void Events::listener_unmapSubsurface(void* owner, void* data) {
@ -259,13 +262,11 @@ void Events::listener_commitSubsurface(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(pNode->pWindowOwner->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear && if (PMONITOR && PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) { pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox; CRegion damageBox{&pNode->pSurface->wlr()->buffer_damage};
wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman());
if (!damageBox.empty()) { if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) { if (PMONITOR->tearingState.busy) {
PMONITOR->tearingState.frameScheduledWhileBusy = true; PMONITOR->tearingState.frameScheduledWhileBusy = true;
} else { } else {

View file

@ -42,14 +42,6 @@ double Vector2D::distance(const Vector2D& other) const {
return std::sqrt(dx * dx + dy * dy); return std::sqrt(dx * dx + dy * dy);
} }
bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const {
const auto a = ((p2.y - p3.y) * (x - p3.x) + (p3.x - p2.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
const auto b = ((p3.y - p1.y) * (x - p3.x) + (p1.x - p3.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
const auto c = 1 - a - b;
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
}
double Vector2D::size() const { double Vector2D::size() const {
return std::sqrt(x * x + y * y); return std::sqrt(x * x + y * y);
} }

View file

@ -92,8 +92,6 @@ class Vector2D {
Vector2D floor() const; Vector2D floor() const;
Vector2D round() const; Vector2D round() const;
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
}; };
/** /**

View file

@ -7,13 +7,15 @@
void handleWrapped(wl_listener* listener, void* data) { void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener); CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
g_pWatchdog->startWatching(); if (g_pWatchdog)
g_pWatchdog->startWatching();
try { try {
pWrap->m_pSelf->emit(data); pWrap->m_pSelf->emit(data);
} catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); } } catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
g_pWatchdog->endWatching(); if (g_pWatchdog)
g_pWatchdog->endWatching();
} }
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) { CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {

View file

@ -28,8 +28,14 @@ class CWLSurface {
bool m_bFillIgnoreSmall = false; bool m_bFillIgnoreSmall = false;
// if present, means this is a base surface of a window. Cleaned on unassign() // if present, means this is a base surface of a window. Cleaned on unassign()
CWindow* m_pOwner = nullptr; CWindow* m_pOwner = nullptr;
// track surface data and avoid dupes
float m_fLastScale = 0;
int m_iLastScale = 0;
wl_output_transform m_eLastTransform = (wl_output_transform)-1;
//
CWLSurface& operator=(wlr_surface* pSurface) { CWLSurface& operator=(wlr_surface* pSurface) {
destroy(); destroy();
m_pWLRSurface = pSurface; m_pWLRSurface = pSurface;

View file

@ -22,13 +22,13 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
if (SPLITSIDE) { if (SPLITSIDE) {
// split left/right // split left/right
const float FIRSTSIZE = box.w / 2.0 * splitRatio; const float FIRSTSIZE = box.w / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h}; children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h}.noNegativeSize();
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h}; children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h}.noNegativeSize();
} else { } else {
// split top/bottom // split top/bottom
const float FIRSTSIZE = box.h / 2.0 * splitRatio; const float FIRSTSIZE = box.h / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE}; children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE}.noNegativeSize();
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE}; children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE}.noNegativeSize();
} }
children[0]->recalcSizePosRecursive(force); children[0]->recalcSizePosRecursive(force);
@ -64,6 +64,21 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) {
return nullptr; return nullptr;
} }
SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) {
SDwindleNodeData* res = nullptr;
double distClosest = -1;
for (auto& n : m_lDwindleNodesData) {
if (n.workspaceID == id && n.pWindow && g_pCompositor->windowValidMapped(n.pWindow)) {
auto distAnother = vecToRectDistanceSquared(point, n.box.pos(), n.box.pos() + n.box.size());
if (!res || distAnother < distClosest) {
res = &n;
distClosest = distAnother;
}
}
}
return res;
}
SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(CWindow* pWindow) { SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(CWindow* pWindow) {
for (auto& n : m_lDwindleNodesData) { for (auto& n : m_lDwindleNodesData) {
if (n.pWindow == pWindow && !n.isNode) if (n.pWindow == pWindow && !n.isNode)
@ -254,26 +269,25 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal()); const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS); const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
const auto TARGETCOORDS = PMONITOR->ID == MONFROMCURSOR->ID && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR) ? pWindow->middle() : MOUSECOORDS;
if (PMONITOR->ID == MONFROMCURSOR->ID && if (PMONITOR->ID == MONFROMCURSOR->ID &&
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) { (PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS)); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
// happens on reserved area if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0) OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
} else if (*PUSEACTIVE) { } else if (*PUSEACTIVE) {
if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow && if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow &&
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) { g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow); OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
} else { } else {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS)); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
} }
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0) if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace); OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
} else } else
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID); OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
@ -386,34 +400,41 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
if (*PERMANENTDIRECTIONOVERRIDE == 0) if (*PERMANENTDIRECTIONOVERRIDE == 0)
overrideDirection = DIRECTION_DEFAULT; overrideDirection = DIRECTION_DEFAULT;
} else if (*PSMARTSPLIT == 1) { } else if (*PSMARTSPLIT == 1) {
const auto tl = NEWPARENT->box.pos(); const auto PARENT_CENTER = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
const auto tr = NEWPARENT->box.pos() + Vector2D(NEWPARENT->box.w, 0); const auto PARENT_PROPORTIONS = NEWPARENT->box.h / NEWPARENT->box.w;
const auto bl = NEWPARENT->box.pos() + Vector2D(0, NEWPARENT->box.h); const auto DELTA = MOUSECOORDS - PARENT_CENTER;
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size(); const auto DELTA_SLOPE = DELTA.y / DELTA.x;
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
if (TARGETCOORDS.inTriangle(tl, tr, cc)) { if (abs(DELTA_SLOPE) < PARENT_PROPORTIONS) {
NEWPARENT->splitTop = true; if (DELTA.x > 0) {
NEWPARENT->children[0] = PNODE; // right
NEWPARENT->children[1] = OPENINGON; NEWPARENT->splitTop = false;
} else if (TARGETCOORDS.inTriangle(tr, cc, br)) { NEWPARENT->children[0] = OPENINGON;
NEWPARENT->splitTop = false; NEWPARENT->children[1] = PNODE;
NEWPARENT->children[0] = OPENINGON; } else {
NEWPARENT->children[1] = PNODE; // left
} else if (TARGETCOORDS.inTriangle(br, bl, cc)) { NEWPARENT->splitTop = false;
NEWPARENT->splitTop = true; NEWPARENT->children[0] = PNODE;
NEWPARENT->children[0] = OPENINGON; NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[1] = PNODE; }
} else { } else {
NEWPARENT->splitTop = false; if (DELTA.y > 0) {
NEWPARENT->children[0] = PNODE; // bottom
NEWPARENT->children[1] = OPENINGON; NEWPARENT->splitTop = true;
NEWPARENT->children[0] = OPENINGON;
NEWPARENT->children[1] = PNODE;
} else {
// top
NEWPARENT->splitTop = true;
NEWPARENT->children[0] = PNODE;
NEWPARENT->children[1] = OPENINGON;
}
} }
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) { } else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
if ((SIDEBYSIDE && if ((SIDEBYSIDE &&
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) || VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
(!SIDEBYSIDE && (!SIDEBYSIDE &&
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) { VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
// we are hovering over the first node, make PNODE first. // we are hovering over the first node, make PNODE first.
NEWPARENT->children[1] = OPENINGON; NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE; NEWPARENT->children[0] = PNODE;
@ -776,6 +797,14 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
return; return;
} }
// save position and size if floating
if (pWindow->m_bIsFloating && on) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
}
// otherwise, accept it. // otherwise, accept it.
pWindow->m_bIsFullscreen = on; pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
@ -803,14 +832,6 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
PWORKSPACE->m_efFullscreenMode = fullscreenMode; PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// save position and size if floating
if (pWindow->m_bIsFloating) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
}
// apply new pos and size being monitors' box // apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) { if (fullscreenMode == FULLSCREEN_FULL) {
pWindow->m_vRealPosition = PMONITOR->vecPosition; pWindow->m_vRealPosition = PMONITOR->vecPosition;

View file

@ -79,6 +79,7 @@ class CHyprDwindleLayout : public IHyprLayout {
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false); void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
SDwindleNodeData* getNodeFromWindow(CWindow*); SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&); SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&); SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
void toggleSplit(CWindow*); void toggleSplit(CWindow*);

View file

@ -314,8 +314,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) || if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) ||
(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count() < (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count() <
1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate && 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate))
(*PANIMATEMOUSE || *PANIMATE)))
return; return;
TIMER = std::chrono::high_resolution_clock::now(); TIMER = std::chrono::high_resolution_clock::now();
@ -469,16 +468,18 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
CBox wb = {pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize};
wb.round();
if (DELTALESSTHAN(pWindow->m_vRealSize.vec().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.vec().y, pWindow->m_vLastFloatingSize.y, 10)) { if (DELTALESSTHAN(pWindow->m_vRealSize.vec().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.vec().y, pWindow->m_vLastFloatingSize.y, 10)) {
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f + Vector2D{10, 10}; wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}};
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize - Vector2D{20, 20};
} }
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f; pWindow->m_vRealPosition = wb.pos();
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->m_vRealSize = wb.size();
pWindow->m_vSize = pWindow->m_vRealSize.goalv(); pWindow->m_vSize = wb.pos();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv(); pWindow->m_vPosition = wb.size();
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));

View file

@ -879,6 +879,14 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
return; return;
} }
// save position and size if floating
if (pWindow->m_bIsFloating && on) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
}
// otherwise, accept it. // otherwise, accept it.
pWindow->m_bIsFullscreen = on; pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
@ -906,14 +914,6 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
PWORKSPACE->m_efFullscreenMode = fullscreenMode; PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// save position and size if floating
if (pWindow->m_bIsFloating) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
}
// apply new pos and size being monitors' box // apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) { if (fullscreenMode == FULLSCREEN_FULL) {
pWindow->m_vRealPosition = PMONITOR->vecPosition; pWindow->m_vRealPosition = PMONITOR->vecPosition;

View file

@ -19,64 +19,65 @@
CKeybindManager::CKeybindManager() { CKeybindManager::CKeybindManager() {
// initialize all dispatchers // initialize all dispatchers
m_mDispatchers["exec"] = spawn; m_mDispatchers["exec"] = spawn;
m_mDispatchers["execr"] = spawnRaw; m_mDispatchers["execr"] = spawnRaw;
m_mDispatchers["killactive"] = killActive; m_mDispatchers["killactive"] = killActive;
m_mDispatchers["closewindow"] = kill; m_mDispatchers["closewindow"] = kill;
m_mDispatchers["togglefloating"] = toggleActiveFloating; m_mDispatchers["togglefloating"] = toggleActiveFloating;
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["fakefullscreen"] = fakeFullscreenActive;
m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace; m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace;
m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent; m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent;
m_mDispatchers["pseudo"] = toggleActivePseudo; m_mDispatchers["pseudo"] = toggleActivePseudo;
m_mDispatchers["movefocus"] = moveFocusTo; m_mDispatchers["movefocus"] = moveFocusTo;
m_mDispatchers["movewindow"] = moveActiveTo; m_mDispatchers["movewindow"] = moveActiveTo;
m_mDispatchers["swapwindow"] = swapActive; m_mDispatchers["swapwindow"] = swapActive;
m_mDispatchers["centerwindow"] = centerWindow; m_mDispatchers["centerwindow"] = centerWindow;
m_mDispatchers["togglegroup"] = toggleGroup; m_mDispatchers["togglegroup"] = toggleGroup;
m_mDispatchers["changegroupactive"] = changeGroupActive; m_mDispatchers["changegroupactive"] = changeGroupActive;
m_mDispatchers["movegroupwindow"] = moveGroupWindow; m_mDispatchers["movegroupwindow"] = moveGroupWindow;
m_mDispatchers["togglesplit"] = toggleSplit; m_mDispatchers["togglesplit"] = toggleSplit;
m_mDispatchers["splitratio"] = alterSplitRatio; m_mDispatchers["splitratio"] = alterSplitRatio;
m_mDispatchers["focusmonitor"] = focusMonitor; m_mDispatchers["focusmonitor"] = focusMonitor;
m_mDispatchers["movecursortocorner"] = moveCursorToCorner; m_mDispatchers["movecursortocorner"] = moveCursorToCorner;
m_mDispatchers["movecursor"] = moveCursor; m_mDispatchers["movecursor"] = moveCursor;
m_mDispatchers["workspaceopt"] = workspaceOpt; m_mDispatchers["workspaceopt"] = workspaceOpt;
m_mDispatchers["exit"] = exitHyprland; m_mDispatchers["exit"] = exitHyprland;
m_mDispatchers["movecurrentworkspacetomonitor"] = moveCurrentWorkspaceToMonitor; m_mDispatchers["movecurrentworkspacetomonitor"] = moveCurrentWorkspaceToMonitor;
m_mDispatchers["moveworkspacetomonitor"] = moveWorkspaceToMonitor; m_mDispatchers["focusworkspaceoncurrentmonitor"] = focusWorkspaceOnCurrentMonitor;
m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace; m_mDispatchers["moveworkspacetomonitor"] = moveWorkspaceToMonitor;
m_mDispatchers["forcerendererreload"] = forceRendererReload; m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace;
m_mDispatchers["resizeactive"] = resizeActive; m_mDispatchers["forcerendererreload"] = forceRendererReload;
m_mDispatchers["moveactive"] = moveActive; m_mDispatchers["resizeactive"] = resizeActive;
m_mDispatchers["cyclenext"] = circleNext; m_mDispatchers["moveactive"] = moveActive;
m_mDispatchers["focuswindowbyclass"] = focusWindow; m_mDispatchers["cyclenext"] = circleNext;
m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["focuswindowbyclass"] = focusWindow;
m_mDispatchers["submap"] = setSubmap; m_mDispatchers["focuswindow"] = focusWindow;
m_mDispatchers["pass"] = pass; m_mDispatchers["submap"] = setSubmap;
m_mDispatchers["layoutmsg"] = layoutmsg; m_mDispatchers["pass"] = pass;
m_mDispatchers["toggleopaque"] = toggleOpaque; m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["dpms"] = dpms; m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["movewindowpixel"] = moveWindow; m_mDispatchers["dpms"] = dpms;
m_mDispatchers["resizewindowpixel"] = resizeWindow; m_mDispatchers["movewindowpixel"] = moveWindow;
m_mDispatchers["swapnext"] = swapnext; m_mDispatchers["resizewindowpixel"] = resizeWindow;
m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces; m_mDispatchers["swapnext"] = swapnext;
m_mDispatchers["pin"] = pinActive; m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces;
m_mDispatchers["mouse"] = mouse; m_mDispatchers["pin"] = pinActive;
m_mDispatchers["bringactivetotop"] = bringActiveToTop; m_mDispatchers["mouse"] = mouse;
m_mDispatchers["alterzorder"] = alterZOrder; m_mDispatchers["bringactivetotop"] = bringActiveToTop;
m_mDispatchers["focusurgentorlast"] = focusUrgentOrLast; m_mDispatchers["alterzorder"] = alterZOrder;
m_mDispatchers["focuscurrentorlast"] = focusCurrentOrLast; m_mDispatchers["focusurgentorlast"] = focusUrgentOrLast;
m_mDispatchers["lockgroups"] = lockGroups; m_mDispatchers["focuscurrentorlast"] = focusCurrentOrLast;
m_mDispatchers["lockactivegroup"] = lockActiveGroup; m_mDispatchers["lockgroups"] = lockGroups;
m_mDispatchers["moveintogroup"] = moveIntoGroup; m_mDispatchers["lockactivegroup"] = lockActiveGroup;
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup; m_mDispatchers["moveintogroup"] = moveIntoGroup;
m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup; m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock; m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup;
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup; m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock;
m_mDispatchers["global"] = global; m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
m_mDispatchers["global"] = global;
m_tScrollTimer.reset(); m_tScrollTimer.reset();
@ -313,9 +314,10 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
.keysym = keysym, .keysym = keysym,
.keycode = KEYCODE, .keycode = KEYCODE,
.modmaskAtPressTime = MODS, .modmaskAtPressTime = MODS,
.sent = true,
}; };
bool found = false; bool suppressEvent = false;
if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) { if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
// clean repeat // clean repeat
if (m_pActiveKeybindEventSource) { if (m_pActiveKeybindEventSource) {
@ -326,10 +328,12 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
m_dPressedKeys.push_back(KEY); m_dPressedKeys.push_back(KEY);
found = handleKeybinds(MODS, KEY, true); suppressEvent = handleKeybinds(MODS, KEY, true);
if (found) if (suppressEvent)
shadowKeybinds(keysym, KEYCODE); shadowKeybinds(keysym, KEYCODE);
m_dPressedKeys.back().sent = !suppressEvent;
} else { // key release } else { // key release
// clean repeat // clean repeat
if (m_pActiveKeybindEventSource) { if (m_pActiveKeybindEventSource) {
@ -341,11 +345,10 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
bool foundInPressedKeys = false; bool foundInPressedKeys = false;
for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) { for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) {
if (it->keycode == KEYCODE) { if (it->keycode == KEYCODE) {
if (!foundInPressedKeys) { suppressEvent = handleKeybinds(MODS, *it, false);
found = handleKeybinds(MODS, *it, false); foundInPressedKeys = true;
foundInPressedKeys = true; suppressEvent = !it->sent;
} it = m_dPressedKeys.erase(it);
it = m_dPressedKeys.erase(it);
} else { } else {
++it; ++it;
} }
@ -353,13 +356,13 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
if (!foundInPressedKeys) { if (!foundInPressedKeys) {
Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys"); Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys");
// fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy
found = handleKeybinds(MODS, KEY, false); suppressEvent = handleKeybinds(MODS, KEY, false);
} }
shadowKeybinds(); shadowKeybinds();
} }
return !found && !mouseBindWasActive; return !suppressEvent && !mouseBindWasActive;
} }
bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
@ -396,7 +399,7 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
bool found = false; bool suppressEvent = false;
m_uLastMouseCode = e->button; m_uLastMouseCode = e->button;
m_uLastCode = 0; m_uLastCode = 0;
@ -414,19 +417,20 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
if (e->state == WLR_BUTTON_PRESSED) { if (e->state == WLR_BUTTON_PRESSED) {
m_dPressedKeys.push_back(KEY); m_dPressedKeys.push_back(KEY);
found = handleKeybinds(MODS, KEY, true); suppressEvent = handleKeybinds(MODS, KEY, true);
if (found) if (suppressEvent)
shadowKeybinds(); shadowKeybinds();
m_dPressedKeys.back().sent = !suppressEvent;
} else { } else {
bool foundInPressedKeys = false; bool foundInPressedKeys = false;
for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) { for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) {
if (it->keyName == KEY_NAME) { if (it->keyName == KEY_NAME) {
if (!foundInPressedKeys) { suppressEvent = handleKeybinds(MODS, *it, false);
found = handleKeybinds(MODS, *it, false); foundInPressedKeys = true;
foundInPressedKeys = true; suppressEvent = !it->sent;
} it = m_dPressedKeys.erase(it);
it = m_dPressedKeys.erase(it);
} else { } else {
++it; ++it;
} }
@ -434,13 +438,13 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
if (!foundInPressedKeys) { if (!foundInPressedKeys) {
Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys (2)"); Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys (2)");
// fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy
found = handleKeybinds(MODS, KEY, false); suppressEvent = handleKeybinds(MODS, KEY, false);
} }
shadowKeybinds(); shadowKeybinds();
} }
return !found && !mouseBindWasActive; return !suppressEvent && !mouseBindWasActive;
} }
void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) { void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) {
@ -522,7 +526,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
if (!pressed) { if (!pressed) {
// Require mods to be matching when the key was first pressed. // Require mods to be matching when the key was first pressed.
if (key.modmaskAtPressTime != modmask) { if (key.modmaskAtPressTime != modmask && !k.ignoreMods) {
// Handle properly `bindr` where a key is itself a bind mod for example: // Handle properly `bindr` where a key is itself a bind mod for example:
// "bindr = SUPER, SUPER_L, exec, $launcher". // "bindr = SUPER, SUPER_L, exec, $launcher".
// This needs to be handled separately for the above case, because `key.modmaskAtPressTime` is set // This needs to be handled separately for the above case, because `key.modmaskAtPressTime` is set
@ -1449,7 +1453,7 @@ void CKeybindManager::renameWorkspace(std::string args) {
} }
void CKeybindManager::exitHyprland(std::string argz) { void CKeybindManager::exitHyprland(std::string argz) {
g_pCompositor->cleanup(); g_pInputManager->m_bExitTriggered = true;
} }
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
@ -1499,6 +1503,48 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PMONITOR); g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PMONITOR);
} }
void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
std::string workspaceName;
const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
if (WORKSPACEID == WORKSPACE_INVALID) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
return;
}
const auto PCURRMONITOR = g_pCompositor->getMonitorFromCursor();
if (!PCURRMONITOR) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!");
return;
}
auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
if (!PWORKSPACE) {
PWORKSPACE = g_pCompositor->createNewWorkspace(WORKSPACEID, PCURRMONITOR->ID);
// we can skip the moving, since it's already on the current monitor
changeworkspace(PWORKSPACE->getConfigName());
return;
}
if (PWORKSPACE->m_iMonitorID != PCURRMONITOR->ID) {
const auto POLDMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (!POLDMONITOR) { // wat
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!");
return;
}
if (POLDMONITOR->activeWorkspace == WORKSPACEID) {
g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR);
return;
} else {
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PCURRMONITOR, true);
}
}
changeworkspace(PWORKSPACE->getConfigName());
}
void CKeybindManager::toggleSpecialWorkspace(std::string args) { void CKeybindManager::toggleSpecialWorkspace(std::string args) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
@ -1806,11 +1852,11 @@ void CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port) if (!port.empty() && m->szName != port)
continue; continue;
wlr_output_enable(m->output, enable); wlr_output_state_set_enabled(m->state.wlr(), enable);
m->dpmsStatus = enable; m->dpmsStatus = enable;
if (!wlr_output_commit(m->output)) { if (!m->state.commit()) {
Debug::log(ERR, "Couldn't commit output {}", m->szName); Debug::log(ERR, "Couldn't commit output {}", m->szName);
} }

View file

@ -41,6 +41,7 @@ struct SPressedKeyWithMods {
xkb_keysym_t keysym = 0; xkb_keysym_t keysym = 0;
uint32_t keycode = 0; uint32_t keycode = 0;
uint32_t modmaskAtPressTime = 0; uint32_t modmaskAtPressTime = 0;
bool sent = false;
}; };
class CKeybindManager { class CKeybindManager {
@ -133,6 +134,7 @@ class CKeybindManager {
static void exitHyprland(std::string); static void exitHyprland(std::string);
static void moveCurrentWorkspaceToMonitor(std::string); static void moveCurrentWorkspaceToMonitor(std::string);
static void moveWorkspaceToMonitor(std::string); static void moveWorkspaceToMonitor(std::string);
static void focusWorkspaceOnCurrentMonitor(std::string);
static void toggleSpecialWorkspace(std::string); static void toggleSpecialWorkspace(std::string);
static void forceRendererReload(std::string); static void forceRendererReload(std::string);
static void resizeActive(std::string); static void resizeActive(std::string);

View file

@ -421,7 +421,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
m_bLastFocusOnLS = false; m_bLastFocusOnLS = false;
return; // don't enter any new surfaces return; // don't enter any new surfaces
} else { } else {
if (((FOLLOWMOUSE != 3 && allowKeyboardRefocus) && (*PMOUSEREFOCUS || m_pLastMouseFocus != pFoundWindow)) || refocus) { if (allowKeyboardRefocus && ((FOLLOWMOUSE != 3 && (*PMOUSEREFOCUS || m_pLastMouseFocus != pFoundWindow)) || refocus)) {
m_pLastMouseFocus = pFoundWindow; m_pLastMouseFocus = pFoundWindow;
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
} }
@ -695,7 +695,8 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
return; return;
} }
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source); wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source,
WLR_AXIS_RELATIVE_DIRECTION_IDENTICAL);
} }
Vector2D CInputManager::getMouseCoordsInternal() { Vector2D CInputManager::getMouseCoordsInternal() {
@ -1185,6 +1186,9 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
updateKeyboardsLeds(pKeyboard->keyboard); updateKeyboardsLeds(pKeyboard->keyboard);
} }
if (m_bExitTriggered)
g_pCompositor->cleanup();
} }
void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) { void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
@ -1457,12 +1461,16 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
} }
void CInputManager::setTouchDeviceConfigs(STouchDevice* dev) { void CInputManager::setTouchDeviceConfigs(STouchDevice* dev) {
auto setConfig = [&](STouchDevice* const PTOUCHDEV) -> void { auto setConfig = [&](STouchDevice* const PTOUCHDEV) -> void {
if (wlr_input_device_is_libinput(PTOUCHDEV->pWlrDevice)) { if (wlr_input_device_is_libinput(PTOUCHDEV->pWlrDevice)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(PTOUCHDEV->pWlrDevice); const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(PTOUCHDEV->pWlrDevice);
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7); const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "enabled", "input:touchdevice:enabled");
const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
if (libinput_device_config_send_events_get_mode(LIBINPUTDEV) != mode)
libinput_device_config_send_events_set_mode(LIBINPUTDEV, mode);
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7);
if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV)) if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV))
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]); libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);

View file

@ -142,25 +142,28 @@ class CInputManager {
// Switches // Switches
std::list<SSwitchDevice> m_lSwitches; std::list<SSwitchDevice> m_lSwitches;
void newTabletTool(wlr_input_device*); // Exclusive layer surfaces
void newTabletPad(wlr_input_device*); std::deque<SLayerSurface*> m_dExclusiveLSes;
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
void newIdleInhibitor(wlr_idle_inhibitor_v1*);
void recheckIdleInhibitorStatus();
void onSwipeBegin(wlr_pointer_swipe_begin_event*); void newTabletTool(wlr_input_device*);
void onSwipeEnd(wlr_pointer_swipe_end_event*); void newTabletPad(wlr_input_device*);
void onSwipeUpdate(wlr_pointer_swipe_update_event*); void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
void newIdleInhibitor(wlr_idle_inhibitor_v1*);
void recheckIdleInhibitorStatus();
SSwipeGesture m_sActiveSwipe; void onSwipeBegin(wlr_pointer_swipe_begin_event*);
void onSwipeEnd(wlr_pointer_swipe_end_event*);
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
SKeyboard* m_pActiveKeyboard = nullptr; SSwipeGesture m_sActiveSwipe;
CTimer m_tmrLastCursorMovement; SKeyboard* m_pActiveKeyboard = nullptr;
CInputMethodRelay m_sIMERelay; CTimer m_tmrLastCursorMovement;
void updateKeyboardsLeds(wlr_input_device* pKeyboard); CInputMethodRelay m_sIMERelay;
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
// for shared mods // for shared mods
uint32_t accumulateModsFromAllKBs(); uint32_t accumulateModsFromAllKBs();
@ -243,6 +246,8 @@ class CInputManager {
void restoreCursorIconToApp(); // no-op if restored void restoreCursorIconToApp(); // no-op if restored
bool m_bExitTriggered = false; // for exit dispatcher
friend class CKeybindManager; friend class CKeybindManager;
friend class CWLSurface; friend class CWLSurface;
}; };

View file

@ -265,7 +265,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
PWORKSPACE->m_bForceRendering = true; PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(1.f); PWORKSPACE->m_fAlpha.setValueAndWarp(1.f);
if (workspaceIDLeft != workspaceIDRight) { if (workspaceIDLeft != workspaceIDRight && workspaceIDRight != m_sActiveSwipe.pWorkspaceBegin->m_iID) {
const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight);
if (PWORKSPACER) { if (PWORKSPACER) {
@ -305,7 +305,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
PWORKSPACE->m_bForceRendering = true; PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(1.f); PWORKSPACE->m_fAlpha.setValueAndWarp(1.f);
if (workspaceIDLeft != workspaceIDRight) { if (workspaceIDLeft != workspaceIDRight && workspaceIDLeft != m_sActiveSwipe.pWorkspaceBegin->m_iID) {
const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
if (PWORKSPACEL) { if (PWORKSPACEL) {

View file

@ -74,9 +74,10 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline); std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline);
if (code.contains("%rip")) { if (code.contains("%rip")) {
CVarList tokens{code, 0, 's'}; CVarList tokens{code, 0, 's'};
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0; size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
std::string addr = tokens[1].substr(plusPresent, tokens[1].find("(%rip)") - plusPresent); size_t minusPresent = tokens[1][0] == '-' ? 1 : 0;
const uint64_t OFFSET = configStringToInt(addr); std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent));
const uint64_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr);
if (OFFSET == 0) if (OFFSET == 0)
return {}; return {};
const uint64_t DESTINATION = currentAddress + OFFSET + len; const uint64_t DESTINATION = currentAddress + OFFSET + len;

View file

@ -189,16 +189,39 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer* fb) { void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer* fb) {
m_RenderData.pMonitor = pMonitor; m_RenderData.pMonitor = pMonitor;
#ifndef GLES2
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
if (RESETSTATUS != GL_NO_ERROR) {
std::string errStr = "";
switch (RESETSTATUS) {
case GL_GUILTY_CONTEXT_RESET: errStr = "GL_GUILTY_CONTEXT_RESET"; break;
case GL_INNOCENT_CONTEXT_RESET: errStr = "GL_INNOCENT_CONTEXT_RESET"; break;
case GL_UNKNOWN_CONTEXT_RESET: errStr = "GL_UNKNOWN_CONTEXT_RESET"; break;
default: errStr = "UNKNOWN??"; break;
}
RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr);
return;
}
#endif
TRACY_GPU_ZONE("RenderBegin"); TRACY_GPU_ZONE("RenderBegin");
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
if (m_mMonitorRenderResources.contains(pMonitor) && m_mMonitorRenderResources.at(pMonitor).offloadFB.m_vSize != pMonitor->vecPixelSize)
destroyMonitorResources(pMonitor);
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders();
// ensure a framebuffer for the monitor exists // ensure a framebuffer for the monitor exists
if (!m_mMonitorRenderResources.contains(pMonitor) || m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) { if (m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) {
m_RenderData.pCurrentMonData->stencilTex.allocate(); m_RenderData.pCurrentMonData->stencilTex.allocate();
m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
@ -210,16 +233,11 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer*
m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
createBGTextureForMonitor(pMonitor);
} }
if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty()) if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty())
m_RenderData.pCurrentMonData->monitorMirrorFB.release(); m_RenderData.pCurrentMonData->monitorMirrorFB.release();
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders();
m_RenderData.damage.set(*pDamage); m_RenderData.damage.set(*pDamage);
m_bFakeFrame = fb; m_bFakeFrame = fb;
@ -312,6 +330,15 @@ void CHyprOpenGLImpl::end() {
m_RenderData.mouseZoomFactor = 1.f; m_RenderData.mouseZoomFactor = 1.f;
m_RenderData.mouseZoomUseMouse = true; m_RenderData.mouseZoomUseMouse = true;
m_RenderData.forceIntrospection = false; m_RenderData.forceIntrospection = false;
m_RenderData.currentFB = nullptr;
m_RenderData.mainFB = nullptr;
m_RenderData.outFB = nullptr;
// check for gl errors
const GLenum ERR = glGetError();
if (ERR == GL_CONTEXT_LOST) /* We don't have infra to recover from this */
RASSERT(false, "glGetError at Opengl::end() returned GL_CONTEXT_LOST. Cannot continue until proper GPU reset handling is implemented.");
} }
void CHyprOpenGLImpl::initShaders() { void CHyprOpenGLImpl::initShaders() {
@ -723,7 +750,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
alpha = std::clamp(alpha, 0.f, 1.f); alpha = std::clamp(alpha, 0.f, 1.f);
if (m_RenderData.damage.empty()) if (damage->empty())
return; return;
CBox newBox = *pBox; CBox newBox = *pBox;
@ -1887,10 +1914,10 @@ void CHyprOpenGLImpl::renderMirrored() {
renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false); renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false);
} }
void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY) { void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) {
cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
const auto FONTSIZE = (int)(m_RenderData.pMonitor->vecPixelSize.y / 76); const auto FONTSIZE = (int)(size.y / 76);
cairo_set_font_size(CAIRO, FONTSIZE); cairo_set_font_size(CAIRO, FONTSIZE);
cairo_set_source_rgba(CAIRO, 1.0, 1.0, 1.0, 0.32); cairo_set_source_rgba(CAIRO, 1.0, 1.0, 1.0, 0.32);
@ -1898,7 +1925,7 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const
cairo_text_extents_t textExtents; cairo_text_extents_t textExtents;
cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents); cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents);
cairo_move_to(CAIRO, (m_RenderData.pMonitor->vecPixelSize.x - textExtents.width) / 2.0, m_RenderData.pMonitor->vecPixelSize.y - textExtents.height + offsetY); cairo_move_to(CAIRO, (size.x - textExtents.width) / 2.0, size.y - textExtents.height + offsetY);
cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str()); cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str());
@ -1910,109 +1937,123 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue; static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
static auto* const PNOSPLASH = &g_pConfigManager->getConfigValuePtr("misc:disable_splash_rendering")->intValue; static auto* const PNOSPLASH = &g_pConfigManager->getConfigValuePtr("misc:disable_splash_rendering")->intValue;
static auto* const PFORCEHYPRCHAN = &g_pConfigManager->getConfigValuePtr("misc:force_hypr_chan")->intValue;
static auto* const PFORCEWALLPAPER = &g_pConfigManager->getConfigValuePtr("misc:force_default_wallpaper")->intValue; static auto* const PFORCEWALLPAPER = &g_pConfigManager->getConfigValuePtr("misc:force_default_wallpaper")->intValue;
const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast<int64_t>(-1L), static_cast<int64_t>(2L)); const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast<int64_t>(-1L), static_cast<int64_t>(2L));
static std::string texPath = "";
if (*PRENDERTEX) if (*PRENDERTEX)
return; return;
// release the last tex if exists // release the last tex if exists
const auto PTEX = &m_mMonitorBGTextures[pMonitor]; const auto PFB = &m_mMonitorBGFBs[pMonitor];
PTEX->destroyTexture(); PFB->release();
PTEX->allocate(); PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
Debug::log(LOG, "Allocated texture for BGTex"); Debug::log(LOG, "Allocated texture for BGTex");
// TODO: use relative paths to the installation // TODO: use relative paths to the installation
// or configure the paths at build time // or configure the paths at build time
std::string texPath = "/usr/share/hyprland/wall_"; if (texPath.empty()) {
std::string prefixes[] = {"", "anime_", "anime2_"}; texPath = "/usr/share/hyprland/wall";
// get the adequate tex // get the adequate tex
if (FORCEWALLPAPER == -1) { if (FORCEWALLPAPER == -1) {
std::random_device dev; std::mt19937_64 engine(time(nullptr));
std::mt19937 engine(dev()); std::uniform_int_distribution<> distribution(0, 2);
std::uniform_int_distribution<> distribution(0, 2);
std::uniform_int_distribution<> distribution_anime(1, 2);
if (PFORCEHYPRCHAN) texPath += std::to_string(distribution(engine));
texPath += prefixes[distribution_anime(engine)]; } else
else texPath += std::to_string(std::clamp(*PFORCEWALLPAPER, (int64_t)0, (int64_t)2));
texPath += prefixes[distribution(engine)];
} else
texPath += prefixes[FORCEWALLPAPER];
Vector2D textureSize; texPath += ".png";
if (pMonitor->vecTransformedSize.x > 3850) {
textureSize = Vector2D(7680, 4320); // check if wallpapers exist
texPath += "8K.png"; if (!std::filesystem::exists(texPath)) {
} else if (pMonitor->vecTransformedSize.x > 1930) { // try local
textureSize = Vector2D(3840, 2160); texPath = texPath.substr(0, 5) + "local/" + texPath.substr(5);
texPath += "4K.png";
} else { if (!std::filesystem::exists(texPath))
textureSize = Vector2D(1920, 1080); return; // the texture will be empty, oh well. We'll clear with a solid color anyways.
texPath += "2K.png"; }
} }
// check if wallpapers exist // create a new one with cairo
if (!std::filesystem::exists(texPath)) { CTexture tex;
// try local
texPath = texPath.substr(0, 5) + "local/" + texPath.substr(5);
if (!std::filesystem::exists(texPath)) const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str());
return; // the texture will be empty, oh well. We'll clear with a solid color anyways. const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE);
}
PTEX->m_vSize = textureSize; tex.allocate();
const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)};
// calc the target box // calc the target box
const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y; const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y;
const double WPRATIO = 1.77; const double WPRATIO = IMAGESIZE.x / IMAGESIZE.y;
Vector2D origin; Vector2D origin;
double scale; double scale;
if (MONRATIO > WPRATIO) { if (MONRATIO > WPRATIO) {
scale = m_RenderData.pMonitor->vecTransformedSize.x / PTEX->m_vSize.x; scale = m_RenderData.pMonitor->vecTransformedSize.x / IMAGESIZE.x;
origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - PTEX->m_vSize.y * scale) / 2.0; origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - IMAGESIZE.y * scale) / 2.0;
} else { } else {
scale = m_RenderData.pMonitor->vecTransformedSize.y / PTEX->m_vSize.y; scale = m_RenderData.pMonitor->vecTransformedSize.y / IMAGESIZE.y;
origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - PTEX->m_vSize.x * scale) / 2.0; origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - IMAGESIZE.x * scale) / 2.0;
} }
CBox box = {origin.x, origin.y, PTEX->m_vSize.x * scale, PTEX->m_vSize.y * scale}; const Vector2D scaledSize = IMAGESIZE * scale;
m_mMonitorRenderResources[pMonitor].backgroundTexBox = box; const auto CAIROSURFACE = cairo_image_surface_create(CAIROFORMAT, scaledSize.x, scaledSize.y);
const auto CAIRO = cairo_create(CAIROSURFACE);
// create a new one with cairo cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_GOOD);
const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str()); cairo_scale(CAIRO, scale, scale);
const auto CAIRO = cairo_create(CAIROSURFACE); cairo_rectangle(CAIRO, 0, 0, 100, 100);
cairo_set_source_surface(CAIRO, CAIROISURFACE, 0, 0);
cairo_paint(CAIRO);
// scale it to fit the current monitor
cairo_scale(CAIRO, textureSize.x / pMonitor->vecTransformedSize.x, textureSize.y / pMonitor->vecTransformedSize.y);
// render splash on wallpaper
if (!*PNOSPLASH) if (!*PNOSPLASH)
renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO); renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO * scale, IMAGESIZE);
cairo_surface_flush(CAIROSURFACE);
CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale};
tex.m_vSize = IMAGESIZE * scale;
// copy the data to an OpenGL texture we have // copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA;
glBindTexture(GL_TEXTURE_2D, PTEX->m_iTexID); const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA;
const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE;
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
glBindTexture(GL_TEXTURE_2D, tex.m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifndef GLES2 #ifndef GLES2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
}
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureSize.x, textureSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex.m_vSize.x, tex.m_vSize.y, 0, glFormat, glType, DATA);
cairo_surface_destroy(CAIROSURFACE); cairo_surface_destroy(CAIROSURFACE);
cairo_surface_destroy(CAIROISURFACE);
cairo_destroy(CAIRO); cairo_destroy(CAIRO);
// render the texture to our fb
PFB->bind();
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
renderTextureInternalWithDamage(tex, &box, 1.0, &fakeDamage);
// bind back
if (m_RenderData.currentFB)
m_RenderData.currentFB->bind();
Debug::log(LOG, "Background created for monitor {}", pMonitor->szName); Debug::log(LOG, "Background created for monitor {}", pMonitor->szName);
} }
@ -2021,15 +2062,19 @@ void CHyprOpenGLImpl::clearWithTex() {
TRACY_GPU_ZONE("RenderClearWithTex"); TRACY_GPU_ZONE("RenderClearWithTex");
auto TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor); auto TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor);
if (TEXIT == m_mMonitorBGTextures.end()) { if (TEXIT == m_mMonitorBGFBs.end()) {
createBGTextureForMonitor(m_RenderData.pMonitor); createBGTextureForMonitor(m_RenderData.pMonitor);
TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor); TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor);
} }
if (TEXIT != m_mMonitorBGTextures.end()) if (TEXIT != m_mMonitorBGFBs.end()) {
renderTexturePrimitive(TEXIT->second, &m_mMonitorRenderResources[m_RenderData.pMonitor].backgroundTexBox); CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
m_bEndFrame = true;
renderTexture(TEXIT->second.m_cTex, &monbox, 1);
m_bEndFrame = false;
}
} }
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
@ -2047,10 +2092,10 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT); g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT);
} }
auto TEXIT = g_pHyprOpenGL->m_mMonitorBGTextures.find(pMonitor); auto TEXIT = g_pHyprOpenGL->m_mMonitorBGFBs.find(pMonitor);
if (TEXIT != g_pHyprOpenGL->m_mMonitorBGTextures.end()) { if (TEXIT != g_pHyprOpenGL->m_mMonitorBGFBs.end()) {
TEXIT->second.destroyTexture(); TEXIT->second.release();
g_pHyprOpenGL->m_mMonitorBGTextures.erase(TEXIT); g_pHyprOpenGL->m_mMonitorBGFBs.erase(TEXIT);
} }
Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName); Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName);

View file

@ -71,8 +71,6 @@ struct SMonitorRenderData {
bool blurFBDirty = true; bool blurFBDirty = true;
bool blurFBShouldRender = false; bool blurFBShouldRender = false;
CBox backgroundTexBox;
// Shaders // Shaders
bool m_bShadersInitialized = false; bool m_bShadersInitialized = false;
CShader m_shQUAD; CShader m_shQUAD;
@ -191,7 +189,7 @@ class CHyprOpenGLImpl {
std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers; std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers;
std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers; std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers;
std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources; std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures; std::unordered_map<CMonitor*, CFramebuffer> m_mMonitorBGFBs;
struct { struct {
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
@ -229,7 +227,7 @@ class CHyprOpenGLImpl {
void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, CCornerRadiiData radii = 0, bool discardOpaque = false, bool noAA = false, void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, CCornerRadiiData radii = 0, bool discardOpaque = false, bool noAA = false,
bool allowCustomUV = false, bool allowDim = false); bool allowCustomUV = false, bool allowDim = false);
void renderTexturePrimitive(const CTexture& tex, CBox* pBox); void renderTexturePrimitive(const CTexture& tex, CBox* pBox);
void renderSplash(cairo_t* const, cairo_surface_t* const, double); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
void preBlurForCurrentMonitor(); void preBlurForCurrentMonitor();

View file

@ -9,8 +9,6 @@ extern "C" {
} }
CHyprRenderer::CHyprRenderer() { CHyprRenderer::CHyprRenderer() {
if (envEnabled("WLR_DRM_NO_ATOMIC"))
m_bTearingEnvSatisfied = true;
if (g_pCompositor->m_sWLRSession) { if (g_pCompositor->m_sWLRSession) {
wlr_device* dev; wlr_device* dev;
@ -107,19 +105,22 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
if (windowBox.width <= 1 || windowBox.height <= 1) if (windowBox.width <= 1 || windowBox.height <= 1)
return; // invisible return; // invisible
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface);
windowBox.scale(RDATA->pMonitor->scale); windowBox.scale(RDATA->pMonitor->scale);
windowBox.round(); windowBox.round();
// check for fractional scale surfaces misaligning the buffer size const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ &&
// in those cases it's better to just force nearest neighbor
// as long as the window is not animated. During those it'd look weird
const auto NEARESTNEIGHBORSET = g_pHyprOpenGL->m_RenderData.useNearestNeighbor;
if (std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ &&
windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ && windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ &&
DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ && DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ &&
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */) (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */;
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1);
// check for fractional scale surfaces misaligning the buffer size
// in those cases it's better to just force nearest neighbor
// as long as the window is not animated. During those it'd look weird.
// UV will fixup it as well
const auto NEARESTNEIGHBORSET = g_pHyprOpenGL->m_RenderData.useNearestNeighbor;
if (MISALIGNEDFSV1)
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true;
CCornerRadiiData radii = RDATA->cornerRadii; CCornerRadiiData radii = RDATA->cornerRadii;
@ -290,11 +291,14 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
continue; continue;
} }
if (w->m_iWorkspaceID != pMonitor->activeWorkspace || !w->m_bIsFullscreen) if (!w->m_bIsFullscreen)
continue; continue;
renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL); renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL);
if (w->m_iWorkspaceID != pWorkspace->m_iID)
continue;
pWorkspaceWindow = w.get(); pWorkspaceWindow = w.get();
} }
@ -453,7 +457,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
// clip box for animated offsets // clip box for animated offsets
const Vector2D PREOFFSETPOS = {renderdata.x, renderdata.y}; const Vector2D PREOFFSETPOS = {renderdata.x, renderdata.y};
if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bPinned) { if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bPinned && !pWindow->m_bIsFullscreen) {
Vector2D offset; Vector2D offset;
if (PWORKSPACE->m_vRenderOffset.vec().x != 0) { if (PWORKSPACE->m_vRenderOffset.vec().x != 0) {
@ -805,7 +809,7 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now) {
} }
} }
void CHyprRenderer::calculateUVForSurface(CWindow* pWindow, wlr_surface* pSurface, bool main) { void CHyprRenderer::calculateUVForSurface(CWindow* pWindow, wlr_surface* pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) {
if (!pWindow || !pWindow->m_bIsX11) { if (!pWindow || !pWindow->m_bIsX11) {
Vector2D uvTL; Vector2D uvTL;
Vector2D uvBR = Vector2D(1, 1); Vector2D uvBR = Vector2D(1, 1);
@ -827,6 +831,15 @@ void CHyprRenderer::calculateUVForSurface(CWindow* pWindow, wlr_surface* pSurfac
} }
} }
if (projSize != Vector2D{} && fixMisalignedFSV1) {
// instead of nearest_neighbor (we will repeat / skip)
// just cut off / expand surface
const Vector2D PIXELASUV = Vector2D{1, 1} / Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height};
const Vector2D MISALIGNMENT = Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height} - projSize;
if (MISALIGNMENT != Vector2D{})
uvBR -= MISALIGNMENT * PIXELASUV;
}
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL; g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR; g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
@ -902,9 +915,9 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
return false; return false;
// finally, we should be GTG. // finally, we should be GTG.
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base); wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base);
if (!wlr_output_test(pMonitor->output)) if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr()))
return false; return false;
timespec now; timespec now;
@ -912,7 +925,7 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
wlr_surface_send_frame_done(PSURFACE, &now); wlr_surface_send_frame_done(PSURFACE, &now);
wlr_presentation_surface_scanned_out_on_output(PSURFACE, pMonitor->output); wlr_presentation_surface_scanned_out_on_output(PSURFACE, pMonitor->output);
if (wlr_output_commit(pMonitor->output)) { if (pMonitor->state.commit()) {
if (!m_pLastScanout) { if (!m_pLastScanout) {
m_pLastScanout = PCANDIDATE; m_pLastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE, PCANDIDATE->m_szTitle); Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE, PCANDIDATE->m_szTitle);
@ -1013,14 +1026,15 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
const auto PGAMMACTRL = wlr_gamma_control_manager_v1_get_control(g_pCompositor->m_sWLRGammaCtrlMgr, pMonitor->output); const auto PGAMMACTRL = wlr_gamma_control_manager_v1_get_control(g_pCompositor->m_sWLRGammaCtrlMgr, pMonitor->output);
if (!wlr_gamma_control_v1_apply(PGAMMACTRL, &pMonitor->output->pending)) { if (!wlr_gamma_control_v1_apply(PGAMMACTRL, pMonitor->state.wlr())) {
Debug::log(ERR, "Could not apply gamma control to {}", pMonitor->szName); Debug::log(ERR, "Could not apply gamma control to {}", pMonitor->szName);
return; return;
} }
if (!wlr_output_test(pMonitor->output)) { if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(ERR, "Output test failed for setting gamma to {}", pMonitor->szName); Debug::log(ERR, "Output test failed for setting gamma to {}", pMonitor->szName);
wlr_output_rollback(pMonitor->output); // aka rollback
wlr_gamma_control_v1_apply(nullptr, pMonitor->state.wlr());
wlr_gamma_control_v1_send_failed_and_destroy(PGAMMACTRL); wlr_gamma_control_v1_send_failed_and_destroy(PGAMMACTRL);
} }
} }
@ -1149,6 +1163,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
if (UNLOCK_SC) if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false); wlr_output_lock_software_cursors(pMonitor->output, false);
pMonitor->state.clear();
return; return;
} }
@ -1235,9 +1251,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
EMIT_HOOK_EVENT("render", RENDER_POST); EMIT_HOOK_EVENT("render", RENDER_POST);
pMonitor->output->pending.tearing_page_flip = shouldTear; pMonitor->state.wlr()->tearing_page_flip = shouldTear;
if (!wlr_output_commit(pMonitor->output)) { if (!pMonitor->state.commit()) {
if (UNLOCK_SC) if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false); wlr_output_lock_software_cursors(pMonitor->output, false);
@ -1324,6 +1340,8 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
std::string commandForCfg = ""; std::string commandForCfg = "";
const auto OUTPUT = head->state.output; const auto OUTPUT = head->state.output;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT);
RASSERT(PMONITOR, "nullptr monitor in outputMgrApplyTest");
commandForCfg += std::string(OUTPUT->name) + ","; commandForCfg += std::string(OUTPUT->name) + ",";
@ -1334,7 +1352,7 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
continue; continue;
} }
wlr_output_enable(OUTPUT, head->state.enabled); wlr_output_state_set_enabled(PMONITOR->state.wlr(), head->state.enabled);
if (head->state.mode) if (head->state.mode)
commandForCfg += commandForCfg +=
@ -1348,10 +1366,10 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
if (!test) { if (!test) {
g_pConfigManager->parseKeyword("monitor", commandForCfg, true); g_pConfigManager->parseKeyword("monitor", commandForCfg, true);
wlr_output_state_set_adaptive_sync_enabled(&OUTPUT->pending, head->state.adaptive_sync_enabled); wlr_output_state_set_adaptive_sync_enabled(PMONITOR->state.wlr(), head->state.adaptive_sync_enabled);
} }
ok = wlr_output_test(OUTPUT); ok = wlr_output_test_state(OUTPUT, PMONITOR->state.wlr());
if (!ok) if (!ok)
break; break;
@ -1572,8 +1590,7 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, dou
y += CORRECTION.y; y += CORRECTION.y;
} }
CRegion damageBox; CRegion damageBox{&pSurface->buffer_damage};
wlr_surface_get_effective_damage(pSurface, damageBox.pixman());
if (scale != 1.0) if (scale != 1.0)
wlr_region_scale(damageBox.pixman(), damageBox.pixman(), scale); wlr_region_scale(damageBox.pixman(), damageBox.pixman(), scale);
@ -1750,6 +1767,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
return true; return true;
} }
const auto WAS10B = pMonitor->enabled10bit;
const auto OLDRES = pMonitor->vecPixelSize;
// Needed in case we are switching from a custom modeline to a standard mode // Needed in case we are switching from a custom modeline to a standard mode
pMonitor->customDrmMode = {}; pMonitor->customDrmMode = {};
bool autoScale = false; bool autoScale = false;
@ -1762,10 +1782,10 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->scale = DEFAULTSCALE; pMonitor->scale = DEFAULTSCALE;
} }
wlr_output_set_scale(pMonitor->output, pMonitor->scale); wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
pMonitor->setScale = pMonitor->scale; pMonitor->setScale = pMonitor->scale;
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform); wlr_output_state_set_transform(pMonitor->state.wlr(), pMonitorRule->transform);
pMonitor->transform = pMonitorRule->transform; pMonitor->transform = pMonitorRule->transform;
const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : pMonitorRule->refreshRate * 1000; const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : pMonitorRule->refreshRate * 1000;
@ -1780,9 +1800,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it // if delta of refresh rate, w and h chosen and mode is < 1 we accept it
if (DELTALESSTHAN(mode->width, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(mode->height, pMonitorRule->resolution.y, 1) && if (DELTALESSTHAN(mode->width, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(mode->height, pMonitorRule->resolution.y, 1) &&
DELTALESSTHAN(mode->refresh / 1000.f, pMonitorRule->refreshRate, 1)) { DELTALESSTHAN(mode->refresh / 1000.f, pMonitorRule->refreshRate, 1)) {
wlr_output_set_mode(pMonitor->output, mode); wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (!wlr_output_test(pMonitor->output)) { if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
continue; continue;
} }
@ -1800,11 +1820,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
if (!found) { if (!found) {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE); wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE);
pMonitor->vecSize = pMonitorRule->resolution; pMonitor->vecSize = pMonitorRule->resolution;
pMonitor->refreshRate = pMonitorRule->refreshRate; pMonitor->refreshRate = pMonitorRule->refreshRate;
if (!wlr_output_test(pMonitor->output)) { if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
@ -1816,7 +1836,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
// Preferred is valid // Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE); wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name,
pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
@ -1838,7 +1858,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} else { } else {
auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &pMonitorRule->drmMode); auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &pMonitorRule->drmMode);
if (mode) { if (mode) {
wlr_output_set_mode(pMonitor->output, mode); wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
pMonitor->customDrmMode = pMonitorRule->drmMode; pMonitor->customDrmMode = pMonitorRule->drmMode;
} else { } else {
Debug::log(ERR, "wlr_drm_connector_add_mode failed"); Debug::log(ERR, "wlr_drm_connector_add_mode failed");
@ -1846,13 +1866,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
} }
} else { } else {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE); wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE);
} }
pMonitor->vecSize = pMonitorRule->resolution; pMonitor->vecSize = pMonitorRule->resolution;
pMonitor->refreshRate = pMonitorRule->refreshRate; pMonitor->refreshRate = pMonitorRule->refreshRate;
if (fail || !wlr_output_test(pMonitor->output)) { if (fail || !wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
@ -1864,7 +1884,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
// Preferred is valid // Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE); wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name,
pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
@ -1888,8 +1908,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
if (pMonitorRule->resolution == Vector2D(-1, -1)) { if (pMonitorRule->resolution == Vector2D(-1, -1)) {
wl_list_for_each(mode, &pMonitor->output->modes, link) { wl_list_for_each(mode, &pMonitor->output->modes, link) {
if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) { if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) {
wlr_output_set_mode(pMonitor->output, mode); wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (wlr_output_test(pMonitor->output)) { if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
currentWidth = mode->width; currentWidth = mode->width;
currentHeight = mode->height; currentHeight = mode->height;
currentRefresh = mode->refresh; currentRefresh = mode->refresh;
@ -1901,8 +1921,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
wl_list_for_each(mode, &pMonitor->output->modes, link) { wl_list_for_each(mode, &pMonitor->output->modes, link) {
if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) ||
(mode->width > currentWidth && mode->height > currentHeight)) { (mode->width > currentWidth && mode->height > currentHeight)) {
wlr_output_set_mode(pMonitor->output, mode); wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (wlr_output_test(pMonitor->output)) { if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
currentWidth = mode->width; currentWidth = mode->width;
currentHeight = mode->height; currentHeight = mode->height;
currentRefresh = mode->refresh; currentRefresh = mode->refresh;
@ -1925,7 +1945,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
// Preferred is valid // Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE); wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name,
pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
@ -1950,9 +1970,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
wlr_output_mode* mode; wlr_output_mode* mode;
wl_list_for_each(mode, &pMonitor->output->modes, link) { wl_list_for_each(mode, &pMonitor->output->modes, link) {
wlr_output_set_mode(pMonitor->output, mode); wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (!wlr_output_test(pMonitor->output)) { if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
continue; continue;
} }
@ -1968,7 +1988,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
} else { } else {
// Preferred is valid // Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE); wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
@ -1977,7 +1997,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
} }
pMonitor->vrrActive = pMonitor->output->pending.adaptive_sync_enabled; // disabled here, will be tested in CConfigManager::ensureVRR() pMonitor->vrrActive = pMonitor->state.wlr()->adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR()
|| pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
pMonitor->vecPixelSize = pMonitor->vecSize; pMonitor->vecPixelSize = pMonitor->vecSize;
@ -1994,6 +2015,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero; Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero;
if (logicalZero == logicalZero.round()) { if (logicalZero == logicalZero.round()) {
pMonitor->scale = scaleZero; pMonitor->scale = scaleZero;
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
} else { } else {
for (size_t i = 1; i < 90; ++i) { for (size_t i = 1; i < 90; ++i) {
double scaleUp = (searchScale + i) / 120.0; double scaleUp = (searchScale + i) / 120.0;
@ -2031,11 +2053,15 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} else } else
pMonitor->scale = searchScale; pMonitor->scale = searchScale;
} }
// for wlroots, that likes flooring, we have to do this.
double logicalX = std::round(pMonitor->vecPixelSize.x / pMonitor->scale);
logicalX += 0.1;
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->vecPixelSize.x / logicalX);
} }
} }
wlr_output_set_scale(pMonitor->output, pMonitor->scale);
// clang-format off // clang-format off
static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{ static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */ std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */
@ -2051,9 +2077,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->drmFormat = DRM_FORMAT_INVALID; pMonitor->drmFormat = DRM_FORMAT_INVALID;
for (auto& fmt : formats[(int)!pMonitorRule->enable10bit]) { for (auto& fmt : formats[(int)!pMonitorRule->enable10bit]) {
wlr_output_set_render_format(pMonitor->output, fmt.second); wlr_output_state_set_render_format(pMonitor->state.wlr(), fmt.second);
if (!wlr_output_test(pMonitor->output)) { if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first);
} else { } else {
Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first); Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first);
@ -2067,9 +2093,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->enabled10bit = set10bit; pMonitor->enabled10bit = set10bit;
if (!wlr_output_commit(pMonitor->output)) { if (!pMonitor->state.commit())
Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name); Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name);
}
int x, y; int x, y;
wlr_output_transformed_resolution(pMonitor->output, &x, &y); wlr_output_transformed_resolution(pMonitor->output, &x, &y);
@ -2085,14 +2110,21 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->updateMatrix(); pMonitor->updateMatrix();
// update renderer (here because it will call rollback, so we cannot do this before committing) if (WAS10B != pMonitor->enabled10bit || OLDRES != pMonitor->vecPixelSize)
g_pHyprOpenGL->destroyMonitorResources(pMonitor); g_pHyprOpenGL->destroyMonitorResources(pMonitor);
// updato wlroots // updato wlroots
g_pCompositor->arrangeMonitors(); g_pCompositor->arrangeMonitors();
wlr_damage_ring_set_bounds(&pMonitor->damage, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); wlr_damage_ring_set_bounds(&pMonitor->damage, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
// Set scale for all surfaces on this monitor, needed for some clients
// but not on unsafe state to avoid crashes
if (!g_pCompositor->m_bUnsafeState) {
for (auto& w : g_pCompositor->m_vWindows) {
w->updateSurfaceScaleTransformDetails();
}
}
// updato us // updato us
arrangeLayersForMonitor(pMonitor->ID); arrangeLayersForMonitor(pMonitor->ID);
@ -2429,7 +2461,7 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
} }
if (!buffer) { if (!buffer) {
if (!wlr_output_configure_primary_swapchain(pMonitor->output, &pMonitor->output->pending, &pMonitor->output->swapchain)) if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain))
return false; return false;
m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &m_iLastBufferAge); m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &m_iLastBufferAge);
@ -2473,7 +2505,7 @@ void CHyprRenderer::endRender() {
glFlush(); glFlush();
if (m_eRenderMode == RENDER_MODE_NORMAL) { if (m_eRenderMode == RENDER_MODE_NORMAL) {
wlr_output_state_set_buffer(&PMONITOR->output->pending, m_pCurrentWlrBuffer); wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer);
unsetEGL(); // flush the context unsetEGL(); // flush the context
} }

View file

@ -57,7 +57,7 @@ class CHyprRenderer {
void ensureCursorRenderingMode(); void ensureCursorRenderingMode();
bool shouldRenderCursor(); bool shouldRenderCursor();
void setCursorHidden(bool hide); void setCursorHidden(bool hide);
void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false); void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false);
std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
void renderLockscreen(CMonitor* pMonitor, timespec* now); void renderLockscreen(CMonitor* pMonitor, timespec* now);
void setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace); void setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace);
@ -82,7 +82,6 @@ class CHyprRenderer {
CMonitor* m_pMostHzMonitor = nullptr; CMonitor* m_pMostHzMonitor = nullptr;
bool m_bDirectScanoutBlocked = false; bool m_bDirectScanoutBlocked = false;
bool m_bSoftwareCursorsLocked = false; bool m_bSoftwareCursorsLocked = false;
bool m_bTearingEnvSatisfied = false;
DAMAGETRACKINGMODES DAMAGETRACKINGMODES
damageTrackingModeFromStr(const std::string&); damageTrackingModeFromStr(const std::string&);

View file

@ -26,9 +26,10 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindow
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {} CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {}
SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue; static auto* const PHEIGHT = &g_pConfigManager->getConfigValuePtr("group:groupbar:height")->intValue;
static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue; static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue; static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue;
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
SDecorationPositioningInfo info; SDecorationPositioningInfo info;
info.policy = DECORATION_POSITION_STICKY; info.policy = DECORATION_POSITION_STICKY;
@ -37,7 +38,7 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
info.reserved = true; info.reserved = true;
if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate) if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate)
info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2}, {0, 0}}; info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}};
else else
info.desiredExtents = {{0, 0}, {0, 0}}; info.desiredExtents = {{0, 0}, {0, 0}};
@ -90,6 +91,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue; static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue; static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue;
static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue; static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue;
static auto* const PHEIGHT = &g_pConfigManager->getConfigValuePtr("group:groupbar:height")->intValue;
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue; static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate) if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate)
@ -99,7 +101,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
m_fBarWidth = (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; m_fBarWidth = (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw;
const auto DESIREDHEIGHT = BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2; const auto DESIREDHEIGHT = BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2;
if (DESIREDHEIGHT != ASSIGNEDBOX.h) if (DESIREDHEIGHT != ASSIGNEDBOX.h)
g_pDecorationPositioner->repositionDeco(this); g_pDecorationPositioner->repositionDeco(this);
@ -128,12 +130,18 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
color.a *= a; color.a *= a;
g_pHyprOpenGL->renderRect(&rect, color); g_pHyprOpenGL->renderRect(&rect, color);
// render title if necessary rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth,
if (*PRENDERTITLES) { ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2};
CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, rect.scale(pMonitor->scale);
ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2};
rect.scale(pMonitor->scale);
if (*PGRADIENTS) {
const auto& GRADIENTTEX = (m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
if (GRADIENTTEX.m_iTexID != 0)
g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
}
if (*PRENDERTITLES) {
CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle); CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle);
if (!pTitleTex) if (!pTitleTex)
@ -142,12 +150,6 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale})) Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}))
.get(); .get();
const auto& GRADIENTTEX = (m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
if (*PGRADIENTS && GRADIENTTEX.m_iTexID != 0)
g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale; rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale;
rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale; rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale;
@ -243,7 +245,7 @@ CTitleTex::~CTitleTex() {
tex.destroyTexture(); tex.destroyTexture();
} }
void renderGradientTo(CTexture& tex, const CColor& grad) { void renderGradientTo(CTexture& tex, CGradientValueData* grad) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return; return;
@ -261,8 +263,12 @@ void renderGradientTo(CTexture& tex, const CColor& grad) {
cairo_pattern_t* pattern; cairo_pattern_t* pattern;
pattern = cairo_pattern_create_linear(0, 0, 0, bufferSize.y); pattern = cairo_pattern_create_linear(0, 0, 0, bufferSize.y);
cairo_pattern_add_color_stop_rgba(pattern, 1, grad.r, grad.g, grad.b, grad.a);
cairo_pattern_add_color_stop_rgba(pattern, 0, grad.r, grad.g, grad.b, 0); for (unsigned long i = 0; i < grad->m_vColors.size(); i++) {
cairo_pattern_add_color_stop_rgba(pattern, 1 - (double)(i + 1) / (grad->m_vColors.size() + 1), grad->m_vColors[i].r, grad->m_vColors[i].g, grad->m_vColors[i].b,
grad->m_vColors[i].a);
}
cairo_rectangle(CAIRO, 0, 0, bufferSize.x, bufferSize.y); cairo_rectangle(CAIRO, 0, 0, bufferSize.x, bufferSize.y);
cairo_set_source(CAIRO, pattern); cairo_set_source(CAIRO, pattern);
cairo_fill(CAIRO); cairo_fill(CAIRO);
@ -290,13 +296,13 @@ void renderGradientTo(CTexture& tex, const CColor& grad) {
} }
void refreshGroupBarGradients() { void refreshGroupBarGradients() {
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue; static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue; static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data; CGradientValueData* PGROUPCOLACTIVE = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data.get();
static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data; CGradientValueData* PGROUPCOLINACTIVE = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data.get();
static auto* const PGROUPCOLACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data; CGradientValueData* PGROUPCOLACTIVELOCKED = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data.get();
static auto* const PGROUPCOLINACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data; CGradientValueData* PGROUPCOLINACTIVELOCKED = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data.get();
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
@ -310,10 +316,10 @@ void refreshGroupBarGradients() {
if (!*PENABLED || !*PGRADIENTS) if (!*PENABLED || !*PGRADIENTS)
return; return;
renderGradientTo(m_tGradientActive, ((CGradientValueData*)PGROUPCOLACTIVE->get())->m_vColors[0]); renderGradientTo(m_tGradientActive, PGROUPCOLACTIVE);
renderGradientTo(m_tGradientInactive, ((CGradientValueData*)PGROUPCOLINACTIVE->get())->m_vColors[0]); renderGradientTo(m_tGradientInactive, PGROUPCOLINACTIVE);
renderGradientTo(m_tGradientLockedActive, ((CGradientValueData*)PGROUPCOLACTIVELOCKED->get())->m_vColors[0]); renderGradientTo(m_tGradientLockedActive, PGROUPCOLACTIVELOCKED);
renderGradientTo(m_tGradientLockedInactive, ((CGradientValueData*)PGROUPCOLINACTIVELOCKED->get())->m_vColors[0]); renderGradientTo(m_tGradientLockedInactive, PGROUPCOLINACTIVELOCKED);
} }
bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {

View file

@ -1,45 +0,0 @@
diff --git a/include/meson.build b/include/meson.build
index e669800..687786b 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -1,4 +1,5 @@
-subdir('wlr')
+run_command('ln', '-sf', join_paths(meson.project_source_root(), 'include', 'wlr'), join_paths(meson.project_source_root(), 'include', 'wlroots'), check: true)
+subdir('wlroots')
exclude_files = ['meson.build', 'config.h.in', 'version.h.in']
if not features.get('drm-backend')
@@ -24,8 +25,8 @@ if not features.get('session')
exclude_files += 'backend/session.h'
endif
-install_subdir('wlr',
- install_dir: get_option('includedir'),
+install_subdir('wlroots',
+ install_dir: join_paths(get_option('includedir'), 'hyprland'),
exclude_files: exclude_files,
)
diff --git a/include/wlr/meson.build b/include/wlr/meson.build
index f7ca413..0a86d54 100644
--- a/include/wlr/meson.build
+++ b/include/wlr/meson.build
@@ -22,4 +22,4 @@ ver_h = configure_file(
configuration: version_data,
)
-install_headers(conf_h, ver_h, subdir: 'wlr')
+install_headers(conf_h, ver_h, subdir: join_paths('hyprland', 'wlroots'))
diff --git a/meson.build b/meson.build
index 29b103a..0b6e5a4 100644
--- a/meson.build
+++ b/meson.build
@@ -15,7 +15,7 @@ project(
version_major = version.split('.')[0]
version_minor = version.split('.')[1]
assert(version_major == '0')
-soversion = version_minor.to_int() - 5
+soversion = 13032
little_endian = target_machine.endian() == 'little'
big_endian = target_machine.endian() == 'big'

@ -1 +1 @@
Subproject commit f81c3d93cd6f61b20ae784297679283438def8df Subproject commit 00b869c1a96f300a8f25da95d624524895e0ddf2

View file

@ -1,7 +0,0 @@
[wrap-git]
directory = wlroots
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
revision = f81c3d93cd6f61b20ae784297679283438def8df
depth = 1
diff_files = wlroots-meson-build.patch