Compare commits

...

13 Commits

Author SHA1 Message Date
drendog 927231a117
Merge 712916a450 into ac11771348 2024-06-28 22:30:06 +02:00
Tom Englund ac11771348
core: fix a few ubsan issues reported at exit of hyprland (#6699)
* watchdog: dont detach and cause race condition

instead of detaching and causing a race condition on destruction where
the thread is alive and watchdog has been destroyed, check if its
joinable and join it on destruction.

causes heap use after free on exit of compositor.

* render: add checks for compositor shutting down

avoid member call on null pointer, if the g_pHyprRenderer is destroyed
we can call the member makeEGLCurrent on it, causes undefined behaviour
on destruction of the compositor/hyprrenderer.

found with ubsan.
2024-06-28 22:24:32 +02:00
Alexander f2dc48d92f
keybinds: never switch to another monitor with per_monitor (#6665)
Co-authored-by: Крылов Александр <aleksandr.krylov@hyperus.team>
2024-06-27 15:07:56 +02:00
outfoxxed e4d09aa3a9
sessionLock: focus lock on creation based on mouse position (#6658)
* sessionLock: focus lock on creation based on mouse position

* sessionLock: immediately unfocus any focused surfaces on lock
2024-06-25 23:22:38 +02:00
Vaxry c338acbb7d ime-relay: fix crash on nullptr surface focus 2024-06-25 22:46:36 +02:00
Vaxry 95782de966 renderer: don't use the surface counter in popup iterations
fixes #6663
2024-06-25 20:04:02 +02:00
Vaxry 3ba3d20ad3 pointer: round position when rendering software cursors
otherwise the image gets resampled and gets blurry
2024-06-25 18:44:54 +02:00
Vaxry 1d70962892 core: move to steady_clock where applicable
avoid issues when system clock gets desynchronized or changed
2024-06-25 16:05:47 +02:00
Mihai Fufezan 918d8340af
flake.lock: update 2024-06-25 15:06:02 +03:00
Vaxry 4f7113972e props: bump version to 0.41.2 2024-06-25 13:53:41 +02:00
Vaxry 8121e66f34 cmake: bump hyprutils dep to 0.1.5 2024-06-25 13:50:59 +02:00
Gregory 784c0b5ccb
keybinds: fix mouse pass (#6652)
* keybinds: fix mouse pass

* keybinds: keep mouse and keyboard focus separate after pass bind
2024-06-25 13:46:49 +02:00
outfoxxed eef207ce0a
output: fix cursors disappearing after dpms (#6659) 2024-06-25 12:55:54 +02:00
22 changed files with 71 additions and 57 deletions

View File

@ -113,7 +113,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET
wayland-server wayland-client wayland-cursor wayland-protocols
cairo pango pangocairo pixman-1
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.4
hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.5
)
find_package(hyprwayland-scanner 0.3.10 REQUIRED)

View File

@ -87,11 +87,11 @@
]
},
"locked": {
"lastModified": 1718804078,
"narHash": "sha256-CqRZne63BpYlPd/i8lXV0UInUt59oKogiwdVtBRHt60=",
"lastModified": 1719316102,
"narHash": "sha256-dmRz128j/lJmMuTYeCYPfSBRHHQO3VeH4PbmoyAhHzw=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "4f1351295c55a8f51219b25aa4a6497a067989d0",
"rev": "1f6bbec5954f623ff8d68e567bddcce97cd2f085",
"type": "github"
},
"original": {
@ -110,11 +110,11 @@
]
},
"locked": {
"lastModified": 1718119275,
"narHash": "sha256-nqDYXATNkyGXVmNMkT19fT4sjtSPBDS1LLOxa3Fueo4=",
"lastModified": 1719067853,
"narHash": "sha256-mAnZG/eQy72Fp1ImGtqCgUrDumnR1rMZv2E/zgP4U74=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "1419520d5f7f38d35e05504da5c1b38212a38525",
"rev": "914f083741e694092ee60a39d31f693d0a6dc734",
"type": "github"
},
"original": {
@ -125,11 +125,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1718530797,
"narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=",
"lastModified": 1719075281,
"narHash": "sha256-CyyxvOwFf12I91PBWz43iGT1kjsf5oi6ax7CrvaMyAo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b60ebf54c15553b393d144357375ea956f89e9a9",
"rev": "a71e967ef3694799d0c418c98332f7ff4cc5f6af",
"type": "github"
},
"original": {

View File

@ -1,3 +1,3 @@
{
"version": "0.41.1"
"version": "0.41.2"
}

View File

@ -19,7 +19,7 @@
static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static auto firstMonitorAdded = std::chrono::system_clock::now();
static auto firstMonitorAdded = std::chrono::steady_clock::now();
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
@ -37,7 +37,7 @@ static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitor
return;
// after 10s, don't set cursor to default monitor
auto timePassedSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - firstMonitorAdded);
auto timePassedSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - firstMonitorAdded);
if (timePassedSec.count() > 10) {
cursorDefaultDone = true;
return;

View File

@ -57,11 +57,11 @@ void CBaseAnimatedVariable::registerVar() {
int CBaseAnimatedVariable::getDurationLeftMs() {
return std::max(
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count(), 0);
}
float CBaseAnimatedVariable::getPercent() {
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count();
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count();
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
}

View File

@ -155,7 +155,7 @@ class CBaseAnimatedVariable {
bool m_bIsRegistered = false;
bool m_bIsBeingAnimated = false;
std::chrono::system_clock::time_point animationBegin;
std::chrono::steady_clock::time_point animationBegin;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
ANIMATEDVARTYPE m_Type;
@ -253,7 +253,7 @@ class CAnimatedVariable : public CBaseAnimatedVariable {
return *this;
m_Goal = v;
animationBegin = std::chrono::system_clock::now();
animationBegin = std::chrono::steady_clock::now();
m_Begun = m_Value;
onAnimationBegin();
@ -267,7 +267,7 @@ class CAnimatedVariable : public CBaseAnimatedVariable {
return;
m_Value = v;
animationBegin = std::chrono::system_clock::now();
animationBegin = std::chrono::steady_clock::now();
m_Begun = m_Value;
onAnimationBegin();

View File

@ -1,11 +1,11 @@
#include "Timer.hpp"
void CTimer::reset() {
m_tpLastReset = std::chrono::system_clock::now();
m_tpLastReset = std::chrono::steady_clock::now();
}
std::chrono::system_clock::duration CTimer::getDuration() {
return std::chrono::system_clock::now() - m_tpLastReset;
std::chrono::steady_clock::duration CTimer::getDuration() {
return std::chrono::steady_clock::now() - m_tpLastReset;
}
int CTimer::getMillis() {
@ -16,6 +16,6 @@ float CTimer::getSeconds() {
return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count() / 1000.f;
}
const std::chrono::system_clock::time_point& CTimer::chrono() const {
const std::chrono::steady_clock::time_point& CTimer::chrono() const {
return m_tpLastReset;
}

View File

@ -7,10 +7,10 @@ class CTimer {
void reset();
float getSeconds();
int getMillis();
const std::chrono::system_clock::time_point& chrono() const;
const std::chrono::steady_clock::time_point& chrono() const;
private:
std::chrono::system_clock::time_point m_tpLastReset;
std::chrono::steady_clock::time_point m_tpLastReset;
std::chrono::system_clock::duration getDuration();
std::chrono::steady_clock::duration getDuration();
};

View File

@ -7,7 +7,9 @@ CWatchdog::~CWatchdog() {
m_bExitThread = true;
m_bNotified = true;
m_cvWatchdogCondition.notify_all();
m_pWatchdog.reset();
if (m_pWatchdog && m_pWatchdog->joinable())
m_pWatchdog->join();
}
CWatchdog::CWatchdog() {
@ -33,8 +35,6 @@ CWatchdog::CWatchdog() {
m_bNotified = false;
}
});
m_pWatchdog->detach();
}
void CWatchdog::startWatching() {

View File

@ -552,7 +552,7 @@ void CAnimationManager::scheduleTick() {
float refreshDelayMs = std::floor(1000.f / PMOSTHZ->refreshRate);
const float SINCEPRES = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f;
const float SINCEPRES = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f;
const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it

View File

@ -5,6 +5,7 @@
#include "../protocols/ShortcutsInhibit.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "KeybindManager.hpp"
#include "PointerManager.hpp"
#include "Compositor.hpp"
#include "TokenManager.hpp"
#include "debug/Log.hpp"
@ -1039,7 +1040,8 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU
return getWorkspaceIDNameFromString(args);
}
const SWorkspaceIDName PPREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(args.contains("_per_monitor"));
const bool PER_MON = args.contains("_per_monitor");
const SWorkspaceIDName PPREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(PER_MON);
// Do nothing if there's no previous workspace, otherwise switch to it.
if (PPREVWS.id == -1) {
Debug::log(LOG, "No previous workspace to change to");
@ -1047,8 +1049,11 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU
}
const auto ID = PCURRENTWORKSPACE->m_iID;
if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO)
if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) {
if (PER_MON && PCURRENTWORKSPACE->m_iMonitorID != PWORKSPACETOCHANGETO->m_iMonitorID)
return {WORKSPACE_NOT_CHANGED, ""};
return {ID, PWORKSPACETOCHANGETO->m_szName};
}
return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name};
}
@ -1677,7 +1682,6 @@ void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
// get the current workspace
const auto PCURRENTWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (!PCURRENTWORKSPACE) {
Debug::log(ERR, "moveCurrentWorkspaceToMonitor invalid workspace!");
return;
@ -2024,8 +2028,9 @@ void CKeybindManager::pass(std::string regexp) {
return;
}
const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11;
const auto LASTSRF = g_pCompositor->m_pLastFocus.lock();
const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11;
const auto LASTMOUSESURF = g_pSeatManager->state.pointerFocus.lock();
const auto LASTKBSURF = g_pSeatManager->state.keyboardFocus.lock();
// pass all mf shit
if (!XWTOXW) {
@ -2077,9 +2082,9 @@ void CKeybindManager::pass(std::string regexp) {
const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal();
if (g_pKeybindManager->m_uLastCode != 0)
g_pSeatManager->setKeyboardFocus(LASTSRF);
g_pSeatManager->setKeyboardFocus(LASTKBSURF);
else
g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), SL);
g_pSeatManager->setPointerFocus(LASTMOUSESURF, SL);
}
void CKeybindManager::sendshortcut(std::string args) {
@ -2280,6 +2285,8 @@ void CKeybindManager::dpms(std::string arg) {
}
g_pCompositor->m_bDPMSStateON = enable;
g_pPointerManager->recheckEnteredOutputs();
}
void CKeybindManager::swapnext(std::string arg) {

View File

@ -576,6 +576,8 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec*
return;
box.scale(pMonitor->scale);
box.x = std::round(box.x);
box.y = std::round(box.y);
g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F);

View File

@ -59,6 +59,8 @@ class CPointerManager {
Vector2D position();
Vector2D cursorSizeLogical();
void recheckEnteredOutputs();
private:
void recheckPointerPosition();
void onMonitorLayoutChange();
@ -67,7 +69,6 @@ class CPointerManager {
void onCursorMoved();
bool hasCursor();
void damageIfSoftware();
void recheckEnteredOutputs();
// closest valid point to a given one
Vector2D closestValid(const Vector2D& pos);

View File

@ -10,7 +10,7 @@ SSessionLockSurface::SSessionLockSurface(SP<CSessionLockSurface> surface_) : sur
listeners.map = surface_->events.map.registerListener([this](std::any data) {
mapped = true;
g_pCompositor->focusSurface(surface->surface());
g_pInputManager->simulateMouseMovement();
const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID);
@ -78,6 +78,7 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
});
pLock->sendLocked();
g_pCompositor->focusSurface(nullptr);
}
bool CSessionLockManager::isSessionLocked() {

View File

@ -2,8 +2,8 @@
#include <uuid/uuid.h>
#include <algorithm>
CUUIDToken::CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::system_clock::duration expires) : data(data_), uuid(uuid_) {
expiresAt = std::chrono::system_clock::now() + expires;
CUUIDToken::CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::steady_clock::duration expires) : data(data_), uuid(uuid_) {
expiresAt = std::chrono::steady_clock::now() + expires;
}
std::string CUUIDToken::getUUID() {
@ -23,7 +23,7 @@ std::string CTokenManager::getRandomUUID() {
return uuid;
}
std::string CTokenManager::registerNewToken(std::any data, std::chrono::system_clock::duration expires) {
std::string CTokenManager::registerNewToken(std::any data, std::chrono::steady_clock::duration expires) {
std::string uuid = getRandomUUID();
m_mTokens[uuid] = makeShared<CUUIDToken>(uuid, data, expires);
@ -33,7 +33,7 @@ std::string CTokenManager::registerNewToken(std::any data, std::chrono::system_c
SP<CUUIDToken> CTokenManager::getToken(const std::string& uuid) {
// cleanup expired tokens
const auto NOW = std::chrono::system_clock::now();
const auto NOW = std::chrono::steady_clock::now();
std::erase_if(m_mTokens, [this, &NOW](const auto& el) { return el.second->expiresAt < NOW; });
if (!m_mTokens.contains(uuid))

View File

@ -9,7 +9,7 @@
class CUUIDToken {
public:
CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::system_clock::duration expires);
CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::steady_clock::duration expires);
std::string getUUID();
@ -18,14 +18,14 @@ class CUUIDToken {
private:
std::string uuid;
std::chrono::system_clock::time_point expiresAt;
std::chrono::steady_clock::time_point expiresAt;
friend class CTokenManager;
};
class CTokenManager {
public:
std::string registerNewToken(std::any data, std::chrono::system_clock::duration expires);
std::string registerNewToken(std::any data, std::chrono::steady_clock::duration expires);
std::string getRandomUUID();
SP<CUUIDToken> getToken(const std::string& uuid);

View File

@ -2,23 +2,23 @@
#include <limits>
#include "EventLoopManager.hpp"
CEventLoopTimer::CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(SP<CEventLoopTimer> self, void* data)> cb_, void* data_) :
CEventLoopTimer::CEventLoopTimer(std::optional<std::chrono::steady_clock::duration> timeout, std::function<void(SP<CEventLoopTimer> self, void* data)> cb_, void* data_) :
cb(cb_), data(data_) {
if (!timeout.has_value())
expires.reset();
else
expires = std::chrono::system_clock::now() + *timeout;
expires = std::chrono::steady_clock::now() + *timeout;
}
void CEventLoopTimer::updateTimeout(std::optional<std::chrono::system_clock::duration> timeout) {
void CEventLoopTimer::updateTimeout(std::optional<std::chrono::steady_clock::duration> timeout) {
if (!timeout.has_value()) {
expires.reset();
g_pEventLoopManager->nudgeTimers();
return;
}
expires = std::chrono::system_clock::now() + *timeout;
expires = std::chrono::steady_clock::now() + *timeout;
g_pEventLoopManager->nudgeTimers();
}
@ -26,7 +26,7 @@ void CEventLoopTimer::updateTimeout(std::optional<std::chrono::system_clock::dur
bool CEventLoopTimer::passed() {
if (!expires.has_value())
return false;
return std::chrono::system_clock::now() > *expires;
return std::chrono::steady_clock::now() > *expires;
}
void CEventLoopTimer::cancel() {
@ -47,5 +47,5 @@ float CEventLoopTimer::leftUs() {
if (!expires.has_value())
return std::numeric_limits<float>::max();
return std::chrono::duration_cast<std::chrono::microseconds>(*expires - std::chrono::system_clock::now()).count();
return std::chrono::duration_cast<std::chrono::microseconds>(*expires - std::chrono::steady_clock::now()).count();
}

View File

@ -8,11 +8,11 @@
class CEventLoopTimer {
public:
CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(SP<CEventLoopTimer> self, void* data)> cb_, void* data_);
CEventLoopTimer(std::optional<std::chrono::steady_clock::duration> timeout, std::function<void(SP<CEventLoopTimer> self, void* data)> cb_, void* data_);
// if not specified, disarms.
// if specified, arms.
void updateTimeout(std::optional<std::chrono::system_clock::duration> timeout);
void updateTimeout(std::optional<std::chrono::steady_clock::duration> timeout);
void cancel();
bool passed();
@ -26,6 +26,6 @@ class CEventLoopTimer {
private:
std::function<void(SP<CEventLoopTimer> self, void* data)> cb;
void* data = nullptr;
std::optional<std::chrono::system_clock::time_point> expires;
std::optional<std::chrono::steady_clock::time_point> expires;
bool wasCancelled = false;
};

View File

@ -143,6 +143,9 @@ void CInputMethodRelay::onKeyboardFocus(SP<CWLSurfaceResource> pSurface) {
ti->leave();
}
if (!pSurface)
return;
for (auto& ti : m_vTextInputs) {
if (!ti->isV3())
continue;

View File

@ -6,7 +6,7 @@
#include <dlfcn.h>
CRenderbuffer::~CRenderbuffer() {
if (!g_pCompositor)
if (!g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer)
return;
g_pHyprRenderer->makeEGLCurrent();

View File

@ -212,7 +212,7 @@ static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* da
// FIXME: This is wrong and will bug the blur out as shit if the first surface
// is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back
// to what we do for misaligned surfaces (blur the entire thing and then render shit without blur)
if (RDATA->surfaceCounter == 0) {
if (RDATA->surfaceCounter == 0 && !RDATA->popup) {
if (RDATA->blur)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha);
else

View File

@ -9,7 +9,7 @@ CTexture::CTexture() {
}
CTexture::~CTexture() {
if (m_bNonOwning)
if (m_bNonOwning || !g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer)
return;
g_pHyprRenderer->makeEGLCurrent();