mirror of
https://github.com/Trensa-Organization/Hyprland.git
synced 2025-03-15 18:53:39 +01:00
update: made it up to date with upstream
This commit is contained in:
parent
aba725a29e
commit
0c51b36b10
95 changed files with 3230 additions and 1161 deletions
1
.clang-format-ignore
Normal file
1
.clang-format-ignore
Normal file
|
@ -0,0 +1 @@
|
|||
subprojects/**/*
|
75
.github/actions/setup_base/action.yml
vendored
Normal file
75
.github/actions/setup_base/action.yml
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
name: "Setup base"
|
||||
|
||||
inputs:
|
||||
INSTALL_XORG_PKGS:
|
||||
description: 'Install xorg dependencies'
|
||||
required: false
|
||||
default: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Get required pacman pkgs
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
|
||||
pacman --noconfirm --noprogressbar -Syyu
|
||||
pacman --noconfirm --noprogressbar -Sy \
|
||||
base-devel \
|
||||
cairo \
|
||||
clang \
|
||||
cmake \
|
||||
git \
|
||||
glm \
|
||||
glslang \
|
||||
go \
|
||||
jq \
|
||||
libc++ \
|
||||
libdisplay-info \
|
||||
libdrm \
|
||||
libepoxy \
|
||||
libfontenc \
|
||||
libglvnd \
|
||||
libinput \
|
||||
libliftoff \
|
||||
libxcvt \
|
||||
libxfont2 \
|
||||
libxkbcommon \
|
||||
libxkbfile \
|
||||
lld \
|
||||
meson \
|
||||
ninja \
|
||||
pango \
|
||||
pixman \
|
||||
pkgconf \
|
||||
scdoc \
|
||||
seatd \
|
||||
systemd \
|
||||
tomlplusplus \
|
||||
wayland \
|
||||
wayland-protocols \
|
||||
xcb-util-errors \
|
||||
xcb-util-renderutil \
|
||||
xcb-util-wm
|
||||
|
||||
- name: Get Xorg pacman pkgs
|
||||
shell: bash
|
||||
if: inputs.INSTALL_XORG_PKGS == 'true'
|
||||
run: |
|
||||
pacman --noconfirm --noprogressbar -Sy \
|
||||
xorg-fonts-encodings \
|
||||
xorg-server-common \
|
||||
xorg-setxkbmap \
|
||||
xorg-xkbcomp \
|
||||
xorg-xwayland
|
||||
|
||||
- name: Checkout Hyprland
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
# Fix an issue with actions/checkout where the checkout repo is not mark as safe
|
||||
- name: Mark directory as safe for git
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global --add safe.directory /__w/Hyprland/Hyprland
|
|
@ -245,5 +245,6 @@ protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" f
|
|||
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
|
||||
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
|
||||
|
||||
# hyprctl
|
||||
# tools
|
||||
add_subdirectory(hyprctl)
|
||||
add_subdirectory(hyprpm)
|
||||
|
|
4
Makefile
4
Makefile
|
@ -38,8 +38,11 @@ install:
|
|||
mkdir -p ${PREFIX}/bin
|
||||
cp -f ./build/Hyprland ${PREFIX}/bin
|
||||
cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin
|
||||
cp -f ./build/hyprpm/hyprpm ${PREFIX}/bin
|
||||
chmod 755 ${PREFIX}/bin/Hyprland
|
||||
chmod 755 ${PREFIX}/bin/hyprctl
|
||||
chmod 755 ${PREFIX}/bin/hyprpm
|
||||
ln -s -r ${PREFIX}/bin/Hyprland ${PREFIX}/bin/hyprland
|
||||
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
|
||||
mkdir -p ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
||||
|
@ -58,6 +61,7 @@ uninstall:
|
|||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
rm -f ${PREFIX}/bin/Hyprland
|
||||
rm -f ${PREFIX}/bin/hyprctl
|
||||
rm -f ${PREFIX}/bin/hyprpm
|
||||
rm -f ${PREFIX}/lib/libwlroots.so.13032
|
||||
rm -rf ${PREFIX}/share/hyprland
|
||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||
|
|
|
@ -23,8 +23,10 @@ monitor=,preferred,auto,auto
|
|||
$terminal = kitty
|
||||
$fileManager = dolphin
|
||||
$menu = wofi --show drun
|
||||
|
||||
# Some default env vars.
|
||||
env = XCURSOR_SIZE,24
|
||||
env = QT_QPA_PLATFORMTHEME,qt5ct # change to qt6ct if you have that
|
||||
|
||||
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||
input {
|
||||
|
|
12
flake.lock
generated
12
flake.lock
generated
|
@ -25,11 +25,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1700612854,
|
||||
"narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
|
||||
"lastModified": 1703438236,
|
||||
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
|
||||
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -95,11 +95,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1700508250,
|
||||
"narHash": "sha256-X4o/mifI7Nhu0UKYlxx53wIC+gYDo3pVM9L2u3PE2bE=",
|
||||
"lastModified": 1703514399,
|
||||
"narHash": "sha256-VRr5Xc4S/VPr/gU3fiOD3vSIL2+GJ+LUrmFTWTwnTz4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "eb120ff25265ecacd0fc13d7dab12131b60d0f47",
|
||||
"rev": "0a318a7a217a6402b0b705837cd5b50b0e94b31b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -62,12 +62,16 @@
|
|||
inherit
|
||||
(pkgsFor.${system})
|
||||
# hyprland-packages
|
||||
|
||||
hyprland
|
||||
hyprland-unwrapped
|
||||
hyprland-debug
|
||||
hyprland-legacy-renderer
|
||||
# hyprland-extras
|
||||
|
||||
xdg-desktop-portal-hyprland
|
||||
# dependencies
|
||||
|
||||
hyprland-protocols
|
||||
wlroots-hyprland
|
||||
udis86
|
||||
|
@ -75,7 +79,8 @@
|
|||
});
|
||||
|
||||
devShells = eachSystem (system: {
|
||||
default = pkgsFor.${system}.mkShell.override {
|
||||
default =
|
||||
pkgsFor.${system}.mkShell.override {
|
||||
stdenv = pkgsFor.${system}.gcc13Stdenv;
|
||||
} {
|
||||
name = "hyprland-shell";
|
||||
|
|
|
@ -23,39 +23,49 @@
|
|||
#include <filesystem>
|
||||
#include <stdarg.h>
|
||||
|
||||
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
|
||||
|
||||
commands:
|
||||
activewindow
|
||||
activeworkspace
|
||||
binds
|
||||
clients
|
||||
cursorpos
|
||||
devices
|
||||
dispatch
|
||||
getoption
|
||||
globalshortcuts
|
||||
hyprpaper
|
||||
instances
|
||||
keyword
|
||||
kill
|
||||
layers
|
||||
layouts
|
||||
monitors
|
||||
notify
|
||||
plugin
|
||||
reload
|
||||
setcursor
|
||||
seterror
|
||||
setprop
|
||||
splash
|
||||
switchxkblayout
|
||||
version
|
||||
workspacerules
|
||||
workspaces
|
||||
|
||||
flags:
|
||||
const std::string USAGE = R"#(usage: hyprctl [flags] [<command> [args]]
|
||||
hyprctl --batch {<command 1> [args] ; <command 2> [args] ; ...}
|
||||
LISTING COMMANDS:
|
||||
monitors: List outputs
|
||||
workspaces: List all workspaces
|
||||
activeworkspace: Get currently active workspace
|
||||
clients: List clients (e.g. windows)
|
||||
activewindow: Get currently active window
|
||||
layers: List layers
|
||||
animations: List animations and bezier curves in use
|
||||
devices: List devices
|
||||
binds: List registered binds
|
||||
instances: List running Hyprland instances
|
||||
layouts: List layouts
|
||||
globalshortcuts: List global shortcuts
|
||||
version: Print hyprland version
|
||||
CONFIGURATION COMMANDS:
|
||||
keyword <keyword> [args]: Execute a keyword
|
||||
getoption <option>: Get value of <option>
|
||||
reload: Reload configurations
|
||||
PLUGIN:
|
||||
plugin list: List loaded plugins
|
||||
plugin load <path>: Load plugin from <path>
|
||||
plugin unload <path>: Unload plugin at <path>
|
||||
THEMING:
|
||||
hyprpaper <keywords> Issue hyprpaper keywords using IPC
|
||||
splash: Prints the current random splash
|
||||
cursorpos: Get the current cursor position in global layout coordinates
|
||||
setcursor <theme> <size>: Set cursor theme and size, (except for GTK)
|
||||
ADDITIONAL COMMANDS:
|
||||
dispatch <name> [args]: Run a dispatcher
|
||||
kill: Enter kill mode, where you can kill an app by clicking on it,
|
||||
use ESCAPE to quit kill mode
|
||||
switchxkblayout <args>: Sets the xkb layout index for a keyboard, see wiki for details
|
||||
setprop <window> <prop>: Set window property, see wiki for details
|
||||
seterror <color> <msg>: Display <msg> as a error message, will reset upon reloading config
|
||||
seterror disable: Clear error message
|
||||
notify <icon> <time_ms> <color> <message>:
|
||||
Sends a notification using the built-in Hyprland notification system.
|
||||
output <args>: Add and remove fake outputs to specified backend, see wiki for details.
|
||||
FLAGS:
|
||||
-j -> output in JSON
|
||||
--help -> display this help
|
||||
--batch -> execute a batch of commands, separated by ';'
|
||||
--instance (-i) -> use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc)
|
||||
)#";
|
||||
|
@ -330,6 +340,12 @@ int main(int argc, char** argv) {
|
|||
|
||||
fullRequest = fullArgs + "/" + fullRequest;
|
||||
|
||||
// instances is HIS-independent
|
||||
if (fullRequest.contains("/instances")) {
|
||||
instancesRequest(json);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (overrideInstance.contains("_"))
|
||||
instanceSignature = overrideInstance;
|
||||
else if (!overrideInstance.empty()) {
|
||||
|
@ -399,8 +415,6 @@ int main(int argc, char** argv) {
|
|||
request(fullRequest);
|
||||
else if (fullRequest.contains("/rollinglog"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/instances"))
|
||||
instancesRequest(json);
|
||||
else if (fullRequest.contains("/switchxkblayout"))
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/seterror"))
|
||||
|
@ -419,6 +433,8 @@ int main(int argc, char** argv) {
|
|||
request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/keyword"))
|
||||
request(fullRequest, 2);
|
||||
else if (fullRequest.contains("/decorations"))
|
||||
request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/hyprpaper"))
|
||||
requestHyprpaper(fullRequest);
|
||||
else if (fullRequest.contains("/layouts"))
|
||||
|
|
16
hyprpm/CMakeLists.txt
Normal file
16
hyprpm/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
project(
|
||||
hyprpm
|
||||
DESCRIPTION "A Hyprland Plugin Manager"
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus)
|
||||
|
||||
add_executable(hyprpm ${SRCFILES})
|
||||
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus)
|
215
hyprpm/src/core/DataState.cpp
Normal file
215
hyprpm/src/core/DataState.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
#include "DataState.hpp"
|
||||
#include <toml++/toml.hpp>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include "PluginManager.hpp"
|
||||
|
||||
std::string DataState::getDataStatePath() {
|
||||
const auto HOME = getenv("HOME");
|
||||
if (!HOME) {
|
||||
std::cerr << "DataState: no $HOME\n";
|
||||
throw std::runtime_error("no $HOME");
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
|
||||
|
||||
if (XDG_DATA_HOME)
|
||||
return std::string{XDG_DATA_HOME} + "/hyprpm";
|
||||
return std::string{HOME} + "/.local/share/hyprpm";
|
||||
}
|
||||
|
||||
void DataState::ensureStateStoreExists() {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
if (!std::filesystem::exists(PATH))
|
||||
std::filesystem::create_directories(PATH);
|
||||
}
|
||||
|
||||
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath() + "/" + repo.name;
|
||||
|
||||
std::filesystem::create_directories(PATH);
|
||||
// clang-format off
|
||||
auto DATA = toml::table{
|
||||
{"repository", toml::table{
|
||||
{"name", repo.name},
|
||||
{"hash", repo.hash},
|
||||
{"url", repo.url}
|
||||
}}
|
||||
};
|
||||
for (auto& p : repo.plugins) {
|
||||
// copy .so to the good place
|
||||
std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
|
||||
|
||||
DATA.emplace(p.name, toml::table{
|
||||
{"filename", p.name + ".so"},
|
||||
{"enabled", p.enabled}
|
||||
});
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
|
||||
ofs << DATA;
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
bool DataState::pluginRepoExists(const std::string& urlOrName) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
|
||||
if (URL == urlOrName || NAME == urlOrName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DataState::removePluginRepo(const std::string& urlOrName) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
|
||||
if (URL == urlOrName || NAME == urlOrName) {
|
||||
|
||||
// unload the plugins!!
|
||||
for (const auto& file : std::filesystem::directory_iterator(entry.path())) {
|
||||
if (!file.path().string().ends_with(".so"))
|
||||
continue;
|
||||
|
||||
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
|
||||
}
|
||||
|
||||
std::filesystem::remove_all(entry.path());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DataState::updateGlobalState(const SGlobalState& state) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
std::filesystem::create_directories(PATH);
|
||||
// clang-format off
|
||||
auto DATA = toml::table{
|
||||
{"state", toml::table{
|
||||
{"hash", state.headersHashCompiled},
|
||||
{"dont_warn_install", state.dontWarnInstall}
|
||||
}}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
|
||||
ofs << DATA;
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
SGlobalState DataState::getGlobalState() {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
if (!std::filesystem::exists(PATH + "/state.toml"))
|
||||
return SGlobalState{};
|
||||
|
||||
auto DATA = toml::parse_file(PATH + "/state.toml");
|
||||
|
||||
SGlobalState state;
|
||||
state.headersHashCompiled = DATA["state"]["hash"].value_or("");
|
||||
state.dontWarnInstall = DATA["state"]["dont_warn_install"].value_or(false);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
std::vector<SPluginRepository> repos;
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
|
||||
const auto NAME = STATE["repository"]["name"].value_or("");
|
||||
const auto URL = STATE["repository"]["url"].value_or("");
|
||||
const auto HASH = STATE["repository"]["hash"].value_or("");
|
||||
|
||||
SPluginRepository repo;
|
||||
repo.hash = HASH;
|
||||
repo.name = NAME;
|
||||
repo.url = URL;
|
||||
|
||||
for (const auto& [key, val] : STATE) {
|
||||
if (key == "repository")
|
||||
continue;
|
||||
|
||||
const auto ENABLED = STATE[key]["enabled"].value_or(false);
|
||||
const auto FILENAME = STATE[key]["filename"].value_or("");
|
||||
|
||||
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED});
|
||||
}
|
||||
|
||||
repos.push_back(repo);
|
||||
}
|
||||
|
||||
return repos;
|
||||
}
|
||||
|
||||
bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
ensureStateStoreExists();
|
||||
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
|
||||
for (const auto& [key, val] : STATE) {
|
||||
if (key == "repository")
|
||||
continue;
|
||||
|
||||
if (key.str() != name)
|
||||
continue;
|
||||
|
||||
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
|
||||
|
||||
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
|
||||
state << STATE;
|
||||
state.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
21
hyprpm/src/core/DataState.hpp
Normal file
21
hyprpm/src/core/DataState.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Plugin.hpp"
|
||||
|
||||
struct SGlobalState {
|
||||
std::string headersHashCompiled = "";
|
||||
bool dontWarnInstall = false;
|
||||
};
|
||||
|
||||
namespace DataState {
|
||||
std::string getDataStatePath();
|
||||
void ensureStateStoreExists();
|
||||
void addNewPluginRepo(const SPluginRepository& repo);
|
||||
void removePluginRepo(const std::string& urlOrName);
|
||||
bool pluginRepoExists(const std::string& urlOrName);
|
||||
void updateGlobalState(const SGlobalState& state);
|
||||
SGlobalState getGlobalState();
|
||||
bool setPluginEnabled(const std::string& name, bool enabled);
|
||||
std::vector<SPluginRepository> getAllRepositories();
|
||||
};
|
104
hyprpm/src/core/Manifest.cpp
Normal file
104
hyprpm/src/core/Manifest.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include "Manifest.hpp"
|
||||
#include <toml++/toml.hpp>
|
||||
#include <iostream>
|
||||
|
||||
CManifest::CManifest(const eManifestType type, const std::string& path) {
|
||||
auto manifest = toml::parse_file(path);
|
||||
|
||||
if (type == MANIFEST_HYPRLOAD) {
|
||||
for (auto& [key, val] : manifest) {
|
||||
if (key.str().ends_with(".build"))
|
||||
continue;
|
||||
|
||||
CManifest::SManifestPlugin plugin;
|
||||
plugin.name = key;
|
||||
m_vPlugins.push_back(plugin);
|
||||
}
|
||||
|
||||
for (auto& plugin : m_vPlugins) {
|
||||
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
||||
plugin.version = manifest[plugin.name]["version"].value_or("?");
|
||||
plugin.output = manifest[plugin.name]["build"]["output"].value_or("?");
|
||||
auto authors = manifest[plugin.name]["authors"].as_array();
|
||||
if (authors) {
|
||||
for (auto&& a : *authors) {
|
||||
plugin.authors.push_back(a.as_string()->value_or("?"));
|
||||
}
|
||||
} else {
|
||||
auto author = manifest[plugin.name]["author"].value_or("");
|
||||
if (!std::string{author}.empty())
|
||||
plugin.authors.push_back(author);
|
||||
}
|
||||
auto buildSteps = manifest[plugin.name]["build"]["steps"].as_array();
|
||||
if (buildSteps) {
|
||||
for (auto&& s : *buildSteps) {
|
||||
plugin.buildSteps.push_back(s.as_string()->value_or("?"));
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
||||
m_bGood = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (type == MANIFEST_HYPRPM) {
|
||||
m_sRepository.name = manifest["repository"]["name"].value_or("");
|
||||
auto authors = manifest["repository"]["authors"].as_array();
|
||||
if (authors) {
|
||||
for (auto&& a : *authors) {
|
||||
m_sRepository.authors.push_back(a.as_string()->value_or("?"));
|
||||
}
|
||||
} else {
|
||||
auto author = manifest["repository"]["author"].value_or("");
|
||||
if (!std::string{author}.empty())
|
||||
m_sRepository.authors.push_back(author);
|
||||
}
|
||||
|
||||
auto pins = manifest["repository"]["commit_pins"].as_array();
|
||||
if (pins) {
|
||||
for (auto&& pin : *pins) {
|
||||
auto pinArr = pin.as_array();
|
||||
if (pinArr && pinArr->get(1))
|
||||
m_sRepository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get()));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [key, val] : manifest) {
|
||||
if (key.str() == "repository")
|
||||
continue;
|
||||
|
||||
CManifest::SManifestPlugin plugin;
|
||||
plugin.name = key;
|
||||
m_vPlugins.push_back(plugin);
|
||||
}
|
||||
|
||||
for (auto& plugin : m_vPlugins) {
|
||||
plugin.description = manifest[plugin.name]["description"].value_or("?");
|
||||
plugin.output = manifest[plugin.name]["output"].value_or("?");
|
||||
auto authors = manifest[plugin.name]["authors"].as_array();
|
||||
if (authors) {
|
||||
for (auto&& a : *authors) {
|
||||
plugin.authors.push_back(a.as_string()->value_or("?"));
|
||||
}
|
||||
} else {
|
||||
auto author = manifest[plugin.name]["author"].value_or("");
|
||||
if (!std::string{author}.empty())
|
||||
plugin.authors.push_back(author);
|
||||
}
|
||||
auto buildSteps = manifest[plugin.name]["build"].as_array();
|
||||
if (buildSteps) {
|
||||
for (auto&& s : *buildSteps) {
|
||||
plugin.buildSteps.push_back(s.as_string()->value_or("?"));
|
||||
}
|
||||
}
|
||||
|
||||
if (plugin.output.empty() || plugin.buildSteps.empty()) {
|
||||
m_bGood = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ???
|
||||
m_bGood = false;
|
||||
}
|
||||
}
|
32
hyprpm/src/core/Manifest.hpp
Normal file
32
hyprpm/src/core/Manifest.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum eManifestType {
|
||||
MANIFEST_HYPRLOAD,
|
||||
MANIFEST_HYPRPM
|
||||
};
|
||||
|
||||
class CManifest {
|
||||
public:
|
||||
CManifest(const eManifestType type, const std::string& path);
|
||||
|
||||
struct SManifestPlugin {
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string version;
|
||||
std::vector<std::string> authors;
|
||||
std::vector<std::string> buildSteps;
|
||||
std::string output;
|
||||
};
|
||||
|
||||
struct {
|
||||
std::string name;
|
||||
std::vector<std::string> authors;
|
||||
std::vector<std::pair<std::string, std::string>> commitPins;
|
||||
} m_sRepository;
|
||||
|
||||
std::vector<SManifestPlugin> m_vPlugins;
|
||||
bool m_bGood = true;
|
||||
};
|
17
hyprpm/src/core/Plugin.hpp
Normal file
17
hyprpm/src/core/Plugin.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct SPlugin {
|
||||
std::string name;
|
||||
std::string filename;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct SPluginRepository {
|
||||
std::string url;
|
||||
std::string name;
|
||||
std::vector<SPlugin> plugins;
|
||||
std::string hash;
|
||||
};
|
724
hyprpm/src/core/PluginManager.cpp
Normal file
724
hyprpm/src/core/PluginManager.cpp
Normal file
|
@ -0,0 +1,724 @@
|
|||
#include "PluginManager.hpp"
|
||||
#include "../helpers/Colors.hpp"
|
||||
#include "../progress/CProgressBar.hpp"
|
||||
#include "Manifest.hpp"
|
||||
#include "DataState.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <toml++/toml.hpp>
|
||||
|
||||
static std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
int countBefore = 0;
|
||||
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
int countAfter = 0;
|
||||
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
||||
countAfter++;
|
||||
}
|
||||
|
||||
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string execAndGet(std::string cmd) {
|
||||
cmd += " 2>&1";
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||
if (!pipe)
|
||||
return "";
|
||||
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
result += buffer.data();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SHyprlandVersion CPluginManager::getHyprlandVersion() {
|
||||
static SHyprlandVersion ver;
|
||||
static bool once = false;
|
||||
|
||||
if (once)
|
||||
return ver;
|
||||
|
||||
once = true;
|
||||
const auto HLVERCALL = execAndGet("hyprctl version");
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n";
|
||||
|
||||
if (!HLVERCALL.contains("Tag:")) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " You don't seem to be running Hyprland.";
|
||||
return SHyprlandVersion{};
|
||||
}
|
||||
|
||||
std::string hlcommit = HLVERCALL.substr(HLVERCALL.find("at commit") + 10);
|
||||
hlcommit = hlcommit.substr(0, hlcommit.find_first_of(' '));
|
||||
|
||||
std::string hlbranch = HLVERCALL.substr(HLVERCALL.find("from branch") + 12);
|
||||
hlbranch = hlbranch.substr(0, hlbranch.find(" at commit "));
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << "\n";
|
||||
|
||||
ver = SHyprlandVersion{hlbranch, hlcommit};
|
||||
return ver;
|
||||
}
|
||||
|
||||
bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
|
||||
if (DataState::pluginRepoExists(url)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
if (!GLOBALSTATE.dontWarnInstall) {
|
||||
std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET
|
||||
<< "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n "
|
||||
<< "This message will not appear again.\n";
|
||||
GLOBALSTATE.dontWarnInstall = true;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
}
|
||||
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << Colors::RED << " adding a new plugin repository " << Colors::RESET << "from " << url << "\n " << Colors::RED
|
||||
<< "MAKE SURE" << Colors::RESET << " that you trust the authors. " << Colors::RED << "DO NOT" << Colors::RESET
|
||||
<< " install random plugins without verifying the code and author.\n "
|
||||
<< "Are you sure? [Y/n] ";
|
||||
std::fflush(stdout);
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
|
||||
std::cout << "Aborting.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = 5;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Cloning the plugin repository";
|
||||
|
||||
progress.print();
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm")) {
|
||||
std::filesystem::create_directory("/tmp/hyprpm");
|
||||
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/new")) {
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " old plugin repo build files found in temp directory, removing.");
|
||||
std::filesystem::remove_all("/tmp/hyprpm/new");
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + url);
|
||||
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " new");
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/new")) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.m_iSteps = 1;
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned");
|
||||
progress.m_szCurrentMessage = "Reading the manifest";
|
||||
progress.print();
|
||||
|
||||
std::unique_ptr<CManifest> pManifest;
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/new/hyprpm.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, "/tmp/hyprpm/new/hyprpm.toml");
|
||||
} else if (std::filesystem::exists("/tmp/hyprpm/new/hyprload.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, "/tmp/hyprpm/new/hyprload.toml");
|
||||
}
|
||||
|
||||
if (!pManifest) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pManifest->m_bGood) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.m_iSteps = 2;
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:");
|
||||
for (auto& pl : pManifest->m_vPlugins) {
|
||||
std::string message = std::string{Colors::RESET} + " → " + pl.name + " by ";
|
||||
for (auto& a : pl.authors) {
|
||||
message += a + ", ";
|
||||
}
|
||||
if (pl.authors.size() > 0) {
|
||||
message.pop_back();
|
||||
message.pop_back();
|
||||
}
|
||||
message += " version " + pl.version;
|
||||
progress.printMessageAbove(message);
|
||||
}
|
||||
progress.m_szCurrentMessage = "Verifying headers";
|
||||
progress.print();
|
||||
|
||||
const auto HEADERSSTATUS = headersValid();
|
||||
|
||||
if (HEADERSSTATUS != HEADERS_OK) {
|
||||
std::cerr << "\n" << headerError(HEADERSSTATUS);
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.m_iSteps = 3;
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " Hyprland headers OK");
|
||||
progress.m_szCurrentMessage = "Building plugin(s)";
|
||||
progress.print();
|
||||
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
std::string out;
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/new && " + bs) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " all plugins built");
|
||||
progress.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing repository";
|
||||
progress.print();
|
||||
|
||||
// add repo toml to DataState
|
||||
SPluginRepository repo;
|
||||
std::string repohash = execAndGet("cd /tmp/hyprpm/new/ && git rev-parse HEAD");
|
||||
if (repohash.length() > 0)
|
||||
repohash.pop_back();
|
||||
repo.name = pManifest->m_sRepository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_sRepository.name;
|
||||
repo.url = url;
|
||||
repo.hash = repohash;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false});
|
||||
}
|
||||
DataState::addNewPluginRepo(repo);
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed repository");
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable");
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all("/tmp/hyprpm/new");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
if (!DataState::pluginRepoExists(urlOrName)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << Colors::YELLOW << "!" << Colors::RESET << Colors::RED << " removing a plugin repository: " << Colors::RESET << urlOrName << "\n "
|
||||
<< "Are you sure? [Y/n] ";
|
||||
std::fflush(stdout);
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
|
||||
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
|
||||
std::cout << "Aborting.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
DataState::removePluginRepo(urlOrName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
eHeadersErrors CPluginManager::headersValid() {
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
// find headers commit
|
||||
auto headers = execAndGet("pkg-config --cflags --keep-system-cflags hyprland");
|
||||
|
||||
if (!headers.contains("-I/"))
|
||||
return HEADERS_MISSING;
|
||||
|
||||
headers.pop_back(); // pop newline
|
||||
|
||||
std::string verHeader = "";
|
||||
|
||||
while (!headers.empty()) {
|
||||
const auto PATH = headers.substr(0, headers.find(" -I/", 3));
|
||||
|
||||
if (headers.find(" -I/", 3) != std::string::npos)
|
||||
headers = headers.substr(headers.find("-I/", 3));
|
||||
else
|
||||
headers = "";
|
||||
|
||||
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots"))
|
||||
continue;
|
||||
|
||||
verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h";
|
||||
break;
|
||||
}
|
||||
|
||||
if (verHeader.empty())
|
||||
return HEADERS_CORRUPTED;
|
||||
|
||||
// read header
|
||||
std::ifstream ifs(verHeader);
|
||||
if (!ifs.good())
|
||||
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>()));
|
||||
ifs.close();
|
||||
|
||||
std::string hash = verHeaderContent.substr(verHeaderContent.find("#define GIT_COMMIT_HASH") + 23);
|
||||
hash = hash.substr(0, hash.find_first_of('\n'));
|
||||
hash = hash.substr(hash.find_first_of('"') + 1);
|
||||
hash = hash.substr(0, hash.find_first_of('"'));
|
||||
|
||||
if (hash != HLVER.hash)
|
||||
return HEADERS_MISMATCHED;
|
||||
|
||||
return HEADERS_OK;
|
||||
}
|
||||
|
||||
bool CPluginManager::updateHeaders() {
|
||||
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm")) {
|
||||
std::filesystem::create_directory("/tmp/hyprpm");
|
||||
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
if (headersValid() == HEADERS_OK) {
|
||||
std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Your headers are already up-to-date.\n";
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
return true;
|
||||
}
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = 5;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Cloning the hyprland repository";
|
||||
progress.print();
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/hyprland")) {
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " old hyprland source files found in temp directory, removing.");
|
||||
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
|
||||
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland");
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/hyprland")) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned");
|
||||
progress.m_iSteps = 2;
|
||||
progress.m_szCurrentMessage = "Checking out sources";
|
||||
progress.print();
|
||||
|
||||
ret =
|
||||
execAndGet("cd /tmp/hyprpm/hyprland && git checkout " + HLVER.branch + " 2>&1 && git submodule update --init 2>&1 && git reset --hard --recurse-submodules " + HLVER.hash);
|
||||
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned: " + ret);
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " checked out to running ver");
|
||||
progress.m_iSteps = 3;
|
||||
progress.m_szCurrentMessage = "Building Hyprland";
|
||||
progress.print();
|
||||
|
||||
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");
|
||||
// le hack. Wlroots has to generate its build/include
|
||||
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build");
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland");
|
||||
progress.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing sources";
|
||||
progress.print();
|
||||
|
||||
progress.printMessageAbove(
|
||||
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.");
|
||||
|
||||
ret = execAndGet("pkexec sh \"-c\" \"cd /tmp/hyprpm/hyprland && make installheaders\"");
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "pkexec returned: " << ret << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
|
||||
|
||||
auto HEADERSVALID = headersValid();
|
||||
if (HEADERSVALID == HEADERS_OK) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed headers");
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
|
||||
std::cout << "\n";
|
||||
} else {
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID));
|
||||
progress.m_iSteps = 5;
|
||||
progress.m_szCurrentMessage = "Failed";
|
||||
progress.print();
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
std::cerr << "\n" << headerError(HEADERSVALID);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
if (headersValid() != HEADERS_OK) {
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
if (REPOS.size() < 1) {
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " No repos to update.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = REPOS.size() * 2 + 1;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Updating repositories";
|
||||
progress.print();
|
||||
|
||||
for (auto& repo : REPOS) {
|
||||
bool update = forceUpdateAll;
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Updating " + repo.name;
|
||||
progress.print();
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → checking for updates for " + repo.name);
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/update")) {
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " old update build files found in temp directory, removing.");
|
||||
std::filesystem::remove_all("/tmp/hyprpm/update");
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + repo.url);
|
||||
|
||||
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " update");
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/update")) {
|
||||
std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not clone repo: shell returned:\n" + ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
// check if git has updates
|
||||
std::string hash = execAndGet("cd /tmp/hyprpm/update && git rev-parse HEAD");
|
||||
if (!hash.empty())
|
||||
hash.pop_back();
|
||||
|
||||
update = update || hash != repo.hash;
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
std::filesystem::remove_all("/tmp/hyprpm/update");
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " is up-to-date.");
|
||||
progress.m_iSteps++;
|
||||
progress.print();
|
||||
continue;
|
||||
}
|
||||
|
||||
// we need to update
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " has updates.");
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + repo.name);
|
||||
progress.m_iSteps++;
|
||||
progress.print();
|
||||
|
||||
std::unique_ptr<CManifest> pManifest;
|
||||
|
||||
if (std::filesystem::exists("/tmp/hyprpm/update/hyprpm.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, "/tmp/hyprpm/update/hyprpm.toml");
|
||||
} else if (std::filesystem::exists("/tmp/hyprpm/update/hyprload.toml")) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest");
|
||||
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, "/tmp/hyprpm/update/hyprload.toml");
|
||||
}
|
||||
|
||||
if (!pManifest) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pManifest->m_bGood) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
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/update/ && git reset --hard --recurse-submodules " + plugin);
|
||||
}
|
||||
}
|
||||
|
||||
bool failed = false;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
std::string out;
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/update && " + bs) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
|
||||
failed = true;
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
}
|
||||
|
||||
if (failed)
|
||||
continue;
|
||||
|
||||
// add repo toml to DataState
|
||||
SPluginRepository newrepo = repo;
|
||||
newrepo.plugins.clear();
|
||||
execAndGet(
|
||||
"cd /tmp/hyprpm/update/ && git pull --recurse-submodules && git reset --hard --recurse-submodules"); // repo hash in the state.toml has to match head and not any pin
|
||||
std::string repohash = execAndGet("cd /tmp/hyprpm/update && git rev-parse HEAD");
|
||||
if (repohash.length() > 0)
|
||||
repohash.pop_back();
|
||||
newrepo.hash = repohash;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; });
|
||||
newrepo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/update/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false});
|
||||
}
|
||||
DataState::removePluginRepo(newrepo.name);
|
||||
DataState::addNewPluginRepo(newrepo);
|
||||
|
||||
std::filesystem::remove_all("/tmp/hyprpm/update");
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name);
|
||||
}
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
std::cout << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPluginManager::enablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, true);
|
||||
if (ret)
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Enabled " << name << "\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CPluginManager::disablePlugin(const std::string& name) {
|
||||
bool ret = DataState::setPluginEnabled(name, false);
|
||||
if (ret)
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Disabled " << name << "\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
|
||||
if (headersValid() != HEADERS_OK) {
|
||||
std::cerr << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
|
||||
return LOADSTATE_HEADERS_OUTDATED;
|
||||
}
|
||||
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
if (!HOME || !HIS) {
|
||||
std::cerr << "PluginManager: no $HOME or HIS\n";
|
||||
return LOADSTATE_FAIL;
|
||||
}
|
||||
const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
|
||||
|
||||
auto pluginLines = execAndGet("hyprctl plugins list | grep Plugin");
|
||||
|
||||
std::vector<std::string> loadedPlugins;
|
||||
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Ensuring plugin load state\n";
|
||||
|
||||
// iterate line by line
|
||||
while (!pluginLines.empty()) {
|
||||
auto plLine = pluginLines.substr(0, pluginLines.find("\n"));
|
||||
|
||||
if (pluginLines.find("\n") != std::string::npos)
|
||||
pluginLines = pluginLines.substr(pluginLines.find("\n") + 1);
|
||||
else
|
||||
pluginLines = "";
|
||||
|
||||
if (plLine.back() != ':')
|
||||
continue;
|
||||
|
||||
plLine = plLine.substr(7);
|
||||
plLine = plLine.substr(0, plLine.find(" by "));
|
||||
|
||||
loadedPlugins.push_back(plLine);
|
||||
}
|
||||
|
||||
// get state
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
auto enabled = [REPOS](const std::string& plugin) -> bool {
|
||||
for (auto& r : REPOS) {
|
||||
for (auto& p : r.plugins) {
|
||||
if (p.name == plugin && p.enabled)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto repoForName = [REPOS](const std::string& name) -> std::string {
|
||||
for (auto& r : REPOS) {
|
||||
for (auto& p : r.plugins) {
|
||||
if (p.name == name)
|
||||
return r.name;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
// unload disabled plugins
|
||||
for (auto& p : loadedPlugins) {
|
||||
if (!enabled(p)) {
|
||||
// unload
|
||||
loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Unloaded " << p << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// load enabled plugins
|
||||
for (auto& r : REPOS) {
|
||||
for (auto& p : r.plugins) {
|
||||
if (!p.enabled)
|
||||
continue;
|
||||
|
||||
if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
|
||||
continue;
|
||||
|
||||
loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Loaded " << p.name << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << Colors::GREEN << "✔" << Colors::RESET << " Plugin load state ensured\n";
|
||||
|
||||
return LOADSTATE_OK;
|
||||
}
|
||||
|
||||
bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
|
||||
if (load)
|
||||
execAndGet("hyprctl plugin load " + path);
|
||||
else
|
||||
execAndGet("hyprctl plugin unload " + path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPluginManager::listAllPlugins() {
|
||||
const auto REPOS = DataState::getAllRepositories();
|
||||
|
||||
for (auto& r : REPOS) {
|
||||
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
|
||||
|
||||
for (auto& p : r.plugins) {
|
||||
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name + "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false")
|
||||
<< Colors::RESET << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message) {
|
||||
execAndGet("hyprctl notify " + std::to_string((int)icon) + " " + std::to_string(durationMs) + " " + std::to_string(color) + " " + message);
|
||||
}
|
||||
|
||||
std::string CPluginManager::headerError(const eHeadersErrors err) {
|
||||
switch (err) {
|
||||
case HEADERS_CORRUPTED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_MISMATCHED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "✖" + Colors::RESET + " It doesn't seem you are running on hyprland.\n";
|
||||
case HEADERS_MISSING: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n";
|
||||
case HEADERS_DUPLICATED: {
|
||||
return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" +
|
||||
" This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" +
|
||||
" If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n";
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return std::string{Colors::RED} + "✖" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
|
||||
}
|
63
hyprpm/src/core/PluginManager.hpp
Normal file
63
hyprpm/src/core/PluginManager.hpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
enum eHeadersErrors {
|
||||
HEADERS_OK = 0,
|
||||
HEADERS_NOT_HYPRLAND,
|
||||
HEADERS_MISSING,
|
||||
HEADERS_CORRUPTED,
|
||||
HEADERS_MISMATCHED,
|
||||
HEADERS_DUPLICATED
|
||||
};
|
||||
|
||||
enum eNotifyIcons {
|
||||
ICON_WARNING = 0,
|
||||
ICON_INFO,
|
||||
ICON_HINT,
|
||||
ICON_ERROR,
|
||||
ICON_CONFUSED,
|
||||
ICON_OK,
|
||||
ICON_NONE
|
||||
};
|
||||
|
||||
enum ePluginLoadStateReturn {
|
||||
LOADSTATE_OK = 0,
|
||||
LOADSTATE_FAIL,
|
||||
LOADSTATE_PARTIAL_FAIL,
|
||||
LOADSTATE_HEADERS_OUTDATED
|
||||
};
|
||||
|
||||
struct SHyprlandVersion {
|
||||
std::string branch;
|
||||
std::string hash;
|
||||
};
|
||||
|
||||
class CPluginManager {
|
||||
public:
|
||||
bool addNewPluginRepo(const std::string& url);
|
||||
bool removePluginRepo(const std::string& urlOrName);
|
||||
|
||||
eHeadersErrors headersValid();
|
||||
bool updateHeaders();
|
||||
bool updatePlugins(bool forceUpdateAll);
|
||||
|
||||
void listAllPlugins();
|
||||
|
||||
bool enablePlugin(const std::string& name);
|
||||
bool disablePlugin(const std::string& name);
|
||||
ePluginLoadStateReturn ensurePluginsLoadState();
|
||||
|
||||
bool loadUnloadPlugin(const std::string& path, bool load);
|
||||
SHyprlandVersion getHyprlandVersion();
|
||||
|
||||
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
|
||||
|
||||
bool m_bVerbose = false;
|
||||
|
||||
private:
|
||||
std::string headerError(const eHeadersErrors err);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CPluginManager> g_pPluginManager;
|
11
hyprpm/src/helpers/Colors.hpp
Normal file
11
hyprpm/src/helpers/Colors.hpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
namespace Colors {
|
||||
constexpr const char* RED = "\x1b[31m";
|
||||
constexpr const char* GREEN = "\x1b[32m";
|
||||
constexpr const char* YELLOW = "\x1b[33m";
|
||||
constexpr const char* BLUE = "\x1b[34m";
|
||||
constexpr const char* MAGENTA = "\x1b[35m";
|
||||
constexpr const char* CYAN = "\x1b[36m";
|
||||
constexpr const char* RESET = "\x1b[0m";
|
||||
};
|
149
hyprpm/src/main.cpp
Normal file
149
hyprpm/src/main.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
#include "progress/CProgressBar.hpp"
|
||||
#include "helpers/Colors.hpp"
|
||||
#include "core/PluginManager.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┃
|
||||
┣ add [url] → Install a new plugin repository from git
|
||||
┣ remove [url/name] → Remove an installed plugin repository
|
||||
┣ enable [name] → Enable a plugin
|
||||
┣ disable [name] → Disable a plugin
|
||||
┣ update → Check and update all plugins if needed
|
||||
┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
|
||||
┣ list → List all installed plugins
|
||||
┃
|
||||
┣ Flags:
|
||||
┃
|
||||
┣ --notify | -n → Send a hyprland notification for important events (e.g. load fail)
|
||||
┣ --help | -h → Show this menu
|
||||
┣ --verbose | -v → Enable too much logging
|
||||
┗
|
||||
)#";
|
||||
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
std::vector<std::string> ARGS{argc};
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
ARGS[i] = std::string{argv[i]};
|
||||
}
|
||||
|
||||
if (ARGS.size() < 2) {
|
||||
std::cout << HELP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<std::string> command;
|
||||
bool notify = false, verbose = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (ARGS[i].starts_with("-")) {
|
||||
if (ARGS[i] == "--help" || ARGS[i] == "-h") {
|
||||
std::cout << HELP;
|
||||
return 0;
|
||||
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
|
||||
notify = true;
|
||||
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
||||
verbose = true;
|
||||
} else {
|
||||
std::cerr << "Unrecognized option " << ARGS[i];
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
command.push_back(ARGS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (command.empty()) {
|
||||
std::cout << HELP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_pPluginManager = std::make_unique<CPluginManager>();
|
||||
g_pPluginManager->m_bVerbose = verbose;
|
||||
|
||||
if (command[0] == "add") {
|
||||
if (command.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for add.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return g_pPluginManager->addNewPluginRepo(command[1]) ? 0 : 1;
|
||||
} else if (command[0] == "remove") {
|
||||
if (ARGS.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for remove.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
|
||||
} else if (command[0] == "update") {
|
||||
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
|
||||
bool headers = g_pPluginManager->updateHeaders();
|
||||
if (headers) {
|
||||
bool ret1 = g_pPluginManager->updatePlugins(!headersValid);
|
||||
|
||||
if (!ret1)
|
||||
return 1;
|
||||
|
||||
auto ret2 = g_pPluginManager->ensurePluginsLoadState();
|
||||
|
||||
if (ret2 != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (notify)
|
||||
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
|
||||
} else if (command[0] == "enable") {
|
||||
if (ARGS.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for enable.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->enablePlugin(command[1])) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't enable plugin (missing?)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
if (ret != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (command[0] == "disable") {
|
||||
if (command.size() < 2) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for disable.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_pPluginManager->disablePlugin(command[1])) {
|
||||
std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't disable plugin (missing?)\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
if (ret != LOADSTATE_OK)
|
||||
return 1;
|
||||
} else if (command[0] == "reload") {
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState();
|
||||
|
||||
if (ret != LOADSTATE_OK && notify) {
|
||||
switch (ret) {
|
||||
case LOADSTATE_FAIL:
|
||||
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
|
||||
case LOADSTATE_HEADERS_OUTDATED:
|
||||
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually.");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else if (notify) {
|
||||
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
|
||||
}
|
||||
} else if (command[0] == "list") {
|
||||
g_pPluginManager->listAllPlugins();
|
||||
} else {
|
||||
std::cout << HELP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
10
hyprpm/src/meson.build
Normal file
10
hyprpm/src/meson.build
Normal file
|
@ -0,0 +1,10 @@
|
|||
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
|
||||
src = globber.stdout().strip().split('\n')
|
||||
|
||||
executable('hyprpm', src,
|
||||
dependencies: [
|
||||
dependency('threads'),
|
||||
dependency('tomlplusplus')
|
||||
],
|
||||
install : true
|
||||
)
|
80
hyprpm/src/progress/CProgressBar.cpp
Normal file
80
hyprpm/src/progress/CProgressBar.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include "CProgressBar.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../helpers/Colors.hpp"
|
||||
|
||||
void CProgressBar::printMessageAbove(const std::string& msg) {
|
||||
struct winsize w;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
std::string spaces;
|
||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
||||
spaces += ' ';
|
||||
}
|
||||
|
||||
std::cout << "\r" << spaces << "\r" << msg << "\n";
|
||||
print();
|
||||
}
|
||||
|
||||
void CProgressBar::print() {
|
||||
struct winsize w;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
|
||||
if (m_bFirstPrint)
|
||||
std::cout << "\n";
|
||||
m_bFirstPrint = false;
|
||||
|
||||
std::string spaces;
|
||||
for (size_t i = 0; i < w.ws_col; ++i) {
|
||||
spaces += ' ';
|
||||
}
|
||||
|
||||
std::cout << "\r" << spaces << "\r";
|
||||
|
||||
std::string message = "";
|
||||
|
||||
float percentDone = 0;
|
||||
if (m_fPercentage >= 0)
|
||||
percentDone = m_fPercentage;
|
||||
else
|
||||
percentDone = (float)m_iSteps / (float)m_iMaxSteps;
|
||||
|
||||
const auto BARWIDTH = std::clamp(w.ws_col - static_cast<unsigned long>(m_szCurrentMessage.length()) - 2, 0UL, 50UL);
|
||||
|
||||
// draw bar
|
||||
message += std::string{" "} + Colors::GREEN;
|
||||
size_t i = 0;
|
||||
for (; i < std::floor(percentDone * BARWIDTH); ++i) {
|
||||
message += "━";
|
||||
}
|
||||
|
||||
if (i < BARWIDTH) {
|
||||
i++;
|
||||
|
||||
message += std::string{"╍"} + Colors::RESET;
|
||||
|
||||
for (; i < BARWIDTH; ++i) {
|
||||
message += "━";
|
||||
}
|
||||
} else
|
||||
message += Colors::RESET;
|
||||
|
||||
// draw progress
|
||||
if (m_fPercentage >= 0)
|
||||
message += " " + std::format("{}%", static_cast<int>(percentDone * 100.0)) + " ";
|
||||
else
|
||||
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
|
||||
|
||||
// draw message
|
||||
std::cout << message + " " + m_szCurrentMessage;
|
||||
|
||||
std::fflush(stdout);
|
||||
}
|
17
hyprpm/src/progress/CProgressBar.hpp
Normal file
17
hyprpm/src/progress/CProgressBar.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class CProgressBar {
|
||||
public:
|
||||
void print();
|
||||
void printMessageAbove(const std::string& msg);
|
||||
|
||||
std::string m_szCurrentMessage = "";
|
||||
size_t m_iSteps = 0;
|
||||
size_t m_iMaxSteps = 0;
|
||||
float m_fPercentage = -1; // if != -1, use percentage
|
||||
|
||||
private:
|
||||
bool m_bFirstPrint = true;
|
||||
};
|
|
@ -80,6 +80,7 @@ endforeach
|
|||
subdir('protocols')
|
||||
subdir('src')
|
||||
subdir('hyprctl')
|
||||
subdir('hyprpm/src')
|
||||
subdir('assets')
|
||||
subdir('example')
|
||||
subdir('docs')
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
lib,
|
||||
fetchurl,
|
||||
stdenv,
|
||||
pkg-config,
|
||||
makeWrapper,
|
||||
|
@ -20,6 +19,7 @@
|
|||
pango,
|
||||
pciutils,
|
||||
systemd,
|
||||
tomlplusplus,
|
||||
udis86,
|
||||
wayland,
|
||||
wayland-protocols,
|
||||
|
@ -34,21 +34,12 @@
|
|||
wrapRuntimeDeps ? true,
|
||||
version ? "git",
|
||||
commit,
|
||||
date,
|
||||
# deprecated flags
|
||||
enableNvidiaPatches ? false,
|
||||
nvidiaPatches ? false,
|
||||
hidpiXWayland ? false,
|
||||
}:
|
||||
let
|
||||
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
|
||||
libdrm_2_4_118 = libdrm.overrideAttrs(attrs: rec {
|
||||
version = "2.4.118";
|
||||
src = fetchurl {
|
||||
url = "https://dri.freedesktop.org/${attrs.pname}/${attrs.pname}-${version}.tar.xz";
|
||||
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
|
||||
};
|
||||
});
|
||||
in
|
||||
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
|
||||
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
|
||||
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
|
||||
|
@ -81,19 +72,20 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
|
||||
buildInputs =
|
||||
[
|
||||
git
|
||||
cairo
|
||||
git
|
||||
hyprland-protocols
|
||||
libdrm
|
||||
libGL
|
||||
libdrm_2_4_118
|
||||
libinput
|
||||
libxkbcommon
|
||||
mesa
|
||||
pango
|
||||
pciutils
|
||||
tomlplusplus
|
||||
udis86
|
||||
wayland
|
||||
wayland-protocols
|
||||
pciutils
|
||||
wlroots
|
||||
]
|
||||
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
|
||||
|
@ -127,6 +119,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
--replace "@HASH@" '${commit}' \
|
||||
--replace "@BRANCH@" "" \
|
||||
--replace "@MESSAGE@" "" \
|
||||
--replace "@DATE@" "${date}" \
|
||||
--replace "@TAG@" "" \
|
||||
--replace "@DIRTY@" '${
|
||||
if commit == ""
|
||||
|
@ -139,7 +132,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
|
||||
${lib.optionalString wrapRuntimeDeps ''
|
||||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${lib.makeBinPath [binutils pciutils]}
|
||||
--suffix PATH : ${lib.makeBinPath [
|
||||
stdenv.cc
|
||||
binutils
|
||||
pciutils
|
||||
]}
|
||||
''}
|
||||
'';
|
||||
|
||||
|
|
|
@ -4,171 +4,11 @@ self: {
|
|||
pkgs,
|
||||
...
|
||||
}: let
|
||||
cfg = config.wayland.windowManager.hyprland;
|
||||
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
};
|
||||
inherit (pkgs.stdenv.hostPlatform) system;
|
||||
|
||||
package = self.packages.${system}.default;
|
||||
in {
|
||||
disabledModules = ["services/window-managers/hyprland.nix"];
|
||||
|
||||
meta.maintainers = [lib.maintainers.fufexan];
|
||||
|
||||
options.wayland.windowManager.hyprland = {
|
||||
enable =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to enable Hyprland, the dynamic tiling Wayland compositor
|
||||
that doesn't sacrifice on its looks.
|
||||
|
||||
You can manually launch Hyprland by executing {command}`Hyprland` on
|
||||
a TTY.
|
||||
|
||||
See <https://wiki.hyprland.org> for more information.
|
||||
'';
|
||||
config = {
|
||||
wayland.windowManager.hyprland.package = lib.mkDefault package;
|
||||
};
|
||||
|
||||
package = lib.mkOption {
|
||||
type = with lib.types; nullOr package;
|
||||
default = defaultHyprlandPackage;
|
||||
defaultText = lib.literalExpression ''
|
||||
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||
enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
|
||||
}
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
Hyprland package to use. Will override the 'xwayland' option.
|
||||
|
||||
Defaults to the one provided by the flake. Set it to
|
||||
{package}`pkgs.hyprland` to use the one provided by nixpkgs or
|
||||
if you have an overlay.
|
||||
|
||||
Set to null to not add any Hyprland package to your path. This should
|
||||
be done if you want to use the NixOS module to install Hyprland.
|
||||
'';
|
||||
};
|
||||
|
||||
plugins = lib.mkOption {
|
||||
type = with lib.types; listOf (either package path);
|
||||
default = [];
|
||||
description = lib.mdDoc ''
|
||||
List of Hyprland plugins to use. Can either be packages or
|
||||
absolute plugin paths.
|
||||
'';
|
||||
};
|
||||
|
||||
systemdIntegration = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = pkgs.stdenv.isLinux;
|
||||
description = lib.mdDoc ''
|
||||
Whether to enable {file}`hyprland-session.target` on
|
||||
Hyprland startup. This links to {file}`graphical-session.target`.
|
||||
Some important environment variables will be imported to systemd
|
||||
and dbus user environment before reaching the target, including
|
||||
- {env}`DISPLAY`
|
||||
- {env}`HYPRLAND_INSTANCE_SIGNATURE`
|
||||
- {env}`WAYLAND_DISPLAY`
|
||||
- {env}`XDG_CURRENT_DESKTOP`
|
||||
'';
|
||||
};
|
||||
|
||||
disableAutoreload =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to disable automatically reloading Hyprland's configuration when
|
||||
rebuilding the Home Manager profile.
|
||||
'';
|
||||
};
|
||||
|
||||
xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
|
||||
|
||||
extraConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.lines;
|
||||
default = "";
|
||||
description = lib.mdDoc ''
|
||||
Extra configuration lines to add to {file}`~/.config/hypr/hyprland.conf`.
|
||||
'';
|
||||
};
|
||||
|
||||
recommendedEnvironment =
|
||||
lib.mkEnableOption null
|
||||
// {
|
||||
description = lib.mdDoc ''
|
||||
Whether to set the recommended environment variables.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
warnings =
|
||||
if (cfg.systemdIntegration || cfg.plugins != []) && cfg.extraConfig == null
|
||||
then [
|
||||
''
|
||||
You have enabled hyprland.systemdIntegration or listed plugins in hyprland.plugins.
|
||||
Your Hyprland config will be linked by home manager.
|
||||
Set hyprland.extraConfig or unset hyprland.systemdIntegration and hyprland.plugins to remove this warning.
|
||||
''
|
||||
]
|
||||
else [];
|
||||
|
||||
home.packages =
|
||||
lib.optional (cfg.package != null) cfg.package
|
||||
++ lib.optional cfg.xwayland.enable pkgs.xwayland;
|
||||
|
||||
home.sessionVariables =
|
||||
lib.mkIf cfg.recommendedEnvironment {NIXOS_OZONE_WL = "1";};
|
||||
|
||||
xdg.configFile."hypr/hyprland.conf" = lib.mkIf (cfg.systemdIntegration || cfg.extraConfig != null || cfg.plugins != []) {
|
||||
text =
|
||||
(lib.optionalString cfg.systemdIntegration ''
|
||||
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && systemctl --user start hyprland-session.target
|
||||
'')
|
||||
+ lib.concatStrings (builtins.map (entry: let
|
||||
plugin =
|
||||
if lib.types.package.check entry
|
||||
then "${entry}/lib/lib${entry.pname}.so"
|
||||
else entry;
|
||||
in "plugin = ${plugin}\n")
|
||||
cfg.plugins)
|
||||
+ (
|
||||
if cfg.extraConfig != null
|
||||
then cfg.extraConfig
|
||||
else ""
|
||||
);
|
||||
|
||||
onChange = let
|
||||
hyprlandPackage =
|
||||
if cfg.package == null
|
||||
then defaultHyprlandPackage
|
||||
else cfg.package;
|
||||
in
|
||||
lib.mkIf (!cfg.disableAutoreload) ''
|
||||
( # execute in subshell so that `shopt` won't affect other scripts
|
||||
shopt -s nullglob # so that nothing is done if /tmp/hypr/ does not exist or is empty
|
||||
for instance in /tmp/hypr/*; do
|
||||
HYPRLAND_INSTANCE_SIGNATURE=''${instance##*/} ${hyprlandPackage}/bin/hyprctl reload config-only \
|
||||
|| true # ignore dead instance(s)
|
||||
done
|
||||
)
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {
|
||||
Unit = {
|
||||
Description = "Hyprland compositor session";
|
||||
Documentation = ["man:systemd.special(7)"];
|
||||
BindsTo = ["graphical-session.target"];
|
||||
Wants = ["graphical-session-pre.target"];
|
||||
After = ["graphical-session-pre.target"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "hidpi"]
|
||||
"Support for this option has been removed. Refer to https://wiki.hyprland.org/Configuring/XWayland for more info")
|
||||
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "enableNvidiaPatches"]
|
||||
"Nvidia patches are no longer needed for Hyprland")
|
||||
];
|
||||
}
|
||||
|
|
|
@ -2,96 +2,20 @@ inputs: {
|
|||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.programs.hyprland;
|
||||
}: let
|
||||
inherit (pkgs.stdenv.hostPlatform) system;
|
||||
cfg = config.programs.hyprland;
|
||||
|
||||
finalPortalPackage = cfg.portalPackage.override {
|
||||
package = inputs.self.packages.${system}.hyprland;
|
||||
portalPackage = inputs.self.packages.${system}.xdg-desktop-portal-hyprland.override {
|
||||
hyprland = cfg.finalPackage;
|
||||
};
|
||||
in {
|
||||
# disables Nixpkgs Hyprland module to avoid conflicts
|
||||
disabledModules = ["programs/hyprland.nix"];
|
||||
|
||||
options.programs.hyprland = {
|
||||
enable =
|
||||
mkEnableOption null
|
||||
// {
|
||||
description = mdDoc ''
|
||||
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
|
||||
|
||||
You can manually launch Hyprland by executing {command}`Hyprland` on a TTY.
|
||||
|
||||
A configuration file will be generated in {file}`~/.config/hypr/hyprland.conf`.
|
||||
See <https://wiki.hyprland.org> for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOptionMD inputs.self.packages.${system} "hyprland" { };
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
default = cfg.package.override {
|
||||
enableXWayland = cfg.xwayland.enable;
|
||||
};
|
||||
defaultText =
|
||||
literalExpression
|
||||
"`programs.hyprland.package` with applied configuration";
|
||||
description = mdDoc ''
|
||||
The Hyprland package after applying configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
|
||||
|
||||
xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [cfg.finalPackage];
|
||||
|
||||
# NixOS changed the name of this attribute between NixOS 23.05 and
|
||||
# 23.11
|
||||
fonts = if builtins.hasAttr "enableDefaultPackages" options.fonts
|
||||
then {enableDefaultPackages = mkDefault true;}
|
||||
else {enableDefaultFonts = mkDefault true;};
|
||||
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
|
||||
programs = {
|
||||
dconf.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault cfg.xwayland.enable;
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
|
||||
services.xserver.displayManager.sessionPackages = [cfg.finalPackage];
|
||||
|
||||
xdg.portal = {
|
||||
enable = mkDefault true;
|
||||
extraPortals = [finalPortalPackage];
|
||||
config = {
|
||||
programs.hyprland = {
|
||||
package = lib.mkDefault package;
|
||||
portalPackage = lib.mkDefault portalPackage;
|
||||
};
|
||||
};
|
||||
|
||||
imports = with lib; [
|
||||
(
|
||||
mkRemovedOptionModule
|
||||
["programs" "hyprland" "xwayland" "hidpi"]
|
||||
"XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland"
|
||||
)
|
||||
(
|
||||
mkRemovedOptionModule
|
||||
["programs" "hyprland" "enableNvidiaPatches"]
|
||||
"Nvidia patches are no longer needed"
|
||||
)
|
||||
(
|
||||
mkRemovedOptionModule
|
||||
["programs" "hyprland" "nvidiaPatches"]
|
||||
"Nvidia patches are no longer needed"
|
||||
)
|
||||
];
|
||||
}
|
||||
|
|
|
@ -28,16 +28,20 @@ in {
|
|||
self.overlays.wlroots-hyprland
|
||||
self.overlays.udis86
|
||||
# Hyprland packages themselves
|
||||
(final: prev: {
|
||||
(final: prev: let
|
||||
date = mkDate (self.lastModifiedDate or "19700101");
|
||||
in {
|
||||
hyprland = final.callPackage ./default.nix {
|
||||
stdenv = final.gcc13Stdenv;
|
||||
version = "${props.version}+date=${mkDate (self.lastModifiedDate or "19700101")}_${self.shortRev or "dirty"}";
|
||||
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
|
||||
wlroots = final.wlroots-hyprland;
|
||||
commit = self.rev or "";
|
||||
inherit (final) udis86 hyprland-protocols;
|
||||
inherit date;
|
||||
};
|
||||
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
||||
hyprland-debug = final.hyprland.override {debug = true;};
|
||||
hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;};
|
||||
hyprland-nvidia =
|
||||
builtins.trace ''
|
||||
hyprland-nvidia was removed. Please use the hyprland package.
|
||||
|
@ -70,30 +74,6 @@ in {
|
|||
wlroots-hyprland = final.callPackage ./wlroots.nix {
|
||||
version = "${mkDate (inputs.wlroots.lastModifiedDate or "19700101")}_${inputs.wlroots.shortRev or "dirty"}";
|
||||
src = inputs.wlroots;
|
||||
|
||||
libdisplay-info = prev.libdisplay-info.overrideAttrs (old: {
|
||||
version = "0.1.1+date=2023-03-02";
|
||||
src = final.fetchFromGitLab {
|
||||
domain = "gitlab.freedesktop.org";
|
||||
owner = "emersion";
|
||||
repo = old.pname;
|
||||
rev = "147d6611a64a6ab04611b923e30efacaca6fc678";
|
||||
sha256 = "sha256-/q79o13Zvu7x02SBGu0W5yQznQ+p7ltZ9L6cMW5t/o4=";
|
||||
};
|
||||
});
|
||||
|
||||
libliftoff = prev.libliftoff.overrideAttrs (old: {
|
||||
version = "0.5.0-dev";
|
||||
src = final.fetchFromGitLab {
|
||||
domain = "gitlab.freedesktop.org";
|
||||
owner = "emersion";
|
||||
repo = old.pname;
|
||||
rev = "d98ae243280074b0ba44bff92215ae8d785658c0";
|
||||
sha256 = "sha256-DjwlS8rXE7srs7A8+tHqXyUsFGtucYSeq6X0T/pVOc8=";
|
||||
};
|
||||
|
||||
NIX_CFLAGS_COMPILE = toString ["-Wno-error=sign-conversion"];
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,33 +1,13 @@
|
|||
{
|
||||
fetchurl,
|
||||
version,
|
||||
src,
|
||||
wlroots,
|
||||
hwdata,
|
||||
libdisplay-info,
|
||||
libliftoff,
|
||||
libdrm,
|
||||
enableXWayland ? true,
|
||||
}:
|
||||
let
|
||||
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
|
||||
libdrm_2_4_118 = libdrm.overrideAttrs(old: rec {
|
||||
version = "2.4.118";
|
||||
src = fetchurl {
|
||||
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
|
||||
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
|
||||
};
|
||||
});
|
||||
in
|
||||
wlroots.overrideAttrs (old: {
|
||||
inherit version src enableXWayland;
|
||||
|
||||
pname = "${old.pname}-hyprland";
|
||||
|
||||
# HACK: libdrm_2_4_118 is placed at the head of list to take precedence over libdrm in `old.buildInputs`
|
||||
buildInputs = [libdrm_2_4_118] ++ old.buildInputs ++ [hwdata libliftoff libdisplay-info];
|
||||
|
||||
NIX_CFLAGS_COMPILE = toString [
|
||||
"-Wno-error=maybe-uninitialized"
|
||||
];
|
||||
patches = [ ]; # don't inherit old.patches
|
||||
})
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"version": "0.33.1"
|
||||
"version": "0.34.0"
|
||||
}
|
|
@ -4,11 +4,13 @@ cp -fr ./src/version.h.in ./src/version.h
|
|||
HASH=$(git rev-parse HEAD)
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g')
|
||||
DATE=$(git show ${GIT_COMMIT_HASH} --no-patch --format=%cd --date=local)
|
||||
DIRTY=$(git diff-index --quiet HEAD -- || echo dirty)
|
||||
TAG=$(git describe --tags)
|
||||
|
||||
sed -i -e "s#@HASH@#${HASH}#" ./src/version.h
|
||||
sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h
|
||||
sed -i -e "s#@MESSAGE@#${MESSAGE}#" ./src/version.h
|
||||
sed -i -e "s#@DATE@#${DATE}#" ./src/version.h
|
||||
sed -i -e "s#@DIRTY@#${DIRTY}#" ./src/version.h
|
||||
sed -i -e "s#@TAG@#${TAG}#" ./src/version.h
|
|
@ -24,7 +24,7 @@ void handleUnrecoverableSignal(int sig) {
|
|||
signal(SIGABRT, SIG_DFL);
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
|
||||
if (g_pHookSystem->m_bCurrentEventPlugin) {
|
||||
if (g_pHookSystem && g_pHookSystem->m_bCurrentEventPlugin) {
|
||||
longjmp(g_pHookSystem->m_jbHookFaultJumpBuf, 1);
|
||||
return;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ CCompositor::CCompositor() {
|
|||
|
||||
if (!std::filesystem::exists("/tmp/hypr")) {
|
||||
std::filesystem::create_directory("/tmp/hypr");
|
||||
std::filesystem::permissions("/tmp/hypr", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
std::filesystem::permissions("/tmp/hypr", std::filesystem::perms::all | std::filesystem::perms::sticky_bit, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
const auto INSTANCEPATH = "/tmp/hypr/" + m_szInstanceSignature;
|
||||
|
@ -125,13 +125,12 @@ void CCompositor::initServer() {
|
|||
|
||||
initManagers(STAGE_PRIORITY);
|
||||
|
||||
if (const auto ENV = getenv("HYPRLAND_TRACE"); ENV && std::string(ENV) == "1")
|
||||
if (envEnabled("HYPRLAND_TRACE"))
|
||||
Debug::trace = true;
|
||||
|
||||
wlr_log_init(WLR_INFO, NULL);
|
||||
|
||||
const auto LOGWLR = getenv("HYPRLAND_LOG_WLR");
|
||||
if (LOGWLR && std::string(LOGWLR) == "1")
|
||||
if (envEnabled("HYPRLAND_LOG_WLR"))
|
||||
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
|
||||
else
|
||||
wlr_log_init(WLR_ERROR, Debug::wlrLog);
|
||||
|
@ -194,7 +193,7 @@ void CCompositor::initServer() {
|
|||
|
||||
m_sWLROutputPowerMgr = wlr_output_power_manager_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 5);
|
||||
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6);
|
||||
|
||||
m_sWLRCursor = wlr_cursor_create();
|
||||
wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout);
|
||||
|
@ -343,7 +342,7 @@ void CCompositor::cleanup() {
|
|||
Debug::shuttingDown = true;
|
||||
|
||||
#ifdef USES_SYSTEMD
|
||||
if (sd_booted() > 0)
|
||||
if (sd_booted() > 0 && !envEnabled("HYPRLAND_NO_SD_NOTIFY"))
|
||||
sd_notify(0, "STOPPING=1");
|
||||
#endif
|
||||
|
||||
|
@ -517,14 +516,15 @@ void CCompositor::startCompositor() {
|
|||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */ && fork() == 0)
|
||||
execl(
|
||||
"/bin/sh", "/bin/sh", "-c",
|
||||
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
|
||||
const auto CMD =
|
||||
#ifdef USES_SYSTEMD
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash "
|
||||
"dbus-update-activation-environment 2>/dev/null && "
|
||||
#endif
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE",
|
||||
nullptr);
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME";
|
||||
g_pKeybindManager->spawn(CMD);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket);
|
||||
|
||||
|
@ -540,10 +540,11 @@ void CCompositor::startCompositor() {
|
|||
g_pHyprRenderer->setCursorFromName("left_ptr");
|
||||
|
||||
#ifdef USES_SYSTEMD
|
||||
if (sd_booted() > 0)
|
||||
if (sd_booted() > 0) {
|
||||
// tell systemd that we are ready so it can start other bond, following, related units
|
||||
if (!envEnabled("HYPRLAND_NO_SD_NOTIFY"))
|
||||
sd_notify(0, "READY=1");
|
||||
else
|
||||
} else
|
||||
Debug::log(LOG, "systemd integration is baked in but system itself is not booted à la systemd!");
|
||||
#endif
|
||||
|
||||
|
@ -943,6 +944,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
|||
|
||||
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
|
||||
if (windowValidMapped(PLASTWINDOW)) {
|
||||
PLASTWINDOW->updateDynamicRules();
|
||||
|
||||
updateWindowAnimatedDecorationValues(PLASTWINDOW);
|
||||
|
||||
if (!pWindow->m_bIsX11 || pWindow->m_iX11Type == 1)
|
||||
|
@ -960,6 +963,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
|||
|
||||
g_pXWaylandManager->activateWindow(pWindow, true); // sets the m_pLastWindow
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
|
||||
updateWindowAnimatedDecorationValues(pWindow);
|
||||
|
||||
if (pWindow->m_bIsUrgent)
|
||||
|
@ -1028,11 +1033,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto KEYBOARD = wlr_seat_get_keyboard(m_sSeat.seat);
|
||||
|
||||
if (!KEYBOARD)
|
||||
return;
|
||||
|
||||
if (const auto KEYBOARD = wlr_seat_get_keyboard(m_sSeat.seat); KEYBOARD) {
|
||||
uint32_t keycodes[WLR_KEYBOARD_KEYS_CAP] = {0}; // TODO: maybe send valid, non-keybind codes?
|
||||
wlr_seat_keyboard_notify_enter(m_sSeat.seat, pSurface, keycodes, 0, &KEYBOARD->modifiers);
|
||||
|
||||
|
@ -1042,6 +1043,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
|
|||
.new_surface = pSurface,
|
||||
};
|
||||
wl_signal_emit_mutable(&m_sSeat.seat->keyboard_state.events.focus_change, &event);
|
||||
}
|
||||
|
||||
if (pWindowOwner)
|
||||
Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface, pWindowOwner);
|
||||
|
@ -1061,9 +1063,6 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) {
|
|||
if (!windowExists(pWindow))
|
||||
return false;
|
||||
|
||||
if (pWindow->m_bIsX11 && !pWindow->m_bMappedX11)
|
||||
return false;
|
||||
|
||||
if (!pWindow->m_bIsMapped)
|
||||
return false;
|
||||
|
||||
|
@ -1127,7 +1126,7 @@ SIMEPopup* CCompositor::vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopu
|
|||
|
||||
CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->m_bFadingOut || !w->m_bMappedX11)
|
||||
if (!w->m_bIsMapped || w->m_bFadingOut)
|
||||
continue;
|
||||
|
||||
if (w->m_pWLSurface.wlr() == pSurface)
|
||||
|
@ -1370,7 +1369,7 @@ void CCompositor::changeWindowZOrder(CWindow* pWindow, bool top) {
|
|||
toMove.emplace_front(pw);
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->m_bIsMapped && w->m_bMappedX11 && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw) {
|
||||
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw) {
|
||||
x11Stack(w.get(), top, x11Stack);
|
||||
}
|
||||
}
|
||||
|
@ -1626,7 +1625,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableOnly) {
|
||||
CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableOnly, std::optional<bool> floating) {
|
||||
bool gotToWindow = false;
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w.get() != pWindow && !gotToWindow)
|
||||
|
@ -1637,11 +1636,17 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
|
|||
continue;
|
||||
}
|
||||
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
@ -1649,7 +1654,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableOnly) {
|
||||
CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableOnly, std::optional<bool> floating) {
|
||||
bool gotToWindow = false;
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
if (w.get() != pWindow && !gotToWindow)
|
||||
|
@ -1660,11 +1665,17 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
|
|||
continue;
|
||||
}
|
||||
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
if (floating.has_value() && w->m_bIsFloating != floating.value())
|
||||
continue;
|
||||
|
||||
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
|
||||
return w.get();
|
||||
}
|
||||
|
@ -1713,6 +1724,15 @@ bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* pMonitor) {
|
||||
const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point);
|
||||
|
||||
const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight;
|
||||
|
||||
return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y);
|
||||
}
|
||||
|
||||
void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) {
|
||||
auto pair = (std::pair<wlr_surface*, bool>*)data;
|
||||
pair->second = pair->second || pSurface == pair->first;
|
||||
|
@ -1725,7 +1745,7 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
|
|||
const auto PSURFACE = pMouse->currentConstraint->surface;
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
if (w->isHidden() || !w->m_bMappedX11 || !w->m_bIsMapped || !w->m_pWLSurface.exists())
|
||||
if (w->isHidden() || !w->m_bIsMapped || !w->m_pWLSurface.exists())
|
||||
continue;
|
||||
|
||||
if (w->m_bIsX11) {
|
||||
|
@ -1813,6 +1833,15 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() {
|
|||
}
|
||||
}
|
||||
|
||||
void CCompositor::updateWorkspaceWindows(const int64_t& id) {
|
||||
for (auto& w : m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->m_iWorkspaceID != id)
|
||||
continue;
|
||||
|
||||
w->updateDynamicRules();
|
||||
}
|
||||
}
|
||||
|
||||
void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
// optimization
|
||||
static auto* const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get();
|
||||
|
@ -1985,7 +2014,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
|
|||
updateFullscreenFadeOnWorkspace(PWORKSPACEB);
|
||||
updateFullscreenFadeOnWorkspace(PWORKSPACEA);
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName});
|
||||
|
@ -2170,7 +2199,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
|
|||
|
||||
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
}
|
||||
|
||||
// finalize
|
||||
|
@ -2253,7 +2282,7 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
|
|||
|
||||
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, MODE, on);
|
||||
|
||||
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && MODE == FULLSCREEN_FULL);
|
||||
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState());
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
updateWindowAnimatedDecorationValues(pWindow);
|
||||
|
@ -2509,17 +2538,6 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
|
|||
}
|
||||
}
|
||||
|
||||
bool CCompositor::cursorOnReservedArea() {
|
||||
const auto PMONITOR = getMonitorFromCursor();
|
||||
|
||||
const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
|
||||
const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight;
|
||||
|
||||
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
return !VECINRECT(CURSORPOS, XY1.x, XY1.y, XY2.x, XY2.y);
|
||||
}
|
||||
|
||||
CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name) {
|
||||
const auto NAME = name == "" ? std::to_string(id) : name;
|
||||
auto monID = monid;
|
||||
|
@ -2588,9 +2606,7 @@ int CCompositor::getNewSpecialID() {
|
|||
}
|
||||
|
||||
void CCompositor::performUserChecks() {
|
||||
const auto atomicEnv = getenv("WLR_DRM_NO_ATOMIC");
|
||||
const auto atomicEnvStr = std::string(atomicEnv ? atomicEnv : "");
|
||||
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && atomicEnvStr != "1") {
|
||||
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && !envEnabled("WLR_DRM_NO_ATOMIC")) {
|
||||
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);
|
||||
|
@ -2613,6 +2629,7 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
|
|||
pWindow->moveToWorkspace(pWorkspace->m_iID);
|
||||
pWindow->updateToplevel();
|
||||
pWindow->updateDynamicRules();
|
||||
pWindow->uncacheWindowDecos();
|
||||
|
||||
if (!pWindow->m_bIsFloating) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow);
|
||||
|
@ -2642,6 +2659,9 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
|
|||
|
||||
if (FULLSCREEN)
|
||||
setWindowFullscreen(pWindow, true, FULLSCREENMODE);
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID);
|
||||
g_pCompositor->updateWorkspaceWindows(pWindow->m_iWorkspaceID);
|
||||
}
|
||||
|
||||
CWindow* CCompositor::getForceFocus() {
|
||||
|
@ -2770,3 +2790,12 @@ void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scal
|
|||
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
|
||||
wlr_surface_set_preferred_buffer_transform(pSurface, transform);
|
||||
}
|
||||
|
||||
void CCompositor::updateSuspendedStates() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped)
|
||||
continue;
|
||||
|
||||
w->setSuspended(w->isHidden() || !isWorkspaceVisible(w->m_iWorkspaceID));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@
|
|||
#include "plugins/PluginSystem.hpp"
|
||||
#include "helpers/Watchdog.hpp"
|
||||
|
||||
enum eManagersInitStage
|
||||
{
|
||||
enum eManagersInitStage {
|
||||
STAGE_PRIORITY = 0,
|
||||
STAGE_LATE
|
||||
};
|
||||
|
@ -166,13 +165,15 @@ class CCompositor {
|
|||
void changeWindowZOrder(CWindow*, bool);
|
||||
void cleanupFadingOut(const int& monid);
|
||||
CWindow* getWindowInDirection(CWindow*, char);
|
||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
|
||||
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false, std::optional<bool> floating = {});
|
||||
int getNextAvailableNamedWorkspace();
|
||||
bool isPointOnAnyMonitor(const Vector2D&);
|
||||
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
|
||||
CWindow* getConstraintWindow(SMouse*);
|
||||
CMonitor* getMonitorInDirection(const char&);
|
||||
void updateAllWindowsAnimatedDecorationValues();
|
||||
void updateWorkspaceWindows(const int64_t& id);
|
||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||
int getNextAvailableMonitorID(std::string const& name);
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
||||
|
@ -192,7 +193,6 @@ class CCompositor {
|
|||
void closeWindow(CWindow*);
|
||||
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
|
||||
void forceReportSizesToWindowsOnWorkspace(const int&);
|
||||
bool cursorOnReservedArea();
|
||||
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
|
||||
void renameWorkspace(const int&, const std::string& name = "");
|
||||
void setActiveMonitor(CMonitor*);
|
||||
|
@ -208,6 +208,7 @@ class CCompositor {
|
|||
void leaveUnsafeState();
|
||||
void setPreferredScaleForSurface(wlr_surface* pSurface, double scale);
|
||||
void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform);
|
||||
void updateSuspendedStates();
|
||||
|
||||
std::string explicitConfigPath;
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
#include "helpers/Vector2D.hpp"
|
||||
|
||||
enum eIcons
|
||||
{
|
||||
enum eIcons {
|
||||
ICON_WARNING = 0,
|
||||
ICON_INFO,
|
||||
ICON_HINT,
|
||||
|
@ -13,8 +12,7 @@ enum eIcons
|
|||
ICON_NONE
|
||||
};
|
||||
|
||||
enum eRenderStage
|
||||
{
|
||||
enum eRenderStage {
|
||||
RENDER_PRE = 0, /* Before binding the gl context */
|
||||
RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
|
||||
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
|
||||
|
@ -26,6 +24,14 @@ enum eRenderStage
|
|||
RENDER_POST_WINDOW, /* After rendering a window (any pass) */
|
||||
};
|
||||
|
||||
enum eInputType {
|
||||
INPUT_TYPE_AXIS = 0,
|
||||
INPUT_TYPE_BUTTON,
|
||||
INPUT_TYPE_DRAG_START,
|
||||
INPUT_TYPE_DRAG_END,
|
||||
INPUT_TYPE_MOTION
|
||||
};
|
||||
|
||||
struct SCallbackInfo {
|
||||
bool cancelled = false; /* on cancellable events, will cancel the event. */
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Compositor.hpp"
|
||||
#include "render/decorations/CHyprDropShadowDecoration.hpp"
|
||||
#include "render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
#include "render/decorations/CHyprBorderDecoration.hpp"
|
||||
|
||||
CWindow::CWindow() {
|
||||
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
|
@ -14,6 +15,7 @@ CWindow::CWindow() {
|
|||
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
|
||||
|
||||
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
|
||||
addWindowDeco(std::make_unique<CHyprBorderDecoration>(this));
|
||||
}
|
||||
|
||||
CWindow::~CWindow() {
|
||||
|
@ -220,6 +222,30 @@ void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
|
|||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
|
||||
}
|
||||
|
||||
void CWindow::uncacheWindowDecos() {
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
g_pDecorationPositioner->uncacheDecoration(wd.get());
|
||||
}
|
||||
}
|
||||
|
||||
bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoords, std::any data) {
|
||||
if (type != INPUT_TYPE_DRAG_END && hasPopupAt(mouseCoords))
|
||||
return false;
|
||||
|
||||
for (auto& wd : m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (!g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords))
|
||||
continue;
|
||||
|
||||
if (wd->onInputOnDeco(type, mouseCoords, data))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pid_t CWindow::getPID() {
|
||||
pid_t PID = -1;
|
||||
if (!m_bIsX11) {
|
||||
|
@ -229,7 +255,7 @@ pid_t CWindow::getPID() {
|
|||
|
||||
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
|
||||
} else {
|
||||
if (!m_bIsMapped || !m_bMappedX11)
|
||||
if (!m_bIsMapped)
|
||||
return -1;
|
||||
|
||||
PID = m_uSurface.xwayland->pid;
|
||||
|
@ -320,7 +346,7 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
|
|||
}
|
||||
|
||||
void CWindow::updateSurfaceOutputs() {
|
||||
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden || !m_bMappedX11)
|
||||
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden)
|
||||
return;
|
||||
|
||||
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
|
||||
|
@ -446,6 +472,8 @@ void CWindow::onUnmap() {
|
|||
|
||||
if (PMONITOR && PMONITOR->solitaryClient == this)
|
||||
PMONITOR->solitaryClient = nullptr;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
|
||||
}
|
||||
|
||||
void CWindow::onMap() {
|
||||
|
@ -507,6 +535,8 @@ void CWindow::setHidden(bool hidden) {
|
|||
if (hidden && g_pCompositor->m_pLastWindow == this) {
|
||||
g_pCompositor->m_pLastWindow = nullptr;
|
||||
}
|
||||
|
||||
setSuspended(hidden);
|
||||
}
|
||||
|
||||
bool CWindow::isHidden() {
|
||||
|
@ -964,7 +994,7 @@ float CWindow::rounding() {
|
|||
|
||||
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
|
||||
|
||||
return rounding;
|
||||
return m_sSpecialRenderData.rounding ? rounding : 0;
|
||||
}
|
||||
|
||||
void CWindow::updateSpecialRenderData() {
|
||||
|
@ -998,3 +1028,19 @@ int CWindow::getRealBorderSize() {
|
|||
bool CWindow::canBeTorn() {
|
||||
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
|
||||
}
|
||||
|
||||
bool CWindow::shouldSendFullscreenState() {
|
||||
const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode;
|
||||
return m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL));
|
||||
}
|
||||
|
||||
void CWindow::setSuspended(bool suspend) {
|
||||
if (suspend == m_bSuspended)
|
||||
return;
|
||||
|
||||
if (m_bIsX11)
|
||||
return;
|
||||
|
||||
wlr_xdg_toplevel_set_suspended(m_uSurface.xdg->toplevel, suspend);
|
||||
m_bSuspended = suspend;
|
||||
}
|
||||
|
|
|
@ -11,16 +11,14 @@
|
|||
#include "macros.hpp"
|
||||
#include "managers/XWaylandManager.hpp"
|
||||
|
||||
enum eIdleInhibitMode
|
||||
{
|
||||
enum eIdleInhibitMode {
|
||||
IDLEINHIBIT_NONE = 0,
|
||||
IDLEINHIBIT_ALWAYS,
|
||||
IDLEINHIBIT_FULLSCREEN,
|
||||
IDLEINHIBIT_FOCUS
|
||||
};
|
||||
|
||||
enum eGroupRules
|
||||
{
|
||||
enum eGroupRules {
|
||||
// effective only during first map, except for _ALWAYS variant
|
||||
GROUP_NONE = 0,
|
||||
GROUP_SET = 1 << 0, // Open as new group or add to focused group
|
||||
|
@ -153,10 +151,14 @@ struct SWindowRule {
|
|||
bool v2 = false;
|
||||
std::string szTitle;
|
||||
std::string szClass;
|
||||
std::string szInitialTitle;
|
||||
std::string szInitialClass;
|
||||
int bX11 = -1; // -1 means "ANY"
|
||||
int bFloating = -1;
|
||||
int bFullscreen = -1;
|
||||
int bPinned = -1;
|
||||
int bFocus = -1;
|
||||
int iOnWorkspace = -1;
|
||||
std::string szWorkspace = ""; // empty means any
|
||||
};
|
||||
|
||||
|
@ -239,7 +241,6 @@ class CWindow {
|
|||
|
||||
// XWayland stuff
|
||||
bool m_bIsX11 = false;
|
||||
bool m_bMappedX11 = false;
|
||||
CWindow* m_pX11Parent = nullptr;
|
||||
uint64_t m_iX11Type = 0;
|
||||
bool m_bIsModal = false;
|
||||
|
@ -347,6 +348,8 @@ class CWindow {
|
|||
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||
void updateWindowDecos();
|
||||
void removeWindowDeco(IHyprWindowDecoration* deco);
|
||||
void uncacheWindowDecos();
|
||||
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
|
||||
pid_t getPID();
|
||||
IHyprWindowDecoration* getDecorationByType(eDecorationType);
|
||||
void removeDecorationByType(eDecorationType);
|
||||
|
@ -367,6 +370,8 @@ class CWindow {
|
|||
bool opaque();
|
||||
float rounding();
|
||||
bool canBeTorn();
|
||||
bool shouldSendFullscreenState();
|
||||
void setSuspended(bool suspend);
|
||||
|
||||
int getRealBorderSize();
|
||||
void updateSpecialRenderData();
|
||||
|
@ -393,6 +398,7 @@ class CWindow {
|
|||
private:
|
||||
// For hidden windows and stuff
|
||||
bool m_bHidden = false;
|
||||
bool m_bSuspended = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -80,6 +80,7 @@ void CConfigManager::setDefaultVars() {
|
|||
configValues["general:apply_sens_to_raw"].intValue = 0;
|
||||
configValues["general:border_size"].intValue = 1;
|
||||
configValues["general:no_border_on_floating"].intValue = 0;
|
||||
configValues["general:border_part_of_window"].intValue = 1;
|
||||
configValues["general:gaps_in"].intValue = 5;
|
||||
configValues["general:gaps_out"].intValue = 20;
|
||||
configValues["general:gaps_workspaces"].intValue = 0;
|
||||
|
@ -133,9 +134,11 @@ void CConfigManager::setDefaultVars() {
|
|||
configValues["group:insert_after_current"].intValue = 1;
|
||||
configValues["group:focus_removed_window"].intValue = 1;
|
||||
|
||||
configValues["group:groupbar:enabled"].intValue = 1;
|
||||
configValues["group:groupbar:font_family"].strValue = "Sans";
|
||||
configValues["group:groupbar:font_size"].intValue = 8;
|
||||
configValues["group:groupbar:gradients"].intValue = 1;
|
||||
configValues["group:groupbar:priority"].intValue = 3;
|
||||
configValues["group:groupbar:render_titles"].intValue = 1;
|
||||
configValues["group:groupbar:scrolling"].intValue = 1;
|
||||
configValues["group:groupbar:text_color"].intValue = 0xffffffff;
|
||||
|
@ -156,6 +159,7 @@ void CConfigManager::setDefaultVars() {
|
|||
configValues["debug:manual_crash"].intValue = 0;
|
||||
configValues["debug:suppress_errors"].intValue = 0;
|
||||
configValues["debug:watchdog_timeout"].intValue = 5;
|
||||
configValues["debug:disable_scale_checks"].intValue = 0;
|
||||
|
||||
configValues["decoration:rounding"].intValue = 0;
|
||||
configValues["decoration:blur:enabled"].intValue = 1;
|
||||
|
@ -170,6 +174,8 @@ void CConfigManager::setDefaultVars() {
|
|||
configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
|
||||
configValues["decoration:blur:noise"].floatValue = 0.0117;
|
||||
configValues["decoration:blur:special"].intValue = 0;
|
||||
configValues["decoration:blur:popups"].intValue = 0;
|
||||
configValues["decoration:blur:popups_ignorealpha"].floatValue = 0.2;
|
||||
configValues["decoration:active_opacity"].floatValue = 1;
|
||||
configValues["decoration:inactive_opacity"].floatValue = 1;
|
||||
configValues["decoration:fullscreen_opacity"].floatValue = 1;
|
||||
|
@ -235,6 +241,7 @@ void CConfigManager::setDefaultVars() {
|
|||
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:scroll_button"].intValue = 0;
|
||||
configValues["input:scroll_button_lock"].intValue = 0;
|
||||
configValues["input:scroll_points"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:touchpad:natural_scroll"].intValue = 0;
|
||||
configValues["input:touchpad:disable_while_typing"].intValue = 1;
|
||||
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
|
||||
|
@ -250,6 +257,7 @@ void CConfigManager::setDefaultVars() {
|
|||
configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:tablet:region_position"].vecValue = Vector2D();
|
||||
configValues["input:tablet:region_size"].vecValue = Vector2D();
|
||||
configValues["input:tablet:relative_input"].intValue = 0;
|
||||
|
||||
configValues["binds:pass_mouse_when_bound"].intValue = 0;
|
||||
configValues["binds:scroll_event_delay"].intValue = 300;
|
||||
|
@ -276,6 +284,8 @@ void CConfigManager::setDefaultVars() {
|
|||
configValues["xwayland:use_nearest_neighbor"].intValue = 1;
|
||||
configValues["xwayland:force_zero_scaling"].intValue = 0;
|
||||
|
||||
configValues["opengl:nvidia_anti_flicker"].intValue = 1;
|
||||
|
||||
configValues["autogenerated"].intValue = 0;
|
||||
}
|
||||
|
||||
|
@ -305,11 +315,13 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
|||
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["scroll_button"].intValue = 0;
|
||||
cfgValues["scroll_button_lock"].intValue = 0;
|
||||
cfgValues["scroll_points"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["transform"].intValue = 0;
|
||||
cfgValues["output"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
|
||||
cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
|
||||
cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
|
||||
cfgValues["relative_input"].intValue = 0; // only for tablets
|
||||
}
|
||||
|
||||
void CConfigManager::setDefaultAnimationVars() {
|
||||
|
@ -1023,14 +1035,29 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
|||
|
||||
const auto TITLEPOS = VALUE.find("title:");
|
||||
const auto CLASSPOS = VALUE.find("class:");
|
||||
const auto INITIALTITLEPOS = VALUE.find("initialTitle:");
|
||||
const auto INITIALCLASSPOS = VALUE.find("initialClass:");
|
||||
const auto X11POS = VALUE.find("xwayland:");
|
||||
const auto FLOATPOS = VALUE.find("floating:");
|
||||
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
|
||||
const auto PINNEDPOS = VALUE.find("pinned:");
|
||||
const auto WORKSPACEPOS = VALUE.find("workspace:");
|
||||
const auto FOCUSPOS = VALUE.find("focus:");
|
||||
const auto ONWORKSPACEPOS = VALUE.find("onworkspace:");
|
||||
|
||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos &&
|
||||
PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos) {
|
||||
// find workspacepos that isn't onworkspacepos
|
||||
size_t WORKSPACEPOS = std::string::npos;
|
||||
size_t currentPos = VALUE.find("workspace:");
|
||||
while (currentPos != std::string::npos) {
|
||||
if (currentPos == 0 || VALUE[currentPos - 1] != 'n') {
|
||||
WORKSPACEPOS = currentPos;
|
||||
break;
|
||||
}
|
||||
currentPos = VALUE.find("workspace:", currentPos + 1);
|
||||
}
|
||||
|
||||
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && INITIALTITLEPOS == std::string::npos && INITIALCLASSPOS == std::string::npos &&
|
||||
X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos &&
|
||||
FOCUSPOS == std::string::npos && ONWORKSPACEPOS == std::string::npos) {
|
||||
Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE);
|
||||
parseError = "Invalid rulev2 syntax: " + VALUE;
|
||||
return;
|
||||
|
@ -1045,6 +1072,10 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
|||
min = TITLEPOS;
|
||||
if (CLASSPOS > pos && CLASSPOS < min)
|
||||
min = CLASSPOS;
|
||||
if (INITIALTITLEPOS > pos && INITIALTITLEPOS < min)
|
||||
min = INITIALTITLEPOS;
|
||||
if (INITIALCLASSPOS > pos && INITIALCLASSPOS < min)
|
||||
min = INITIALCLASSPOS;
|
||||
if (X11POS > pos && X11POS < min)
|
||||
min = X11POS;
|
||||
if (FLOATPOS > pos && FLOATPOS < min)
|
||||
|
@ -1053,8 +1084,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
|||
min = FULLSCREENPOS;
|
||||
if (PINNEDPOS > pos && PINNEDPOS < min)
|
||||
min = PINNEDPOS;
|
||||
if (ONWORKSPACEPOS > pos && ONWORKSPACEPOS < min)
|
||||
min = ONWORKSPACEPOS;
|
||||
if (WORKSPACEPOS > pos && WORKSPACEPOS < min)
|
||||
min = PINNEDPOS;
|
||||
min = WORKSPACEPOS;
|
||||
if (FOCUSPOS > pos && FOCUSPOS < min)
|
||||
min = FOCUSPOS;
|
||||
|
||||
result = result.substr(0, min - pos);
|
||||
|
||||
|
@ -1072,6 +1107,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
|||
if (TITLEPOS != std::string::npos)
|
||||
rule.szTitle = extract(TITLEPOS + 6);
|
||||
|
||||
if (INITIALCLASSPOS != std::string::npos)
|
||||
rule.szInitialClass = extract(INITIALCLASSPOS + 13);
|
||||
|
||||
if (INITIALTITLEPOS != std::string::npos)
|
||||
rule.szInitialTitle = extract(INITIALTITLEPOS + 13);
|
||||
|
||||
if (X11POS != std::string::npos)
|
||||
rule.bX11 = extract(X11POS + 9) == "1" ? 1 : 0;
|
||||
|
||||
|
@ -1087,6 +1128,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
|||
if (WORKSPACEPOS != std::string::npos)
|
||||
rule.szWorkspace = extract(WORKSPACEPOS + 10);
|
||||
|
||||
if (FOCUSPOS != std::string::npos)
|
||||
rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
|
||||
|
||||
if (ONWORKSPACEPOS != std::string::npos)
|
||||
rule.iOnWorkspace = configStringToInt(extract(ONWORKSPACEPOS + 12));
|
||||
|
||||
if (RULE == "unset") {
|
||||
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
|
||||
if (!other.v2) {
|
||||
|
@ -1098,6 +1145,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
|||
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle)
|
||||
return false;
|
||||
|
||||
if (!rule.szInitialClass.empty() && rule.szInitialClass != other.szInitialClass)
|
||||
return false;
|
||||
|
||||
if (!rule.szInitialTitle.empty() && rule.szInitialTitle != other.szInitialTitle)
|
||||
return false;
|
||||
|
||||
if (rule.bX11 != -1 && rule.bX11 != other.bX11)
|
||||
return false;
|
||||
|
||||
|
@ -1113,6 +1166,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
|
|||
if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace)
|
||||
return false;
|
||||
|
||||
if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
|
||||
return false;
|
||||
|
||||
if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -1213,8 +1272,20 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
|
|||
wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
|
||||
else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos)
|
||||
wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen));
|
||||
else if ((delim = rule.find("layoutopt:orientation:")) != std::string::npos)
|
||||
wsRule.layoutopts["orientation"] = rule.substr(delim + 22);
|
||||
else if ((delim = rule.find("layoutopt:")) != std::string::npos) {
|
||||
std::string opt = rule.substr(delim + 10);
|
||||
if (!opt.contains(":")) {
|
||||
// invalid
|
||||
Debug::log(ERR, "Invalid workspace rule found: {}", rule);
|
||||
parseError = "Invalid workspace rule found: " + rule;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string val = opt.substr(opt.find(":") + 1);
|
||||
opt = opt.substr(0, opt.find(":"));
|
||||
|
||||
wsRule.layoutopts[opt] = val;
|
||||
}
|
||||
};
|
||||
|
||||
size_t pos = 0;
|
||||
|
@ -1452,7 +1523,10 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
|
|||
void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equalsPlace) {
|
||||
auto dollarPlace = line.find_first_of('$', equalsPlace);
|
||||
|
||||
int times = 0;
|
||||
|
||||
while (dollarPlace != std::string::npos) {
|
||||
times++;
|
||||
|
||||
const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1);
|
||||
bool found = false;
|
||||
|
@ -1475,6 +1549,13 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
|
|||
}
|
||||
|
||||
dollarPlace = line.find_first_of('$', dollarPlace + 1);
|
||||
|
||||
if (times > 256 /* arbitrary limit */) {
|
||||
line = "";
|
||||
parseError = "Maximum variable recursion limit hit. Evaluating the line led to too many variable substitutions.";
|
||||
Debug::log(ERR, "Variable recursion limit hit in configmanager");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1599,10 +1680,16 @@ void CConfigManager::loadConfigLoadVars() {
|
|||
ifs.open(mainConfigPath);
|
||||
|
||||
if (!ifs.good()) {
|
||||
Debug::log(WARN, "Config reading error. Attempting to generate, backing up old one if exists");
|
||||
|
||||
ifs.close();
|
||||
|
||||
if (!g_pCompositor->explicitConfigPath.empty()) {
|
||||
Debug::log(WARN, "Config reading error!");
|
||||
parseError = "Broken config file! (Could not read)";
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(WARN, "Config reading error. Attempting to generate, backing up old one if exists");
|
||||
|
||||
if (std::filesystem::exists(mainConfigPath))
|
||||
std::filesystem::rename(mainConfigPath, mainConfigPath + ".backup");
|
||||
|
||||
|
@ -1645,6 +1732,10 @@ void CConfigManager::loadConfigLoadVars() {
|
|||
ifs.close();
|
||||
}
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
w->uncacheWindowDecos();
|
||||
}
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
|
||||
|
||||
|
@ -1727,6 +1818,8 @@ void CConfigManager::loadConfigLoadVars() {
|
|||
handlePluginLoads();
|
||||
|
||||
EMIT_HOOK_EVENT("configReloaded", nullptr);
|
||||
if (g_pEventManager)
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"configreloaded", ""});
|
||||
}
|
||||
|
||||
void CConfigManager::tick() {
|
||||
|
@ -1945,6 +2038,20 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (rule.szInitialTitle != "") {
|
||||
std::regex RULECHECK(rule.szInitialTitle);
|
||||
|
||||
if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.szInitialClass != "") {
|
||||
std::regex RULECHECK(rule.szInitialClass);
|
||||
|
||||
if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.bX11 != -1) {
|
||||
if (pWindow->m_bIsX11 != rule.bX11)
|
||||
continue;
|
||||
|
@ -1965,6 +2072,16 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (rule.bFocus != -1) {
|
||||
if (rule.bFocus != (g_pCompositor->m_pLastWindow == pWindow))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.iOnWorkspace != -1) {
|
||||
if (rule.iOnWorkspace != g_pCompositor->getWindowsOnWorkspace(pWindow->m_iWorkspaceID))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rule.szWorkspace.empty()) {
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
||||
|
@ -2055,12 +2172,12 @@ void CConfigManager::dispatchExecOnce() {
|
|||
|
||||
// update dbus env
|
||||
if (g_pCompositor->m_sWLRSession)
|
||||
handleRawExec(
|
||||
"",
|
||||
handleRawExec("",
|
||||
#ifdef USES_SYSTEMD
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
|
||||
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash "
|
||||
"dbus-update-activation-environment 2>/dev/null && "
|
||||
#endif
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE");
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME");
|
||||
|
||||
firstExecDispatched = true;
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ struct SWorkspaceRule {
|
|||
std::optional<int> decorate;
|
||||
std::optional<int> shadow;
|
||||
std::optional<std::string> onCreatedEmptyRunCmd;
|
||||
std::map<std::string, std::any> layoutopts;
|
||||
std::map<std::string, std::string> layoutopts;
|
||||
};
|
||||
|
||||
struct SMonitorAdditionalReservedArea {
|
||||
|
|
|
@ -35,6 +35,7 @@ $menu = wofi --show drun
|
|||
|
||||
# Some default env vars.
|
||||
env = XCURSOR_SIZE,24
|
||||
env = QT_QPA_PLATFORMTHEME,qt5ct # change to qt6ct if you have that
|
||||
|
||||
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
|
||||
input {
|
||||
|
|
|
@ -63,8 +63,8 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
|||
struct utsname unameInfo;
|
||||
uname(&unameInfo);
|
||||
|
||||
finalCrashReport +=
|
||||
std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
|
||||
finalCrashReport += std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", std::string{unameInfo.sysname}, std::string{unameInfo.nodename},
|
||||
std::string{unameInfo.release}, std::string{unameInfo.version});
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
||||
|
@ -130,19 +130,15 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
|||
std::ofstream ofs;
|
||||
std::string path;
|
||||
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
|
||||
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
|
||||
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland"))
|
||||
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
|
||||
std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
ofs.open(path, std::ios::trunc);
|
||||
|
||||
} else {
|
||||
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
|
||||
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland"))
|
||||
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
|
||||
std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
||||
ofs.open(path, std::ios::trunc);
|
||||
|
|
|
@ -75,10 +75,9 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
|
|||
"vrr": {},
|
||||
"activelyTearing": {}
|
||||
}},)#",
|
||||
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szDescription), (m->output->make ? m->output->make : ""),
|
||||
(m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate,
|
||||
(int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace,
|
||||
(m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
|
||||
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szDescription), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
|
||||
(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
|
||||
m->activeWorkspace, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
|
||||
escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
|
||||
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
|
||||
(m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"),
|
||||
|
@ -93,17 +92,17 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
|
|||
if (!m->output || m->ID == -1ull)
|
||||
continue;
|
||||
|
||||
result += std::format(
|
||||
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
|
||||
result +=
|
||||
std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
|
||||
"workspace: {} ({})\n\treserved: {} "
|
||||
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
|
||||
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\n",
|
||||
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
|
||||
m->szDescription, (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
|
||||
(m->output->serial ? m->output->serial : ""), m->activeWorkspace, (m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName),
|
||||
m->specialWorkspaceID, getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
|
||||
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"),
|
||||
(int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing);
|
||||
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szDescription,
|
||||
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspace,
|
||||
(m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), m->specialWorkspaceID,
|
||||
getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x,
|
||||
(int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus,
|
||||
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -749,15 +748,12 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
|||
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
|
||||
").\nTag: " + GIT_TAG + "\n\nflags: (if any)\n";
|
||||
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + "\n\nflags: (if any)\n";
|
||||
|
||||
#ifdef LEGACY_RENDERER
|
||||
result += "legacyrenderer\n";
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
result += "debug\n";
|
||||
#endif
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
#ifndef ISDEBUG
|
||||
result += "debug\n";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
|
@ -772,17 +768,15 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
|||
"commit": "{}",
|
||||
"dirty": {},
|
||||
"commit_message": "{}",
|
||||
"commit_date": "{}",
|
||||
"tag": "{}",
|
||||
"flags": [)#",
|
||||
GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_TAG);
|
||||
GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG);
|
||||
|
||||
#ifdef LEGACY_RENDERER
|
||||
result += "\"legacyrenderer\",";
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
result += "\"debug\",";
|
||||
#endif
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
#ifndef ISDEBUG
|
||||
result += "\"debug\",";
|
||||
#endif
|
||||
#ifdef NO_XWAYLAND
|
||||
|
@ -1180,6 +1174,32 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
|
|||
}
|
||||
}
|
||||
|
||||
std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
|
||||
|
||||
if (!PWINDOW)
|
||||
return "none";
|
||||
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
result += "[";
|
||||
for (auto& wd : PWINDOW->m_dWindowDecorations) {
|
||||
result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},";
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
result += "]";
|
||||
} else {
|
||||
result = +"Decoration\tPriority\n";
|
||||
for (auto& wd : PWINDOW->m_dWindowDecorations) {
|
||||
result += wd->getDisplayName() + "\t" + std::to_string(wd->getPositioningInfo().priority) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void createOutputIter(wlr_backend* backend, void* data) {
|
||||
const auto DATA = (std::pair<std::string, bool>*)data;
|
||||
|
||||
|
@ -1421,6 +1441,8 @@ std::string getReply(std::string request) {
|
|||
return dispatchSetCursor(request);
|
||||
else if (request.starts_with("getoption"))
|
||||
return dispatchGetOption(request, format);
|
||||
else if (request.starts_with("decorations"))
|
||||
return decorationRequest(request, format);
|
||||
else if (request.starts_with("[[BATCH]]"))
|
||||
return dispatchBatch(request);
|
||||
|
||||
|
|
|
@ -19,8 +19,7 @@ namespace HyprCtl {
|
|||
|
||||
inline int iSocketFD = -1;
|
||||
|
||||
enum eHyprCtlOutputFormat
|
||||
{
|
||||
enum eHyprCtlOutputFormat {
|
||||
FORMAT_NORMAL = 0,
|
||||
FORMAT_JSON
|
||||
};
|
||||
|
|
|
@ -10,16 +10,15 @@
|
|||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
enum eIconBackend
|
||||
{
|
||||
enum eIconBackend {
|
||||
ICONS_BACKEND_NONE = 0,
|
||||
ICONS_BACKEND_NF,
|
||||
ICONS_BACKEND_FA
|
||||
};
|
||||
|
||||
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
|
||||
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "", ""},
|
||||
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
|
||||
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
|
||||
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
|
||||
static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
|
||||
CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
|
||||
CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#define LOGMESSAGESIZE 1024
|
||||
#define ROLLING_LOG_SIZE 4096
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
enum LogLevel {
|
||||
NONE = -1,
|
||||
LOG = 0,
|
||||
WARN,
|
||||
|
|
|
@ -255,7 +255,7 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
|||
(int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
|
||||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
}
|
||||
|
||||
void Events::listener_commitLayerSurface(void* owner, void* data) {
|
||||
|
|
|
@ -52,7 +52,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
const auto PWORKSPACE =
|
||||
PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
PWINDOW->m_bMappedX11 = true;
|
||||
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
PWINDOW->m_bIsMapped = true;
|
||||
PWINDOW->m_bReadyToDelete = false;
|
||||
|
@ -479,7 +478,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
|
||||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late");
|
||||
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW,
|
||||
|
@ -506,14 +504,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
"XWayland Window Late");
|
||||
}
|
||||
|
||||
// do the animation thing
|
||||
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
|
||||
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||
PWINDOW->m_fAlpha = 1.f;
|
||||
|
||||
PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
|
||||
PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
|
||||
|
||||
if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) ||
|
||||
requestsFakeFullscreen) {
|
||||
// fix fullscreen on requested (basically do a switcheroo)
|
||||
|
@ -627,6 +617,19 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
|
||||
EMIT_HOOK_EVENT("openWindow", PWINDOW);
|
||||
|
||||
// apply data from default decos. Borders, shadows.
|
||||
g_pDecorationPositioner->forceRecalcFor(PWINDOW);
|
||||
PWINDOW->updateWindowDecos();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW);
|
||||
|
||||
// do animations
|
||||
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
|
||||
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
|
||||
PWINDOW->m_fAlpha = 1.f;
|
||||
|
||||
PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
|
||||
PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
|
||||
|
||||
// recalc the values for this window
|
||||
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
||||
// avoid this window being visible
|
||||
|
@ -636,11 +639,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
|
||||
|
||||
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == g_pCompositor->m_pLastWindow)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// fix some xwayland apps that don't behave nicely
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
|
||||
|
||||
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
|
||||
}
|
||||
|
||||
void Events::listener_unmapWindow(void* owner, void* data) {
|
||||
|
@ -668,7 +672,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
|||
|
||||
if (!PWINDOW->m_bIsX11) {
|
||||
Debug::log(LOG, "Unregistered late callbacks XDG");
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
||||
PWINDOW->hyprListener_newPopupXDG.removeCallback();
|
||||
PWINDOW->hyprListener_requestMaximize.removeCallback();
|
||||
|
@ -710,8 +713,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
|||
g_pInputManager->releaseAllMouseButtons();
|
||||
}
|
||||
|
||||
PWINDOW->m_bMappedX11 = false;
|
||||
|
||||
// remove the fullscreen window status from workspace if we closed it
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
|
@ -732,8 +733,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
|||
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
|
||||
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
|
||||
|
||||
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == PWINDOWCANDIDATE)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow || !g_pCompositor->m_pLastWindow) {
|
||||
|
@ -793,7 +793,7 @@ void Events::listener_ackConfigure(void* owner, void* data) {
|
|||
void Events::listener_commitWindow(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
|
||||
return;
|
||||
|
||||
if (PWINDOW->m_bIsX11)
|
||||
|
@ -811,22 +811,29 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
|||
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
|
||||
return;
|
||||
|
||||
const auto ISRIGID = PWINDOW->m_uSurface.xdg->toplevel->current.max_height == PWINDOW->m_uSurface.xdg->toplevel->current.min_height &&
|
||||
PWINDOW->m_uSurface.xdg->toplevel->current.max_width == PWINDOW->m_uSurface.xdg->toplevel->current.min_width;
|
||||
const auto MINSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.min_width, PWINDOW->m_uSurface.xdg->toplevel->current.min_height};
|
||||
const auto MAXSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
|
||||
|
||||
if (!ISRIGID)
|
||||
if (MAXSIZE < Vector2D{1, 1})
|
||||
return;
|
||||
|
||||
const Vector2D REQUESTEDSIZE = {PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
|
||||
const auto REALSIZE = PWINDOW->m_vRealSize.goalv();
|
||||
Vector2D newSize = REALSIZE;
|
||||
|
||||
if (REQUESTEDSIZE == PWINDOW->m_vReportedSize || REQUESTEDSIZE.x < 5 || REQUESTEDSIZE.y < 5)
|
||||
return;
|
||||
if (MAXSIZE.x < newSize.x)
|
||||
newSize.x = MAXSIZE.x;
|
||||
if (MAXSIZE.y < newSize.y)
|
||||
newSize.y = MAXSIZE.y;
|
||||
if (MINSIZE.x > newSize.x)
|
||||
newSize.x = MINSIZE.x;
|
||||
if (MINSIZE.y > newSize.y)
|
||||
newSize.y = MINSIZE.y;
|
||||
|
||||
const Vector2D DELTA = PWINDOW->m_vReportedSize - REQUESTEDSIZE;
|
||||
const Vector2D DELTA = REALSIZE - newSize;
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0;
|
||||
PWINDOW->m_vRealSize = REQUESTEDSIZE;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, REQUESTEDSIZE, true);
|
||||
PWINDOW->m_vRealSize = newSize;
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
}
|
||||
|
||||
|
@ -843,6 +850,7 @@ void Events::listener_destroyWindow(void* owner, void* data) {
|
|||
g_pCompositor->m_pLastFocus = nullptr;
|
||||
}
|
||||
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_unmapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_destroyWindow.removeCallback();
|
||||
|
@ -1018,8 +1026,9 @@ void Events::listener_configureX11(void* owner, void* data) {
|
|||
|
||||
const auto E = (wlr_xwayland_surface_configure_event*)data;
|
||||
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bMappedX11) {
|
||||
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bIsMapped) {
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
return;
|
||||
}
|
||||
|
@ -1057,6 +1066,14 @@ void Events::listener_configureX11(void* owner, void* data) {
|
|||
|
||||
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
|
||||
|
||||
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_iWorkspaceID))
|
||||
return; // further things are only for visible windows
|
||||
|
||||
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
|
||||
|
||||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
|
@ -1067,16 +1084,12 @@ void Events::listener_configureX11(void* owner, void* data) {
|
|||
g_pInputManager->refocus();
|
||||
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
PWINDOW->m_vReportedSize = {E->width, E->height};
|
||||
}
|
||||
|
||||
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
CWindow* PWINDOW = (CWindow*)owner;
|
||||
|
||||
if (!PWINDOW->m_bMappedX11)
|
||||
if (!PWINDOW->m_bIsMapped)
|
||||
return;
|
||||
|
||||
const auto POS = PWINDOW->m_vRealPosition.goalv();
|
||||
|
@ -1124,6 +1137,10 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
|||
g_pCompositor->changeWindowZOrder(PWINDOW, true);
|
||||
PWINDOW->updateWindowDecos();
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv();
|
||||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1139,12 +1156,14 @@ void Events::listener_associateX11(void* owner, void* data) {
|
|||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW, "XWayland Window");
|
||||
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XWayland Window");
|
||||
}
|
||||
|
||||
void Events::listener_dissociateX11(void* owner, void* data) {
|
||||
const auto PWINDOW = (CWindow*)owner;
|
||||
|
||||
PWINDOW->hyprListener_mapWindow.removeCallback();
|
||||
PWINDOW->hyprListener_commitWindow.removeCallback();
|
||||
}
|
||||
|
||||
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
|
||||
|
@ -1181,6 +1200,7 @@ void Events::listener_newXDGToplevel(wl_listener* listener, void* data) {
|
|||
|
||||
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
|
||||
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XDG Window");
|
||||
PNEWWINDOW->hyprListener_commitWindow.initCallback(&XDGSURFACE->surface->events.commit, &Events::listener_commitWindow, PNEWWINDOW, "XDG Window");
|
||||
}
|
||||
|
||||
void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
|
||||
|
@ -1203,7 +1223,7 @@ void Events::listener_requestMaximize(void* owner, void* data) {
|
|||
|
||||
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
|
||||
} else {
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||
return;
|
||||
|
||||
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED);
|
||||
|
@ -1216,7 +1236,7 @@ void Events::listener_requestMinimize(void* owner, void* data) {
|
|||
Debug::log(LOG, "Minimize request for {}", PWINDOW);
|
||||
|
||||
if (PWINDOW->m_bIsX11) {
|
||||
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
|
||||
if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1)
|
||||
return;
|
||||
|
||||
const auto E = (wlr_xwayland_minimize_event*)data;
|
||||
|
|
|
@ -8,16 +8,14 @@
|
|||
#include "../macros.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
|
||||
enum ANIMATEDVARTYPE
|
||||
{
|
||||
enum ANIMATEDVARTYPE {
|
||||
AVARTYPE_INVALID = -1,
|
||||
AVARTYPE_FLOAT,
|
||||
AVARTYPE_VECTOR,
|
||||
AVARTYPE_COLOR
|
||||
};
|
||||
|
||||
enum AVARDAMAGEPOLICY
|
||||
{
|
||||
enum AVARDAMAGEPOLICY {
|
||||
AVARDAMAGE_NONE = -1,
|
||||
AVARDAMAGE_ENTIRE = 0,
|
||||
AVARDAMAGE_BORDER,
|
||||
|
|
|
@ -577,10 +577,10 @@ void logSystemInfo() {
|
|||
|
||||
uname(&unameInfo);
|
||||
|
||||
Debug::log(LOG, "System name: {}", unameInfo.sysname);
|
||||
Debug::log(LOG, "Node name: {}", unameInfo.nodename);
|
||||
Debug::log(LOG, "Release: {}", unameInfo.release);
|
||||
Debug::log(LOG, "Version: {}", unameInfo.version);
|
||||
Debug::log(LOG, "System name: {}", std::string{unameInfo.sysname});
|
||||
Debug::log(LOG, "Node name: {}", std::string{unameInfo.nodename});
|
||||
Debug::log(LOG, "Release: {}", std::string{unameInfo.release});
|
||||
Debug::log(LOG, "Version: {}", std::string{unameInfo.version});
|
||||
|
||||
Debug::log(NONE, "\n");
|
||||
|
||||
|
@ -792,3 +792,10 @@ uint32_t glFormatToType(uint32_t gl) {
|
|||
#endif
|
||||
GL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
bool envEnabled(const std::string& env) {
|
||||
const auto ENV = getenv(env.c_str());
|
||||
if (!ENV)
|
||||
return false;
|
||||
return std::string(ENV) == "1";
|
||||
}
|
|
@ -35,6 +35,7 @@ std::vector<SCallstackFrameInfo> getBacktrace();
|
|||
void throwError(const std::string& err);
|
||||
uint32_t drmFormatToGL(uint32_t drm);
|
||||
uint32_t glFormatToType(uint32_t gl);
|
||||
bool envEnabled(const std::string& env);
|
||||
|
||||
template <typename... Args>
|
||||
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
|
||||
|
|
|
@ -533,13 +533,11 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
|||
}
|
||||
}
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
|
||||
|
||||
if (const auto PLASTWINDOW = pWorkspace->getLastFocusedWindow(); PLASTWINDOW)
|
||||
g_pCompositor->focusWindow(PLASTWINDOW);
|
||||
else {
|
||||
CWindow* pWindow = nullptr;
|
||||
|
||||
if (!pWindow) {
|
||||
if (*PFOLLOWMOUSE == 1)
|
||||
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||
|
||||
|
@ -548,9 +546,11 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
|||
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
|
||||
}
|
||||
|
||||
g_pCompositor->focusWindow(pWindow);
|
||||
}
|
||||
|
||||
if (!noMouseMove)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
|
@ -565,6 +565,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
|||
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
|
||||
|
||||
g_pConfigManager->ensureVRR(this);
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
}
|
||||
|
||||
void CMonitor::changeWorkspace(const int& id, bool internal) {
|
||||
|
@ -590,6 +592,8 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
|||
else
|
||||
g_pInputManager->refocus();
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -618,6 +622,22 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
|||
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
||||
w->m_iMonitorID = ID;
|
||||
w->updateSurfaceOutputs();
|
||||
|
||||
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 it's floating and the middle isnt on the current mon, move it to the center
|
||||
const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE);
|
||||
Vector2D pos = w->m_vRealPosition.goalv();
|
||||
if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x,
|
||||
PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) {
|
||||
// not on any monitor, center
|
||||
pos = middle() / 2.f - w->m_vRealSize.goalv() / 2.f;
|
||||
} else
|
||||
pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition;
|
||||
|
||||
w->m_vRealPosition = pos;
|
||||
w->m_vPosition = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -631,6 +651,8 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
|||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
|
||||
|
||||
g_pHyprRenderer->damageMonitor(this);
|
||||
|
||||
g_pCompositor->updateSuspendedStates();
|
||||
}
|
||||
|
||||
void CMonitor::setSpecialWorkspace(const int& id) {
|
||||
|
|
|
@ -40,7 +40,8 @@ class CMonitor {
|
|||
|
||||
uint64_t ID = -1;
|
||||
int activeWorkspace = -1;
|
||||
float scale = 1;
|
||||
float setScale = 1; // scale set by cfg
|
||||
float scale = 1; // real scale
|
||||
|
||||
std::string szName = "";
|
||||
std::string szDescription = "";
|
||||
|
|
|
@ -50,6 +50,15 @@ class CVarList {
|
|||
return m_vArgs.end();
|
||||
}
|
||||
|
||||
bool contains(const std::string& el) {
|
||||
for (auto& a : m_vArgs) {
|
||||
if (a == el)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_vArgs;
|
||||
};
|
|
@ -97,6 +97,8 @@ struct SRenderData {
|
|||
|
||||
// for calculating UV
|
||||
CWindow* pWindow = nullptr;
|
||||
|
||||
bool popup = false;
|
||||
};
|
||||
|
||||
struct SExtensionFindingData {
|
||||
|
@ -180,6 +182,7 @@ struct SConstraint {
|
|||
Vector2D getLogicConstraintPos();
|
||||
Vector2D getLogicConstraintSize();
|
||||
|
||||
//
|
||||
bool operator==(const SConstraint& b) const {
|
||||
return constraint == b.constraint;
|
||||
}
|
||||
|
@ -252,6 +255,8 @@ struct STablet {
|
|||
wlr_tablet_v2_tablet* wlrTabletV2 = nullptr;
|
||||
wlr_input_device* wlrDevice = nullptr;
|
||||
|
||||
bool relativeInput = false;
|
||||
|
||||
std::string name = "";
|
||||
|
||||
//
|
||||
|
|
|
@ -28,8 +28,7 @@ typedef struct {
|
|||
} xcb_size_hints_t;
|
||||
typedef unsigned int xcb_window_t;
|
||||
|
||||
typedef enum xcb_stack_mode_t
|
||||
{
|
||||
typedef enum xcb_stack_mode_t {
|
||||
XCB_STACK_MODE_ABOVE = 0,
|
||||
XCB_STACK_MODE_BELOW = 1,
|
||||
XCB_STACK_MODE_TOP_IF = 2,
|
||||
|
|
|
@ -149,24 +149,20 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.shadow = false;
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
const auto RESERVED = PWINDOW->getFullWindowReservedArea();
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE) + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE) - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
auto calcPos = PWINDOW->m_vPosition;
|
||||
auto calcSize = PWINDOW->m_vSize;
|
||||
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut : gapsIn, DISPLAYTOP ? gapsOut : gapsIn);
|
||||
|
||||
|
@ -258,10 +254,11 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
|||
|
||||
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
|
||||
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 &&
|
||||
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
|
||||
|
||||
// happens on reserved area
|
||||
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
|
||||
|
@ -272,7 +269,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
|||
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
|
||||
} else {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
|
||||
}
|
||||
|
||||
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
|
||||
|
@ -319,16 +316,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
|||
}
|
||||
|
||||
if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) {
|
||||
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
|
||||
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
|
||||
if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it's a group, add the window
|
||||
|
@ -403,15 +392,15 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
|||
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size();
|
||||
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
|
||||
|
||||
if (MOUSECOORDS.inTriangle(tl, tr, cc)) {
|
||||
if (TARGETCOORDS.inTriangle(tl, tr, cc)) {
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
} else if (MOUSECOORDS.inTriangle(tr, cc, br)) {
|
||||
} else if (TARGETCOORDS.inTriangle(tr, cc, br)) {
|
||||
NEWPARENT->splitTop = false;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
} else if (MOUSECOORDS.inTriangle(br, bl, cc)) {
|
||||
} else if (TARGETCOORDS.inTriangle(br, bl, cc)) {
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
|
@ -422,9 +411,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
|||
}
|
||||
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
|
||||
if ((SIDEBYSIDE &&
|
||||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
|
||||
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
|
||||
(!SIDEBYSIDE &&
|
||||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
|
||||
VECINRECT(TARGETCOORDS, 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.
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
|
@ -1048,7 +1037,7 @@ std::string CHyprDwindleLayout::getLayoutName() {
|
|||
|
||||
void CHyprDwindleLayout::onEnable() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->isHidden())
|
||||
if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
onWindowCreatedTiling(w.get());
|
||||
|
|
|
@ -36,15 +36,15 @@ void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
|
|||
const auto WINDOWISVISIBLE = pWindow->getGroupCurrent() == pWindow;
|
||||
|
||||
if (WINDOWISVISIBLE)
|
||||
PWINDOWPREV->setGroupCurrent(PWINDOWPREV);
|
||||
PWINDOWPREV->setGroupCurrent(pWindow->m_sGroupData.head ? pWindow->m_sGroupData.pNextWindow : PWINDOWPREV);
|
||||
|
||||
PWINDOWPREV->m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
|
||||
|
||||
pWindow->m_sGroupData.pNextWindow = nullptr;
|
||||
|
||||
if (pWindow->m_sGroupData.head) {
|
||||
std::swap(PWINDOWPREV->m_sGroupData.head, pWindow->m_sGroupData.head);
|
||||
std::swap(PWINDOWPREV->m_sGroupData.locked, pWindow->m_sGroupData.locked);
|
||||
std::swap(PWINDOWPREV->m_sGroupData.pNextWindow->m_sGroupData.head, pWindow->m_sGroupData.head);
|
||||
std::swap(PWINDOWPREV->m_sGroupData.pNextWindow->m_sGroupData.locked, pWindow->m_sGroupData.locked);
|
||||
}
|
||||
|
||||
if (pWindow == m_pLastTiledWindow)
|
||||
|
@ -271,16 +271,8 @@ void IHyprLayout::onEndDragWindow() {
|
|||
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS, DRAGGINGWINDOW);
|
||||
|
||||
if (pWindow && pWindow->m_bIsFloating) {
|
||||
for (auto& wd : pWindow->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
|
||||
if (!wd->onEndWindowDragOnDeco(DRAGGINGWINDOW, MOUSECOORDS))
|
||||
if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) {
|
||||
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
|
||||
|
@ -565,13 +557,19 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
|||
}
|
||||
|
||||
// if it was a tiled window, we first try to find the window that will replace it.
|
||||
const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->middle());
|
||||
auto pWindowCandidate = g_pCompositor->vectorToWindowIdeal(pWindow->middle());
|
||||
|
||||
if (!PWINDOWCANDIDATE || pWindow == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->isHidden() || PWINDOWCANDIDATE->m_bX11ShouldntFocus ||
|
||||
PWINDOWCANDIDATE->m_iX11Type == 2 || PWINDOWCANDIDATE->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
|
||||
if (!pWindowCandidate)
|
||||
pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (!pWindowCandidate)
|
||||
pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus ||
|
||||
pWindowCandidate->m_iX11Type == 2 || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
|
||||
return nullptr;
|
||||
|
||||
return PWINDOWCANDIDATE;
|
||||
return pWindowCandidate;
|
||||
}
|
||||
|
||||
bool IHyprLayout::isWindowReachable(CWindow* pWindow) {
|
||||
|
|
|
@ -15,8 +15,7 @@ struct SLayoutMessageHeader {
|
|||
|
||||
enum eFullscreenMode : int8_t;
|
||||
|
||||
enum eRectCorner
|
||||
{
|
||||
enum eRectCorner {
|
||||
CORNER_NONE = 0,
|
||||
CORNER_TOPLEFT,
|
||||
CORNER_TOPRIGHT,
|
||||
|
@ -24,8 +23,7 @@ enum eRectCorner
|
|||
CORNER_BOTTOMLEFT
|
||||
};
|
||||
|
||||
enum eDirection
|
||||
{
|
||||
enum eDirection {
|
||||
DIRECTION_DEFAULT = -1,
|
||||
DIRECTION_UP = 0,
|
||||
DIRECTION_RIGHT,
|
||||
|
|
|
@ -45,10 +45,8 @@ SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
|
|||
const auto layoutoptsForWs = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(ws)).layoutopts;
|
||||
auto orientationForWs = *orientation;
|
||||
|
||||
try {
|
||||
if (layoutoptsForWs.contains("orientation"))
|
||||
orientationForWs = std::any_cast<std::string>(layoutoptsForWs.at("orientation"));
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Error from layoutopt rules: {}", e.what()); }
|
||||
orientationForWs = layoutoptsForWs.at("orientation");
|
||||
|
||||
if (orientationForWs == "top") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
|
||||
|
@ -56,11 +54,12 @@ SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
|
|||
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
|
||||
} else if (orientationForWs == "bottom") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
|
||||
} else if (orientationForWs == "left") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
|
||||
} else {
|
||||
} else if (orientationForWs == "center") {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
|
||||
} else {
|
||||
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
|
||||
}
|
||||
|
||||
return PWORKSPACEDATA;
|
||||
}
|
||||
|
||||
|
@ -103,16 +102,8 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
|
|||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
if (g_pInputManager->m_bWasDraggingWindow && OPENINGON) {
|
||||
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
|
||||
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
|
||||
if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it's a group, add the window
|
||||
|
@ -667,24 +658,20 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
|||
PWINDOW->m_sSpecialRenderData.rounding = false;
|
||||
PWINDOW->m_sSpecialRenderData.shadow = false;
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
|
||||
const auto RESERVED = PWINDOW->getFullWindowReservedArea();
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE) + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE) - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
PWINDOW->updateWindowDecos();
|
||||
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
|
||||
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
|
||||
|
||||
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const int BORDERSIZE = PWINDOW->getRealBorderSize();
|
||||
|
||||
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
|
||||
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
|
||||
auto calcPos = PWINDOW->m_vPosition;
|
||||
auto calcSize = PWINDOW->m_vSize;
|
||||
|
||||
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut : gapsIn, DISPLAYTOP ? gapsOut : gapsIn);
|
||||
|
||||
|
@ -1337,6 +1324,50 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
|||
nd.percMaster = std::clamp(newMfact, 0.05f, 0.95f);
|
||||
}
|
||||
}
|
||||
} else if (command == "rollnext") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
|
||||
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
if (nd.workspaceID == PNODE->workspaceID && !nd.isMaster) {
|
||||
nd.isMaster = true;
|
||||
const auto NEWMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), nd);
|
||||
m_lMasterNodesData.splice(OLDMASTERIT, m_lMasterNodesData, NEWMASTERIT);
|
||||
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
|
||||
switchToWindow(nd.pWindow);
|
||||
prepareNewFocus(nd.pWindow, inheritFullscreen);
|
||||
OLDMASTER->isMaster = false;
|
||||
m_lMasterNodesData.splice(m_lMasterNodesData.end(), m_lMasterNodesData, OLDMASTERIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
} else if (command == "rollprev") {
|
||||
const auto PWINDOW = header.pWindow;
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
|
||||
|
||||
for (auto& nd : m_lMasterNodesData | std::views::reverse) {
|
||||
if (nd.workspaceID == PNODE->workspaceID && !nd.isMaster) {
|
||||
nd.isMaster = true;
|
||||
const auto NEWMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), nd);
|
||||
m_lMasterNodesData.splice(OLDMASTERIT, m_lMasterNodesData, NEWMASTERIT);
|
||||
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
|
||||
switchToWindow(nd.pWindow);
|
||||
prepareNewFocus(nd.pWindow, inheritFullscreen);
|
||||
OLDMASTER->isMaster = false;
|
||||
m_lMasterNodesData.splice(m_lMasterNodesData.begin(), m_lMasterNodesData, OLDMASTERIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1412,7 +1443,7 @@ void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
|||
|
||||
void CHyprMasterLayout::onEnable() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->isHidden())
|
||||
if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
onWindowCreatedTiling(w.get());
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
if (!(expr)) { \
|
||||
Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n{}\n\nat: line {} in {}", \
|
||||
std::format(reason, ##__VA_ARGS__), __LINE__, \
|
||||
([]() constexpr->std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })()); \
|
||||
([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })()); \
|
||||
printf("Assertion failed! See the log in /tmp/hypr/hyprland.log for more info."); \
|
||||
raise(SIGABRT); \
|
||||
}
|
||||
|
@ -63,9 +63,7 @@
|
|||
}
|
||||
|
||||
#define FORMAT_FLAG(spec__, flag__) \
|
||||
case spec__: \
|
||||
(flag__) = true; \
|
||||
break;
|
||||
case spec__: (flag__) = true; break;
|
||||
|
||||
#define FORMAT_NUMBER(buf__) \
|
||||
case '0': \
|
||||
|
@ -77,9 +75,7 @@
|
|||
case '6': \
|
||||
case '7': \
|
||||
case '8': \
|
||||
case '9': \
|
||||
(buf__).push_back(*it); \
|
||||
break;
|
||||
case '9': (buf__).push_back(*it); break;
|
||||
|
||||
#if ISDEBUG
|
||||
#define UNREACHABLE() \
|
||||
|
|
16
src/main.cpp
16
src/main.cpp
|
@ -56,19 +56,21 @@ int main(int argc, char** argv) {
|
|||
|
||||
return 1;
|
||||
}
|
||||
std::string next_arg = std::next(it)->c_str();
|
||||
configPath = std::next(it)->c_str();
|
||||
|
||||
if (std::filesystem::is_symlink(next_arg))
|
||||
next_arg = std::filesystem::read_symlink(next_arg);
|
||||
try {
|
||||
configPath = std::filesystem::canonical(configPath);
|
||||
|
||||
if (!std::filesystem::is_regular_file(next_arg)) {
|
||||
std::cerr << "[ ERROR ] Config file '" << next_arg << "' doesn't exist!\n";
|
||||
if (!std::filesystem::is_regular_file(configPath)) {
|
||||
throw std::exception();
|
||||
}
|
||||
} catch (...) {
|
||||
std::cerr << "[ ERROR ] Config file '" << configPath << "' doesn't exist!\n";
|
||||
help();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
configPath = std::filesystem::weakly_canonical(next_arg);
|
||||
Debug::log(LOG, "User-specified config location: '{}'", configPath);
|
||||
|
||||
it++;
|
||||
|
@ -104,7 +106,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
g_pCompositor->initServer();
|
||||
|
||||
if (!getenv("HYPRLAND_NO_RT") || configStringToInt(std::string(getenv("HYPRLAND_NO_RT"))) == 0)
|
||||
if (!envEnabled("HYPRLAND_NO_RT"))
|
||||
Init::gainRealTime();
|
||||
|
||||
Debug::log(LOG, "Hyprland init finished.");
|
||||
|
|
|
@ -229,6 +229,8 @@ void CAnimationManager::tick() {
|
|||
case AVARDAMAGE_BORDER: {
|
||||
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
|
||||
|
||||
// TODO: move this to the border class
|
||||
|
||||
// damage only the border.
|
||||
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
|
||||
const auto ROUNDINGSIZE = *PROUNDING + 1;
|
||||
|
|
|
@ -20,6 +20,7 @@ class CEventManager {
|
|||
void startThread();
|
||||
|
||||
std::thread m_tThread;
|
||||
|
||||
private:
|
||||
void flushEvents();
|
||||
|
||||
|
|
|
@ -751,6 +751,7 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
|
|||
while (curr != PCURRENT) {
|
||||
curr->m_bIsFloating = PCURRENT->m_bIsFloating;
|
||||
curr->updateDynamicRules();
|
||||
curr->updateSpecialRenderData();
|
||||
curr = curr->m_sGroupData.pNextWindow;
|
||||
}
|
||||
} else {
|
||||
|
@ -801,6 +802,10 @@ void CKeybindManager::changeworkspace(std::string args) {
|
|||
static auto* const PWORKSPACECENTERON = &g_pConfigManager->getConfigValuePtr("binds:workspace_center_on")->intValue;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
|
||||
const bool EXPLICITPREVIOUS = args.starts_with("previous");
|
||||
|
||||
|
@ -875,10 +880,12 @@ void CKeybindManager::changeworkspace(std::string args) {
|
|||
} else
|
||||
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
|
||||
|
||||
if (!g_pCompositor->m_pLastFocus)
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
else
|
||||
if (!g_pInputManager->m_bLastFocusOnLS) {
|
||||
if (g_pCompositor->m_pLastFocus)
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
else
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
}
|
||||
|
||||
void CKeybindManager::fullscreenActive(std::string args) {
|
||||
|
@ -1567,10 +1574,18 @@ void CKeybindManager::circleNext(std::string arg) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
|
||||
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow, true));
|
||||
CVarList args{arg, 0, 's', true};
|
||||
|
||||
std::optional<bool> floatStatus = {};
|
||||
if (args.contains("tile") || args.contains("tiled"))
|
||||
floatStatus = false;
|
||||
else if (args.contains("float") || args.contains("floating"))
|
||||
floatStatus = true;
|
||||
|
||||
if (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l"))
|
||||
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow, true, floatStatus));
|
||||
else
|
||||
switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow, true));
|
||||
switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow, true, floatStatus));
|
||||
}
|
||||
|
||||
void CKeybindManager::focusWindow(std::string regexp) {
|
||||
|
@ -1828,17 +1843,8 @@ void CKeybindManager::mouse(std::string args) {
|
|||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
||||
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
|
||||
if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords)) {
|
||||
for (auto& wd : pWindow->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
|
||||
wd->onBeginWindowDragOnDeco(mouseCoords);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pWindow && !pWindow->m_bIsFullscreen)
|
||||
pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_START, mouseCoords);
|
||||
|
||||
if (!g_pInputManager->currentlyDraggedWindow)
|
||||
g_pInputManager->currentlyDraggedWindow = pWindow;
|
||||
|
@ -1914,8 +1920,7 @@ void CKeybindManager::fakeFullscreenActive(std::string args) {
|
|||
if (g_pCompositor->m_pLastWindow) {
|
||||
// will also set the flag
|
||||
g_pCompositor->m_pLastWindow->m_bFakeFullscreenState = !g_pCompositor->m_pLastWindow->m_bFakeFullscreenState;
|
||||
g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow,
|
||||
g_pCompositor->m_pLastWindow->m_bFakeFullscreenState || g_pCompositor->m_pLastWindow->m_bIsFullscreen);
|
||||
g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow, g_pCompositor->m_pLastWindow->shouldSendFullscreenState());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,7 @@ struct SKeybind {
|
|||
bool shadowed = false;
|
||||
};
|
||||
|
||||
enum eFocusWindowMode
|
||||
{
|
||||
enum eFocusWindowMode {
|
||||
MODE_CLASS_REGEX = 0,
|
||||
MODE_TITLE_REGEX,
|
||||
MODE_ADDRESS,
|
||||
|
|
|
@ -119,7 +119,7 @@ std::string CHyprXWaylandManager::getTitle(CWindow* pWindow) {
|
|||
}
|
||||
|
||||
std::string CHyprXWaylandManager::getAppIDClass(CWindow* pWindow) {
|
||||
if (!pWindow->m_bMappedX11 || !pWindow->m_bIsMapped)
|
||||
if (!pWindow->m_bIsMapped)
|
||||
return "";
|
||||
|
||||
try {
|
||||
|
@ -150,14 +150,12 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
|
|||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
// calculate pos
|
||||
// TODO: this should be decoupled from setWindowSize IMO
|
||||
Vector2D windowPos = pWindow->m_vRealPosition.vec();
|
||||
|
||||
if (pWindow->m_bIsX11) {
|
||||
if (pWindow->m_bIsX11 && PMONITOR) {
|
||||
windowPos = windowPos - PMONITOR->vecPosition; // normalize to monitor
|
||||
if (*PXWLFORCESCALEZERO)
|
||||
windowPos = windowPos * PMONITOR->scale; // scale if applicable
|
||||
|
@ -172,12 +170,10 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
|
|||
|
||||
pWindow->m_fX11SurfaceScaledBy = 1.f;
|
||||
|
||||
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR) {
|
||||
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11 && PMONITOR) {
|
||||
size = size * PMONITOR->scale;
|
||||
pWindow->m_fX11SurfaceScaledBy = PMONITOR->scale;
|
||||
}
|
||||
}
|
||||
|
||||
if (pWindow->m_bIsX11)
|
||||
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y);
|
||||
|
|
|
@ -319,14 +319,16 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
|
||||
if (!foundSurface) {
|
||||
if (!m_bEmptyFocusCursorSet) {
|
||||
if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) {
|
||||
m_eBorderIconDirection = BORDERICON_NONE;
|
||||
if (g_pHyprRenderer->m_bHasARenderedCursor) {
|
||||
unsetCursorImage();
|
||||
}
|
||||
|
||||
// TODO: maybe wrap?
|
||||
if (m_ecbClickBehavior == CLICKMODE_KILL)
|
||||
setCursorImageOverride("crosshair");
|
||||
else
|
||||
setCursorImageOverride("left_ptr");
|
||||
}
|
||||
|
||||
m_bEmptyFocusCursorSet = true;
|
||||
}
|
||||
|
@ -481,12 +483,7 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
|
|||
}
|
||||
|
||||
void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) {
|
||||
if (!e->surface)
|
||||
g_pHyprRenderer->m_bWindowRequestedCursorHide = true;
|
||||
else
|
||||
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
|
||||
|
||||
if (!cursorImageUnlocked() || !g_pHyprRenderer->m_bHasARenderedCursor)
|
||||
if (!cursorImageUnlocked())
|
||||
return;
|
||||
|
||||
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
|
||||
|
@ -509,7 +506,7 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
|
|||
}
|
||||
|
||||
void CInputManager::processMouseRequest(wlr_cursor_shape_manager_v1_request_set_shape_event* e) {
|
||||
if (!g_pHyprRenderer->m_bHasARenderedCursor || !cursorImageUnlocked())
|
||||
if (!cursorImageUnlocked())
|
||||
return;
|
||||
|
||||
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
|
||||
|
@ -551,9 +548,6 @@ void CInputManager::setCursorImageOverride(const std::string& name) {
|
|||
}
|
||||
|
||||
bool CInputManager::cursorImageUnlocked() {
|
||||
if (!g_pHyprRenderer->m_bHasARenderedCursor)
|
||||
return false;
|
||||
|
||||
if (m_ecbClickBehavior == CLICKMODE_KILL)
|
||||
return false;
|
||||
|
||||
|
@ -607,24 +601,16 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
|||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
||||
const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
|
||||
if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords)) {
|
||||
for (auto& wd : w->m_dWindowDecorations) {
|
||||
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
|
||||
continue;
|
||||
|
||||
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
|
||||
wd->onMouseButtonOnDeco(mouseCoords, e);
|
||||
if (w && !m_bLastFocusOnLS && w->checkInputOnDecos(INPUT_TYPE_BUTTON, mouseCoords, e))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clicking on border triggers resize
|
||||
// TODO detect click on LS properly
|
||||
if (*PRESIZEONBORDER && !m_bLastFocusOnLS) {
|
||||
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e->state == WLR_BUTTON_PRESSED) {
|
||||
if (w && !w->m_bIsFullscreen) {
|
||||
const CBox real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
|
||||
|
||||
if ((grab.containsPoint(mouseCoords) && (!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y))) && !w->hasPopupAt(mouseCoords)) {
|
||||
g_pKeybindManager->resizeWithBorder(e);
|
||||
return;
|
||||
|
@ -688,7 +674,6 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
|
|||
|
||||
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
|
||||
static auto* const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue;
|
||||
static auto* const PGROUPBARSCROLLING = &g_pConfigManager->getConfigValuePtr("group:groupbar:scrolling")->intValue;
|
||||
|
||||
auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR);
|
||||
|
||||
|
@ -702,19 +687,13 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
|
|||
if (!passEvent)
|
||||
return;
|
||||
|
||||
if (!m_bLastFocusOnLS) {
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
|
||||
const auto PWINDOW = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
|
||||
|
||||
if (*PGROUPBARSCROLLING && pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(MOUSECOORDS) && pWindow->m_sGroupData.pNextWindow) {
|
||||
const CBox box = g_pDecorationPositioner->getWindowDecorationBox(pWindow->getDecorationByType(DECORATION_GROUPBAR));
|
||||
if (box.containsPoint(MOUSECOORDS)) {
|
||||
if (e->delta > 0)
|
||||
pWindow->setGroupCurrent(pWindow->m_sGroupData.pNextWindow);
|
||||
else
|
||||
pWindow->setGroupCurrent(pWindow->getGroupPrevious());
|
||||
if (PWINDOW && PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e))
|
||||
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);
|
||||
}
|
||||
|
@ -853,7 +832,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
|||
pKeyboard->repeatDelay = REPEATDELAY;
|
||||
pKeyboard->repeatRate = REPEATRATE;
|
||||
pKeyboard->numlockOn = NUMLOCKON;
|
||||
pKeyboard->xkbFilePath = FILEPATH.c_str();
|
||||
pKeyboard->xkbFilePath = FILEPATH;
|
||||
|
||||
xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()};
|
||||
|
||||
|
@ -929,7 +908,8 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
|
|||
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->name + "," + LAYOUTSTR});
|
||||
EMIT_HOOK_EVENT("activeLayout", (std::vector<void*>{pKeyboard, (void*)&LAYOUTSTR}));
|
||||
|
||||
Debug::log(LOG, "Set the keyboard layout to {} and variant to {} for keyboard \"{}\"", rules.layout, rules.variant, pKeyboard->keyboard->name);
|
||||
Debug::log(LOG, "Set the keyboard layout to {} and variant to {} for keyboard \"{}\"", pKeyboard->currentRules.layout, pKeyboard->currentRules.variant,
|
||||
pKeyboard->keyboard->name);
|
||||
}
|
||||
|
||||
void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
|
||||
|
@ -1066,23 +1046,40 @@ void CInputManager::setPointerConfigs() {
|
|||
libinput_device_config_accel_set_speed(LIBINPUTDEV, LIBINPUTSENS);
|
||||
|
||||
const auto ACCELPROFILE = g_pConfigManager->getDeviceString(devname, "accel_profile", "input:accel_profile");
|
||||
const auto SCROLLPOINTS = g_pConfigManager->getDeviceString(devname, "scroll_points", "input:scroll_points");
|
||||
|
||||
if (ACCELPROFILE == "") {
|
||||
if (ACCELPROFILE.empty()) {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
|
||||
} else if (ACCELPROFILE == "adaptive") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
|
||||
} else if (ACCELPROFILE == "flat") {
|
||||
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
|
||||
} else if (ACCELPROFILE.starts_with("custom")) {
|
||||
CVarList args = {ACCELPROFILE, 0, ' '};
|
||||
CVarList accelValues = {ACCELPROFILE, 0, ' '};
|
||||
|
||||
try {
|
||||
double step = std::stod(args[1]);
|
||||
std::vector<double> points;
|
||||
for (size_t i = 2; i < args.size(); ++i)
|
||||
points.push_back(std::stod(args[i]));
|
||||
double accelStep = std::stod(accelValues[1]);
|
||||
std::vector<double> accelPoints;
|
||||
for (size_t i = 2; i < accelValues.size(); ++i) {
|
||||
accelPoints.push_back(std::stod(accelValues[i]));
|
||||
}
|
||||
|
||||
const auto CONFIG = libinput_config_accel_create(LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM);
|
||||
libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_MOTION, step, points.size(), points.data());
|
||||
|
||||
if (!SCROLLPOINTS.empty()) {
|
||||
CVarList scrollValues = {SCROLLPOINTS, 0, ' '};
|
||||
try {
|
||||
double scrollStep = std::stod(scrollValues[0]);
|
||||
std::vector<double> scrollPoints;
|
||||
for (size_t i = 1; i < scrollValues.size(); ++i) {
|
||||
scrollPoints.push_back(std::stod(scrollValues[i]));
|
||||
}
|
||||
|
||||
libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_SCROLL, scrollStep, scrollPoints.size(), scrollPoints.data());
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Invalid values in scroll_points"); }
|
||||
}
|
||||
|
||||
libinput_config_accel_set_points(CONFIG, LIBINPUT_ACCEL_TYPE_MOTION, accelStep, accelPoints.size(), accelPoints.data());
|
||||
libinput_device_config_accel_apply(LIBINPUTDEV, CONFIG);
|
||||
libinput_config_accel_destroy(CONFIG);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Invalid values in custom accel profile"); }
|
||||
|
@ -1494,6 +1491,9 @@ void CInputManager::setTabletConfigs() {
|
|||
if (wlr_input_device_is_libinput(t.wlrDevice)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(t.wlrDevice);
|
||||
|
||||
const auto RELINPUT = g_pConfigManager->getDeviceInt(t.name, "relative_input", "input:tablet:relative_input");
|
||||
t.relativeInput = RELINPUT;
|
||||
|
||||
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(t.name, "transform", "input:tablet:transform"), 0, 7);
|
||||
Debug::log(LOG, "Setting calibration matrix for device {}", t.name);
|
||||
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
|
||||
|
@ -1566,7 +1566,7 @@ void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
|
|||
}
|
||||
|
||||
void CInputManager::setCursorImageUntilUnset(std::string name) {
|
||||
g_pHyprRenderer->setCursorFromName(name.c_str());
|
||||
g_pHyprRenderer->setCursorFromName(name);
|
||||
m_bCursorImageOverridden = true;
|
||||
m_sCursorSurfaceInfo.inUse = false;
|
||||
}
|
||||
|
|
|
@ -7,14 +7,12 @@
|
|||
#include "../../helpers/Timer.hpp"
|
||||
#include "InputMethodRelay.hpp"
|
||||
|
||||
enum eClickBehaviorMode
|
||||
{
|
||||
enum eClickBehaviorMode {
|
||||
CLICKMODE_DEFAULT = 0,
|
||||
CLICKMODE_KILL
|
||||
};
|
||||
|
||||
enum eMouseBindMode
|
||||
{
|
||||
enum eMouseBindMode {
|
||||
MBIND_INVALID = -1,
|
||||
MBIND_MOVE = 0,
|
||||
MBIND_RESIZE = 1,
|
||||
|
@ -22,8 +20,7 @@ enum eMouseBindMode
|
|||
MBIND_RESIZE_FORCE_RATIO = 3
|
||||
};
|
||||
|
||||
enum eBorderIconDirection
|
||||
{
|
||||
enum eBorderIconDirection {
|
||||
BORDERICON_NONE,
|
||||
BORDERICON_UP,
|
||||
BORDERICON_DOWN,
|
||||
|
|
|
@ -251,11 +251,9 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
|||
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
|
||||
|
||||
if (VERTANIMS)
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
else
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
|
||||
return;
|
||||
|
@ -277,15 +275,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
|||
}
|
||||
|
||||
if (VERTANIMS) {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
|
||||
0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE - YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE - YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
} else {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
|
||||
((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE - XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE - XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
}
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft);
|
||||
|
@ -297,11 +291,9 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
|||
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
|
||||
|
||||
if (VERTANIMS)
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
else
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
|
||||
return;
|
||||
|
@ -323,15 +315,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
|||
}
|
||||
|
||||
if (VERTANIMS) {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
|
||||
0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE + YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE + YDISTANCE));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * YDISTANCE));
|
||||
} else {
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(
|
||||
((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE + XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(
|
||||
Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE + XDISTANCE, 0));
|
||||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * XDISTANCE, 0));
|
||||
}
|
||||
|
||||
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight);
|
||||
|
|
|
@ -44,8 +44,15 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
|||
break;
|
||||
default:
|
||||
double x = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->x : NAN;
|
||||
double dx = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->dx : NAN;
|
||||
double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN;
|
||||
double dy = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->dy : NAN;
|
||||
|
||||
if (PTAB->relativeInput)
|
||||
wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy);
|
||||
else
|
||||
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
|
||||
|
||||
g_pInputManager->refocus();
|
||||
g_pInputManager->m_tmrLastCursorMovement.reset();
|
||||
break;
|
||||
|
@ -83,6 +90,8 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
|||
|
||||
if (EVENT->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
|
||||
wlr_tablet_v2_tablet_tool_notify_tilt(PTOOL->wlrTabletToolV2, PTOOL->tiltX, PTOOL->tiltY);
|
||||
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
|
@ -102,6 +111,8 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
|||
} else {
|
||||
wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2);
|
||||
}
|
||||
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
|
@ -113,6 +124,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
|||
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
|
||||
|
||||
wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state);
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
|
@ -137,6 +149,8 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
|||
g_pInputManager->refocus();
|
||||
g_pInputManager->focusTablet(PTAB, EVENT->tool);
|
||||
}
|
||||
|
||||
g_pCompositor->notifyIdleActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "HookSystem.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
|
||||
#define register
|
||||
#include <udis86.h>
|
||||
|
@ -19,12 +20,12 @@ CFunctionHook::~CFunctionHook() {
|
|||
unhook();
|
||||
}
|
||||
|
||||
size_t CFunctionHook::getInstructionLenAt(void* start) {
|
||||
CFunctionHook::SInstructionProbe CFunctionHook::getInstructionLenAt(void* start) {
|
||||
ud_t udis;
|
||||
|
||||
ud_init(&udis);
|
||||
ud_set_mode(&udis, 64);
|
||||
ud_set_syntax(&udis, UD_SYN_INTEL);
|
||||
ud_set_syntax(&udis, UD_SYN_ATT);
|
||||
|
||||
size_t curOffset = 1;
|
||||
size_t insSize = 0;
|
||||
|
@ -41,31 +42,101 @@ size_t CFunctionHook::getInstructionLenAt(void* start) {
|
|||
if (const auto CINS = ud_insn_asm(&udis); CINS)
|
||||
ins = std::string(CINS);
|
||||
|
||||
if (!ins.empty() && ins.find("rip") != std::string::npos) {
|
||||
// todo: support something besides call qword ptr [rip + 0xdeadbeef]
|
||||
// I don't have an assembler. I don't think udis provides one. Besides, variables might be tricky.
|
||||
if (((uint8_t*)start)[0] == 0xFF && ((uint8_t*)start)[1] == 0x15)
|
||||
m_vTrampolineRIPUses.emplace_back(std::make_pair<>((uint64_t)start - (uint64_t)m_pSource, ins));
|
||||
else {
|
||||
Debug::log(ERR, "[CFunctionHook] Cannot hook: unsupported %rip usage: {}", ins);
|
||||
throw std::runtime_error("unsupported %rip usage");
|
||||
}
|
||||
}
|
||||
|
||||
return insSize;
|
||||
return {insSize, ins};
|
||||
}
|
||||
|
||||
size_t CFunctionHook::probeMinimumJumpSize(void* start, size_t min) {
|
||||
CFunctionHook::SInstructionProbe CFunctionHook::probeMinimumJumpSize(void* start, size_t min) {
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
std::string instrs = "";
|
||||
std::vector<size_t> sizes;
|
||||
|
||||
while (size <= min) {
|
||||
// find info about this instruction
|
||||
size_t insLen = getInstructionLenAt((uint8_t*)start + size);
|
||||
size += insLen;
|
||||
auto probe = getInstructionLenAt((uint8_t*)start + size);
|
||||
sizes.push_back(probe.len);
|
||||
size += probe.len;
|
||||
instrs += probe.assembly + "\n";
|
||||
}
|
||||
|
||||
return size;
|
||||
return {size, instrs, sizes};
|
||||
}
|
||||
|
||||
CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstructionProbe& probe) {
|
||||
// analyze the code and fix what we know how to.
|
||||
uint64_t currentAddress = (uint64_t)m_pSource;
|
||||
// actually newline + 1
|
||||
size_t lastAsmNewline = 0;
|
||||
std::string assemblyBuilder;
|
||||
for (auto& len : probe.insSizes) {
|
||||
|
||||
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline);
|
||||
if (code.contains("%rip")) {
|
||||
CVarList tokens{code, 0, 's'};
|
||||
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
||||
std::string addr = tokens[1].substr(plusPresent, tokens[1].find("(%rip)") - plusPresent);
|
||||
const uint64_t OFFSET = configStringToInt(addr);
|
||||
if (OFFSET == 0)
|
||||
return {};
|
||||
const uint64_t DESTINATION = currentAddress + OFFSET + len;
|
||||
|
||||
if (code.starts_with("mov")) {
|
||||
// mov +0xdeadbeef(%rip), %rax
|
||||
assemblyBuilder += std::format("movabs $0x{:x}, {}\n", DESTINATION, tokens[2]);
|
||||
} else if (code.starts_with("call")) {
|
||||
// call +0xdeadbeef(%rip)
|
||||
assemblyBuilder += std::format("pushq %rax\nmovabs $0x{:x}, %rax\ncallq *%rax\npopq %rax\n", DESTINATION);
|
||||
} else if (code.starts_with("lea")) {
|
||||
// lea 0xdeadbeef(%rip), %rax
|
||||
assemblyBuilder += std::format("movabs $0x{:x}, {}\n", DESTINATION, tokens[2]);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
} else if (code.contains("invalid")) {
|
||||
std::vector<uint8_t> bytes;
|
||||
bytes.resize(len);
|
||||
memcpy(bytes.data(), (std::byte*)currentAddress, len);
|
||||
if (len == 4 && bytes[0] == 0xF3 && bytes[1] == 0x0F && bytes[2] == 0x1E && bytes[3] == 0xFA) {
|
||||
// F3 0F 1E FA = endbr64, udis doesn't understand that one
|
||||
assemblyBuilder += "endbr64\n";
|
||||
} else {
|
||||
// raise error, unknown op
|
||||
std::string strBytes;
|
||||
for (auto& b : bytes) {
|
||||
strBytes += std::format("{:x} ", b);
|
||||
}
|
||||
Debug::log(ERR, "[functionhook] unknown bytes: {}", strBytes);
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
assemblyBuilder += code + "\n";
|
||||
}
|
||||
|
||||
lastAsmNewline = probe.assembly.find("\n", lastAsmNewline) + 1;
|
||||
currentAddress += len;
|
||||
}
|
||||
|
||||
std::ofstream ofs("/tmp/hypr/.hookcode.asm", std::ios::trunc);
|
||||
ofs << assemblyBuilder;
|
||||
ofs.close();
|
||||
std::string ret = execAndGet(
|
||||
"cc -x assembler -c /tmp/hypr/.hookcode.asm -o /tmp/hypr/.hookbinary.o 2>&1 && objcopy -O binary -j .text /tmp/hypr/.hookbinary.o /tmp/hypr/.hookbinary2.o 2>&1");
|
||||
Debug::log(LOG, "[functionhook] assembler returned:\n{}", ret);
|
||||
if (!std::filesystem::exists("/tmp/hypr/.hookbinary2.o")) {
|
||||
std::filesystem::remove("/tmp/hypr/.hookcode.asm");
|
||||
std::filesystem::remove("/tmp/hypr/.hookbinary.asm");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ifstream ifs("/tmp/hypr/.hookbinary2.o", std::ios::binary);
|
||||
SAssembly returns = {std::vector<char>(std::istreambuf_iterator<char>(ifs), {})};
|
||||
ifs.close();
|
||||
std::filesystem::remove("/tmp/hypr/.hookcode.asm");
|
||||
std::filesystem::remove("/tmp/hypr/.hookbinary.o");
|
||||
std::filesystem::remove("/tmp/hypr/.hookbinary2.o");
|
||||
|
||||
return returns;
|
||||
}
|
||||
|
||||
bool CFunctionHook::hook() {
|
||||
|
@ -85,68 +156,62 @@ bool CFunctionHook::hook() {
|
|||
static constexpr uint8_t POP_RAX[] = {0x58};
|
||||
// nop
|
||||
static constexpr uint8_t NOP = 0x90;
|
||||
/*
|
||||
movabs $0,%rax
|
||||
callq *%rax
|
||||
|
||||
offset for addr: 3
|
||||
*/
|
||||
static constexpr uint8_t CALL_WITH_RAX[] = {0x48, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x10};
|
||||
static constexpr size_t CALL_WITH_RAX_ADDRESS_OFFSET = 2;
|
||||
|
||||
// get minimum size to overwrite
|
||||
size_t HOOKSIZE = 0;
|
||||
// probe instructions to be trampolin'd
|
||||
SInstructionProbe probe;
|
||||
try {
|
||||
HOOKSIZE = probeMinimumJumpSize(m_pSource, sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(PUSH_RAX) + sizeof(POP_RAX));
|
||||
probe = probeMinimumJumpSize(m_pSource, sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(PUSH_RAX) + sizeof(POP_RAX));
|
||||
} catch (std::exception& e) { return false; }
|
||||
|
||||
const auto PROBEFIXEDASM = fixInstructionProbeRIPCalls(probe);
|
||||
|
||||
if (PROBEFIXEDASM.bytes.size() == 0) {
|
||||
Debug::log(ERR, "[functionhook] failed, unsupported asm / failed assembling:\n{}", probe.assembly);
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t HOOKSIZE = PROBEFIXEDASM.bytes.size();
|
||||
const size_t ORIGSIZE = probe.len;
|
||||
|
||||
// alloc trampoline
|
||||
const auto TRAMPOLINE_SIZE = sizeof(ABSOLUTE_JMP_ADDRESS) + HOOKSIZE + sizeof(PUSH_RAX) + m_vTrampolineRIPUses.size() * (sizeof(CALL_WITH_RAX) - 6);
|
||||
const auto TRAMPOLINE_SIZE = sizeof(ABSOLUTE_JMP_ADDRESS) + HOOKSIZE + sizeof(PUSH_RAX);
|
||||
m_pTrampolineAddr = mmap(NULL, TRAMPOLINE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
m_pOriginalBytes = malloc(HOOKSIZE);
|
||||
memcpy(m_pOriginalBytes, m_pSource, HOOKSIZE);
|
||||
m_pOriginalBytes = malloc(ORIGSIZE);
|
||||
memcpy(m_pOriginalBytes, m_pSource, ORIGSIZE);
|
||||
|
||||
// populate trampoline
|
||||
memcpy(m_pTrampolineAddr, m_pSource, HOOKSIZE); // first, original func bytes
|
||||
memcpy(m_pTrampolineAddr, PROBEFIXEDASM.bytes.data(), HOOKSIZE); // first, original but fixed func bytes
|
||||
memcpy((uint8_t*)m_pTrampolineAddr + HOOKSIZE, PUSH_RAX, sizeof(PUSH_RAX)); // then, pushq %rax
|
||||
memcpy((uint8_t*)m_pTrampolineAddr + HOOKSIZE + sizeof(PUSH_RAX), ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS)); // then, jump to source
|
||||
|
||||
// fix trampoline %rip calls
|
||||
for (size_t i = 0; i < m_vTrampolineRIPUses.size(); ++i) {
|
||||
size_t callOffset = i * (sizeof(CALL_WITH_RAX) - 6 /* callq [rip + x] */) + m_vTrampolineRIPUses[i].first;
|
||||
size_t realCallAddress = (uint64_t)m_pSource + callOffset + 6 + *((uint32_t*)((uint8_t*)m_pSource + callOffset + 2));
|
||||
|
||||
memmove((uint8_t*)m_pTrampolineAddr + callOffset + sizeof(CALL_WITH_RAX), (uint8_t*)m_pTrampolineAddr + callOffset + 6, TRAMPOLINE_SIZE - callOffset - 6);
|
||||
memcpy((uint8_t*)m_pTrampolineAddr + callOffset, CALL_WITH_RAX, sizeof(CALL_WITH_RAX));
|
||||
|
||||
*(uint64_t*)((uint8_t*)m_pTrampolineAddr + callOffset + CALL_WITH_RAX_ADDRESS_OFFSET) = (uint64_t)realCallAddress;
|
||||
}
|
||||
|
||||
// fixup trampoline addr
|
||||
*(uint64_t*)((uint8_t*)m_pTrampolineAddr + TRAMPOLINE_SIZE - sizeof(ABSOLUTE_JMP_ADDRESS) + ABSOLUTE_JMP_ADDRESS_OFFSET) =
|
||||
(uint64_t)((uint8_t*)m_pSource + sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
|
||||
// make jump to hk
|
||||
mprotect((uint8_t*)m_pSource - ((uint64_t)m_pSource) % sysconf(_SC_PAGE_SIZE), sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
memcpy(m_pSource, ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
const auto PAGESIZE = sysconf(_SC_PAGE_SIZE);
|
||||
const uint8_t* PROTSTART = (uint8_t*)m_pSource - ((uint64_t)m_pSource % PAGESIZE);
|
||||
const size_t PROTLEN = std::ceil((float)(ORIGSIZE + ((uint64_t)m_pSource - (uint64_t)PROTSTART)) / (float)PAGESIZE) * PAGESIZE;
|
||||
mprotect((uint8_t*)PROTSTART, PROTLEN, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
memcpy((uint8_t*)m_pSource, ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
|
||||
// make popq %rax and NOP all remaining
|
||||
memcpy((uint8_t*)m_pSource + sizeof(ABSOLUTE_JMP_ADDRESS), POP_RAX, sizeof(POP_RAX));
|
||||
size_t currentOp = sizeof(ABSOLUTE_JMP_ADDRESS) + sizeof(POP_RAX);
|
||||
memset((uint8_t*)m_pSource + currentOp, NOP, HOOKSIZE - currentOp);
|
||||
memset((uint8_t*)m_pSource + currentOp, NOP, ORIGSIZE - currentOp);
|
||||
|
||||
// fixup jump addr
|
||||
*(uint64_t*)((uint8_t*)m_pSource + ABSOLUTE_JMP_ADDRESS_OFFSET) = (uint64_t)(m_pDestination);
|
||||
|
||||
// revert mprot
|
||||
mprotect((uint8_t*)m_pSource - ((uint64_t)m_pSource) % sysconf(_SC_PAGE_SIZE), sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_EXEC);
|
||||
mprotect((uint8_t*)PROTSTART, PROTLEN, PROT_READ | PROT_EXEC);
|
||||
|
||||
// set original addr to trampo addr
|
||||
m_pOriginal = m_pTrampolineAddr;
|
||||
|
||||
m_bActive = true;
|
||||
m_iHookLen = HOOKSIZE;
|
||||
m_iHookLen = ORIGSIZE;
|
||||
m_iTrampoLen = TRAMPOLINE_SIZE;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -31,12 +31,22 @@ class CFunctionHook {
|
|||
HANDLE m_pOwner = nullptr;
|
||||
bool m_bActive = false;
|
||||
|
||||
std::vector<std::pair<size_t, std::string>> m_vTrampolineRIPUses;
|
||||
|
||||
void* m_pOriginalBytes = nullptr;
|
||||
|
||||
size_t probeMinimumJumpSize(void* start, size_t min);
|
||||
size_t getInstructionLenAt(void* start);
|
||||
struct SInstructionProbe {
|
||||
size_t len = 0;
|
||||
std::string assembly = "";
|
||||
std::vector<size_t> insSizes;
|
||||
};
|
||||
|
||||
struct SAssembly {
|
||||
std::vector<char> bytes;
|
||||
};
|
||||
|
||||
SInstructionProbe probeMinimumJumpSize(void* start, size_t min);
|
||||
SInstructionProbe getInstructionLenAt(void* start);
|
||||
|
||||
SAssembly fixInstructionProbeRIPCalls(const SInstructionProbe& probe);
|
||||
|
||||
friend class CHookSystem;
|
||||
};
|
||||
|
|
|
@ -53,7 +53,9 @@ void CFractionalScaleProtocolManager::bindManager(wl_client* client, void* data,
|
|||
static void handleDestroyScaleAddon(wl_client* client, wl_resource* resource);
|
||||
//
|
||||
|
||||
static const struct wp_fractional_scale_v1_interface fractionalScaleAddonImpl { .destroy = handleDestroyScaleAddon };
|
||||
static const struct wp_fractional_scale_v1_interface fractionalScaleAddonImpl {
|
||||
.destroy = handleDestroyScaleAddon
|
||||
};
|
||||
|
||||
//
|
||||
SFractionalScaleAddon* addonFromResource(wl_resource* resource) {
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
class CMonitor;
|
||||
|
||||
enum eClientOwners
|
||||
{
|
||||
enum eClientOwners {
|
||||
CLIENT_SCREENCOPY = 0,
|
||||
CLIENT_TOPLEVEL_EXPORT
|
||||
};
|
||||
|
|
|
@ -394,14 +394,20 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
|
|||
return false;
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.mainFB->bind();
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
g_pHyprOpenGL->m_RenderData.pMonitor = PMONITOR;
|
||||
outFB.bind();
|
||||
|
||||
#ifndef GLES2
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, outFB.m_iFb);
|
||||
#endif
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, data);
|
||||
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
wlr_buffer_end_data_ptr_access(frame->buffer);
|
||||
|
||||
if (frame->overlayCursor)
|
||||
|
|
|
@ -583,14 +583,14 @@ void CHyprOpenGLImpl::renderRect(CBox* box, const CColor& col, int round) {
|
|||
renderRectWithDamage(box, col, &m_RenderData.damage, round);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round, float blurA) {
|
||||
void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round, float blurA, bool xray) {
|
||||
if (m_RenderData.damage.empty())
|
||||
return;
|
||||
|
||||
CRegion damage{m_RenderData.damage};
|
||||
damage.intersect(*box);
|
||||
|
||||
CFramebuffer* POUTFB = blurMainFramebufferWithDamage(blurA, &damage);
|
||||
CFramebuffer* POUTFB = xray ? &m_RenderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(blurA, &damage);
|
||||
|
||||
m_RenderData.currentFB->bind();
|
||||
|
||||
|
@ -1233,6 +1233,9 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
|
|||
if (pWindow->m_sAdditionalConfigData.forceNoBlur)
|
||||
return false;
|
||||
|
||||
if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall)
|
||||
return true;
|
||||
|
||||
const auto PSURFACE = pWindow->m_pWLSurface.wlr();
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
|
@ -1894,12 +1897,16 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const
|
|||
void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
|
||||
RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!");
|
||||
|
||||
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 PFORCEHYPRCHAN = &g_pConfigManager->getConfigValuePtr("misc:force_hypr_chan")->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));
|
||||
|
||||
if (*PRENDERTEX)
|
||||
return;
|
||||
|
||||
// release the last tex if exists
|
||||
const auto PTEX = &m_mMonitorBGTextures[pMonitor];
|
||||
PTEX->destroyTexture();
|
||||
|
@ -2017,16 +2024,23 @@ void CHyprOpenGLImpl::clearWithTex() {
|
|||
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorFB.release();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].offloadFB.release();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorSwapFB.release();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].monitorMirrorFB.release();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].blurFB.release();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].offMainFB.release();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].stencilTex.destroyTexture();
|
||||
g_pHyprOpenGL->m_mMonitorBGTextures[pMonitor].destroyTexture();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources.erase(pMonitor);
|
||||
g_pHyprOpenGL->m_mMonitorBGTextures.erase(pMonitor);
|
||||
auto RESIT = g_pHyprOpenGL->m_mMonitorRenderResources.find(pMonitor);
|
||||
if (RESIT != g_pHyprOpenGL->m_mMonitorRenderResources.end()) {
|
||||
RESIT->second.mirrorFB.release();
|
||||
RESIT->second.offloadFB.release();
|
||||
RESIT->second.mirrorSwapFB.release();
|
||||
RESIT->second.monitorMirrorFB.release();
|
||||
RESIT->second.blurFB.release();
|
||||
RESIT->second.offMainFB.release();
|
||||
RESIT->second.stencilTex.destroyTexture();
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT);
|
||||
}
|
||||
|
||||
auto TEXIT = g_pHyprOpenGL->m_mMonitorBGTextures.find(pMonitor);
|
||||
if (TEXIT != g_pHyprOpenGL->m_mMonitorBGTextures.end()) {
|
||||
TEXIT->second.destroyTexture();
|
||||
g_pHyprOpenGL->m_mMonitorBGTextures.erase(TEXIT);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName);
|
||||
}
|
||||
|
|
|
@ -30,8 +30,7 @@ inline const float fullVerts[] = {
|
|||
};
|
||||
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
|
||||
|
||||
enum eDiscardMode
|
||||
{
|
||||
enum eDiscardMode {
|
||||
DISCARD_OPAQUE = 1,
|
||||
DISCARD_ALPHA = 1 << 1
|
||||
};
|
||||
|
@ -120,7 +119,7 @@ class CHyprOpenGLImpl {
|
|||
void end();
|
||||
|
||||
void renderRect(CBox*, const CColor&, int round = 0);
|
||||
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f);
|
||||
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false);
|
||||
void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
|
||||
void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false);
|
||||
void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
|
||||
|
@ -142,6 +141,7 @@ class CHyprOpenGLImpl {
|
|||
void makeLayerSnapshot(SLayerSurface*);
|
||||
void renderSnapshot(CWindow**);
|
||||
void renderSnapshot(SLayerSurface**);
|
||||
bool shouldUseNewBlurOptimizations(SLayerSurface* pLayer, CWindow* pWindow);
|
||||
|
||||
void clear(const CColor&);
|
||||
void clearWithTex();
|
||||
|
@ -223,8 +223,6 @@ class CHyprOpenGLImpl {
|
|||
|
||||
void preBlurForCurrentMonitor();
|
||||
|
||||
bool shouldUseNewBlurOptimizations(SLayerSurface* pLayer, CWindow* pWindow);
|
||||
|
||||
bool passRequiresIntrospection(CMonitor* pMonitor);
|
||||
|
||||
friend class CHyprRenderer;
|
||||
|
|
|
@ -9,9 +9,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
CHyprRenderer::CHyprRenderer() {
|
||||
const auto ENV = getenv("WLR_DRM_NO_ATOMIC");
|
||||
|
||||
if (ENV && std::string(ENV) == "1")
|
||||
if (envEnabled("WLR_DRM_NO_ATOMIC"))
|
||||
m_bTearingEnvSatisfied = true;
|
||||
|
||||
if (g_pCompositor->m_sWLRSession) {
|
||||
|
@ -51,9 +49,13 @@ CHyprRenderer::CHyprRenderer() {
|
|||
Debug::log(WARN, "NVIDIA detected, please remember to follow nvidia instructions on the wiki");
|
||||
}
|
||||
|
||||
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||
static auto* const PBLURPOPUPS = &g_pConfigManager->getConfigValuePtr("decoration:blur:popups")->intValue;
|
||||
static auto* const PBLURPOPUPSIGNOREALPHA = &g_pConfigManager->getConfigValuePtr("decoration:blur:popups_ignorealpha")->floatValue;
|
||||
|
||||
const auto TEXTURE = wlr_surface_get_texture(surface);
|
||||
const auto RDATA = (SRenderData*)data;
|
||||
const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE;
|
||||
|
||||
if (!TEXTURE)
|
||||
return;
|
||||
|
@ -73,7 +75,6 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|||
if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees m_pOwner */) {
|
||||
const auto CORRECT = PSURFACE->correctSmallVec();
|
||||
const auto SIZE = PSURFACE->getViewporterCorrectedSize();
|
||||
const auto INTERACTIVERESIZEINPROGRESS = g_pInputManager->currentlyDraggedWindow == PSURFACE->m_pOwner && g_pInputManager->dragMode == MBIND_RESIZE;
|
||||
|
||||
if (!INTERACTIVERESIZEINPROGRESS) {
|
||||
windowBox.x += CORRECT.x;
|
||||
|
@ -111,6 +112,15 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|||
windowBox.scale(RDATA->pMonitor->scale);
|
||||
windowBox.round();
|
||||
|
||||
// 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
|
||||
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 */ &&
|
||||
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */)
|
||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true;
|
||||
|
||||
float rounding = RDATA->rounding;
|
||||
|
||||
rounding -= 1; // to fix a border issue
|
||||
|
@ -136,6 +146,16 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
}
|
||||
} else {
|
||||
if (RDATA->blur && RDATA->popup && *PBLURPOPUPS) {
|
||||
|
||||
if (*PBLURPOPUPSIGNOREALPHA != 1.f) {
|
||||
g_pHyprOpenGL->m_RenderData.discardMode |= DISCARD_ALPHA;
|
||||
g_pHyprOpenGL->m_RenderData.discardOpacity = *PBLURPOPUPSIGNOREALPHA;
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, true);
|
||||
g_pHyprOpenGL->m_RenderData.discardMode &= ~DISCARD_ALPHA;
|
||||
} else
|
||||
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
|
||||
}
|
||||
|
||||
|
@ -146,9 +166,10 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
|||
|
||||
g_pHyprOpenGL->blend(true);
|
||||
|
||||
// reset the UV, we might've set it above
|
||||
// reset props
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = NEARESTNEIGHBORSET;
|
||||
}
|
||||
|
||||
bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor, CWorkspace* pWorkspace) {
|
||||
|
@ -168,7 +189,8 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor, CWo
|
|||
if (PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) {
|
||||
return true;
|
||||
} else {
|
||||
if (!(!PWINDOWWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen)))
|
||||
if (PWINDOWWORKSPACE->m_bHasFullscreenWindow && !pWindow->m_bIsFullscreen && !pWindow->m_bIsFloating && !pWindow->m_bCreatedOverFullscreen &&
|
||||
pWindow->m_fAlpha.fl() == 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -220,7 +242,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
|
|||
|
||||
// loop over the tiled windows that are fading out
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID != pMonitor->activeWorkspace)
|
||||
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
|
||||
continue;
|
||||
|
||||
if (w->m_fAlpha.fl() == 0.f)
|
||||
|
@ -237,7 +259,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
|
|||
|
||||
// and floating ones too
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID != pMonitor->activeWorkspace)
|
||||
if (!shouldRenderWindow(w.get(), pMonitor, pWorkspace))
|
||||
continue;
|
||||
|
||||
if (w->m_fAlpha.fl() == 0.f)
|
||||
|
@ -383,7 +405,6 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
const auto REALPOS = pWindow->m_vRealPosition.vec() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.vec());
|
||||
static auto* const PDIMAROUND = &g_pConfigManager->getConfigValuePtr("decoration:dim_around")->floatValue;
|
||||
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue;
|
||||
|
||||
SRenderData renderdata = {pMonitor, time};
|
||||
|
@ -461,7 +482,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
}
|
||||
|
||||
// if window is floating and we have a slide animation, clip it to its full bb
|
||||
if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bIsFullscreen && PWORKSPACE->m_vRenderOffset.isBeingAnimated()) {
|
||||
if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bIsFullscreen && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) {
|
||||
CRegion rg = pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.vec()).scale(pMonitor->scale);
|
||||
g_pHyprOpenGL->m_RenderData.clipBox = rg.getExtents();
|
||||
}
|
||||
|
@ -479,7 +500,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
}
|
||||
}
|
||||
|
||||
if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) {
|
||||
if (decorate) {
|
||||
for (auto& wd : pWindow->m_dWindowDecorations) {
|
||||
if (wd->getDecorationLayer() != DECORATION_LAYER_BOTTOM)
|
||||
continue;
|
||||
|
@ -502,7 +523,8 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall && renderdata.blur && *PBLUR) {
|
||||
CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
|
||||
wb.scale(pMonitor->scale).round();
|
||||
g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha);
|
||||
g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha,
|
||||
g_pHyprOpenGL->shouldUseNewBlurOptimizations(nullptr, pWindow));
|
||||
renderdata.blur = false;
|
||||
}
|
||||
|
||||
|
@ -510,38 +532,14 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
|
||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
|
||||
|
||||
if (renderdata.decorate && pWindow->m_sSpecialRenderData.border) {
|
||||
auto grad = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor;
|
||||
const bool ANIMATED = g_pHyprOpenGL->m_pCurrentWindow->m_fBorderFadeAnimationProgress.isBeingAnimated();
|
||||
float a1 = renderdata.fadeAlpha * renderdata.alpha * (ANIMATED ? g_pHyprOpenGL->m_pCurrentWindow->m_fBorderFadeAnimationProgress.fl() : 1.f);
|
||||
|
||||
if (g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) {
|
||||
grad.m_fAngle += g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAngleAnimationProgress.fl() * M_PI * 2;
|
||||
grad.m_fAngle = normalizeAngleRad(grad.m_fAngle);
|
||||
}
|
||||
|
||||
CBox windowBox = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
|
||||
|
||||
windowBox.scale(pMonitor->scale).round();
|
||||
|
||||
int borderSize = pWindow->m_sSpecialRenderData.borderSize.toUnderlying() == -1 ? *PBORDERSIZE : pWindow->m_sSpecialRenderData.borderSize.toUnderlying();
|
||||
if (pWindow->m_sAdditionalConfigData.borderSize.toUnderlying() != -1)
|
||||
borderSize = pWindow->m_sAdditionalConfigData.borderSize.toUnderlying();
|
||||
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, grad, renderdata.rounding, borderSize, a1);
|
||||
|
||||
if (ANIMATED) {
|
||||
float a2 = renderdata.fadeAlpha * renderdata.alpha * (1.f - g_pHyprOpenGL->m_pCurrentWindow->m_fBorderFadeAnimationProgress.fl());
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColorPrevious, renderdata.rounding, borderSize, a2);
|
||||
}
|
||||
}
|
||||
|
||||
if (decorate) {
|
||||
for (auto& wd : pWindow->m_dWindowDecorations) {
|
||||
if (wd->getDecorationLayer() != DECORATION_LAYER_OVER)
|
||||
continue;
|
||||
|
||||
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha, Vector2D{renderdata.x, renderdata.y} - PREOFFSETPOS);
|
||||
}
|
||||
}
|
||||
|
||||
if (TRANSFORMERSPRESENT) {
|
||||
|
||||
|
@ -569,6 +567,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
renderdata.dontRound = true; // don't round popups
|
||||
renderdata.pMonitor = pMonitor;
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
renderdata.popup = true;
|
||||
|
||||
if (pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying())
|
||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true;
|
||||
|
@ -578,6 +577,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false;
|
||||
}
|
||||
|
||||
if (decorate) {
|
||||
for (auto& wd : pWindow->m_dWindowDecorations) {
|
||||
if (wd->getDecorationLayer() != DECORATION_LAYER_OVERLAY)
|
||||
continue;
|
||||
|
@ -585,6 +585,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
|||
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha, Vector2D{renderdata.x, renderdata.y} - PREOFFSETPOS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EMIT_HOOK_EVENT("render", RENDER_POST_WINDOW);
|
||||
|
||||
|
@ -620,6 +621,7 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
|
|||
|
||||
renderdata.squishOversized = false; // don't squish popups
|
||||
renderdata.dontRound = true;
|
||||
renderdata.popup = true;
|
||||
wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata);
|
||||
|
||||
g_pHyprOpenGL->m_pCurrentLayer = nullptr;
|
||||
|
@ -708,11 +710,15 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace*
|
|||
// pre window pass
|
||||
g_pHyprOpenGL->preWindowPass();
|
||||
|
||||
setOccludedForMainWorkspace(g_pHyprOpenGL->m_RenderData.damage, pWorkspace);
|
||||
|
||||
if (pWorkspace->m_bHasFullscreenWindow)
|
||||
renderWorkspaceWindowsFullscreen(pMonitor, pWorkspace, time);
|
||||
else
|
||||
renderWorkspaceWindows(pMonitor, pWorkspace, time);
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.damage = preOccludedDamage;
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.renderModif = {};
|
||||
|
||||
// and then special
|
||||
|
@ -1369,7 +1375,7 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
|
|||
|
||||
// taken from Sway.
|
||||
// this is just too much of a spaghetti for me to understand
|
||||
void apply_exclusive(struct wlr_box* usable_area, uint32_t anchor, int32_t exclusive, int32_t margin_top, int32_t margin_right, int32_t margin_bottom, int32_t margin_left) {
|
||||
static void applyExclusive(wlr_box& usableArea, uint32_t anchor, int32_t exclusive, int32_t marginTop, int32_t marginRight, int32_t marginBottom, int32_t marginLeft) {
|
||||
if (exclusive <= 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -1384,33 +1390,33 @@ void apply_exclusive(struct wlr_box* usable_area, uint32_t anchor, int32_t exclu
|
|||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP,
|
||||
.positive_axis = &usable_area->y,
|
||||
.negative_axis = &usable_area->height,
|
||||
.margin = margin_top,
|
||||
.positive_axis = &usableArea.y,
|
||||
.negative_axis = &usableArea.height,
|
||||
.margin = marginTop,
|
||||
},
|
||||
// Bottom
|
||||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.positive_axis = NULL,
|
||||
.negative_axis = &usable_area->height,
|
||||
.margin = margin_bottom,
|
||||
.negative_axis = &usableArea.height,
|
||||
.margin = marginBottom,
|
||||
},
|
||||
// Left
|
||||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.positive_axis = &usable_area->x,
|
||||
.negative_axis = &usable_area->width,
|
||||
.margin = margin_left,
|
||||
.positive_axis = &usableArea.x,
|
||||
.negative_axis = &usableArea.width,
|
||||
.margin = marginLeft,
|
||||
},
|
||||
// Right
|
||||
{
|
||||
.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT,
|
||||
.anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM,
|
||||
.positive_axis = NULL,
|
||||
.negative_axis = &usable_area->width,
|
||||
.margin = margin_right,
|
||||
.negative_axis = &usableArea.width,
|
||||
.margin = marginRight,
|
||||
},
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
|
||||
|
@ -1501,7 +1507,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector<std:
|
|||
// Apply
|
||||
ls->geometry = box;
|
||||
|
||||
apply_exclusive(usableArea->pWlr(), PSTATE->anchor, PSTATE->exclusive_zone, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left);
|
||||
applyExclusive(*usableArea->pWlr(), PSTATE->anchor, PSTATE->exclusive_zone, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left);
|
||||
|
||||
usableArea->applyFromWlr();
|
||||
|
||||
|
@ -1702,6 +1708,8 @@ DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string&
|
|||
|
||||
bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) {
|
||||
|
||||
static auto* const PDISABLESCALECHECKS = &g_pConfigManager->getConfigValuePtr("debug:disable_scale_checks")->intValue;
|
||||
|
||||
Debug::log(LOG, "Applying monitor rule for {}", pMonitor->szName);
|
||||
|
||||
pMonitor->activeMonitorRule = *pMonitorRule;
|
||||
|
@ -1727,7 +1735,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
|||
// Check if the rule isn't already applied
|
||||
// TODO: clean this up lol
|
||||
if (!force && DELTALESSTHAN(pMonitor->vecPixelSize.x, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecPixelSize.y, pMonitorRule->resolution.y, 1) &&
|
||||
DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->scale == pMonitorRule->scale &&
|
||||
DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->setScale == pMonitorRule->scale &&
|
||||
((DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1)) ||
|
||||
pMonitorRule->offset == Vector2D(-INT32_MAX, -INT32_MAX)) &&
|
||||
pMonitor->transform == pMonitorRule->transform && pMonitorRule->enable10bit == pMonitor->enabled10bit &&
|
||||
|
@ -1739,16 +1747,19 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
|||
|
||||
// Needed in case we are switching from a custom modeline to a standard mode
|
||||
pMonitor->customDrmMode = {};
|
||||
bool autoScale = false;
|
||||
|
||||
if (pMonitorRule->scale > 0.1) {
|
||||
wlr_output_set_scale(pMonitor->output, pMonitorRule->scale);
|
||||
pMonitor->scale = pMonitorRule->scale;
|
||||
} else {
|
||||
autoScale = true;
|
||||
const auto DEFAULTSCALE = pMonitor->getDefaultScale();
|
||||
wlr_output_set_scale(pMonitor->output, DEFAULTSCALE);
|
||||
pMonitor->scale = DEFAULTSCALE;
|
||||
}
|
||||
|
||||
wlr_output_set_scale(pMonitor->output, pMonitor->scale);
|
||||
pMonitor->setScale = pMonitor->scale;
|
||||
|
||||
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
|
||||
pMonitor->transform = pMonitorRule->transform;
|
||||
|
||||
|
@ -1965,6 +1976,61 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
|||
|
||||
pMonitor->vecPixelSize = pMonitor->vecSize;
|
||||
|
||||
Vector2D logicalSize = pMonitor->vecPixelSize / pMonitor->scale;
|
||||
if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) {
|
||||
// invalid scale, will produce fractional pixels.
|
||||
// find the nearest valid.
|
||||
|
||||
float searchScale = std::round(pMonitor->scale * 120.0);
|
||||
bool found = false;
|
||||
|
||||
double scaleZero = searchScale / 120.0;
|
||||
|
||||
Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero;
|
||||
if (logicalZero == logicalZero.round()) {
|
||||
pMonitor->scale = scaleZero;
|
||||
} else {
|
||||
for (size_t i = 1; i < 90; ++i) {
|
||||
double scaleUp = (searchScale + i) / 120.0;
|
||||
double scaleDown = (searchScale - i) / 120.0;
|
||||
|
||||
Vector2D logicalUp = pMonitor->vecPixelSize / scaleUp;
|
||||
Vector2D logicalDown = pMonitor->vecPixelSize / scaleDown;
|
||||
|
||||
if (logicalUp == logicalUp.round()) {
|
||||
found = true;
|
||||
searchScale = scaleUp;
|
||||
break;
|
||||
}
|
||||
if (logicalDown == logicalDown.round()) {
|
||||
found = true;
|
||||
searchScale = scaleDown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (autoScale)
|
||||
pMonitor->scale = std::round(scaleZero);
|
||||
else {
|
||||
Debug::log(ERR, "Invalid scale passed to monitor, {} failed to find a clean divisor", pMonitor->scale);
|
||||
g_pConfigManager->addParseError("Invalid scale passed to monitor " + pMonitor->szName + ", failed to find a clean divisor");
|
||||
pMonitor->scale = pMonitor->getDefaultScale();
|
||||
}
|
||||
} else {
|
||||
if (!autoScale) {
|
||||
Debug::log(ERR, "Invalid scale passed to monitor, {} found suggestion {}", pMonitor->scale, searchScale);
|
||||
g_pConfigManager->addParseError(
|
||||
std::format("Invalid scale passed to monitor {}, failed to find a clean divisor. Suggested nearest scale: {:5f}", pMonitor->szName, searchScale));
|
||||
pMonitor->scale = pMonitor->getDefaultScale();
|
||||
} else
|
||||
pMonitor->scale = searchScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_output_set_scale(pMonitor->output, pMonitor->scale);
|
||||
|
||||
// clang-format off
|
||||
static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
|
||||
std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */
|
||||
|
@ -2041,21 +2107,24 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
|||
return true;
|
||||
}
|
||||
|
||||
void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY) {
|
||||
void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force) {
|
||||
m_bCursorHasSurface = surf;
|
||||
|
||||
if (surf == m_sLastCursorData.surf)
|
||||
if ((surf == m_sLastCursorData.surf || m_bCursorHidden) && !force)
|
||||
return;
|
||||
|
||||
m_sLastCursorData.name = "";
|
||||
m_sLastCursorData.surf = surf;
|
||||
m_sLastCursorData.hotspotX = hotspotX;
|
||||
m_sLastCursorData.hotspotY = hotspotY;
|
||||
|
||||
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspotX, hotspotY);
|
||||
}
|
||||
void CHyprRenderer::setCursorFromName(const std::string& name) {
|
||||
|
||||
void CHyprRenderer::setCursorFromName(const std::string& name, bool force) {
|
||||
m_bCursorHasSurface = true;
|
||||
|
||||
if (name == m_sLastCursorData.name)
|
||||
if ((name == m_sLastCursorData.name || m_bCursorHidden) && !force)
|
||||
return;
|
||||
|
||||
m_sLastCursorData.name = name;
|
||||
|
@ -2073,33 +2142,49 @@ void CHyprRenderer::ensureCursorRenderingMode() {
|
|||
if (*PCURSORTIMEOUT > 0 || *PHIDEONTOUCH) {
|
||||
const bool HIDE = (*PCURSORTIMEOUT > 0 && *PCURSORTIMEOUT < PASSEDCURSORSECONDS) || (g_pInputManager->m_bLastInputTouch && *PHIDEONTOUCH);
|
||||
|
||||
if (HIDE && m_bHasARenderedCursor) {
|
||||
m_bHasARenderedCursor = false;
|
||||
|
||||
setCursorSurface(nullptr, 0, 0); // hide
|
||||
|
||||
if (HIDE && !m_bCursorHidden) {
|
||||
Debug::log(LOG, "Hiding the cursor (timeout)");
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area?
|
||||
} else if (!HIDE && !m_bHasARenderedCursor) {
|
||||
m_bHasARenderedCursor = true;
|
||||
|
||||
if (!m_bWindowRequestedCursorHide)
|
||||
setCursorFromName("left_ptr");
|
||||
setCursorHidden(true);
|
||||
|
||||
} else if (!HIDE && m_bCursorHidden) {
|
||||
Debug::log(LOG, "Showing the cursor (timeout)");
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors)
|
||||
g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area?
|
||||
|
||||
setCursorHidden(false);
|
||||
}
|
||||
} else {
|
||||
m_bHasARenderedCursor = true;
|
||||
setCursorHidden(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprRenderer::setCursorHidden(bool hide) {
|
||||
|
||||
if (hide == m_bCursorHidden)
|
||||
return;
|
||||
|
||||
m_bCursorHidden = hide;
|
||||
|
||||
if (hide) {
|
||||
wlr_cursor_unset_image(g_pCompositor->m_sWLRCursor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sLastCursorData.surf.has_value())
|
||||
setCursorSurface(m_sLastCursorData.surf.value(), m_sLastCursorData.hotspotX, m_sLastCursorData.hotspotY, true);
|
||||
else if (!m_sLastCursorData.name.empty())
|
||||
setCursorFromName(m_sLastCursorData.name, true);
|
||||
else
|
||||
setCursorFromName("left_ptr", true);
|
||||
}
|
||||
|
||||
bool CHyprRenderer::shouldRenderCursor() {
|
||||
return m_bHasARenderedCursor && m_bCursorHasSurface;
|
||||
return !m_bCursorHidden && m_bCursorHasSurface;
|
||||
}
|
||||
|
||||
std::tuple<float, float, float> CHyprRenderer::getRenderTimes(CMonitor* pMonitor) {
|
||||
|
@ -2149,6 +2234,35 @@ void CHyprRenderer::initiateManualCrash() {
|
|||
g_pConfigManager->setInt("debug:damage_tracking", 0);
|
||||
}
|
||||
|
||||
void CHyprRenderer::setOccludedForMainWorkspace(CRegion& region, CWorkspace* pWorkspace) {
|
||||
CRegion rg;
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
|
||||
|
||||
if (!PMONITOR->specialWorkspaceID)
|
||||
return;
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->isHidden() || w->m_iWorkspaceID != PMONITOR->specialWorkspaceID)
|
||||
continue;
|
||||
|
||||
if (!w->opaque())
|
||||
continue;
|
||||
|
||||
const auto ROUNDING = w->rounding() * PMONITOR->scale;
|
||||
const Vector2D POS = w->m_vRealPosition.vec() + Vector2D{ROUNDING, ROUNDING} - PMONITOR->vecPosition + (w->m_bPinned ? Vector2D{} : pWorkspace->m_vRenderOffset.vec());
|
||||
const Vector2D SIZE = w->m_vRealSize.vec() - Vector2D{ROUNDING * 2, ROUNDING * 2};
|
||||
|
||||
CBox box = {POS.x, POS.y, SIZE.x, SIZE.y};
|
||||
|
||||
box.scale(PMONITOR->scale);
|
||||
|
||||
rg.add(box);
|
||||
}
|
||||
|
||||
region.subtract(rg);
|
||||
}
|
||||
|
||||
void CHyprRenderer::setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace) {
|
||||
CRegion rg;
|
||||
|
||||
|
@ -2333,6 +2447,7 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
|
|||
|
||||
void CHyprRenderer::endRender() {
|
||||
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
|
||||
static auto* const PNVIDIAANTIFLICKER = &g_pConfigManager->getConfigValuePtr("opengl:nvidia_anti_flicker")->intValue;
|
||||
|
||||
if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY)
|
||||
g_pHyprOpenGL->end();
|
||||
|
@ -2345,7 +2460,7 @@ void CHyprRenderer::endRender() {
|
|||
if (m_eRenderMode == RENDER_MODE_FULL_FAKE)
|
||||
return;
|
||||
|
||||
if (isNvidia())
|
||||
if (isNvidia() && *PNVIDIAANTIFLICKER)
|
||||
glFinish();
|
||||
else
|
||||
glFlush();
|
||||
|
|
|
@ -13,23 +13,20 @@
|
|||
struct SMonitorRule;
|
||||
|
||||
// TODO: add fuller damage tracking for updating only parts of a window
|
||||
enum DAMAGETRACKINGMODES
|
||||
{
|
||||
enum DAMAGETRACKINGMODES {
|
||||
DAMAGE_TRACKING_INVALID = -1,
|
||||
DAMAGE_TRACKING_NONE = 0,
|
||||
DAMAGE_TRACKING_MONITOR,
|
||||
DAMAGE_TRACKING_FULL
|
||||
};
|
||||
|
||||
enum eRenderPassMode
|
||||
{
|
||||
enum eRenderPassMode {
|
||||
RENDER_PASS_ALL = 0,
|
||||
RENDER_PASS_MAIN,
|
||||
RENDER_PASS_POPUP
|
||||
};
|
||||
|
||||
enum eRenderMode
|
||||
{
|
||||
enum eRenderMode {
|
||||
RENDER_MODE_NORMAL = 0,
|
||||
RENDER_MODE_FULL_FAKE = 1,
|
||||
RENDER_MODE_TO_BUFFER = 2,
|
||||
|
@ -59,14 +56,16 @@ class CHyprRenderer {
|
|||
bool shouldRenderWindow(CWindow*);
|
||||
void ensureCursorRenderingMode();
|
||||
bool shouldRenderCursor();
|
||||
void setCursorHidden(bool hide);
|
||||
void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false);
|
||||
std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
|
||||
void renderLockscreen(CMonitor* pMonitor, timespec* now);
|
||||
void setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace);
|
||||
void setOccludedForMainWorkspace(CRegion& region, CWorkspace* pWorkspace); // TODO: merge occlusion methods
|
||||
bool canSkipBackBufferClear(CMonitor* pMonitor);
|
||||
void recheckSolitaryForMonitor(CMonitor* pMonitor);
|
||||
void setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY);
|
||||
void setCursorFromName(const std::string& name);
|
||||
void setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force = false);
|
||||
void setCursorFromName(const std::string& name, bool force = false);
|
||||
void renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional<Vector2D> overridePos = {});
|
||||
void onRenderbufferDestroy(CRenderbuffer* rb);
|
||||
CRenderbuffer* getCurrentRBO();
|
||||
|
@ -77,7 +76,6 @@ class CHyprRenderer {
|
|||
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr);
|
||||
void endRender();
|
||||
|
||||
bool m_bWindowRequestedCursorHide = false;
|
||||
bool m_bBlockSurfaceFeedback = false;
|
||||
bool m_bRenderingSnapshot = false;
|
||||
CWindow* m_pLastScanout = nullptr;
|
||||
|
@ -102,6 +100,8 @@ class CHyprRenderer {
|
|||
CTimer m_tRenderTimer;
|
||||
|
||||
struct {
|
||||
int hotspotX;
|
||||
int hotspotY;
|
||||
std::optional<wlr_surface*> surf = nullptr;
|
||||
std::string name;
|
||||
} m_sLastCursorData;
|
||||
|
@ -118,7 +118,7 @@ class CHyprRenderer {
|
|||
void renderWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const CBox& geometry);
|
||||
void renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
|
||||
|
||||
bool m_bHasARenderedCursor = true;
|
||||
bool m_bCursorHidden = false;
|
||||
bool m_bCursorHasSurface = false;
|
||||
CRenderbuffer* m_pCurrentRenderbuffer = nullptr;
|
||||
wlr_buffer* m_pCurrentWlrBuffer = nullptr;
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
#include "../defines.hpp"
|
||||
|
||||
enum TEXTURETYPE
|
||||
{
|
||||
enum TEXTURETYPE {
|
||||
TEXTURE_INVALID, // Invalid
|
||||
TEXTURE_RGBA, // 4 channels
|
||||
TEXTURE_RGBX, // discard A
|
||||
|
|
108
src/render/decorations/CHyprBorderDecoration.cpp
Normal file
108
src/render/decorations/CHyprBorderDecoration.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "CHyprBorderDecoration.hpp"
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
CHyprBorderDecoration::CHyprBorderDecoration(CWindow* pWindow) : IHyprWindowDecoration(pWindow) {
|
||||
m_pWindow = pWindow;
|
||||
}
|
||||
|
||||
CHyprBorderDecoration::~CHyprBorderDecoration() {
|
||||
;
|
||||
}
|
||||
|
||||
SDecorationPositioningInfo CHyprBorderDecoration::getPositioningInfo() {
|
||||
const auto BORDERSIZE = m_pWindow->getRealBorderSize();
|
||||
m_seExtents = {{BORDERSIZE, BORDERSIZE}, {BORDERSIZE, BORDERSIZE}};
|
||||
|
||||
if (doesntWantBorders())
|
||||
m_seExtents = {{}, {}};
|
||||
|
||||
SDecorationPositioningInfo info;
|
||||
info.priority = 10000;
|
||||
info.policy = DECORATION_POSITION_STICKY;
|
||||
info.desiredExtents = m_seExtents;
|
||||
info.reserved = true;
|
||||
info.edges = DECORATION_EDGE_BOTTOM | DECORATION_EDGE_LEFT | DECORATION_EDGE_RIGHT | DECORATION_EDGE_TOP;
|
||||
|
||||
m_seReportedExtents = m_seExtents;
|
||||
return info;
|
||||
}
|
||||
|
||||
void CHyprBorderDecoration::onPositioningReply(const SDecorationPositioningReply& reply) {
|
||||
m_bAssignedGeometry = reply.assignedGeometry;
|
||||
}
|
||||
|
||||
CBox CHyprBorderDecoration::assignedBoxGlobal() {
|
||||
CBox box = m_bAssignedGeometry;
|
||||
box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_BOTTOM | DECORATION_EDGE_LEFT | DECORATION_EDGE_RIGHT | DECORATION_EDGE_TOP, m_pWindow));
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID);
|
||||
|
||||
if (!PWORKSPACE)
|
||||
return box;
|
||||
|
||||
const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
||||
return box.translate(WORKSPACEOFFSET);
|
||||
}
|
||||
|
||||
void CHyprBorderDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
||||
if (doesntWantBorders())
|
||||
return;
|
||||
|
||||
if (m_bAssignedGeometry.width < m_seExtents.topLeft.x + 1 || m_bAssignedGeometry.height < m_seExtents.topLeft.y + 1)
|
||||
return;
|
||||
|
||||
CBox windowBox = assignedBoxGlobal().translate(-pMonitor->vecPosition + offset).expand(-m_pWindow->getRealBorderSize()).scale(pMonitor->scale).round();
|
||||
|
||||
if (windowBox.width < 1 || windowBox.height < 1)
|
||||
return;
|
||||
|
||||
auto grad = m_pWindow->m_cRealBorderColor;
|
||||
const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress.isBeingAnimated();
|
||||
float a1 = a * (ANIMATED ? m_pWindow->m_fBorderFadeAnimationProgress.fl() : 1.f);
|
||||
|
||||
if (m_pWindow->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) {
|
||||
grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress.fl() * M_PI * 2;
|
||||
grad.m_fAngle = normalizeAngleRad(grad.m_fAngle);
|
||||
}
|
||||
|
||||
int borderSize = m_pWindow->getRealBorderSize();
|
||||
const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale;
|
||||
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, grad, ROUNDING, borderSize, a1);
|
||||
|
||||
if (ANIMATED) {
|
||||
float a2 = a * (1.f - m_pWindow->m_fBorderFadeAnimationProgress.fl());
|
||||
g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, ROUNDING, borderSize, a2);
|
||||
}
|
||||
}
|
||||
|
||||
eDecorationType CHyprBorderDecoration::getDecorationType() {
|
||||
return DECORATION_BORDER;
|
||||
}
|
||||
|
||||
void CHyprBorderDecoration::updateWindow(CWindow*) {
|
||||
if (m_pWindow->getRealBorderSize() != m_seExtents.topLeft.x)
|
||||
g_pDecorationPositioner->repositionDeco(this);
|
||||
}
|
||||
|
||||
void CHyprBorderDecoration::damageEntire() {
|
||||
; // ignored, done in animationManager. todo, move.
|
||||
}
|
||||
|
||||
eDecorationLayer CHyprBorderDecoration::getDecorationLayer() {
|
||||
return DECORATION_LAYER_OVER;
|
||||
}
|
||||
|
||||
uint64_t CHyprBorderDecoration::getDecorationFlags() {
|
||||
static auto* const PPARTOFWINDOW = &g_pConfigManager->getConfigValuePtr("general:border_part_of_window")->intValue;
|
||||
|
||||
return *PPARTOFWINDOW && !doesntWantBorders() ? DECORATION_PART_OF_MAIN_WINDOW : 0;
|
||||
}
|
||||
|
||||
std::string CHyprBorderDecoration::getDisplayName() {
|
||||
return "Border";
|
||||
}
|
||||
|
||||
bool CHyprBorderDecoration::doesntWantBorders() {
|
||||
return !m_pWindow->m_sSpecialRenderData.border || m_pWindow->m_bX11DoesntWantBorders;
|
||||
}
|
41
src/render/decorations/CHyprBorderDecoration.hpp
Normal file
41
src/render/decorations/CHyprBorderDecoration.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "IHyprWindowDecoration.hpp"
|
||||
|
||||
class CHyprBorderDecoration : public IHyprWindowDecoration {
|
||||
public:
|
||||
CHyprBorderDecoration(CWindow*);
|
||||
virtual ~CHyprBorderDecoration();
|
||||
|
||||
virtual SDecorationPositioningInfo getPositioningInfo();
|
||||
|
||||
virtual void onPositioningReply(const SDecorationPositioningReply& reply);
|
||||
|
||||
virtual void draw(CMonitor*, float a, const Vector2D& offset);
|
||||
|
||||
virtual eDecorationType getDecorationType();
|
||||
|
||||
virtual void updateWindow(CWindow*);
|
||||
|
||||
virtual void damageEntire();
|
||||
|
||||
virtual eDecorationLayer getDecorationLayer();
|
||||
|
||||
virtual uint64_t getDecorationFlags();
|
||||
|
||||
virtual std::string getDisplayName();
|
||||
|
||||
private:
|
||||
SWindowDecorationExtents m_seExtents;
|
||||
SWindowDecorationExtents m_seReportedExtents;
|
||||
|
||||
CWindow* m_pWindow = nullptr;
|
||||
|
||||
Vector2D m_vLastWindowPos;
|
||||
Vector2D m_vLastWindowSize;
|
||||
|
||||
CBox m_bAssignedGeometry = {0};
|
||||
|
||||
CBox assignedBoxGlobal();
|
||||
bool doesntWantBorders();
|
||||
};
|
|
@ -30,6 +30,10 @@ uint64_t CHyprDropShadowDecoration::getDecorationFlags() {
|
|||
return DECORATION_NON_SOLID;
|
||||
}
|
||||
|
||||
std::string CHyprDropShadowDecoration::getDisplayName() {
|
||||
return "Drop Shadow";
|
||||
}
|
||||
|
||||
void CHyprDropShadowDecoration::damageEntire() {
|
||||
static auto* const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
|
||||
|
||||
|
@ -75,7 +79,8 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
|
|||
if (*PSHADOWS != 1)
|
||||
return; // disabled
|
||||
|
||||
const auto ROUNDING = m_pWindow->rounding() + m_pWindow->getRealBorderSize();
|
||||
const auto ROUNDINGBASE = m_pWindow->rounding();
|
||||
const auto ROUNDING = ROUNDINGBASE > 0 ? ROUNDINGBASE + m_pWindow->getRealBorderSize() : 0;
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID);
|
||||
const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
|
||||
|
||||
|
@ -116,13 +121,15 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
|
|||
CBox withDecos = m_bLastWindowBoxWithDecos;
|
||||
|
||||
// get window box
|
||||
windowBox.translate(-pMonitor->vecPosition + WORKSPACEOFFSET).scale(pMonitor->scale).round();
|
||||
withDecos.translate(-pMonitor->vecPosition + WORKSPACEOFFSET).scale(pMonitor->scale).round();
|
||||
windowBox.translate(-pMonitor->vecPosition + WORKSPACEOFFSET);
|
||||
withDecos.translate(-pMonitor->vecPosition + WORKSPACEOFFSET);
|
||||
|
||||
auto scaledDecoExtents = withDecos.extentsFrom(windowBox).round();
|
||||
auto scaledExtentss = withDecos.extentsFrom(windowBox);
|
||||
scaledExtentss = scaledExtentss * pMonitor->scale;
|
||||
scaledExtentss = scaledExtentss.round();
|
||||
|
||||
// add extents
|
||||
windowBox.addExtents(scaledDecoExtents).round();
|
||||
windowBox.scale(pMonitor->scale).round().addExtents(scaledExtentss);
|
||||
|
||||
if (windowBox.width < 1 || windowBox.height < 1)
|
||||
return; // prevent assert failed
|
||||
|
@ -159,7 +166,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D
|
|||
|
||||
g_pHyprOpenGL->m_RenderData.damage = saveDamage;
|
||||
} else {
|
||||
g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, a);
|
||||
g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, m_pWindow->m_cRealShadowColor.col(), a);
|
||||
}
|
||||
|
||||
if (m_seExtents != m_seReportedExtents)
|
||||
|
|
|
@ -23,6 +23,8 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration {
|
|||
|
||||
virtual uint64_t getDecorationFlags();
|
||||
|
||||
virtual std::string getDisplayName();
|
||||
|
||||
private:
|
||||
SWindowDecorationExtents m_seExtents;
|
||||
SWindowDecorationExtents m_seReportedExtents;
|
||||
|
|
|
@ -15,24 +15,32 @@ constexpr int BAR_TEXT_PAD = 2;
|
|||
constexpr int BAR_HORIZONTAL_PADDING = 2;
|
||||
|
||||
CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindowDecoration(pWindow) {
|
||||
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
||||
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
||||
m_pWindow = pWindow;
|
||||
if (m_tGradientActive.m_iTexID == 0)
|
||||
|
||||
if (m_tGradientActive.m_iTexID == 0 && *PENABLED && *PGRADIENTS)
|
||||
refreshGroupBarGradients();
|
||||
}
|
||||
|
||||
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {}
|
||||
|
||||
SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
|
||||
const int BORDERSIZE = m_pWindow->getRealBorderSize();
|
||||
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 PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
||||
|
||||
SDecorationPositioningInfo info;
|
||||
info.policy = DECORATION_POSITION_STICKY;
|
||||
info.edges = DECORATION_EDGE_TOP;
|
||||
info.priority = 3;
|
||||
info.priority = g_pConfigManager->getConfigValuePtr("group:groupbar:priority")->intValue;
|
||||
info.reserved = true;
|
||||
info.desiredExtents = {{0, BORDERSIZE + BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2}, {0, 0}};
|
||||
|
||||
if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate)
|
||||
info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2}, {0, 0}};
|
||||
else
|
||||
info.desiredExtents = {{0, 0}, {0, 0}};
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@ -79,20 +87,19 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
|
|||
// get how many bars we will draw
|
||||
int barsToDraw = m_dwGroupMembers.size();
|
||||
|
||||
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 PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue;
|
||||
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
||||
|
||||
const int BORDERSIZE = m_pWindow->getRealBorderSize();
|
||||
|
||||
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
||||
if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate)
|
||||
return;
|
||||
|
||||
const auto ASSIGNEDBOX = assignedBoxGlobal();
|
||||
|
||||
m_fBarWidth = (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw;
|
||||
|
||||
const auto DESIREDHEIGHT = BORDERSIZE + BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2;
|
||||
const auto DESIREDHEIGHT = BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2;
|
||||
if (DESIREDHEIGHT != ASSIGNEDBOX.h)
|
||||
g_pDecorationPositioner->repositionDeco(this);
|
||||
|
||||
|
@ -283,11 +290,16 @@ void renderGradientTo(CTexture& tex, const CColor& grad) {
|
|||
}
|
||||
|
||||
void refreshGroupBarGradients() {
|
||||
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 PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data;
|
||||
static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data;
|
||||
static auto* const PGROUPCOLACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data;
|
||||
static auto* const PGROUPCOLINACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data;
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
if (m_tGradientActive.m_iTexID != 0) {
|
||||
m_tGradientActive.destroyTexture();
|
||||
m_tGradientInactive.destroyTexture();
|
||||
|
@ -295,16 +307,44 @@ void refreshGroupBarGradients() {
|
|||
m_tGradientLockedInactive.destroyTexture();
|
||||
}
|
||||
|
||||
if (!*PENABLED || !*PGRADIENTS)
|
||||
return;
|
||||
|
||||
renderGradientTo(m_tGradientActive, ((CGradientValueData*)PGROUPCOLACTIVE->get())->m_vColors[0]);
|
||||
renderGradientTo(m_tGradientInactive, ((CGradientValueData*)PGROUPCOLINACTIVE->get())->m_vColors[0]);
|
||||
renderGradientTo(m_tGradientLockedActive, ((CGradientValueData*)PGROUPCOLACTIVELOCKED->get())->m_vColors[0]);
|
||||
renderGradientTo(m_tGradientLockedInactive, ((CGradientValueData*)PGROUPCOLINACTIVELOCKED->get())->m_vColors[0]);
|
||||
}
|
||||
|
||||
bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D& pos) {
|
||||
bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {
|
||||
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x;
|
||||
const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
||||
|
||||
if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth)
|
||||
return false;
|
||||
|
||||
CWindow* pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX);
|
||||
|
||||
// hack
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow);
|
||||
if (!pWindow->m_bIsFloating) {
|
||||
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
|
||||
g_pKeybindManager->m_bGroupsLocked = true;
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow);
|
||||
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
|
||||
}
|
||||
|
||||
g_pInputManager->currentlyDraggedWindow = pWindow;
|
||||
|
||||
if (!g_pCompositor->isWindowActive(pWindow))
|
||||
g_pCompositor->focusWindow(pWindow);
|
||||
|
||||
if (!pDraggedWindow->canBeGroupedInto(m_pWindow))
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, CWindow* pDraggedWindow) {
|
||||
if (!pDraggedWindow->canBeGroupedInto(m_pWindow))
|
||||
return false;
|
||||
|
||||
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x - m_fBarWidth / 2;
|
||||
const int WINDOWINDEX = BARRELATIVEX < 0 ? -1 : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
||||
|
@ -358,20 +398,36 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, con
|
|||
if (!pDraggedWindow->getDecorationByType(DECORATION_GROUPBAR))
|
||||
pDraggedWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pDraggedWindow));
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_pointer_button_event* e) {
|
||||
if (e->state != WLR_BUTTON_PRESSED)
|
||||
return;
|
||||
bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_pointer_button_event* e) {
|
||||
if (m_pWindow->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(m_pWindow->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_FULL)
|
||||
return true;
|
||||
|
||||
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x;
|
||||
const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
||||
|
||||
// close window on middle click
|
||||
if (e->button == 274) {
|
||||
static Vector2D pressedCursorPos;
|
||||
|
||||
if (e->state == WLR_BUTTON_PRESSED)
|
||||
pressedCursorPos = pos;
|
||||
else if (e->state == WLR_BUTTON_RELEASED && pressedCursorPos == pos)
|
||||
g_pXWaylandManager->sendCloseWindow(m_pWindow->getGroupWindowByIndex(WINDOWINDEX));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e->state != WLR_BUTTON_PRESSED)
|
||||
return true;
|
||||
|
||||
// click on padding
|
||||
if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) {
|
||||
if (!g_pCompositor->isWindowActive(m_pWindow))
|
||||
g_pCompositor->focusWindow(m_pWindow);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
CWindow* pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX);
|
||||
|
@ -379,32 +435,35 @@ void CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point
|
|||
if (pWindow != m_pWindow)
|
||||
pWindow->setGroupCurrent(pWindow);
|
||||
|
||||
if (!g_pCompositor->isWindowActive(pWindow))
|
||||
g_pCompositor->focusWindow(pWindow);
|
||||
if (pWindow->m_bIsFloating)
|
||||
g_pCompositor->changeWindowZOrder(pWindow, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {
|
||||
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x;
|
||||
const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
||||
bool CHyprGroupBarDecoration::onScrollOnDeco(const Vector2D& pos, wlr_pointer_axis_event* e) {
|
||||
static auto* const PGROUPBARSCROLLING = &g_pConfigManager->getConfigValuePtr("group:groupbar:scrolling")->intValue;
|
||||
|
||||
if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth)
|
||||
return;
|
||||
|
||||
CWindow* pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX);
|
||||
|
||||
// hack
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow);
|
||||
if (!pWindow->m_bIsFloating) {
|
||||
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
|
||||
g_pKeybindManager->m_bGroupsLocked = true;
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow);
|
||||
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
|
||||
if (!*PGROUPBARSCROLLING || !m_pWindow->m_sGroupData.pNextWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
g_pInputManager->currentlyDraggedWindow = pWindow;
|
||||
if (e->delta > 0)
|
||||
m_pWindow->setGroupCurrent(m_pWindow->m_sGroupData.pNextWindow);
|
||||
else
|
||||
m_pWindow->setGroupCurrent(m_pWindow->getGroupPrevious());
|
||||
|
||||
if (!g_pCompositor->isWindowActive(pWindow))
|
||||
g_pCompositor->focusWindow(pWindow);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CHyprGroupBarDecoration::onInputOnDeco(const eInputType type, const Vector2D& mouseCoords, std::any data) {
|
||||
switch (type) {
|
||||
case INPUT_TYPE_AXIS: return onScrollOnDeco(mouseCoords, std::any_cast<wlr_pointer_axis_event*>(data));
|
||||
case INPUT_TYPE_BUTTON: return onMouseButtonOnDeco(mouseCoords, std::any_cast<wlr_pointer_button_event*>(data));
|
||||
case INPUT_TYPE_DRAG_START: return onBeginWindowDragOnDeco(mouseCoords);
|
||||
case INPUT_TYPE_DRAG_END: return onEndWindowDragOnDeco(mouseCoords, std::any_cast<CWindow*>(data));
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
eDecorationLayer CHyprGroupBarDecoration::getDecorationLayer() {
|
||||
|
@ -415,6 +474,10 @@ uint64_t CHyprGroupBarDecoration::getDecorationFlags() {
|
|||
return DECORATION_ALLOWS_MOUSE_INPUT;
|
||||
}
|
||||
|
||||
std::string CHyprGroupBarDecoration::getDisplayName() {
|
||||
return "GroupBar";
|
||||
}
|
||||
|
||||
CBox CHyprGroupBarDecoration::assignedBoxGlobal() {
|
||||
CBox box = m_bAssignedBox;
|
||||
box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow));
|
||||
|
|
|
@ -35,16 +35,14 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration {
|
|||
|
||||
virtual void damageEntire();
|
||||
|
||||
virtual void onBeginWindowDragOnDeco(const Vector2D&);
|
||||
|
||||
virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&);
|
||||
|
||||
virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*);
|
||||
virtual bool onInputOnDeco(const eInputType, const Vector2D&, std::any = {});
|
||||
|
||||
virtual eDecorationLayer getDecorationLayer();
|
||||
|
||||
virtual uint64_t getDecorationFlags();
|
||||
|
||||
virtual std::string getDisplayName();
|
||||
|
||||
private:
|
||||
SWindowDecorationExtents m_seExtents;
|
||||
|
||||
|
@ -61,6 +59,11 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration {
|
|||
|
||||
CBox assignedBoxGlobal();
|
||||
|
||||
bool onBeginWindowDragOnDeco(const Vector2D&);
|
||||
bool onEndWindowDragOnDeco(const Vector2D&, CWindow*);
|
||||
bool onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*);
|
||||
bool onScrollOnDeco(const Vector2D&, wlr_pointer_axis_event*);
|
||||
|
||||
struct STitleTexs {
|
||||
// STitleTexs* overriden = nullptr; // TODO: make shit shared in-group to decrease VRAM usage.
|
||||
std::deque<std::unique_ptr<CTitleTex>> titleTexs;
|
||||
|
|
|
@ -21,14 +21,15 @@ Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, CWindow* pWi
|
|||
|
||||
const int EDGESNO = TOP + BOTTOM + LEFT + RIGHT;
|
||||
|
||||
if (EDGESNO == 0 || EDGESNO > 2) {
|
||||
if (EDGESNO == 0 || EDGESNO == 3 || EDGESNO > 4) {
|
||||
Debug::log(ERR, "getEdgeDefinedPoint: invalid number of edges");
|
||||
return {};
|
||||
}
|
||||
|
||||
CBox wb = pWindow->getWindowMainSurfaceBox();
|
||||
const auto BORDERSIZE = pWindow->getRealBorderSize();
|
||||
wb.expand(BORDERSIZE);
|
||||
|
||||
if (EDGESNO == 4)
|
||||
return wb.pos();
|
||||
|
||||
if (EDGESNO == 1) {
|
||||
if (TOP)
|
||||
|
@ -138,8 +139,6 @@ void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) {
|
|||
std::sort(datas.begin(), datas.end(), [](const auto& a, const auto& b) { return a->positioningInfo.priority > b->positioningInfo.priority; });
|
||||
|
||||
CBox wb = pWindow->getWindowMainSurfaceBox();
|
||||
const auto BORDERSIZE = pWindow->getRealBorderSize();
|
||||
wb.expand(BORDERSIZE);
|
||||
|
||||
// calc reserved
|
||||
float reservedXL = 0, reservedYT = 0, reservedXR = 0, reservedYB = 0;
|
||||
|
@ -199,7 +198,7 @@ void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) {
|
|||
}
|
||||
|
||||
if (wd->positioningInfo.policy == DECORATION_POSITION_STICKY) {
|
||||
if (EDGESNO != 1) {
|
||||
if (EDGESNO != 1 && EDGESNO != 4) {
|
||||
wd->lastReply = {};
|
||||
wd->pDecoration->onPositioningReply({});
|
||||
continue;
|
||||
|
@ -219,29 +218,37 @@ void CDecorationPositioner::onWindowUpdate(CWindow* pWindow) {
|
|||
|
||||
Vector2D pos, size;
|
||||
|
||||
if (LEFT) {
|
||||
pos = wb.pos() - EDGEPOINT - Vector2D{stickyOffsetXL, 0};
|
||||
if (EDGESNO == 4) {
|
||||
pos = wb.pos() - EDGEPOINT - Vector2D{stickyOffsetXL + desiredSize, stickyOffsetYT + desiredSize};
|
||||
size = wb.size() + Vector2D{stickyOffsetXL + stickyOffsetXR + desiredSize * 2, stickyOffsetYB + stickyOffsetYT + desiredSize * 2};
|
||||
|
||||
stickyOffsetXL += desiredSize;
|
||||
stickyOffsetXR += desiredSize;
|
||||
stickyOffsetYT += desiredSize;
|
||||
stickyOffsetYB += desiredSize;
|
||||
} else if (LEFT) {
|
||||
pos = wb.pos() - EDGEPOINT - Vector2D{stickyOffsetXL, -stickyOffsetYT};
|
||||
pos.x -= desiredSize;
|
||||
size = {desiredSize, wb.size().y};
|
||||
size = {desiredSize, wb.size().y + stickyOffsetYB + stickyOffsetYT};
|
||||
|
||||
if (SOLID)
|
||||
stickyOffsetXL += desiredSize;
|
||||
} else if (RIGHT) {
|
||||
pos = wb.pos() + Vector2D{wb.size().x, 0} - EDGEPOINT + Vector2D{stickyOffsetXR, 0};
|
||||
size = {desiredSize, wb.size().y};
|
||||
pos = wb.pos() + Vector2D{wb.size().x, 0} - EDGEPOINT + Vector2D{stickyOffsetXR, -stickyOffsetYT};
|
||||
size = {desiredSize, wb.size().y + stickyOffsetYB + stickyOffsetYT};
|
||||
|
||||
if (SOLID)
|
||||
stickyOffsetXR += desiredSize;
|
||||
} else if (TOP) {
|
||||
pos = wb.pos() - EDGEPOINT - Vector2D{0, stickyOffsetYT};
|
||||
pos = wb.pos() - EDGEPOINT - Vector2D{stickyOffsetXL, stickyOffsetYT};
|
||||
pos.y -= desiredSize;
|
||||
size = {wb.size().x, desiredSize};
|
||||
size = {wb.size().x + stickyOffsetXL + stickyOffsetXR, desiredSize};
|
||||
|
||||
if (SOLID)
|
||||
stickyOffsetYT += desiredSize;
|
||||
} else {
|
||||
pos = wb.pos() + Vector2D{0, wb.size().y} - EDGEPOINT - Vector2D{0, stickyOffsetYB};
|
||||
size = {wb.size().x, desiredSize};
|
||||
pos = wb.pos() + Vector2D{0, wb.size().y} - EDGEPOINT - Vector2D{stickyOffsetXL, stickyOffsetYB};
|
||||
size = {wb.size().x + stickyOffsetXL + stickyOffsetXR, desiredSize};
|
||||
|
||||
if (SOLID)
|
||||
stickyOffsetYB += desiredSize;
|
||||
|
@ -279,7 +286,7 @@ SWindowDecorationExtents CDecorationPositioner::getWindowDecorationReserved(CWin
|
|||
}
|
||||
|
||||
SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(CWindow* pWindow, bool inputOnly) {
|
||||
CBox accum = pWindow->getWindowMainSurfaceBox().expand(pWindow->getRealBorderSize());
|
||||
CBox accum = pWindow->getWindowMainSurfaceBox();
|
||||
|
||||
for (auto& data : m_vWindowPositioningDatas) {
|
||||
if (data->pWindow != pWindow)
|
||||
|
@ -320,7 +327,7 @@ SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(CWind
|
|||
}
|
||||
|
||||
CBox CDecorationPositioner::getBoxWithIncludedDecos(CWindow* pWindow) {
|
||||
CBox accum = pWindow->getWindowMainSurfaceBox().expand(pWindow->getRealBorderSize());
|
||||
CBox accum = pWindow->getWindowMainSurfaceBox();
|
||||
|
||||
for (auto& data : m_vWindowPositioningDatas) {
|
||||
if (data->pWindow != pWindow)
|
||||
|
@ -347,9 +354,9 @@ CBox CDecorationPositioner::getBoxWithIncludedDecos(CWindow* pWindow) {
|
|||
if (decoBox.y < accum.y)
|
||||
extentsToAdd.topLeft.y = accum.y - decoBox.y;
|
||||
if (decoBox.x + decoBox.w > accum.x + accum.w)
|
||||
extentsToAdd.bottomRight.x = accum.x + accum.w - (decoBox.x + decoBox.w);
|
||||
extentsToAdd.bottomRight.x = (decoBox.x + decoBox.w) - (accum.x + accum.w);
|
||||
if (decoBox.y + decoBox.h > accum.y + accum.h)
|
||||
extentsToAdd.bottomRight.y = accum.y + accum.h - (decoBox.y + decoBox.h);
|
||||
extentsToAdd.bottomRight.y = (decoBox.y + decoBox.h) - (accum.y + accum.h);
|
||||
|
||||
accum.addExtents(extentsToAdd);
|
||||
}
|
||||
|
|
|
@ -9,14 +9,12 @@
|
|||
class CWindow;
|
||||
class IHyprWindowDecoration;
|
||||
|
||||
enum eDecorationPositioningPolicy
|
||||
{
|
||||
enum eDecorationPositioningPolicy {
|
||||
DECORATION_POSITION_ABSOLUTE = 0, /* Decoration wants absolute positioning */
|
||||
DECORATION_POSITION_STICKY, /* Decoration is stuck to some edge of a window */
|
||||
};
|
||||
|
||||
enum eDecorationEdges
|
||||
{
|
||||
enum eDecorationEdges {
|
||||
DECORATION_EDGE_TOP = 1 << 0,
|
||||
DECORATION_EDGE_BOTTOM = 1 << 1,
|
||||
DECORATION_EDGE_LEFT = 1 << 2,
|
||||
|
|
|
@ -8,16 +8,8 @@ IHyprWindowDecoration::IHyprWindowDecoration(CWindow* pWindow) {
|
|||
|
||||
IHyprWindowDecoration::~IHyprWindowDecoration() {}
|
||||
|
||||
void IHyprWindowDecoration::onBeginWindowDragOnDeco(const Vector2D&) {
|
||||
;
|
||||
}
|
||||
|
||||
bool IHyprWindowDecoration::onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void IHyprWindowDecoration::onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*) {
|
||||
;
|
||||
bool IHyprWindowDecoration::onInputOnDeco(const eInputType, const Vector2D&, std::any) {
|
||||
return false;
|
||||
}
|
||||
|
||||
eDecorationLayer IHyprWindowDecoration::getDecorationLayer() {
|
||||
|
@ -27,3 +19,7 @@ eDecorationLayer IHyprWindowDecoration::getDecorationLayer() {
|
|||
uint64_t IHyprWindowDecoration::getDecorationFlags() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string IHyprWindowDecoration::getDisplayName() {
|
||||
return "Unknown Decoration";
|
||||
}
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include "../../defines.hpp"
|
||||
#include "../../helpers/Region.hpp"
|
||||
#include "DecorationPositioner.hpp"
|
||||
|
||||
enum eDecorationType
|
||||
{
|
||||
enum eDecorationType {
|
||||
DECORATION_NONE = -1,
|
||||
DECORATION_GROUPBAR,
|
||||
DECORATION_SHADOW,
|
||||
DECORATION_BORDER,
|
||||
DECORATION_CUSTOM
|
||||
};
|
||||
|
||||
enum eDecorationLayer
|
||||
{
|
||||
enum eDecorationLayer {
|
||||
DECORATION_LAYER_BOTTOM = 0, /* lowest. */
|
||||
DECORATION_LAYER_UNDER, /* under the window, but above BOTTOM */
|
||||
DECORATION_LAYER_OVER, /* above the window, but below its popups */
|
||||
DECORATION_LAYER_OVERLAY /* above everything of the window, including popups */
|
||||
};
|
||||
|
||||
enum eDecorationFlags
|
||||
{
|
||||
enum eDecorationFlags {
|
||||
DECORATION_ALLOWS_MOUSE_INPUT = 1 << 0, /* this decoration accepts mouse input */
|
||||
DECORATION_PART_OF_MAIN_WINDOW = 1 << 1, /* this decoration is a *seamless* part of the main window, so stuff like shadows will include it */
|
||||
DECORATION_NON_SOLID = 1 << 2, /* this decoration is not solid. Other decorations should draw on top of it. Example: shadow */
|
||||
|
@ -48,16 +47,14 @@ class IHyprWindowDecoration {
|
|||
|
||||
virtual void damageEntire() = 0; // should be ignored by non-absolute decos
|
||||
|
||||
virtual void onBeginWindowDragOnDeco(const Vector2D&); // called when the user calls the "movewindow" mouse dispatcher on the deco
|
||||
|
||||
virtual bool onEndWindowDragOnDeco(CWindow* pDraggedWindow, const Vector2D&); // returns true if the window should be placed by the layout
|
||||
|
||||
virtual void onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*);
|
||||
virtual bool onInputOnDeco(const eInputType, const Vector2D&, std::any = {});
|
||||
|
||||
virtual eDecorationLayer getDecorationLayer();
|
||||
|
||||
virtual uint64_t getDecorationFlags();
|
||||
|
||||
virtual std::string getDisplayName();
|
||||
|
||||
private:
|
||||
CWindow* m_pWindow = nullptr;
|
||||
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
#define GIT_COMMIT_HASH "@HASH@"
|
||||
#define GIT_BRANCH "@BRANCH@"
|
||||
#define GIT_COMMIT_MESSAGE "@MESSAGE@"
|
||||
#define GIT_COMMIT_DATE "@DATE@"
|
||||
#define GIT_DIRTY "@DIRTY@"
|
||||
#define GIT_TAG "@TAG@"
|
45
subprojects/packagefiles/wlroots-meson-build.patch
Normal file
45
subprojects/packagefiles/wlroots-meson-build.patch
Normal file
|
@ -0,0 +1,45 @@
|
|||
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(
|
||||
# necessary for bugfix releases. Increasing soversion is required because
|
||||
# wlroots never guarantees ABI stability -- only API stability is guaranteed
|
||||
# between minor releases.
|
||||
-soversion = 13
|
||||
+soversion = 13032
|
||||
|
||||
little_endian = target_machine.endian() == 'little'
|
||||
big_endian = target_machine.endian() == 'big'
|
7
subprojects/wlroots.wrap
Normal file
7
subprojects/wlroots.wrap
Normal file
|
@ -0,0 +1,7 @@
|
|||
[wrap-git]
|
||||
directory = wlroots
|
||||
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
revision = 5d639394f3e83b01596dcd166a44a9a1a2583350
|
||||
depth = 1
|
||||
|
||||
diff_files = wlroots-meson-build.patch
|
Loading…
Add table
Reference in a new issue