mirror of
https://github.com/hyprwm/hyprlock.git
synced 2025-05-13 05:40:42 +01:00
Compare commits
34 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f7f0c9c6b0 | ||
![]() |
c12cf8e509 | ||
![]() |
0c5fd97d61 | ||
![]() |
fae1c4f6fe | ||
![]() |
e3bd47e177 | ||
![]() |
6c64630df8 | ||
![]() |
0e3e7206bc | ||
![]() |
867a71dd78 | ||
![]() |
82808290d9 | ||
![]() |
eb28a71756 | ||
![]() |
b3f1aa7580 | ||
![]() |
248dfb09f7 | ||
![]() |
656704aeb0 | ||
![]() |
d953296227 | ||
![]() |
71d35aa75f | ||
![]() |
8f73c39f07 | ||
![]() |
a8de918cc4 | ||
![]() |
6daab0517c | ||
![]() |
854235e1c8 | ||
![]() |
dd4c1d5034 | ||
![]() |
0b1f2a97ef | ||
![]() |
ce1eb7b5f9 | ||
![]() |
1ebbc35c55 | ||
![]() |
d9a1625315 | ||
![]() |
9e54d02590 | ||
![]() |
f883e669d1 | ||
![]() |
ee8ee1f9f7 | ||
![]() |
7ab3162d66 | ||
![]() |
9e82fe3547 | ||
![]() |
a13b6f0d1a | ||
![]() |
78ad1d46b5 | ||
![]() |
cb1c504b38 | ||
![]() |
9f37c1c8e9 | ||
![]() |
712ab62a42 |
52 changed files with 1099 additions and 701 deletions
|
@ -1,12 +1,12 @@
|
|||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: '.*\.hpp'
|
||||
FormatStyle: file
|
||||
FormatStyle: 'file'
|
||||
Checks: >
|
||||
-*,
|
||||
bugprone-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-forward-declararion-namespace,
|
||||
-bugprone-forward-declararion-namespace,
|
||||
-bugprone-forward-declaration-namespace,
|
||||
-bugprone-forward-declaration-namespace,
|
||||
-bugprone-macro-parentheses,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-branch-clone,
|
||||
|
|
|
@ -36,7 +36,7 @@ add_compile_definitions(HYPRLOCK_VERSION="${VERSION}")
|
|||
if (DEFINED HYPRLOCK_COMMIT)
|
||||
add_compile_definitions(HYPRLOCK_COMMIT="${HYPRLOCK_COMMIT}")
|
||||
else()
|
||||
# get git commit
|
||||
# get git commit
|
||||
execute_process(
|
||||
OUTPUT_VARIABLE GIT_SHORT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
|
@ -77,14 +77,11 @@ pkg_check_modules(
|
|||
REQUIRED
|
||||
IMPORTED_TARGET
|
||||
wayland-client
|
||||
wayland-protocols
|
||||
wayland-protocols>=1.35
|
||||
wayland-egl
|
||||
hyprlang>=0.6.0
|
||||
egl
|
||||
xkbcommon
|
||||
libjpeg
|
||||
libwebp
|
||||
libmagic
|
||||
cairo
|
||||
pangocairo
|
||||
libdrm
|
||||
|
|
39
README.md
39
README.md
|
@ -2,10 +2,14 @@
|
|||
Hyprland's simple, yet multi-threaded and GPU-accelerated screen locking utility.
|
||||
|
||||
## Features
|
||||
- uses the secure ext-session-lock protocol
|
||||
- full support for fractional-scale
|
||||
- fully GPU accelerated
|
||||
- multi-threaded resource acquisition for no hitches
|
||||
- Uses the ext-session-lock protocol
|
||||
- Support for fractional-scale
|
||||
- Fully GPU accelerated
|
||||
- Multi-threaded resource acquisition
|
||||
- Blurred screenshot as the background
|
||||
- Native fingerprint support (using libfprint's dbus interface)
|
||||
- Some of Hyprland's eyecandy: gradient borders, blur, animations, shadows, etc.
|
||||
- and more...
|
||||
|
||||
## How it looks
|
||||
|
||||
|
@ -25,26 +29,23 @@ yay -S hyprlock-git # compiles from latest source
|
|||
|
||||
### Deps
|
||||
You need the following dependencies
|
||||
- wayland-client
|
||||
- wayland-protocols
|
||||
- mesa
|
||||
- hyprwayland-scanner
|
||||
|
||||
And the development libraries for the following
|
||||
- cairo
|
||||
- libdrm
|
||||
- pango
|
||||
- xkbcommon
|
||||
- pam
|
||||
- hyprgraphics
|
||||
- hyprland-protocols
|
||||
- hyprlang
|
||||
- hyprutils
|
||||
- hyprgraphics
|
||||
- libmagic (file-devel on Fedora)
|
||||
- hyprwayland-scanner
|
||||
- mesa (required is libgbm, libdrm and the opengl runtime)
|
||||
- pam
|
||||
- pango
|
||||
- sdbus-cpp (>= 2.0.0)
|
||||
- wayland-client
|
||||
- wayland-protocols
|
||||
- xkbcommon
|
||||
|
||||
Development libraries are usually suffixed with `-devel` or `-dev` in most distro repos.
|
||||
|
||||
You also need to install `mesa-libgbm-devel` on some distros like RPM based ones where its not
|
||||
bundled with the mesa package.
|
||||
Sometimes distro packages are missing required development files.
|
||||
Such distros usually offer development versions of library package - commonly suffixed with `-devel` or `-dev`.
|
||||
|
||||
### Building
|
||||
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.7.0
|
||||
0.8.2
|
||||
|
|
|
@ -1,18 +1,106 @@
|
|||
# sample hyprlock.conf
|
||||
# for more configuration options, refer https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock
|
||||
#
|
||||
# rendered text in all widgets supports pango markup (e.g. <b> or <i> tags)
|
||||
# ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#general-remarks
|
||||
#
|
||||
# shortcuts to clear password buffer: ESC, Ctrl+U, Ctrl+Backspace
|
||||
#
|
||||
# you can get started by copying this config to ~/.config/hypr/hyprlock.conf
|
||||
#
|
||||
|
||||
$font = Monospace
|
||||
|
||||
general {
|
||||
hide_cursor = false
|
||||
}
|
||||
|
||||
# uncomment to enable fingerprint authentication
|
||||
# auth {
|
||||
# fingerprint {
|
||||
# enabled = true
|
||||
# ready_message = Scan fingerprint to unlock
|
||||
# present_message = Scanning...
|
||||
# retry_delay = 250 # in milliseconds
|
||||
# }
|
||||
# }
|
||||
|
||||
animations {
|
||||
enabled = true
|
||||
bezier = linear, 1, 1, 0, 0
|
||||
animation = fadeIn, 1, 5, linear
|
||||
animation = fadeOut, 1, 5, linear
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor =
|
||||
fade_on_empty = false
|
||||
animation = inputFieldDots, 1, 2, linear
|
||||
}
|
||||
|
||||
background {
|
||||
color = rgb(23, 39, 41)
|
||||
monitor =
|
||||
path = screenshot
|
||||
blur_passes = 3
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor =
|
||||
size = 20%, 5%
|
||||
outline_thickness = 3
|
||||
inner_color = rgba(0, 0, 0, 0.0) # no fill
|
||||
|
||||
outer_color = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
check_color = rgba(00ff99ee) rgba(ff6633ee) 120deg
|
||||
fail_color = rgba(ff6633ee) rgba(ff0066ee) 40deg
|
||||
|
||||
font_color = rgb(143, 143, 143)
|
||||
fade_on_empty = false
|
||||
rounding = 15
|
||||
|
||||
font_family = $font
|
||||
placeholder_text = Input password...
|
||||
fail_text = $PAMFAIL
|
||||
|
||||
# uncomment to use a letter instead of a dot to indicate the typed password
|
||||
# dots_text_format = *
|
||||
# dots_size = 0.4
|
||||
dots_spacing = 0.3
|
||||
|
||||
# uncomment to use an input indicator that does not show the password length (similar to swaylock's input indicator)
|
||||
# hide_input = true
|
||||
|
||||
position = 0, -20
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
# TIME
|
||||
label {
|
||||
monitor =
|
||||
text = $TIME # ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#variable-substitution
|
||||
font_size = 90
|
||||
font_family = $font
|
||||
|
||||
position = -30, 0
|
||||
halign = right
|
||||
valign = top
|
||||
}
|
||||
|
||||
# DATE
|
||||
label {
|
||||
monitor =
|
||||
text = cmd[update:60000] date +"%A, %d %B %Y" # update every 60 seconds
|
||||
font_size = 25
|
||||
font_family = $font
|
||||
|
||||
position = -30, -150
|
||||
halign = right
|
||||
valign = top
|
||||
}
|
||||
|
||||
label {
|
||||
monitor =
|
||||
text = $LAYOUT[en,ru]
|
||||
font_size = 24
|
||||
onclick = hyprctl switchxkblayout all next
|
||||
|
||||
position = 250, -20
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
|
30
flake.lock
30
flake.lock
|
@ -13,11 +13,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737634889,
|
||||
"narHash": "sha256-9JZE3KxcXOqZH9zs3UeadngDiK/yIACTiAR8HSA/TNI=",
|
||||
"lastModified": 1743953322,
|
||||
"narHash": "sha256-prQ5JKopXtzCMX2eT3dXbaVvGmzjMRE2bXStQDdazpM=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprgraphics",
|
||||
"rev": "0d77b4895ad5f1bb3b0ee43103a5246c58b65591",
|
||||
"rev": "9d7f2687c84c729afbc3b13f7937655570f2978d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -39,11 +39,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737634606,
|
||||
"narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=",
|
||||
"lastModified": 1744468525,
|
||||
"narHash": "sha256-9HySx+EtsbbKlZDlY+naqqOV679VdxP6x6fP3wxDXJk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "f41271d35cc0f370d300413d756c2677f386af9d",
|
||||
"rev": "f1000c54d266e6e4e9d646df0774fac5b8a652df",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -62,11 +62,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737978343,
|
||||
"narHash": "sha256-TfFS0HCEJh63Kahrkp1h9hVDMdLU8a37Zz+IFucxyfA=",
|
||||
"lastModified": 1743950287,
|
||||
"narHash": "sha256-/6IAEWyb8gC/NKZElxiHChkouiUOrVYNq9YqG0Pzm4Y=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "6a8bc9d2a4451df12f5179dc0b1d2d46518a90ab",
|
||||
"rev": "f2dc70e448b994cef627a157ee340135bd68fbc6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -85,11 +85,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1735493474,
|
||||
"narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=",
|
||||
"lastModified": 1739870480,
|
||||
"narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b",
|
||||
"rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -100,11 +100,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1737469691,
|
||||
"narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=",
|
||||
"lastModified": 1744463964,
|
||||
"narHash": "sha256-LWqduOgLHCFxiTNYi3Uj5Lgz0SR+Xhw3kr/3Xd0GPTM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab",
|
||||
"rev": "2631b0b7abcea6e640ce31cd78ea58910d31e650",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -4,13 +4,10 @@
|
|||
cmake,
|
||||
pkg-config,
|
||||
cairo,
|
||||
file,
|
||||
libdrm,
|
||||
libGL,
|
||||
libjpeg,
|
||||
libwebp,
|
||||
libxkbcommon,
|
||||
mesa,
|
||||
libgbm,
|
||||
hyprgraphics,
|
||||
hyprlang,
|
||||
hyprutils,
|
||||
|
@ -40,13 +37,10 @@ stdenv.mkDerivation {
|
|||
|
||||
buildInputs = [
|
||||
cairo
|
||||
file
|
||||
libdrm
|
||||
libGL
|
||||
libjpeg
|
||||
libwebp
|
||||
libxkbcommon
|
||||
mesa
|
||||
libgbm
|
||||
hyprgraphics
|
||||
hyprlang
|
||||
hyprutils
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
CAuth::CAuth() {
|
||||
static const auto ENABLEPAM = g_pConfigManager->getValue<Hyprlang::INT>("auth:pam:enabled");
|
||||
if (*ENABLEPAM)
|
||||
m_vImpls.push_back(std::make_shared<CPam>());
|
||||
m_vImpls.emplace_back(makeShared<CPam>());
|
||||
static const auto ENABLEFINGERPRINT = g_pConfigManager->getValue<Hyprlang::INT>("auth:fingerprint:enabled");
|
||||
if (*ENABLEFINGERPRINT)
|
||||
m_vImpls.push_back(std::make_shared<CFingerprint>());
|
||||
m_vImpls.emplace_back(makeShared<CFingerprint>());
|
||||
|
||||
RASSERT(!m_vImpls.empty(), "At least one authentication method must be enabled!");
|
||||
}
|
||||
|
@ -29,15 +29,12 @@ void CAuth::submitInput(const std::string& input) {
|
|||
for (const auto& i : m_vImpls) {
|
||||
i->handleInput(input);
|
||||
}
|
||||
|
||||
g_pHyprlock->clearPasswordBuffer();
|
||||
}
|
||||
|
||||
bool CAuth::checkWaiting() {
|
||||
for (const auto& i : m_vImpls) {
|
||||
if (i->checkWaiting())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return std::ranges::any_of(m_vImpls, [](const auto& i) { return i->checkWaiting(); });
|
||||
}
|
||||
|
||||
const std::string& CAuth::getCurrentFailText() {
|
||||
|
@ -64,7 +61,7 @@ size_t CAuth::getFailedAttempts() {
|
|||
return m_sCurrentFail.failedAttempts;
|
||||
}
|
||||
|
||||
std::shared_ptr<IAuthImplementation> CAuth::getImpl(eAuthImplementations implType) {
|
||||
SP<IAuthImplementation> CAuth::getImpl(eAuthImplementations implType) {
|
||||
for (const auto& i : m_vImpls) {
|
||||
if (i->getImplType() == implType)
|
||||
return i;
|
||||
|
@ -79,30 +76,49 @@ void CAuth::terminate() {
|
|||
}
|
||||
}
|
||||
|
||||
static void unlockCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
g_pHyprlock->unlock();
|
||||
}
|
||||
|
||||
void CAuth::enqueueUnlock() {
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(0), unlockCallback, nullptr);
|
||||
}
|
||||
|
||||
static void passwordFailCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
g_pAuth->m_bDisplayFailText = true;
|
||||
|
||||
g_pHyprlock->clearPasswordBuffer();
|
||||
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
}
|
||||
|
||||
static void passwordUnlockCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
g_pHyprlock->unlock();
|
||||
static void displayFailTimeoutCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
if (g_pAuth->m_bDisplayFailText) {
|
||||
g_pAuth->m_bDisplayFailText = false;
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
void CAuth::enqueueFail(const std::string& failText, eAuthImplementations implType) {
|
||||
static const auto FAILTIMEOUT = g_pConfigManager->getValue<Hyprlang::INT>("general:fail_timeout");
|
||||
|
||||
m_sCurrentFail.failText = failText;
|
||||
m_sCurrentFail.failSource = implType;
|
||||
m_sCurrentFail.failedAttempts++;
|
||||
|
||||
Debug::log(LOG, "Failed attempts: {}", m_sCurrentFail.failedAttempts);
|
||||
|
||||
if (m_resetDisplayFailTimer) {
|
||||
m_resetDisplayFailTimer->cancel();
|
||||
m_resetDisplayFailTimer.reset();
|
||||
}
|
||||
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(0), passwordFailCallback, nullptr);
|
||||
m_resetDisplayFailTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(*FAILTIMEOUT), displayFailTimeoutCallback, nullptr);
|
||||
}
|
||||
|
||||
void CAuth::enqueueUnlock() {
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(0), passwordUnlockCallback, nullptr);
|
||||
void CAuth::resetDisplayFail() {
|
||||
g_pAuth->m_bDisplayFailText = false;
|
||||
m_resetDisplayFailTimer->cancel();
|
||||
m_resetDisplayFailTimer.reset();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../core/Timer.hpp"
|
||||
|
||||
enum eAuthImplementations {
|
||||
AUTH_IMPL_PAM = 0,
|
||||
AUTH_IMPL_FINGERPRINT = 1,
|
||||
|
@ -28,23 +30,25 @@ class CAuth {
|
|||
public:
|
||||
CAuth();
|
||||
|
||||
void start();
|
||||
void start();
|
||||
|
||||
void submitInput(const std::string& input);
|
||||
bool checkWaiting();
|
||||
void submitInput(const std::string& input);
|
||||
bool checkWaiting();
|
||||
|
||||
const std::string& getCurrentFailText();
|
||||
const std::string& getCurrentFailText();
|
||||
|
||||
std::optional<std::string> getFailText(eAuthImplementations implType);
|
||||
std::optional<std::string> getPrompt(eAuthImplementations implType);
|
||||
size_t getFailedAttempts();
|
||||
std::optional<std::string> getFailText(eAuthImplementations implType);
|
||||
std::optional<std::string> getPrompt(eAuthImplementations implType);
|
||||
size_t getFailedAttempts();
|
||||
|
||||
std::shared_ptr<IAuthImplementation> getImpl(eAuthImplementations implType);
|
||||
SP<IAuthImplementation> getImpl(eAuthImplementations implType);
|
||||
|
||||
void terminate();
|
||||
void terminate();
|
||||
|
||||
void enqueueUnlock();
|
||||
void enqueueFail(const std::string& failText, eAuthImplementations implType);
|
||||
void enqueueUnlock();
|
||||
void enqueueFail(const std::string& failText, eAuthImplementations implType);
|
||||
|
||||
void resetDisplayFail();
|
||||
|
||||
// Should only be set via the main thread
|
||||
bool m_bDisplayFailText = false;
|
||||
|
@ -56,7 +60,8 @@ class CAuth {
|
|||
size_t failedAttempts = 0;
|
||||
} m_sCurrentFail;
|
||||
|
||||
std::vector<std::shared_ptr<IAuthImplementation>> m_vImpls;
|
||||
std::vector<SP<IAuthImplementation>> m_vImpls;
|
||||
std::shared_ptr<CTimer> m_resetDisplayFailTimer;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CAuth> g_pAuth;
|
||||
inline UP<CAuth> g_pAuth;
|
||||
|
|
|
@ -65,20 +65,13 @@ void CFingerprint::init() {
|
|||
// When entering sleep, the wake signal will trigger startVerify().
|
||||
if (m_sDBUSState.sleeping)
|
||||
return;
|
||||
inhibitSleep();
|
||||
startVerify();
|
||||
});
|
||||
m_sDBUSState.login->uponSignal("PrepareForSleep").onInterface(LOGIN_MANAGER).call([this](bool start) {
|
||||
Debug::log(LOG, "fprint: PrepareForSleep (start: {})", start);
|
||||
if (start) {
|
||||
m_sDBUSState.sleeping = true;
|
||||
stopVerify();
|
||||
m_sDBUSState.inhibitLock.reset();
|
||||
} else {
|
||||
m_sDBUSState.sleeping = false;
|
||||
inhibitSleep();
|
||||
m_sDBUSState.sleeping = start;
|
||||
if (!m_sDBUSState.sleeping && !m_sDBUSState.verifying)
|
||||
startVerify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -111,18 +104,6 @@ std::shared_ptr<sdbus::IConnection> CFingerprint::getConnection() {
|
|||
return m_sDBUSState.connection;
|
||||
}
|
||||
|
||||
void CFingerprint::inhibitSleep() {
|
||||
m_sDBUSState.login->callMethodAsync("Inhibit")
|
||||
.onInterface(LOGIN_MANAGER)
|
||||
.withArguments("sleep", "hyprlock", "Fingerprint verifcation must be stopped before sleep", "delay")
|
||||
.uponReplyInvoke([this](std::optional<sdbus::Error> e, sdbus::UnixFd fd) {
|
||||
if (e)
|
||||
Debug::log(WARN, "fprint: could not inhibit sleep: {}", e->what());
|
||||
else
|
||||
m_sDBUSState.inhibitLock = fd;
|
||||
});
|
||||
}
|
||||
|
||||
bool CFingerprint::createDeviceProxy() {
|
||||
auto proxy = sdbus::createProxy(*m_sDBUSState.connection, FPRINT, sdbus::ObjectPath{"/net/reactivated/Fprint/Manager"});
|
||||
|
||||
|
@ -163,8 +144,11 @@ void CFingerprint::handleVerifyStatus(const std::string& result, bool done) {
|
|||
auto matchResult = s_mapStringToTestType[result];
|
||||
bool authenticated = false;
|
||||
bool retry = false;
|
||||
if (m_sDBUSState.sleeping && matchResult != MATCH_DISCONNECTED)
|
||||
if (m_sDBUSState.sleeping) {
|
||||
stopVerify();
|
||||
Debug::log(LOG, "fprint: device suspended");
|
||||
return;
|
||||
}
|
||||
switch (matchResult) {
|
||||
case MATCH_INVALID: Debug::log(WARN, "fprint: unknown status: {}", result); break;
|
||||
case MATCH_NO_MATCH:
|
||||
|
@ -211,6 +195,8 @@ void CFingerprint::handleVerifyStatus(const std::string& result, bool done) {
|
|||
|
||||
if (!authenticated && !retry)
|
||||
g_pAuth->enqueueFail(m_sFailureReason, AUTH_IMPL_FINGERPRINT);
|
||||
else if (retry)
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
|
||||
if (done || m_sDBUSState.abort)
|
||||
m_sDBUSState.done = true;
|
||||
|
@ -229,6 +215,7 @@ void CFingerprint::claimDevice() {
|
|||
}
|
||||
|
||||
void CFingerprint::startVerify(bool isRetry) {
|
||||
m_sDBUSState.verifying = true;
|
||||
if (!m_sDBUSState.device) {
|
||||
if (!createDeviceProxy())
|
||||
return;
|
||||
|
@ -256,6 +243,7 @@ void CFingerprint::startVerify(bool isRetry) {
|
|||
}
|
||||
|
||||
bool CFingerprint::stopVerify() {
|
||||
m_sDBUSState.verifying = false;
|
||||
if (!m_sDBUSState.device)
|
||||
return false;
|
||||
try {
|
||||
|
|
|
@ -29,12 +29,12 @@ class CFingerprint : public IAuthImplementation {
|
|||
std::shared_ptr<sdbus::IConnection> connection;
|
||||
std::unique_ptr<sdbus::IProxy> login;
|
||||
std::unique_ptr<sdbus::IProxy> device;
|
||||
sdbus::UnixFd inhibitLock;
|
||||
|
||||
bool abort = false;
|
||||
bool done = false;
|
||||
int retries = 0;
|
||||
bool sleeping = false;
|
||||
bool abort = false;
|
||||
bool done = false;
|
||||
int retries = 0;
|
||||
bool sleeping = false;
|
||||
bool verifying = false;
|
||||
} m_sDBUSState;
|
||||
|
||||
std::string m_sFingerprintReady;
|
||||
|
@ -45,8 +45,6 @@ class CFingerprint : public IAuthImplementation {
|
|||
|
||||
void handleVerifyStatus(const std::string& result, const bool done);
|
||||
|
||||
void inhibitSleep();
|
||||
|
||||
bool createDeviceProxy();
|
||||
void claimDevice();
|
||||
void startVerify(bool isRetry = false);
|
||||
|
|
|
@ -138,14 +138,7 @@ bool CPam::auth() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// clearing the input must be done from the main thread
|
||||
static void clearInputTimerCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
g_pHyprlock->clearPasswordBuffer();
|
||||
}
|
||||
|
||||
void CPam::waitForInput() {
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(1), clearInputTimerCallback, nullptr);
|
||||
|
||||
std::unique_lock<std::mutex> lk(m_sConversationState.inputMutex);
|
||||
m_bBlockInput = false;
|
||||
m_sConversationState.waitingForPamAuth = false;
|
||||
|
|
|
@ -27,7 +27,7 @@ class ICustomConfigValueData {
|
|||
|
||||
class CLayoutValueData : public ICustomConfigValueData {
|
||||
public:
|
||||
CLayoutValueData() {};
|
||||
CLayoutValueData() = default;
|
||||
virtual ~CLayoutValueData() {};
|
||||
|
||||
virtual eConfigValueDataTypes getDataType() {
|
||||
|
|
|
@ -209,7 +209,9 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue(name, "shadow_passes", Hyprlang::INT{0}); \
|
||||
m_config.addSpecialConfigValue(name, "shadow_color", Hyprlang::INT{0xFF000000}); \
|
||||
m_config.addSpecialConfigValue(name, "shadow_boost", Hyprlang::FLOAT{1.2});
|
||||
m_config.addConfigValue("general:disable_loading_bar", Hyprlang::INT{0});
|
||||
|
||||
#define CLICKABLE(name) m_config.addSpecialConfigValue(name, "onclick", Hyprlang::STRING{""});
|
||||
|
||||
m_config.addConfigValue("general:text_trim", Hyprlang::INT{1});
|
||||
m_config.addConfigValue("general:hide_cursor", Hyprlang::INT{0});
|
||||
m_config.addConfigValue("general:grace", Hyprlang::INT{0});
|
||||
|
@ -217,6 +219,7 @@ void CConfigManager::init() {
|
|||
m_config.addConfigValue("general:immediate_render", Hyprlang::INT{0});
|
||||
m_config.addConfigValue("general:fractional_scaling", Hyprlang::INT{2});
|
||||
m_config.addConfigValue("general:screencopy_mode", Hyprlang::INT{0});
|
||||
m_config.addConfigValue("general:fail_timeout", Hyprlang::INT{2000});
|
||||
|
||||
m_config.addConfigValue("auth:pam:enabled", Hyprlang::INT{1});
|
||||
m_config.addConfigValue("auth:pam:module", Hyprlang::STRING{"hyprlock"});
|
||||
|
@ -257,6 +260,7 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue("shape", "xray", Hyprlang::INT{0});
|
||||
m_config.addSpecialConfigValue("shape", "zindex", Hyprlang::INT{0});
|
||||
SHADOWABLE("shape");
|
||||
CLICKABLE("shape");
|
||||
|
||||
m_config.addSpecialCategory("image", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||
m_config.addSpecialConfigValue("image", "monitor", Hyprlang::STRING{""});
|
||||
|
@ -273,6 +277,7 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue("image", "reload_cmd", Hyprlang::STRING{""});
|
||||
m_config.addSpecialConfigValue("image", "zindex", Hyprlang::INT{0});
|
||||
SHADOWABLE("image");
|
||||
CLICKABLE("image");
|
||||
|
||||
m_config.addSpecialCategory("input-field", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true});
|
||||
m_config.addSpecialConfigValue("input-field", "monitor", Hyprlang::STRING{""});
|
||||
|
@ -294,11 +299,11 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue("input-field", "position", LAYOUTCONFIG("0,0"));
|
||||
m_config.addSpecialConfigValue("input-field", "placeholder_text", Hyprlang::STRING{"<i>Input Password</i>"});
|
||||
m_config.addSpecialConfigValue("input-field", "hide_input", Hyprlang::INT{0});
|
||||
m_config.addSpecialConfigValue("input-field", "hide_input_base_color", Hyprlang::INT{0xEE00FF99});
|
||||
m_config.addSpecialConfigValue("input-field", "rounding", Hyprlang::INT{-1});
|
||||
m_config.addSpecialConfigValue("input-field", "check_color", GRADIENTCONFIG("0xFF22CC88"));
|
||||
m_config.addSpecialConfigValue("input-field", "fail_color", GRADIENTCONFIG("0xFFCC2222"));
|
||||
m_config.addSpecialConfigValue("input-field", "fail_text", Hyprlang::STRING{"<i>$FAIL</i>"});
|
||||
m_config.addSpecialConfigValue("input-field", "fail_timeout", Hyprlang::INT{2000});
|
||||
m_config.addSpecialConfigValue("input-field", "capslock_color", GRADIENTCONFIG(""));
|
||||
m_config.addSpecialConfigValue("input-field", "numlock_color", GRADIENTCONFIG(""));
|
||||
m_config.addSpecialConfigValue("input-field", "bothlock_color", GRADIENTCONFIG(""));
|
||||
|
@ -314,12 +319,13 @@ void CConfigManager::init() {
|
|||
m_config.addSpecialConfigValue("label", "font_size", Hyprlang::INT{16});
|
||||
m_config.addSpecialConfigValue("label", "text", Hyprlang::STRING{"Sample Text"});
|
||||
m_config.addSpecialConfigValue("label", "font_family", Hyprlang::STRING{"Sans"});
|
||||
m_config.addSpecialConfigValue("label", "halign", Hyprlang::STRING{"none"});
|
||||
m_config.addSpecialConfigValue("label", "valign", Hyprlang::STRING{"none"});
|
||||
m_config.addSpecialConfigValue("label", "halign", Hyprlang::STRING{"center"});
|
||||
m_config.addSpecialConfigValue("label", "valign", Hyprlang::STRING{"center"});
|
||||
m_config.addSpecialConfigValue("label", "rotate", Hyprlang::FLOAT{0});
|
||||
m_config.addSpecialConfigValue("label", "text_align", Hyprlang::STRING{""});
|
||||
m_config.addSpecialConfigValue("label", "zindex", Hyprlang::INT{0});
|
||||
SHADOWABLE("label");
|
||||
CLICKABLE("label");
|
||||
|
||||
m_config.registerHandler(&::handleSource, "source", {.allowFlags = false});
|
||||
m_config.registerHandler(&::handleBezier, "bezier", {.allowFlags = false});
|
||||
|
@ -356,6 +362,7 @@ void CConfigManager::init() {
|
|||
Debug::log(ERR, "Config has errors:\n{}\nProceeding ignoring faulty entries", result.getError());
|
||||
|
||||
#undef SHADOWABLE
|
||||
#undef CLICKABLE
|
||||
}
|
||||
|
||||
std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
||||
|
@ -367,6 +374,8 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
"shadow_boost", m_config.getSpecialConfigValue(name, "shadow_boost", k.c_str()) \
|
||||
}
|
||||
|
||||
#define CLICKABLE(name) {"onclick", m_config.getSpecialConfigValue(name, "onclick", k.c_str())}
|
||||
|
||||
//
|
||||
auto keys = m_config.listKeysForSpecialCategory("background");
|
||||
result.reserve(keys.size());
|
||||
|
@ -414,6 +423,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
{"xray", m_config.getSpecialConfigValue("shape", "xray", k.c_str())},
|
||||
{"zindex", m_config.getSpecialConfigValue("shape", "zindex", k.c_str())},
|
||||
SHADOWABLE("shape"),
|
||||
CLICKABLE("shape"),
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
|
@ -440,6 +450,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
{"reload_cmd", m_config.getSpecialConfigValue("image", "reload_cmd", k.c_str())},
|
||||
{"zindex", m_config.getSpecialConfigValue("image", "zindex", k.c_str())},
|
||||
SHADOWABLE("image"),
|
||||
CLICKABLE("image"),
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
|
@ -470,11 +481,11 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
{"position", m_config.getSpecialConfigValue("input-field", "position", k.c_str())},
|
||||
{"placeholder_text", m_config.getSpecialConfigValue("input-field", "placeholder_text", k.c_str())},
|
||||
{"hide_input", m_config.getSpecialConfigValue("input-field", "hide_input", k.c_str())},
|
||||
{"hide_input_base_color", m_config.getSpecialConfigValue("input-field", "hide_input_base_color", k.c_str())},
|
||||
{"rounding", m_config.getSpecialConfigValue("input-field", "rounding", k.c_str())},
|
||||
{"check_color", m_config.getSpecialConfigValue("input-field", "check_color", k.c_str())},
|
||||
{"fail_color", m_config.getSpecialConfigValue("input-field", "fail_color", k.c_str())},
|
||||
{"fail_text", m_config.getSpecialConfigValue("input-field", "fail_text", k.c_str())},
|
||||
{"fail_timeout", m_config.getSpecialConfigValue("input-field", "fail_timeout", k.c_str())},
|
||||
{"capslock_color", m_config.getSpecialConfigValue("input-field", "capslock_color", k.c_str())},
|
||||
{"numlock_color", m_config.getSpecialConfigValue("input-field", "numlock_color", k.c_str())},
|
||||
{"bothlock_color", m_config.getSpecialConfigValue("input-field", "bothlock_color", k.c_str())},
|
||||
|
@ -505,6 +516,7 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
{"text_align", m_config.getSpecialConfigValue("label", "text_align", k.c_str())},
|
||||
{"zindex", m_config.getSpecialConfigValue("label", "zindex", k.c_str())},
|
||||
SHADOWABLE("label"),
|
||||
CLICKABLE("label"),
|
||||
}
|
||||
});
|
||||
// clang-format on
|
||||
|
@ -603,6 +615,11 @@ std::optional<std::string> CConfigManager::handleAnimation(const std::string& co
|
|||
if (enabledInt > 1 || enabledInt < 0)
|
||||
return "invalid animation on/off state";
|
||||
|
||||
if (!enabledInt) {
|
||||
m_AnimationTree.setConfigForNode(ANIMNAME, 0, 1, "default");
|
||||
return {};
|
||||
}
|
||||
|
||||
int64_t speed = -1;
|
||||
|
||||
// speed
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include <hyprlang.hpp>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../defines.hpp"
|
||||
|
@ -41,4 +40,4 @@ class CConfigManager {
|
|||
Hyprlang::CConfig m_config;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CConfigManager> g_pConfigManager;
|
||||
inline UP<CConfigManager> g_pConfigManager;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <hyprutils/animation/AnimatedVariable.hpp>
|
||||
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
#include "../helpers/Math.hpp"
|
||||
#include "../defines.hpp"
|
||||
|
||||
class CHyprlockAnimationManager : public Hyprutils::Animation::CAnimationManager {
|
||||
|
@ -31,4 +30,4 @@ class CHyprlockAnimationManager : public Hyprutils::Animation::CAnimationManager
|
|||
bool m_bTickScheduled = false;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprlockAnimationManager> g_pAnimationManager;
|
||||
inline UP<CHyprlockAnimationManager> g_pAnimationManager;
|
||||
|
|
|
@ -9,12 +9,15 @@ CCursorShape::CCursorShape(SP<CCWpCursorShapeManagerV1> mgr) : mgr(mgr) {
|
|||
}
|
||||
|
||||
void CCursorShape::setShape(const wpCursorShapeDeviceV1Shape shape) {
|
||||
if (!dev)
|
||||
if (!g_pSeatManager->m_pPointer)
|
||||
return;
|
||||
|
||||
if (!dev)
|
||||
dev = makeShared<CCWpCursorShapeDeviceV1>(mgr->sendGetPointer(g_pSeatManager->m_pPointer->resource()));
|
||||
|
||||
dev->sendSetShape(lastCursorSerial, shape);
|
||||
}
|
||||
|
||||
void CCursorShape::hideCursor() {
|
||||
g_pSeatManager->m_pPointer->sendSetCursor(lastCursorSerial, nullptr, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "../defines.hpp"
|
||||
|
||||
class CEGL {
|
||||
public:
|
||||
CEGL(wl_display*);
|
||||
|
@ -19,4 +19,4 @@ class CEGL {
|
|||
void makeCurrent(EGLSurface surf);
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CEGL> g_pEGL;
|
||||
inline UP<CEGL> g_pEGL;
|
||||
|
|
|
@ -11,13 +11,9 @@ CSessionLockSurface::~CSessionLockSurface() {
|
|||
wl_egl_window_destroy(eglWindow);
|
||||
}
|
||||
|
||||
CSessionLockSurface::CSessionLockSurface(COutput* output) : output(output) {
|
||||
CSessionLockSurface::CSessionLockSurface(const SP<COutput>& pOutput) : m_outputRef(pOutput), m_outputID(pOutput->m_ID) {
|
||||
surface = makeShared<CCWlSurface>(g_pHyprlock->getCompositor()->sendCreateSurface());
|
||||
|
||||
if (!surface) {
|
||||
Debug::log(CRIT, "Couldn't create wl_surface");
|
||||
exit(1);
|
||||
}
|
||||
RASSERT(surface, "Couldn't create wl_surface");
|
||||
|
||||
static const auto FRACTIONALSCALING = g_pConfigManager->getValue<Hyprlang::INT>("general:fractional_scaling");
|
||||
const auto ENABLE_FSV1 = *FRACTIONALSCALING == 1 || /* auto enable */ (*FRACTIONALSCALING == 2);
|
||||
|
@ -45,12 +41,8 @@ CSessionLockSurface::CSessionLockSurface(COutput* output) : output(output) {
|
|||
if (!PVIEWPORTER)
|
||||
Debug::log(LOG, "No viewporter support! Oops, won't be able to scale!");
|
||||
|
||||
lockSurface = makeShared<CCExtSessionLockSurfaceV1>(g_pHyprlock->getSessionLock()->sendGetLockSurface(surface->resource(), output->output->resource()));
|
||||
|
||||
if (!lockSurface) {
|
||||
Debug::log(CRIT, "Couldn't create ext_session_lock_surface_v1");
|
||||
exit(1);
|
||||
}
|
||||
lockSurface = makeShared<CCExtSessionLockSurfaceV1>(g_pHyprlock->getSessionLock()->sendGetLockSurface(surface->resource(), pOutput->m_wlOutput->resource()));
|
||||
RASSERT(lockSurface, "Couldn't create ext_session_lock_surface_v1");
|
||||
|
||||
lockSurface->setConfigure([this](CCExtSessionLockSurfaceV1* r, uint32_t serial, uint32_t width, uint32_t height) { configure({(double)width, (double)height}, serial); });
|
||||
}
|
||||
|
@ -62,6 +54,8 @@ void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) {
|
|||
const bool SAMESIZE = logicalSize == size_;
|
||||
const bool SAMESCALE = appliedScale == fractionalScale;
|
||||
|
||||
const auto POUTPUT = m_outputRef.lock();
|
||||
|
||||
serial = serial_;
|
||||
logicalSize = size_;
|
||||
appliedScale = fractionalScale;
|
||||
|
@ -71,8 +65,8 @@ void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) {
|
|||
viewport->sendSetDestination(logicalSize.x, logicalSize.y);
|
||||
surface->sendSetBufferScale(1);
|
||||
} else {
|
||||
size = size_ * output->scale;
|
||||
surface->sendSetBufferScale(output->scale);
|
||||
size = size_ * POUTPUT->scale;
|
||||
surface->sendSetBufferScale(POUTPUT->scale);
|
||||
}
|
||||
|
||||
if (!SAMESERIAL)
|
||||
|
@ -84,27 +78,18 @@ void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) {
|
|||
|
||||
if (!eglWindow) {
|
||||
eglWindow = wl_egl_window_create((wl_surface*)surface->resource(), size.x, size.y);
|
||||
if (!eglWindow) {
|
||||
Debug::log(CRIT, "Couldn't create eglWindow");
|
||||
exit(1);
|
||||
}
|
||||
RASSERT(eglWindow, "Couldn't create eglWindow");
|
||||
} else
|
||||
wl_egl_window_resize(eglWindow, size.x, size.y, 0, 0);
|
||||
|
||||
if (!eglSurface) {
|
||||
eglSurface = g_pEGL->eglCreatePlatformWindowSurfaceEXT(g_pEGL->eglDisplay, g_pEGL->eglConfig, eglWindow, nullptr);
|
||||
if (!eglSurface) {
|
||||
Debug::log(CRIT, "Couldn't create eglSurface: {}", eglGetError());
|
||||
// Clean up resources to prevent leaks
|
||||
wl_egl_window_destroy(eglWindow);
|
||||
eglWindow = nullptr;
|
||||
exit(1); // Consider graceful exit or fallback
|
||||
}
|
||||
RASSERT(eglSurface, "Couldn't create eglSurface");
|
||||
}
|
||||
|
||||
if (readyForFrame && !(SAMESIZE && SAMESCALE)) {
|
||||
g_pRenderer->removeWidgetsFor(this);
|
||||
Debug::log(LOG, "Reloading widgets");
|
||||
Debug::log(LOG, "output {} changed, reloading widgets!", POUTPUT->stringPort);
|
||||
g_pRenderer->reconfigureWidgetsFor(POUTPUT->m_ID);
|
||||
}
|
||||
|
||||
readyForFrame = true;
|
||||
|
@ -129,7 +114,10 @@ void CSessionLockSurface::render() {
|
|||
if (g_pHyprlock->m_bTerminate)
|
||||
return;
|
||||
|
||||
Debug::log(TRACE, "[{}] frame {}, Current fps: {:.2f}", output->stringPort, m_frames, 1000.f / (frameTime - m_lastFrameTime));
|
||||
if (Debug::verbose) {
|
||||
const auto POUTPUT = m_outputRef.lock();
|
||||
Debug::log(TRACE, "[{}] frame {}, Current fps: {:.2f}", POUTPUT->stringPort, m_frames, 1000.f / (frameTime - m_lastFrameTime));
|
||||
}
|
||||
|
||||
m_lastFrameTime = frameTime;
|
||||
|
||||
|
@ -151,3 +139,7 @@ void CSessionLockSurface::onCallback() {
|
|||
render();
|
||||
}
|
||||
}
|
||||
|
||||
SP<CCWlSurface> CSessionLockSurface::getWlSurface() {
|
||||
return surface;
|
||||
}
|
||||
|
|
|
@ -14,21 +14,24 @@ class CRenderer;
|
|||
|
||||
class CSessionLockSurface {
|
||||
public:
|
||||
CSessionLockSurface(COutput* output);
|
||||
CSessionLockSurface(const SP<COutput>& pOutput);
|
||||
~CSessionLockSurface();
|
||||
|
||||
void configure(const Vector2D& size, uint32_t serial);
|
||||
void configure(const Vector2D& size, uint32_t serial);
|
||||
|
||||
bool readyForFrame = false;
|
||||
bool readyForFrame = false;
|
||||
|
||||
float fractionalScale = 1.0;
|
||||
float fractionalScale = 1.0;
|
||||
|
||||
void render();
|
||||
void onCallback();
|
||||
void onScaleUpdate();
|
||||
void render();
|
||||
void onCallback();
|
||||
void onScaleUpdate();
|
||||
SP<CCWlSurface> getWlSurface();
|
||||
|
||||
private:
|
||||
COutput* output = nullptr;
|
||||
WP<COutput> m_outputRef;
|
||||
OUTPUTID m_outputID = OUTPUT_INVALID;
|
||||
|
||||
SP<CCWlSurface> surface = nullptr;
|
||||
SP<CCExtSessionLockSurfaceV1> lockSurface = nullptr;
|
||||
uint32_t serial = 0;
|
||||
|
@ -49,4 +52,5 @@ class CSessionLockSurface {
|
|||
SP<CCWlCallback> frameCallback = nullptr;
|
||||
|
||||
friend class CRenderer;
|
||||
};
|
||||
friend class COutput;
|
||||
};
|
||||
|
|
|
@ -1,32 +1,35 @@
|
|||
#include "Output.hpp"
|
||||
#include "../helpers/Log.hpp"
|
||||
#include "hyprlock.hpp"
|
||||
#include "../renderer/Renderer.hpp"
|
||||
|
||||
COutput::COutput(SP<CCWlOutput> output_, uint32_t name_) : name(name_), output(output_) {
|
||||
output->setDescription([this](CCWlOutput* r, const char* description) {
|
||||
void COutput::create(WP<COutput> pSelf, SP<CCWlOutput> pWlOutput, uint32_t _name) {
|
||||
m_ID = _name;
|
||||
m_wlOutput = pWlOutput;
|
||||
m_self = pSelf;
|
||||
|
||||
m_wlOutput->setDescription([this](CCWlOutput* r, const char* description) {
|
||||
stringDesc = description ? std::string{description} : "";
|
||||
Debug::log(LOG, "output {} description {}", name, stringDesc);
|
||||
Debug::log(LOG, "output {} description {}", m_ID, stringDesc);
|
||||
});
|
||||
|
||||
output->setName([this](CCWlOutput* r, const char* name) {
|
||||
m_wlOutput->setName([this](CCWlOutput* r, const char* name) {
|
||||
stringName = std::string{name} + stringName;
|
||||
stringPort = std::string{name};
|
||||
Debug::log(LOG, "output {} name {}", name, name);
|
||||
});
|
||||
|
||||
output->setScale([this](CCWlOutput* r, int32_t sc) { scale = sc; });
|
||||
m_wlOutput->setScale([this](CCWlOutput* r, int32_t sc) { scale = sc; });
|
||||
|
||||
output->setDone([this](CCWlOutput* r) {
|
||||
m_wlOutput->setDone([this](CCWlOutput* r) {
|
||||
done = true;
|
||||
Debug::log(LOG, "output {} done", name);
|
||||
if (g_pHyprlock->m_lockAquired && !sessionLockSurface) {
|
||||
Debug::log(LOG, "output {} creating a new lock surface", name);
|
||||
sessionLockSurface = std::make_unique<CSessionLockSurface>(this);
|
||||
Debug::log(LOG, "output {} done", m_ID);
|
||||
if (g_pHyprlock->m_lockAquired && !m_sessionLockSurface) {
|
||||
Debug::log(LOG, "output {} creating a new lock surface", m_ID);
|
||||
createSessionLockSurface();
|
||||
}
|
||||
});
|
||||
|
||||
output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
||||
m_wlOutput->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
||||
// handle portrait mode and flipped cases
|
||||
if (transform % 2 == 1)
|
||||
size = {height, width};
|
||||
|
@ -34,10 +37,33 @@ COutput::COutput(SP<CCWlOutput> output_, uint32_t name_) : name(name_), output(o
|
|||
size = {width, height};
|
||||
});
|
||||
|
||||
output->setGeometry(
|
||||
m_wlOutput->setGeometry(
|
||||
[this](CCWlOutput* r, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make, const char* model, int32_t transform_) {
|
||||
transform = (wl_output_transform)transform_;
|
||||
|
||||
Debug::log(LOG, "output {} make {} model {}", name, make ? make : "", model ? model : "");
|
||||
Debug::log(LOG, "output {} make {} model {}", m_ID, make ? make : "", model ? model : "");
|
||||
});
|
||||
}
|
||||
|
||||
void COutput::createSessionLockSurface() {
|
||||
if (!m_self.valid()) {
|
||||
Debug::log(ERR, "output {} dead??", m_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sessionLockSurface) {
|
||||
Debug::log(ERR, "output {} already has a session lock surface", m_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size == Vector2D{0, 0}) {
|
||||
Debug::log(WARN, "output {} refusing to create a lock surface with size 0x0", m_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
m_sessionLockSurface = makeUnique<CSessionLockSurface>(m_self.lock());
|
||||
}
|
||||
|
||||
Vector2D COutput::getViewport() const {
|
||||
return (m_sessionLockSurface) ? m_sessionLockSurface->size : size;
|
||||
}
|
||||
|
|
|
@ -2,27 +2,32 @@
|
|||
|
||||
#include "../defines.hpp"
|
||||
#include "wayland.hpp"
|
||||
#include "../helpers/Math.hpp"
|
||||
#include "LockSurface.hpp"
|
||||
#include <memory>
|
||||
|
||||
class COutput {
|
||||
public:
|
||||
COutput(SP<CCWlOutput> output, uint32_t name);
|
||||
COutput() = default;
|
||||
~COutput() = default;
|
||||
|
||||
uint32_t name = 0;
|
||||
bool focused = false;
|
||||
bool done = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
Vector2D size;
|
||||
int scale = 1;
|
||||
std::string stringName = "";
|
||||
std::string stringPort = "";
|
||||
std::string stringDesc = "";
|
||||
void create(WP<COutput> pSelf, SP<CCWlOutput> pWlOutput, uint32_t name);
|
||||
|
||||
std::unique_ptr<CSessionLockSurface> sessionLockSurface;
|
||||
OUTPUTID m_ID = 0;
|
||||
bool focused = false;
|
||||
bool done = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
Vector2D size;
|
||||
int scale = 1;
|
||||
std::string stringName = "";
|
||||
std::string stringPort = "";
|
||||
std::string stringDesc = "";
|
||||
|
||||
SP<CCWlOutput> output = nullptr;
|
||||
UP<CSessionLockSurface> m_sessionLockSurface;
|
||||
|
||||
private:
|
||||
SP<CCWlOutput> m_wlOutput = nullptr;
|
||||
|
||||
WP<COutput> m_self;
|
||||
|
||||
void createSessionLockSurface();
|
||||
|
||||
Vector2D getViewport() const;
|
||||
};
|
||||
|
|
|
@ -26,7 +26,13 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
|||
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
||||
m_pPointer = makeShared<CCWlPointer>(r->sendGetPointer());
|
||||
|
||||
static const auto HIDECURSOR = g_pConfigManager->getValue<Hyprlang::INT>("general:hide_cursor");
|
||||
m_pPointer->setMotion([](CCWlPointer* r, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||
g_pHyprlock->m_vMouseLocation = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)};
|
||||
|
||||
if (!*HIDECURSOR)
|
||||
g_pHyprlock->onHover(g_pHyprlock->m_vMouseLocation);
|
||||
|
||||
if (std::chrono::system_clock::now() > g_pHyprlock->m_tGraceEnds)
|
||||
return;
|
||||
|
||||
|
@ -40,16 +46,34 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
|||
if (!m_pCursorShape)
|
||||
return;
|
||||
|
||||
static const auto HIDE = g_pConfigManager->getValue<Hyprlang::INT>("general:hide_cursor");
|
||||
|
||||
m_pCursorShape->lastCursorSerial = serial;
|
||||
|
||||
if (*HIDE)
|
||||
if (*HIDECURSOR)
|
||||
m_pCursorShape->hideCursor();
|
||||
else
|
||||
m_pCursorShape->setShape(wpCursorShapeDeviceV1Shape::WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
|
||||
|
||||
g_pHyprlock->m_vLastEnterCoords = {wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)};
|
||||
|
||||
if (*HIDECURSOR)
|
||||
return;
|
||||
|
||||
for (const auto& POUTPUT : g_pHyprlock->m_vOutputs) {
|
||||
if (!POUTPUT->m_sessionLockSurface)
|
||||
continue;
|
||||
|
||||
const auto& PWLSURFACE = POUTPUT->m_sessionLockSurface->getWlSurface();
|
||||
if (PWLSURFACE->resource() == surf)
|
||||
g_pHyprlock->m_focusedOutput = POUTPUT;
|
||||
}
|
||||
});
|
||||
|
||||
m_pPointer->setLeave([](CCWlPointer* r, uint32_t serial, wl_proxy* surf) { g_pHyprlock->m_focusedOutput.reset(); });
|
||||
|
||||
m_pPointer->setButton([](CCWlPointer* r, uint32_t serial, uint32_t time, uint32_t button, wl_pointer_button_state state) {
|
||||
if (*HIDECURSOR)
|
||||
return;
|
||||
g_pHyprlock->onClick(button, state == WL_POINTER_BUTTON_STATE_PRESSED, g_pHyprlock->m_vMouseLocation);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -131,7 +155,7 @@ void CSeatManager::registerSeat(SP<CCWlSeat> seat) {
|
|||
}
|
||||
|
||||
void CSeatManager::registerCursorShape(SP<CCWpCursorShapeManagerV1> shape) {
|
||||
m_pCursorShape = std::make_unique<CCursorShape>(shape);
|
||||
m_pCursorShape = makeUnique<CCursorShape>(shape);
|
||||
}
|
||||
|
||||
bool CSeatManager::registered() {
|
||||
|
|
|
@ -5,29 +5,28 @@
|
|||
#include "wayland.hpp"
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-compose.h>
|
||||
#include <memory>
|
||||
|
||||
class CSeatManager {
|
||||
public:
|
||||
CSeatManager() = default;
|
||||
~CSeatManager();
|
||||
|
||||
void registerSeat(SP<CCWlSeat> seat);
|
||||
void registerCursorShape(SP<CCWpCursorShapeManagerV1> shape);
|
||||
bool registered();
|
||||
void registerSeat(SP<CCWlSeat> seat);
|
||||
void registerCursorShape(SP<CCWpCursorShapeManagerV1> shape);
|
||||
bool registered();
|
||||
|
||||
SP<CCWlKeyboard> m_pKeeb;
|
||||
SP<CCWlPointer> m_pPointer;
|
||||
SP<CCWlKeyboard> m_pKeeb;
|
||||
SP<CCWlPointer> m_pPointer;
|
||||
|
||||
std::unique_ptr<CCursorShape> m_pCursorShape;
|
||||
UP<CCursorShape> m_pCursorShape;
|
||||
|
||||
xkb_context* m_pXKBContext = nullptr;
|
||||
xkb_keymap* m_pXKBKeymap = nullptr;
|
||||
xkb_state* m_pXKBState = nullptr;
|
||||
xkb_compose_state* m_pXKBComposeState = nullptr;
|
||||
xkb_context* m_pXKBContext = nullptr;
|
||||
xkb_keymap* m_pXKBKeymap = nullptr;
|
||||
xkb_state* m_pXKBState = nullptr;
|
||||
xkb_compose_state* m_pXKBComposeState = nullptr;
|
||||
|
||||
private:
|
||||
SP<CCWlSeat> m_pSeat;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CSeatManager> g_pSeatManager = std::make_unique<CSeatManager>();
|
||||
inline UP<CSeatManager> g_pSeatManager = makeUnique<CSeatManager>();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../auth/Auth.hpp"
|
||||
#include "../auth/Fingerprint.hpp"
|
||||
#include "Egl.hpp"
|
||||
#include <hyprutils/memory/UniquePtr.hpp>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/mman.h>
|
||||
|
@ -38,12 +39,9 @@ CHyprlock::CHyprlock(const std::string& wlDisplay, const bool immediate, const b
|
|||
setMallocThreshold();
|
||||
|
||||
m_sWaylandState.display = wl_display_connect(wlDisplay.empty() ? nullptr : wlDisplay.c_str());
|
||||
if (!m_sWaylandState.display) {
|
||||
Debug::log(CRIT, "Couldn't connect to a wayland compositor");
|
||||
exit(1);
|
||||
}
|
||||
RASSERT(m_sWaylandState.display, "Couldn't connect to a wayland compositor");
|
||||
|
||||
g_pEGL = std::make_unique<CEGL>(m_sWaylandState.display);
|
||||
g_pEGL = makeUnique<CEGL>(m_sWaylandState.display);
|
||||
|
||||
if (!immediate) {
|
||||
static const auto GRACE = g_pConfigManager->getValue<Hyprlang::INT>("general:grace");
|
||||
|
@ -75,7 +73,7 @@ static void registerSignalAction(int sig, void (*handler)(int), int sa_flags = 0
|
|||
static void handleUnlockSignal(int sig) {
|
||||
if (sig == SIGUSR1) {
|
||||
Debug::log(LOG, "Unlocking with a SIGUSR1");
|
||||
g_pHyprlock->releaseSessionLock();
|
||||
g_pAuth->enqueueUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,20 +92,6 @@ static void handlePollTerminate(int sig) {
|
|||
;
|
||||
}
|
||||
|
||||
static void handleCriticalSignal(int sig) {
|
||||
g_pHyprlock->attemptRestoreOnDeath();
|
||||
|
||||
// remove our handlers
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGABRT, &sa, nullptr);
|
||||
sigaction(SIGSEGV, &sa, nullptr);
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
static char* gbm_find_render_node(drmDevice* device) {
|
||||
drmDevice* devices[64];
|
||||
char* render_node = nullptr;
|
||||
|
@ -243,10 +227,7 @@ void CHyprlock::addDmabufListener() {
|
|||
memcpy(&device, device_arr->data, sizeof(device));
|
||||
|
||||
drmDevice* drmDev;
|
||||
if (drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) != 0) {
|
||||
Debug::log(WARN, "[dmabuf] unable to open main device?");
|
||||
exit(1);
|
||||
}
|
||||
RASSERT(drmGetDeviceFromDevId(device, /* flags */ 0, &drmDev) == 0, "unable to open main device?");
|
||||
|
||||
dma.gbmDevice = createGBMDevice(drmDev);
|
||||
drmFreeDevice(&drmDev);
|
||||
|
@ -283,10 +264,11 @@ void CHyprlock::run() {
|
|||
} else if (IFACE == ext_session_lock_manager_v1_interface.name)
|
||||
m_sWaylandState.sessionLock =
|
||||
makeShared<CCExtSessionLockManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &ext_session_lock_manager_v1_interface, 1));
|
||||
else if (IFACE == wl_output_interface.name)
|
||||
m_vOutputs.emplace_back(
|
||||
std::make_unique<COutput>(makeShared<CCWlOutput>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_output_interface, 4)), name));
|
||||
else if (IFACE == wp_cursor_shape_manager_v1_interface.name)
|
||||
else if (IFACE == wl_output_interface.name) {
|
||||
const auto POUTPUT = makeShared<COutput>();
|
||||
POUTPUT->create(POUTPUT, makeShared<CCWlOutput>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_output_interface, 4)), name);
|
||||
m_vOutputs.emplace_back(POUTPUT);
|
||||
} else if (IFACE == wp_cursor_shape_manager_v1_interface.name)
|
||||
g_pSeatManager->registerCursorShape(
|
||||
makeShared<CCWpCursorShapeManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wp_cursor_shape_manager_v1_interface, 1)));
|
||||
else if (IFACE == wl_compositor_interface.name)
|
||||
|
@ -308,9 +290,9 @@ void CHyprlock::run() {
|
|||
});
|
||||
m_sWaylandState.registry->setGlobalRemove([this](CCWlRegistry* r, uint32_t name) {
|
||||
Debug::log(LOG, " | removed iface {}", name);
|
||||
auto outputIt = std::ranges::find_if(m_vOutputs, [name](const auto& other) { return other->name == name; });
|
||||
auto outputIt = std::ranges::find_if(m_vOutputs, [id = name](const auto& other) { return other->m_ID == id; });
|
||||
if (outputIt != m_vOutputs.end()) {
|
||||
g_pRenderer->removeWidgetsFor(outputIt->get()->sessionLockSurface.get());
|
||||
g_pRenderer->removeWidgetsFor((*outputIt)->m_ID);
|
||||
m_vOutputs.erase(outputIt);
|
||||
}
|
||||
});
|
||||
|
@ -325,8 +307,8 @@ void CHyprlock::run() {
|
|||
// gather info about monitors
|
||||
wl_display_roundtrip(m_sWaylandState.display);
|
||||
|
||||
g_pRenderer = std::make_unique<CRenderer>();
|
||||
g_pAuth = std::make_unique<CAuth>();
|
||||
g_pRenderer = makeUnique<CRenderer>();
|
||||
g_pAuth = makeUnique<CAuth>();
|
||||
g_pAuth->start();
|
||||
|
||||
Debug::log(LOG, "Running on {}", m_sCurrentDesktop);
|
||||
|
@ -361,8 +343,6 @@ void CHyprlock::run() {
|
|||
registerSignalAction(SIGUSR1, handleUnlockSignal, SA_RESTART);
|
||||
registerSignalAction(SIGUSR2, handleForceUpdateSignal);
|
||||
registerSignalAction(SIGRTMIN, handlePollTerminate);
|
||||
registerSignalAction(SIGSEGV, handleCriticalSignal);
|
||||
registerSignalAction(SIGABRT, handleCriticalSignal);
|
||||
|
||||
pollfd pollfds[2];
|
||||
pollfds[0] = {
|
||||
|
@ -386,24 +366,13 @@ void CHyprlock::run() {
|
|||
events = poll(pollfds, fdcount, 5000);
|
||||
|
||||
if (events < 0) {
|
||||
RASSERT(errno == EINTR, "[core] Polling fds failed with {}", errno);
|
||||
wl_display_cancel_read(m_sWaylandState.display);
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
Debug::log(CRIT, "[core] Polling fds failed with {}", errno);
|
||||
attemptRestoreOnDeath();
|
||||
m_bTerminate = true;
|
||||
exit(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < fdcount; ++i) {
|
||||
if (pollfds[i].revents & POLLHUP) {
|
||||
Debug::log(CRIT, "[core] Disconnected from pollfd id {}", i);
|
||||
attemptRestoreOnDeath();
|
||||
m_bTerminate = true;
|
||||
exit(1);
|
||||
}
|
||||
RASSERT(!(pollfds[i].revents & POLLHUP), "[core] Disconnected from pollfd id {}", i);
|
||||
}
|
||||
|
||||
wl_display_read_events(m_sWaylandState.display);
|
||||
|
@ -554,23 +523,23 @@ void CHyprlock::clearPasswordBuffer() {
|
|||
void CHyprlock::renderOutput(const std::string& stringPort) {
|
||||
const auto MON = std::ranges::find_if(m_vOutputs, [stringPort](const auto& other) { return other->stringPort == stringPort; });
|
||||
|
||||
if (MON == m_vOutputs.end() || !MON->get())
|
||||
if (MON == m_vOutputs.end() || !*MON)
|
||||
return;
|
||||
|
||||
const auto PMONITOR = MON->get();
|
||||
const auto& PMONITOR = *MON;
|
||||
|
||||
if (!PMONITOR->sessionLockSurface)
|
||||
if (!PMONITOR->m_sessionLockSurface)
|
||||
return;
|
||||
|
||||
PMONITOR->sessionLockSurface->render();
|
||||
PMONITOR->m_sessionLockSurface->render();
|
||||
}
|
||||
|
||||
void CHyprlock::renderAllOutputs() {
|
||||
for (auto& o : m_vOutputs) {
|
||||
if (!o->sessionLockSurface)
|
||||
if (!o->m_sessionLockSurface)
|
||||
continue;
|
||||
|
||||
o->sessionLockSurface->render();
|
||||
o->m_sessionLockSurface->render();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -634,6 +603,9 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (g_pAuth->m_bDisplayFailText)
|
||||
g_pAuth->resetDisplayFail();
|
||||
|
||||
if (down) {
|
||||
m_bCapsLock = xkb_state_mod_name_is_active(g_pSeatManager->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED);
|
||||
m_bNumLock = xkb_state_mod_name_is_active(g_pSeatManager->m_pXKBState, XKB_MOD_NAME_NUM, XKB_STATE_MODS_LOCKED);
|
||||
|
@ -697,6 +669,61 @@ void CHyprlock::handleKeySym(xkb_keysym_t sym, bool composed) {
|
|||
}
|
||||
}
|
||||
|
||||
void CHyprlock::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (!m_focusedOutput.lock())
|
||||
return;
|
||||
|
||||
// TODO: add the UNLIKELY marco from Hyprland
|
||||
if (!m_focusedOutput->m_sessionLockSurface)
|
||||
return;
|
||||
|
||||
const auto SCALEDPOS = pos * m_focusedOutput->m_sessionLockSurface->fractionalScale;
|
||||
const auto widgets = g_pRenderer->getOrCreateWidgetsFor(*m_focusedOutput->m_sessionLockSurface);
|
||||
for (const auto& widget : widgets) {
|
||||
if (widget->containsPoint(SCALEDPOS))
|
||||
widget->onClick(button, down, pos);
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprlock::onHover(const Vector2D& pos) {
|
||||
if (!m_focusedOutput.lock())
|
||||
return;
|
||||
|
||||
if (!m_focusedOutput->m_sessionLockSurface)
|
||||
return;
|
||||
|
||||
bool outputNeedsRedraw = false;
|
||||
bool cursorChanged = false;
|
||||
|
||||
const auto SCALEDPOS = pos * m_focusedOutput->m_sessionLockSurface->fractionalScale;
|
||||
const auto widgets = g_pRenderer->getOrCreateWidgetsFor(*m_focusedOutput->m_sessionLockSurface);
|
||||
for (const auto& widget : widgets) {
|
||||
const bool CONTAINSPOINT = widget->containsPoint(SCALEDPOS);
|
||||
const bool HOVERED = widget->isHovered();
|
||||
|
||||
if (CONTAINSPOINT) {
|
||||
if (!HOVERED) {
|
||||
widget->setHover(true);
|
||||
widget->onHover(pos);
|
||||
outputNeedsRedraw = true;
|
||||
}
|
||||
|
||||
if (!cursorChanged)
|
||||
cursorChanged = true;
|
||||
|
||||
} else if (HOVERED) {
|
||||
widget->setHover(false);
|
||||
outputNeedsRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cursorChanged)
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
|
||||
|
||||
if (outputNeedsRedraw)
|
||||
m_focusedOutput->m_sessionLockSurface->render();
|
||||
}
|
||||
|
||||
bool CHyprlock::acquireSessionLock() {
|
||||
Debug::log(LOG, "Locking session");
|
||||
m_sLockState.lock = makeShared<CCExtSessionLockV1>(m_sWaylandState.sessionLock->sendLock());
|
||||
|
@ -723,7 +750,7 @@ bool CHyprlock::acquireSessionLock() {
|
|||
if (!o->done)
|
||||
continue;
|
||||
|
||||
o->sessionLockSurface = std::make_unique<CSessionLockSurface>(o.get());
|
||||
o->createSessionLockSurface();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -845,19 +872,6 @@ void CHyprlock::enqueueForceUpdateTimers() {
|
|||
nullptr, false);
|
||||
}
|
||||
|
||||
std::string CHyprlock::spawnSync(const std::string& cmd) {
|
||||
CProcess proc("/bin/sh", {"-c", cmd});
|
||||
if (!proc.runSync()) {
|
||||
Debug::log(ERR, "Failed to run \"{}\"", cmd);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!proc.stdErr().empty())
|
||||
Debug::log(ERR, "Shell command \"{}\" STDERR:\n{}", cmd, proc.stdErr());
|
||||
|
||||
return proc.stdOut();
|
||||
}
|
||||
|
||||
SP<CCZwlrScreencopyManagerV1> CHyprlock::getScreencopy() {
|
||||
return m_sWaylandState.screencopy;
|
||||
}
|
||||
|
@ -865,53 +879,3 @@ SP<CCZwlrScreencopyManagerV1> CHyprlock::getScreencopy() {
|
|||
SP<CCWlShm> CHyprlock::getShm() {
|
||||
return m_sWaylandState.shm;
|
||||
}
|
||||
|
||||
void CHyprlock::attemptRestoreOnDeath() {
|
||||
if (m_bTerminate || m_sCurrentDesktop != "Hyprland")
|
||||
return;
|
||||
|
||||
const auto XDG_RUNTIME_DIR = getenv("XDG_RUNTIME_DIR");
|
||||
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
|
||||
if (!XDG_RUNTIME_DIR || !HIS)
|
||||
return;
|
||||
|
||||
// dirty hack
|
||||
uint64_t timeNowMs = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t(0)).count();
|
||||
|
||||
const auto LASTRESTARTPATH = std::string{XDG_RUNTIME_DIR} + "/.hyprlockrestart";
|
||||
|
||||
if (std::filesystem::exists(LASTRESTARTPATH)) {
|
||||
std::ifstream ifs(LASTRESTARTPATH);
|
||||
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
uint64_t timeEncoded = 0;
|
||||
try {
|
||||
timeEncoded = std::stoull(content);
|
||||
} catch (std::exception& e) {
|
||||
// oops?
|
||||
ifs.close();
|
||||
std::filesystem::remove(LASTRESTARTPATH);
|
||||
return;
|
||||
}
|
||||
ifs.close();
|
||||
|
||||
if (timeNowMs - timeEncoded < 4000 /* 4s, seems reasonable */) {
|
||||
Debug::log(LOG, "Not restoring on death; less than 4s since last death");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream ofs(LASTRESTARTPATH, std::ios::trunc);
|
||||
ofs << timeNowMs;
|
||||
ofs.close();
|
||||
|
||||
if (m_bLocked && m_sLockState.lock) {
|
||||
m_sLockState.lock.reset();
|
||||
|
||||
// Destroy sessionLockSurfaces
|
||||
m_vOutputs.clear();
|
||||
}
|
||||
|
||||
spawnSync("hyprctl keyword misc:allow_session_lock_restore true");
|
||||
spawnSync("hyprctl dispatch exec \"hyprlock --immediate --immediate-render\"");
|
||||
}
|
||||
|
|
|
@ -37,9 +37,6 @@ class CHyprlock {
|
|||
void unlock();
|
||||
bool isUnlocked();
|
||||
|
||||
void onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version);
|
||||
void onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name);
|
||||
|
||||
std::shared_ptr<CTimer> addTimer(const std::chrono::system_clock::duration& timeout, std::function<void(std::shared_ptr<CTimer> self, void* data)> cb_, void* data,
|
||||
bool force = false);
|
||||
|
||||
|
@ -51,11 +48,9 @@ class CHyprlock {
|
|||
bool acquireSessionLock();
|
||||
void releaseSessionLock();
|
||||
|
||||
void attemptRestoreOnDeath();
|
||||
|
||||
std::string spawnSync(const std::string& cmd);
|
||||
|
||||
void onKey(uint32_t key, bool down);
|
||||
void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
void onHover(const Vector2D& pos);
|
||||
void startKeyRepeat(xkb_keysym_t sym);
|
||||
void repeatKey(xkb_keysym_t sym);
|
||||
void handleKeySym(xkb_keysym_t sym, bool compose);
|
||||
|
@ -100,10 +95,13 @@ class CHyprlock {
|
|||
//
|
||||
std::chrono::system_clock::time_point m_tGraceEnds;
|
||||
Vector2D m_vLastEnterCoords = {};
|
||||
WP<COutput> m_focusedOutput;
|
||||
|
||||
Vector2D m_vMouseLocation = {};
|
||||
|
||||
std::shared_ptr<CTimer> m_pKeyRepeatTimer = nullptr;
|
||||
|
||||
std::vector<std::unique_ptr<COutput>> m_vOutputs;
|
||||
std::vector<SP<COutput>> m_vOutputs;
|
||||
std::vector<std::shared_ptr<CTimer>> getTimers();
|
||||
|
||||
struct {
|
||||
|
@ -167,4 +165,4 @@ class CHyprlock {
|
|||
std::vector<uint32_t> m_vPressedKeys;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CHyprlock> g_pHyprlock;
|
||||
inline UP<CHyprlock> g_pHyprlock;
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
#include <hyprutils/memory/UniquePtr.hpp>
|
||||
#include <hyprgraphics/color/Color.hpp>
|
||||
|
||||
using namespace Hyprutils::Memory;
|
||||
using namespace Hyprgraphics;
|
||||
#define SP CSharedPointer
|
||||
#define WP CWeakPointer
|
||||
#define WP CWeakPointer
|
||||
#define UP CUniquePointer
|
||||
|
||||
typedef int64_t OUTPUTID;
|
||||
constexpr OUTPUTID OUTPUT_INVALID = -1;
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#include "MiscFunctions.hpp"
|
||||
#include "Log.hpp"
|
||||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
std::string absolutePath(const std::string& rawpath, const std::string& currentDir) {
|
||||
std::filesystem::path path(rawpath);
|
||||
|
@ -137,3 +139,22 @@ int createPoolFile(size_t size, std::string& name) {
|
|||
|
||||
return FD;
|
||||
}
|
||||
|
||||
std::string spawnSync(const std::string& cmd) {
|
||||
CProcess proc("/bin/sh", {"-c", cmd});
|
||||
if (!proc.runSync()) {
|
||||
Debug::log(ERR, "Failed to run \"{}\"", cmd);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!proc.stdErr().empty())
|
||||
Debug::log(ERR, "Shell command \"{}\" STDERR:\n{}", cmd, proc.stdErr());
|
||||
|
||||
return proc.stdOut();
|
||||
}
|
||||
|
||||
void spawnAsync(const std::string& cmd) {
|
||||
CProcess proc("/bin/sh", {"-c", cmd});
|
||||
if (!proc.runAsync())
|
||||
Debug::log(ERR, "Failed to start \"{}\"", cmd);
|
||||
}
|
||||
|
|
|
@ -7,3 +7,5 @@
|
|||
std::string absolutePath(const std::string&, const std::string&);
|
||||
int64_t configStringToInt(const std::string& VALUE);
|
||||
int createPoolFile(size_t size, std::string& name);
|
||||
std::string spawnSync(const std::string& cmd);
|
||||
void spawnAsync(const std::string& cmd);
|
||||
|
|
24
src/main.cpp
24
src/main.cpp
|
@ -29,6 +29,14 @@ std::optional<std::string> parseArg(const std::vector<std::string>& args, const
|
|||
}
|
||||
}
|
||||
|
||||
static void printVersion() {
|
||||
constexpr bool ISTAGGEDRELEASE = std::string_view(HYPRLOCK_COMMIT) == HYPRLOCK_VERSION_COMMIT;
|
||||
if (ISTAGGEDRELEASE)
|
||||
std::println("Hyprlock version v{}", HYPRLOCK_VERSION);
|
||||
else
|
||||
std::println("Hyprlock version v{} (commit {})", HYPRLOCK_VERSION, HYPRLOCK_COMMIT);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
std::string configPath;
|
||||
std::string wlDisplay;
|
||||
|
@ -47,12 +55,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
}
|
||||
|
||||
if (arg == "--version" || arg == "-V") {
|
||||
constexpr bool ISTAGGEDRELEASE = std::string_view(HYPRLOCK_COMMIT) == HYPRLOCK_VERSION_COMMIT;
|
||||
if (ISTAGGEDRELEASE)
|
||||
std::println("Hyprlock version v{}", HYPRLOCK_VERSION);
|
||||
else
|
||||
std::println("Hyprlock version v{} (commit {})", HYPRLOCK_VERSION, HYPRLOCK_COMMIT);
|
||||
|
||||
printVersion();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -90,10 +93,11 @@ int main(int argc, char** argv, char** envp) {
|
|||
}
|
||||
}
|
||||
|
||||
g_pAnimationManager = std::make_unique<CHyprlockAnimationManager>();
|
||||
printVersion();
|
||||
g_pAnimationManager = makeUnique<CHyprlockAnimationManager>();
|
||||
|
||||
try {
|
||||
g_pConfigManager = std::make_unique<CConfigManager>(configPath);
|
||||
g_pConfigManager = makeUnique<CConfigManager>(configPath);
|
||||
g_pConfigManager->init();
|
||||
} catch (const std::exception& ex) {
|
||||
Debug::log(CRIT, "ConfigManager threw: {}", ex.what());
|
||||
|
@ -103,11 +107,11 @@ int main(int argc, char** argv, char** envp) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (noFadeIn)
|
||||
if (noFadeIn || immediate)
|
||||
g_pConfigManager->m_AnimationTree.setConfigForNode("fadeIn", false, 0.f, "default");
|
||||
|
||||
try {
|
||||
g_pHyprlock = std::make_unique<CHyprlock>(wlDisplay, immediate, immediateRender);
|
||||
g_pHyprlock = makeUnique<CHyprlock>(wlDisplay, immediate, immediateRender);
|
||||
g_pHyprlock->run();
|
||||
} catch (const std::exception& ex) {
|
||||
Debug::log(CRIT, "Hyprlock threw: {}", ex.what());
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../config/ConfigManager.hpp"
|
||||
#include "../core/Egl.hpp"
|
||||
#include <cairo/cairo.h>
|
||||
#include <magic.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
@ -48,15 +47,12 @@ void CAsyncResourceGatherer::enqueueScreencopyFrames() {
|
|||
}
|
||||
|
||||
for (auto& mon : mons) {
|
||||
const auto MON = std::find_if(g_pHyprlock->m_vOutputs.begin(), g_pHyprlock->m_vOutputs.end(),
|
||||
[mon](const auto& other) { return other->stringPort == mon || other->stringDesc.starts_with(mon); });
|
||||
const auto MON = std::ranges::find_if(g_pHyprlock->m_vOutputs, [mon](const auto& other) { return other->stringPort == mon || other->stringDesc.starts_with(mon); });
|
||||
|
||||
if (MON == g_pHyprlock->m_vOutputs.end())
|
||||
continue;
|
||||
|
||||
const auto PMONITOR = MON->get();
|
||||
|
||||
scframes.emplace_back(std::make_unique<CScreencopyFrame>(PMONITOR));
|
||||
scframes.emplace_back(makeUnique<CScreencopyFrame>(*MON));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +217,7 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) {
|
|||
const bool ISCMD = rq.props.contains("cmd") ? std::any_cast<bool>(rq.props.at("cmd")) : false;
|
||||
|
||||
static const auto TRIM = g_pConfigManager->getValue<Hyprlang::INT>("general:text_trim");
|
||||
std::string text = ISCMD ? g_pHyprlock->spawnSync(rq.asset) : rq.asset;
|
||||
std::string text = ISCMD ? spawnSync(rq.asset) : rq.asset;
|
||||
|
||||
if (*TRIM) {
|
||||
text.erase(0, text.find_first_not_of(" \n\r\t"));
|
||||
|
@ -304,17 +300,6 @@ void CAsyncResourceGatherer::renderText(const SPreloadRequest& rq) {
|
|||
preloadTargets.push_back(target);
|
||||
}
|
||||
|
||||
struct STimerCallbackData {
|
||||
void (*cb)(void*) = nullptr;
|
||||
void* data = nullptr;
|
||||
};
|
||||
|
||||
static void timerCallback(std::shared_ptr<CTimer> self, void* data_) {
|
||||
auto data = (STimerCallbackData*)data_;
|
||||
data->cb(data->data);
|
||||
delete data;
|
||||
}
|
||||
|
||||
void CAsyncResourceGatherer::asyncAssetSpinLock() {
|
||||
while (!g_pHyprlock->m_bTerminate) {
|
||||
|
||||
|
@ -349,7 +334,7 @@ void CAsyncResourceGatherer::asyncAssetSpinLock() {
|
|||
|
||||
// plant timer for callback
|
||||
if (r.callback)
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(0), timerCallback, new STimerCallbackData{.cb = r.callback, .data = r.callbackData});
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(0), [cb = r.callback](auto, auto) { cb(); }, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,7 @@ class CAsyncResourceGatherer {
|
|||
// optional. Callbacks will be dispatched from the main thread,
|
||||
// so wayland/gl calls are OK.
|
||||
// will fire once the resource is fully loaded and ready.
|
||||
void (*callback)(void*) = nullptr;
|
||||
void* callbackData = nullptr;
|
||||
std::function<void()> callback = nullptr;
|
||||
};
|
||||
|
||||
void requestAsyncAssetPreload(const SPreloadRequest& request);
|
||||
|
@ -75,7 +74,7 @@ class CAsyncResourceGatherer {
|
|||
Vector2D size;
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<CScreencopyFrame>> scframes;
|
||||
std::vector<UP<CScreencopyFrame>> scframes;
|
||||
|
||||
std::vector<SPreloadTarget> preloadTargets;
|
||||
std::mutex preloadTargetsMutex;
|
||||
|
|
|
@ -117,6 +117,6 @@ CFramebuffer::~CFramebuffer() {
|
|||
release();
|
||||
}
|
||||
|
||||
bool CFramebuffer::isAllocated() {
|
||||
bool CFramebuffer::isAllocated() const {
|
||||
return m_iFb != (GLuint)-1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ class CFramebuffer {
|
|||
void bind() const;
|
||||
void release();
|
||||
void reset();
|
||||
bool isAllocated();
|
||||
bool isAllocated() const;
|
||||
|
||||
Vector2D m_vSize;
|
||||
|
||||
|
@ -21,4 +21,4 @@ class CFramebuffer {
|
|||
GLuint m_iFb = -1;
|
||||
|
||||
CTexture* m_pStencilTex = nullptr;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -194,15 +194,13 @@ CRenderer::CRenderer() {
|
|||
borderShader.gradientLerp = glGetUniformLocation(prog, "gradientLerp");
|
||||
borderShader.alpha = glGetUniformLocation(prog, "alpha");
|
||||
|
||||
asyncResourceGatherer = std::make_unique<CAsyncResourceGatherer>();
|
||||
asyncResourceGatherer = makeUnique<CAsyncResourceGatherer>();
|
||||
|
||||
g_pAnimationManager->createAnimation(0.f, opacity, g_pConfigManager->m_AnimationTree.getConfig("fadeIn"));
|
||||
}
|
||||
|
||||
//
|
||||
CRenderer::SRenderFeedback CRenderer::renderLock(const CSessionLockSurface& surf) {
|
||||
static const auto DISABLEBAR = g_pConfigManager->getValue<Hyprlang::INT>("general:disable_loading_bar");
|
||||
|
||||
projection = Mat3x3::outputProjection(surf.size, HYPRUTILS_TRANSFORM_NORMAL);
|
||||
|
||||
g_pEGL->makeCurrent(surf.eglSurface);
|
||||
|
@ -221,18 +219,10 @@ CRenderer::SRenderFeedback CRenderer::renderLock(const CSessionLockSurface& surf
|
|||
SRenderFeedback feedback;
|
||||
const bool WAITFORASSETS = !g_pHyprlock->m_bImmediateRender && !asyncResourceGatherer->gathered;
|
||||
|
||||
if (WAITFORASSETS) {
|
||||
|
||||
// render status
|
||||
if (!*DISABLEBAR) {
|
||||
CBox progress = {0, 0, asyncResourceGatherer->progress * surf.size.x, 2};
|
||||
renderRect(progress, CHyprColor{0.2f, 0.1f, 0.1f, 1.f}, 0);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!WAITFORASSETS) {
|
||||
// render widgets
|
||||
const auto WIDGETS = getOrCreateWidgetsFor(&surf);
|
||||
for (auto& w : *WIDGETS) {
|
||||
const auto WIDGETS = getOrCreateWidgetsFor(surf);
|
||||
for (auto& w : WIDGETS) {
|
||||
feedback.needsFrame = w->draw({opacity->value()}) || feedback.needsFrame;
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +272,7 @@ void CRenderer::renderBorder(const CBox& box, const CGradientValueData& gradient
|
|||
|
||||
glUniformMatrix3fv(borderShader.proj, 1, GL_TRUE, glMatrix.getMatrix().data());
|
||||
|
||||
glUniform4fv(borderShader.gradient, gradient.m_vColorsOkLabA.size(), (float*)gradient.m_vColorsOkLabA.data());
|
||||
glUniform4fv(borderShader.gradient, gradient.m_vColorsOkLabA.size() / 4, (float*)gradient.m_vColorsOkLabA.data());
|
||||
glUniform1i(borderShader.gradientLength, gradient.m_vColorsOkLabA.size() / 4);
|
||||
glUniform1f(borderShader.angle, (int)(gradient.m_fAngle / (M_PI / 180.0)) % 360 * (M_PI / 180.0));
|
||||
glUniform1f(borderShader.alpha, alpha);
|
||||
|
@ -397,62 +387,49 @@ void CRenderer::renderTextureMix(const CBox& box, const CTexture& tex, const CTe
|
|||
glBindTexture(tex.m_iTarget, 0);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<IWidget>>* CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface* surf) {
|
||||
if (!widgets.contains(surf)) {
|
||||
template <class Widget>
|
||||
static void createWidget(std::vector<SP<IWidget>>& widgets) {
|
||||
const auto W = makeShared<Widget>();
|
||||
W->registerSelf(W);
|
||||
widgets.emplace_back(W);
|
||||
}
|
||||
|
||||
std::vector<SP<IWidget>>& CRenderer::getOrCreateWidgetsFor(const CSessionLockSurface& surf) {
|
||||
RASSERT(surf.m_outputID != OUTPUT_INVALID, "Invalid output ID!");
|
||||
|
||||
if (!widgets.contains(surf.m_outputID)) {
|
||||
auto CWIDGETS = g_pConfigManager->getWidgetConfigs();
|
||||
|
||||
std::ranges::sort(CWIDGETS, [](CConfigManager::SWidgetConfig& a, CConfigManager::SWidgetConfig& b) {
|
||||
return std::any_cast<Hyprlang::INT>(a.values.at("zindex")) < std::any_cast<Hyprlang::INT>(b.values.at("zindex"));
|
||||
});
|
||||
|
||||
const auto POUTPUT = surf.m_outputRef.lock();
|
||||
for (auto& c : CWIDGETS) {
|
||||
if (!c.monitor.empty() && c.monitor != surf->output->stringPort && !surf->output->stringDesc.starts_with(c.monitor) &&
|
||||
!surf->output->stringDesc.starts_with("desc:" + c.monitor))
|
||||
if (!c.monitor.empty() && c.monitor != POUTPUT->stringPort && !POUTPUT->stringDesc.starts_with(c.monitor) && !("desc:" + POUTPUT->stringDesc).starts_with(c.monitor))
|
||||
continue;
|
||||
|
||||
// by type
|
||||
if (c.type == "background") {
|
||||
const std::string PATH = std::any_cast<Hyprlang::STRING>(c.values.at("path"));
|
||||
|
||||
std::string resourceID = "";
|
||||
if (PATH == "screenshot") {
|
||||
resourceID = CScreencopyFrame::getResourceId(surf->output);
|
||||
// When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available.
|
||||
// Dynamic ones are tricky, because a screencopy would copy hyprlock itself.
|
||||
if (asyncResourceGatherer->gathered) {
|
||||
if (!asyncResourceGatherer->getAssetByID(resourceID))
|
||||
resourceID = ""; // Fallback to solid color (background:color)
|
||||
}
|
||||
|
||||
if (!g_pHyprlock->getScreencopy()) {
|
||||
Debug::log(ERR, "No screencopy support! path=screenshot won't work. Falling back to background color.");
|
||||
resourceID = "";
|
||||
}
|
||||
|
||||
} else if (!PATH.empty())
|
||||
resourceID = "background:" + PATH;
|
||||
|
||||
widgets[surf].emplace_back(std::make_unique<CBackground>(surf->size, surf->output, resourceID, c.values, PATH == "screenshot"));
|
||||
createWidget<CBackground>(widgets[surf.m_outputID]);
|
||||
} else if (c.type == "input-field") {
|
||||
widgets[surf].emplace_back(std::make_unique<CPasswordInputField>(surf->size, c.values, surf->output->stringPort));
|
||||
createWidget<CPasswordInputField>(widgets[surf.m_outputID]);
|
||||
} else if (c.type == "label") {
|
||||
widgets[surf].emplace_back(std::make_unique<CLabel>(surf->size, c.values, surf->output->stringPort));
|
||||
createWidget<CLabel>(widgets[surf.m_outputID]);
|
||||
} else if (c.type == "shape") {
|
||||
widgets[surf].emplace_back(std::make_unique<CShape>(surf->size, c.values));
|
||||
createWidget<CShape>(widgets[surf.m_outputID]);
|
||||
} else if (c.type == "image") {
|
||||
const std::string PATH = std::any_cast<Hyprlang::STRING>(c.values.at("path"));
|
||||
|
||||
std::string resourceID = "";
|
||||
if (!PATH.empty())
|
||||
resourceID = "image:" + PATH;
|
||||
|
||||
widgets[surf].emplace_back(std::make_unique<CImage>(surf->size, surf->output, resourceID, c.values));
|
||||
createWidget<CImage>(widgets[surf.m_outputID]);
|
||||
} else {
|
||||
Debug::log(ERR, "Unknown widget type: {}", c.type);
|
||||
continue;
|
||||
}
|
||||
|
||||
widgets[surf.m_outputID].back()->configure(c.values, POUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
return &widgets[surf];
|
||||
return widgets[surf.m_outputID];
|
||||
}
|
||||
|
||||
void CRenderer::blurFB(const CFramebuffer& outfb, SBlurParams params) {
|
||||
|
@ -618,8 +595,15 @@ void CRenderer::popFb() {
|
|||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundFBs.empty() ? 0 : boundFBs.back());
|
||||
}
|
||||
|
||||
void CRenderer::removeWidgetsFor(const CSessionLockSurface* surf) {
|
||||
widgets.erase(surf);
|
||||
void CRenderer::removeWidgetsFor(OUTPUTID id) {
|
||||
widgets.erase(id);
|
||||
}
|
||||
|
||||
void CRenderer::reconfigureWidgetsFor(OUTPUTID id) {
|
||||
// TODO: reconfigure widgets by just calling their configure method again.
|
||||
// Requires a way to get a widgets config properties.
|
||||
// I think the best way would be to store the anonymos key of the widget config.
|
||||
removeWidgetsFor(id);
|
||||
}
|
||||
|
||||
void CRenderer::startFadeIn() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
#include "Shader.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../core/LockSurface.hpp"
|
||||
#include "../helpers/AnimatedVariable.hpp"
|
||||
#include "../helpers/Color.hpp"
|
||||
|
@ -12,7 +12,7 @@
|
|||
#include "widgets/IWidget.hpp"
|
||||
#include "Framebuffer.hpp"
|
||||
|
||||
typedef std::unordered_map<const CSessionLockSurface*, std::vector<std::unique_ptr<IWidget>>> widgetMap_t;
|
||||
typedef std::unordered_map<OUTPUTID, std::vector<SP<IWidget>>> widgetMap_t;
|
||||
|
||||
class CRenderer {
|
||||
public:
|
||||
|
@ -29,7 +29,7 @@ class CRenderer {
|
|||
float boostA = 1.0;
|
||||
};
|
||||
|
||||
SRenderFeedback renderLock(const CSessionLockSurface& surface);
|
||||
SRenderFeedback renderLock(const CSessionLockSurface& surf);
|
||||
|
||||
void renderRect(const CBox& box, const CHyprColor& col, int rounding = 0);
|
||||
void renderBorder(const CBox& box, const CGradientValueData& gradient, int thickness, int rounding = 0, float alpha = 1.0);
|
||||
|
@ -37,37 +37,37 @@ class CRenderer {
|
|||
void renderTextureMix(const CBox& box, const CTexture& tex, const CTexture& tex2, float a = 1.0, float mixFactor = 0.0, int rounding = 0, std::optional<eTransform> tr = {});
|
||||
void blurFB(const CFramebuffer& outfb, SBlurParams params);
|
||||
|
||||
std::unique_ptr<CAsyncResourceGatherer> asyncResourceGatherer;
|
||||
std::chrono::system_clock::time_point firstFullFrameTime;
|
||||
UP<CAsyncResourceGatherer> asyncResourceGatherer;
|
||||
std::chrono::system_clock::time_point firstFullFrameTime;
|
||||
|
||||
void pushFb(GLint fb);
|
||||
void popFb();
|
||||
void pushFb(GLint fb);
|
||||
void popFb();
|
||||
|
||||
void removeWidgetsFor(const CSessionLockSurface* surf);
|
||||
void removeWidgetsFor(OUTPUTID id);
|
||||
void reconfigureWidgetsFor(OUTPUTID id);
|
||||
|
||||
void startFadeIn();
|
||||
void startFadeOut(bool unlock = false, bool immediate = true);
|
||||
void startFadeIn();
|
||||
void startFadeOut(bool unlock = false, bool immediate = true);
|
||||
std::vector<SP<IWidget>>& getOrCreateWidgetsFor(const CSessionLockSurface& surf);
|
||||
|
||||
private:
|
||||
widgetMap_t widgets;
|
||||
widgetMap_t widgets;
|
||||
|
||||
std::vector<std::unique_ptr<IWidget>>* getOrCreateWidgetsFor(const CSessionLockSurface* surf);
|
||||
CShader rectShader;
|
||||
CShader texShader;
|
||||
CShader texMixShader;
|
||||
CShader blurShader1;
|
||||
CShader blurShader2;
|
||||
CShader blurPrepareShader;
|
||||
CShader blurFinishShader;
|
||||
CShader borderShader;
|
||||
|
||||
CShader rectShader;
|
||||
CShader texShader;
|
||||
CShader texMixShader;
|
||||
CShader blurShader1;
|
||||
CShader blurShader2;
|
||||
CShader blurPrepareShader;
|
||||
CShader blurFinishShader;
|
||||
CShader borderShader;
|
||||
Mat3x3 projMatrix = Mat3x3::identity();
|
||||
Mat3x3 projection;
|
||||
|
||||
Mat3x3 projMatrix = Mat3x3::identity();
|
||||
Mat3x3 projection;
|
||||
PHLANIMVAR<float> opacity;
|
||||
|
||||
PHLANIMVAR<float> opacity;
|
||||
|
||||
std::vector<GLint> boundFBs;
|
||||
std::vector<GLint> boundFBs;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CRenderer> g_pRenderer;
|
||||
inline UP<CRenderer> g_pRenderer;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <gbm.h>
|
||||
#include <hyprutils/memory/UniquePtr.hpp>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
|
@ -22,24 +23,27 @@ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullpt
|
|||
static PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
|
||||
|
||||
//
|
||||
std::string CScreencopyFrame::getResourceId(COutput* output) {
|
||||
return std::format("screencopy:{}-{}x{}", output->stringPort, output->size.x, output->size.y);
|
||||
std::string CScreencopyFrame::getResourceId(SP<COutput> pOutput) {
|
||||
return std::format("screencopy:{}-{}x{}", pOutput->stringPort, pOutput->size.x, pOutput->size.y);
|
||||
}
|
||||
|
||||
CScreencopyFrame::CScreencopyFrame(COutput* output) : m_output(output) {
|
||||
m_resourceID = getResourceId(m_output);
|
||||
|
||||
CScreencopyFrame::CScreencopyFrame(SP<COutput> pOutput) : m_outputRef(pOutput) {
|
||||
captureOutput();
|
||||
|
||||
static const auto SCMODE = g_pConfigManager->getValue<Hyprlang::INT>("general:screencopy_mode");
|
||||
if (*SCMODE == 1)
|
||||
m_frame = std::make_unique<CSCSHMFrame>(m_sc);
|
||||
m_frame = makeUnique<CSCSHMFrame>(m_sc);
|
||||
else
|
||||
m_frame = std::make_unique<CSCDMAFrame>(m_sc);
|
||||
m_frame = makeUnique<CSCDMAFrame>(m_sc);
|
||||
}
|
||||
|
||||
void CScreencopyFrame::captureOutput() {
|
||||
m_sc = makeShared<CCZwlrScreencopyFrameV1>(g_pHyprlock->getScreencopy()->sendCaptureOutput(false, m_output->output->resource()));
|
||||
const auto POUTPUT = m_outputRef.lock();
|
||||
RASSERT(POUTPUT, "Screencopy, but no valid output");
|
||||
|
||||
m_resourceID = getResourceId(POUTPUT);
|
||||
|
||||
m_sc = makeShared<CCZwlrScreencopyFrameV1>(g_pHyprlock->getScreencopy()->sendCaptureOutput(false, POUTPUT->m_wlOutput->resource()));
|
||||
|
||||
m_sc->setBufferDone([this](CCZwlrScreencopyFrameV1* r) {
|
||||
Debug::log(TRACE, "[sc] wlrOnBufferDone for {}", (void*)this);
|
||||
|
|
|
@ -22,9 +22,9 @@ class ISCFrame {
|
|||
|
||||
class CScreencopyFrame {
|
||||
public:
|
||||
static std::string getResourceId(COutput* output);
|
||||
static std::string getResourceId(SP<COutput> pOutput);
|
||||
|
||||
CScreencopyFrame(COutput* mon);
|
||||
CScreencopyFrame(SP<COutput> pOutput);
|
||||
~CScreencopyFrame() = default;
|
||||
|
||||
void captureOutput();
|
||||
|
@ -35,10 +35,10 @@ class CScreencopyFrame {
|
|||
SPreloadedAsset m_asset;
|
||||
|
||||
private:
|
||||
COutput* m_output = nullptr;
|
||||
std::unique_ptr<ISCFrame> m_frame = nullptr;
|
||||
WP<COutput> m_outputRef;
|
||||
UP<ISCFrame> m_frame = nullptr;
|
||||
|
||||
bool m_dmaFailed = false;
|
||||
bool m_dmaFailed = false;
|
||||
};
|
||||
|
||||
// Uses a gpu buffer created via gbm_bo
|
||||
|
|
|
@ -10,23 +10,15 @@
|
|||
#include <GLES3/gl32.h>
|
||||
|
||||
CBackground::~CBackground() {
|
||||
|
||||
if (reloadTimer) {
|
||||
reloadTimer->cancel();
|
||||
reloadTimer.reset();
|
||||
}
|
||||
|
||||
if (fade) {
|
||||
if (fade->crossFadeTimer) {
|
||||
fade->crossFadeTimer->cancel();
|
||||
fade->crossFadeTimer.reset();
|
||||
}
|
||||
fade.reset();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std::string& resourceID_, const std::unordered_map<std::string, std::any>& props, bool ss) :
|
||||
viewport(viewport_), resourceID(resourceID_), output(output_), isScreenshot(ss) {
|
||||
void CBackground::registerSelf(const SP<CBackground>& self) {
|
||||
m_self = self;
|
||||
}
|
||||
|
||||
void CBackground::configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput) {
|
||||
reset();
|
||||
|
||||
try {
|
||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||
|
@ -48,6 +40,29 @@ CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std:
|
|||
RASSERT(false, "Missing propperty for CBackground: {}", e.what()); //
|
||||
}
|
||||
|
||||
isScreenshot = path == "screenshot";
|
||||
|
||||
viewport = pOutput->getViewport();
|
||||
outputPort = pOutput->stringPort;
|
||||
transform = isScreenshot ? wlTransformToHyprutils(invertTransform(pOutput->transform)) : HYPRUTILS_TRANSFORM_NORMAL;
|
||||
|
||||
if (isScreenshot) {
|
||||
resourceID = CScreencopyFrame::getResourceId(pOutput);
|
||||
// When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available.
|
||||
// Dynamic ones are tricky, because a screencopy would copy hyprlock itself.
|
||||
if (g_pRenderer->asyncResourceGatherer->gathered) {
|
||||
if (!g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID))
|
||||
resourceID = ""; // Fallback to solid color (background:color)
|
||||
}
|
||||
|
||||
if (!g_pHyprlock->getScreencopy()) {
|
||||
Debug::log(ERR, "No screencopy support! path=screenshot won't work. Falling back to background color.");
|
||||
resourceID = "";
|
||||
}
|
||||
|
||||
} else if (!path.empty())
|
||||
resourceID = "background:" + path;
|
||||
|
||||
if (!isScreenshot && reloadTime > -1) {
|
||||
try {
|
||||
modificationTime = std::filesystem::last_write_time(absolutePath(path, ""));
|
||||
|
@ -57,30 +72,41 @@ CBackground::CBackground(const Vector2D& viewport_, COutput* output_, const std:
|
|||
}
|
||||
}
|
||||
|
||||
void CBackground::reset() {
|
||||
if (reloadTimer) {
|
||||
reloadTimer->cancel();
|
||||
reloadTimer.reset();
|
||||
}
|
||||
|
||||
if (fade) {
|
||||
if (fade->crossFadeTimer) {
|
||||
fade->crossFadeTimer->cancel();
|
||||
fade->crossFadeTimer.reset();
|
||||
}
|
||||
fade.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CBackground::renderRect(CHyprColor color) {
|
||||
CBox monbox = {0, 0, viewport.x, viewport.y};
|
||||
g_pRenderer->renderRect(monbox, color, 0);
|
||||
}
|
||||
|
||||
static void onReloadTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||
const auto PBG = (CBackground*)data;
|
||||
|
||||
PBG->onReloadTimerUpdate();
|
||||
PBG->plantReloadTimer();
|
||||
static void onReloadTimer(WP<CBackground> ref) {
|
||||
if (auto PBG = ref.lock(); PBG) {
|
||||
PBG->onReloadTimerUpdate();
|
||||
PBG->plantReloadTimer();
|
||||
}
|
||||
}
|
||||
|
||||
static void onCrossFadeTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||
const auto PBG = (CBackground*)data;
|
||||
PBG->onCrossFadeTimerUpdate();
|
||||
static void onCrossFadeTimer(WP<CBackground> ref) {
|
||||
if (auto PBG = ref.lock(); PBG)
|
||||
PBG->onCrossFadeTimerUpdate();
|
||||
}
|
||||
|
||||
static void onAssetCallback(void* data) {
|
||||
const auto PBG = (CBackground*)data;
|
||||
PBG->startCrossFadeOrUpdateRender();
|
||||
}
|
||||
|
||||
static void onAssetCallbackTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||
onAssetCallback(data);
|
||||
static void onAssetCallback(WP<CBackground> ref) {
|
||||
if (auto PBG = ref.lock(); PBG)
|
||||
PBG->startCrossFadeOrUpdateRender();
|
||||
}
|
||||
|
||||
bool CBackground::draw(const SRenderData& data) {
|
||||
|
@ -115,7 +141,7 @@ bool CBackground::draw(const SRenderData& data) {
|
|||
|
||||
// make it brah
|
||||
Vector2D size = asset->texture.m_vSize;
|
||||
if (output->transform % 2 == 1 && isScreenshot) {
|
||||
if (transform % 2 == 1 && isScreenshot) {
|
||||
size.x = asset->texture.m_vSize.y;
|
||||
size.y = asset->texture.m_vSize.x;
|
||||
}
|
||||
|
@ -142,16 +168,19 @@ bool CBackground::draw(const SRenderData& data) {
|
|||
if (fade)
|
||||
g_pRenderer->renderTextureMix(texbox, asset->texture, pendingAsset->texture, 1.0,
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - fade->start).count() / (1000 * crossFadeTime), 0,
|
||||
HYPRUTILS_TRANSFORM_NORMAL);
|
||||
transform);
|
||||
else
|
||||
g_pRenderer->renderTexture(texbox, asset->texture, 1.0, 0,
|
||||
isScreenshot ?
|
||||
wlTransformToHyprutils(invertTransform(output->transform)) :
|
||||
HYPRUTILS_TRANSFORM_NORMAL); // this could be omitted but whatever it's only once and makes code cleaner plus less blurring on large texs
|
||||
g_pRenderer->renderTexture(texbox, asset->texture, 1.0, 0, transform);
|
||||
|
||||
if (blurPasses > 0)
|
||||
g_pRenderer->blurFB(blurredFB, CRenderer::SBlurParams{
|
||||
.size = blurSize, .passes = blurPasses, .noise = noise, .contrast = contrast, .brightness = brightness, .vibrancy = vibrancy, .vibrancy_darkness = vibrancy_darkness});
|
||||
g_pRenderer->blurFB(blurredFB,
|
||||
CRenderer::SBlurParams{.size = blurSize,
|
||||
.passes = blurPasses,
|
||||
.noise = noise,
|
||||
.contrast = contrast,
|
||||
.brightness = brightness,
|
||||
.vibrancy = vibrancy,
|
||||
.vibrancy_darkness = vibrancy_darkness});
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
|
@ -179,9 +208,9 @@ bool CBackground::draw(const SRenderData& data) {
|
|||
void CBackground::plantReloadTimer() {
|
||||
|
||||
if (reloadTime == 0)
|
||||
reloadTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onReloadTimer, this, true);
|
||||
reloadTimer = g_pHyprlock->addTimer(std::chrono::hours(1), [REF = m_self](auto, auto) { onReloadTimer(REF); }, nullptr, true);
|
||||
else if (reloadTime > 0)
|
||||
reloadTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), onReloadTimer, this, false);
|
||||
reloadTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), [REF = m_self](auto, auto) { onReloadTimer(REF); }, nullptr, true);
|
||||
}
|
||||
|
||||
void CBackground::onCrossFadeTimerUpdate() {
|
||||
|
@ -190,7 +219,7 @@ void CBackground::onCrossFadeTimerUpdate() {
|
|||
|
||||
if (fade) {
|
||||
fade->crossFadeTimer.reset();
|
||||
fade.reset(nullptr);
|
||||
fade.reset();
|
||||
}
|
||||
|
||||
if (blurPasses <= 0 && !isScreenshot)
|
||||
|
@ -202,7 +231,7 @@ void CBackground::onCrossFadeTimerUpdate() {
|
|||
pendingAsset = nullptr;
|
||||
firstRender = true;
|
||||
|
||||
g_pHyprlock->renderOutput(output->stringPort);
|
||||
g_pHyprlock->renderOutput(outputPort);
|
||||
}
|
||||
|
||||
void CBackground::onReloadTimerUpdate() {
|
||||
|
@ -211,7 +240,7 @@ void CBackground::onReloadTimerUpdate() {
|
|||
// Path parsing and early returns
|
||||
|
||||
if (!reloadCommand.empty()) {
|
||||
path = g_pHyprlock->spawnSync(reloadCommand);
|
||||
path = spawnSync(reloadCommand);
|
||||
|
||||
if (path.ends_with('\n'))
|
||||
path.pop_back();
|
||||
|
@ -245,8 +274,7 @@ void CBackground::onReloadTimerUpdate() {
|
|||
request.asset = path;
|
||||
request.type = CAsyncResourceGatherer::eTargetType::TARGET_IMAGE;
|
||||
|
||||
request.callback = onAssetCallback;
|
||||
request.callbackData = this;
|
||||
request.callback = [REF = m_self]() { onAssetCallback(REF); };
|
||||
|
||||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||
}
|
||||
|
@ -262,7 +290,7 @@ void CBackground::startCrossFadeOrUpdateRender() {
|
|||
if (crossFadeTime > 0) {
|
||||
// Start a fade
|
||||
if (!fade)
|
||||
fade = std::make_unique<SFade>(std::chrono::system_clock::now(), 0, nullptr);
|
||||
fade = makeUnique<SFade>(std::chrono::system_clock::now(), 0, nullptr);
|
||||
else {
|
||||
// Maybe we where already fading so reset it just in case, but should'nt be happening.
|
||||
if (fade->crossFadeTimer) {
|
||||
|
@ -270,17 +298,18 @@ void CBackground::startCrossFadeOrUpdateRender() {
|
|||
fade->crossFadeTimer.reset();
|
||||
}
|
||||
}
|
||||
fade->start = std::chrono::system_clock::now();
|
||||
fade->a = 0;
|
||||
fade->crossFadeTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)(1000.0 * crossFadeTime)), onCrossFadeTimer, this);
|
||||
fade->start = std::chrono::system_clock::now();
|
||||
fade->a = 0;
|
||||
fade->crossFadeTimer =
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds((int)(1000.0 * crossFadeTime)), [REF = m_self](auto, auto) { onCrossFadeTimer(REF); }, nullptr);
|
||||
} else {
|
||||
onCrossFadeTimerUpdate();
|
||||
}
|
||||
}
|
||||
} else if (!pendingResourceID.empty()) {
|
||||
Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID);
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(100), onAssetCallbackTimer, this);
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(100), [REF = m_self](auto, auto) { onAssetCallback(REF); }, nullptr);
|
||||
}
|
||||
|
||||
g_pHyprlock->renderOutput(output->stringPort);
|
||||
g_pHyprlock->renderOutput(outputPort);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../../core/Timer.hpp"
|
||||
#include "../Framebuffer.hpp"
|
||||
#include "../AsyncResourceGatherer.hpp"
|
||||
#include <hyprutils/math/Misc.hpp>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <any>
|
||||
|
@ -23,10 +24,16 @@ struct SFade {
|
|||
|
||||
class CBackground : public IWidget {
|
||||
public:
|
||||
CBackground(const Vector2D& viewport, COutput* output_, const std::string& resourceID, const std::unordered_map<std::string, std::any>& props, bool ss_);
|
||||
CBackground() = default;
|
||||
~CBackground();
|
||||
|
||||
void registerSelf(const SP<CBackground>& self);
|
||||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
|
||||
void reset(); // Unload assets, remove timers, etc.
|
||||
|
||||
void renderRect(CHyprColor color);
|
||||
|
||||
void onReloadTimerUpdate();
|
||||
|
@ -35,6 +42,8 @@ class CBackground : public IWidget {
|
|||
void startCrossFadeOrUpdateRender();
|
||||
|
||||
private:
|
||||
WP<CBackground> m_self;
|
||||
|
||||
// if needed
|
||||
CFramebuffer blurredFB;
|
||||
|
||||
|
@ -48,6 +57,9 @@ class CBackground : public IWidget {
|
|||
Vector2D viewport;
|
||||
std::string path = "";
|
||||
|
||||
std::string outputPort;
|
||||
Hyprutils::Math::eTransform transform;
|
||||
|
||||
std::string resourceID;
|
||||
std::string pendingResourceID;
|
||||
|
||||
|
@ -55,16 +67,15 @@ class CBackground : public IWidget {
|
|||
|
||||
CHyprColor color;
|
||||
SPreloadedAsset* asset = nullptr;
|
||||
COutput* output = nullptr;
|
||||
bool isScreenshot = false;
|
||||
SPreloadedAsset* pendingAsset = nullptr;
|
||||
bool firstRender = true;
|
||||
|
||||
std::unique_ptr<SFade> fade;
|
||||
UP<SFade> fade;
|
||||
|
||||
int reloadTime = -1;
|
||||
std::string reloadCommand;
|
||||
CAsyncResourceGatherer::SPreloadRequest request;
|
||||
std::shared_ptr<CTimer> reloadTimer;
|
||||
std::filesystem::file_time_type modificationTime;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace std {
|
|||
}
|
||||
#endif
|
||||
|
||||
Vector2D rotateVector(const Vector2D& vec, const double& ang) {
|
||||
static Vector2D rotateVector(const Vector2D& vec, const double& ang) {
|
||||
const double COS = std::abs(std::cos(ang));
|
||||
const double SIN = std::abs(std::sin(ang));
|
||||
return Vector2D((vec.x * COS) + (vec.y * SIN), (vec.x * SIN) + (vec.y * COS));
|
||||
|
@ -100,22 +100,31 @@ static void replaceAllAttempts(std::string& str) {
|
|||
}
|
||||
|
||||
static void replaceAllLayout(std::string& str) {
|
||||
std::string layoutName = "error";
|
||||
const auto LAYOUTIDX = g_pHyprlock->m_uiActiveLayout;
|
||||
|
||||
const auto LAYOUTIDX = g_pHyprlock->m_uiActiveLayout;
|
||||
const auto LAYOUTNAME = xkb_keymap_layout_get_name(g_pSeatManager->m_pXKBKeymap, LAYOUTIDX);
|
||||
const std::string STR = LAYOUTNAME ? LAYOUTNAME : "error";
|
||||
size_t pos = 0;
|
||||
if (g_pSeatManager->m_pXKBKeymap) {
|
||||
const auto PNAME = xkb_keymap_layout_get_name(g_pSeatManager->m_pXKBKeymap, LAYOUTIDX);
|
||||
if (PNAME)
|
||||
layoutName = PNAME;
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
while ((pos = str.find("$LAYOUT", pos)) != std::string::npos) {
|
||||
if (str.substr(pos, 8).ends_with('[') && str.substr(pos).contains(']')) {
|
||||
const std::string REPL = str.substr(pos + 8, str.find_first_of(']', pos) - 8 - pos);
|
||||
const CVarList LANGS(REPL);
|
||||
const std::string LANG = LANGS[LAYOUTIDX].empty() ? STR : LANGS[LAYOUTIDX] == "!" ? "" : LANGS[LAYOUTIDX];
|
||||
if (LAYOUTIDX >= LANGS.size()) {
|
||||
Debug::log(ERR, "Layout index {} out of bounds. Max is {}.", LAYOUTIDX, LANGS.size() - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string LANG = LANGS[LAYOUTIDX].empty() ? layoutName : LANGS[LAYOUTIDX] == "!" ? "" : LANGS[LAYOUTIDX];
|
||||
str.replace(pos, 9 + REPL.length(), LANG);
|
||||
pos += LANG.length();
|
||||
} else {
|
||||
str.replace(pos, 7, STR);
|
||||
pos += STR.length();
|
||||
str.replace(pos, 7, layoutName);
|
||||
pos += layoutName.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,3 +266,15 @@ IWidget::SFormatResult IWidget::formatString(std::string in) {
|
|||
result.formatted = in;
|
||||
return result;
|
||||
}
|
||||
|
||||
void IWidget::setHover(bool hover) {
|
||||
hovered = hover;
|
||||
}
|
||||
|
||||
bool IWidget::isHovered() const {
|
||||
return hovered;
|
||||
}
|
||||
|
||||
bool IWidget::containsPoint(const Vector2D& pos) const {
|
||||
return getBoundingBoxWl().containsPoint(pos);
|
||||
}
|
||||
|
|
|
@ -1,22 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../defines.hpp"
|
||||
#include "../../helpers/Math.hpp"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <any>
|
||||
|
||||
class COutput;
|
||||
|
||||
class IWidget {
|
||||
public:
|
||||
struct SRenderData {
|
||||
float opacity = 1;
|
||||
};
|
||||
|
||||
virtual ~IWidget() = default;
|
||||
|
||||
virtual bool draw(const SRenderData& data) = 0;
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput) = 0;
|
||||
virtual bool draw(const SRenderData& data) = 0;
|
||||
|
||||
static Vector2D posFromHVAlign(const Vector2D& viewport, const Vector2D& size, const Vector2D& offset, const std::string& halign, const std::string& valign,
|
||||
const double& ang = 0);
|
||||
static int roundingForBox(const CBox& box, int roundingConfig);
|
||||
static int roundingForBorderBox(const CBox& borderBox, int roundingConfig, int thickness);
|
||||
|
||||
virtual CBox getBoundingBoxWl() const {
|
||||
return CBox();
|
||||
};
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos) {}
|
||||
virtual void onHover(const Vector2D& pos) {}
|
||||
bool containsPoint(const Vector2D& pos) const;
|
||||
|
||||
struct SFormatResult {
|
||||
std::string formatted;
|
||||
float updateEveryMs = 0; // 0 means don't (static)
|
||||
|
@ -26,4 +40,10 @@ class IWidget {
|
|||
};
|
||||
|
||||
static SFormatResult formatString(std::string in);
|
||||
|
||||
void setHover(bool hover);
|
||||
bool isHovered() const;
|
||||
|
||||
private:
|
||||
bool hovered = false;
|
||||
};
|
||||
|
|
|
@ -6,35 +6,33 @@
|
|||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include <cmath>
|
||||
#include <hyprlang.hpp>
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
|
||||
CImage::~CImage() {
|
||||
if (imageTimer) {
|
||||
imageTimer->cancel();
|
||||
imageTimer.reset();
|
||||
reset();
|
||||
}
|
||||
|
||||
void CImage::registerSelf(const SP<CImage>& self) {
|
||||
m_self = self;
|
||||
}
|
||||
|
||||
static void onTimer(WP<CImage> ref) {
|
||||
if (auto PIMAGE = ref.lock(); PIMAGE) {
|
||||
PIMAGE->onTimerUpdate();
|
||||
PIMAGE->plantTimer();
|
||||
}
|
||||
}
|
||||
|
||||
static void onTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||
const auto PIMAGE = (CImage*)data;
|
||||
|
||||
PIMAGE->onTimerUpdate();
|
||||
PIMAGE->plantTimer();
|
||||
}
|
||||
|
||||
static void onAssetCallback(void* data) {
|
||||
const auto PIMAGE = (CImage*)data;
|
||||
PIMAGE->renderUpdate();
|
||||
}
|
||||
|
||||
static void onAssetCallbackTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||
onAssetCallback(data);
|
||||
static void onAssetCallback(WP<CImage> ref) {
|
||||
if (auto PIMAGE = ref.lock(); PIMAGE)
|
||||
PIMAGE->renderUpdate();
|
||||
}
|
||||
|
||||
void CImage::onTimerUpdate() {
|
||||
const std::string OLDPATH = path;
|
||||
|
||||
if (!reloadCommand.empty()) {
|
||||
path = g_pHyprlock->spawnSync(reloadCommand);
|
||||
path = spawnSync(reloadCommand);
|
||||
|
||||
if (path.ends_with('\n'))
|
||||
path.pop_back();
|
||||
|
@ -65,9 +63,7 @@ void CImage::onTimerUpdate() {
|
|||
pendingResourceID = request.id;
|
||||
request.asset = path;
|
||||
request.type = CAsyncResourceGatherer::eTargetType::TARGET_IMAGE;
|
||||
|
||||
request.callback = onAssetCallback;
|
||||
request.callbackData = this;
|
||||
request.callback = [REF = m_self]() { onAssetCallback(REF); };
|
||||
|
||||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||
}
|
||||
|
@ -75,34 +71,41 @@ void CImage::onTimerUpdate() {
|
|||
void CImage::plantTimer() {
|
||||
|
||||
if (reloadTime == 0) {
|
||||
imageTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onTimer, this, true);
|
||||
imageTimer = g_pHyprlock->addTimer(std::chrono::hours(1), [REF = m_self](auto, auto) { onTimer(REF); }, nullptr, true);
|
||||
} else if (reloadTime > 0)
|
||||
imageTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), onTimer, this, false);
|
||||
imageTimer = g_pHyprlock->addTimer(std::chrono::seconds(reloadTime), [REF = m_self](auto, auto) { onTimer(REF); }, nullptr, false);
|
||||
}
|
||||
|
||||
CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& resourceID_, const std::unordered_map<std::string, std::any>& props) :
|
||||
viewport(viewport_), resourceID(resourceID_), output(output_), shadow(this, props, viewport_) {
|
||||
void CImage::configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput) {
|
||||
reset();
|
||||
|
||||
viewport = pOutput->getViewport();
|
||||
stringPort = pOutput->stringPort;
|
||||
|
||||
shadow.configure(m_self.lock(), props, viewport);
|
||||
|
||||
try {
|
||||
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
size = std::any_cast<Hyprlang::INT>(props.at("size"));
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
configPos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
|
||||
path = std::any_cast<Hyprlang::STRING>(props.at("path"));
|
||||
reloadTime = std::any_cast<Hyprlang::INT>(props.at("reload_time"));
|
||||
reloadCommand = std::any_cast<Hyprlang::STRING>(props.at("reload_cmd"));
|
||||
path = std::any_cast<Hyprlang::STRING>(props.at("path"));
|
||||
reloadTime = std::any_cast<Hyprlang::INT>(props.at("reload_time"));
|
||||
reloadCommand = std::any_cast<Hyprlang::STRING>(props.at("reload_cmd"));
|
||||
onclickCommand = std::any_cast<Hyprlang::STRING>(props.at("onclick"));
|
||||
} catch (const std::bad_any_cast& e) {
|
||||
RASSERT(false, "Failed to construct CImage: {}", e.what()); //
|
||||
} catch (const std::out_of_range& e) {
|
||||
RASSERT(false, "Missing propperty for CImage: {}", e.what()); //
|
||||
}
|
||||
|
||||
angle = angle * M_PI / 180.0;
|
||||
resourceID = "image:" + path;
|
||||
angle = angle * M_PI / 180.0;
|
||||
|
||||
if (reloadTime > -1) {
|
||||
try {
|
||||
|
@ -113,6 +116,25 @@ CImage::CImage(const Vector2D& viewport_, COutput* output_, const std::string& r
|
|||
}
|
||||
}
|
||||
|
||||
void CImage::reset() {
|
||||
if (imageTimer) {
|
||||
imageTimer->cancel();
|
||||
imageTimer.reset();
|
||||
}
|
||||
|
||||
if (g_pHyprlock->m_bTerminate)
|
||||
return;
|
||||
|
||||
imageFB.release();
|
||||
|
||||
if (asset && reloadTime > -1) // Don't unload asset if it's a static image
|
||||
g_pRenderer->asyncResourceGatherer->unloadAsset(asset);
|
||||
|
||||
asset = nullptr;
|
||||
pendingResourceID = "";
|
||||
resourceID = "";
|
||||
}
|
||||
|
||||
bool CImage::draw(const SRenderData& data) {
|
||||
|
||||
if (resourceID.empty())
|
||||
|
@ -176,10 +198,10 @@ bool CImage::draw(const SRenderData& data) {
|
|||
|
||||
shadow.draw(data);
|
||||
|
||||
const auto TEXPOS = posFromHVAlign(viewport, tex->m_vSize, pos, halign, valign, angle);
|
||||
pos = posFromHVAlign(viewport, tex->m_vSize, configPos, halign, valign, angle);
|
||||
|
||||
texbox.x = TEXPOS.x;
|
||||
texbox.y = TEXPOS.y;
|
||||
texbox.x = pos.x;
|
||||
texbox.y = pos.y;
|
||||
|
||||
texbox.round();
|
||||
texbox.rot = angle;
|
||||
|
@ -204,9 +226,32 @@ void CImage::renderUpdate() {
|
|||
pendingResourceID = "";
|
||||
} else if (!pendingResourceID.empty()) {
|
||||
Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID);
|
||||
pendingResourceID = "";
|
||||
} else if (!pendingResourceID.empty()) {
|
||||
Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID);
|
||||
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(100), onAssetCallbackTimer, this);
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(100), [REF = m_self](auto, auto) { onAssetCallback(REF); }, nullptr);
|
||||
}
|
||||
|
||||
g_pHyprlock->renderOutput(output->stringPort);
|
||||
g_pHyprlock->renderOutput(stringPort);
|
||||
}
|
||||
|
||||
CBox CImage::getBoundingBoxWl() const {
|
||||
if (!imageFB.isAllocated())
|
||||
return CBox{};
|
||||
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - imageFB.m_cTex.m_vSize.y},
|
||||
imageFB.m_cTex.m_vSize,
|
||||
};
|
||||
}
|
||||
|
||||
void CImage::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (down && !onclickCommand.empty())
|
||||
spawnAsync(onclickCommand);
|
||||
}
|
||||
|
||||
void CImage::onHover(const Vector2D& pos) {
|
||||
if (!onclickCommand.empty())
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER);
|
||||
}
|
||||
|
|
|
@ -17,16 +17,26 @@ class COutput;
|
|||
|
||||
class CImage : public IWidget {
|
||||
public:
|
||||
CImage(const Vector2D& viewport, COutput* output_, const std::string& resourceID, const std::unordered_map<std::string, std::any>& props);
|
||||
CImage() = default;
|
||||
~CImage();
|
||||
|
||||
void registerSelf(const SP<CImage>& self);
|
||||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
|
||||
void reset();
|
||||
|
||||
void renderUpdate();
|
||||
void onTimerUpdate();
|
||||
void plantTimer();
|
||||
|
||||
private:
|
||||
WP<CImage> m_self;
|
||||
|
||||
CFramebuffer imageFB;
|
||||
|
||||
int size;
|
||||
|
@ -35,6 +45,7 @@ class CImage : public IWidget {
|
|||
double angle;
|
||||
CGradientValueData color;
|
||||
Vector2D pos;
|
||||
Vector2D configPos;
|
||||
|
||||
std::string halign, valign, path;
|
||||
|
||||
|
@ -42,14 +53,17 @@ class CImage : public IWidget {
|
|||
|
||||
int reloadTime;
|
||||
std::string reloadCommand;
|
||||
std::string onclickCommand;
|
||||
|
||||
std::filesystem::file_time_type modificationTime;
|
||||
std::shared_ptr<CTimer> imageTimer;
|
||||
CAsyncResourceGatherer::SPreloadRequest request;
|
||||
|
||||
Vector2D viewport;
|
||||
std::string stringPort;
|
||||
|
||||
std::string resourceID;
|
||||
std::string pendingResourceID; // if reloading image
|
||||
SPreloadedAsset* asset = nullptr;
|
||||
COutput* output = nullptr;
|
||||
SPreloadedAsset* asset = nullptr;
|
||||
CShadowable shadow;
|
||||
};
|
||||
|
|
|
@ -3,36 +3,31 @@
|
|||
#include "../../helpers/Log.hpp"
|
||||
#include "../../core/hyprlock.hpp"
|
||||
#include "../../helpers/Color.hpp"
|
||||
#include "../../helpers/MiscFunctions.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include <hyprlang.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
CLabel::~CLabel() {
|
||||
if (labelTimer) {
|
||||
labelTimer->cancel();
|
||||
labelTimer.reset();
|
||||
reset();
|
||||
}
|
||||
|
||||
void CLabel::registerSelf(const SP<CLabel>& self) {
|
||||
m_self = self;
|
||||
}
|
||||
|
||||
static void onTimer(WP<CLabel> ref) {
|
||||
if (auto PLABEL = ref.lock(); PLABEL) {
|
||||
// update label
|
||||
PLABEL->onTimerUpdate();
|
||||
// plant new timer
|
||||
PLABEL->plantTimer();
|
||||
}
|
||||
}
|
||||
|
||||
static void onTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||
if (data == nullptr)
|
||||
return;
|
||||
const auto PLABEL = (CLabel*)data;
|
||||
|
||||
// update label
|
||||
PLABEL->onTimerUpdate();
|
||||
|
||||
// plant new timer
|
||||
PLABEL->plantTimer();
|
||||
}
|
||||
|
||||
static void onAssetCallback(void* data) {
|
||||
const auto PLABEL = (CLabel*)data;
|
||||
PLABEL->renderUpdate();
|
||||
}
|
||||
|
||||
static void onAssetCallbackTimer(std::shared_ptr<CTimer> self, void* data) {
|
||||
onAssetCallback(data);
|
||||
static void onAssetCallback(WP<CLabel> ref) {
|
||||
if (auto PLABEL = ref.lock(); PLABEL)
|
||||
PLABEL->renderUpdate();
|
||||
}
|
||||
|
||||
std::string CLabel::getUniqueResourceId() {
|
||||
|
@ -57,32 +52,39 @@ void CLabel::onTimerUpdate() {
|
|||
pendingResourceID = request.id;
|
||||
request.asset = label.formatted;
|
||||
|
||||
request.callback = onAssetCallback;
|
||||
request.callbackData = this;
|
||||
request.callback = [REF = m_self]() { onAssetCallback(REF); };
|
||||
|
||||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||
}
|
||||
|
||||
void CLabel::plantTimer() {
|
||||
|
||||
if (label.updateEveryMs != 0)
|
||||
labelTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)label.updateEveryMs), onTimer, this, label.allowForceUpdate);
|
||||
labelTimer = g_pHyprlock->addTimer(std::chrono::milliseconds((int)label.updateEveryMs), [REF = m_self](auto, auto) { onTimer(REF); }, this, label.allowForceUpdate);
|
||||
else if (label.updateEveryMs == 0 && label.allowForceUpdate)
|
||||
labelTimer = g_pHyprlock->addTimer(std::chrono::hours(1), onTimer, this, true);
|
||||
labelTimer = g_pHyprlock->addTimer(std::chrono::hours(1), [REF = m_self](auto, auto) { onTimer(REF); }, this, true);
|
||||
}
|
||||
|
||||
CLabel::CLabel(const Vector2D& viewport_, const std::unordered_map<std::string, std::any>& props, const std::string& output) :
|
||||
outputStringPort(output), shadow(this, props, viewport_) {
|
||||
void CLabel::configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput) {
|
||||
reset();
|
||||
|
||||
outputStringPort = pOutput->stringPort;
|
||||
viewport = pOutput->getViewport();
|
||||
|
||||
shadow.configure(m_self.lock(), props, viewport);
|
||||
|
||||
try {
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
||||
configPos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
labelPreFormat = std::any_cast<Hyprlang::STRING>(props.at("text"));
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
angle = angle * M_PI / 180.0;
|
||||
onclickCommand = std::any_cast<Hyprlang::STRING>(props.at("onclick"));
|
||||
|
||||
std::string textAlign = std::any_cast<Hyprlang::STRING>(props.at("text_align"));
|
||||
std::string fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
||||
CHyprColor labelColor = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||
CHyprColor labelColor = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||
int fontSize = std::any_cast<Hyprlang::INT>(props.at("font_size"));
|
||||
|
||||
label = formatString(labelPreFormat);
|
||||
|
@ -105,14 +107,30 @@ CLabel::CLabel(const Vector2D& viewport_, const std::unordered_map<std::string,
|
|||
RASSERT(false, "Missing property for CLabel: {}", e.what()); //
|
||||
}
|
||||
|
||||
configPos = pos;
|
||||
viewport = viewport_;
|
||||
pos = configPos; // Label size not known yet
|
||||
|
||||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||
|
||||
plantTimer();
|
||||
}
|
||||
|
||||
void CLabel::reset() {
|
||||
if (labelTimer) {
|
||||
labelTimer->cancel();
|
||||
labelTimer.reset();
|
||||
}
|
||||
|
||||
if (g_pHyprlock->m_bTerminate)
|
||||
return;
|
||||
|
||||
if (asset)
|
||||
g_pRenderer->asyncResourceGatherer->unloadAsset(asset);
|
||||
|
||||
asset = nullptr;
|
||||
pendingResourceID.clear();
|
||||
resourceID.clear();
|
||||
}
|
||||
|
||||
bool CLabel::draw(const SRenderData& data) {
|
||||
if (!asset) {
|
||||
asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID);
|
||||
|
@ -150,9 +168,29 @@ void CLabel::renderUpdate() {
|
|||
} else {
|
||||
Debug::log(WARN, "Asset {} not available after the asyncResourceGatherer's callback!", pendingResourceID);
|
||||
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(100), onAssetCallbackTimer, this);
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(100), [REF = m_self](auto, auto) { onAssetCallback(REF); }, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHyprlock->renderOutput(outputStringPort);
|
||||
}
|
||||
|
||||
CBox CLabel::getBoundingBoxWl() const {
|
||||
if (!asset)
|
||||
return CBox{};
|
||||
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - asset->texture.m_vSize.y},
|
||||
asset->texture.m_vSize,
|
||||
};
|
||||
}
|
||||
|
||||
void CLabel::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (down && !onclickCommand.empty())
|
||||
spawnAsync(onclickCommand);
|
||||
}
|
||||
|
||||
void CLabel::onHover(const Vector2D& pos) {
|
||||
if (!onclickCommand.empty())
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER);
|
||||
}
|
||||
|
|
|
@ -14,16 +14,26 @@ class CSessionLockSurface;
|
|||
|
||||
class CLabel : public IWidget {
|
||||
public:
|
||||
CLabel(const Vector2D& viewport, const std::unordered_map<std::string, std::any>& props, const std::string& output);
|
||||
CLabel() = default;
|
||||
~CLabel();
|
||||
|
||||
void registerSelf(const SP<CLabel>& self);
|
||||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
|
||||
void reset();
|
||||
|
||||
void renderUpdate();
|
||||
void onTimerUpdate();
|
||||
void plantTimer();
|
||||
|
||||
private:
|
||||
WP<CLabel> m_self;
|
||||
|
||||
std::string getUniqueResourceId();
|
||||
|
||||
std::string labelPreFormat;
|
||||
|
@ -36,6 +46,7 @@ class CLabel : public IWidget {
|
|||
std::string resourceID;
|
||||
std::string pendingResourceID; // if dynamic label
|
||||
std::string halign, valign;
|
||||
std::string onclickCommand;
|
||||
SPreloadedAsset* asset = nullptr;
|
||||
|
||||
std::string outputStringPort;
|
||||
|
|
|
@ -15,11 +15,25 @@
|
|||
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::unordered_map<std::string, std::any>& props, const std::string& output) :
|
||||
viewport(viewport_), outputStringPort(output), shadow(this, props, viewport_) {
|
||||
CPasswordInputField::~CPasswordInputField() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void CPasswordInputField::registerSelf(const SP<CPasswordInputField>& self) {
|
||||
m_self = self;
|
||||
}
|
||||
|
||||
void CPasswordInputField::configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput) {
|
||||
reset();
|
||||
|
||||
outputStringPort = pOutput->stringPort;
|
||||
viewport = pOutput->getViewport();
|
||||
|
||||
shadow.configure(m_self.lock(), props, viewport);
|
||||
|
||||
try {
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
||||
configSize = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_);
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
configSize = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
outThick = std::any_cast<Hyprlang::INT>(props.at("outline_thickness"));
|
||||
|
@ -34,7 +48,6 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
|||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
configPlaceholderText = std::any_cast<Hyprlang::STRING>(props.at("placeholder_text"));
|
||||
configFailText = std::any_cast<Hyprlang::STRING>(props.at("fail_text"));
|
||||
configFailTimeoutMs = std::any_cast<Hyprlang::INT>(props.at("fail_timeout"));
|
||||
fontFamily = std::any_cast<Hyprlang::STRING>(props.at("font_family"));
|
||||
colorConfig.outer = CGradientValueData::fromAnyPv(props.at("outer_color"));
|
||||
colorConfig.inner = std::any_cast<Hyprlang::INT>(props.at("inner_color"));
|
||||
|
@ -46,6 +59,7 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
|||
colorConfig.num = CGradientValueData::fromAnyPv(props.at("numlock_color"));
|
||||
colorConfig.invertNum = std::any_cast<Hyprlang::INT>(props.at("invert_numlock"));
|
||||
colorConfig.swapFont = std::any_cast<Hyprlang::INT>(props.at("swap_font_color"));
|
||||
colorConfig.hiddenBase = std::any_cast<Hyprlang::INT>(props.at("hide_input_base_color"));
|
||||
} catch (const std::bad_any_cast& e) {
|
||||
RASSERT(false, "Failed to construct CPasswordInputField: {}", e.what()); //
|
||||
} catch (const std::out_of_range& e) {
|
||||
|
@ -61,6 +75,16 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
|||
|
||||
colorConfig.caps = colorConfig.caps->m_bIsFallback ? colorConfig.fail : colorConfig.caps;
|
||||
|
||||
g_pAnimationManager->createAnimation(0.f, fade.a, g_pConfigManager->m_AnimationTree.getConfig("inputFieldFade"));
|
||||
g_pAnimationManager->createAnimation(0.f, dots.currentAmount, g_pConfigManager->m_AnimationTree.getConfig("inputFieldDots"));
|
||||
g_pAnimationManager->createAnimation(configSize, size, g_pConfigManager->m_AnimationTree.getConfig("inputFieldWidth"));
|
||||
g_pAnimationManager->createAnimation(colorConfig.inner, colorState.inner, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors"));
|
||||
g_pAnimationManager->createAnimation(*colorConfig.outer, colorState.outer, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors"));
|
||||
|
||||
srand(std::chrono::system_clock::now().time_since_epoch().count());
|
||||
|
||||
pos = posFromHVAlign(viewport, size->goal(), configPos, halign, valign);
|
||||
|
||||
if (!dots.textFormat.empty()) {
|
||||
dots.textResourceID = std::format("input:{}-{}", (uintptr_t)this, dots.textFormat);
|
||||
CAsyncResourceGatherer::SPreloadRequest request;
|
||||
|
@ -74,23 +98,30 @@ CPasswordInputField::CPasswordInputField(const Vector2D& viewport_, const std::u
|
|||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||
}
|
||||
|
||||
g_pAnimationManager->createAnimation(0.f, fade.a, g_pConfigManager->m_AnimationTree.getConfig("inputFieldFade"));
|
||||
g_pAnimationManager->createAnimation(0.f, dots.currentAmount, g_pConfigManager->m_AnimationTree.getConfig("inputFieldDots"));
|
||||
g_pAnimationManager->createAnimation(configSize, size, g_pConfigManager->m_AnimationTree.getConfig("inputFieldWidth"));
|
||||
|
||||
g_pAnimationManager->createAnimation(colorConfig.inner, colorState.inner, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors"));
|
||||
g_pAnimationManager->createAnimation(*colorConfig.outer, colorState.outer, g_pConfigManager->m_AnimationTree.getConfig("inputFieldColors"));
|
||||
|
||||
srand(std::chrono::system_clock::now().time_since_epoch().count());
|
||||
|
||||
// request the inital placeholder asset
|
||||
updatePlaceholder();
|
||||
}
|
||||
|
||||
static void fadeOutCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
CPasswordInputField* p = (CPasswordInputField*)data;
|
||||
void CPasswordInputField::reset() {
|
||||
if (fade.fadeOutTimer.get()) {
|
||||
fade.fadeOutTimer->cancel();
|
||||
fade.fadeOutTimer.reset();
|
||||
}
|
||||
|
||||
p->onFadeOutTimer();
|
||||
if (g_pHyprlock->m_bTerminate)
|
||||
return;
|
||||
|
||||
if (placeholder.asset)
|
||||
g_pRenderer->asyncResourceGatherer->unloadAsset(placeholder.asset);
|
||||
|
||||
placeholder.asset = nullptr;
|
||||
placeholder.resourceID.clear();
|
||||
placeholder.currentText.clear();
|
||||
}
|
||||
|
||||
static void fadeOutCallback(WP<CPasswordInputField> ref) {
|
||||
if (const auto PP = ref.lock(); PP)
|
||||
PP->onFadeOutTimer();
|
||||
}
|
||||
|
||||
void CPasswordInputField::onFadeOutTimer() {
|
||||
|
@ -121,7 +152,8 @@ void CPasswordInputField::updateFade() {
|
|||
*fade.a = 0.0;
|
||||
fade.allowFadeOut = false;
|
||||
} else if (!fade.fadeOutTimer.get())
|
||||
fade.fadeOutTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(fadeTimeoutMs), fadeOutCallback, this);
|
||||
fade.fadeOutTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(fadeTimeoutMs), [REF = m_self](auto, auto) { fadeOutCallback(REF); }, nullptr);
|
||||
|
||||
} else if (INPUTUSED && fade.a->goal() != 1.0)
|
||||
*fade.a = 1.0;
|
||||
|
||||
|
@ -133,6 +165,9 @@ void CPasswordInputField::updateDots() {
|
|||
if (dots.currentAmount->goal() == passwordLength)
|
||||
return;
|
||||
|
||||
if (checkWaiting)
|
||||
return;
|
||||
|
||||
if (passwordLength == 0)
|
||||
dots.currentAmount->setValueAndWarp(passwordLength);
|
||||
else
|
||||
|
@ -266,7 +301,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
}
|
||||
}
|
||||
|
||||
if (passwordLength == 0 && !placeholder.resourceID.empty()) {
|
||||
if (passwordLength == 0 && !checkWaiting && !placeholder.resourceID.empty()) {
|
||||
SPreloadedAsset* currAsset = nullptr;
|
||||
|
||||
if (!placeholder.asset)
|
||||
|
@ -291,13 +326,6 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
return redrawShadow || forceReload;
|
||||
}
|
||||
|
||||
static void failTimeoutCallback(std::shared_ptr<CTimer> self, void* data) {
|
||||
if (g_pAuth->m_bDisplayFailText) {
|
||||
g_pAuth->m_bDisplayFailText = false;
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
void CPasswordInputField::updatePlaceholder() {
|
||||
if (passwordLength != 0) {
|
||||
if (placeholder.asset && /* keep prompt asset cause it is likely to be used again */ displayFail) {
|
||||
|
@ -316,12 +344,7 @@ void CPasswordInputField::updatePlaceholder() {
|
|||
|
||||
placeholder.failedAttempts = g_pAuth->getFailedAttempts();
|
||||
|
||||
std::string newText;
|
||||
if (displayFail) {
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(configFailTimeoutMs), failTimeoutCallback, nullptr);
|
||||
newText = formatString(configFailText).formatted;
|
||||
} else
|
||||
newText = formatString(configPlaceholderText).formatted;
|
||||
std::string newText = (displayFail) ? formatString(configFailText).formatted : formatString(configPlaceholderText).formatted;
|
||||
|
||||
// if the text is unchanged we don't need to do anything, unless we are swapping font color
|
||||
const auto ALLOWCOLORSWAP = outThick == 0 && colorConfig.swapFont;
|
||||
|
@ -353,6 +376,10 @@ void CPasswordInputField::updatePlaceholder() {
|
|||
request.props["font_family"] = fontFamily;
|
||||
request.props["color"] = colorState.font;
|
||||
request.props["font_size"] = (int)size->value().y / 4;
|
||||
request.callback = [REF = m_self] {
|
||||
if (const auto SELF = REF.lock(); SELF)
|
||||
g_pHyprlock->renderOutput(SELF->outputStringPort);
|
||||
};
|
||||
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request);
|
||||
}
|
||||
|
||||
|
@ -385,7 +412,7 @@ void CPasswordInputField::updateHiddenInputState() {
|
|||
// randomize new thang
|
||||
hiddenInputState.lastPasswordLength = passwordLength;
|
||||
|
||||
const auto BASEOK = colorConfig.outer->m_vColors.front().asOkLab();
|
||||
const auto BASEOK = colorConfig.hiddenBase.asOkLab();
|
||||
|
||||
// convert to polar coordinates
|
||||
const auto OKICHCHROMA = std::sqrt(std::pow(BASEOK.a, 2) + std::pow(BASEOK.b, 2));
|
||||
|
@ -419,7 +446,7 @@ void CPasswordInputField::updateColors() {
|
|||
|
||||
if (checkWaiting)
|
||||
targetGrad = colorConfig.check;
|
||||
else if (displayFail)
|
||||
else if (displayFail && passwordLength == 0)
|
||||
targetGrad = colorConfig.fail;
|
||||
|
||||
CGradientValueData* outerTarget = colorConfig.outer;
|
||||
|
@ -446,3 +473,14 @@ void CPasswordInputField::updateColors() {
|
|||
|
||||
colorState.font = fontTarget;
|
||||
}
|
||||
|
||||
CBox CPasswordInputField::getBoundingBoxWl() const {
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - size->value().y},
|
||||
size->value(),
|
||||
};
|
||||
}
|
||||
|
||||
void CPasswordInputField::onHover(const Vector2D& pos) {
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "Shadowable.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include "../../helpers/AnimatedVariable.hpp"
|
||||
#include <chrono>
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
#include <vector>
|
||||
#include <any>
|
||||
#include <unordered_map>
|
||||
|
@ -16,37 +16,47 @@ struct SPreloadedAsset;
|
|||
|
||||
class CPasswordInputField : public IWidget {
|
||||
public:
|
||||
CPasswordInputField(const Vector2D& viewport, const std::unordered_map<std::string, std::any>& props, const std::string& output);
|
||||
CPasswordInputField() = default;
|
||||
virtual ~CPasswordInputField();
|
||||
|
||||
void registerSelf(const SP<CPasswordInputField>& self);
|
||||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
|
||||
void reset();
|
||||
void onFadeOutTimer();
|
||||
|
||||
private:
|
||||
void updateDots();
|
||||
void updateFade();
|
||||
void updatePlaceholder();
|
||||
void updateWidth();
|
||||
void updateHiddenInputState();
|
||||
void updateInputState();
|
||||
void updateColors();
|
||||
WP<CPasswordInputField> m_self;
|
||||
|
||||
bool firstRender = true;
|
||||
bool redrawShadow = false;
|
||||
bool checkWaiting = false;
|
||||
bool displayFail = false;
|
||||
void updateDots();
|
||||
void updateFade();
|
||||
void updatePlaceholder();
|
||||
void updateWidth();
|
||||
void updateHiddenInputState();
|
||||
void updateInputState();
|
||||
void updateColors();
|
||||
|
||||
size_t passwordLength = 0;
|
||||
bool firstRender = true;
|
||||
bool redrawShadow = false;
|
||||
bool checkWaiting = false;
|
||||
bool displayFail = false;
|
||||
|
||||
PHLANIMVAR<Vector2D> size;
|
||||
Vector2D pos;
|
||||
Vector2D viewport;
|
||||
Vector2D configPos;
|
||||
Vector2D configSize;
|
||||
size_t passwordLength = 0;
|
||||
|
||||
std::string halign, valign, configFailText, outputStringPort, configPlaceholderText, fontFamily;
|
||||
uint64_t configFailTimeoutMs = 2000;
|
||||
PHLANIMVAR<Vector2D> size;
|
||||
Vector2D pos;
|
||||
Vector2D viewport;
|
||||
Vector2D configPos;
|
||||
Vector2D configSize;
|
||||
|
||||
int outThick, rounding;
|
||||
std::string halign, valign, configFailText, outputStringPort, configPlaceholderText, fontFamily;
|
||||
uint64_t configFailTimeoutMs = 2000;
|
||||
|
||||
int outThick, rounding;
|
||||
|
||||
struct {
|
||||
PHLANIMVAR<float> currentAmount;
|
||||
|
@ -74,7 +84,6 @@ class CPasswordInputField : public IWidget {
|
|||
size_t failedAttempts = 0;
|
||||
|
||||
std::vector<std::string> registeredResourceIDs;
|
||||
|
||||
} placeholder;
|
||||
|
||||
struct {
|
||||
|
@ -94,6 +103,8 @@ class CPasswordInputField : public IWidget {
|
|||
CGradientValueData* num = nullptr;
|
||||
CGradientValueData* both = nullptr;
|
||||
|
||||
CHyprColor hiddenBase;
|
||||
|
||||
int transitionMs = 0;
|
||||
bool invertNum = false;
|
||||
bool swapFont = false;
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
#include "../Renderer.hpp"
|
||||
#include <hyprlang.hpp>
|
||||
|
||||
CShadowable::CShadowable(IWidget* widget_, const std::unordered_map<std::string, std::any>& props, const Vector2D& viewport_) : widget(widget_), viewport(viewport_) {
|
||||
void CShadowable::configure(WP<IWidget> widget_, const std::unordered_map<std::string, std::any>& props, const Vector2D& viewport_) {
|
||||
m_widget = widget_;
|
||||
viewport = viewport_;
|
||||
|
||||
size = std::any_cast<Hyprlang::INT>(props.at("shadow_size"));
|
||||
passes = std::any_cast<Hyprlang::INT>(props.at("shadow_passes"));
|
||||
color = std::any_cast<Hyprlang::INT>(props.at("shadow_color"));
|
||||
|
@ -10,6 +13,10 @@ CShadowable::CShadowable(IWidget* widget_, const std::unordered_map<std::string,
|
|||
}
|
||||
|
||||
void CShadowable::markShadowDirty() {
|
||||
const auto WIDGET = m_widget.lock();
|
||||
|
||||
if (!m_widget)
|
||||
return;
|
||||
|
||||
if (passes == 0)
|
||||
return;
|
||||
|
@ -22,7 +29,7 @@ void CShadowable::markShadowDirty() {
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
ignoreDraw = true;
|
||||
widget->draw(IWidget::SRenderData{.opacity = 1.0});
|
||||
WIDGET->draw(IWidget::SRenderData{.opacity = 1.0});
|
||||
ignoreDraw = false;
|
||||
|
||||
g_pRenderer->blurFB(shadowFB, CRenderer::SBlurParams{.size = size, .passes = passes, .colorize = color, .boostA = boostA});
|
||||
|
@ -31,7 +38,7 @@ void CShadowable::markShadowDirty() {
|
|||
}
|
||||
|
||||
bool CShadowable::draw(const IWidget::SRenderData& data) {
|
||||
if (passes == 0)
|
||||
if (!m_widget || passes == 0)
|
||||
return true;
|
||||
|
||||
if (!shadowFB.isAllocated() || ignoreDraw)
|
||||
|
@ -40,4 +47,4 @@ bool CShadowable::draw(const IWidget::SRenderData& data) {
|
|||
CBox box = {0, 0, viewport.x, viewport.y};
|
||||
g_pRenderer->renderTexture(box, shadowFB.m_cTex, data.opacity, 0, HYPRUTILS_TRANSFORM_NORMAL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,22 +11,24 @@
|
|||
|
||||
class CShadowable {
|
||||
public:
|
||||
CShadowable(IWidget* widget_, const std::unordered_map<std::string, std::any>& props, const Vector2D& viewport_ /* TODO: make this not the entire viewport */);
|
||||
virtual ~CShadowable() = default;
|
||||
CShadowable() = default;
|
||||
void configure(WP<IWidget> widget_, const std::unordered_map<std::string, std::any>& props, const Vector2D& viewport_ /* TODO: make this not the entire viewport */);
|
||||
|
||||
// instantly re-renders the shadow using the widget's draw() method
|
||||
void markShadowDirty();
|
||||
virtual bool draw(const IWidget::SRenderData& data);
|
||||
|
||||
private:
|
||||
IWidget* widget = nullptr;
|
||||
int size = 10;
|
||||
int passes = 4;
|
||||
float boostA = 1.0;
|
||||
CHyprColor color{0, 0, 0, 1.0};
|
||||
Vector2D viewport;
|
||||
WP<IWidget> m_widget;
|
||||
int size = 10;
|
||||
int passes = 4;
|
||||
float boostA = 1.0;
|
||||
CHyprColor color{0, 0, 0, 1.0};
|
||||
Vector2D viewport;
|
||||
|
||||
// to avoid recursive shadows
|
||||
bool ignoreDraw = false;
|
||||
|
||||
CFramebuffer shadowFB;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,30 +1,40 @@
|
|||
#include "Shape.hpp"
|
||||
#include "../Renderer.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include "../../core/hyprlock.hpp"
|
||||
#include "../../helpers/MiscFunctions.hpp"
|
||||
#include <cmath>
|
||||
#include <hyprlang.hpp>
|
||||
#include <sys/types.h>
|
||||
|
||||
CShape::CShape(const Vector2D& viewport_, const std::unordered_map<std::string, std::any>& props) : shadow(this, props, viewport_) {
|
||||
void CShape::registerSelf(const SP<CShape>& self) {
|
||||
m_self = self;
|
||||
}
|
||||
|
||||
void CShape::configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput) {
|
||||
viewport = pOutput->getViewport();
|
||||
|
||||
shadow.configure(m_self.lock(), props, viewport);
|
||||
|
||||
try {
|
||||
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport_);
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport_);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
xray = std::any_cast<Hyprlang::INT>(props.at("xray"));
|
||||
size = CLayoutValueData::fromAnyPv(props.at("size"))->getAbsolute(viewport);
|
||||
rounding = std::any_cast<Hyprlang::INT>(props.at("rounding"));
|
||||
border = std::any_cast<Hyprlang::INT>(props.at("border_size"));
|
||||
color = std::any_cast<Hyprlang::INT>(props.at("color"));
|
||||
borderGrad = *CGradientValueData::fromAnyPv(props.at("border_color"));
|
||||
pos = CLayoutValueData::fromAnyPv(props.at("position"))->getAbsolute(viewport);
|
||||
halign = std::any_cast<Hyprlang::STRING>(props.at("halign"));
|
||||
valign = std::any_cast<Hyprlang::STRING>(props.at("valign"));
|
||||
angle = std::any_cast<Hyprlang::FLOAT>(props.at("rotate"));
|
||||
xray = std::any_cast<Hyprlang::INT>(props.at("xray"));
|
||||
onclickCommand = std::any_cast<Hyprlang::STRING>(props.at("onclick"));
|
||||
} catch (const std::bad_any_cast& e) {
|
||||
RASSERT(false, "Failed to construct CShape: {}", e.what()); //
|
||||
} catch (const std::out_of_range& e) {
|
||||
RASSERT(false, "Missing property for CShape: {}", e.what()); //
|
||||
}
|
||||
|
||||
viewport = viewport_;
|
||||
angle = angle * M_PI / 180.0;
|
||||
angle = angle * M_PI / 180.0;
|
||||
|
||||
const Vector2D VBORDER = {border, border};
|
||||
const Vector2D REALSIZE = size + VBORDER * 2.0;
|
||||
|
@ -94,3 +104,19 @@ bool CShape::draw(const SRenderData& data) {
|
|||
|
||||
return data.opacity < 1.0;
|
||||
}
|
||||
CBox CShape::getBoundingBoxWl() const {
|
||||
return {
|
||||
Vector2D{pos.x, viewport.y - pos.y - size.y},
|
||||
size,
|
||||
};
|
||||
}
|
||||
|
||||
void CShape::onClick(uint32_t button, bool down, const Vector2D& pos) {
|
||||
if (down && !onclickCommand.empty())
|
||||
spawnAsync(onclickCommand);
|
||||
}
|
||||
|
||||
void CShape::onHover(const Vector2D& pos) {
|
||||
if (!onclickCommand.empty())
|
||||
g_pSeatManager->m_pCursorShape->setShape(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER);
|
||||
}
|
||||
|
|
|
@ -11,11 +11,20 @@
|
|||
|
||||
class CShape : public IWidget {
|
||||
public:
|
||||
CShape(const Vector2D& viewport, const std::unordered_map<std::string, std::any>& props);
|
||||
CShape() = default;
|
||||
virtual ~CShape() = default;
|
||||
|
||||
void registerSelf(const SP<CShape>& self);
|
||||
|
||||
virtual void configure(const std::unordered_map<std::string, std::any>& prop, const SP<COutput>& pOutput);
|
||||
virtual bool draw(const SRenderData& data);
|
||||
virtual CBox getBoundingBoxWl() const;
|
||||
virtual void onClick(uint32_t button, bool down, const Vector2D& pos);
|
||||
virtual void onHover(const Vector2D& pos);
|
||||
|
||||
private:
|
||||
WP<CShape> m_self;
|
||||
|
||||
CFramebuffer shapeFB;
|
||||
|
||||
int rounding;
|
||||
|
@ -32,6 +41,7 @@ class CShape : public IWidget {
|
|||
std::string halign, valign;
|
||||
|
||||
bool firstRender = true;
|
||||
std::string onclickCommand;
|
||||
|
||||
Vector2D viewport;
|
||||
CShadowable shadow;
|
||||
|
|
Loading…
Reference in a new issue