From 640d1618519d42dd592f7af5e9984ad52eb8b820 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:52:19 +0100 Subject: [PATCH 001/298] renderer: Explicit sync fixes (#7151) Enables explicit sync by default for most platforms `misc:no_direct_scanout` -> `render:direct_scanout` --- src/Compositor.cpp | 4 +- src/config/ConfigManager.cpp | 17 ++- src/helpers/Monitor.cpp | 64 +++++++++- src/helpers/Monitor.hpp | 3 +- src/helpers/ScopeGuard.cpp | 10 ++ src/helpers/ScopeGuard.hpp | 13 ++ src/helpers/sync/SyncReleaser.cpp | 25 ++++ src/helpers/sync/SyncReleaser.hpp | 31 +++++ src/helpers/sync/SyncTimeline.cpp | 5 + src/helpers/sync/SyncTimeline.hpp | 1 + src/managers/KeybindManager.cpp | 1 + src/managers/ProtocolManager.cpp | 2 +- src/protocols/DRMSyncobj.cpp | 53 ++++++--- src/protocols/DRMSyncobj.hpp | 11 +- src/protocols/core/Compositor.cpp | 17 +-- src/protocols/core/Compositor.hpp | 5 +- src/protocols/types/Buffer.cpp | 25 +--- src/protocols/types/Buffer.hpp | 12 +- src/protocols/types/WLBuffer.cpp | 10 -- src/protocols/types/WLBuffer.hpp | 1 - src/render/OpenGL.cpp | 32 ++--- src/render/OpenGL.hpp | 4 +- src/render/Renderer.cpp | 191 +++++++++++++++++++----------- src/render/Renderer.hpp | 6 + 24 files changed, 378 insertions(+), 165 deletions(-) create mode 100644 src/helpers/ScopeGuard.cpp create mode 100644 src/helpers/ScopeGuard.hpp create mode 100644 src/helpers/sync/SyncReleaser.cpp create mode 100644 src/helpers/sync/SyncReleaser.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a139742c..299a16c6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2282,7 +2282,7 @@ void CCompositor::setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFull } void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenState state) { - static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); + static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); if (!validMapped(PWINDOW) || g_pCompositor->m_bUnsafeState) return; @@ -2342,7 +2342,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. // ignore if DS is disabled. - if (!*PNODIRECTSCANOUT) + if (*PDIRECTSCANOUT) g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fe3af8c0..be6433fa 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -3,6 +3,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "config/ConfigDataValues.hpp" +#include "config/ConfigValue.hpp" #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" @@ -346,7 +347,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0}); - m_pConfig->addConfigValue("misc:no_direct_scanout", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1}); @@ -560,7 +560,9 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"}); - m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0}); + m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2}); + m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2}); + m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0}); // devices m_pConfig->addSpecialCategory("device", {"name"}); @@ -798,6 +800,9 @@ std::optional CConfigManager::resetHLConfig() { } void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { + static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static int prevEnabledExplicit = *PENABLEEXPLICIT; + for (auto& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); } @@ -816,6 +821,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { if (!isFirstLaunch) g_pHyprOpenGL->m_bReloadScreenShader = true; + if (!isFirstLaunch && *PENABLEEXPLICIT != prevEnabledExplicit) + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); + // parseError will be displayed next frame if (result.error) @@ -1417,7 +1425,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { if (USEVRR == 0) { if (m->vrrActive) { - + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(false); if (!m->state.commit()) @@ -1427,6 +1435,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { return; } else if (USEVRR == 1) { if (!m->vrrActive) { + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(true); if (!m->state.test()) { @@ -1451,6 +1460,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN); if (WORKSPACEFULL) { + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(true); if (!m->state.test()) { @@ -1462,6 +1472,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); } else if (!WORKSPACEFULL) { + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(false); if (!m->state.commit()) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 1cf1b069..8f23c462 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1,6 +1,8 @@ #include "Monitor.hpp" #include "MiscFunctions.hpp" #include "math/Math.hpp" +#include "sync/SyncReleaser.hpp" +#include "ScopeGuard.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" @@ -8,6 +10,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/DRMLease.hpp" +#include "../protocols/DRMSyncobj.hpp" #include "../protocols/core/Output.hpp" #include "../managers/PointerManager.hpp" #include "../protocols/core/Compositor.hpp" @@ -77,6 +80,7 @@ void CMonitor::onConnect(bool noRule) { tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; if (m_bEnabled) { + output->state->resetExplicitFences(); output->state->setEnabled(true); state.commit(); return; @@ -101,6 +105,7 @@ void CMonitor::onConnect(bool noRule) { // if it's disabled, disable and ignore if (monitorRule.disabled) { + output->state->resetExplicitFences(); output->state->setEnabled(false); if (!state.commit()) @@ -137,6 +142,7 @@ void CMonitor::onConnect(bool noRule) { m_bEnabled = true; + output->state->resetExplicitFences(); output->state->setEnabled(true); // set mode, also applies @@ -300,6 +306,7 @@ void CMonitor::onDisconnect(bool destroy) { activeWorkspace->m_bVisible = false; activeWorkspace.reset(); + output->state->resetExplicitFences(); output->state->setEnabled(false); if (!state.commit()) @@ -808,28 +815,77 @@ bool CMonitor::attemptDirectScanout() { if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */) return false; + Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get()); + // FIXME: make sure the buffer actually follows the available scanout dmabuf formats // and comes from the appropriate device. This may implode on multi-gpu!! output->state->setBuffer(PSURFACE->current.buffer->buffer.lock()); output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); - if (!state.test()) + if (!state.test()) { + Debug::log(TRACE, "attemptDirectScanout: failed basic test"); return false; + } + + auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(); + + // wait for the explicit fence if present, and if kms explicit is allowed + bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; + int explicitWaitFD = -1; + if (DOEXPLICIT) { + explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint); + if (explicitWaitFD < 0) + Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd"); + } + DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0; + + auto cleanup = CScopeGuard([explicitWaitFD, this]() { + output->state->resetExplicitFences(); + if (explicitWaitFD >= 0) + close(explicitWaitFD); + }); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - Debug::log(TRACE, "presentFeedback for DS"); - PSURFACE->presentFeedback(&now, this, true); + PSURFACE->presentFeedback(&now, this); output->state->addDamage(CBox{{}, vecPixelSize}); + output->state->resetExplicitFences(); - if (state.commit()) { + if (DOEXPLICIT) { + Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD); + output->state->setExplicitInFence(explicitWaitFD); + } + + bool ok = output->commit(); + + if (!ok && DOEXPLICIT) { + Debug::log(TRACE, "attemptDirectScanout: EXPLICIT SYNC FAILED: commit() returned false. Resetting fences and retrying, might result in glitches."); + output->state->resetExplicitFences(); + + ok = output->commit(); + } + + if (ok) { if (lastScanout.expired()) { lastScanout = PCANDIDATE; Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); } + + // delay explicit sync feedback until kms release of the buffer + if (DOEXPLICIT) { + Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release"); + PSURFACE->current.buffer->releaser->drop(); + + PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) { + const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline; + if (DOEXPLICIT) + PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint); + }); + } } else { + Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface"); lastScanout.reset(); return false; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 32fc768a..fbe26f67 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -121,8 +121,7 @@ class CMonitor { // explicit sync SP inTimeline; SP outTimeline; - uint64_t lastWaitPoint = 0; - uint64_t commitSeq = 0; + uint64_t commitSeq = 0; WP self; diff --git a/src/helpers/ScopeGuard.cpp b/src/helpers/ScopeGuard.cpp new file mode 100644 index 00000000..319255cd --- /dev/null +++ b/src/helpers/ScopeGuard.cpp @@ -0,0 +1,10 @@ +#include "ScopeGuard.hpp" + +CScopeGuard::CScopeGuard(const std::function& fn_) : fn(fn_) { + ; +} + +CScopeGuard::~CScopeGuard() { + if (fn) + fn(); +} diff --git a/src/helpers/ScopeGuard.hpp b/src/helpers/ScopeGuard.hpp new file mode 100644 index 00000000..8a1468eb --- /dev/null +++ b/src/helpers/ScopeGuard.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +// calls a function when it goes out of scope +class CScopeGuard { + public: + CScopeGuard(const std::function& fn_); + ~CScopeGuard(); + + private: + std::function fn; +}; diff --git a/src/helpers/sync/SyncReleaser.cpp b/src/helpers/sync/SyncReleaser.cpp new file mode 100644 index 00000000..198495ab --- /dev/null +++ b/src/helpers/sync/SyncReleaser.cpp @@ -0,0 +1,25 @@ +#include "SyncReleaser.hpp" +#include "SyncTimeline.hpp" +#include "../../render/OpenGL.hpp" + +CSyncReleaser::CSyncReleaser(WP timeline_, uint64_t point_) : timeline(timeline_), point(point_) { + ; +} + +CSyncReleaser::~CSyncReleaser() { + if (timeline.expired()) + return; + + if (sync) + timeline->importFromSyncFileFD(point, sync->fd()); + else + timeline->signal(point); +} + +void CSyncReleaser::addReleaseSync(SP sync_) { + sync = sync_; +} + +void CSyncReleaser::drop() { + timeline.reset(); +} \ No newline at end of file diff --git a/src/helpers/sync/SyncReleaser.hpp b/src/helpers/sync/SyncReleaser.hpp new file mode 100644 index 00000000..e21d2e34 --- /dev/null +++ b/src/helpers/sync/SyncReleaser.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include +#include "../memory/Memory.hpp" + +/* + A helper (inspired by KDE's KWin) that will release the timeline point in the dtor +*/ + +class CSyncTimeline; +class CEGLSync; + +class CSyncReleaser { + public: + CSyncReleaser(WP timeline_, uint64_t point_); + ~CSyncReleaser(); + + // drops the releaser, will never signal anymore + void drop(); + + // wait for this gpu job to finish before releasing + void addReleaseSync(SP sync); + + private: + WP timeline; + uint64_t point = 0; + SP sync; +}; diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index 352120ea..16b5bd92 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -188,3 +188,8 @@ bool CSyncTimeline::transfer(SP from, uint64_t fromPoint, uint64_ return true; } + +void CSyncTimeline::signal(uint64_t point) { + if (drmSyncobjTimelineSignal(drmFD, &handle, &point, 1)) + Debug::log(ERR, "CSyncTimeline::signal: drmSyncobjTimelineSignal failed"); +} diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp index 3d868a95..88ad4921 100644 --- a/src/helpers/sync/SyncTimeline.hpp +++ b/src/helpers/sync/SyncTimeline.hpp @@ -35,6 +35,7 @@ class CSyncTimeline { int exportAsSyncFileFD(uint64_t src); bool importFromSyncFileFD(uint64_t dst, int fd); bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + void signal(uint64_t point); int drmFD = -1; uint32_t handle = 0; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 09ba7d50..08c6998d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2293,6 +2293,7 @@ void CKeybindManager::dpms(std::string arg) { if (!port.empty() && m->szName != port) continue; + m->output->state->resetExplicitFences(); m->output->state->setEnabled(enable); m->dpmsStatus = enable; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 635e6223..6e5cd16f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -76,7 +76,7 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { CProtocolManager::CProtocolManager() { - static const auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 33339554..8b0330de 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -24,9 +24,9 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPsetSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { @@ -35,29 +35,33 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPevents.precommit.registerListener([this](std::any d) { - if (!!acquireTimeline != !!releaseTimeline) { - resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline"); - surface->pending.rejected = true; - return; - } - - if ((acquireTimeline || releaseTimeline) && !surface->pending.texture) { + if ((pending.acquireTimeline || pending.releaseTimeline) && !surface->pending.texture) { resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); surface->pending.rejected = true; return; } - if (!acquireTimeline) + if (!surface->pending.newBuffer) + return; // this commit does not change the state here + + if (!!pending.acquireTimeline != !!pending.releaseTimeline) { + resource->error(pending.acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, + "Missing timeline"); + surface->pending.rejected = true; + return; + } + + if (!pending.acquireTimeline) return; // wait for the acquire timeline to materialize - auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); if (!materialized.has_value()) { LOGM(ERR, "Failed to check the acquire timeline"); resource->noMemory(); @@ -68,7 +72,24 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); - acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + }); + + listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) { + // apply timelines if new ones have been attached, otherwise don't touch + // the current ones + if (pending.releaseTimeline) { + current.releaseTimeline = pending.releaseTimeline; + current.releasePoint = pending.releasePoint; + } + + if (pending.acquireTimeline) { + current.acquireTimeline = pending.acquireTimeline; + current.acquirePoint = pending.acquirePoint; + } + + pending.releaseTimeline.reset(); + pending.acquireTimeline.reset(); }); } diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index c1c884ff..25dc10c1 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -14,17 +14,20 @@ class CDRMSyncobjSurfaceResource { public: CDRMSyncobjSurfaceResource(SP resource_, SP surface_); - bool good(); + bool good(); - WP surface; - WP acquireTimeline, releaseTimeline; - uint64_t acquirePoint = 0, releasePoint = 0; + WP surface; + struct { + WP acquireTimeline, releaseTimeline; + uint64_t acquirePoint = 0, releasePoint = 0; + } current, pending; private: SP resource; struct { CHyprSignalListener surfacePrecommit; + CHyprSignalListener surfaceCommit; } listeners; }; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 4a6fa40f..b0111032 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -7,6 +7,7 @@ #include "Subcompositor.hpp" #include "../Viewporter.hpp" #include "../../helpers/Monitor.hpp" +#include "../../helpers/sync/SyncReleaser.hpp" #include "../PresentationTime.hpp" #include "../DRMSyncobj.hpp" #include "../../render/Renderer.hpp" @@ -69,7 +70,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso resource->setOnDestroy([this](CWlSurface* r) { destroy(); }); resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) { - pending.offset = {x, y}; + pending.offset = {x, y}; + pending.newBuffer = true; if (!buffer) { pending.buffer.reset(); @@ -428,6 +430,10 @@ void CWLSurfaceResource::commitPendingState() { current = pending; pending.damage.clear(); pending.bufferDamage.clear(); + pending.newBuffer = false; + + if (syncobj && syncobj->current.releaseTimeline && syncobj->current.releaseTimeline->timeline && current.buffer && current.buffer->buffer) + current.buffer->releaser = makeShared(syncobj->current.releaseTimeline->timeline, syncobj->current.releasePoint); if (current.texture) current.texture->m_eTransform = wlTransformToHyprutils(current.transform); @@ -501,23 +507,18 @@ void CWLSurfaceResource::updateCursorShm() { memcpy(shmData.data(), pixelData, bufLen); } -void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { +void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor) { frame(when); auto FEEDBACK = makeShared(self.lock()); FEEDBACK->attachMonitor(pMonitor); FEEDBACK->presented(); PROTO::presentation->queueData(FEEDBACK); - if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync) + if (!pMonitor || !pMonitor->outTimeline || !syncobj) return; // attach explicit sync g_pHyprRenderer->explicitPresented.emplace_back(self.lock()); - - if (syncobj->acquirePoint > pMonitor->lastWaitPoint) { - Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint); - pMonitor->lastWaitPoint = syncobj->acquirePoint; - } } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 460ec755..af0dfa58 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -97,7 +97,8 @@ class CWLSurfaceResource { Vector2D destination; CBox source; } viewport; - bool rejected = false; + bool rejected = false; + bool newBuffer = false; // void reset() { @@ -122,7 +123,7 @@ class CWLSurfaceResource { void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); - void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false); + void presentFeedback(timespec* when, CMonitor* pMonitor); void lockPendingState(); void unlockPendingState(); diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index 40f2eaf8..ea12f017 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -9,11 +9,6 @@ void IHLBuffer::sendRelease() { resource->sendRelease(); } -void IHLBuffer::sendReleaseWithSurface(SP surf) { - if (resource && resource->good()) - resource->sendReleaseWithSurface(surf); -} - void IHLBuffer::lock() { nLocks++; } @@ -27,26 +22,13 @@ void IHLBuffer::unlock() { sendRelease(); } -void IHLBuffer::unlockWithSurface(SP surf) { - nLocks--; - - ASSERT(nLocks >= 0); - - if (nLocks == 0) - sendReleaseWithSurface(surf); -} - bool IHLBuffer::locked() { return nLocks > 0; } void IHLBuffer::unlockOnBufferRelease(WP surf) { - unlockSurface = surf; hlEvents.backendRelease = events.backendRelease.registerListener([this](std::any data) { - if (unlockSurface.expired()) - unlock(); - else - unlockWithSurface(unlockSurface.lock()); + unlock(); hlEvents.backendRelease.reset(); }); } @@ -59,8 +41,5 @@ CHLBufferReference::~CHLBufferReference() { if (buffer.expired()) return; - if (surface) - buffer->unlockWithSurface(surface.lock()); - else - buffer->unlock(); + buffer->unlock(); } diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index d2157181..7d84dce7 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -6,6 +6,8 @@ #include +class CSyncReleaser; + class IHLBuffer : public Aquamarine::IBuffer { public: virtual ~IHLBuffer(); @@ -15,10 +17,8 @@ class IHLBuffer : public Aquamarine::IBuffer { virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu virtual bool good() = 0; virtual void sendRelease(); - virtual void sendReleaseWithSurface(SP); virtual void lock(); virtual void unlock(); - virtual void unlockWithSurface(SP surf); virtual bool locked(); void unlockOnBufferRelease(WP surf /* optional */); @@ -29,12 +29,11 @@ class IHLBuffer : public Aquamarine::IBuffer { struct { CHyprSignalListener backendRelease; + CHyprSignalListener backendRelease2; // for explicit ds } hlEvents; private: - int nLocks = 0; - - WP unlockSurface; + int nLocks = 0; }; // for ref-counting. Releases in ~dtor @@ -44,7 +43,8 @@ class CHLBufferReference { CHLBufferReference(SP buffer, SP surface); ~CHLBufferReference(); - WP buffer; + WP buffer; + SP releaser; private: WP surface; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index d34a867d..eb7d1fde 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -32,16 +32,6 @@ void CWLBufferResource::sendRelease() { resource->sendRelease(); } -void CWLBufferResource::sendReleaseWithSurface(SP surf) { - sendRelease(); - - if (!surf || !surf->syncobj) - return; - - if (drmSyncobjTimelineSignal(g_pCompositor->m_iDRMFD, &surf->syncobj->releaseTimeline->timeline->handle, &surf->syncobj->releasePoint, 1)) - Debug::log(ERR, "sendReleaseWithSurface: drmSyncobjTimelineSignal failed"); -} - wl_resource* CWLBufferResource::getResource() { return resource->resource(); } diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index 59512128..787abe1f 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -17,7 +17,6 @@ class CWLBufferResource { bool good(); void sendRelease(); - void sendReleaseWithSurface(SP); wl_resource* getResource(); WP buffer; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ea388df0..8875d8f4 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2870,7 +2870,7 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { std::vector attribs; int dupFd = -1; if (fenceFD > 0) { - int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); + dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); if (dupFd < 0) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; @@ -2889,8 +2889,18 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { return nullptr; } - auto eglsync = SP(new CEGLSync); - eglsync->sync = sync; + // we need to flush otherwise we might not get a valid fd + glFlush(); + + int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync); + if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + Debug::log(ERR, "eglDupNativeFenceFDANDROID failed"); + return nullptr; + } + + auto eglsync = SP(new CEGLSync); + eglsync->sync = sync; + eglsync->m_iFd = fd; return eglsync; } @@ -2983,19 +2993,13 @@ CEGLSync::~CEGLSync() { if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) Debug::log(ERR, "eglDestroySyncKHR failed"); + + if (m_iFd >= 0) + close(m_iFd); } -int CEGLSync::dupFenceFD() { - if (sync == EGL_NO_SYNC_KHR) - return -1; - - int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync); - if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - Debug::log(ERR, "eglDupNativeFenceFDANDROID failed"); - return -1; - } - - return fd; +int CEGLSync::fd() { + return m_iFd; } bool CEGLSync::wait() { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 1e8325c1..f405cb7c 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -131,12 +131,14 @@ class CEGLSync { EGLSyncKHR sync = nullptr; - int dupFenceFD(); + int fd(); bool wait(); private: CEGLSync() = default; + int m_iFd = -1; + friend class CHyprOpenGLImpl; }; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 127ae187..7794d476 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,9 +1,12 @@ #include "Renderer.hpp" #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" +#include "../helpers/ScopeGuard.hpp" +#include "../helpers/sync/SyncReleaser.hpp" #include #include #include +#include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" #include "../managers/PointerManager.hpp" @@ -115,8 +118,8 @@ static void renderSurface(SP surface, int x, int y, void* da return; // explicit sync: wait for the timeline, if any - if (surface->syncobj && surface->syncobj->acquireTimeline) { - if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) { + if (surface->syncobj && surface->syncobj->current.acquireTimeline) { + if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->current.acquireTimeline->timeline, surface->syncobj->current.acquirePoint)) { Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); return; } @@ -1095,7 +1098,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static auto PDEBUGOVERLAY = CConfigValue("debug:overlay"); static auto PDAMAGETRACKINGMODE = CConfigValue("debug:damage_tracking"); static auto PDAMAGEBLINK = CConfigValue("debug:damage_blink"); - static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); + static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); static auto PVFR = CConfigValue("misc:vfr"); static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); static auto PANIMENABLED = CConfigValue("animations:enabled"); @@ -1195,7 +1198,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->tearingState.activelyTearing = shouldTear; - if (!*PNODIRECTSCANOUT && !shouldTear) { + if (*PDIRECTSCANOUT && !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; } else if (!pMonitor->lastScanout.expired()) { @@ -1403,59 +1406,62 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { - static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); - // apply timelines for explicit sync + // save inFD otherwise reset will reset it + auto inFD = pMonitor->output->state->state().explicitInFence; pMonitor->output->state->resetExplicitFences(); - - bool anyExplicit = !explicitPresented.empty(); - if (anyExplicit) { - Debug::log(TRACE, "Explicit sync presented begin"); - auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint); - if (inFence < 0) - Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint); - - pMonitor->output->state->setExplicitInFence(inFence); - - for (auto& e : explicitPresented) { - Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1); - if (!e->syncobj || !e->syncobj->releaseTimeline) - continue; - e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint); - } - - explicitPresented.clear(); - auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq); - if (outFence < 0) - Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq); - - pMonitor->output->state->setExplicitOutFence(outFence); - Debug::log(TRACE, "Explicit sync presented end"); - } - - pMonitor->lastWaitPoint = 0; + if (inFD >= 0) + pMonitor->output->state->setExplicitInFence(inFD); bool ok = pMonitor->state.commit(); if (!ok) { - Debug::log(TRACE, "Monitor state commit failed"); - // rollback the buffer to avoid writing to the front buffer that is being - // displayed - pMonitor->output->swapchain->rollback(); - pMonitor->damage.damageEntire(); + if (inFD >= 0) { + Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); + pMonitor->output->state->resetExplicitFences(); + ok = pMonitor->state.commit(); + } + + if (!ok) { + Debug::log(TRACE, "Monitor state commit failed"); + // rollback the buffer to avoid writing to the front buffer that is being + // displayed + pMonitor->output->swapchain->rollback(); + pMonitor->damage.damageEntire(); + } } - if (!*PENABLEEXPLICIT) + auto explicitOptions = getExplicitSyncSettings(); + + if (!explicitOptions.explicitEnabled) return ok; - if (pMonitor->output->state->state().explicitInFence >= 0) - close(pMonitor->output->state->state().explicitInFence); + if (inFD >= 0) + close(inFD); if (pMonitor->output->state->state().explicitOutFence >= 0) { - if (ok) - pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, pMonitor->output->state->state().explicitOutFence); + Debug::log(TRACE, "Aquamarine returned an explicit out fence at {}", pMonitor->output->state->state().explicitOutFence); close(pMonitor->output->state->state().explicitOutFence); + } else + Debug::log(TRACE, "Aquamarine did not return an explicit out fence"); + + Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); + auto sync = g_pHyprOpenGL->createEGLSync(-1); + + if (!sync) + Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); + else { + for (auto& e : explicitPresented) { + if (!e->current.buffer || !e->current.buffer->releaser) + continue; + + e->current.buffer->releaser->addReleaseSync(sync); + } } + explicitPresented.clear(); + + pMonitor->output->state->resetExplicitFences(); + return ok; } @@ -1898,6 +1904,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->currentMode = nullptr; pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + pMonitor->output->state->resetExplicitFences(); bool autoScale = false; @@ -2643,10 +2650,16 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode void CHyprRenderer::endRender() { const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor; static auto PNVIDIAANTIFLICKER = CConfigValue("opengl:nvidia_anti_flicker"); - static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); PMONITOR->commitSeq++; + auto cleanup = CScopeGuard([this]() { + if (m_pCurrentRenderbuffer) + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + }); + if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY) g_pHyprOpenGL->end(); else { @@ -2661,35 +2674,28 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_NORMAL) { PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - if (PMONITOR->inTimeline && *PENABLEEXPLICIT) { + auto explicitOptions = getExplicitSyncSettings(); + + if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { auto sync = g_pHyprOpenGL->createEGLSync(-1); if (!sync) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; } - auto dupedfd = sync->dupFenceFD(); - sync.reset(); - if (dupedfd < 0) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; - Debug::log(ERR, "renderer: couldn't dup an EGLSync fence for out in endRender"); - return; - } - - bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); - close(dupedfd); + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, sync->fd()); if (!ok) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); return; } + + auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); + if (fd <= 0) { + Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); + return; + } + + PMONITOR->output->state->setExplicitInFence(fd); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); @@ -2697,11 +2703,6 @@ void CHyprRenderer::endRender() { glFlush(); } } - - m_pCurrentRenderbuffer->unbind(); - - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; } void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) { @@ -2715,3 +2716,57 @@ SP CHyprRenderer::getCurrentRBO() { bool CHyprRenderer::isNvidia() { return m_bNvidia; } + +SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { + static auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static auto PENABLEEXPLICITKMS = CConfigValue("render:explicit_sync_kms"); + + SExplicitSyncSettings settings; + settings.explicitEnabled = *PENABLEEXPLICIT; + settings.explicitKMSEnabled = *PENABLEEXPLICITKMS; + + if (*PENABLEEXPLICIT == 2 /* auto */) + settings.explicitEnabled = true; + if (*PENABLEEXPLICITKMS == 2 /* auto */) { + if (!m_bNvidia) + settings.explicitKMSEnabled = true; + else { + + // check nvidia version. Explicit KMS is supported in >=560 + // in the case of an error, driverMajor will stay 0 and explicit KMS will be disabled + int driverMajor = 0; + + static bool once = true; + if (once) { + once = false; + + Debug::log(LOG, "Renderer: checking for explicit KMS support for nvidia"); + + if (std::filesystem::exists("/sys/module/nvidia_drm/version")) { + Debug::log(LOG, "Renderer: Nvidia version file exists"); + + std::ifstream ifs("/sys/module/nvidia_drm/version"); + if (ifs.good()) { + try { + std::string driverInfo((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); + + Debug::log(LOG, "Renderer: Read nvidia version {}", driverInfo); + + CVarList ver(driverInfo, 0, '.', true); + driverMajor = std::stoi(ver[0]); + + Debug::log(LOG, "Renderer: Parsed nvidia major version: {}", driverMajor); + + } catch (std::exception& e) { settings.explicitKMSEnabled = false; } + + ifs.close(); + } + } + } + + settings.explicitKMSEnabled = driverMajor >= 560; + } + } + + return settings; +} diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index a9397cac..84501821 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -39,6 +39,10 @@ class CToplevelExportProtocolManager; class CInputManager; struct SSessionLockSurface; +struct SExplicitSyncSettings { + bool explicitEnabled = false, explicitKMSEnabled = false; +}; + class CHyprRenderer { public: CHyprRenderer(); @@ -73,6 +77,7 @@ class CHyprRenderer { bool isNvidia(); void makeEGLCurrent(); void unsetEGL(); + SExplicitSyncSettings getExplicitSyncSettings(); // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. @@ -142,6 +147,7 @@ class CHyprRenderer { friend class CToplevelExportFrame; friend class CInputManager; friend class CPointerManager; + friend class CMonitor; }; inline std::unique_ptr g_pHyprRenderer; From d597ae41b9ce7d995a4ad28bda9ef54d4d01a020 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 6 Aug 2024 16:57:15 +0200 Subject: [PATCH 002/298] renderer: fixup crashes on inaccessible files for bg --- src/render/OpenGL.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 8875d8f4..c355f4f9 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2688,12 +2688,10 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { texPath += ".png"; // check if wallpapers exist - if (!std::filesystem::exists(texPath)) { - // try local - texPath = texPath.substr(0, 5) + "local/" + texPath.substr(5); - - if (!std::filesystem::exists(texPath)) - return; // the texture will be empty, oh well. We'll clear with a solid color anyways. + std::error_code err; + if (!std::filesystem::exists(texPath, err)) { + Debug::log(ERR, "createBGTextureForMonitor: failed, file doesn't exist or access denied, ec: {}", err.message()); + return; // the texture will be empty, oh well. We'll clear with a solid color anyways. } createBackgroundTexture(texPath); From b0a70f63e3865eaa77f0b78a04b230aa583bc95c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 6 Aug 2024 17:08:22 +0200 Subject: [PATCH 003/298] wayland/compositor: drop pending buffer ref if synchronous fixes https://github.com/hyprwm/hyprpicker/issues/85 --- src/protocols/core/Compositor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index b0111032..656433d3 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -448,8 +448,10 @@ void CWLSurfaceResource::commitPendingState() { // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - if (current.buffer->buffer->isSynchronous()) + if (current.buffer->buffer->isSynchronous()) { dropCurrentBuffer(); + dropPendingBuffer(); // pending atm is just a copied ref of the current, drop it too to send a release + } } // TODO: we should _accumulate_ and not replace above if sync From fa6ee513678e6e1cfdc575a421c1e0ddf4608994 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:44:20 -0500 Subject: [PATCH 004/298] input: fix leds on kb creation (#7206) --- src/managers/input/InputManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 8c38893f..c502cb0d 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -919,6 +919,8 @@ void CInputManager::setupKeyboard(SP keeb) { applyConfigToKeyboard(keeb); g_pSeatManager->setKeyboard(keeb); + + keeb->updateLEDs(); } void CInputManager::setKeyboardLayout() { From 5b736a4a661220ab07abc3afda6cdb8774095bfb Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 7 Aug 2024 13:22:01 +0200 Subject: [PATCH 005/298] debug: dont manually unlock the lock_guard (#7210) when lock_guard goes out of scope it RAII itself and calls unlock. causes crashes on freebsd/libc++ and double unlocking a mutex is UB. --- src/debug/Log.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 617f451a..4fc8ed5b 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -72,6 +72,5 @@ namespace Debug { logMsg += std::vformat(fmt.get(), std::make_format_args(args...)); log(level, logMsg); - logMutex.unlock(); } }; From a05da63d853fc750bae29228d924b346243afaec Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 7 Aug 2024 06:22:19 -0500 Subject: [PATCH 006/298] keybinds: fix NoSymbol keybinds (#7199) --- src/managers/KeybindManager.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 08c6998d..c7b93730 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -639,18 +639,17 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi if (found || key.submapAtPress != m_szCurrentSelectedSubmap) continue; } else { - // in this case, we only have the keysym to go off. - // if the keysym failed resolving, we can't do anything. It's likely missing - // from the keymap. - if (key.keysym == 0) - return false; + // in this case, we only have the keysym to go off of for this keybind, and it's invalid + // since there might be something like keycode to match with other keybinds, try the next + if (key.keysym == XKB_KEY_NoSymbol) + continue; // oMg such performance hit!!11! // this little maneouver is gonna cost us 4µs const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS); const auto KBKEYLOWER = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); - if (KBKEY == 0 && KBKEYLOWER == 0) { + if (KBKEY == XKB_KEY_NoSymbol && KBKEYLOWER == XKB_KEY_NoSymbol) { // Keysym failed to resolve from the key name of the currently iterated bind. // This happens for names such as `switch:off:Lid Switch` as well as some keys // (such as yen and ro). From 3d82d199f0ec6d8bf6252ed0795b4d883ade84ff Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 7 Aug 2024 13:23:00 +0200 Subject: [PATCH 007/298] cursormgr: implement inheriting themes for xcursor (#7197) * cursormgr: reduce duplicated code add a few functions such as setCursorBuffer and setAnimationTimer to reduce duplicated code and also avoid future mishaps of forgetting to clear buffer or disarm timer. and generally reduce spaghetti even tho pasta can be delicious. * xcursormgr: implent inherited themes implent index.theme parsing and inherited themes. * cursormgr: ensure a fallback xcursor exist ensure a xcursor fallback exist otherwise it wont load the proper theme if we at launch have hyprcursor enabled and then set it to false in config and reload. also use the env var when using hyprctl setcursor incase its empty. --- src/managers/CursorManager.cpp | 343 ++++++++++++++++---------------- src/managers/CursorManager.hpp | 54 +++-- src/managers/XCursorManager.cpp | 90 +++++++-- src/managers/XCursorManager.hpp | 21 +- 4 files changed, 285 insertions(+), 223 deletions(-) diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 9b574901..3f3a25f6 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -17,11 +17,61 @@ static void hcLogger(enum eHyprcursorLogLevel level, char* message) { Debug::log(NONE, "[hc] {}", message); } -CCursorManager::CCursorManager() { - m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); - m_pXcursor = std::make_unique(); +CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + surface = surf; + size = size_; + stride = cairo_image_surface_get_stride(surf); +} - if (m_pHyprcursor->valid()) { +CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + pixelData = pixelData_; + size = size_; + stride = 4 * size_.x; +} + +Aquamarine::eBufferCapability CCursorBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; +} + +Aquamarine::eBufferType CCursorBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; +} + +void CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) { + ; +} + +bool CCursorBuffer::isSynchronous() { + return true; +} + +bool CCursorBuffer::good() { + return true; +} + +Aquamarine::SSHMAttrs CCursorBuffer::shm() { + Aquamarine::SSHMAttrs attrs; + attrs.success = true; + attrs.format = DRM_FORMAT_ARGB8888; + attrs.size = size; + attrs.stride = stride; + return attrs; +} + +std::tuple CCursorBuffer::beginDataPtr(uint32_t flags) { + return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride}; +} + +void CCursorBuffer::endDataPtr() { + ; +} + +CCursorManager::CCursorManager() { + m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); + m_pXcursor = std::make_unique(); + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + + if (m_pHyprcursor->valid() && *PUSEHYPRCURSOR) { // find default size. First, HYPRCURSOR_SIZE then default to 24 auto const* SIZE = getenv("HYPRCURSOR_SIZE"); if (SIZE) { @@ -48,10 +98,12 @@ CCursorManager::CCursorManager() { Debug::log(WARN, "XCURSOR_SIZE size not set, defaulting to size 24"); m_iSize = 24; } - - m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); } + // since we fallback to xcursor always load it on startup. otherwise we end up with a empty theme if hyprcursor is enabled in the config + // and then later is disabled. + m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); + m_pAnimationTimer = makeShared(std::nullopt, cursorAnimTimer, this); g_pEventLoopManager->addTimer(m_pAnimationTimer); @@ -65,63 +117,9 @@ CCursorManager::~CCursorManager() { g_pEventLoopManager->removeTimer(m_pAnimationTimer); m_pAnimationTimer.reset(); } -} -void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) { - std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; }); -} - -CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { - surface = surf; - size = size_; - stride = cairo_image_surface_get_stride(surf); -} - -CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { - pixelData = pixelData_; - size = size_; - stride = 4 * size_.x; -} - -CCursorManager::CCursorBuffer::~CCursorBuffer() { - ; -} - -Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() { - return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; -} - -Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() { - return Aquamarine::eBufferType::BUFFER_TYPE_SHM; -} - -void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) { - ; -} - -bool CCursorManager::CCursorBuffer::isSynchronous() { - return true; -} - -bool CCursorManager::CCursorBuffer::good() { - return true; -} - -Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() { - Aquamarine::SSHMAttrs attrs; - attrs.success = true; - attrs.format = DRM_FORMAT_ARGB8888; - attrs.size = size; - attrs.stride = stride; - return attrs; -} - -std::tuple CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) { - return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride}; -} - -void CCursorManager::CCursorBuffer::endDataPtr() { - ; + if (m_pHyprcursor->valid() && m_sCurrentStyleInfo.size > 0) + m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo); } SP CCursorManager::getCursorBuffer() { @@ -137,91 +135,101 @@ void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotsp m_bOurBufferConnected = false; } -void CCursorManager::setXCursor(const std::string& name) { - float scale = std::ceil(m_fCursorScale); - - auto xcursor = m_pXcursor->getShape(name, m_iSize * scale); - auto& icon = xcursor->images.front(); - - m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot)); - - g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale); +void CCursorManager::setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale) { + m_vCursorBuffers.emplace_back(buf); + g_pPointerManager->setCursorBuffer(getCursorBuffer(), hotspot, scale); if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); + std::erase_if(m_vCursorBuffers, [this](const auto& buf) { return buf.get() == m_vCursorBuffers.front().get(); }); - m_currentXcursor = xcursor; m_bOurBufferConnected = true; +} - if (m_currentXcursor->images.size() > 1) { - // animated - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[0].delay)); - m_iCurrentAnimationFrame = 0; +void CCursorManager::setAnimationTimer(const int& frame, const int& delay) { + if (delay > 0) { + // arm + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(delay)); } else { // disarm m_pAnimationTimer->updateTimeout(std::nullopt); } + + m_iCurrentAnimationFrame = frame; } void CCursorManager::setCursorFromName(const std::string& name) { static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); - if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) { - setXCursor(name); - return; - } + auto setXCursor = [this](auto const& name) { + float scale = std::ceil(m_fCursorScale); - m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo); + auto xcursor = m_pXcursor->getShape(name, m_iSize * scale); + auto& icon = xcursor->images.front(); + auto buf = makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot); + setCursorBuffer(buf, icon.hotspot / scale, scale); - if (m_sCurrentCursorShapeData.images.size() < 1) { - // try with '_' first (old hc, etc) - std::string newName = name; - std::replace(newName.begin(), newName.end(), '-', '_'); + m_currentXcursor = xcursor; - m_sCurrentCursorShapeData = m_pHyprcursor->getShape(newName.c_str(), m_sCurrentStyleInfo); - } + int delay = 0; + int frame = 0; + if (m_currentXcursor->images.size() > 1) + delay = m_currentXcursor->images[frame].delay; - if (m_sCurrentCursorShapeData.images.size() < 1) { - // fallback to a default if available - constexpr const std::array fallbackShapes = {"default", "left_ptr", "left-ptr"}; + setAnimationTimer(frame, delay); + }; - for (auto& s : fallbackShapes) { - m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo); + auto setHyprCursor = [this](auto const& name) { + m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo); - if (m_sCurrentCursorShapeData.images.size() > 0) - break; + if (m_sCurrentCursorShapeData.images.size() < 1) { + // try with '_' first (old hc, etc) + std::string newName = name; + std::replace(newName.begin(), newName.end(), '-', '_'); + + m_sCurrentCursorShapeData = m_pHyprcursor->getShape(newName.c_str(), m_sCurrentStyleInfo); } if (m_sCurrentCursorShapeData.images.size() < 1) { - Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); - setXCursor(name); - return; + // fallback to a default if available + constexpr const std::array fallbackShapes = {"default", "left_ptr", "left-ptr"}; + + for (auto& s : fallbackShapes) { + m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo); + + if (m_sCurrentCursorShapeData.images.size() > 0) + break; + } + + if (m_sCurrentCursorShapeData.images.size() < 1) { + Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); + return false; + } } - } - m_vCursorBuffers.emplace_back(makeShared(m_sCurrentCursorShapeData.images[0].surface, - Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, - Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); + auto buf = + makeShared(m_sCurrentCursorShapeData.images[0].surface, Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, + Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}); + auto hotspot = Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale; + setCursorBuffer(buf, hotspot, m_fCursorScale); - g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale, - m_fCursorScale); - if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); + int delay = 0; + int frame = 0; + if (m_sCurrentCursorShapeData.images.size() > 1) + delay = m_sCurrentCursorShapeData.images[frame].delay; - m_bOurBufferConnected = true; + setAnimationTimer(frame, delay); + return true; + }; - if (m_sCurrentCursorShapeData.images.size() > 1) { - // animated - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[0].delay)); - m_iCurrentAnimationFrame = 0; - } else { - // disarm - m_pAnimationTimer->updateTimeout(std::nullopt); - } + if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR || !setHyprCursor(name)) + setXCursor(name); } void CCursorManager::tickAnimatedCursor() { - if (!m_pHyprcursor->valid() && m_currentXcursor->images.size() > 1 && m_bOurBufferConnected) { + if (!m_bOurBufferConnected) + return; + + if (!m_pHyprcursor->valid() && m_currentXcursor->images.size() > 1) { m_iCurrentAnimationFrame++; if ((size_t)m_iCurrentAnimationFrame >= m_currentXcursor->images.size()) @@ -229,39 +237,24 @@ void CCursorManager::tickAnimatedCursor() { float scale = std::ceil(m_fCursorScale); auto& icon = m_currentXcursor->images.at(m_iCurrentAnimationFrame); - m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot)); + auto buf = makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot); + setCursorBuffer(buf, icon.hotspot / scale, scale); + setAnimationTimer(m_iCurrentAnimationFrame, m_currentXcursor->images[m_iCurrentAnimationFrame].delay); + } else if (m_sCurrentCursorShapeData.images.size() > 1) { + m_iCurrentAnimationFrame++; - g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale); + if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) + m_iCurrentAnimationFrame = 0; - if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); - - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[m_iCurrentAnimationFrame].delay)); - - return; + auto hotspot = + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale; + auto buf = makeShared( + m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}); + setCursorBuffer(buf, hotspot, m_fCursorScale); + setAnimationTimer(m_iCurrentAnimationFrame, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay); } - - if (m_sCurrentCursorShapeData.images.size() < 2 || !m_bOurBufferConnected) - return; - - m_iCurrentAnimationFrame++; - if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) - m_iCurrentAnimationFrame = 0; - - m_vCursorBuffers.emplace_back(makeShared( - m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, - Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, - Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY})); - - g_pPointerManager->setCursorBuffer( - getCursorBuffer(), - Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale, - m_fCursorScale); - - if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); - - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay)); } SCursorImageData CCursorManager::dataFor(const std::string& name) { @@ -278,11 +271,12 @@ SCursorImageData CCursorManager::dataFor(const std::string& name) { } void CCursorManager::setXWaylandCursor() { - const auto CURSOR = dataFor("left_ptr"); - if (CURSOR.surface) { + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + const auto CURSOR = dataFor("left_ptr"); + if (CURSOR.surface && *PUSEHYPRCURSOR) g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); - } else { + else { auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale)); auto& icon = xcursor->images.front(); @@ -291,21 +285,25 @@ void CCursorManager::setXWaylandCursor() { } void CCursorManager::updateTheme() { - float highestScale = 1.0; + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + float highestScale = 1.0; for (auto& m : g_pCompositor->m_vMonitors) { if (m->scale > highestScale) highestScale = m->scale; } - if (m_sCurrentStyleInfo.size && m_pHyprcursor->valid()) - m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo); + m_fCursorScale = highestScale; - m_sCurrentStyleInfo.size = std::round(m_iSize * highestScale); - m_fCursorScale = highestScale; + if (*PUSEHYPRCURSOR) { + if (m_sCurrentStyleInfo.size > 0 && m_pHyprcursor->valid()) + m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo); - if (m_pHyprcursor->valid()) - m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo); + m_sCurrentStyleInfo.size = std::round(m_iSize * highestScale); + + if (m_pHyprcursor->valid()) + m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo); + } setCursorFromName("left_ptr"); @@ -316,24 +314,27 @@ void CCursorManager::updateTheme() { } bool CCursorManager::changeTheme(const std::string& name, const int size) { - auto options = Hyprcursor::SManagerOptions(); - options.logFn = hcLogger; - options.allowDefaultFallback = false; + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + m_szTheme = name.empty() ? "" : name; + m_iSize = size <= 0 ? 24 : size; + auto xcursor_theme = getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default"; - m_pHyprcursor = std::make_unique(name.empty() ? "" : name.c_str(), options); - if (m_pHyprcursor->valid()) { - m_szTheme = name; - m_iSize = size; - updateTheme(); - return true; - } + if (*PUSEHYPRCURSOR) { + auto options = Hyprcursor::SManagerOptions(); + options.logFn = hcLogger; + options.allowDefaultFallback = false; + m_szTheme = name.empty() ? "" : name; + m_iSize = size; - Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", name); + m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options); + if (!m_pHyprcursor->valid()) { + Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", m_szTheme); + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); + } + } else + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); - m_pXcursor->loadTheme(name, size); - - m_szTheme = name; - m_iSize = size; updateTheme(); + return true; } \ No newline at end of file diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index a114b6c2..ceb4816b 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -15,6 +15,28 @@ class CWLSurface; AQUAMARINE_FORWARD(IBuffer); +class CCursorBuffer : public Aquamarine::IBuffer { + public: + CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); + CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); + ~CCursorBuffer() = default; + + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); + virtual void update(const Hyprutils::Math::CRegion& damage); + virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu + virtual bool good(); + virtual Aquamarine::SSHMAttrs shm(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + + private: + Vector2D hotspot; + cairo_surface_t* surface = nullptr; + uint8_t* pixelData = nullptr; + size_t stride = 0; +}; + class CCursorManager { public: CCursorManager(); @@ -24,7 +46,8 @@ class CCursorManager { void setCursorFromName(const std::string& name); void setCursorSurface(SP surf, const Vector2D& hotspot); - void setXCursor(const std::string& name); + void setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale); + void setAnimationTimer(const int& frame, const int& delay); bool changeTheme(const std::string& name, const int size); void updateTheme(); @@ -33,35 +56,8 @@ class CCursorManager { void tickAnimatedCursor(); - class CCursorBuffer : public Aquamarine::IBuffer { - public: - CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); - CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); - ~CCursorBuffer(); - - virtual Aquamarine::eBufferCapability caps(); - virtual Aquamarine::eBufferType type(); - virtual void update(const Hyprutils::Math::CRegion& damage); - virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu - virtual bool good(); - virtual Aquamarine::SSHMAttrs shm(); - virtual std::tuple beginDataPtr(uint32_t flags); - virtual void endDataPtr(); - - private: - Vector2D hotspot; - cairo_surface_t* surface = nullptr; - uint8_t* pixelData = nullptr; - size_t stride = 0; - - friend class CCursorManager; - }; - - void dropBufferRef(CCursorBuffer* ref); - - bool m_bOurBufferConnected = false; - private: + bool m_bOurBufferConnected = false; std::vector> m_vCursorBuffers; std::unique_ptr m_pHyprcursor; diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index b3f33086..76c908db 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -135,6 +135,11 @@ void CXCursorManager::loadTheme(std::string const& name, int size) { continue; } + if (std::any_of(cursors.begin(), cursors.end(), [&shape](auto const& dp) { return dp->shape == shape; })) { + Debug::log(LOG, "XCursor already has a shape {} loaded, skipping", shape); + continue; + } + auto cursor = makeShared(); cursor->images = it->get()->images; cursor->shape = shape; @@ -180,11 +185,10 @@ SP CXCursorManager::createCursor(std::string const& shape, XcursorIma return xcursor; } -std::vector CXCursorManager::themePaths(std::string const& theme) { - auto const* path = XcursorLibraryPath(); - std::vector paths; +std::unordered_set CXCursorManager::themePaths(std::string const& theme) { + auto const* path = XcursorLibraryPath(); - auto expandTilde = [](std::string const& path) { + auto expandTilde = [](std::string const& path) { if (!path.empty() && path[0] == '~') { const char* home = std::getenv("HOME"); if (home) @@ -193,15 +197,76 @@ std::vector CXCursorManager::themePaths(std::string const& theme) { return path; }; - if (path) { + auto getInheritThemes = [](std::string const& indexTheme) { + std::ifstream infile(indexTheme); + std::string line; + std::vector themes; + + Debug::log(LOG, "XCursor parsing index.theme {}", indexTheme); + + while (std::getline(infile, line)) { + // Trim leading and trailing whitespace + line.erase(0, line.find_first_not_of(" \t\n\r")); + line.erase(line.find_last_not_of(" \t\n\r") + 1); + + if (line.rfind("Inherits", 0) == 0) { // Check if line starts with "Inherits" + std::string inheritThemes = line.substr(8); // Extract the part after "Inherits" + // Remove leading whitespace from inheritThemes and = + inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); + inheritThemes.erase(0, 1); + inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); + + std::stringstream inheritStream(inheritThemes); + std::string inheritTheme; + while (std::getline(inheritStream, inheritTheme, ',')) { + // Trim leading and trailing whitespace from each theme + inheritTheme.erase(0, inheritTheme.find_first_not_of(" \t\n\r")); + inheritTheme.erase(inheritTheme.find_last_not_of(" \t\n\r") + 1); + themes.push_back(inheritTheme); + } + } + } + infile.close(); + + return themes; + }; + + std::unordered_set paths; + std::unordered_set inherits; + + auto scanTheme = [&path, &paths, &expandTilde, &inherits, &getInheritThemes](auto const& t) { std::stringstream ss(path); - std::string item; + std::string line; - while (std::getline(ss, item, ':')) { - auto p = expandTilde(item + "/" + theme + "/cursors"); + Debug::log(LOG, "XCursor scanning theme {}", t); - if (std::filesystem::exists(p) && std::filesystem::is_directory(p)) - paths.push_back(p); + while (std::getline(ss, line, ':')) { + auto p = expandTilde(line + "/" + t + "/cursors"); + if (std::filesystem::exists(p) && std::filesystem::is_directory(p)) { + Debug::log(LOG, "XCursor using theme path {}", p); + paths.insert(p); + } + + auto inherit = expandTilde(line + "/" + t + "/index.theme"); + if (std::filesystem::exists(inherit) && std::filesystem::is_regular_file(inherit)) { + auto inheritThemes = getInheritThemes(inherit); + for (auto const& i : inheritThemes) { + Debug::log(LOG, "XCursor theme {} inherits {}", t, i); + inherits.insert(i); + } + } + } + }; + + if (path) { + scanTheme(theme); + while (!inherits.empty()) { + auto oldInherits = inherits; + for (auto& i : oldInherits) + scanTheme(i); + + if (oldInherits.size() == inherits.size()) + break; } } @@ -402,14 +467,13 @@ std::vector> CXCursorManager::loadStandardCursors(std::string cons std::vector> CXCursorManager::loadAllFromDir(std::string const& path, int size) { std::vector> newCursors; - std::string full; if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { for (const auto& entry : std::filesystem::directory_iterator(path)) { if (!entry.is_regular_file() && !entry.is_symlink()) continue; - std::string full = entry.path().string(); + auto const& full = entry.path().string(); using PcloseType = int (*)(FILE*); const std::unique_ptr f(fopen(full.c_str(), "r"), static_cast(fclose)); @@ -428,7 +492,7 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa } } - std::string shape = entry.path().filename().string(); + auto const& shape = entry.path().filename().string(); auto cursor = createCursor(shape, xImages); newCursors.emplace_back(cursor); diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 9ced076f..20637055 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include @@ -32,15 +33,15 @@ class CXCursorManager { SP getShape(std::string const& shape, int size); private: - SP createCursor(std::string const& shape, XcursorImages* xImages); - std::vector themePaths(std::string const& theme); - std::string getLegacyShapeName(std::string const& shape); - std::vector> loadStandardCursors(std::string const& name, int size); - std::vector> loadAllFromDir(std::string const& path, int size); + SP createCursor(std::string const& shape, XcursorImages* xImages); + std::unordered_set themePaths(std::string const& theme); + std::string getLegacyShapeName(std::string const& shape); + std::vector> loadStandardCursors(std::string const& name, int size); + std::vector> loadAllFromDir(std::string const& path, int size); - int lastLoadSize = 0; - std::string themeName = ""; - SP defaultCursor; - SP hyprCursor; - std::vector> cursors; + int lastLoadSize = 0; + std::string themeName = ""; + SP defaultCursor; + SP hyprCursor; + std::vector> cursors; }; \ No newline at end of file From b2717cf7fd86774b450b58f6263291e277553e63 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Wed, 7 Aug 2024 04:26:09 -0700 Subject: [PATCH 008/298] xdg-shell: make xdg-positioner flip target greatest available space (#7209) When both flip directions use more space than is available, pick the direction that has more space available instead of just the opposite of what was initially requested. --- src/protocols/XDGShell.cpp | 93 +++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 4aa5d373..aea23329 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -531,29 +531,66 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo auto anchorRect = state.anchorRect.copy().translate(parentCoord); - auto width = state.requestedSize.x; - auto height = state.requestedSize.y; + auto width = state.requestedSize.x; + auto height = state.requestedSize.y; + auto gravity = state.gravity; auto anchorX = state.anchor.left() ? anchorRect.x : state.anchor.right() ? anchorRect.extent().x : anchorRect.middle().x; auto anchorY = state.anchor.top() ? anchorRect.y : state.anchor.bottom() ? anchorRect.extent().y : anchorRect.middle().y; - auto calcEffectiveX = [&]() { return state.gravity.left() ? anchorX - width : state.gravity.right() ? anchorX : anchorX - width / 2; }; - auto calcEffectiveY = [&]() { return state.gravity.top() ? anchorY - height : state.gravity.bottom() ? anchorY : anchorY - height / 2; }; + auto calcEffectiveX = [&](CEdges anchorGravity, double anchorX) { return anchorGravity.left() ? anchorX - width : anchorGravity.right() ? anchorX : anchorX - width / 2; }; + auto calcEffectiveY = [&](CEdges anchorGravity, double anchorY) { return anchorGravity.top() ? anchorY - height : anchorGravity.bottom() ? anchorY : anchorY - height / 2; }; - auto effectiveX = calcEffectiveX(); - auto effectiveY = calcEffectiveY(); + auto calcRemainingWidth = [&](double effectiveX) { + auto width = state.requestedSize.x; + if (effectiveX < constraint.x) { + auto diff = constraint.x - effectiveX; + effectiveX = constraint.x; + width -= diff; + } + + auto effectiveX2 = effectiveX + width; + if (effectiveX2 > constraint.extent().x) + width -= effectiveX2 - constraint.extent().x; + + return std::make_pair(effectiveX, width); + }; + + auto calcRemainingHeight = [&](double effectiveY) { + auto height = state.requestedSize.y; + if (effectiveY < constraint.y) { + auto diff = constraint.y - effectiveY; + effectiveY = constraint.y; + height -= diff; + } + + auto effectiveY2 = effectiveY + height; + if (effectiveY2 > constraint.extent().y) + height -= effectiveY2 - constraint.extent().y; + + return std::make_pair(effectiveY, height); + }; + + auto effectiveX = calcEffectiveX(gravity, anchorX); + auto effectiveY = calcEffectiveY(gravity, anchorY); // Note: the usage of offset is a guess which maintains compatibility with other compositors that were tested. // It considers the offset when deciding whether or not to flip but does not actually flip the offset, instead // applying it after the flip step. if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) { - auto flip = (state.gravity.left() && effectiveX + state.offset.x < constraint.x) || (state.gravity.right() && effectiveX + state.offset.x + width > constraint.extent().x); + auto flip = (gravity.left() && effectiveX + state.offset.x < constraint.x) || (gravity.right() && effectiveX + state.offset.x + width > constraint.extent().x); if (flip) { - state.gravity ^= CEdges::LEFT | CEdges::RIGHT; - anchorX = state.anchor.left() ? anchorRect.extent().x : state.anchor.right() ? anchorRect.x : anchorX; - effectiveX = calcEffectiveX(); + auto newGravity = gravity ^ (CEdges::LEFT | CEdges::RIGHT); + auto newAnchorX = state.anchor.left() ? anchorRect.extent().x : state.anchor.right() ? anchorRect.x : anchorX; + auto newEffectiveX = calcEffectiveX(newGravity, newAnchorX); + + if (calcRemainingWidth(newEffectiveX).second > calcRemainingWidth(effectiveX).second) { + gravity = newGravity; + anchorX = newAnchorX; + effectiveX = newEffectiveX; + } } } @@ -561,9 +598,15 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo auto flip = (state.gravity.top() && effectiveY + state.offset.y < constraint.y) || (state.gravity.bottom() && effectiveY + state.offset.y + height > constraint.extent().y); if (flip) { - state.gravity ^= CEdges::TOP | CEdges::BOTTOM; - anchorY = state.anchor.top() ? anchorRect.extent().y : state.anchor.bottom() ? anchorRect.y : anchorY; - effectiveY = calcEffectiveY(); + auto newGravity = gravity ^ (CEdges::TOP | CEdges::BOTTOM); + auto newAnchorY = state.anchor.top() ? anchorRect.extent().y : state.anchor.bottom() ? anchorRect.y : anchorY; + auto newEffectiveY = calcEffectiveY(newGravity, newAnchorY); + + if (calcRemainingHeight(newEffectiveY).second > calcRemainingHeight(effectiveY).second) { + gravity = newGravity; + anchorY = newAnchorY; + effectiveY = newEffectiveY; + } } } @@ -589,27 +632,15 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo } if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) { - if (effectiveX < constraint.x) { - auto diff = constraint.x - effectiveX; - effectiveX = constraint.x; - width -= diff; - } - - auto effectiveX2 = effectiveX + width; - if (effectiveX2 > constraint.extent().x) - width -= effectiveX2 - constraint.extent().x; + auto [newX, newWidth] = calcRemainingWidth(effectiveX); + effectiveX = newX; + width = newWidth; } if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) { - if (effectiveY < constraint.y) { - auto diff = constraint.y - effectiveY; - effectiveY = constraint.y; - height -= diff; - } - - auto effectiveY2 = effectiveY + height; - if (effectiveY2 > constraint.extent().y) - height -= effectiveY2 - constraint.extent().y; + auto [newY, newHeight] = calcRemainingHeight(effectiveY); + effectiveY = newY; + height = newHeight; } return {effectiveX - parentCoord.x, effectiveY - parentCoord.y, width, height}; From 2e3dc17a7e56c609659514af13ce911481334be3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 13:31:27 +0200 Subject: [PATCH 009/298] renderer: guard layer in renderLayer ref #7181 --- src/render/Renderer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7794d476..8c29bef4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -716,6 +716,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec } void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time, bool popups) { + if (!pLayer) + return; + static auto PDIMAROUND = CConfigValue("decoration:dim_around"); if (*PDIMAROUND && pLayer->dimAround && !m_bRenderingSnapshot && !popups) { From f36c625e37f8913d8da38365a4783948f2217f02 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 13:35:02 +0200 Subject: [PATCH 010/298] compositor: minor cleanups for fading out layers --- src/Compositor.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 299a16c6..9b8fd3d7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1425,12 +1425,16 @@ void CCompositor::cleanupFadingOut(const int& monid) { } } + bool layersDirty = false; + for (auto& lsr : m_vSurfacesFadingOut) { auto ls = lsr.lock(); - if (!ls) + if (!ls) { + layersDirty = true; continue; + } if (ls->monitorID != monid) continue; @@ -1443,7 +1447,7 @@ void CCompositor::cleanupFadingOut(const int& monid) { for (auto& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLayers) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) { - std::erase_if(lsl, [&](auto& other) { return other == ls; }); + std::erase_if(lsl, [&](auto& other) { return other == ls || !other; }); } } } @@ -1459,6 +1463,9 @@ void CCompositor::cleanupFadingOut(const int& monid) { return; } } + + if (layersDirty) + std::erase_if(m_vSurfacesFadingOut, [](const auto& el) { return el.expired(); }); } void CCompositor::addToFadingOutSafe(PHLLS pLS) { From 99e9cb510777c62f56c94137b302186d4d9506d8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 16:08:50 +0200 Subject: [PATCH 011/298] drm-syncobj: fixup fd leak with timelines --- src/protocols/DRMSyncobj.cpp | 5 +++++ src/protocols/DRMSyncobj.hpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 8b0330de..37e6d0f1 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -114,6 +114,11 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP= 0) + close(fd); +} + SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 25dc10c1..bc89a3d3 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -34,6 +34,7 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: CDRMSyncobjTimelineResource(SP resource_, int fd_); + ~CDRMSyncobjTimelineResource(); static SP fromResource(wl_resource*); bool good(); From d5bc3eb1fa0e11e9e77ffef8c8449a9c022a13a5 Mon Sep 17 00:00:00 2001 From: Sami Liedes Date: Wed, 7 Aug 2024 16:28:02 +0200 Subject: [PATCH 012/298] hyprctl: link to much less libraries (#7212) This makes hyprctl start significantly faster. $ time for ((i=0; i<1000; i++)); do hyprctl/hyprctl -j activewindow >/dev/null; done Before: 12.269 s (about 12.3 ms/execution) After: 2.142 s (about 2.1 ms/execution) --- CMakeLists.txt | 6 ++++++ hyprctl/CMakeLists.txt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa58b63d..fc8eafd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,12 @@ else() endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) +pkg_check_modules( + hyprctl_deps + REQUIRED + IMPORTED_TARGET + hyprutils>=0.2.1) + pkg_check_modules( deps REQUIRED diff --git a/hyprctl/CMakeLists.txt b/hyprctl/CMakeLists.txt index 64b983e6..aaffe411 100644 --- a/hyprctl/CMakeLists.txt +++ b/hyprctl/CMakeLists.txt @@ -9,7 +9,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1) add_executable(hyprctl "main.cpp") -target_link_libraries(hyprctl PUBLIC PkgConfig::deps) +target_link_libraries(hyprctl PUBLIC PkgConfig::hyprctl_deps) # binary install(TARGETS hyprctl) From 3e00d7dde774a44b5738d339ce58a4903897942b Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:36:20 -0400 Subject: [PATCH 013/298] compositor: fix general:extend_border_grab_area (#7214) Co-authored-by: Agent_00Ming --- src/Compositor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9b8fd3d7..49408597 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -777,7 +777,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & ALLOW_FLOATING) { for (auto& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); - CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) @@ -807,7 +807,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) continue; - CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent From a399f98c68d017152883fbf81d67624ac3254073 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 7 Aug 2024 16:37:09 +0200 Subject: [PATCH 014/298] cursormgr: avoid scanning ill formed inherit (#7211) avoid adding ill formed Inherit lines to inherit vector and later scanning them, it wont change anything in practice but makes the inherit theme parsing more in line with what its supposed todo. also check for return values of the various string functions so we dont end up erasing the wrong thing. --- src/managers/XCursorManager.cpp | 53 ++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 76c908db..f2a7ab53 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -205,23 +205,56 @@ std::unordered_set CXCursorManager::themePaths(std::string const& t Debug::log(LOG, "XCursor parsing index.theme {}", indexTheme); while (std::getline(infile, line)) { - // Trim leading and trailing whitespace - line.erase(0, line.find_first_not_of(" \t\n\r")); - line.erase(line.find_last_not_of(" \t\n\r") + 1); + if (line.empty()) + continue; + + // Trim leading and trailing whitespace + auto pos = line.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + line.erase(0, pos); + + pos = line.find_last_not_of(" \t\n\r"); + if (pos != std::string::npos && pos < line.length()) { + line.erase(pos + 1); + } + + if (line.rfind("Inherits", 8) != std::string::npos) { // Check if line starts with "Inherits" + std::string inheritThemes = line.substr(8); // Extract the part after "Inherits" + if (inheritThemes.empty()) + continue; - if (line.rfind("Inherits", 0) == 0) { // Check if line starts with "Inherits" - std::string inheritThemes = line.substr(8); // Extract the part after "Inherits" // Remove leading whitespace from inheritThemes and = - inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); - inheritThemes.erase(0, 1); - inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); + pos = inheritThemes.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + inheritThemes.erase(0, pos); + + if (inheritThemes.empty()) + continue; + + if (inheritThemes.at(0) == '=') + inheritThemes.erase(0, 1); + else + continue; // not correct formatted index.theme + + pos = inheritThemes.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + inheritThemes.erase(0, pos); std::stringstream inheritStream(inheritThemes); std::string inheritTheme; while (std::getline(inheritStream, inheritTheme, ',')) { + if (inheritTheme.empty()) + continue; + // Trim leading and trailing whitespace from each theme - inheritTheme.erase(0, inheritTheme.find_first_not_of(" \t\n\r")); - inheritTheme.erase(inheritTheme.find_last_not_of(" \t\n\r") + 1); + pos = inheritTheme.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + inheritTheme.erase(0, pos); + + pos = inheritTheme.find_last_not_of(" \t\n\r"); + if (pos != std::string::npos && pos < inheritTheme.length()) + inheritTheme.erase(inheritTheme.find_last_not_of(" \t\n\r") + 1); + themes.push_back(inheritTheme); } } From ea728315410e220d73a993f17c83ae9dc9be9015 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 17:04:43 +0200 Subject: [PATCH 015/298] wayland/compositor: introduce client commit events --- src/protocols/DRMSyncobj.cpp | 2 +- src/protocols/core/Compositor.cpp | 2 ++ src/protocols/core/Compositor.hpp | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 37e6d0f1..9a48b99a 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -75,7 +75,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPtimeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); }); - listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) { + listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) { // apply timelines if new ones have been attached, otherwise don't touch // the current ones if (pending.releaseTimeline) { diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 656433d3..a767dd52 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -432,6 +432,8 @@ void CWLSurfaceResource::commitPendingState() { pending.bufferDamage.clear(); pending.newBuffer = false; + events.roleCommit.emit(); + if (syncobj && syncobj->current.releaseTimeline && syncobj->current.releaseTimeline->timeline && current.buffer && current.buffer->buffer) current.buffer->releaser = makeShared(syncobj->current.releaseTimeline->timeline, syncobj->current.releasePoint); diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index af0dfa58..a3245399 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -75,8 +75,9 @@ class CWLSurfaceResource { Vector2D sourceSize(); struct { - CSignal precommit; - CSignal commit; + CSignal precommit; // before commit + CSignal roleCommit; // commit for role objects, before regular commit + CSignal commit; // after commit CSignal map; CSignal unmap; CSignal newSubsurface; From 2d552fbaa25f1457c3819521a2750dd30820271b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 18:54:45 +0200 Subject: [PATCH 016/298] renderer: fixup nvidia driver version checks --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8c29bef4..7b29eb77 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2737,7 +2737,7 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { // check nvidia version. Explicit KMS is supported in >=560 // in the case of an error, driverMajor will stay 0 and explicit KMS will be disabled - int driverMajor = 0; + static int driverMajor = 0; static bool once = true; if (once) { From 9a09eac79b85c846e3a865a9078a3f8ff65a9259 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 21:17:10 +0200 Subject: [PATCH 017/298] props: bump version to 0.42.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6599454d..787ffc30 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.41.2 +0.42.0 From 83a334f97df4389ca30cb63e50317a66a82562b9 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:54:41 +0100 Subject: [PATCH 018/298] core: Move to C++26 and use native_handle to CLOEXEC the debug fd (#7219) Requires GCC >= 14 / Clang >= 18 --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- flake.nix | 2 +- meson.build | 2 +- nix/default.nix | 5 +++++ nix/overlays.nix | 2 +- nix/stdcxx.patch | 12 ++++++++++++ src/debug/Log.cpp | 3 +++ 7 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 nix/stdcxx.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index fc8eafd5..cfbd431f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ else() endif() include_directories(. "src/" "subprojects/udis86/" "protocols/") -set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD 26) add_compile_options( -Wall -Wextra diff --git a/flake.nix b/flake.nix index 9c20b3f5..9e1e3ab4 100644 --- a/flake.nix +++ b/flake.nix @@ -95,7 +95,7 @@ devShells = eachSystem (system: { default = pkgsFor.${system}.mkShell.override { - stdenv = pkgsFor.${system}.gcc13Stdenv; + stdenv = pkgsFor.${system}.gcc14Stdenv; } { name = "hyprland-shell"; nativeBuildInputs = with pkgsFor.${system}; [ diff --git a/meson.build b/meson.build index 886f4f9c..e8cd25b4 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ project('Hyprland', 'cpp', 'c', 'optimization=3', 'buildtype=release', 'debug=false', - 'cpp_std=c++23', + 'cpp_std=c++26', ]) datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"' diff --git a/nix/default.nix b/nix/default.nix index e4e12f43..9bae9d83 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -71,6 +71,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov src = lib.cleanSource ../.; }; + patches = [ + # forces GCC to use -std=c++26 + ./stdcxx.patch + ]; + postPatch = '' # Fix hardcoded paths to /usr installation sed -i "s#/usr#$out#" src/render/OpenGL.cpp diff --git a/nix/overlays.nix b/nix/overlays.nix index d8979b45..36206f46 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -31,7 +31,7 @@ in { date = mkDate (self.lastModifiedDate or "19700101"); in { hyprland = final.callPackage ./default.nix { - stdenv = final.gcc13Stdenv; + stdenv = final.gcc14Stdenv; version = "${version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; inherit date; diff --git a/nix/stdcxx.patch b/nix/stdcxx.patch new file mode 100644 index 00000000..032e494d --- /dev/null +++ b/nix/stdcxx.patch @@ -0,0 +1,12 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index cfbd431f..73e8e0c2 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -64,6 +64,7 @@ endif() + include_directories(. "src/" "subprojects/udis86/" "protocols/") + set(CMAKE_CXX_STANDARD 26) + add_compile_options( ++ -std=c++26 + -Wall + -Wextra + -Wno-unused-parameter diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 0def77c0..a4c5b08e 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -5,10 +5,13 @@ #include #include +#include void Debug::init(const std::string& IS) { logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); logOfs.open(logFile, std::ios::out | std::ios::app); + auto handle = logOfs.native_handle(); + fcntl(handle, F_SETFD, FD_CLOEXEC); } void Debug::close() { From 4b4971c06fb02df00a2bd20b6b47b5d0e7d799a7 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 8 Aug 2024 21:01:50 +0200 Subject: [PATCH 019/298] internal: introduce new types to avoid unsigned int rollover and signed int overflow (#7216) * framebuffer: avoid gluint overflow GLuint was being initialized to -1 and rolling over to unsigned int max, its defined behaviour but very unnecessery. add a bool and use it for checking if allocated or not. * opengl: avoid gluint rollover -1 rolls over to unsigned int max, use 0xFF instead. * core: big uint64_t to int type conversion there were a few uint64_t to int implicit conversions overflowing int and causing UB, make all monitor/workspaces/windows use the new typedefs. also fix the various related 64 to 32 implicit conversions going around found with -Wshorten-64-to-32 --- hyprctl/main.cpp | 2 +- src/Compositor.cpp | 74 ++++++------- src/Compositor.hpp | 115 ++++++++++---------- src/SharedDefs.hpp | 4 + src/config/ConfigManager.cpp | 2 +- src/config/ConfigManager.hpp | 2 +- src/debug/HyprCtl.cpp | 4 +- src/desktop/LayerSurface.cpp | 4 +- src/desktop/LayerSurface.hpp | 4 +- src/desktop/Window.cpp | 2 +- src/desktop/Window.hpp | 14 +-- src/desktop/Workspace.cpp | 14 +-- src/desktop/Workspace.hpp | 10 +- src/events/Windows.cpp | 2 +- src/helpers/MiscFunctions.cpp | 78 ++++++------- src/helpers/MiscFunctions.hpp | 4 +- src/helpers/Monitor.cpp | 14 +-- src/helpers/Monitor.hpp | 52 ++++----- src/helpers/Timer.cpp | 2 +- src/helpers/Timer.hpp | 2 +- src/layout/DwindleLayout.cpp | 12 +- src/layout/DwindleLayout.hpp | 12 +- src/layout/IHyprLayout.hpp | 2 +- src/layout/MasterLayout.cpp | 10 +- src/layout/MasterLayout.hpp | 14 +-- src/macros.hpp | 2 + src/managers/KeybindManager.cpp | 6 +- src/managers/eventLoop/EventLoopManager.cpp | 4 +- src/managers/input/InputMethodPopup.hpp | 2 +- src/managers/input/Swipe.cpp | 2 +- src/protocols/ForeignToplevelWlr.cpp | 2 +- src/protocols/ForeignToplevelWlr.hpp | 2 +- src/render/Framebuffer.cpp | 11 +- src/render/Framebuffer.hpp | 3 +- src/render/OpenGL.cpp | 16 +-- src/render/Renderer.cpp | 2 +- src/render/Renderer.hpp | 2 +- src/signal-safe.cpp | 2 +- src/signal-safe.hpp | 4 +- 39 files changed, 263 insertions(+), 252 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 336d479e..c86406fc 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -113,7 +113,7 @@ int rollingRead(const int socket) { constexpr size_t BUFFER_SIZE = 8192; std::array buffer = {0}; - int sizeWritten = 0; + long sizeWritten = 0; std::cout << "[hyprctl] reading from socket following up log:" << std::endl; while (!sigintReceived) { sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 49408597..e3a347fd 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -683,9 +683,9 @@ void CCompositor::startCompositor() { g_pEventLoopManager->enterLoop(); } -CMonitor* CCompositor::getMonitorFromID(const int& id) { +CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { for (auto& m : m_vMonitors) { - if (m->ID == (uint64_t)id) { + if (m->ID == id) { return m.get(); } } @@ -845,8 +845,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & FLOATING_ONLY) return floating(false); - const int64_t WORKSPACEID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID(); - const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID); + const WORKSPACEID WSPID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID(); + const auto PWORKSPACE = getWorkspaceByID(WSPID); if (PWORKSPACE->m_bHasFullscreenWindow) return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); @@ -860,7 +860,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (special != w->onSpecialWorkspace()) continue; - if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && + if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (w->hasPopupAt(pos)) return w; @@ -872,7 +872,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; - if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && + if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) return w; } @@ -1207,7 +1207,7 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { return nullptr; } -PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { +PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) { for (auto& w : m_vWindows) { if (w->workspaceID() == ID && w->isFullscreen()) return w; @@ -1231,7 +1231,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { return PMONITOR->activeWorkspace->m_iID == w->m_iID; } -PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) { +PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) { for (auto& w : m_vWorkspaces) { if (w->m_iID == id && !w->inert()) return w; @@ -1255,7 +1255,7 @@ void CCompositor::sanityCheckWorkspaces() { } } -int CCompositor::getWindowsOnWorkspace(const int& id, std::optional onlyTiled, std::optional onlyVisible) { +int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; for (auto& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) @@ -1270,7 +1270,7 @@ int CCompositor::getWindowsOnWorkspace(const int& id, std::optional onlyTi return no; } -int CCompositor::getGroupsOnWorkspace(const int& id, std::optional onlyTiled, std::optional onlyVisible) { +int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; for (auto& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) @@ -1295,7 +1295,7 @@ PHLWINDOW CCompositor::getUrgentWindow() { return nullptr; } -bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) { +bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) { for (auto& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent) return true; @@ -1304,7 +1304,7 @@ bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) { return false; } -PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) { +PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) { for (auto& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden()) return w; @@ -1313,7 +1313,7 @@ PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) { return nullptr; } -PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const int& id) { +PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) { const auto PWORKSPACE = getWorkspaceByID(id); if (!PWORKSPACE) @@ -1401,12 +1401,12 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { } } -void CCompositor::cleanupFadingOut(const int& monid) { +void CCompositor::cleanupFadingOut(const MONITORID& monid) { for (auto& ww : m_vWindowsFadingOut) { auto w = ww.lock(); - if (w->m_iMonitorID != (long unsigned int)monid) + if (w->m_iMonitorID != monid) continue; if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) { @@ -1702,8 +1702,8 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl return nullptr; } -int CCompositor::getNextAvailableNamedWorkspace() { - int lowest = -1337 + 1; +WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { + WORKSPACEID lowest = -1337 + 1; for (auto& w : m_vWorkspaces) { if (w->m_iID < -1 && w->m_iID < lowest) lowest = w->m_iID; @@ -1927,18 +1927,18 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { pWindow->updateWindowDecos(); } -int CCompositor::getNextAvailableMonitorID(std::string const& name) { +MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { // reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) return m_mMonitorIDMap[name]; // otherwise, find minimum available ID that is not in the map - std::unordered_set usedIDs; + std::unordered_set usedIDs; for (auto const& monitor : m_vRealMonitors) { usedIDs.insert(monitor->ID); } - uint64_t nextID = 0; + MONITORID nextID = 0; while (usedIDs.count(nextID) > 0) { nextID++; } @@ -2078,7 +2078,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { return m_vMonitors[currentPlace].get(); } else if (isNumber(name)) { // change by ID - int monID = -1; + MONITORID monID = MONITOR_INVALID; try { monID = std::stoi(name); } catch (std::exception& e) { @@ -2087,7 +2087,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { return nullptr; } - if (monID > -1 && monID < (int)m_vMonitors.size()) { + if (monID > -1 && monID < (MONITORID)m_vMonitors.size()) { return getMonitorFromID(monID); } else { Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1"); @@ -2121,7 +2121,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false; // fix old mon - int nextWorkspaceOnMonitorID = -1; + WORKSPACEID nextWorkspaceOnMonitorID = WORKSPACE_INVALID; if (!SWITCHINGISACTIVE) nextWorkspaceOnMonitorID = pWorkspace->m_iID; else { @@ -2132,7 +2132,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon } } - if (nextWorkspaceOnMonitorID == -1) { + if (nextWorkspaceOnMonitorID == WORKSPACE_INVALID) { nextWorkspaceOnMonitorID = 1; while (getWorkspaceByID(nextWorkspaceOnMonitorID) || [&]() -> bool { @@ -2219,9 +2219,9 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon EMIT_HOOK_EVENT("moveWorkspace", (std::vector{pWorkspace, pMonitor})); } -bool CCompositor::workspaceIDOutOfBounds(const int64_t& id) { - int64_t lowestID = INT64_MAX; - int64_t highestID = INT64_MIN; +bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { + WORKSPACEID lowestID = INT64_MAX; + WORKSPACEID highestID = INT64_MIN; for (auto& w : m_vWorkspaces) { if (w->m_bIsSpecialWorkspace) @@ -2370,7 +2370,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { return nullptr; } -void CCompositor::updateWorkspaceWindowDecos(const int& id) { +void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) { for (auto& w : m_vWindows) { if (w->workspaceID() != id) continue; @@ -2379,7 +2379,7 @@ void CCompositor::updateWorkspaceWindowDecos(const int& id) { } } -void CCompositor::updateWorkspaceWindowData(const int& id) { +void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) { const auto PWORKSPACE = getWorkspaceByID(id); const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; @@ -2599,7 +2599,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con return Vector2D(X, Y); } -void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { +void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) { for (auto& w : m_vWindows) { if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) { g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); @@ -2607,7 +2607,7 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { } } -PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name, bool isEmtpy) { +PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmtpy) { const auto NAME = name == "" ? std::to_string(id) : name; auto monID = monid; @@ -2625,7 +2625,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, co return PWORKSPACE; } -void CCompositor::renameWorkspace(const int& id, const std::string& name) { +void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name) { const auto PWORKSPACE = getWorkspaceByID(id); if (!PWORKSPACE) @@ -2656,12 +2656,12 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) { m_pLastMonitor = pMonitor->self; } -bool CCompositor::isWorkspaceSpecial(const int& id) { +bool CCompositor::isWorkspaceSpecial(const WORKSPACEID& id) { return id >= SPECIAL_WORKSPACE_START && id <= -2; } -int CCompositor::getNewSpecialID() { - int highest = SPECIAL_WORKSPACE_START; +WORKSPACEID CCompositor::getNewSpecialID() { + WORKSPACEID highest = SPECIAL_WORKSPACE_START; for (auto& ws : m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) { highest = ws->m_iID; @@ -2965,7 +2965,7 @@ void CCompositor::onNewMonitor(SP output) { PNEWMONITOR->output = output; PNEWMONITOR->self = PNEWMONITOR; const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false; - PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(output->name); + PNEWMONITOR->ID = FALLBACK ? MONITOR_INVALID : g_pCompositor->getNextAvailableMonitorID(output->name); PNEWMONITOR->isUnsafeFallback = FALLBACK; EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); @@ -2990,7 +2990,7 @@ void CCompositor::onNewMonitor(SP output) { for (auto& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { - w->m_iLastSurfaceMonitorID = -1; + w->m_iLastSurfaceMonitorID = MONITOR_INVALID; w->updateSurfaceScaleTransformDetails(); } } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 295935c4..5e9e3266 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -46,55 +46,55 @@ class CCompositor { CCompositor(); ~CCompositor(); - wl_display* m_sWLDisplay; - wl_event_loop* m_sWLEventLoop; - int m_iDRMFD = -1; - bool m_bInitialized = false; - SP m_pAqBackend; + wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; + int m_iDRMFD = -1; + bool m_bInitialized = false; + SP m_pAqBackend; - std::string m_szHyprTempDataRoot = ""; + std::string m_szHyprTempDataRoot = ""; - std::string m_szWLDisplaySocket = ""; - std::string m_szInstanceSignature = ""; - std::string m_szInstancePath = ""; - std::string m_szCurrentSplash = "error"; + std::string m_szWLDisplaySocket = ""; + std::string m_szInstanceSignature = ""; + std::string m_szInstancePath = ""; + std::string m_szCurrentSplash = "error"; - std::vector> m_vMonitors; - std::vector> m_vRealMonitors; // for all monitors, even those turned off - std::vector m_vWindows; - std::vector m_vLayers; - std::vector m_vWorkspaces; - std::vector m_vWindowsFadingOut; - std::vector m_vSurfacesFadingOut; + std::vector> m_vMonitors; + std::vector> m_vRealMonitors; // for all monitors, even those turned off + std::vector m_vWindows; + std::vector m_vLayers; + std::vector m_vWorkspaces; + std::vector m_vWindowsFadingOut; + std::vector m_vSurfacesFadingOut; - std::unordered_map m_mMonitorIDMap; + std::unordered_map m_mMonitorIDMap; - void initServer(std::string socketName, int socketFd); - void startCompositor(); - void stopCompositor(); - void cleanup(); - void createLockFile(); - void removeLockFile(); - void bumpNofile(); - void restoreNofile(); + void initServer(std::string socketName, int socketFd); + void startCompositor(); + void stopCompositor(); + void cleanup(); + void createLockFile(); + void removeLockFile(); + void bumpNofile(); + void restoreNofile(); - WP m_pLastFocus; - PHLWINDOWREF m_pLastWindow; - WP m_pLastMonitor; + WP m_pLastFocus; + PHLWINDOWREF m_pLastWindow; + WP m_pLastMonitor; - std::vector m_vWindowFocusHistory; // first element is the most recently focused. + std::vector m_vWindowFocusHistory; // first element is the most recently focused. - bool m_bReadyToProcess = false; - bool m_bSessionActive = true; - bool m_bDPMSStateON = true; - bool m_bUnsafeState = false; // unsafe state is when there is no monitors. - bool m_bNextIsUnsafe = false; - CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state - bool m_bIsShuttingDown = false; + bool m_bReadyToProcess = false; + bool m_bSessionActive = true; + bool m_bDPMSStateON = true; + bool m_bUnsafeState = false; // unsafe state is when there is no monitors. + bool m_bNextIsUnsafe = false; + CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state + bool m_bIsShuttingDown = false; // ------------------------------------------------- // - CMonitor* getMonitorFromID(const int&); + CMonitor* getMonitorFromID(const MONITORID&); CMonitor* getMonitorFromName(const std::string&); CMonitor* getMonitorFromDesc(const std::string&); CMonitor* getMonitorFromCursor(); @@ -114,38 +114,38 @@ class CCompositor { PHLWINDOW getWindowFromHandle(uint32_t); bool isWorkspaceVisible(PHLWORKSPACE); bool isWorkspaceVisibleNotCovered(PHLWORKSPACE); - PHLWORKSPACE getWorkspaceByID(const int&); + PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&); PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&); void sanityCheckWorkspaces(); - void updateWorkspaceWindowDecos(const int&); - void updateWorkspaceWindowData(const int&); - int getWindowsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); - int getGroupsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); + void updateWorkspaceWindowDecos(const WORKSPACEID&); + void updateWorkspaceWindowData(const WORKSPACEID&); + int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); + int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); PHLWINDOW getUrgentWindow(); - bool hasUrgentWindowOnWorkspace(const int&); - PHLWINDOW getFirstWindowOnWorkspace(const int&); - PHLWINDOW getTopLeftWindowOnWorkspace(const int&); - PHLWINDOW getFullscreenWindowOnWorkspace(const int&); + bool hasUrgentWindowOnWorkspace(const WORKSPACEID&); + PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&); + PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&); + PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&); bool isWindowActive(PHLWINDOW); void changeWindowZOrder(PHLWINDOW, bool); - void cleanupFadingOut(const int& monid); + void cleanupFadingOut(const MONITORID& monid); PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); - int getNextAvailableNamedWorkspace(); + WORKSPACEID getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); CMonitor* getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(CMonitor*, const char&); void updateAllWindowsAnimatedDecorationValues(); - void updateWorkspaceWindows(const int64_t& id); + void updateWorkspaceWindows(const WORKSPACEID& id); void updateWindowAnimatedDecorationValues(PHLWINDOW); - int getNextAvailableMonitorID(std::string const& name); + MONITORID getNextAvailableMonitorID(std::string const& name); void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); void swapActiveWorkspaces(CMonitor*, CMonitor*); CMonitor* getMonitorFromString(const std::string&); - bool workspaceIDOutOfBounds(const int64_t&); + bool workspaceIDOutOfBounds(const WORKSPACEID&); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state); @@ -162,12 +162,13 @@ class CCompositor { PHLLS getLayerSurfaceFromSurface(SP); void closeWindow(PHLWINDOW); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); - void forceReportSizesToWindowsOnWorkspace(const int&); - PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! - void renameWorkspace(const int&, const std::string& name = ""); + void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&); + PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", + bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! + void renameWorkspace(const WORKSPACEID&, const std::string& name = ""); void setActiveMonitor(CMonitor*); - bool isWorkspaceSpecial(const int&); - int getNewSpecialID(); + bool isWorkspaceSpecial(const WORKSPACEID&); + WORKSPACEID getNewSpecialID(); void performUserChecks(); void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); PHLWINDOW getForceFocus(); diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp index 2a1546c6..9bee7150 100644 --- a/src/SharedDefs.hpp +++ b/src/SharedDefs.hpp @@ -52,4 +52,8 @@ struct SHyprCtlCommand { std::function fn; }; +typedef int64_t WINDOWID; +typedef int64_t MONITORID; +typedef int64_t WORKSPACEID; + typedef std::function HOOK_CALLBACK_FN; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index be6433fa..1a823f3e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2425,7 +2425,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin // } const static std::string ruleOnCreatedEmpty = "on-created-empty:"; - const static int ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length(); + const static auto ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length(); auto assignRule = [&](std::string rule) -> std::optional { size_t delim = std::string::npos; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 75dea9ef..38dd0872 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -33,7 +33,7 @@ struct SWorkspaceRule { std::string monitor = ""; std::string workspaceString = ""; std::string workspaceName = ""; - int workspaceId = -1; + WORKSPACEID workspaceId = -1; bool isDefault = false; bool isPersistent = false; std::optional gapsIn; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d91a1cec..3ab0fa7a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -71,7 +71,7 @@ static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFor std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer m, eHyprCtlOutputFormat format) { std::string result; - if (!m->output || m->ID == -1ull) + if (!m->output || m->ID == -1) return ""; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { @@ -155,7 +155,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { result += "]"; } else { for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { - if (!m->output || m->ID == -1ull) + if (!m->output || m->ID == -1) continue; result += diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 8fd448ef..c352fa74 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -432,8 +432,8 @@ void CLayerSurface::startAnimation(bool in, bool instant) { PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, }; - float closest = std::numeric_limits::max(); - int leader = force; + float closest = std::numeric_limits::max(); + size_t leader = force; if (leader == -1) { for (size_t i = 0; i < 4; ++i) { float dist = MIDDLE.distance(edgePoints[i]); diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 056f66a8..84935b34 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -42,7 +42,7 @@ class CLayerSurface { bool mapped = false; uint32_t layer = 0; - int monitorID = -1; + MONITORID monitorID = -1; bool fadingOut = false; bool readyToDelete = false; @@ -51,7 +51,7 @@ class CLayerSurface { bool forceBlur = false; bool forceBlurPopups = false; - int xray = -1; + int64_t xray = -1; bool ignoreAlpha = false; float ignoreAlphaValue = 0.f; bool dimAround = false; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 93c208cf..dcdcb573 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1243,7 +1243,7 @@ bool CWindow::isEffectiveInternalFSMode(const eFullscreenMode MODE) { return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE; } -int CWindow::workspaceID() { +WORKSPACEID CWindow::workspaceID() { return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 11bf662a..2e5b54b1 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -270,7 +270,7 @@ class CWindow { bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bWasMaximized = false; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; - uint64_t m_iMonitorID = -1; + MONITORID m_iMonitorID = -1; std::string m_szTitle = ""; std::string m_szClass = ""; std::string m_szInitialTitle = ""; @@ -358,8 +358,8 @@ class CWindow { bool m_bStayFocused = false; // for toplevel monitor events - uint64_t m_iLastToplevelMonitorID = -1; - uint64_t m_iLastSurfaceMonitorID = -1; + MONITORID m_iLastToplevelMonitorID = -1; + MONITORID m_iLastSurfaceMonitorID = -1; // for idle inhibiting windows eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE; @@ -421,7 +421,7 @@ class CWindow { bool canBeTorn(); void setSuspended(bool suspend); bool visibleOnMonitor(CMonitor* pMonitor); - int workspaceID(); + WORKSPACEID workspaceID(); bool onSpecialWorkspace(); void activate(bool force = false); int surfacesCount(); @@ -490,9 +490,9 @@ class CWindow { private: // For hidden windows and stuff - bool m_bHidden = false; - bool m_bSuspended = false; - int m_iLastWorkspace = WORKSPACE_INVALID; + bool m_bHidden = false; + bool m_bSuspended = false; + WORKSPACEID m_iLastWorkspace = WORKSPACE_INVALID; }; inline bool valid(PHLWINDOW w) { diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index a08f1804..d9ac7927 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -5,13 +5,13 @@ #include using namespace Hyprutils::String; -PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) { +PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy); workspace->init(workspace); return workspace; } -CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special, bool isEmtpy) { +CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { m_iMonitorID = monitorID; m_iID = id; m_szName = name; @@ -190,7 +190,7 @@ void CWorkspace::setActive(bool on) { ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40 } -void CWorkspace::moveToMonitor(const int& id) { +void CWorkspace::moveToMonitor(const MONITORID& id) { ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40 } @@ -275,7 +275,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { i = std::min(NEXTSPACE, std::string::npos - 1); if (cur == 'r') { - int from = 0, to = 0; + WORKSPACEID from = 0, to = 0; if (!prop.starts_with("r[") || !prop.ends_with("]")) { Debug::log(LOG, "Invalid selector {}", selector); return false; @@ -365,7 +365,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { } if (cur == 'w') { - int from = 0, to = 0; + WORKSPACEID from = 0, to = 0; if (!prop.starts_with("w[") || !prop.ends_with("]")) { Debug::log(LOG, "Invalid selector {}", selector); return false; @@ -446,7 +446,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { return false; } - int count; + WORKSPACEID count; if (wantsCountGroup) count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); @@ -506,7 +506,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { void CWorkspace::markInert() { m_bInert = true; m_iID = WORKSPACE_INVALID; - m_iMonitorID = -1; + m_iMonitorID = MONITOR_INVALID; m_bVisible = false; } diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 3e9ac8a8..9cacb0cc 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -17,16 +17,16 @@ class CWindow; class CWorkspace { public: - static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false, bool isEmtpy = true); + static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmtpy = true); // use create() don't use this - CWorkspace(int id, int monitorID, std::string name, bool special = false, bool isEmpty = true); + CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); ~CWorkspace(); // Workspaces ID-based have IDs > 0 // and workspaces name-based have IDs starting with -1337 - int m_iID = -1; + WORKSPACEID m_iID = WORKSPACE_INVALID; std::string m_szName = ""; - uint64_t m_iMonitorID = -1; + MONITORID m_iMonitorID = MONITOR_INVALID; // Previous workspace ID and name is stored during a workspace change, allowing travel // to the previous workspace. SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; @@ -67,7 +67,7 @@ class CWorkspace { void startAnim(bool in, bool left, bool instant = false); void setActive(bool on); - void moveToMonitor(const int&); + void moveToMonitor(const MONITORID&); PHLWINDOW getLastFocusedWindow(); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 5d29a3b7..2eb7038f 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -148,7 +148,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_iMonitorID = PMONITOR->ID; } else { if (isNumber(MONITORSTR)) { - const long int MONITOR = std::stoi(MONITORSTR); + const MONITORID MONITOR = std::stoi(MONITORSTR); if (!g_pCompositor->getMonitorFromID(MONITOR)) PWINDOW->m_iMonitorID = 0; else diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 53c0dc13..a81aa7d1 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -249,7 +249,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { return {WORKSPACE_INVALID}; } - std::set invalidWSes; + std::set invalidWSes; if (same_mon) { for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); @@ -258,8 +258,8 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } } - int id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; - while (++id < INT_MAX) { + WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; + while (++id < LONG_MAX) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) { result.id = id; @@ -296,9 +296,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { result.id = (int)PLUSMINUSRESULT.value(); - int remains = (int)result.id; + WORKSPACEID remains = result.id; - std::set invalidWSes; + std::set invalidWSes; // Collect all the workspaces we can't jump to. for (auto& ws : g_pCompositor->m_vWorkspaces) { @@ -318,7 +318,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } // Prepare all named workspaces in case when we need them - std::vector namedWSes; + std::vector namedWSes; for (auto& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0) continue; @@ -347,18 +347,18 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } else { // Just take a blind guess at where we'll probably end up - int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; - int predictedWSID = activeWSID + remains; - int remainingWSes = 0; - char walkDir = in[1]; + WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; + WORKSPACEID predictedWSID = activeWSID + remains; + int remainingWSes = 0; + char walkDir = in[1]; // sanitize. 0 means invalid oob in - - predictedWSID = std::max(predictedWSID, 0); + predictedWSID = std::max(predictedWSID, 0L); // Count how many invalidWSes are in between (how bad the prediction was) - int beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID; - int endID = in[1] == '+' ? predictedWSID : activeWSID; - auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= + WORKSPACEID beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID; + WORKSPACEID endID = in[1] == '+' ? predictedWSID : activeWSID; + auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { remainingWSes++; } @@ -367,7 +367,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { if (activeWSID < 0) { // Behaviour similar to 'm' // Find current - int currentItem = -1; + size_t currentItem = -1; for (size_t i = 0; i < namedWSes.size(); i++) { if (namedWSes[i] == activeWSID) { currentItem = i; @@ -376,14 +376,14 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } currentItem += remains; - currentItem = std::max(currentItem, 0); - if (currentItem >= (int)namedWSes.size()) { + currentItem = std::max(currentItem, 0UL); + if (currentItem >= namedWSes.size()) { // At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0 - int diff = currentItem - (namedWSes.size() - 1); - predictedWSID = diff; - int beginID = 1; - int endID = predictedWSID; - auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= + size_t diff = currentItem - (namedWSes.size() - 1); + predictedWSID = diff; + WORKSPACEID beginID = 1; + WORKSPACEID endID = predictedWSID; + auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { remainingWSes++; } @@ -397,10 +397,10 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Go in the search direction for remainingWSes // The performance impact is directly proportional to the number of open and bound workspaces - int finalWSID = predictedWSID; + WORKSPACEID finalWSID = predictedWSID; if (walkDir == '-') { - int beginID = finalWSID; - int curID = finalWSID; + WORKSPACEID beginID = finalWSID; + WORKSPACEID curID = finalWSID; while (--curID > 0 && remainingWSes > 0) { if (!invalidWSes.contains(curID)) { remainingWSes--; @@ -411,9 +411,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { if (namedWSes.size()) { // Go to the named workspaces // Need remainingWSes more - int namedWSIdx = namedWSes.size() - remainingWSes; + auto namedWSIdx = namedWSes.size() - remainingWSes; // Sanitze - namedWSIdx = std::clamp(namedWSIdx, 0, (int)namedWSes.size() - 1); + namedWSIdx = std::clamp(namedWSIdx, 0UL, namedWSes.size() - 1); finalWSID = namedWSes[namedWSIdx]; } else { // Couldn't find valid workspace in negative direction, search last first one back up positive direction @@ -425,7 +425,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } } if (walkDir == '+') { - int curID = finalWSID; + WORKSPACEID curID = finalWSID; while (++curID < INT32_MAX && remainingWSes > 0) { if (!invalidWSes.contains(curID)) { remainingWSes--; @@ -460,9 +460,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { result.id = (int)PLUSMINUSRESULT.value(); // result now has +/- what we should move on mon - int remains = (int)result.id; + int remains = (int)result.id; - std::vector validWSes; + std::vector validWSes; for (auto& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors)) continue; @@ -472,7 +472,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::sort(validWSes.begin(), validWSes.end()); - int currentItem = -1; + size_t currentItem = -1; if (absolute) { // 1-index @@ -481,7 +481,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // clamp if (currentItem < 0) { currentItem = 0; - } else if (currentItem >= (int)validWSes.size()) { + } else if (currentItem >= validWSes.size()) { currentItem = validWSes.size() - 1; } } else { @@ -489,7 +489,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size(); // get the current item - int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; + WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; for (size_t i = 0; i < validWSes.size(); i++) { if (validWSes[i] == activeWSID) { currentItem = i; @@ -501,7 +501,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { currentItem += remains; // sanitize - if (currentItem >= (int)validWSes.size()) { + if (currentItem >= validWSes.size()) { currentItem = currentItem % validWSes.size(); } else if (currentItem < 0) { currentItem = validWSes.size() + currentItem; @@ -547,9 +547,9 @@ std::optional cleanCmdForWorkspace(const std::string& inWorkspaceNa const std::string workspaceRule = "workspace " + inWorkspaceName; if (cmd[0] == '[') { - const int closingBracketIdx = cmd.find_last_of(']'); - auto tmpRules = cmd.substr(1, closingBracketIdx - 1); - cmd = cmd.substr(closingBracketIdx + 1); + const auto closingBracketIdx = cmd.find_last_of(']'); + auto tmpRules = cmd.substr(1, closingBracketIdx - 1); + cmd = cmd.substr(closingBracketIdx + 1); auto rulesList = CVarList(tmpRules, 0, ';'); @@ -785,13 +785,13 @@ std::vector getBacktrace() { #ifdef HAS_EXECINFO void* bt[1024]; - size_t btSize; + int btSize; char** btSymbols; btSize = backtrace(bt, 1024); btSymbols = backtrace_symbols(bt, btSize); - for (size_t i = 0; i < btSize; ++i) { + for (auto i = 0; i < btSize; ++i) { callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}}); } #else diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 49e3bced..7eb2a1ed 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -6,6 +6,8 @@ #include "math/Math.hpp" #include #include +#include "SharedDefs.hpp" +#include "macros.hpp" struct SCallstackFrameInfo { void* adr = nullptr; @@ -13,7 +15,7 @@ struct SCallstackFrameInfo { }; struct SWorkspaceIDName { - int id = -1; + WORKSPACEID id = WORKSPACE_INVALID; std::string name; }; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 8f23c462..f6b61d57 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -389,8 +389,8 @@ bool CMonitor::matchesStaticSelector(const std::string& selector) const { } } -int CMonitor::findAvailableDefaultWS() { - for (size_t i = 1; i < INT32_MAX; ++i) { +WORKSPACEID CMonitor::findAvailableDefaultWS() { + for (WORKSPACEID i = 1; i < LONG_MAX; ++i) { if (g_pCompositor->getWorkspaceByID(i)) continue; @@ -400,7 +400,7 @@ int CMonitor::findAvailableDefaultWS() { return i; } - return INT32_MAX; // shouldn't be reachable + return LONG_MAX; // shouldn't be reachable } void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { @@ -638,7 +638,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo g_pCompositor->updateFullscreenFadeOnWorkspace(activeSpecialWorkspace); } -void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) { +void CMonitor::changeWorkspace(const WORKSPACEID& id, bool internal, bool noMouseMove, bool noFocus) { changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus); } @@ -745,7 +745,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pCompositor->updateSuspendedStates(); } -void CMonitor::setSpecialWorkspace(const int& id) { +void CMonitor::setSpecialWorkspace(const WORKSPACEID& id) { setSpecialWorkspace(g_pCompositor->getWorkspaceByID(id)); } @@ -766,11 +766,11 @@ void CMonitor::updateMatrix() { } } -int64_t CMonitor::activeWorkspaceID() { +WORKSPACEID CMonitor::activeWorkspaceID() { return activeWorkspace ? activeWorkspace->m_iID : 0; } -int64_t CMonitor::activeSpecialWorkspaceID() { +WORKSPACEID CMonitor::activeSpecialWorkspaceID() { return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index fbe26f67..7429ecf1 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -70,7 +70,7 @@ class CMonitor { bool primary = false; - uint64_t ID = -1; + MONITORID ID = MONITOR_INVALID; PHLWORKSPACE activeWorkspace = nullptr; PHLWORKSPACE activeSpecialWorkspace = nullptr; float setScale = 1; // scale set by cfg @@ -155,31 +155,31 @@ class CMonitor { std::array, 4> m_aLayerSurfaceLayers; // methods - void onConnect(bool noRule); - void onDisconnect(bool destroy = false); - void addDamage(const pixman_region32_t* rg); - void addDamage(const CRegion* rg); - void addDamage(const CBox* box); - bool shouldSkipScheduleFrameOnMouseEvent(); - void setMirror(const std::string&); - bool isMirror(); - bool matchesStaticSelector(const std::string& selector) const; - float getDefaultScale(); - void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false); - void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false); - void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace); - void setSpecialWorkspace(const int& id); - void moveTo(const Vector2D& pos); - Vector2D middle(); - void updateMatrix(); - int64_t activeWorkspaceID(); - int64_t activeSpecialWorkspaceID(); - CBox logicalBox(); - void scheduleDone(); - bool attemptDirectScanout(); + void onConnect(bool noRule); + void onDisconnect(bool destroy = false); + void addDamage(const pixman_region32_t* rg); + void addDamage(const CRegion* rg); + void addDamage(const CBox* box); + bool shouldSkipScheduleFrameOnMouseEvent(); + void setMirror(const std::string&); + bool isMirror(); + bool matchesStaticSelector(const std::string& selector) const; + float getDefaultScale(); + void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false); + void changeWorkspace(const WORKSPACEID& id, bool internal = false, bool noMouseMove = false, bool noFocus = false); + void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace); + void setSpecialWorkspace(const WORKSPACEID& id); + void moveTo(const Vector2D& pos); + Vector2D middle(); + void updateMatrix(); + WORKSPACEID activeWorkspaceID(); + WORKSPACEID activeSpecialWorkspaceID(); + CBox logicalBox(); + void scheduleDone(); + bool attemptDirectScanout(); - bool m_bEnabled = false; - bool m_bRenderingInitPassed = false; + bool m_bEnabled = false; + bool m_bRenderingInitPassed = false; // For the list lookup @@ -189,7 +189,7 @@ class CMonitor { private: void setupDefaultWS(const SMonitorRule&); - int findAvailableDefaultWS(); + WORKSPACEID findAvailableDefaultWS(); wl_event_source* doneSource = nullptr; diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp index ec530df4..7b1726df 100644 --- a/src/helpers/Timer.cpp +++ b/src/helpers/Timer.cpp @@ -8,7 +8,7 @@ std::chrono::steady_clock::duration CTimer::getDuration() { return std::chrono::steady_clock::now() - m_tpLastReset; } -int CTimer::getMillis() { +long CTimer::getMillis() { return std::chrono::duration_cast(getDuration()).count(); } diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp index a6d1aeed..827e7625 100644 --- a/src/helpers/Timer.hpp +++ b/src/helpers/Timer.hpp @@ -6,7 +6,7 @@ class CTimer { public: void reset(); float getSeconds(); - int getMillis(); + long getMillis(); const std::chrono::steady_clock::time_point& chrono() const; private: diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index f287056f..acdc3de2 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -47,7 +47,7 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque* pD } } -int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) { +int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) { int no = 0; for (auto& n : m_lDwindleNodesData) { if (n.workspaceID == id && n.valid) @@ -56,7 +56,7 @@ int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) { return no; } -SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) { +SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const WORKSPACEID& id) { for (auto& n : m_lDwindleNodesData) { if (n.workspaceID == id && validMapped(n.pWindow)) return &n; @@ -64,7 +64,7 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) { return nullptr; } -SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) { +SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const WORKSPACEID& id, const Vector2D& point) { SDwindleNodeData* res = nullptr; double distClosest = -1; for (auto& n : m_lDwindleNodesData) { @@ -88,7 +88,7 @@ SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(PHLWINDOW pWindow) { return nullptr; } -SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const int& id) { +SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const WORKSPACEID& id) { for (auto& n : m_lDwindleNodesData) { if (!n.pParent && n.workspaceID == id) return &n; @@ -535,7 +535,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { m_lDwindleNodesData.remove(*PNODE); } -void CHyprDwindleLayout::recalculateMonitor(const int& monid) { +void CHyprDwindleLayout::recalculateMonitor(const MONITORID& monid) { const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); if (!PMONITOR || !PMONITOR->activeWorkspace) @@ -872,7 +872,7 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir, return; const auto PNODE = getNodeFromWindow(pWindow); - const int originalWorkspaceID = pWindow->workspaceID(); + const auto originalWorkspaceID = pWindow->workspaceID(); const Vector2D originalPos = pWindow->middle(); if (!PNODE) diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index f638f6a2..bbd511c2 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -24,7 +24,7 @@ struct SDwindleNodeData { CBox box = {0}; - int workspaceID = -1; + WORKSPACEID workspaceID = WORKSPACE_INVALID; float splitRatio = 1.f; @@ -48,7 +48,7 @@ class CHyprDwindleLayout : public IHyprLayout { virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowRemovedTiling(PHLWINDOW); virtual bool isWindowTiled(PHLWINDOW); - virtual void recalculateMonitor(const int&); + virtual void recalculateMonitor(const MONITORID&); virtual void recalculateWindow(PHLWINDOW); virtual void onBeginDragWindow(); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); @@ -77,13 +77,13 @@ class CHyprDwindleLayout : public IHyprLayout { std::optional m_vOverrideFocalPoint; // for onWindowCreatedTiling. - int getNodesOnWorkspace(const int&); + int getNodesOnWorkspace(const WORKSPACEID&); void applyNodeDataToWindow(SDwindleNodeData*, bool force = false); void calculateWorkspace(const PHLWORKSPACE& pWorkspace); SDwindleNodeData* getNodeFromWindow(PHLWINDOW); - SDwindleNodeData* getFirstNodeOnWorkspace(const int&); - SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&); - SDwindleNodeData* getMasterNodeOnWorkspace(const int&); + SDwindleNodeData* getFirstNodeOnWorkspace(const WORKSPACEID&); + SDwindleNodeData* getClosestNodeOnWorkspace(const WORKSPACEID&, const Vector2D&); + SDwindleNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&); void toggleSplit(PHLWINDOW); void swapSplit(PHLWINDOW); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 4b1b59e3..7e0d5704 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -63,7 +63,7 @@ class IHyprLayout { Called when the monitor requires a layout recalculation this usually means reserved area changes */ - virtual void recalculateMonitor(const int&) = 0; + virtual void recalculateMonitor(const MONITORID&) = 0; /* Called when the compositor requests a window diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index be00168f..aa1c0adf 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -14,7 +14,7 @@ SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(PHLWINDOW pWindow) { return nullptr; } -int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) { +int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) { int no = 0; for (auto& n : m_lMasterNodesData) { if (n.workspaceID == ws) @@ -24,7 +24,7 @@ int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) { return no; } -int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) { +int CHyprMasterLayout::getMastersOnWorkspace(const WORKSPACEID& ws) { int no = 0; for (auto& n : m_lMasterNodesData) { if (n.workspaceID == ws && n.isMaster) @@ -34,7 +34,7 @@ int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) { return no; } -SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) { +SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const WORKSPACEID& ws) { for (auto& n : m_lMasterWorkspacesData) { if (n.workspaceID == ws) return &n; @@ -63,7 +63,7 @@ std::string CHyprMasterLayout::getLayoutName() { return "Master"; } -SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) { +SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const WORKSPACEID& ws) { for (auto& n : m_lMasterNodesData) { if (n.isMaster && n.workspaceID == ws) return &n; @@ -304,7 +304,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { recalculateMonitor(pWindow->m_iMonitorID); } -void CHyprMasterLayout::recalculateMonitor(const int& monid) { +void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) { const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); if (!PMONITOR || !PMONITOR->activeWorkspace) diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index fdb916e5..b72be74f 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -30,7 +30,7 @@ struct SMasterNodeData { float percSize = 1.f; // size multiplier for resizing children - int workspaceID = -1; + WORKSPACEID workspaceID = WORKSPACE_INVALID; bool ignoreFullscreenChecks = false; @@ -41,7 +41,7 @@ struct SMasterNodeData { }; struct SMasterWorkspaceData { - int workspaceID = -1; + WORKSPACEID workspaceID = WORKSPACE_INVALID; eOrientation orientation = ORIENTATION_LEFT; // @@ -55,7 +55,7 @@ class CHyprMasterLayout : public IHyprLayout { virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowRemovedTiling(PHLWINDOW); virtual bool isWindowTiled(PHLWINDOW); - virtual void recalculateMonitor(const int&); + virtual void recalculateMonitor(const MONITORID&); virtual void recalculateWindow(PHLWINDOW); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE); @@ -81,14 +81,14 @@ class CHyprMasterLayout : public IHyprLayout { void buildOrientationCycleVectorFromEOperation(std::vector& cycle); void runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int next); eOrientation getDynamicOrientation(PHLWORKSPACE); - int getNodesOnWorkspace(const int&); + int getNodesOnWorkspace(const WORKSPACEID&); void applyNodeDataToWindow(SMasterNodeData*); SMasterNodeData* getNodeFromWindow(PHLWINDOW); - SMasterNodeData* getMasterNodeOnWorkspace(const int&); - SMasterWorkspaceData* getMasterWorkspaceData(const int&); + SMasterNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&); + SMasterWorkspaceData* getMasterWorkspaceData(const WORKSPACEID&); void calculateWorkspace(PHLWORKSPACE); PHLWINDOW getNextWindow(PHLWINDOW, bool); - int getMastersOnWorkspace(const int&); + int getMastersOnWorkspace(const WORKSPACEID&); friend struct SMasterNodeData; friend struct SMasterWorkspaceData; diff --git a/src/macros.hpp b/src/macros.hpp index b2adb036..44014085 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -27,6 +27,8 @@ #define WORKSPACE_INVALID -1L #define WORKSPACE_NOT_CHANGED -101 +#define MONITOR_INVALID -1L + #define LISTENER(name) \ void listener_##name(wl_listener*, void*); \ inline wl_listener listen_##name = {.notify = listener_##name} diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c7b93730..d4bac507 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1738,7 +1738,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { return; } - const int WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; + const auto WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!"); @@ -1756,7 +1756,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { } void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { - int workspaceID = getWorkspaceIDNameFromString(args).id; + auto workspaceID = getWorkspaceIDNameFromString(args).id; if (workspaceID == WORKSPACE_INVALID) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); return; @@ -1816,7 +1816,7 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { bool requestedWorkspaceIsAlreadyOpen = false; const auto PMONITOR = g_pCompositor->m_pLastMonitor; - int specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID(); + auto specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID(); for (auto& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == workspaceID) { diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index c2c088f8..041e7101 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -76,8 +76,8 @@ void CEventLoopManager::removeTimer(SP timer) { } static void timespecAddNs(timespec* pTimespec, int64_t delta) { - int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC; - int delta_s_high = delta / TIMESPEC_NSEC_PER_SEC; + auto delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC; + auto delta_s_high = delta / TIMESPEC_NSEC_PER_SEC; pTimespec->tv_sec += delta_s_high; diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index f6e5c8be..f8e4b962 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -33,7 +33,7 @@ class CInputPopup { WP popup; SP surface; CBox lastBoxLocal; - uint64_t lastMonitor = -1; + MONITORID lastMonitor = MONITOR_INVALID; struct { CHyprSignalListener map; diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index c0e6c4f0..6ee690cd 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -77,7 +77,7 @@ void CInputManager::endWorkspaceSwipe() { // left of where we started. Instead, it's one more than the greatest // workspace ID that currently exists. if (workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID && *PSWIPENEW) { - int maxWorkspace = 0; + WORKSPACEID maxWorkspace = 0; for (const auto& ws : g_pCompositor->m_vWorkspaces) { maxWorkspace = std::max(maxWorkspace, ws->m_iID); } diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 295834ea..b31a4083 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -119,7 +119,7 @@ wl_resource* CForeignToplevelHandleWlr::res() { } void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { - if (lastMonitorID == (int64_t)pMonitor->ID) + if (lastMonitorID == pMonitor->ID) return; const auto CLIENT = resource->client(); diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp index e3b6f3f3..99f63b47 100644 --- a/src/protocols/ForeignToplevelWlr.hpp +++ b/src/protocols/ForeignToplevelWlr.hpp @@ -20,7 +20,7 @@ class CForeignToplevelHandleWlr { SP resource; PHLWINDOWREF pWindow; bool closed = false; - int64_t lastMonitorID = -1; + MONITORID lastMonitorID = MONITOR_INVALID; void sendMonitor(CMonitor* pMonitor); void sendState(); diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 67629e23..c48ff6f3 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -12,9 +12,10 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat); uint32_t glType = FormatUtils::glFormatToType(glFormat); - if (m_iFb == (uint32_t)-1) { + if (!m_iFbAllocated) { firstAlloc = true; glGenFramebuffers(1, &m_iFb); + m_iFbAllocated = true; } if (m_cTex->m_iTexID == 0) { @@ -88,12 +89,12 @@ void CFramebuffer::bind() { } void CFramebuffer::release() { - if (m_iFb != (uint32_t)-1 && m_iFb) + if (m_iFbAllocated) glDeleteFramebuffers(1, &m_iFb); m_cTex->destroyTexture(); - m_iFb = -1; - m_vSize = Vector2D(); + m_iFbAllocated = false; + m_vSize = Vector2D(); } CFramebuffer::~CFramebuffer() { @@ -101,5 +102,5 @@ CFramebuffer::~CFramebuffer() { } bool CFramebuffer::isAllocated() { - return m_iFb != (GLuint)-1; + return m_iFbAllocated; } \ No newline at end of file diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index a46a4859..ca7f9e8a 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -18,7 +18,8 @@ class CFramebuffer { Vector2D m_vSize; SP m_cTex; - GLuint m_iFb = -1; + GLuint m_iFb; + bool m_iFbAllocated{false}; SP m_pStencilTex; }; \ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index c355f4f9..0461662c 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1247,14 +1247,14 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 1, -1); + glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); renderRect(box, CColor(0, 0, 0, 0), round); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, 1, -1); + glStencilFunc(GL_EQUAL, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); scissor(box); @@ -1269,7 +1269,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); glDisable(GL_STENCIL_TEST); - glStencilMask(-1); + glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); @@ -1802,12 +1802,12 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o CRegion tempDamage{damage}; // and draw - for (int i = 1; i <= *PBLURPASSES; ++i) { + for (auto i = 1; i <= *PBLURPASSES; ++i) { tempDamage = damage.copy().scale(1.f / (1 << i)); drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down } - for (int i = *PBLURPASSES - 1; i >= 0; --i) { + for (auto i = *PBLURPASSES - 1; i >= 0; --i) { tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up } @@ -2091,7 +2091,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 1, -1); + glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -2101,7 +2101,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float renderTexture(tex, pBox, a, round, true, true); // discard opaque glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, 1, -1); + glStencilFunc(GL_EQUAL, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // stencil done. Render everything. @@ -2124,7 +2124,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glDisable(GL_STENCIL_TEST); renderTextureInternalWithDamage(tex, pBox, a, &texDamage, round, false, false, true, true); - glStencilMask(-1); + glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7b29eb77..17aed940 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1658,7 +1658,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgetMonitorFromID(monitor); if (!PMONITOR) diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 84501821..0b16efea 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -49,7 +49,7 @@ class CHyprRenderer { ~CHyprRenderer(); void renderMonitor(CMonitor* pMonitor); - void arrangeLayersForMonitor(const int&); + void arrangeLayersForMonitor(const MONITORID&); void damageSurface(SP, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); void damageBox(CBox*, bool skipFrameSchedule = false); diff --git a/src/signal-safe.cpp b/src/signal-safe.cpp index 05ca9c65..44d23f9b 100644 --- a/src/signal-safe.cpp +++ b/src/signal-safe.cpp @@ -10,7 +10,7 @@ extern char** environ; char const* sig_getenv(char const* name) { - int len = strlen(name); + size_t len = strlen(name); for (char** var = environ; *var != NULL; var++) { if (strncmp(*var, name, len) == 0 && (*var)[len] == '=') { return (*var) + len + 1; diff --git a/src/signal-safe.hpp b/src/signal-safe.hpp index 3a38f043..ef643097 100644 --- a/src/signal-safe.hpp +++ b/src/signal-safe.hpp @@ -139,7 +139,7 @@ class BufFileWriter { abort(); } else { close(pipefd[1]); - int len; + long len; char readbuf[256]; while ((len = read(pipefd[0], readbuf, 256)) > 0) { write(readbuf, len); @@ -155,7 +155,7 @@ class BufFileWriter { void flush() { size_t i = 0; while (i < m_writeBufPos) { - int written = ::write(m_fd, m_writeBuf + i, m_writeBufPos - i); + auto written = ::write(m_fd, m_writeBuf + i, m_writeBufPos - i); if (written <= 0) { return; } From fd1d4e288edd586a3d5273cda053a51f5b14cad7 Mon Sep 17 00:00:00 2001 From: "Mathis H." Date: Fri, 9 Aug 2024 14:51:21 +0000 Subject: [PATCH 020/298] headers: set correct paths to header files (#7245) --- src/helpers/MiscFunctions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 7eb2a1ed..8b2ea0d1 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -6,8 +6,8 @@ #include "math/Math.hpp" #include #include -#include "SharedDefs.hpp" -#include "macros.hpp" +#include "../SharedDefs.hpp" +#include "../macros.hpp" struct SCallstackFrameInfo { void* adr = nullptr; From 8b37e81374928856d8fd859b95a62c8bf4211901 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 9 Aug 2024 19:33:20 +0200 Subject: [PATCH 021/298] cursormgr: add a new setting to sync gsettings (#7253) cursor:sync_gsettings_theme is set to default true and if enabled it will now sync xcursor theme loading with gsettings if it can, meaning CSD clients will now also change to the appropiate theme upon start and hyprctl setcursor THEME SIZE . --- CMakeLists.txt | 1 + meson.build | 2 ++ src/config/ConfigManager.cpp | 1 + src/managers/XCursorManager.cpp | 59 +++++++++++++++++++++++++++++++++ src/managers/XCursorManager.hpp | 1 + src/meson.build | 1 + 6 files changed, 65 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfbd431f..d8c45bbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ pkg_check_modules( libliftoff libudev gbm + gio-2.0 hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.2.1) diff --git a/meson.build b/meson.build index e8cd25b4..6a9b7ac5 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,8 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland')) xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) +gio_dep = dependency('gio-2.0', required:true) + cmake = import('cmake') udis = cmake.subproject('udis86') udis86 = udis.dependency('libudis86') diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1a823f3e..fb93032a 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -539,6 +539,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); + m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0}); diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index f2a7ab53..1108bbb2 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include "config/ConfigValue.hpp" #include "helpers/CursorShapes.hpp" #include "debug/Log.hpp" #include "XCursorManager.hpp" @@ -146,6 +149,10 @@ void CXCursorManager::loadTheme(std::string const& name, int size) { cursors.emplace_back(cursor); } + + static auto SYNCGSETTINGS = CConfigValue("cursor:sync_gsettings_theme"); + if (*SYNCGSETTINGS) + syncGsettings(); } SP CXCursorManager::getShape(std::string const& shape, int size) { @@ -542,3 +549,55 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa return newCursors; } + +void CXCursorManager::syncGsettings() { + auto checkParamExists = [](std::string const& paramName, std::string const& category) { + auto* gSettingsSchemaSource = g_settings_schema_source_get_default(); + + if (!gSettingsSchemaSource) { + Debug::log(WARN, "GSettings default schema source does not exist, cant sync GSettings"); + return false; + } + + auto* gSettingsSchema = g_settings_schema_source_lookup(gSettingsSchemaSource, category.c_str(), true); + bool hasParam = false; + + if (gSettingsSchema != NULL) { + hasParam = gSettingsSchema && g_settings_schema_has_key(gSettingsSchema, paramName.c_str()); + g_settings_schema_unref(gSettingsSchema); + } + + return hasParam; + }; + + using SettingValue = std::variant; + auto setValue = [&checkParamExists](std::string const& paramName, const SettingValue& paramValue, std::string const& category) { + if (!checkParamExists(paramName, category)) { + Debug::log(WARN, "GSettings parameter doesnt exist {} in {}", paramName, category); + return; + } + + auto* gsettings = g_settings_new(category.c_str()); + + if (!gsettings) { + Debug::log(WARN, "GSettings failed to allocate new settings with category {}", category); + return; + } + + std::visit( + [&](auto&& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) + g_settings_set_string(gsettings, paramName.c_str(), value.c_str()); + else if constexpr (std::is_same_v) + g_settings_set_int(gsettings, paramName.c_str(), value); + }, + paramValue); + + g_settings_sync(); + g_object_unref(gsettings); + }; + + setValue("cursor-theme", themeName, "org.gnome.desktop.interface"); + setValue("cursor-size", lastLoadSize, "org.gnome.desktop.interface"); +} diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 20637055..464c1ec3 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -38,6 +38,7 @@ class CXCursorManager { std::string getLegacyShapeName(std::string const& shape); std::vector> loadStandardCursors(std::string const& name, int size); std::vector> loadAllFromDir(std::string const& path, int size); + void syncGsettings(); int lastLoadSize = 0; std::string themeName = ""; diff --git a/src/meson.build b/src/meson.build index 098d8298..475ecc24 100644 --- a/src/meson.build +++ b/src/meson.build @@ -28,6 +28,7 @@ executable('Hyprland', src, xcb_xfixes_dep, backtrace_dep, epoll_dep, + gio_dep, udis86, dependency('pixman-1'), From 4fdc0d55e4b44bb5300679025d2378fb6de0cae4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 10 Aug 2024 00:04:26 +0200 Subject: [PATCH 022/298] eventloop: don't dispatch in enterLoop ref #6842, BSD blocks in udev on no event apparently --- src/managers/eventLoop/EventLoopManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 041e7101..d1b85cf2 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -48,7 +48,6 @@ void CEventLoopManager::enterLoop() { aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); for (auto& fd : aqPollFDs) { m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); - fd->onSignal(); // dispatch outstanding } wl_display_run(m_sWayland.display); From 0bf9ceb53b338c79ab65e631877efcf96f53b49a Mon Sep 17 00:00:00 2001 From: Zach DeCook Date: Sat, 10 Aug 2024 16:09:12 -0400 Subject: [PATCH 023/298] core: Include cstring whenever strncpy is used (#7267) Fixes ppc64le build in alpine --- hyprctl/main.cpp | 1 + src/helpers/SdDaemon.cpp | 1 + src/managers/EventManager.cpp | 1 + src/xwayland/Server.cpp | 1 + 4 files changed, 4 insertions(+) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index c86406fc..5d5113b8 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace Hyprutils::String; #include "Strings.hpp" diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index 25e0ca3b..48c23e6b 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace Systemd { int SdBooted(void) { diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index 75c98e2a..079a6b68 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include CEventManager::CEventManager() { m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index cec582f6..200bec70 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -19,6 +19,7 @@ #include #include #include +#include // TODO: cleanup static bool set_cloexec(int fd, bool cloexec) { From 01ff5fdf6a00a9231bd3b56400d8bcab378c4257 Mon Sep 17 00:00:00 2001 From: Walt Bringenberg <44916811+wwaltb@users.noreply.github.com> Date: Sat, 10 Aug 2024 13:42:45 -0700 Subject: [PATCH 024/298] cursor: make inactive_timeout setting a float (#7268) --- src/config/ConfigManager.cpp | 2 +- src/render/Renderer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fb93032a..edc1723d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -531,7 +531,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); - m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:inactive_timeout", {0.f}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0}); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 17aed940..a2d5a95e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2299,7 +2299,7 @@ void CHyprRenderer::setCursorFromName(const std::string& name, bool force) { } void CHyprRenderer::ensureCursorRenderingMode() { - static auto PCURSORTIMEOUT = CConfigValue("cursor:inactive_timeout"); + static auto PCURSORTIMEOUT = CConfigValue("cursor:inactive_timeout"); static auto PHIDEONTOUCH = CConfigValue("cursor:hide_on_touch"); static auto PHIDEONKEY = CConfigValue("cursor:hide_on_key_press"); From 511eea71c60e10f3d3d757a376f1ca98b9034ae0 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 11 Aug 2024 20:42:18 +0200 Subject: [PATCH 025/298] pointermgr: fix initial cursorwarp (#7286) change the hook to monitorAdded instead of newMonitor so its finalized in the compositor and added to vMonitors, move the checkDefaultCursorWarp to PointerManager and check for it upon mode change. and also ensure it doesnt go out of bounds by replacing it in the middle again on resolution changes. --- src/Compositor.cpp | 35 ------------------------ src/managers/PointerManager.cpp | 48 ++++++++++++++++++++++++++++++--- src/managers/PointerManager.hpp | 1 + 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e3a347fd..c3f95961 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2918,39 +2918,6 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { return {}; } -static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { - static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); - static auto firstMonitorAdded = std::chrono::system_clock::now(); - static bool cursorDefaultDone = false; - static bool firstLaunch = true; - - const auto POS = PNEWMONITOR->middle(); - - // by default, cursor should be set to first monitor detected - // this is needed as a default if the monitor given in config above doesn't exist - if (firstLaunch) { - firstLaunch = false; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } - - if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY) - return; - - // after 10s, don't set cursor to default monitor - auto timePassedSec = std::chrono::duration_cast(std::chrono::system_clock::now() - firstMonitorAdded); - if (timePassedSec.count() > 10) { - cursorDefaultDone = true; - return; - } - - if (*PCURSORMONITOR == monitorName) { - cursorDefaultDone = true; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } -} - void CCompositor::onNewMonitor(SP output) { // add it to real auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); @@ -2986,8 +2953,6 @@ void CCompositor::onNewMonitor(SP output) { g_pConfigManager->m_bWantsMonitorReload = true; g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); - checkDefaultCursorWarp(PNEWMONITOR, output->name); - for (auto& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { w->m_iLastSurfaceMonitorID = MONITOR_INVALID; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3ba34c11..72ff5ae7 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -11,13 +11,21 @@ #include CPointerManager::CPointerManager() { - hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { - auto PMONITOR = std::any_cast>(data); + hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { + auto PMONITOR = std::any_cast(data)->self.lock(); onMonitorLayoutChange(); - PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); - PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); + PMONITOR->events.modeChanged.registerStaticListener( + [this, PMONITOR](void* owner, std::any data) { + g_pEventLoopManager->doLater([this, PMONITOR]() { + onMonitorLayoutChange(); + checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name); + }); + }, + nullptr); + PMONITOR->events.disconnect.registerStaticListener( + [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.destroy.registerStaticListener( [this](void* owner, std::any data) { if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) @@ -35,6 +43,38 @@ CPointerManager::CPointerManager() { }); } +void CPointerManager::checkDefaultCursorWarp(SP monitor, std::string monitorName) { + static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); + static bool cursorDefaultDone = false; + static bool firstLaunch = true; + + const auto POS = monitor->middle(); + + // by default, cursor should be set to first monitor detected + // this is needed as a default if the monitor given in config above doesn't exist + if (firstLaunch) { + firstLaunch = false; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + + if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) { + if (*PCURSORMONITOR == monitorName) { + cursorDefaultDone = true; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + } + + // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. + if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } +} + void CPointerManager::lockSoftwareAll() { for (auto& state : monitorStates) state->softwareLocks++; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 4a4c4f61..082855b5 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -26,6 +26,7 @@ class CPointerManager { public: CPointerManager(); + void checkDefaultCursorWarp(SP monitor, std::string monitorName); void attachPointer(SP pointer); void attachTouch(SP touch); void attachTablet(SP tablet); From 118d4e1001d5847aa42d1e5d5fa9623954ae751d Mon Sep 17 00:00:00 2001 From: "Yang, Ying-chao" Date: Mon, 12 Aug 2024 03:38:16 +0800 Subject: [PATCH 026/298] install: Prepend ${DESTDIR} when creating hyprland symbolic link (fixes #7280). (#7281) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8c45bbe..f26a5c3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,7 +330,7 @@ install( CODE "execute_process( \ COMMAND ${CMAKE_COMMAND} -E create_symlink \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ - ${CMAKE_INSTALL_FULL_BINDIR}/hyprland + \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \ )") # session file From df9d830117cbbf8a1b2a144a28261c28753cb022 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 12 Aug 2024 18:18:03 +0300 Subject: [PATCH 027/298] flake.lock: update --- flake.lock | 24 ++-- hyprpm/Makefile | 363 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 375 insertions(+), 12 deletions(-) create mode 100644 hyprpm/Makefile diff --git a/flake.lock b/flake.lock index 5c384d4d..8930d2e3 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1722347739, - "narHash": "sha256-rAoh+K6KG+b1DwSWtqRVocdojnH6nGk6q07mNltoUSM=", + "lastModified": 1723405438, + "narHash": "sha256-bpmC2m7OhlDvqgQZdZ2jBLyeIkq/Jld3X4bqRAxBSp8=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7c3565f9bedc7cb601cc0baa14792247e4dc1d5a", + "rev": "9312aa28271c91e5d67ecb9def527b2bbcff0e66", "type": "github" }, "original": { @@ -42,11 +42,11 @@ ] }, "locked": { - "lastModified": 1721330371, - "narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=", + "lastModified": 1722623071, + "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc", + "rev": "912d56025f03d41b1ad29510c423757b4379eb1c", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1722098849, - "narHash": "sha256-D3wIZlBNh7LuZ0NaoCpY/Pvu+xHxIVtSN+KkWZYvvVs=", + "lastModified": 1722869141, + "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "5dcbbc1e3de40b2cecfd2007434d86e924468f1f", + "rev": "0252fd13e78e60fb0da512a212e56007515a49f7", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1722185531, - "narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=", + "lastModified": 1723175592, + "narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d", + "rev": "5e0ca22929f3342b19569b21b2f3462f053e497b", "type": "github" }, "original": { diff --git a/hyprpm/Makefile b/hyprpm/Makefile new file mode 100644 index 00000000..5249a14b --- /dev/null +++ b/hyprpm/Makefile @@ -0,0 +1,363 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.29 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake + +# The command to remove a file. +RM = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/mihai/Documents/code/git/Hyprland + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/mihai/Documents/code/git/Hyprland + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target package +package: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool..." + cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackConfig.cmake +.PHONY : package + +# Special rule for the target package +package/fast: package +.PHONY : package/fast + +# Special rule for the target package_source +package_source: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool for source..." + cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackSourceConfig.cmake /home/mihai/Documents/code/git/Hyprland/CPackSourceConfig.cmake +.PHONY : package_source + +# Special rule for the target package_source +package_source/fast: package_source +.PHONY : package_source/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "No interactive CMake dialog available..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# The main all target +all: cmake_check_build_system + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles /home/mihai/Documents/code/git/Hyprland/hyprpm//CMakeFiles/progress.marks + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +hyprpm/CMakeFiles/hyprpm.dir/rule: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/CMakeFiles/hyprpm.dir/rule +.PHONY : hyprpm/CMakeFiles/hyprpm.dir/rule + +# Convenience name for target. +hyprpm: hyprpm/CMakeFiles/hyprpm.dir/rule +.PHONY : hyprpm + +# fast build rule for target. +hyprpm/fast: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/build +.PHONY : hyprpm/fast + +src/core/DataState.o: src/core/DataState.cpp.o +.PHONY : src/core/DataState.o + +# target to build an object file +src/core/DataState.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.o +.PHONY : src/core/DataState.cpp.o + +src/core/DataState.i: src/core/DataState.cpp.i +.PHONY : src/core/DataState.i + +# target to preprocess a source file +src/core/DataState.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.i +.PHONY : src/core/DataState.cpp.i + +src/core/DataState.s: src/core/DataState.cpp.s +.PHONY : src/core/DataState.s + +# target to generate assembly for a file +src/core/DataState.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.s +.PHONY : src/core/DataState.cpp.s + +src/core/Manifest.o: src/core/Manifest.cpp.o +.PHONY : src/core/Manifest.o + +# target to build an object file +src/core/Manifest.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.o +.PHONY : src/core/Manifest.cpp.o + +src/core/Manifest.i: src/core/Manifest.cpp.i +.PHONY : src/core/Manifest.i + +# target to preprocess a source file +src/core/Manifest.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.i +.PHONY : src/core/Manifest.cpp.i + +src/core/Manifest.s: src/core/Manifest.cpp.s +.PHONY : src/core/Manifest.s + +# target to generate assembly for a file +src/core/Manifest.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.s +.PHONY : src/core/Manifest.cpp.s + +src/core/PluginManager.o: src/core/PluginManager.cpp.o +.PHONY : src/core/PluginManager.o + +# target to build an object file +src/core/PluginManager.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.o +.PHONY : src/core/PluginManager.cpp.o + +src/core/PluginManager.i: src/core/PluginManager.cpp.i +.PHONY : src/core/PluginManager.i + +# target to preprocess a source file +src/core/PluginManager.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.i +.PHONY : src/core/PluginManager.cpp.i + +src/core/PluginManager.s: src/core/PluginManager.cpp.s +.PHONY : src/core/PluginManager.s + +# target to generate assembly for a file +src/core/PluginManager.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.s +.PHONY : src/core/PluginManager.cpp.s + +src/main.o: src/main.cpp.o +.PHONY : src/main.o + +# target to build an object file +src/main.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.o +.PHONY : src/main.cpp.o + +src/main.i: src/main.cpp.i +.PHONY : src/main.i + +# target to preprocess a source file +src/main.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.i +.PHONY : src/main.cpp.i + +src/main.s: src/main.cpp.s +.PHONY : src/main.s + +# target to generate assembly for a file +src/main.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.s +.PHONY : src/main.cpp.s + +src/progress/CProgressBar.o: src/progress/CProgressBar.cpp.o +.PHONY : src/progress/CProgressBar.o + +# target to build an object file +src/progress/CProgressBar.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.o +.PHONY : src/progress/CProgressBar.cpp.o + +src/progress/CProgressBar.i: src/progress/CProgressBar.cpp.i +.PHONY : src/progress/CProgressBar.i + +# target to preprocess a source file +src/progress/CProgressBar.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.i +.PHONY : src/progress/CProgressBar.cpp.i + +src/progress/CProgressBar.s: src/progress/CProgressBar.cpp.s +.PHONY : src/progress/CProgressBar.s + +# target to generate assembly for a file +src/progress/CProgressBar.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.s +.PHONY : src/progress/CProgressBar.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... package" + @echo "... package_source" + @echo "... rebuild_cache" + @echo "... hyprpm" + @echo "... src/core/DataState.o" + @echo "... src/core/DataState.i" + @echo "... src/core/DataState.s" + @echo "... src/core/Manifest.o" + @echo "... src/core/Manifest.i" + @echo "... src/core/Manifest.s" + @echo "... src/core/PluginManager.o" + @echo "... src/core/PluginManager.i" + @echo "... src/core/PluginManager.s" + @echo "... src/main.o" + @echo "... src/main.i" + @echo "... src/main.s" + @echo "... src/progress/CProgressBar.o" + @echo "... src/progress/CProgressBar.i" + @echo "... src/progress/CProgressBar.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + From d361fcbd85a92f0494c6d8ef0c63aad798df20a7 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:16:00 -0500 Subject: [PATCH 028/298] config: fix explicit sync option warning (#7293) --- src/config/ConfigManager.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index edc1723d..41d3871c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -822,9 +822,6 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { if (!isFirstLaunch) g_pHyprOpenGL->m_bReloadScreenShader = true; - if (!isFirstLaunch && *PENABLEEXPLICIT != prevEnabledExplicit) - g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); - // parseError will be displayed next frame if (result.error) @@ -837,6 +834,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1) g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); + else if (*PENABLEEXPLICIT != prevEnabledExplicit) + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); else g_pHyprError->destroy(); @@ -925,7 +924,10 @@ void CConfigManager::init() { } std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE) { - const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str()); + static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static int prevEnabledExplicit = *PENABLEEXPLICIT; + + const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str()); // invalidate layouts if they changed if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) { @@ -933,6 +935,13 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } + if (COMMAND.contains("explicit")) { + if (*PENABLEEXPLICIT != prevEnabledExplicit) + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); + else + g_pHyprError->destroy(); + } + // Update window border colors g_pCompositor->updateAllWindowsAnimatedDecorationValues(); From 3fa6db1e7a7f5596f449ae12d0b45ff364d7f6f1 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 12 Aug 2024 19:19:03 +0200 Subject: [PATCH 029/298] core: fix data race and a unsigned int rollover (#7278) * keybindmgr: avoid uint rollover on mouse keycode mouse keycode is 0, and the switch case checks for 0 - 8 and rolls over, just return early if keycode is 0. * watchdog: avoid data races in watchdog asan thread sanitizer reported data races in the watchdog from reading and setting the bool variables make them std::atomic bools. also add a atomic bool for the main thread to wait for to avoid data race when reading the config values. * hyprdebug: change non unicode character to name asan created false positives and didnt like this bit, so for the sake of easier debugging rename it to something unicode. --- src/Compositor.cpp | 4 ++++ src/debug/HyprDebugOverlay.cpp | 16 ++++++++-------- src/debug/HyprDebugOverlay.hpp | 8 ++++---- src/helpers/Watchdog.cpp | 13 ++++++------- src/helpers/Watchdog.hpp | 14 ++++++++------ src/managers/KeybindManager.cpp | 3 +++ src/render/Renderer.cpp | 10 +++++----- 7 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c3f95961..a2f7c52a 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -552,6 +552,10 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pConfigManager->init(); g_pWatchdog = std::make_unique(); // requires config + // wait for watchdog to initialize to not hit data races in reading config values. + while (!g_pWatchdog->m_bWatchdogInitialized) { + std::this_thread::yield(); + } Debug::log(LOG, "Creating the PointerManager!"); g_pPointerManager = std::make_unique(); diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 889be8ea..fbd8cd71 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -7,8 +7,8 @@ CHyprDebugOverlay::CHyprDebugOverlay() { m_pTexture = makeShared(); } -void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { - m_dLastRenderTimes.push_back(µs / 1000.f); +void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { + m_dLastRenderTimes.push_back(durationUs / 1000.f); if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) m_dLastRenderTimes.pop_front(); @@ -17,8 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { m_pMonitor = pMonitor; } -void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { - m_dLastRenderTimesNoOverlay.push_back(µs / 1000.f); +void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { + m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f); if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) m_dLastRenderTimesNoOverlay.pop_front(); @@ -188,12 +188,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) { return posY - offset; } -void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) { - m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs); +void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { + m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs); } -void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { - m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, µs); +void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { + m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); } void CHyprDebugOverlay::frameData(CMonitor* pMonitor) { diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index a6063ee9..e7742b35 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -13,8 +13,8 @@ class CHyprMonitorDebugOverlay { public: int draw(int offset); - void renderData(CMonitor* pMonitor, float µs); - void renderDataNoOverlay(CMonitor* pMonitor, float µs); + void renderData(CMonitor* pMonitor, float durationUs); + void renderDataNoOverlay(CMonitor* pMonitor, float durationUs); void frameData(CMonitor* pMonitor); private: @@ -33,8 +33,8 @@ class CHyprDebugOverlay { public: CHyprDebugOverlay(); void draw(); - void renderData(CMonitor*, float µs); - void renderDataNoOverlay(CMonitor*, float µs); + void renderData(CMonitor*, float durationUs); + void renderDataNoOverlay(CMonitor*, float durationUs); void frameData(CMonitor*); private: diff --git a/src/helpers/Watchdog.cpp b/src/helpers/Watchdog.cpp index b9f654da..c7ff648b 100644 --- a/src/helpers/Watchdog.cpp +++ b/src/helpers/Watchdog.cpp @@ -18,15 +18,14 @@ CWatchdog::CWatchdog() { m_pWatchdog = std::make_unique([this] { static auto PTIMEOUT = CConfigValue("debug:watchdog_timeout"); - while (1337) { - std::unique_lock lk(m_mWatchdogMutex); + m_bWatchdogInitialized = true; + while (!m_bExitThread) { + std::unique_lock lk(m_mWatchdogMutex); if (!m_bWillWatch) - m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; }); - else { - if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false) - pthread_kill(m_iMainThreadPID, SIGUSR1); - } + m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified || m_bExitThread; }); + else if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified || m_bExitThread; }) == false) + pthread_kill(m_iMainThreadPID, SIGUSR1); if (m_bExitThread) break; diff --git a/src/helpers/Watchdog.hpp b/src/helpers/Watchdog.hpp index 7bb499d6..b16cb518 100644 --- a/src/helpers/Watchdog.hpp +++ b/src/helpers/Watchdog.hpp @@ -11,21 +11,23 @@ class CWatchdog { CWatchdog(); ~CWatchdog(); - void startWatching(); - void endWatching(); + void startWatching(); + void endWatching(); + + std::atomic m_bWatchdogInitialized{false}; private: std::chrono::high_resolution_clock::time_point m_tTriggered; pthread_t m_iMainThreadPID = 0; - bool m_bWatching = false; - bool m_bWillWatch = false; + std::atomic m_bWatching = false; + std::atomic m_bWillWatch = false; std::unique_ptr m_pWatchdog; std::mutex m_mWatchdogMutex; - bool m_bNotified = false; - bool m_bExitThread = false; + std::atomic m_bNotified = false; + std::atomic m_bExitThread = false; std::condition_variable m_cvWatchdogCondition; }; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index d4bac507..dba34d70 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -180,6 +180,9 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) { } uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) { + if (keycode == 0) + return 0; + switch (keycode - 8) { case KEY_LEFTMETA: return HL_MODIFIER_META; case KEY_RIGHTMETA: return HL_MODIFIER_META; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a2d5a95e..6bf6a761 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1395,15 +1395,15 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->pendingFrame = false; - const float µs = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - renderStart).count() / 1000.f; - g_pDebugOverlay->renderData(pMonitor, µs); + const float durationUs = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - renderStart).count() / 1000.f; + g_pDebugOverlay->renderData(pMonitor, durationUs); if (*PDEBUGOVERLAY == 1) { if (pMonitor == g_pCompositor->m_vMonitors.front().get()) { - const float µsNoOverlay = µs - std::chrono::duration_cast(endRenderOverlay - renderStartOverlay).count() / 1000.f; - g_pDebugOverlay->renderDataNoOverlay(pMonitor, µsNoOverlay); + const float noOverlayUs = durationUs - std::chrono::duration_cast(endRenderOverlay - renderStartOverlay).count() / 1000.f; + g_pDebugOverlay->renderDataNoOverlay(pMonitor, noOverlayUs); } else { - g_pDebugOverlay->renderDataNoOverlay(pMonitor, µs); + g_pDebugOverlay->renderDataNoOverlay(pMonitor, durationUs); } } } From c7b72790bd63172f04ee86784d4cb2a400532927 Mon Sep 17 00:00:00 2001 From: Kyle <56144092+txkyel@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:41:26 -0400 Subject: [PATCH 030/298] keybinds: Fix fullscreenState toggling behaviour (#7288) * Update fullscreen state dispatcher behaviour * Change syncFullscreen default to false * Revert all changes * Modify fullscreenstate dispatcher toggle behaviour * Update syncFullscreen according to state * Update syncFullscreen before setting fullscreen state --- src/managers/KeybindManager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index dba34d70..8fc025ec 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1166,6 +1166,8 @@ void CKeybindManager::fullscreenStateActive(std::string args) { if (!PWINDOW) return; + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); + int internalMode, clientMode; try { internalMode = std::stoi(ARGS[0]); @@ -1184,18 +1186,15 @@ void CKeybindManager::fullscreenStateActive(std::string args) { } if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) { - g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.client, .client = PWINDOW->m_sFullscreenState.client}); - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client}); return; } if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) { - g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = PWINDOW->m_sFullscreenState.internal}); - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE}); return; } - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); } From 77cf651825c2afac69e3a827ff910a62c73e1218 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 12 Aug 2024 20:49:52 +0200 Subject: [PATCH 031/298] protocols: avoid crashing in drmlease (#7290) instead of potentially causing wonky behaviour from destructing in the constructor add the unique_ptr reset to doLater and dont use the not done constructed protolog in the constructor, call Debug::log directly. see issue #7240 --- src/protocols/DRMLease.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 9f5b6312..3ab38ea1 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -1,5 +1,6 @@ #include "DRMLease.hpp" #include "../Compositor.hpp" +#include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -225,7 +226,7 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backe auto fd = drm->getNonMasterFD(); if (fd < 0) { - LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); + Debug::log(ERR, "[DRMLease] Failed to dup fd for drm node {}", drm->gpuName); return; } @@ -247,10 +248,8 @@ CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, break; } - if (!primaryDevice || primaryDevice->success) { - PROTO::lease.reset(); - return; - } + if (!primaryDevice || !primaryDevice->success) + g_pEventLoopManager->doLater([]() { PROTO::lease.reset(); }); } void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { From 39df1f4dbfedf97a7f30f9de359f3b3415844380 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 13 Aug 2024 12:27:00 -0500 Subject: [PATCH 032/298] cursormgr: fix cursor gsettings on session change (#7295) --- src/Compositor.cpp | 1 + src/managers/CursorManager.cpp | 6 +++++- src/managers/CursorManager.hpp | 3 ++- src/managers/XCursorManager.cpp | 1 + src/managers/XCursorManager.hpp | 4 ++-- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a2f7c52a..26a985ef 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -393,6 +393,7 @@ void CCompositor::initAllSignals() { } g_pConfigManager->m_bWantsMonitorReload = true; + g_pCursorManager->syncGsettings(); } else { Debug::log(LOG, "Session got deactivated!"); diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 3f3a25f6..e2dd5bb3 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -337,4 +337,8 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { updateTheme(); return true; -} \ No newline at end of file +} + +void CCursorManager::syncGsettings() { + m_pXcursor->syncGsettings(); +} diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index ceb4816b..796ab10e 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -53,6 +53,7 @@ class CCursorManager { void updateTheme(); SCursorImageData dataFor(const std::string& name); // for xwayland void setXWaylandCursor(); + void syncGsettings(); void tickAnimatedCursor(); @@ -75,4 +76,4 @@ class CCursorManager { Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; }; -inline std::unique_ptr g_pCursorManager; \ No newline at end of file +inline std::unique_ptr g_pCursorManager; diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 1108bbb2..3d36add5 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -5,6 +5,7 @@ #include #include "config/ConfigValue.hpp" #include "helpers/CursorShapes.hpp" +#include "../managers/CursorManager.hpp" #include "debug/Log.hpp" #include "XCursorManager.hpp" diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 464c1ec3..48fda5dd 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -31,6 +31,7 @@ class CXCursorManager { void loadTheme(const std::string& name, int size); SP getShape(std::string const& shape, int size); + void syncGsettings(); private: SP createCursor(std::string const& shape, XcursorImages* xImages); @@ -38,11 +39,10 @@ class CXCursorManager { std::string getLegacyShapeName(std::string const& shape); std::vector> loadStandardCursors(std::string const& name, int size); std::vector> loadAllFromDir(std::string const& path, int size); - void syncGsettings(); int lastLoadSize = 0; std::string themeName = ""; SP defaultCursor; SP hyprCursor; std::vector> cursors; -}; \ No newline at end of file +}; From 4aec237ec0bfcb86be9c26926f5a87e036b7f668 Mon Sep 17 00:00:00 2001 From: Patrick Ulbricht <70023807+PaddeCraft@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:14:52 +0200 Subject: [PATCH 033/298] README: Change image sources from vaxerski/Hyprland to hyprwm/Hyprland (#7315) * readme: Change image sources from vaxerski/Hyprland to hyprwm/Hyprland * readme: Remove unused image --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index fc2bd206..f271c29c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-banner +banner
@@ -125,7 +125,6 @@ easy IPC, much more QoL stuff than other compositors and more... -[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg [Preview A]: https://i.ibb.co/C1yTb0r/falf.png [Preview B]: https://linfindel.github.io/cdn/hyprland-preview-b.png [Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png From c5ec079c6fa92fe89bd2b689dd49197675edbe58 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 13 Aug 2024 22:14:58 +0300 Subject: [PATCH 034/298] hyprpm, hyprctl: remove Makefiles --- .gitignore | 2 + hyprctl/Makefile | 4 - hyprpm/Makefile | 363 ----------------------------------------------- 3 files changed, 2 insertions(+), 367 deletions(-) delete mode 100644 hyprctl/Makefile delete mode 100644 hyprpm/Makefile diff --git a/.gitignore b/.gitignore index 78f794fc..2e158a4e 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ gmon.out PKGBUILD src/version.h +hyprpm/Makefile +hyprctl/Makefile diff --git a/hyprctl/Makefile b/hyprctl/Makefile deleted file mode 100644 index 9798320c..00000000 --- a/hyprctl/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: - $(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl -clean: - rm ./hyprctl diff --git a/hyprpm/Makefile b/hyprpm/Makefile deleted file mode 100644 index 5249a14b..00000000 --- a/hyprpm/Makefile +++ /dev/null @@ -1,363 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.29 - -# Default target executed when no arguments are given to make. -default_target: all -.PHONY : default_target - -# Allow only one "make -f Makefile2" at a time, but pass parallelism. -.NOTPARALLEL: - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - -# Disable VCS-based implicit rules. -% : %,v - -# Disable VCS-based implicit rules. -% : RCS/% - -# Disable VCS-based implicit rules. -% : RCS/%,v - -# Disable VCS-based implicit rules. -% : SCCS/s.% - -# Disable VCS-based implicit rules. -% : s.% - -.SUFFIXES: .hpux_make_needs_suffix_list - -# Command-line flag to silence nested $(MAKE). -$(VERBOSE)MAKESILENT = -s - -#Suppress display of executed commands. -$(VERBOSE).SILENT: - -# A target that is always out of date. -cmake_force: -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake - -# The command to remove a file. -RM = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E rm -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /home/mihai/Documents/code/git/Hyprland - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /home/mihai/Documents/code/git/Hyprland - -#============================================================================= -# Targets provided globally by CMake. - -# Special rule for the target package -package: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool..." - cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackConfig.cmake -.PHONY : package - -# Special rule for the target package -package/fast: package -.PHONY : package/fast - -# Special rule for the target package_source -package_source: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool for source..." - cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackSourceConfig.cmake /home/mihai/Documents/code/git/Hyprland/CPackSourceConfig.cmake -.PHONY : package_source - -# Special rule for the target package_source -package_source/fast: package_source -.PHONY : package_source/fast - -# Special rule for the target edit_cache -edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "No interactive CMake dialog available..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. -.PHONY : edit_cache - -# Special rule for the target edit_cache -edit_cache/fast: edit_cache -.PHONY : edit_cache/fast - -# Special rule for the target rebuild_cache -rebuild_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : rebuild_cache - -# Special rule for the target rebuild_cache -rebuild_cache/fast: rebuild_cache -.PHONY : rebuild_cache/fast - -# Special rule for the target list_install_components -list_install_components: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Available install components are: \"Unspecified\"" -.PHONY : list_install_components - -# Special rule for the target list_install_components -list_install_components/fast: list_install_components -.PHONY : list_install_components/fast - -# Special rule for the target install -install: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake -.PHONY : install - -# Special rule for the target install -install/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake -.PHONY : install/fast - -# Special rule for the target install/local -install/local: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local - -# Special rule for the target install/local -install/local/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local/fast - -# Special rule for the target install/strip -install/strip: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip - -# Special rule for the target install/strip -install/strip/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip/fast - -# The main all target -all: cmake_check_build_system - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles /home/mihai/Documents/code/git/Hyprland/hyprpm//CMakeFiles/progress.marks - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/all - $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles 0 -.PHONY : all - -# The main clean target -clean: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/clean -.PHONY : clean - -# The main clean target -clean/fast: clean -.PHONY : clean/fast - -# Prepare targets for installation. -preinstall: all - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall -.PHONY : preinstall - -# Prepare targets for installation. -preinstall/fast: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall -.PHONY : preinstall/fast - -# clear depends -depend: - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -.PHONY : depend - -# Convenience name for target. -hyprpm/CMakeFiles/hyprpm.dir/rule: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/CMakeFiles/hyprpm.dir/rule -.PHONY : hyprpm/CMakeFiles/hyprpm.dir/rule - -# Convenience name for target. -hyprpm: hyprpm/CMakeFiles/hyprpm.dir/rule -.PHONY : hyprpm - -# fast build rule for target. -hyprpm/fast: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/build -.PHONY : hyprpm/fast - -src/core/DataState.o: src/core/DataState.cpp.o -.PHONY : src/core/DataState.o - -# target to build an object file -src/core/DataState.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.o -.PHONY : src/core/DataState.cpp.o - -src/core/DataState.i: src/core/DataState.cpp.i -.PHONY : src/core/DataState.i - -# target to preprocess a source file -src/core/DataState.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.i -.PHONY : src/core/DataState.cpp.i - -src/core/DataState.s: src/core/DataState.cpp.s -.PHONY : src/core/DataState.s - -# target to generate assembly for a file -src/core/DataState.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.s -.PHONY : src/core/DataState.cpp.s - -src/core/Manifest.o: src/core/Manifest.cpp.o -.PHONY : src/core/Manifest.o - -# target to build an object file -src/core/Manifest.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.o -.PHONY : src/core/Manifest.cpp.o - -src/core/Manifest.i: src/core/Manifest.cpp.i -.PHONY : src/core/Manifest.i - -# target to preprocess a source file -src/core/Manifest.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.i -.PHONY : src/core/Manifest.cpp.i - -src/core/Manifest.s: src/core/Manifest.cpp.s -.PHONY : src/core/Manifest.s - -# target to generate assembly for a file -src/core/Manifest.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.s -.PHONY : src/core/Manifest.cpp.s - -src/core/PluginManager.o: src/core/PluginManager.cpp.o -.PHONY : src/core/PluginManager.o - -# target to build an object file -src/core/PluginManager.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.o -.PHONY : src/core/PluginManager.cpp.o - -src/core/PluginManager.i: src/core/PluginManager.cpp.i -.PHONY : src/core/PluginManager.i - -# target to preprocess a source file -src/core/PluginManager.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.i -.PHONY : src/core/PluginManager.cpp.i - -src/core/PluginManager.s: src/core/PluginManager.cpp.s -.PHONY : src/core/PluginManager.s - -# target to generate assembly for a file -src/core/PluginManager.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.s -.PHONY : src/core/PluginManager.cpp.s - -src/main.o: src/main.cpp.o -.PHONY : src/main.o - -# target to build an object file -src/main.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.o -.PHONY : src/main.cpp.o - -src/main.i: src/main.cpp.i -.PHONY : src/main.i - -# target to preprocess a source file -src/main.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.i -.PHONY : src/main.cpp.i - -src/main.s: src/main.cpp.s -.PHONY : src/main.s - -# target to generate assembly for a file -src/main.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.s -.PHONY : src/main.cpp.s - -src/progress/CProgressBar.o: src/progress/CProgressBar.cpp.o -.PHONY : src/progress/CProgressBar.o - -# target to build an object file -src/progress/CProgressBar.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.o -.PHONY : src/progress/CProgressBar.cpp.o - -src/progress/CProgressBar.i: src/progress/CProgressBar.cpp.i -.PHONY : src/progress/CProgressBar.i - -# target to preprocess a source file -src/progress/CProgressBar.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.i -.PHONY : src/progress/CProgressBar.cpp.i - -src/progress/CProgressBar.s: src/progress/CProgressBar.cpp.s -.PHONY : src/progress/CProgressBar.s - -# target to generate assembly for a file -src/progress/CProgressBar.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.s -.PHONY : src/progress/CProgressBar.cpp.s - -# Help Target -help: - @echo "The following are some of the valid targets for this Makefile:" - @echo "... all (the default if no target is provided)" - @echo "... clean" - @echo "... depend" - @echo "... edit_cache" - @echo "... install" - @echo "... install/local" - @echo "... install/strip" - @echo "... list_install_components" - @echo "... package" - @echo "... package_source" - @echo "... rebuild_cache" - @echo "... hyprpm" - @echo "... src/core/DataState.o" - @echo "... src/core/DataState.i" - @echo "... src/core/DataState.s" - @echo "... src/core/Manifest.o" - @echo "... src/core/Manifest.i" - @echo "... src/core/Manifest.s" - @echo "... src/core/PluginManager.o" - @echo "... src/core/PluginManager.i" - @echo "... src/core/PluginManager.s" - @echo "... src/main.o" - @echo "... src/main.i" - @echo "... src/main.s" - @echo "... src/progress/CProgressBar.o" - @echo "... src/progress/CProgressBar.i" - @echo "... src/progress/CProgressBar.s" -.PHONY : help - - - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - From 3b4aabe04c7756fb0a70d78b6f0e701228f46345 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:00:31 +0000 Subject: [PATCH 035/298] decorations: fix manual resize not recalculating decos (#7323) modified: src/layout/DwindleLayout.cpp modified: src/layout/MasterLayout.cpp --- src/layout/DwindleLayout.cpp | 2 ++ src/layout/MasterLayout.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index acdc3de2..20085ff7 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -246,6 +246,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for g_pHyprRenderer->damageWindow(PWINDOW); } + + PWINDOW->updateWindowDecos(); } void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection direction) { diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index aa1c0adf..e0b48e98 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -732,6 +732,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { g_pHyprRenderer->damageWindow(PWINDOW); } + + PWINDOW->updateWindowDecos(); } bool CHyprMasterLayout::isWindowTiled(PHLWINDOW pWindow) { From 197f8807900afc81c1c92ad17e621d1998ee268b Mon Sep 17 00:00:00 2001 From: davc0n Date: Wed, 14 Aug 2024 19:35:07 +0200 Subject: [PATCH 036/298] logs: Add file path to asset ERR log (#7336) --- src/render/OpenGL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 0461662c..63cc2203 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2690,7 +2690,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { // check if wallpapers exist std::error_code err; if (!std::filesystem::exists(texPath, err)) { - Debug::log(ERR, "createBGTextureForMonitor: failed, file doesn't exist or access denied, ec: {}", err.message()); + Debug::log(ERR, "createBGTextureForMonitor: failed, file \"{}\" doesn't exist or access denied, ec: {}", texPath, err.message()); return; // the texture will be empty, oh well. We'll clear with a solid color anyways. } From d85ae306c5746c6ebeac74c2a7a520bb3f05a119 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Thu, 15 Aug 2024 06:37:56 -0500 Subject: [PATCH 037/298] xcursor: handle file errors when loading xcursor themes (#7326) --- src/managers/XCursorManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 3d36add5..0921bcd4 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -511,8 +511,11 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { for (const auto& entry : std::filesystem::directory_iterator(path)) { - if (!entry.is_regular_file() && !entry.is_symlink()) + std::error_code e1, e2; + if ((!entry.is_regular_file(e1) && !entry.is_symlink(e2)) || e1 || e2) { + Debug::log(WARN, "XCursor failed to load shape {}: {}", entry.path().stem().string(), e1 ? e1.message() : e2.message()); continue; + } auto const& full = entry.path().string(); using PcloseType = int (*)(FILE*); From c30dfe92eee017bc70e131fa30d3c87b56d0a143 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 15 Aug 2024 11:39:29 +0000 Subject: [PATCH 038/298] [gha] Nix: update inputs --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 8930d2e3..b4868793 100644 --- a/flake.lock +++ b/flake.lock @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1723175592, - "narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=", + "lastModified": 1723637854, + "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5e0ca22929f3342b19569b21b2f3462f053e497b", + "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9", "type": "github" }, "original": { From 069faa4027d016549ee72afcd7df3b2c1e7ee578 Mon Sep 17 00:00:00 2001 From: Mirkwood Date: Thu, 15 Aug 2024 14:03:23 +0200 Subject: [PATCH 039/298] helpers: fix: revert to signed arithmetic for cycling through workspaces (#7339) The code clearly expects signed types there. Fixes #7329 --- src/helpers/MiscFunctions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index a81aa7d1..86f24e3a 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -472,7 +472,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::sort(validWSes.begin(), validWSes.end()); - size_t currentItem = -1; + ssize_t currentItem = -1; if (absolute) { // 1-index @@ -481,7 +481,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // clamp if (currentItem < 0) { currentItem = 0; - } else if (currentItem >= validWSes.size()) { + } else if (currentItem >= (ssize_t)validWSes.size()) { currentItem = validWSes.size() - 1; } } else { @@ -490,7 +490,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // get the current item WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; - for (size_t i = 0; i < validWSes.size(); i++) { + for (ssize_t i = 0; i < (ssize_t)validWSes.size(); i++) { if (validWSes[i] == activeWSID) { currentItem = i; break; @@ -501,7 +501,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { currentItem += remains; // sanitize - if (currentItem >= validWSes.size()) { + if (currentItem >= (ssize_t)validWSes.size()) { currentItem = currentItem % validWSes.size(); } else if (currentItem < 0) { currentItem = validWSes.size() + currentItem; From 0c56be74a310e137f577a2b71fc2c72a8100eada Mon Sep 17 00:00:00 2001 From: Kyle <56144092+txkyel@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:04:24 -0400 Subject: [PATCH 040/298] keybinds: Fix syncFullscreen inconsistent with state when set by fullscreenState (#7343) * Set syncFullscreen to true on synced non -1 states * Fix syncFullscreen value in fullscreenState --- src/managers/KeybindManager.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8fc025ec..38593497 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1179,23 +1179,16 @@ void CKeybindManager::fullscreenStateActive(std::string args) { const sFullscreenState STATE = sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal), .client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)}; - if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) { + if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE}); - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); - return; - } - - if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) { + else if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client}); - return; - } - - if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) { + else if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE}); - return; - } + else + g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); - g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(PWINDOW->m_sFullscreenState.internal == PWINDOW->m_sFullscreenState.client, PRIORITY_SET_PROP); } void CKeybindManager::moveActiveToWorkspace(std::string args) { From 520e91238f0e6e6990e6a0845d73d85012485525 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:08:54 +0000 Subject: [PATCH 041/298] gamma-control: fix crash on monitor disconnect (#7353) --- src/protocols/GammaControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 494d9862..4febffbb 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -109,7 +109,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } CGammaControl::~CGammaControl() { - if (!gammaTableSet || !pMonitor) + if (!gammaTableSet || !pMonitor || !pMonitor->output) return; // reset the LUT if the client dies for whatever reason and doesn't unset the gamma From 15f942000ef53776852d6d9dfd303e691aed73e3 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:14:48 +0300 Subject: [PATCH 042/298] core: Preserve existing XDG_CURRENT_DESKTOP (#7347) * Preserve existing XDG_CURRENT_DESKTOP * fix --------- Co-authored-by: vaxerski --- src/Compositor.cpp | 7 ++++++- src/Compositor.hpp | 1 + src/main.cpp | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 26a985ef..4024fadf 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -305,6 +305,10 @@ void CCompositor::initServer(std::string socketName, int socketFd) { setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); setenv("XDG_SESSION_TYPE", "wayland", 1); + if (!getenv("XDG_CURRENT_DESKTOP")) { + setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1); + m_bDesktopEnvSet = true; + } initManagers(STAGE_BASICINIT); @@ -422,7 +426,8 @@ void CCompositor::cleanEnvironment() { // in main unsetenv("HYPRLAND_CMD"); unsetenv("XDG_BACKEND"); - unsetenv("XDG_CURRENT_DESKTOP"); + if (m_bDesktopEnvSet) + unsetenv("XDG_CURRENT_DESKTOP"); if (m_pAqBackend->hasSession()) { const auto CMD = diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 5e9e3266..a570a06e 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -91,6 +91,7 @@ class CCompositor { bool m_bNextIsUnsafe = false; CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state bool m_bIsShuttingDown = false; + bool m_bDesktopEnvSet = false; // ------------------------------------------------- // diff --git a/src/main.cpp b/src/main.cpp index e85b0a22..820a248c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,6 @@ int main(int argc, char** argv) { setenv("XDG_BACKEND", "wayland", 1); setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1); setenv("MOZ_ENABLE_WAYLAND", "1", 1); - setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1); // parse some args std::string configPath; From 12d9901472c6f9128fa8b16c25b3a879d1859e60 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 15 Aug 2024 18:16:18 +0200 Subject: [PATCH 043/298] protocols: refactor protocol logging to a macro (#7324) this avoids the usage of the unique_ptr PROTO::protocol before it has been constructed incase one wants to log something inside the constructor itself, move the logging to macros and print file:linenumber on ERR,CRIT,WARN and classname on the rest of the levels. --- src/protocols/AlphaModifier.cpp | 2 -- src/protocols/CursorShape.cpp | 2 -- src/protocols/DRMLease.cpp | 4 +-- src/protocols/DRMSyncobj.cpp | 2 -- src/protocols/DataDeviceWlr.cpp | 2 -- src/protocols/FocusGrab.cpp | 2 -- src/protocols/ForeignToplevel.cpp | 2 -- src/protocols/ForeignToplevelWlr.cpp | 2 -- src/protocols/FractionalScale.cpp | 2 -- src/protocols/GammaControl.cpp | 2 -- src/protocols/GlobalShortcuts.cpp | 2 -- src/protocols/IdleNotify.cpp | 2 -- src/protocols/InputMethodV2.cpp | 2 -- src/protocols/LayerShell.cpp | 2 -- src/protocols/LinuxDMABUF.cpp | 10 +++---- src/protocols/MesaDRM.cpp | 8 ++---- src/protocols/OutputManagement.cpp | 2 -- src/protocols/OutputPower.cpp | 2 -- src/protocols/PointerConstraints.cpp | 2 -- src/protocols/PointerGestures.cpp | 2 -- src/protocols/PresentationTime.cpp | 2 -- src/protocols/PrimarySelection.cpp | 2 -- src/protocols/Screencopy.cpp | 2 -- src/protocols/ServerDecorationKDE.cpp | 2 -- src/protocols/SessionLock.cpp | 2 -- src/protocols/ShortcutsInhibit.cpp | 2 -- src/protocols/Tablet.cpp | 2 -- src/protocols/TextInputV1.cpp | 2 -- src/protocols/TextInputV3.cpp | 2 -- src/protocols/ToplevelExport.cpp | 2 -- src/protocols/Viewporter.cpp | 2 -- src/protocols/VirtualKeyboard.cpp | 2 -- src/protocols/VirtualPointer.cpp | 2 -- src/protocols/WaylandProtocol.cpp | 4 +-- src/protocols/WaylandProtocol.hpp | 40 +++++++++++++++++++++------ src/protocols/XDGActivation.cpp | 2 -- src/protocols/XDGDecoration.cpp | 2 -- src/protocols/XDGOutput.cpp | 2 -- src/protocols/XDGShell.cpp | 2 -- src/protocols/XWaylandShell.cpp | 2 -- src/protocols/core/Compositor.cpp | 2 -- src/protocols/core/DataDevice.cpp | 2 -- src/protocols/core/Seat.cpp | 2 -- src/protocols/core/Shm.cpp | 2 -- src/protocols/core/Subcompositor.cpp | 2 -- 45 files changed, 42 insertions(+), 104 deletions(-) diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index 38b8c800..13597fa9 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -4,8 +4,6 @@ #include "../render/Renderer.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::alphaModifier->protoLog - CAlphaModifier::CAlphaModifier(SP resource_, SP surface_) : resource(resource_), pSurface(surface_) { if (!resource->resource()) return; diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 812afe53..233a5df9 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -2,8 +2,6 @@ #include #include "../helpers/CursorShapes.hpp" -#define LOGM PROTO::cursorShape->protoLog - CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 3ab38ea1..bc0945f1 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -4,8 +4,6 @@ #include #include -#define LOGM PROTO::lease->protoLog - CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { if (!good()) return; @@ -226,7 +224,7 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backe auto fd = drm->getNonMasterFD(); if (fd < 0) { - Debug::log(ERR, "[DRMLease] Failed to dup fd for drm node {}", drm->gpuName); + LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); return; } diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 9a48b99a..4993f1a4 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -7,8 +7,6 @@ #include -#define LOGM PROTO::sync->protoLog - CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index c039d3b4..ad6ee89a 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -3,8 +3,6 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" -#define LOGM PROTO::dataWlr->protoLog - CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 40f9af44..2d6b2ee2 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -8,8 +8,6 @@ #include #include -#define LOGM PROTO::focusGrab->protoLog - CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP surface) { listeners.destroy = surface->events.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); }); } diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index f7b3886f..59888ce2 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -1,8 +1,6 @@ #include "ForeignToplevel.hpp" #include "../Compositor.hpp" -#define LOGM PROTO::foreignToplevel->protoLog - CForeignToplevelHandle::CForeignToplevelHandle(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { if (!resource_->resource()) return; diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index b31a4083..bd597a91 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -4,8 +4,6 @@ #include "protocols/core/Output.hpp" #include "render/Renderer.hpp" -#define LOGM PROTO::foreignToplevelWlr->protoLog - CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { if (!resource_->resource()) return; diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index 5bf56c5a..d39fa67c 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -2,8 +2,6 @@ #include #include "core/Compositor.hpp" -#define LOGM PROTO::fractional->protoLog - CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 4febffbb..c902d00e 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -5,8 +5,6 @@ #include "../Compositor.hpp" #include "../protocols/core/Output.hpp" -#define LOGM PROTO::gamma->protoLog - CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { if (!resource_->resource()) return; diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 860004c9..92bfbae4 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -1,8 +1,6 @@ #include "GlobalShortcuts.hpp" #include "../Compositor.hpp" -#define LOGM PROTO::globalShortcuts->protoLog - CShortcutClient::CShortcutClient(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index 2ec7d2a1..8d915ac6 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -1,8 +1,6 @@ #include "IdleNotify.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" -#define LOGM PROTO::idle->protoLog - static int onTimer(SP self, void* data) { const auto NOTIF = (CExtIdleNotification*)data; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index fd306f09..a0820e0b 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -6,8 +6,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::ime->protoLog - CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SP resource_, SP owner_) : resource(resource_), owner(owner_) { if (!resource->resource()) return; diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 17d3b22a..c02d23f3 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -4,8 +4,6 @@ #include "core/Compositor.hpp" #include "core/Output.hpp" -#define LOGM PROTO::layerShell->protoLog - void CLayerShellResource::SState::reset() { anchor = 0; exclusive = 0; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 0fbf832e..3cdb5b34 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -14,8 +14,6 @@ #include "../render/OpenGL.hpp" #include "../Compositor.hpp" -#define LOGM PROTO::linuxDma->protoLog - static std::optional devIDFromFD(int fd) { struct stat stat; if (fstat(fd, &stat) != 0) @@ -425,7 +423,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const auto dev = devIDFromFD(rendererFD); if (!dev.has_value()) { - protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + LOGM(ERR, "failed to get drm dev, disabling linux dmabuf"); removeGlobal(); return; } @@ -477,7 +475,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const drmDevice* device = nullptr; if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { - protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + LOGM(ERR, "failed to get drm dev, disabling linux dmabuf"); removeGlobal(); return; } @@ -487,12 +485,12 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); drmFreeDevice(&device); if (mainDeviceFD < 0) { - protoLog(ERR, "failed to open drm dev, disabling linux dmabuf"); + LOGM(ERR, "failed to open drm dev, disabling linux dmabuf"); removeGlobal(); return; } } else { - protoLog(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); + LOGM(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); drmFreeDevice(&device); removeGlobal(); } diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index ed412555..9fcd5f9b 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -4,8 +4,6 @@ #include "../Compositor.hpp" #include "types/WLBuffer.hpp" -#define LOGM PROTO::mesaDRM->protoLog - CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) { LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); for (int i = 0; i < attrs_.planes; ++i) { @@ -115,7 +113,7 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co drmDevice* dev = nullptr; int drmFD = g_pCompositor->m_iDRMFD; if (drmGetDevice2(drmFD, 0, &dev) != 0) { - protoLog(ERR, "Failed to get device, disabling MesaDRM"); + LOGM(ERR, "Failed to get device, disabling MesaDRM"); removeGlobal(); return; } @@ -126,13 +124,13 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); if (!dev->nodes[DRM_NODE_PRIMARY]) { - protoLog(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); + LOGM(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); drmFreeDevice(&dev); removeGlobal(); return; } - protoLog(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); + LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); nodeName = dev->nodes[DRM_NODE_PRIMARY]; } drmFreeDevice(&dev); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 66f4c5f0..cfe388fa 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -4,8 +4,6 @@ using namespace Aquamarine; -#define LOGM PROTO::outputManagement->protoLog - COutputManager::COutputManager(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index 597b9871..0c324bf0 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -2,8 +2,6 @@ #include "../Compositor.hpp" #include "core/Output.hpp" -#define LOGM PROTO::outputPower->protoLog - COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_) : resource(resource_), pMonitor(pMonitor_) { if (!resource->resource()) return; diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index fd15242d..0f2dd991 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -5,8 +5,6 @@ #include "../managers/SeatManager.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::constraints->protoLog - CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) : resourceL(resource_), locked(true), lifetime(lifetime_) { if (!resource_->resource()) diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 86510779..c83e3887 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -4,8 +4,6 @@ #include "core/Seat.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::pointerGestures->protoLog - CPointerGestureSwipe::CPointerGestureSwipe(SP resource_) : resource(resource_) { if (!resource->resource()) return; diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index a2fc270c..335cf557 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -6,8 +6,6 @@ #include "core/Output.hpp" #include -#define LOGM PROTO::presentation->protoLog - CQueuedPresentationData::CQueuedPresentationData(SP surf) : surface(surf) { ; } diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 78eb8d63..4fede706 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -4,8 +4,6 @@ #include "core/Seat.hpp" #include "../config/ConfigValue.hpp" -#define LOGM PROTO::primarySelection->protoLog - CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index a8afba84..f246f6dd 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -9,8 +9,6 @@ #include -#define LOGM PROTO::screencopy->protoLog - CScreencopyFrame::~CScreencopyFrame() { if (buffer && buffer->locked()) buffer->unlock(); diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp index 42da52a9..c7b98a9c 100644 --- a/src/protocols/ServerDecorationKDE.cpp +++ b/src/protocols/ServerDecorationKDE.cpp @@ -1,8 +1,6 @@ #include "ServerDecorationKDE.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::serverDecorationKDE->protoLog - CServerDecorationKDE::CServerDecorationKDE(SP resource_, SP surf) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index df97413c..7b0d8b3b 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -5,8 +5,6 @@ #include "core/Compositor.hpp" #include "core/Output.hpp" -#define LOGM PROTO::sessionLock->protoLog - CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, CMonitor* pMonitor_, WP owner_) : resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { if (!resource->resource()) diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index 1a0433e6..e4424ed7 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -3,8 +3,6 @@ #include "../Compositor.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::shortcutsInhibit->protoLog - CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP resource_, SP surf) : resource(resource_), pSurface(surf) { if (!resource->resource()) return; diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 72c7cfde..b974152e 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -7,8 +7,6 @@ #include #include -#define LOGM PROTO::tablet->protoLog - CTabletPadStripV2Resource::CTabletPadStripV2Resource(SP resource_, uint32_t id_) : id(id_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index 78e910cb..f25f5aca 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -3,8 +3,6 @@ #include "../Compositor.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::textInputV1->protoLog - CTextInputV1::~CTextInputV1() { events.destroy.emit(); } diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 1302a57f..99d799f3 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -2,8 +2,6 @@ #include #include "core/Compositor.hpp" -#define LOGM PROTO::textInputV3->protoLog - void CTextInputV3::SState::reset() { cause = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD; surrounding.updated = false; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index fb3fde2b..05e991d6 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -8,8 +8,6 @@ #include -#define LOGM PROTO::toplevelExport->protoLog - CToplevelExportClient::CToplevelExportClient(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 78f3039f..58cb851d 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -2,8 +2,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::viewport->protoLog - CViewportResource::CViewportResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 2642ec11..27a4f248 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -2,8 +2,6 @@ #include #include "../devices/IKeyboard.hpp" -#define LOGM PROTO::virtualKeyboard->protoLog - CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index 8626241a..eb92a640 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -1,8 +1,6 @@ #include "VirtualPointer.hpp" #include "core/Output.hpp" -#define LOGM PROTO::virtualPointer->protoLog - CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_, WP boundOutput_) : boundOutput(boundOutput_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 954f160d..0782d323 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -21,7 +21,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, iface, ver, this, &bindManagerInternal); if (!m_pGlobal) { - protoLog(ERR, "could not create a global"); + LOGM(ERR, "could not create a global [{}]", m_szName); return; } @@ -30,7 +30,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co m_liDisplayDestroy.parent = this; wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener); - protoLog(LOG, "Registered global"); + LOGM(LOG, "Registered global [{}]", m_szName); } IWaylandProtocol::~IWaylandProtocol() { diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index 4d4e7925..0fa8daab 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -11,6 +11,35 @@ #define PROTO NProtocols +#define EXTRACT_CLASS_NAME() \ + []() constexpr -> std::string_view { \ + constexpr std::string_view prettyFunction = __PRETTY_FUNCTION__; \ + constexpr size_t colons = prettyFunction.find("::"); \ + if (colons != std::string_view::npos) { \ + constexpr size_t begin = prettyFunction.substr(0, colons).rfind(' ') + 1; \ + constexpr size_t end = colons - begin; \ + return prettyFunction.substr(begin, end); \ + } else { \ + return "Global"; \ + } \ + }() + +#define LOGM(level, ...) \ + do { \ + std::ostringstream oss; \ + if (level == WARN || level == ERR || level == CRIT) { \ + oss << "[" << __FILE__ << ":" << __LINE__ << "] "; \ + } else if (level == LOG || level == INFO || level == TRACE) { \ + oss << "[" << EXTRACT_CLASS_NAME() << "] "; \ + } \ + if constexpr (std::is_same_v) { \ + oss << __VA_ARGS__; \ + Debug::log(level, oss.str()); \ + } else { \ + Debug::log(level, std::format("{}{}", oss.str(), std::format(__VA_ARGS__))); \ + } \ + } while (0) + class IWaylandProtocol; struct IWaylandProtocolDestroyWrapper { wl_listener listener; @@ -22,15 +51,10 @@ class IWaylandProtocol { IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name); virtual ~IWaylandProtocol(); - virtual void onDisplayDestroy(); - virtual void removeGlobal(); + virtual void onDisplayDestroy(); + virtual void removeGlobal(); - virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; - - template - void protoLog(LogLevel level, std::format_string fmt, Args&&... args) { - Debug::log(level, std::format("[{}] ", m_szName) + std::vformat(fmt.get(), std::make_format_args(args...))); - }; + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; IWaylandProtocolDestroyWrapper m_liDisplayDestroy; diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index 40f33f02..4a6c7bfe 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -4,8 +4,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::activation->protoLog - CXDGActivationToken::CXDGActivationToken(SP resource_) : resource(resource_) { if (!resource_->resource()) return; diff --git a/src/protocols/XDGDecoration.cpp b/src/protocols/XDGDecoration.cpp index 021a1141..07b1694c 100644 --- a/src/protocols/XDGDecoration.cpp +++ b/src/protocols/XDGDecoration.cpp @@ -1,8 +1,6 @@ #include "XDGDecoration.hpp" #include -#define LOGM PROTO::xdgDecoration->protoLog - CXDGDecoration::CXDGDecoration(SP resource_, wl_resource* toplevel) : resource(resource_), pToplevelResource(toplevel) { if (!resource->resource()) return; diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 073aa502..9c2c353c 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -12,8 +12,6 @@ // -#define LOGM PROTO::xdgOutput->protoLog - void CXDGOutputProtocol::onManagerResourceDestroy(wl_resource* res) { std::erase_if(m_vManagerResources, [&](const auto& other) { return other->resource() == res; }); } diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index aea23329..eaf5c333 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -6,8 +6,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::xdgShell->protoLog - void SXDGPositionerState::setAnchor(xdgPositionerAnchor edges) { anchor.setTop(edges == XDG_POSITIONER_ANCHOR_TOP || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT); anchor.setLeft(edges == XDG_POSITIONER_ANCHOR_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT); diff --git a/src/protocols/XWaylandShell.cpp b/src/protocols/XWaylandShell.cpp index 6cc5256f..d6c3b1a8 100644 --- a/src/protocols/XWaylandShell.cpp +++ b/src/protocols/XWaylandShell.cpp @@ -2,8 +2,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::xwaylandShell->protoLog - CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index a767dd52..8b6f46b1 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -13,8 +13,6 @@ #include "../../render/Renderer.hpp" #include -#define LOGM PROTO::compositor->protoLog - class CDefaultSurfaceRole : public ISurfaceRole { public: virtual eSurfaceRole role() { diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index fe3905d0..4ed28f24 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -6,8 +6,6 @@ #include "Seat.hpp" #include "Compositor.hpp" -#define LOGM PROTO::data->protoLog - CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index bb6a9d4d..a111c12c 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -9,8 +9,6 @@ #include -#define LOGM PROTO::seat->protoLog - CWLTouchResource::CWLTouchResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 75c2134a..99459d9a 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -7,8 +7,6 @@ #include "../../Compositor.hpp" #include "../../helpers/Format.hpp" -#define LOGM PROTO::shm->protoLog - CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { if (!pool_->pool->data) return; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index 2a7c06dc..e0679eff 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -2,8 +2,6 @@ #include "Compositor.hpp" #include -#define LOGM PROTO::subcompositor->protoLog - CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP surface_, SP parent_) : surface(surface_), parent(parent_), resource(resource_) { if (!good()) From 682b30fba89c043e86d9c96bdb8df133c1683054 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:19:08 +0300 Subject: [PATCH 044/298] env: Add HYPRLAND_NO_SD_VARS env condition (#7358) * Add HYPRLAND_NO_SD_VARS env condition wip #7083 * Formatting shuffle * Formatting --- src/Compositor.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 4024fadf..9d247a56 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -429,7 +429,7 @@ void CCompositor::cleanEnvironment() { if (m_bDesktopEnvSet) unsetenv("XDG_CURRENT_DESKTOP"); - if (m_pAqBackend->hasSession()) { + if (m_pAqBackend->hasSession() && !envEnabled("HYPRLAND_NO_SD_VARS")) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -659,7 +659,11 @@ void CCompositor::prepareFallbackOutput() { void CCompositor::startCompositor() { signal(SIGPIPE, SIG_IGN); - if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) { + if ( + /* Session-less Hyprland usually means a nest, don't update the env in that case */ + m_pAqBackend->hasSession() && + /* Activation environment management is not disabled */ + !envEnabled("HYPRLAND_NO_SD_VARS")) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " From 1840a907a8c6b1f59cfa6738a8f46b320e8df8b1 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 16 Aug 2024 11:09:01 +0200 Subject: [PATCH 045/298] renderbuffer: ensure framebuffer gets deleted (#7363) after commit 4b4971c it uses m_iFbAllocated and deletes if upon calling release() but Renderbuffer generates directly on m_iFb without calling alloc() meaning it wont be deleted on release(), set m_iFbAllocated to true after generating the buffer. --- src/render/Renderbuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 58ed88d6..c4425ce9 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -35,7 +35,8 @@ CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : glBindRenderbuffer(GL_RENDERBUFFER, 0); glGenFramebuffers(1, &m_sFramebuffer.m_iFb); - m_sFramebuffer.m_vSize = buffer->size; + m_sFramebuffer.m_iFbAllocated = true; + m_sFramebuffer.m_vSize = buffer->size; m_sFramebuffer.bind(); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); From c5feee1e357f3c3c59ebe406630601c627807963 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 16 Aug 2024 18:00:59 +0200 Subject: [PATCH 046/298] xcursormgr: dont apply scale on gsettings (#7316) gtk scales the cursor size itself since its CSD so if we scale the size its gonna get double scaled. incorporate the scale into xcursormanager to keep track of it. --- src/managers/CursorManager.cpp | 10 +++++----- src/managers/XCursorManager.cpp | 18 ++++++++++-------- src/managers/XCursorManager.hpp | 9 +++++---- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index e2dd5bb3..1c047f85 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -102,7 +102,7 @@ CCursorManager::CCursorManager() { // since we fallback to xcursor always load it on startup. otherwise we end up with a empty theme if hyprcursor is enabled in the config // and then later is disabled. - m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); + m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize, m_fCursorScale); m_pAnimationTimer = makeShared(std::nullopt, cursorAnimTimer, this); g_pEventLoopManager->addTimer(m_pAnimationTimer); @@ -163,7 +163,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { auto setXCursor = [this](auto const& name) { float scale = std::ceil(m_fCursorScale); - auto xcursor = m_pXcursor->getShape(name, m_iSize * scale); + auto xcursor = m_pXcursor->getShape(name, m_iSize, m_fCursorScale); auto& icon = xcursor->images.front(); auto buf = makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot); setCursorBuffer(buf, icon.hotspot / scale, scale); @@ -277,7 +277,7 @@ void CCursorManager::setXWaylandCursor() { g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); else { - auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale)); + auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize, 1); auto& icon = xcursor->images.front(); g_pXWayland->setCursor((uint8_t*)icon.pixels.data(), icon.size.x * 4, icon.size, icon.hotspot); @@ -329,10 +329,10 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options); if (!m_pHyprcursor->valid()) { Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", m_szTheme); - m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize, m_fCursorScale); } } else - m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize, m_fCursorScale); updateTheme(); diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 0921bcd4..6f000f9f 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -100,12 +100,13 @@ CXCursorManager::CXCursorManager() { defaultCursor = hyprCursor; } -void CXCursorManager::loadTheme(std::string const& name, int size) { - if (lastLoadSize == size && themeName == name) +void CXCursorManager::loadTheme(std::string const& name, int size, float scale) { + if (lastLoadSize == (size * std::ceil(scale)) && themeName == name && lastLoadScale == scale) return; - lastLoadSize = size; - themeName = name.empty() ? "default" : name; + lastLoadSize = size * std::ceil(scale); + lastLoadScale = scale; + themeName = name.empty() ? "default" : name; defaultCursor.reset(); cursors.clear(); @@ -156,10 +157,10 @@ void CXCursorManager::loadTheme(std::string const& name, int size) { syncGsettings(); } -SP CXCursorManager::getShape(std::string const& shape, int size) { +SP CXCursorManager::getShape(std::string const& shape, int size, float scale) { // monitor scaling changed etc, so reload theme with new size. - if (size != lastLoadSize) - loadTheme(themeName, size); + if ((size * std::ceil(scale)) != lastLoadSize || scale != lastLoadScale) + loadTheme(themeName, size, scale); // try to get an icon we know if we have one for (auto const& c : cursors) { @@ -602,6 +603,7 @@ void CXCursorManager::syncGsettings() { g_object_unref(gsettings); }; + int unscaledSize = lastLoadSize / std::ceil(lastLoadScale); setValue("cursor-theme", themeName, "org.gnome.desktop.interface"); - setValue("cursor-size", lastLoadSize, "org.gnome.desktop.interface"); + setValue("cursor-size", unscaledSize, "org.gnome.desktop.interface"); } diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 48fda5dd..1f3c24db 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -29,8 +29,8 @@ class CXCursorManager { CXCursorManager(); ~CXCursorManager() = default; - void loadTheme(const std::string& name, int size); - SP getShape(std::string const& shape, int size); + void loadTheme(const std::string& name, int size, float scale); + SP getShape(std::string const& shape, int size, float scale); void syncGsettings(); private: @@ -40,8 +40,9 @@ class CXCursorManager { std::vector> loadStandardCursors(std::string const& name, int size); std::vector> loadAllFromDir(std::string const& path, int size); - int lastLoadSize = 0; - std::string themeName = ""; + int lastLoadSize = 0; + float lastLoadScale = 0; + std::string themeName = ""; SP defaultCursor; SP hyprCursor; std::vector> cursors; From 92744b5b9aa386257bf243c957ab64f7f4171a19 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 17 Aug 2024 17:33:16 +0100 Subject: [PATCH 047/298] IPC: Add config descriptions (#7377) Thanks @gulafaran for the work --- Co-authored-by: @gulafaran --- src/config/ConfigDescriptions.hpp | 1344 +++++++++++++++++++++++++++ src/config/ConfigManager.cpp | 63 +- src/config/ConfigManager.hpp | 66 ++ src/debug/HyprCtl.cpp | 16 + src/helpers/Color.cpp | 2 +- src/helpers/Color.hpp | 2 +- src/managers/input/InputManager.cpp | 11 +- 7 files changed, 1491 insertions(+), 13 deletions(-) create mode 100644 src/config/ConfigDescriptions.hpp diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp new file mode 100644 index 00000000..3c830132 --- /dev/null +++ b/src/config/ConfigDescriptions.hpp @@ -0,0 +1,1344 @@ +#pragma once + +#include "ConfigManager.hpp" + +inline static const std::vector CONFIG_OPTIONS = { + + /* + * general: + */ + + SConfigOptionDescription{ + .value = "general:border_size", + .description = "size of the border around windows", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "general:no_border_on_floating", + .description = "disable borders for floating windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:gaps_in", + .description = "gaps between windows\n\nsupports css style gaps (top, right, bottom, left -> 5 10 15 20)", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"5"}, + }, + SConfigOptionDescription{ + .value = "general:gaps_out", + .description = "gaps between windows and monitor edges\n\nsupports css style gaps (top, right, bottom, left -> 5 10 15 20)", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"20"}, + }, + SConfigOptionDescription{ + .value = "general:gaps_workspaces", + .description = "gaps between workspaces. Stacks with gaps_out.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 100}, + }, + SConfigOptionDescription{ + .value = "general:col.inactive_border", + .description = "border color for inactive windows", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xff444444"}, + }, + SConfigOptionDescription{ + .value = "general:col.active_border", + .description = "border color for the active window", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xffffffff"}, + }, + SConfigOptionDescription{ + .value = "general:col.nogroup_border", + .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xffffaaff"}, + }, + SConfigOptionDescription{ + .value = "general:col.nogroup_border_active", + .description = "active border color for window that cannot be added to a group", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xffff00ff"}, + }, + SConfigOptionDescription{ + .value = "general:layout", + .description = "which layout to use. [dwindle/master]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"dwindle"}, + }, + SConfigOptionDescription{ + .value = "general:no_focus_fallback", + .description = "if true, will not fall back to the next available window when moving focus in a direction where no window was found", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:resize_on_border", + .description = "enables resizing windows by clicking and dragging on borders and gaps", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:extend_border_grab_area", + .description = "extends the area around the border where you can click and drag on, only used when general:resize_on_border is on.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{15, 0, 100}, + }, + SConfigOptionDescription{ + .value = "general:hover_icon_on_border", + .description = "show a cursor icon when hovering over borders, only used when general:resize_on_border is on.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "general:allow_tearing", + .description = "master switch for allowing tearing to occur. See the Tearing page.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:resize_corner", + .description = "force floating windows to use a specific corner when being resized (1-4 going clockwise from top left, 0 to disable)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 4}, + }, + + /* + * decoration: + */ + + SConfigOptionDescription{ + .value = "decoration:rounding", + .description = "rounded corners' radius (in layout px)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 20}, + }, + SConfigOptionDescription{ + .value = "decoration:active_opacity", + .description = "opacity of active windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:inactive_opacity", + .description = "opacity of inactive windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:fullscreen_opacity", + .description = "opacity of fullscreen windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:drop_shadow", + .description = "enable drop shadows on windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_range", + .description = "Shadow range (size) in layout px", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{4, 0, 100}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_render_power", + .description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 1, 4}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_ignore_window", + .description = "if true, the shadow will not be rendered behind the window itself, only around it.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "decoration:col.shadow", + .description = "shadow's color. Alpha dictates shadow's opacity.", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0xee1a1a1a}, + }, + SConfigOptionDescription{ + .value = "decoration:col.shadow_inactive", + .description = "inactive shadow color. (if not set, will fall back to col.shadow)", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "decoration:shadow_offset", + .description = "shadow's rendering offset.", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_scale", + .description = "shadow's scale. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_inactive", + .description = "enables dimming of inactive windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_strength", + .description = "how much inactive windows should be dimmed [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.5, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_special", + .description = "how much to dim the rest of the screen by when a special workspace is open. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_around", + .description = "how much the dimaround window rule should dim by. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.4, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:screen_shader", + .description = "screen_shader a path to a custom shader to be applied at the end of rendering. See examples/screenShader.frag for an example.", + .type = CONFIG_OPTION_STRING_LONG, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + + /* + * blur: + */ + + SConfigOptionDescription{ + .value = "blur:enabled", + .description = "enable kawase window background blur", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "blur:size", + .description = "blur size (distance)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{8, 0, 100}, + }, + SConfigOptionDescription{ + .value = "blur:passes", + .description = "the amount of passes to perform", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 10}, + }, + SConfigOptionDescription{ + .value = "blur:ignore_opacity", + .description = "make the blur layer ignore the opacity of the window", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:new_optimizations", + .description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "blur:xray", + .description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating " + "blur significantly.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:noise", + .description = "how much noise to apply. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.0117, 0, 1}, + }, + SConfigOptionDescription{ + .value = "blur:contrast", + .description = "contrast modulation for blur. [0.0 - 2.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.8916, 0, 2}, + }, + SConfigOptionDescription{ + .value = "blur:brightness", + .description = "brightness modulation for blur. [0.0 - 2.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.8172, 0, 2}, + }, + SConfigOptionDescription{ + .value = "blur:vibrancy", + .description = "Increase saturation of blurred colors. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.1696, 0, 1}, + }, + SConfigOptionDescription{ + .value = "blur:vibrancy_darkness", + .description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "blur:special", + .description = "whether to blur behind the special workspace (note: expensive)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:popups", + .description = "whether to blur popups (e.g. right-click menus)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:popups_ignorealpha", + .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, + }, + + /* + * animations: + */ + + SConfigOptionDescription{ + .value = "animations:enabled", + .description = "enable animations", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "animations:first_launch_animation", + .description = "enable first launch animation", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * input: + */ + + SConfigOptionDescription{ + .value = "input:kb_model", + .description = "Appropriate XKB keymap parameter. See the note below.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, + }, + SConfigOptionDescription{ + .value = "input:kb_layout", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"us"}, + }, + SConfigOptionDescription{ + .value = "input:kb_variant", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, + }, + SConfigOptionDescription{ + .value = "input:kb_options", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, + }, + SConfigOptionDescription{ + .value = "input:kb_rules", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, + }, + SConfigOptionDescription{ + .value = "input:kb_file", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_LONG, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:numlock_by_default", + .description = "Engage numlock by default.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:resolve_binds_by_sym", + .description = "Determines how keybinds act when multiple layouts are used. If false, keybinds will always act as if the first specified layout is active. If true, " + "keybinds specified by symbols are activated when you type the respective symbol with the current layout.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:repeat_rate", + .description = "The repeat rate for held-down keys, in repeats per second.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{25, 0, 200}, + }, + SConfigOptionDescription{ + .value = "input:repeat_delay", + .description = "Delay before a held-down key is repeated, in milliseconds.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{600, 0, 2000}, + }, + SConfigOptionDescription{ + .value = "input:sensitivity", + .description = "Sets the mouse input sensitivity. Value is clamped to the range -1.0 to 1.0.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0, -1, 1}, + }, + SConfigOptionDescription{ + .value = "input:accel_profile", + .description = "Sets the cursor acceleration profile. Can be one of adaptive, flat. Can also be custom, see below. Leave empty to use libinput's default mode for your " + "input device. [adaptive/flat/custom]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:force_no_accel", + .description = "Force no cursor acceleration. This bypasses most of your pointer settings to get as raw of a signal as possible. Enabling this is not recommended due to " + "potential cursor desynchronization.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:left_handed", + .description = "Switches RMB and LMB", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:scroll_points", + .description = "Sets the scroll acceleration profile, when accel_profile is set to custom. Has to be in the form . Leave empty to have a flat scroll curve.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:scroll_method", + .description = "Sets the scroll method. Can be one of 2fg (2 fingers), edge, on_button_down, no_scroll. [2fg/edge/on_button_down/no_scroll]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:scroll_button", + .description = "Sets the scroll button. Has to be an int, cannot be a string. Check wev if you have any doubts regarding the ID. 0 means default.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 300}, + }, + SConfigOptionDescription{ + .value = "input:scroll_button_lock", + .description = "If the scroll button lock is enabled, the button does not need to be held down. Pressing and releasing the button toggles the button lock, which logically " + "holds the button down or releases it. While the button is logically held down, motion events are converted to scroll events.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:scroll_factor", + .description = "Multiplier added to scroll movement for external mice. Note that there is a separate setting for touchpad scroll_factor.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "input:natural_scroll", + .description = "Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:follow_mouse", + .description = "Specify if and how cursor movement should affect window focus. See the note below. [0/1/2/3]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 3}, + }, + SConfigOptionDescription{ + .value = "input:mouse_refocus", + .description = "if disabled, mouse focus won't switch to the hovered window unless the mouse crosses a window boundary when follow_mouse=1.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "input:float_switch_override_focus", + .description = "If enabled (1 or 2), focus will change to the window under the cursor when changing from tiled-to-floating and vice versa. If 2, focus will also follow " + "mouse on float-to-float switches.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "input:special_fallthrough", + .description = "if enabled, having only floating windows in the special workspace will not block focusing windows in the regular workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:off_window_axis_events", + .description = "Handles axis events around (gaps/border for tiled, dragarea/border for floated) a focused window. 0 ignores axis events 1 sends out-of-bound coordinates 2 " + "fakes pointer coordinates to the closest point inside the window 3 warps the cursor to the closest point inside the window", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 3}, + }, + SConfigOptionDescription{ + .value = "input:emulate_discrete_scroll", + .description = "Emulates discrete scrolling from high resolution scrolling events. 0 disables it, 1 enables handling of non-standard events only, and 2 force enables all " + "scroll wheel events to be handled", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 2}, + }, + + /* + * input:touchpad: + */ + + SConfigOptionDescription{ + .value = "input:touchpad:disable_while_typing", + .description = "Disable the touchpad while typing.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:natural_scroll", + .description = "Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:scroll_factor", + .description = "Multiplier applied to the amount of scroll movement.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:middle_button_emulation", + .description = + "Sending LMB and RMB simultaneously will be interpreted as a middle click. This disables any touchpad area that would normally send a middle click based on location.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:tap_button_map", + .description = "Sets the tap button mapping for touchpad button emulation. Can be one of lrm (default) or lmr (Left, Middle, Right Buttons). [lrm/lmr]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:touchpad:clickfinger_behavior", + .description = + "Button presses with 1, 2, or 3 fingers will be mapped to LMB, RMB, and MMB respectively. This disables interpretation of clicks based on location on the touchpad.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:tap-to-click", + .description = "Tapping on the touchpad with 1, 2, or 3 fingers will send LMB, RMB, and MMB respectively.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:drag_lock", + .description = "When enabled, lifting the finger off for a short time while dragging will not drop the dragged item.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:tap-and-drag", + .description = "Sets the tap and drag mode for the touchpad", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * input:touchdevice: + */ + + SConfigOptionDescription{ + .value = "input:touchdevice:transform", + .description = "Transform the input from touchdevices. The possible transformations are the same as those of the monitors", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 6}, // ##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "input:touchdevice:output", + .description = "The monitor to bind touch devices. The default is auto-detection. To stop auto-detection, use an empty string or the [[Empty]] value.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:touchdevice:enabled", + .description = "Whether input is enabled for touch devices.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * input:tablet: + */ + + SConfigOptionDescription{ + .value = "input:tablet:transform", + .description = "transform the input from tablets. The possible transformations are the same as those of the monitors", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 6}, // ##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "input:tablet:output", + .description = "the monitor to bind tablets. Empty means unbound..", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:tablet:region_position", + .description = "position of the mapped region in monitor layout.", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}}, + }, + SConfigOptionDescription{ + .value = "input:tablet:region_size", + .description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {-100, -100}, {4000, 4000}}, + }, + SConfigOptionDescription{ + .value = "input:tablet:relative_input", + .description = "whether the input should be relative", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:tablet:left_handed", + .description = "if enabled, the tablet will be rotated 180 degrees", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:tablet:active_area_size", + .description = "size of tablet's active area in mm", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {}, {500, 500}}, + }, + SConfigOptionDescription{ + .value = "input:tablet:active_area_position", + .description = "position of the active area in mm", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {}, {500, 500}}, + }, + + /* ##TODO + * + * PER DEVICE SETTINGS? + * + * */ + + /* + * gestures: + */ + + SConfigOptionDescription{ + .value = "gestures:workspace_swipe", + .description = "enable workspace swipe gesture on touchpad", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_fingers", + .description = "how many fingers for the touchpad gesture", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 0, 5}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_min_fingers", + .description = "if enabled, workspace_swipe_fingers is considered the minimum number of fingers to swipe", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_distance", + .description = "in px, the distance of the touchpad gesture", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{300, 0, 2000}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_touch", + .description = "enable workspace swiping from the edge of a touchscreen", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_invert", + .description = "invert the direction (touchpad only)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_touch_invert", + .description = "invert the direction (touchscreen only)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_min_speed_to_force", + .description = "minimum speed in px per timepoint to force the change ignoring cancel_ratio. Setting to 0 will disable this mechanic.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{30, 0, 200}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_cancel_ratio", + .description = "how much the swipe has to proceed in order to commence it. (0.7 -> if > 0.7 * distance, switch, if less, revert) [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.5, 0, 1}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_create_new", + .description = "whether a swipe right on the last workspace should create a new one.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_direction_lock", + .description = "if enabled, switching direction will be locked when you swipe past the direction_lock_threshold (touchpad only).", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_direction_lock_threshold", + .description = "in px, the distance to swipe before direction lock activates (touchpad only).", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{10, 0, 200}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_forever", + .description = "if enabled, swiping will not clamp at the neighboring workspaces but continue to the further ones.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_use_r", + .description = "if enabled, swiping will use the r prefix instead of the m prefix for finding workspaces.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * group: + */ + + SConfigOptionDescription{ + .value = "group:insert_after_current", + .description = "whether new windows in a group spawn after current or at group tail", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:focus_removed_window", + .description = "whether Hyprland should focus on the window that has just been moved out of the group", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "general:col.border_active", + .description = "border color for inactive windows", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66ffff00"}, + }, + SConfigOptionDescription{ + .value = "general:col.border_inactive", + .description = "border color for the active window", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66777700"}, + }, + SConfigOptionDescription{ + .value = "general:col.border_locked_active", + .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66ff5500"}, + }, + SConfigOptionDescription{ + .value = "general:col.border_locked_inactive", + .description = "active border color for window that cannot be added to a group", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66775500"}, + }, + + /* + * group:groupbar: + */ + + SConfigOptionDescription{ + .value = "group:groupbar:enabled", + .description = "enables groupbars", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:font_family", + .description = "font used to display groupbar titles, use misc:font_family if not specified", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "group:groupbar:font_size", + .description = "font size of groupbar title", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{8, 2, 64}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:gradients", + .description = "enables gradients", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:height", + .description = "height of the groupbar", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{14, 1, 64}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:stacked", + .description = "render the groupbar as a vertical stack", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:priority", + .description = "sets the decoration priority for groupbars", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 0, 6}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "group:groupbar:render_titles", + .description = "whether to render titles in the group bar decoration", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:scrolling", + .description = "whether scrolling in the groupbar changes group active window", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:text_color", + .description = "controls the group bar text color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0xffffffff}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.active", + .description = "active group border color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66ffff00}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.inactive", + .description = "inactive (out of focus) group border color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66777700}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.locked_active", + .description = "active locked group border color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66ff5500}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.locked_inactive", + .description = "controls the group bar text color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66775500}, + }, + + /* + * misc: + */ + + SConfigOptionDescription{ + .value = "misc:disable_hyprland_logo", + .description = "disables the random Hyprland logo / anime girl background. :(", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:disable_splash_rendering", + .description = "disables the Hyprland splash rendering. (requires a monitor reload to take effect)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:col.splash", + .description = "Changes the color of the splash text (requires a monitor reload to take effect).", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0xffffffff}, + }, + SConfigOptionDescription{ + .value = "misc:font_family", + .description = "Set the global default font to render the text including debug fps/notification, config error messages and etc., selected from system fonts.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"Sans"}, + }, + SConfigOptionDescription{ + .value = "misc:splash_font_family", + .description = "Changes the font used to render the splash text, selected from system fonts (requires a monitor reload to take effect).", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "misc:force_default_wallpaper", + .description = "Enforce any of the 3 default wallpapers. Setting this to 0 or 1 disables the anime background. -1 means “random”. [-1/0/1/2]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{-1, -1, 2}, + }, + SConfigOptionDescription{ + .value = "misc:vfr", + .description = "controls the VFR status of Hyprland. Heavily recommended to leave enabled to conserve resources.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:vrr", + .description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 2}, + }, + SConfigOptionDescription{ + .value = "misc:mouse_move_enables_dpms", + .description = "If DPMS is set to off, wake up the monitors if the mouse move", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:key_press_enables_dpms", + .description = "If DPMS is set to off, wake up the monitors if a key is pressed.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:always_follow_on_dnd", + .description = "Will make mouse focus follow the mouse when drag and dropping. Recommended to leave it enabled, especially for people using focus follows mouse at 0.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:layers_hog_keyboard_focus", + .description = "If true, will make keyboard-interactive layers keep their focus on mouse move (e.g. wofi, bemenu)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:animate_manual_resizes", + .description = "If true, will animate manual window resizes/moves", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:animate_mouse_windowdragging", + .description = "If true, will animate windows being dragged by mouse, note that this can cause weird behavior on some curves", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:disable_autoreload", + .description = "If true, the config will not reload automatically on save, and instead needs to be reloaded with hyprctl reload. Might save on battery.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:enable_swallow", + .description = "Enable window swallowing", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:swallow_regex", + .description = + "The class regex to be used for windows that should be swallowed (usually, a terminal). To know more about the list of regex which can be used use this cheatsheet.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "misc:swallow_exception_regex", + .description = "The title regex to be used for windows that should not be swallowed by the windows specified in swallow_regex (e.g. wev). The regex is matched against the " + "parent (e.g. Kitty) window’s title on the assumption that it changes to whatever process it’s running.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "misc:focus_on_activate", + .description = "Whether Hyprland should focus an app that requests to be focused (an activate request)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:mouse_move_focuses_monitor", + .description = "Whether mouse moving into a different monitor should focus it", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:render_ahead_of_time", + .description = "[Warning: buggy] starts rendering before your monitor displays a frame in order to lower latency", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:render_ahead_safezone", + .description = "how many ms of safezone to add to rendering ahead of time. Recommended 1-2.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 1, 10}, + }, + SConfigOptionDescription{ + .value = "misc:allow_session_lock_restore", + .description = "if true, will allow you to restart a lockscreen app in case it crashes (red screen of death)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:background_color", + .description = "change the background color. (requires enabled disable_hyprland_logo)", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x111111}, + }, + SConfigOptionDescription{ + .value = "misc:close_special_on_empty", + .description = "close the special workspace if the last window is removed", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:new_window_takes_over_fullscreen", + .description = "if there is a fullscreen or maximized window, decide whether a new tiled window opened should replace it, stay behind or disable the fullscreen/maximized " + "state. 0 - behind, 1 - takes over, 2 - unfullscreen/unmaxize [0/1/2]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 2}, + }, + SConfigOptionDescription{ + .value = "misc:exit_window_retains_fullscreen", + .description = "if true, closing a fullscreen window makes the next focused window fullscreen", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:initial_workspace_tracking", + .description = "if enabled, windows will open on the workspace they were invoked on. 0 - disabled, 1 - single-shot, 2 - persistent (all children too)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "misc:middle_click_paste", + .description = "whether to enable middle-click-paste (aka primary selection)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * binds: + */ + + SConfigOptionDescription{ + .value = "binds:pass_mouse_when_bound", + .description = "if disabled, will not pass the mouse events to apps / dragging windows around if a keybind has been triggered.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:scroll_event_delay", + .description = "in ms, how many ms to wait after a scroll event to allow passing another one for the binds.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{300, 0, 2000}, + }, + SConfigOptionDescription{ + .value = "binds:workspace_back_and_forth", + .description = "If enabled, an attempt to switch to the currently focused workspace will instead switch to the previous workspace. Akin to i3’s auto_back_and_forth.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:allow_workspace_cycles", + .description = "If enabled, workspaces don’t forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly " + "going to the previous workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:workspace_center_on", + .description = "Whether switching workspaces should center the cursor on the workspace (0) or on the last active window for that workspace (1)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "binds:focus_preferred_method", + .description = "sets the preferred focus finding method when using focuswindow/movewindow/etc with a direction. 0 - history (recent have priority), 1 - length (longer " + "shared edges have priority)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "binds:ignore_group_lock", + .description = "If enabled, dispatchers like moveintogroup, moveoutofgroup and movewindoworgroup will ignore lock per group.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:movefocus_cycles_fullscreen", + .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "binds:disable_keybind_grabbing", + .description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:window_direction_monitor_fallback", + .description = "If enabled, moving a window or focus over the edge of a monitor with a direction will move it to the next monitor in that direction.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * xwayland: + */ + + SConfigOptionDescription{ + .value = "xwayland:use_nearest_neighbor", + .description = "uses the nearest neighbor filtering for xwayland apps, making them pixelated rather than blurry", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "xwayland:force_zero_scaling", + .description = "forces a scale of 1 on xwayland windows on scaled displays.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * opengl: + */ + + SConfigOptionDescription{ + .value = "opengl:nvidia_anti_flicker", + .description = "reduces flickering on nvidia at the cost of possible frame drops on lower-end GPUs. On non-nvidia, this is ignored.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "opengl:force_introspection", + .description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - " + "nothing, 1 - force always on, 2 - force always on if nvidia", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + + /* + * render: + */ + + SConfigOptionDescription{ + .value = "render:explicit_sync", + .description = "Whether to enable explicit sync support. Requires a hyprland restart. 0 - no, 1 - yes, 2 - auto based on the gpu driver", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + SConfigOptionDescription{ + .value = "render:explicit_sync_kms", + .description = "Whether to enable explicit sync support for the KMS layer. Requires explicit_sync to be enabled. 0 - no, 1 - yes, 2 - auto based on the gpu driver", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + SConfigOptionDescription{ + .value = "render:direct_scanout", + .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also " + "recommended to set this to false if the fullscreen application shows graphical glitches.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * cursor: + */ + + SConfigOptionDescription{ + .value = "cursor:use_nearest_neighbor", + .description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor " + "theme and size.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "cursor:no_hardware_cursors", + .description = "disables hardware cursors", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:no_break_fs_vrr", + .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:min_refresh_rate", + .description = "minimum refresh rate for cursor movement when no_break_fs_vrr is active. Set to minimum supported refresh rate or higher", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{24, 10, 500}, + }, + SConfigOptionDescription{ + .value = "cursor:hotspot_padding", + .description = "the padding, in logical px, between screen edges and the cursor", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "cursor:inactive_timeout", + .description = "in seconds, after how many seconds of cursor’s inactivity to hide it. Set to 0 for never.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 20}, + }, + SConfigOptionDescription{ + .value = "cursor:no_warps", + .description = "if true, will not warp the cursor in many cases (focusing, keybinds, etc)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:persistent_warps", + .description = "When a window is refocused, the cursor returns to its last position relative to that window, rather than to the centre.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:warp_on_change_workspace", + .description = "If true, move the cursor to the last focused window after changing the workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:default_monitor", + .description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "cursor:zoom_factor", + .description = "the factor to zoom by around the cursor. Like a magnifying glass. Minimum 1.0 (meaning no zoom)", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 1, 10}, + }, + SConfigOptionDescription{ + .value = "cursor:zoom_rigid", + .description = "whether the zoom should follow the cursor rigidly (cursor is always centered if it can be) or loosely", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:enable_hyprcursor", + .description = "whether to enable hyprcursor support", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "cursor:hide_on_key_press", + .description = "Hides the cursor when you press any key until the mouse is moved.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:hide_on_touch", + .description = "Hides the cursor when the last input was a touch input until a mouse input is done.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "cursor:allow_dumb_copy", + .description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * debug: + */ + + SConfigOptionDescription{ + .value = "debug:overlay", + .description = "print the debug performance overlay. Disable VFR for accurate results.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:damage_blink", + .description = "disable logging to a file", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:disable_logs", + .description = "disable logging to a file", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "debug:disable_time", + .description = "disables time logging", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "debug:damage_tracking", + .description = "redraw only the needed bits of the display. Do not change. (default: full - 2) monitor - 1, none - 0", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + SConfigOptionDescription{ + .value = "debug:enable_stdout_logs", + .description = "enables logging to stdout", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:manual_crash", + .description = "set to 1 and then back to 0 to crash Hyprland.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "debug:suppress_errors", + .description = "if true, do not display config file parsing errors.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:watchdog_timeout", + .description = "sets the timeout in seconds for watchdog to abort processing of a signal of the main thread. Set to 0 to disable.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{5, 0, 20}, + }, + SConfigOptionDescription{ + .value = "debug:disable_scale_checks", + .description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:error_limit", + .description = "limits the number of displayed config file parsing errors.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{5, 0, 20}, + }, + SConfigOptionDescription{ + .value = "debug:error_position", + .description = "sets the position of the error bar. top - 0, bottom - 1", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "debug:colored_stdout_logs", + .description = "enables colors in the stdout logs.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, +}; \ No newline at end of file diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 41d3871c..1856bd49 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -28,7 +28,9 @@ #include using namespace Hyprutils::String; -extern "C" char** environ; +extern "C" char** environ; + +#include "ConfigDescriptions.hpp" static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** data) { std::string V = VALUE; @@ -312,8 +314,6 @@ CConfigManager::CConfigManager() { configPaths.emplace_back(getMainConfigPath()); m_pConfig = std::make_unique(configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true}); - m_pConfig->addConfigValue("general:sensitivity", {1.0f}); - m_pConfig->addConfigValue("general:apply_sens_to_raw", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:border_size", Hyprlang::INT{1}); m_pConfig->addConfigValue("general:no_border_on_floating", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:border_part_of_window", Hyprlang::INT{1}); @@ -2607,3 +2607,60 @@ std::optional CConfigManager::handlePlugin(const std::string& comma return {}; } + +const std::vector& CConfigManager::getAllDescriptions() { + return CONFIG_OPTIONS; +} + +std::string SConfigOptionDescription::jsonify() const { + auto parseData = [this]() -> std::string { + return std::visit( + [](auto&& val) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return std::format(R"#( "value": "{}")#", val.value); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {}, + "min": {}, + "max": {})#", + val.value, val.min, val.max); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {}, + "min": {}, + "max": {})#", + val.value, val.min, val.max); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {})#", val.color.getAsHex()); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {})#", val.value); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {})#", val.choices); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "x": {}, + "y": {}, + "min_x": {}, + "min_y": {}, + "max_x": {}, + "max_y": {})#", + val.vec.x, val.vec.y, val.min.x, val.min.y, val.max.x, val.max.y); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": "{}")#", val.gradient); + } + return std::string{""}; + }, + data); + }; + + std::string json = std::format(R"#({{ + "value": "{}", + "description": "{}", + "type": {}, + "flags": {}, + "data": {{ + {} + }} +}})#", + value, description, (uint16_t)type, (uint32_t)flags, parseData()); + + return json; +} diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 38dd0872..4241031b 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -83,6 +83,70 @@ struct SExecRequestedRule { uint64_t iPid = 0; }; +enum eConfigOptionType : uint16_t { + CONFIG_OPTION_BOOL = 0, + CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/ + CONFIG_OPTION_FLOAT = 2, + CONFIG_OPTION_STRING_SHORT = 3, /* e.g. "auto" */ + CONFIG_OPTION_STRING_LONG = 4, /* e.g. a command */ + CONFIG_OPTION_COLOR = 5, + CONFIG_OPTION_CHOICE = 6, /* e.g. "one", "two", "three" */ + CONFIG_OPTION_GRADIENT = 7, + CONFIG_OPTION_VECTOR = 8, +}; + +enum eConfigOptionFlags : uint32_t { + CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0), +}; + +struct SConfigOptionDescription { + + struct SBoolData { + bool value = false; + }; + + struct SRangeData { + int value = 0, min = 0, max = 2; + }; + + struct SFloatData { + float value = 0, min = 0, max = 100; + }; + + struct SStringData { + std::string value; + }; + + struct SColorData { + CColor color; + }; + + struct SChoiceData { + int firstIndex = 0; + std::string choices; // comma-separated + }; + + struct SGradientData { + std::string gradient; + }; + + struct SVectorData { + Vector2D vec, min, max; + }; + + std::string value; // e.g. general:gaps_in + std::string description; + std::string specialCategory; // if value is special (e.g. device:abc) value will be abc and special device + bool specialKey = false; + eConfigOptionType type = CONFIG_OPTION_BOOL; + uint32_t flags = 0; // eConfigOptionFlags + + std::string jsonify() const; + + // + std::variant data; +}; + class CConfigManager { public: CConfigManager(); @@ -115,6 +179,8 @@ class CConfigManager { std::vector getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false); std::vector getMatchingRules(PHLLS); + const std::vector& getAllDescriptions(); + std::unordered_map m_mAdditionalReservedAreas; std::unordered_map getAnimationConfig(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 3ab0fa7a..717fb5c0 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1561,6 +1561,21 @@ std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) { return lockedStr; } +std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) { + std::string json = "{"; + const auto& DESCS = g_pConfigManager->getAllDescriptions(); + + for (const auto& d : DESCS) { + json += d.jsonify() + ",\n"; + } + + json.pop_back(); + json.pop_back(); + + json += "}\n"; + return json; +} + CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); @@ -1581,6 +1596,7 @@ CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest}); registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); + registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); diff --git a/src/helpers/Color.cpp b/src/helpers/Color.cpp index 67526dc7..f9a207bb 100644 --- a/src/helpers/Color.cpp +++ b/src/helpers/Color.cpp @@ -21,6 +21,6 @@ CColor::CColor(uint64_t hex) { this->a = ALPHA(hex); } -uint32_t CColor::getAsHex() { +uint32_t CColor::getAsHex() const { return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1; } \ No newline at end of file diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp index 7ec55b0d..8abfe748 100644 --- a/src/helpers/Color.hpp +++ b/src/helpers/Color.hpp @@ -10,7 +10,7 @@ class CColor { float r = 0, g = 0, b = 0, a = 1.f; - uint32_t getAsHex(); + uint32_t getAsHex() const; CColor operator-(const CColor& c2) const { return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index c502cb0d..069cdddb 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -82,18 +82,13 @@ CInputManager::~CInputManager() { } void CInputManager::onMouseMoved(IPointer::SMotionEvent e) { - static auto PSENS = CConfigValue("general:sensitivity"); - static auto PNOACCEL = CConfigValue("input:force_no_accel"); - static auto PSENSTORAW = CConfigValue("general:apply_sens_to_raw"); + static auto PNOACCEL = CConfigValue("input:force_no_accel"); const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta; - if (*PSENSTORAW == 1) - PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA * *PSENS, e.unaccel * *PSENS); - else - PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); - g_pPointerManager->move(DELTA * *PSENS); + g_pPointerManager->move(DELTA); mouseMoveUnified(e.timeMs); From 912e7ba82defdb10efc892a5db578598c972fe4a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 17 Aug 2024 19:27:11 +0200 Subject: [PATCH 048/298] render: fixup format mismatch after leaving DS fixes #7373 --- src/debug/HyprCtl.cpp | 20 ++++++++++---------- src/helpers/Monitor.cpp | 2 +- src/helpers/Monitor.hpp | 1 + src/render/Renderer.cpp | 4 ++++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 717fb5c0..78c8504a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -158,16 +158,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (!m->output || m->ID == -1) continue; - result += - std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" - "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", - m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, - m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), - m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, - (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), - m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + result += std::format( + "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" + "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" + "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n", + m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, + m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), + m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, + (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), + (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled, + formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); } } diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index f6b61d57..9542d2c4 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -946,7 +946,7 @@ bool CMonitorState::updateSwapchain() { Debug::log(WARN, "updateSwapchain: No mode?"); return true; } - options.format = STATE.drmFormat; + options.format = m_pOwner->drmFormat; options.scanout = true; options.length = 2; options.size = MODE->pixelSize; diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 7429ecf1..dcfcb63b 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -100,6 +100,7 @@ class CMonitor { std::optional forceSize; SP currentMode; SP cursorSwapchain; + uint32_t drmFormat = DRM_FORMAT_INVALID; bool dpmsStatus = true; bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6bf6a761..b363c287 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1207,6 +1207,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } else if (!pMonitor->lastScanout.expired()) { Debug::log(LOG, "Left a direct scanout."); pMonitor->lastScanout.reset(); + + // reset DRM format, make sure it's the one we want. + pMonitor->output->state->setFormat(pMonitor->drmFormat); } } @@ -2155,6 +2158,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR for (auto& fmt : formats[(int)!RULE->enable10bit]) { pMonitor->output->state->setFormat(fmt.second); + pMonitor->drmFormat = fmt.second; if (!pMonitor->state.test()) { Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); From d21a6b12b8983bba8745a62fd595a1dbee882012 Mon Sep 17 00:00:00 2001 From: leiserfg Date: Sun, 18 Aug 2024 08:43:30 +0200 Subject: [PATCH 049/298] Update aquamarine input in flake --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index b4868793..c70d31d1 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1723405438, - "narHash": "sha256-bpmC2m7OhlDvqgQZdZ2jBLyeIkq/Jld3X4bqRAxBSp8=", + "lastModified": 1723920171, + "narHash": "sha256-dVCMrAe+D/5S91erhwQj2DSzHOVzAanWqoy+vPWB9DY=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "9312aa28271c91e5d67ecb9def527b2bbcff0e66", + "rev": "71d49670fe246cdaff4860b0effba0ab9f163b72", "type": "github" }, "original": { From b2a18aa80a29ecf400ae1e8c964d4313f7223bf5 Mon Sep 17 00:00:00 2001 From: Sami Liedes Date: Sun, 18 Aug 2024 10:14:42 +0300 Subject: [PATCH 050/298] input: Fix disabling tap-to-click (#7304) * Allow disabling tap-to-click * Style fix --- src/managers/input/InputManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 069cdddb..e5f921a2 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1107,8 +1107,9 @@ void CInputManager::setPointerConfigs() { libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop) - if (g_pConfigManager->getDeviceInt(devname, "tap-to-click", "input:touchpad:tap-to-click") == 1) - libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED); + libinput_device_config_tap_set_enabled(LIBINPUTDEV, + g_pConfigManager->getDeviceInt(devname, "tap-to-click", "input:touchpad:tap-to-click") == 1 ? LIBINPUT_CONFIG_TAP_ENABLED : + LIBINPUT_CONFIG_TAP_DISABLED); if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) { From 1006663b6eaa55149e9a21aa8a34e41c85eb08ca Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 18 Aug 2024 10:23:27 +0200 Subject: [PATCH 051/298] shm: align size to stride (#7383) calculate the size to the stride we got to better align it. --- src/protocols/core/Shm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 99459d9a..9996a607 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -63,7 +63,7 @@ Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { } std::tuple CWLSHMBuffer::beginDataPtr(uint32_t flags) { - return {(uint8_t*)pool->data + offset, fmt, size.x * size.y * 4}; + return {(uint8_t*)pool->data + offset, fmt, stride * size.y}; } void CWLSHMBuffer::endDataPtr() { From 279ec1c291021479b050c83a0435ac7076c1aee0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 19:51:54 +0200 Subject: [PATCH 052/298] linux-dmabuf: allow on split-node systems ref #7364 --- src/protocols/LinuxDMABUF.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 3cdb5b34..32625792 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -490,9 +490,8 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const return; } } else { - LOGM(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); + LOGM(ERR, "DRM device {} has no render node, disabling linux dmabuf checks", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); drmFreeDevice(&device); - removeGlobal(); } }); } From 50348a3ddbb6bc3367300c9bba2ff682e4a356e3 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 20:19:13 +0200 Subject: [PATCH 053/298] renderer: pass custom modelines to aq ref #7390 --- src/render/Renderer.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b363c287..c2ecbbf3 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1994,17 +1994,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (pMonitor->output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) { Debug::log(ERR, "Tried to set custom modeline on non-DRM output"); fail = true; - } else { - // FIXME: - // auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); - // if (mode) { - // wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - // pMonitor->customDrmMode = RULE->drmMode; - // } else { - // Debug::log(ERR, "wlr_drm_connector_add_mode failed"); - // fail = true; - // } - } + } else + pMonitor->output->state->setCustomMode(makeShared( + Aquamarine::SOutputMode{.pixelSize = {RULE->drmMode.hdisplay, RULE->drmMode.vdisplay}, .refreshRate = RULE->drmMode.vrefresh, .modeInfo = RULE->drmMode})); } else pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); From 5afc4dc42e2409da62b7bcdf0ead90329e8d7a92 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 18 Aug 2024 21:02:46 +0200 Subject: [PATCH 054/298] compositor: update suspendstate on window move (#7396) hyprctl dispatch -- movetoworkspacesilent x,"^kitty$" where X is the current workspace makes kitty stops updating until current workspace is changed while it is on the screen. update the suspend state after it has been moved. --- src/Compositor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9d247a56..1437a653 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2737,6 +2737,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID); g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID()); + g_pCompositor->updateSuspendedStates(); } PHLWINDOW CCompositor::getForceFocus() { From bf611fbbf3183e6f96529d79189be56189a46e1b Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 22:40:21 +0200 Subject: [PATCH 055/298] screencopy: nuke unused stuff --- src/protocols/Screencopy.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index f246f6dd..8a7fd567 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -38,17 +38,6 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t g_pHyprRenderer->makeEGLCurrent(); - if (g_pHyprOpenGL->m_mMonitorRenderResources.contains(pMonitor)) { - const auto& RDATA = g_pHyprOpenGL->m_mMonitorRenderResources.at(pMonitor); - // bind the fb for its format. Suppress gl errors. -#ifndef GLES2 - glBindFramebuffer(GL_READ_FRAMEBUFFER, RDATA.offloadFB.m_iFb); -#else - glBindFramebuffer(GL_FRAMEBUFFER, RDATA.offloadFB.m_iFb); -#endif - } else - LOGM(ERR, "No RDATA in screencopy???"); - shmFormat = g_pHyprOpenGL->getPreferredReadFormat(pMonitor); if (shmFormat == DRM_FORMAT_INVALID) { LOGM(ERR, "No format supported by renderer in capture output"); From fa12efdd2aae6851305245f16a801fb571fbe2c1 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 22:54:47 +0200 Subject: [PATCH 056/298] protocol: fix logm template checks --- src/protocols/WaylandProtocol.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index 0fa8daab..87c75ed8 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -32,7 +32,7 @@ } else if (level == LOG || level == INFO || level == TRACE) { \ oss << "[" << EXTRACT_CLASS_NAME() << "] "; \ } \ - if constexpr (std::is_same_v) { \ + if constexpr (std::tuple_size::value == 1 && std::is_same_v) { \ oss << __VA_ARGS__; \ Debug::log(level, oss.str()); \ } else { \ From f4045ab8d032186b7c5409cd9f05eeaa813320ba Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 22:57:21 +0200 Subject: [PATCH 057/298] screencopy: fix 10b format r/b flip --- src/protocols/Screencopy.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 8a7fd567..b25d9456 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -46,6 +46,10 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t return; } + // TODO: hack, we can't bit flip so we'll format flip heh, GL_BGRA_EXT wont work here + if (shmFormat == DRM_FORMAT_XRGB2101010 || shmFormat == DRM_FORMAT_ARGB2101010) + shmFormat = DRM_FORMAT_XBGR2101010; + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(shmFormat); if (!PSHMINFO) { LOGM(ERR, "No pixel format supported by renderer in capture output"); From 11dfb8397becca85cad078dd31bf043d1c40ceac Mon Sep 17 00:00:00 2001 From: diniamo Date: Sun, 18 Aug 2024 20:43:04 +0200 Subject: [PATCH 058/298] flake: update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index c70d31d1..97016819 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1723920171, - "narHash": "sha256-dVCMrAe+D/5S91erhwQj2DSzHOVzAanWqoy+vPWB9DY=", + "lastModified": 1724006173, + "narHash": "sha256-1ROh0buuxiMyc6eIb3CIbJsmYO7PhLqSYs55mOx1XTk=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "71d49670fe246cdaff4860b0effba0ab9f163b72", + "rev": "7f8df01d4297b9068a9592400f16044602844f86", "type": "github" }, "original": { From 83d88fa56467a2b749fb2320e1595281107bd326 Mon Sep 17 00:00:00 2001 From: loseardes77 Date: Sun, 18 Aug 2024 22:25:23 +0200 Subject: [PATCH 059/298] hyprpm, hyprctl: update shell completions --- hyprctl/hyprctl.bash | 89 ++++++------ hyprctl/hyprctl.fish | 305 ++++++++++++++++++++++-------------------- hyprctl/hyprctl.usage | 20 ++- hyprctl/hyprctl.zsh | 271 ++++++++++++++++++++----------------- hyprpm/hyprpm.bash | 58 ++++---- hyprpm/hyprpm.fish | 85 ++++++------ hyprpm/hyprpm.usage | 4 +- hyprpm/hyprpm.zsh | 46 ++++--- 8 files changed, 471 insertions(+), 407 deletions(-) diff --git a/hyprctl/hyprctl.bash b/hyprctl/hyprctl.bash index c69cca21..e26e623e 100644 --- a/hyprctl/hyprctl.bash +++ b/hyprctl/hyprctl.bash @@ -1,17 +1,17 @@ -_hyprctl_cmd_2 () { +_hyprctl_cmd_1 () { hyprctl monitors | awk '/Monitor/{ print $2 }' } _hyprctl_cmd_3 () { - hyprpm list | awk '/Plugin/{ print $4 }' + hyprctl clients | awk '/class/{print $2}' +} + +_hyprctl_cmd_2 () { + hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' } _hyprctl_cmd_0 () { - hyprctl clients | awk '/class/{ print $2 }' -} - -_hyprctl_cmd_1 () { - hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' + hyprpm list | awk '/Plugin/{print $4}' } _hyprctl () { @@ -23,25 +23,25 @@ _hyprctl () { local words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") - + declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize) declare -A literal_transitions - literal_transitions[0]="([105]=1 [75]=2 [33]=3 [35]=4 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [111]=4 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [88]=4 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [98]=4 [99]=2 [27]=2 [28]=14 [102]=2 [104]=4)" - literal_transitions[3]="([73]=17 [13]=2 [32]=17 [55]=17 [56]=17 [91]=17 [106]=2 [123]=2 [77]=1 [16]=2 [126]=17 [3]=1 [5]=2 [64]=17 [131]=2 [133]=17 [81]=17 [134]=17 [84]=17 [31]=17 [49]=2 [12]=2 [86]=17 [10]=17 [87]=17 [141]=17)" - literal_transitions[7]="([105]=1 [75]=2 [33]=3 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [99]=2 [27]=2 [28]=14 [102]=2)" - literal_transitions[8]="([101]=2 [130]=2 [132]=2 [0]=2 [74]=2 [36]=2 [108]=2 [109]=2 [38]=2 [110]=2 [4]=2 [79]=2 [40]=2 [80]=2 [113]=2 [6]=2 [42]=2 [43]=2 [82]=2 [83]=2 [47]=2 [48]=2 [9]=2 [50]=2 [51]=2 [53]=2 [11]=2 [112]=2 [89]=2 [118]=2 [57]=2 [92]=2 [58]=2 [93]=2 [94]=2 [61]=2 [62]=2 [128]=2 [95]=2 [63]=2 [20]=2 [97]=2 [22]=2 [23]=2 [65]=2 [66]=2 [135]=2 [136]=2 [24]=2 [26]=2 [69]=2 [100]=2 [70]=2 [140]=2 [29]=2 [71]=2)" - literal_transitions[9]="([117]=20 [114]=16)" - literal_transitions[11]="([103]=2)" - literal_transitions[13]="([21]=1 [119]=1 [30]=1 [139]=1 [121]=1 [44]=1 [72]=1)" - literal_transitions[14]="([39]=2)" - literal_transitions[15]="([138]=2 [96]=2)" - literal_transitions[17]="([18]=2 [7]=2)" - literal_transitions[18]="([76]=19)" - literal_transitions[19]="([34]=4 [45]=4)" - literal_transitions[20]="([8]=2 [67]=2 [14]=2 [137]=2)" - - declare -A match_anything_transitions - match_anything_transitions=([1]=2 [0]=7 [6]=2 [15]=2 [10]=2 [5]=15 [14]=18 [7]=7 [2]=18 [16]=2 [12]=2 [11]=18) + literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)" + literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)" + literal_transitions[3]="([139]=2 [63]=16 [64]=16 [45]=16 [105]=16 [27]=2 [26]=2 [52]=4 [5]=16 [66]=2 [67]=16 [129]=16 [113]=16 [12]=2 [74]=4 [99]=2 [35]=16 [152]=16 [98]=16 [59]=16 [117]=16 [41]=16 [17]=2 [138]=16 [154]=2 [122]=16)" + literal_transitions[6]="([126]=2)" + literal_transitions[10]="([56]=2)" + literal_transitions[11]="([9]=2)" + literal_transitions[12]="([14]=19 [80]=22)" + literal_transitions[13]="([142]=2)" + literal_transitions[14]="([0]=2 [84]=2 [2]=2 [85]=2 [4]=2 [87]=2 [88]=2 [90]=2 [91]=2 [92]=2 [93]=2 [94]=2 [96]=2 [15]=2 [18]=2 [103]=2 [21]=2 [104]=2 [23]=2 [24]=2 [28]=2 [29]=2 [30]=2 [108]=2 [111]=2 [32]=2 [112]=2 [36]=2 [38]=2 [119]=2 [124]=2 [46]=2 [47]=2 [48]=2 [49]=2 [53]=2 [55]=2 [131]=2 [132]=2 [134]=2 [135]=2 [60]=2 [136]=20 [141]=2 [65]=2 [144]=2 [145]=2 [68]=2 [147]=2 [70]=2 [71]=2 [72]=2 [73]=2 [148]=2 [75]=2 [76]=2 [150]=2 [153]=2)" + literal_transitions[15]="([86]=4 [6]=4 [109]=4 [61]=4 [77]=4 [54]=4 [62]=4)" + literal_transitions[16]="([40]=2 [44]=2)" + literal_transitions[17]="([7]=23)" + literal_transitions[18]="([31]=2 [149]=2)" + literal_transitions[19]="([95]=2 [16]=2 [115]=2 [20]=2)" + literal_transitions[20]="([106]=2 [82]=2 [127]=2 [1]=2 [83]=2)" + literal_transitions[23]="([57]=21 [110]=21)" + declare -A match_anything_transitions=([6]=17 [7]=2 [0]=1 [22]=2 [5]=18 [4]=2 [2]=17 [18]=2 [11]=17 [8]=2 [9]=2 [13]=17 [10]=17 [1]=1) declare -A subword_transitions local state=0 @@ -79,21 +79,9 @@ _hyprctl () { done + local -a matches=() + local prefix="${words[$cword]}" - - local shortest_suffix="$word" - for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do - local char="${COMP_WORDBREAKS:$i:1}" - local candidate="${word##*$char}" - if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then - shortest_suffix=$candidate - fi - done - local superfluous_prefix="" - if [[ "$shortest_suffix" != "$word" ]]; then - local superfluous_prefix=${word%$shortest_suffix} - fi - if [[ -v "literal_transitions[$state]" ]]; then local state_transitions_initializer=${literal_transitions[$state]} declare -A state_transitions @@ -102,25 +90,38 @@ _hyprctl () { for literal_id in "${!state_transitions[@]}"; do local literal="${literals[$literal_id]}" if [[ $literal = "${prefix}"* ]]; then - local completion=${literal#"$superfluous_prefix"} - COMPREPLY+=("$completion ") + matches+=("$literal ") fi done fi declare -A commands - commands=([5]=1 [16]=2 [12]=3 [10]=0) + commands=([7]=0 [22]=1 [8]=3 [5]=2) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} local completions=() - mapfile -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1) + readarray -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1) for item in "${completions[@]}"; do if [[ $item = "${prefix}"* ]]; then - COMPREPLY+=("$item") + matches+=("$item") fi done fi + local shortest_suffix="$prefix" + for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do + local char="${COMP_WORDBREAKS:$i:1}" + local candidate=${prefix##*$char} + if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then + shortest_suffix=$candidate + fi + done + local superfluous_prefix="" + if [[ "$shortest_suffix" != "$prefix" ]]; then + local superfluous_prefix=${prefix%$shortest_suffix} + fi + COMPREPLY=("${matches[@]#$superfluous_prefix}") + return 0 } diff --git a/hyprctl/hyprctl.fish b/hyprctl/hyprctl.fish index c5c03e49..11309416 100644 --- a/hyprctl/hyprctl.fish +++ b/hyprctl/hyprctl.fish @@ -1,21 +1,21 @@ -function _hyprctl_3 +function _hyprctl_2 set 1 $argv[1] hyprctl monitors | awk '/Monitor/{ print $2 }' end function _hyprctl_4 set 1 $argv[1] - hyprpm list | awk '/Plugin/{ print $4 }' + hyprctl clients | awk '/class/{print $2}' +end + +function _hyprctl_3 + set 1 $argv[1] + hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' end function _hyprctl_1 set 1 $argv[1] - hyprctl clients | awk '/class/{ print $2 }' -end - -function _hyprctl_2 - set 1 $argv[1] - hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' + hyprpm list | awk '/Plugin/{print $4}' end function _hyprctl @@ -29,145 +29,160 @@ function _hyprctl set COMP_CWORD (count $COMP_WORDS) end - set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" + set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" - set --local descriptions - set descriptions[1] "Focus the next window on a workspace" - set descriptions[3] "Get the current cursor pos in global layout coordinates" - set descriptions[5] "Rename a workspace" - set descriptions[7] "Focus the first window matching" - set descriptions[10] "Swap the focused window with the next window" - set descriptions[12] "Move the active window" - set descriptions[16] "List the layers" - set descriptions[18] "List active outputs with their properties" - set descriptions[20] "Get into a kill mode, where you can kill an app by clicking on it" - set descriptions[21] "Set the current window's floating state to false" - set descriptions[22] "ERROR" - set descriptions[23] "Focus a monitor" - set descriptions[24] "Swap the active window with another window" - set descriptions[25] "Move the active window out of a group" - set descriptions[26] "Send a notification using the built-in Hyprland notification system" - set descriptions[27] "Move the cursor to a specified position" - set descriptions[28] "Set the cursor theme and reloads the cursor manager" - set descriptions[29] "Set the hyprctl error string" - set descriptions[30] "Move the active workspace to a monitor" - set descriptions[31] "CONFUSED" - set descriptions[34] "Set a property of a window" - set descriptions[35] "Specify the Hyprland instance" - set descriptions[36] "Disable output" - set descriptions[37] "Toggle the current window's floating state" - set descriptions[38] "Get the list of defined workspace rules" - set descriptions[39] "Move the focused window to a workspace" - set descriptions[41] "Temporarily enable or disable binds:ignore_group_lock" - set descriptions[42] "List all workspaces with their properties" - set descriptions[43] "Swap the active window with the next or previous in a group" - set descriptions[44] "Close a specified window" - set descriptions[45] "WARNING" - set descriptions[46] "Specify the Hyprland instance" - set descriptions[47] "List all registered binds" - set descriptions[48] "Move the active window in a direction or to a monitor" - set descriptions[49] "Change the split ratio" - set descriptions[51] "Prohibit the active window from becoming or being inserted into group" - set descriptions[52] "Change the workspace" - set descriptions[53] "List all current config parsing errors" - set descriptions[54] "Toggle the current active window into a group" - set descriptions[55] "Get the config option status (values)" - set descriptions[58] "Close the active window" - set descriptions[59] "Pass the key to a specified window" - set descriptions[60] "List all decorations and their info" - set descriptions[61] "List all connected keyboards and mice" - set descriptions[62] "Switch focus from current to previously focused window" - set descriptions[63] "Change the current mapping group" - set descriptions[64] "Execute a Global Shortcut using the GlobalShortcuts portal" - set descriptions[66] "Force the renderer to reload all resources and outputs" - set descriptions[67] "Move a selected window" - set descriptions[69] "Print the Hyprland version: flags, commit and branch of build" - set descriptions[70] "Set all monitors' DPMS status" - set descriptions[71] "Resize the active window" - set descriptions[72] "Move the active window into a group" - set descriptions[73] "OK" - set descriptions[75] "Set the current window's floating state to true" - set descriptions[76] "Print tail of the log" - set descriptions[79] "List all layouts available (including plugin ones)" - set descriptions[80] "Move a workspace to a monitor" - set descriptions[81] "Execute a shell command" - set descriptions[83] "Modify the window stack order of the active or specified window" - set descriptions[84] "Toggle the focused window's internal fullscreen state" - set descriptions[86] "Issue a keyword to call a config keyword dynamically" - set descriptions[89] "Disable output" - set descriptions[90] "Pin a window" - set descriptions[91] "Allows adding/removing fake outputs to a specific backend" - set descriptions[93] "Toggle a special workspace on/off" - set descriptions[94] "Toggle the focused window's fullscreen state" - set descriptions[95] "Toggle the current window to always be opaque" - set descriptions[96] "Focus the requested workspace" - set descriptions[98] "Switch to the next window in a group" - set descriptions[99] "Output in JSON format" - set descriptions[100] "List all running Hyprland instances and their info" - set descriptions[101] "Execute a raw shell command" - set descriptions[102] "Exit the compositor with no questions asked" - set descriptions[103] "List all windows with their properties" - set descriptions[105] "Execute a batch of commands separated by ;" - set descriptions[106] "Dismiss all or up to amount of notifications" - set descriptions[108] "Set the xkb layout index for a keyboard" - set descriptions[109] "Move window doesnt switch to the workspace" - set descriptions[110] "Apply a tag to the window" - set descriptions[111] "Behave as moveintogroup" - set descriptions[112] "Refresh state after issuing the command" - set descriptions[113] "Move the focus in a direction" - set descriptions[114] "Focus the urgent window or the last window" - set descriptions[116] "Get the active workspace name and its properties" - set descriptions[117] "Issue a dispatch to call a keybind dispatcher with an arg" - set descriptions[119] "Center the active window" - set descriptions[120] "HINT" - set descriptions[121] "Interact with hyprpaper if present" - set descriptions[122] "No Icon" - set descriptions[123] "Force reload the config" - set descriptions[125] "Print system info" - set descriptions[126] "Interact with a plugin" - set descriptions[128] "Get the active window name and its properties" - set descriptions[129] "Swap the active workspaces between two monitors" - set descriptions[130] "Print the current random splash" - set descriptions[131] "On shortcut X sends shortcut Y to a specified window" - set descriptions[133] "Lock the focused group" - set descriptions[136] "Lock the groups" - set descriptions[137] "Move the cursor to the corner of the active window" - set descriptions[140] "INFO" - set descriptions[141] "Resize a selected window" + set descriptions + set descriptions[1] "Resize the active window" + set descriptions[2] "Fullscreen" + set descriptions[3] "Switch to the next window in a group" + set descriptions[4] "Refresh state after issuing the command" + set descriptions[5] "Move the active window into a group" + set descriptions[7] "CONFUSED" + set descriptions[9] "Print system info" + set descriptions[11] "List all layouts available (including plugin ones)" + set descriptions[12] "Set a property of a window" + set descriptions[14] "Set the xkb layout index for a keyboard" + set descriptions[16] "Prohibit the active window from becoming or being inserted into group" + set descriptions[19] "Execute a shell command" + set descriptions[20] "Set the cursor theme and reloads the cursor manager" + set descriptions[22] "Focus the urgent window or the last window" + set descriptions[23] "Get the list of defined workspace rules" + set descriptions[24] "Move the active workspace to a monitor" + set descriptions[25] "Move window doesnt switch to the workspace" + set descriptions[26] "Interact with hyprpaper if present" + set descriptions[29] "Swap the active window with the next or previous in a group" + set descriptions[30] "Move the cursor to the corner of the active window" + set descriptions[31] "Move a selected window" + set descriptions[33] "Move the active window in a direction or to a monitor" + set descriptions[34] "Lists all global shortcuts" + set descriptions[35] "List all windows with their properties" + set descriptions[37] "Temporarily enable or disable binds:ignore_group_lock" + set descriptions[38] "Print the current random splash" + set descriptions[39] "Execute a raw shell command" + set descriptions[40] "List active outputs with their properties" + set descriptions[43] "Disable output" + set descriptions[44] "Gets the current config info about animations and beziers" + set descriptions[47] "Change the split ratio" + set descriptions[48] "Move the active window" + set descriptions[49] "Pass the key to a specified window" + set descriptions[50] "Swap the focused window with the next window" + set descriptions[51] "List all connected keyboards and mice" + set descriptions[52] "List the layers" + set descriptions[54] "Lock the focused group" + set descriptions[55] "OK" + set descriptions[56] "Move a workspace to a monitor" + set descriptions[58] "Specify the Hyprland instance" + set descriptions[59] "Disable output" + set descriptions[61] "Pin a window" + set descriptions[62] "WARNING" + set descriptions[63] "INFO" + set descriptions[66] "Set the current window's floating state to true" + set descriptions[69] "On shortcut X sends shortcut Y to a specified window" + set descriptions[70] "List all workspaces with their properties" + set descriptions[71] "Focus the next window on a workspace" + set descriptions[72] "Modify the window stack order of the active or specified window" + set descriptions[73] "Toggle the current active window into a group" + set descriptions[74] "Lock the groups" + set descriptions[76] "Set all monitors' DPMS status" + set descriptions[77] "Switch focus from current to previously focused window" + set descriptions[78] "No Icon" + set descriptions[79] "Execute a batch of commands separated by ;" + set descriptions[80] "Send a notification using the built-in Hyprland notification system" + set descriptions[82] "List all running Hyprland instances and their info" + set descriptions[83] "Maximize no fullscreen" + set descriptions[84] "Maximize and fullscreen" + set descriptions[85] "Move the active window out of a group" + set descriptions[86] "Close the active window" + set descriptions[87] "HINT" + set descriptions[88] "Move the focused window to a workspace" + set descriptions[89] "Move the cursor to a specified position" + set descriptions[90] "List all current config parsing errors" + set descriptions[91] "Close a specified window" + set descriptions[92] "Swap the active window with another window" + set descriptions[93] "Apply a tag to the window" + set descriptions[94] "Force the renderer to reload all resources and outputs" + set descriptions[95] "Center the active window" + set descriptions[97] "Focus the first window matching" + set descriptions[98] "Set the hyprctl error string" + set descriptions[101] "List all registered binds" + set descriptions[102] "Print the Hyprland version: flags, commit and branch of build" + set descriptions[103] "Prints the help message" + set descriptions[104] "Toggle a special workspace on/off" + set descriptions[105] "Toggle the focused window's fullscreen state" + set descriptions[107] "None" + set descriptions[108] "Issue a keyword to call a config keyword dynamically" + set descriptions[109] "Toggle the current window to always be opaque" + set descriptions[110] "ERROR" + set descriptions[111] "Specify the Hyprland instance" + set descriptions[112] "Toggle the current window's floating state" + set descriptions[113] "Rename a workspace" + set descriptions[115] "Get the active workspace name and its properties" + set descriptions[117] "Get into a kill mode, where you can kill an app by clicking on it" + set descriptions[119] "Allows adding/removing fake outputs to a specific backend" + set descriptions[120] "Execute a Global Shortcut using the GlobalShortcuts portal" + set descriptions[121] "Issue a dispatch to call a keybind dispatcher with an arg" + set descriptions[122] "Force reload the config" + set descriptions[124] "Output in JSON format" + set descriptions[125] "Emits a custom event to socket2" + set descriptions[126] "Prints the help message" + set descriptions[128] "Current" + set descriptions[129] "Get the active window name and its properties" + set descriptions[131] "Dismiss all or up to amount of notifications" + set descriptions[132] "Focus a monitor" + set descriptions[133] "Move the focus in a direction" + set descriptions[134] "Interact with a plugin" + set descriptions[135] "Exit the compositor with no questions asked" + set descriptions[136] "Change the workspace" + set descriptions[137] "Sets the focused window’s fullscreen mode and the one sent to the client" + set descriptions[138] "Get the config option status (values)" + set descriptions[141] "List all decorations and their info" + set descriptions[142] "Set the current window's floating state to false" + set descriptions[144] "Return a parsable JSON with all the config options, descriptions, value types and ranges" + set descriptions[145] "Resize a selected window" + set descriptions[146] "Toggle the focused window's internal fullscreen state" + set descriptions[147] "Print tail of the log" + set descriptions[148] "Swap the active workspaces between two monitors" + set descriptions[149] "Change the current mapping group" + set descriptions[151] "Behave as moveintogroup" + set descriptions[152] "Get the current cursor pos in global layout coordinates" + set descriptions[154] "Focus the requested workspace" - set --local literal_transitions - set literal_transitions[1] "set inputs 106 76 34 36 2 3 79 108 38 112 42 47 116 86 117 53 89 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 99 100 28 29 103 105; set tos 2 3 4 5 3 3 3 6 3 5 3 3 3 7 9 3 5 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 5 3 3 15 3 5" - set literal_transitions[4] "set inputs 74 14 33 56 57 92 107 124 78 17 127 4 6 65 132 134 82 135 85 32 50 13 87 11 88 142; set tos 18 3 18 18 18 18 3 3 2 3 18 2 3 18 3 18 18 18 18 18 3 3 18 18 18 18" - set literal_transitions[8] "set inputs 106 76 34 2 3 79 108 38 42 47 116 86 117 53 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 100 28 29 103; set tos 2 3 4 3 3 3 6 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3" - set literal_transitions[9] "set inputs 102 131 133 1 75 37 109 110 39 111 5 80 41 81 114 7 43 44 83 84 48 49 10 51 52 54 12 113 90 119 58 93 59 94 95 62 63 129 96 64 21 98 23 24 66 67 136 137 25 27 70 101 71 141 30 72; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" - set literal_transitions[10] "set inputs 118 115; set tos 21 17" - set literal_transitions[12] "set inputs 104; set tos 3" - set literal_transitions[14] "set inputs 22 120 31 140 122 45 73; set tos 2 2 2 2 2 2 2" - set literal_transitions[15] "set inputs 40; set tos 3" - set literal_transitions[16] "set inputs 139 97; set tos 3 3" - set literal_transitions[18] "set inputs 19 8; set tos 3 3" - set literal_transitions[19] "set inputs 77; set tos 20" - set literal_transitions[20] "set inputs 35 46; set tos 5 5" - set literal_transitions[21] "set inputs 9 68 15 138; set tos 3 3 3 3" + set literal_transitions + set literal_transitions[1] "set inputs 121 44 126 82 4 52 51 129 90 59 9 11 12 131 14 98 102 103 134 101 138 23 20 141 26 144 108 147 70 34 35 79 115 38 152 117 122 124 40 43 80 119; set tos 15 3 22 3 22 3 3 3 3 22 3 3 4 5 6 7 3 22 8 3 3 3 3 9 3 3 10 11 3 3 3 22 3 3 3 3 14 22 12 22 16 13" + set literal_transitions[2] "set inputs 82 52 51 129 9 90 11 12 131 14 98 102 134 101 23 20 138 141 26 144 108 147 70 34 35 115 38 152 117 40 119 122 121 80 44; set tos 3 3 3 3 3 3 3 4 5 6 7 3 8 3 3 3 3 9 3 3 10 11 3 3 3 3 3 3 3 12 13 14 15 16 3" + set literal_transitions[4] "set inputs 140 64 65 46 106 28 27 53 6 67 68 130 114 13 75 100 36 153 99 60 118 42 18 139 155 123; set tos 3 17 17 17 17 3 3 5 17 3 17 17 17 3 5 3 17 17 17 17 17 17 3 17 3 17" + set literal_transitions[7] "set inputs 127; set tos 3" + set literal_transitions[11] "set inputs 57; set tos 3" + set literal_transitions[12] "set inputs 10; set tos 3" + set literal_transitions[13] "set inputs 15 81; set tos 20 23" + set literal_transitions[14] "set inputs 143; set tos 3" + set literal_transitions[15] "set inputs 1 85 3 86 5 88 89 91 92 93 94 95 97 16 19 104 22 105 24 25 29 30 31 109 112 33 113 37 39 120 125 47 48 49 50 54 56 132 133 135 136 61 137 142 66 145 146 69 148 71 72 73 74 149 76 77 151 154; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 21 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" + set literal_transitions[16] "set inputs 87 7 110 62 78 55 63; set tos 5 5 5 5 5 5 5" + set literal_transitions[17] "set inputs 41 45; set tos 3 3" + set literal_transitions[18] "set inputs 8; set tos 24" + set literal_transitions[19] "set inputs 32 150; set tos 3 3" + set literal_transitions[20] "set inputs 96 17 116 21; set tos 3 3 3 3" + set literal_transitions[21] "set inputs 107 83 128 2 84; set tos 3 3 3 3 3" + set literal_transitions[24] "set inputs 58 111; set tos 22 22" - set --local match_anything_transitions_from 2 1 7 16 11 6 15 8 3 17 13 12 - set --local match_anything_transitions_to 3 8 3 3 3 16 19 8 19 3 3 19 + set match_anything_transitions_from 7 8 1 23 6 5 3 19 12 9 10 14 11 2 + set match_anything_transitions_to 18 3 2 3 19 3 18 3 18 3 3 18 18 2 - set --local state 1 - set --local word_index 2 + set state 1 + set word_index 2 while test $word_index -lt $COMP_CWORD - set --local -- word $COMP_WORDS[$word_index] + set -- word $COMP_WORDS[$word_index] if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] if contains -- $word $literals - set --local literal_matched 0 + set literal_matched 0 for literal_id in (seq 1 (count $literals)) if test $literals[$literal_id] = $word - set --local index (contains --index -- $literal_id $inputs) + set index (contains --index -- $literal_id $inputs) set state $tos[$index] set word_index (math $word_index + 1) set literal_matched 1 @@ -181,7 +196,7 @@ function _hyprctl end if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state] - set --local index (contains --index -- $state $match_anything_transitions_from) + set index (contains --index -- $state $match_anything_transitions_from) set state $match_anything_transitions_to[$index] set word_index (math $word_index + 1) continue @@ -191,8 +206,8 @@ function _hyprctl end if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] for literal_id in $inputs if test -n $descriptions[$literal_id] @@ -203,14 +218,14 @@ function _hyprctl end end - set command_states 6 17 13 11 - set command_ids 2 3 4 1 + set command_states 8 23 9 6 + set command_ids 1 2 4 3 if contains $state $command_states - set --local index (contains --index $state $command_states) - set --local function_id $command_ids[$index] - set --local function_name _hyprctl_$function_id - set --local --erase inputs - set --local --erase tos + set index (contains --index $state $command_states) + set function_id $command_ids[$index] + set function_name _hyprctl_$function_id + set --erase inputs + set --erase tos $function_name "$COMP_WORDS[$COMP_CWORD]" end diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage index 298d253e..b2c55682 100644 --- a/hyprctl/hyprctl.usage +++ b/hyprctl/hyprctl.usage @@ -2,13 +2,14 @@ # Repo: https://github.com/adaszko/complgen # Generate completion scripts: "complgen aot --bash-script hyprctl.bash --fish-script hyprctl.fish --zsh-script hyprctl.zsh ./hyprctl.usage" -hyprctl []... +hyprctl []... ::= (-i | --instance) "Specify the Hyprland instance" | (-j) "Output in JSON format" | (-r) "Refresh state after issuing the command" | (--batch) "Execute a batch of commands separated by ;" | (-q | --quiet) "Disable output" + | (-h | --help) "Prints the help message" ; ::= {{{ hyprctl clients | awk '/class/{print $2}' }}}; @@ -59,16 +60,18 @@ hyprctl []... ::= (activewindow) "Get the active window name and its properties" | (activeworkspace) "Get the active workspace name and its properties" + | (animations) "Gets the current config info about animations and beziers" | (binds) "List all registered binds" | (clients) "List all windows with their properties" | (configerrors) "List all current config parsing errors" | (cursorpos) "Get the current cursor pos in global layout coordinates" | (decorations ) "List all decorations and their info" + | (descriptions) "Return a parsable JSON with all the config options, descriptions, value types and ranges" | (devices) "List all connected keyboards and mice" | (dismissnotify ) "Dismiss all or up to amount of notifications" | (dispatch ) "Issue a dispatch to call a keybind dispatcher with an arg" | (getoption) "Get the config option status (values)" - | (globalshortcuts) "" + | (globalshortcuts) "Lists all global shortcuts" | (hyprpaper) "Interact with hyprpaper if present" | (instances) "List all running Hyprland instances and their info" | (keyword ) "Issue a keyword to call a config keyword dynamically" @@ -79,8 +82,8 @@ hyprctl []... | (notify ) "Send a notification using the built-in Hyprland notification system" | (output (create (wayland | x11 | headless | auto) | remove )) "Allows adding/removing fake outputs to a specific backend" | (plugin ) "Interact with a plugin" - | (reload) "Force reload the config" - | (rollinglog) "Print tail of the log" + | (reload [config-only]) "Force reload the config" + | (rollinglog [-f]) "Print tail of the log" | (setcursor) "Set the cursor theme and reloads the cursor manager" | (seterror [disable]) "Set the hyprctl error string" | (setprop ) "Set a property of a window" @@ -92,6 +95,13 @@ hyprctl []... | (workspaces) "List all workspaces with their properties" ; + ::= (-1) "Current" + | (0) "None" + | (1) "Maximize no fullscreen" + | (2) "Fullscreen" + | (3) "Maximize and fullscreen" + ; + ::= (exec) "Execute a shell command" | (execr) "Execute a raw shell command" | (pass) "Pass the key to a specified window" @@ -106,6 +116,7 @@ hyprctl []... | (settiled) "Set the current window's floating state to false" | (fullscreen) "Toggle the focused window's fullscreen state" | (fakefullscreen) "Toggle the focused window's internal fullscreen state" + | (fullscreenstate ) "Sets the focused window’s fullscreen mode and the one sent to the client" | (dpms) "Set all monitors' DPMS status" | (pin) "Pin a window" | (movefocus) "Move the focus in a direction" @@ -148,4 +159,5 @@ hyprctl []... | (setignoregrouplock) "Temporarily enable or disable binds:ignore_group_lock" | (global) "Execute a Global Shortcut using the GlobalShortcuts portal" | (submap) "Change the current mapping group" + | (event) "Emits a custom event to socket2" ; diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh index aeac9663..9a858100 100644 --- a/hyprctl/hyprctl.zsh +++ b/hyprctl/hyprctl.zsh @@ -1,145 +1,160 @@ #compdef hyprctl -_hyprctl_cmd_2 () { +_hyprctl_cmd_1 () { hyprctl monitors | awk '/Monitor/{ print $2 }' } _hyprctl_cmd_3 () { - hyprpm list | awk '/Plugin/{ print $4 }' + hyprctl clients | awk '/class/{print $2}' } -_hyprctl_cmd_0 () { - hyprctl clients | awk '/class/{ print $2 }' -} - -_hyprctl_cmd_1 () { +_hyprctl_cmd_2 () { hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' } +_hyprctl_cmd_0 () { + hyprpm list | awk '/Plugin/{print $4}' +} + _hyprctl () { - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") + local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize") local -A descriptions - descriptions[1]="Focus the next window on a workspace" - descriptions[3]="Get the current cursor pos in global layout coordinates" - descriptions[5]="Rename a workspace" - descriptions[7]="Focus the first window matching" - descriptions[10]="Swap the focused window with the next window" - descriptions[12]="Move the active window" - descriptions[16]="List the layers" - descriptions[18]="List active outputs with their properties" - descriptions[20]="Get into a kill mode, where you can kill an app by clicking on it" - descriptions[21]="Set the current window's floating state to false" - descriptions[22]="ERROR" - descriptions[23]="Focus a monitor" - descriptions[24]="Swap the active window with another window" - descriptions[25]="Move the active window out of a group" - descriptions[26]="Send a notification using the built-in Hyprland notification system" - descriptions[27]="Move the cursor to a specified position" - descriptions[28]="Set the cursor theme and reloads the cursor manager" - descriptions[29]="Set the hyprctl error string" - descriptions[30]="Move the active workspace to a monitor" - descriptions[31]="CONFUSED" - descriptions[34]="Set a property of a window" - descriptions[35]="Specify the Hyprland instance" - descriptions[36]="Disable output" - descriptions[37]="Toggle the current window's floating state" - descriptions[38]="Get the list of defined workspace rules" - descriptions[39]="Move the focused window to a workspace" - descriptions[41]="Temporarily enable or disable binds:ignore_group_lock" - descriptions[42]="List all workspaces with their properties" - descriptions[43]="Swap the active window with the next or previous in a group" - descriptions[44]="Close a specified window" - descriptions[45]="WARNING" - descriptions[46]="Specify the Hyprland instance" - descriptions[47]="List all registered binds" - descriptions[48]="Move the active window in a direction or to a monitor" - descriptions[49]="Change the split ratio" - descriptions[51]="Prohibit the active window from becoming or being inserted into group" - descriptions[52]="Change the workspace" - descriptions[53]="List all current config parsing errors" - descriptions[54]="Toggle the current active window into a group" - descriptions[55]="Get the config option status (values)" - descriptions[58]="Close the active window" - descriptions[59]="Pass the key to a specified window" - descriptions[60]="List all decorations and their info" - descriptions[61]="List all connected keyboards and mice" - descriptions[62]="Switch focus from current to previously focused window" - descriptions[63]="Change the current mapping group" - descriptions[64]="Execute a Global Shortcut using the GlobalShortcuts portal" - descriptions[66]="Force the renderer to reload all resources and outputs" - descriptions[67]="Move a selected window" - descriptions[69]="Print the Hyprland version: flags, commit and branch of build" - descriptions[70]="Set all monitors' DPMS status" - descriptions[71]="Resize the active window" - descriptions[72]="Move the active window into a group" - descriptions[73]="OK" - descriptions[75]="Set the current window's floating state to true" - descriptions[76]="Print tail of the log" - descriptions[79]="List all layouts available (including plugin ones)" - descriptions[80]="Move a workspace to a monitor" - descriptions[81]="Execute a shell command" - descriptions[83]="Modify the window stack order of the active or specified window" - descriptions[84]="Toggle the focused window's internal fullscreen state" - descriptions[86]="Issue a keyword to call a config keyword dynamically" - descriptions[89]="Disable output" - descriptions[90]="Pin a window" - descriptions[91]="Allows adding/removing fake outputs to a specific backend" - descriptions[93]="Toggle a special workspace on/off" - descriptions[94]="Toggle the focused window's fullscreen state" - descriptions[95]="Toggle the current window to always be opaque" - descriptions[96]="Focus the requested workspace" - descriptions[98]="Switch to the next window in a group" - descriptions[99]="Output in JSON format" - descriptions[100]="List all running Hyprland instances and their info" - descriptions[101]="Execute a raw shell command" - descriptions[102]="Exit the compositor with no questions asked" - descriptions[103]="List all windows with their properties" - descriptions[105]="Execute a batch of commands separated by ;" - descriptions[106]="Dismiss all or up to amount of notifications" - descriptions[108]="Set the xkb layout index for a keyboard" - descriptions[109]="Move window doesnt switch to the workspace" - descriptions[110]="Apply a tag to the window" - descriptions[111]="Behave as moveintogroup" - descriptions[112]="Refresh state after issuing the command" - descriptions[113]="Move the focus in a direction" - descriptions[114]="Focus the urgent window or the last window" - descriptions[116]="Get the active workspace name and its properties" - descriptions[117]="Issue a dispatch to call a keybind dispatcher with an arg" - descriptions[119]="Center the active window" - descriptions[120]="HINT" - descriptions[121]="Interact with hyprpaper if present" - descriptions[122]="No Icon" - descriptions[123]="Force reload the config" - descriptions[125]="Print system info" - descriptions[126]="Interact with a plugin" - descriptions[128]="Get the active window name and its properties" - descriptions[129]="Swap the active workspaces between two monitors" - descriptions[130]="Print the current random splash" - descriptions[131]="On shortcut X sends shortcut Y to a specified window" - descriptions[133]="Lock the focused group" - descriptions[136]="Lock the groups" - descriptions[137]="Move the cursor to the corner of the active window" - descriptions[140]="INFO" - descriptions[141]="Resize a selected window" + descriptions[1]="Resize the active window" + descriptions[2]="Fullscreen" + descriptions[3]="Switch to the next window in a group" + descriptions[4]="Refresh state after issuing the command" + descriptions[5]="Move the active window into a group" + descriptions[7]="CONFUSED" + descriptions[9]="Print system info" + descriptions[11]="List all layouts available (including plugin ones)" + descriptions[12]="Set a property of a window" + descriptions[14]="Set the xkb layout index for a keyboard" + descriptions[16]="Prohibit the active window from becoming or being inserted into group" + descriptions[19]="Execute a shell command" + descriptions[20]="Set the cursor theme and reloads the cursor manager" + descriptions[22]="Focus the urgent window or the last window" + descriptions[23]="Get the list of defined workspace rules" + descriptions[24]="Move the active workspace to a monitor" + descriptions[25]="Move window doesnt switch to the workspace" + descriptions[26]="Interact with hyprpaper if present" + descriptions[29]="Swap the active window with the next or previous in a group" + descriptions[30]="Move the cursor to the corner of the active window" + descriptions[31]="Move a selected window" + descriptions[33]="Move the active window in a direction or to a monitor" + descriptions[34]="Lists all global shortcuts" + descriptions[35]="List all windows with their properties" + descriptions[37]="Temporarily enable or disable binds:ignore_group_lock" + descriptions[38]="Print the current random splash" + descriptions[39]="Execute a raw shell command" + descriptions[40]="List active outputs with their properties" + descriptions[43]="Disable output" + descriptions[44]="Gets the current config info about animations and beziers" + descriptions[47]="Change the split ratio" + descriptions[48]="Move the active window" + descriptions[49]="Pass the key to a specified window" + descriptions[50]="Swap the focused window with the next window" + descriptions[51]="List all connected keyboards and mice" + descriptions[52]="List the layers" + descriptions[54]="Lock the focused group" + descriptions[55]="OK" + descriptions[56]="Move a workspace to a monitor" + descriptions[58]="Specify the Hyprland instance" + descriptions[59]="Disable output" + descriptions[61]="Pin a window" + descriptions[62]="WARNING" + descriptions[63]="INFO" + descriptions[66]="Set the current window's floating state to true" + descriptions[69]="On shortcut X sends shortcut Y to a specified window" + descriptions[70]="List all workspaces with their properties" + descriptions[71]="Focus the next window on a workspace" + descriptions[72]="Modify the window stack order of the active or specified window" + descriptions[73]="Toggle the current active window into a group" + descriptions[74]="Lock the groups" + descriptions[76]="Set all monitors' DPMS status" + descriptions[77]="Switch focus from current to previously focused window" + descriptions[78]="No Icon" + descriptions[79]="Execute a batch of commands separated by ;" + descriptions[80]="Send a notification using the built-in Hyprland notification system" + descriptions[82]="List all running Hyprland instances and their info" + descriptions[83]="Maximize no fullscreen" + descriptions[84]="Maximize and fullscreen" + descriptions[85]="Move the active window out of a group" + descriptions[86]="Close the active window" + descriptions[87]="HINT" + descriptions[88]="Move the focused window to a workspace" + descriptions[89]="Move the cursor to a specified position" + descriptions[90]="List all current config parsing errors" + descriptions[91]="Close a specified window" + descriptions[92]="Swap the active window with another window" + descriptions[93]="Apply a tag to the window" + descriptions[94]="Force the renderer to reload all resources and outputs" + descriptions[95]="Center the active window" + descriptions[97]="Focus the first window matching" + descriptions[98]="Set the hyprctl error string" + descriptions[101]="List all registered binds" + descriptions[102]="Print the Hyprland version: flags, commit and branch of build" + descriptions[103]="Prints the help message" + descriptions[104]="Toggle a special workspace on/off" + descriptions[105]="Toggle the focused window's fullscreen state" + descriptions[107]="None" + descriptions[108]="Issue a keyword to call a config keyword dynamically" + descriptions[109]="Toggle the current window to always be opaque" + descriptions[110]="ERROR" + descriptions[111]="Specify the Hyprland instance" + descriptions[112]="Toggle the current window's floating state" + descriptions[113]="Rename a workspace" + descriptions[115]="Get the active workspace name and its properties" + descriptions[117]="Get into a kill mode, where you can kill an app by clicking on it" + descriptions[119]="Allows adding/removing fake outputs to a specific backend" + descriptions[120]="Execute a Global Shortcut using the GlobalShortcuts portal" + descriptions[121]="Issue a dispatch to call a keybind dispatcher with an arg" + descriptions[122]="Force reload the config" + descriptions[124]="Output in JSON format" + descriptions[125]="Emits a custom event to socket2" + descriptions[126]="Prints the help message" + descriptions[128]="Current" + descriptions[129]="Get the active window name and its properties" + descriptions[131]="Dismiss all or up to amount of notifications" + descriptions[132]="Focus a monitor" + descriptions[133]="Move the focus in a direction" + descriptions[134]="Interact with a plugin" + descriptions[135]="Exit the compositor with no questions asked" + descriptions[136]="Change the workspace" + descriptions[137]="Sets the focused window’s fullscreen mode and the one sent to the client" + descriptions[138]="Get the config option status (values)" + descriptions[141]="List all decorations and their info" + descriptions[142]="Set the current window's floating state to false" + descriptions[144]="Return a parsable JSON with all the config options, descriptions, value types and ranges" + descriptions[145]="Resize a selected window" + descriptions[146]="Toggle the focused window's internal fullscreen state" + descriptions[147]="Print tail of the log" + descriptions[148]="Swap the active workspaces between two monitors" + descriptions[149]="Change the current mapping group" + descriptions[151]="Behave as moveintogroup" + descriptions[152]="Get the current cursor pos in global layout coordinates" + descriptions[154]="Focus the requested workspace" local -A literal_transitions - literal_transitions[1]="([106]=2 [76]=3 [34]=4 [36]=5 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [112]=5 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [89]=5 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [99]=5 [100]=3 [28]=3 [29]=15 [103]=3 [105]=5)" - literal_transitions[4]="([74]=18 [14]=3 [33]=18 [56]=18 [57]=18 [92]=18 [107]=3 [124]=3 [78]=2 [17]=3 [127]=18 [4]=2 [6]=3 [65]=18 [132]=3 [134]=18 [82]=18 [135]=18 [85]=18 [32]=18 [50]=3 [13]=3 [87]=18 [11]=18 [88]=18 [142]=18)" - literal_transitions[8]="([106]=2 [76]=3 [34]=4 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [100]=3 [28]=3 [29]=15 [103]=3)" - literal_transitions[9]="([102]=3 [131]=3 [133]=3 [1]=3 [75]=3 [37]=3 [109]=3 [110]=3 [39]=3 [111]=3 [5]=3 [80]=3 [41]=3 [81]=3 [114]=3 [7]=3 [43]=3 [44]=3 [83]=3 [84]=3 [48]=3 [49]=3 [10]=3 [51]=3 [52]=3 [54]=3 [12]=3 [113]=3 [90]=3 [119]=3 [58]=3 [93]=3 [59]=3 [94]=3 [95]=3 [62]=3 [63]=3 [129]=3 [96]=3 [64]=3 [21]=3 [98]=3 [23]=3 [24]=3 [66]=3 [67]=3 [136]=3 [137]=3 [25]=3 [27]=3 [70]=3 [101]=3 [71]=3 [141]=3 [30]=3 [72]=3)" - literal_transitions[10]="([118]=21 [115]=17)" - literal_transitions[12]="([104]=3)" - literal_transitions[14]="([22]=2 [120]=2 [31]=2 [140]=2 [122]=2 [45]=2 [73]=2)" - literal_transitions[15]="([40]=3)" - literal_transitions[16]="([139]=3 [97]=3)" - literal_transitions[18]="([19]=3 [8]=3)" - literal_transitions[19]="([77]=20)" - literal_transitions[20]="([35]=5 [46]=5)" - literal_transitions[21]="([9]=3 [68]=3 [15]=3 [138]=3)" + literal_transitions[1]="([121]=15 [44]=3 [126]=22 [82]=3 [4]=22 [52]=3 [51]=3 [129]=3 [90]=3 [59]=22 [9]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [103]=22 [134]=8 [101]=3 [138]=3 [23]=3 [20]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [79]=22 [115]=3 [38]=3 [152]=3 [117]=3 [122]=14 [124]=22 [40]=12 [43]=22 [80]=16 [119]=13)" + literal_transitions[2]="([82]=3 [52]=3 [51]=3 [129]=3 [9]=3 [90]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [134]=8 [101]=3 [23]=3 [20]=3 [138]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [115]=3 [38]=3 [152]=3 [117]=3 [40]=12 [119]=13 [122]=14 [121]=15 [80]=16 [44]=3)" + literal_transitions[4]="([140]=3 [64]=17 [65]=17 [46]=17 [106]=17 [28]=3 [27]=3 [53]=5 [6]=17 [67]=3 [68]=17 [130]=17 [114]=17 [13]=3 [75]=5 [100]=3 [36]=17 [153]=17 [99]=17 [60]=17 [118]=17 [42]=17 [18]=3 [139]=17 [155]=3 [123]=17)" + literal_transitions[7]="([127]=3)" + literal_transitions[11]="([57]=3)" + literal_transitions[12]="([10]=3)" + literal_transitions[13]="([15]=20 [81]=23)" + literal_transitions[14]="([143]=3)" + literal_transitions[15]="([1]=3 [85]=3 [3]=3 [86]=3 [5]=3 [88]=3 [89]=3 [91]=3 [92]=3 [93]=3 [94]=3 [95]=3 [97]=3 [16]=3 [19]=3 [104]=3 [22]=3 [105]=3 [24]=3 [25]=3 [29]=3 [30]=3 [31]=3 [109]=3 [112]=3 [33]=3 [113]=3 [37]=3 [39]=3 [120]=3 [125]=3 [47]=3 [48]=3 [49]=3 [50]=3 [54]=3 [56]=3 [132]=3 [133]=3 [135]=3 [136]=3 [61]=3 [137]=21 [142]=3 [66]=3 [145]=3 [146]=3 [69]=3 [148]=3 [71]=3 [72]=3 [73]=3 [74]=3 [149]=3 [76]=3 [77]=3 [151]=3 [154]=3)" + literal_transitions[16]="([87]=5 [7]=5 [110]=5 [62]=5 [78]=5 [55]=5 [63]=5)" + literal_transitions[17]="([41]=3 [45]=3)" + literal_transitions[18]="([8]=24)" + literal_transitions[19]="([32]=3 [150]=3)" + literal_transitions[20]="([96]=3 [17]=3 [116]=3 [21]=3)" + literal_transitions[21]="([107]=3 [83]=3 [128]=3 [2]=3 [84]=3)" + literal_transitions[24]="([58]=22 [111]=22)" local -A match_anything_transitions - match_anything_transitions=([2]=3 [1]=8 [7]=3 [16]=3 [11]=3 [6]=16 [15]=19 [8]=8 [3]=19 [17]=3 [13]=3 [12]=19) + match_anything_transitions=([7]=18 [8]=3 [1]=2 [23]=3 [6]=19 [5]=3 [3]=18 [19]=3 [12]=18 [9]=3 [10]=3 [14]=18 [11]=18 [2]=2) declare -A subword_transitions @@ -199,7 +214,7 @@ _hyprctl () { fi done fi - local -A commands=([6]=1 [17]=2 [13]=3 [11]=0) + local -A commands=([8]=0 [23]=1 [9]=3 [6]=2) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} @@ -252,4 +267,8 @@ _hyprctl () { return 0 } -compdef _hyprctl hyprctl +if [[ $ZSH_EVAL_CONTEXT =~ :file$ ]]; then + compdef _hyprctl hyprctl +else + _hyprctl +fi diff --git a/hyprpm/hyprpm.bash b/hyprpm/hyprpm.bash index ffc33e19..3c2bc90b 100644 --- a/hyprpm/hyprpm.bash +++ b/hyprpm/hyprpm.bash @@ -2,6 +2,10 @@ _hyprpm_cmd_0 () { hyprpm list | awk '/Plugin/{print $4}' } +_hyprpm_cmd_1 () { + hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' +} + _hyprpm () { if [[ $(type -t _get_comp_words_by_ref) != function ]]; then echo _get_comp_words_by_ref: function not defined. Make sure the bash-completions system package is installed @@ -11,16 +15,13 @@ _hyprpm () { local words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword - local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f") - + declare -a literals=(--no-shallow -n ::= disable list --help update add --verbose -v --force -s remove enable --notify -h reload -f) declare -A literal_transitions - literal_transitions[0]="([9]=6 [2]=2 [7]=6 [8]=6 [4]=6 [10]=2 [11]=3 [5]=2 [13]=6 [3]=3 [14]=2 [15]=6 [6]=2)" - literal_transitions[1]="([10]=2 [11]=3 [3]=3 [2]=2 [14]=2 [5]=2 [6]=2)" - literal_transitions[4]="([1]=5)" - literal_transitions[5]="([0]=6 [12]=6)" - - declare -A match_anything_transitions - match_anything_transitions=([3]=2 [2]=4 [0]=1 [1]=1) + literal_transitions[0]="([0]=7 [3]=3 [4]=4 [8]=7 [9]=7 [6]=4 [7]=4 [11]=7 [5]=7 [10]=7 [12]=2 [13]=3 [15]=7 [16]=4 [17]=7)" + literal_transitions[1]="([12]=2 [13]=3 [3]=3 [4]=4 [16]=4 [6]=4 [7]=4)" + literal_transitions[5]="([2]=6)" + literal_transitions[6]="([1]=7 [14]=7)" + declare -A match_anything_transitions=([1]=1 [4]=5 [3]=4 [2]=4 [0]=1) declare -A subword_transitions local state=0 @@ -58,21 +59,9 @@ _hyprpm () { done + local -a matches=() + local prefix="${words[$cword]}" - - local shortest_suffix="$word" - for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do - local char="${COMP_WORDBREAKS:$i:1}" - local candidate="${word##*$char}" - if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then - shortest_suffix=$candidate - fi - done - local superfluous_prefix="" - if [[ "$shortest_suffix" != "$word" ]]; then - local superfluous_prefix=${word%$shortest_suffix} - fi - if [[ -v "literal_transitions[$state]" ]]; then local state_transitions_initializer=${literal_transitions[$state]} declare -A state_transitions @@ -81,25 +70,38 @@ _hyprpm () { for literal_id in "${!state_transitions[@]}"; do local literal="${literals[$literal_id]}" if [[ $literal = "${prefix}"* ]]; then - local completion=${literal#"$superfluous_prefix"} - COMPREPLY+=("$completion ") + matches+=("$literal ") fi done fi declare -A commands - commands=([3]=0) + commands=([3]=0 [2]=1) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} local completions=() - mapfile -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1) + readarray -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1) for item in "${completions[@]}"; do if [[ $item = "${prefix}"* ]]; then - COMPREPLY+=("$item") + matches+=("$item") fi done fi + local shortest_suffix="$prefix" + for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do + local char="${COMP_WORDBREAKS:$i:1}" + local candidate=${prefix##*$char} + if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then + shortest_suffix=$candidate + fi + done + local superfluous_prefix="" + if [[ "$shortest_suffix" != "$prefix" ]]; then + local superfluous_prefix=${prefix%$shortest_suffix} + fi + COMPREPLY=("${matches[@]#$superfluous_prefix}") + return 0 } diff --git a/hyprpm/hyprpm.fish b/hyprpm/hyprpm.fish index 7be4f224..82561bd8 100644 --- a/hyprpm/hyprpm.fish +++ b/hyprpm/hyprpm.fish @@ -3,6 +3,11 @@ function _hyprpm_1 hyprpm list | awk '/Plugin/{print $4}' end +function _hyprpm_2 + set 1 $argv[1] + hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' +end + function _hyprpm set COMP_LINE (commandline --cut-at-cursor) @@ -14,49 +19,51 @@ function _hyprpm set COMP_CWORD (count $COMP_WORDS) end - set --local literals "-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f" + set literals "--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f" - set --local descriptions - set descriptions[1] "Send a hyprland notification for important events (e.g. load fail)" - set descriptions[3] "List all installed plugins" + set descriptions + set descriptions[1] "Disable shallow cloning of Hyprland sources" + set descriptions[2] "Send a hyprland notification for important events (e.g. load fail)" set descriptions[4] "Unload a plugin" - set descriptions[5] "Show help menu" - set descriptions[6] "Check and update all plugins if needed" - set descriptions[7] "Install a new plugin repository from git" - set descriptions[8] "Enable too much loggin" + set descriptions[5] "List all installed plugins" + set descriptions[6] "Show help menu" + set descriptions[7] "Check and update all plugins if needed" + set descriptions[8] "Install a new plugin repository from git" set descriptions[9] "Enable too much loggin" - set descriptions[10] "Force an operation ignoring checks (e.g. update -f)" - set descriptions[11] "Remove a plugin repository" - set descriptions[12] "Load a plugin" - set descriptions[13] "Send a hyprland notification for important events (e.g. load fail)" - set descriptions[14] "Show help menu" - set descriptions[15] "Reload all plugins" - set descriptions[16] "Force an operation ignoring checks (e.g. update -f)" + set descriptions[10] "Enable too much loggin" + set descriptions[11] "Force an operation ignoring checks (e.g. update -f)" + set descriptions[12] "Disable shallow cloning of Hyprland sources" + set descriptions[13] "Remove a plugin repository" + set descriptions[14] "Load a plugin" + set descriptions[15] "Send a hyprland notification for important events (e.g. load fail)" + set descriptions[16] "Show help menu" + set descriptions[17] "Reload all plugins" + set descriptions[18] "Force an operation ignoring checks (e.g. update -f)" - set --local literal_transitions - set literal_transitions[1] "set inputs 10 3 8 9 5 11 12 6 14 4 15 16 7; set tos 7 3 7 7 7 3 4 3 7 4 3 7 3" - set literal_transitions[2] "set inputs 11 12 4 3 15 6 7; set tos 3 4 4 3 3 3 3" - set literal_transitions[5] "set inputs 2; set tos 6" - set literal_transitions[6] "set inputs 1 13; set tos 7 7" + set literal_transitions + set literal_transitions[1] "set inputs 1 4 5 9 10 7 8 12 6 11 13 14 16 17 18; set tos 8 4 5 8 8 5 5 8 8 8 3 4 8 5 8" + set literal_transitions[2] "set inputs 13 14 4 5 17 7 8; set tos 3 4 4 5 5 5 5" + set literal_transitions[6] "set inputs 3; set tos 7" + set literal_transitions[7] "set inputs 2 15; set tos 8 8" - set --local match_anything_transitions_from 4 3 1 2 - set --local match_anything_transitions_to 3 5 2 2 + set match_anything_transitions_from 2 5 4 3 1 + set match_anything_transitions_to 2 6 5 5 2 - set --local state 1 - set --local word_index 2 + set state 1 + set word_index 2 while test $word_index -lt $COMP_CWORD - set --local -- word $COMP_WORDS[$word_index] + set -- word $COMP_WORDS[$word_index] if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] if contains -- $word $literals - set --local literal_matched 0 + set literal_matched 0 for literal_id in (seq 1 (count $literals)) if test $literals[$literal_id] = $word - set --local index (contains --index -- $literal_id $inputs) + set index (contains --index -- $literal_id $inputs) set state $tos[$index] set word_index (math $word_index + 1) set literal_matched 1 @@ -70,7 +77,7 @@ function _hyprpm end if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state] - set --local index (contains --index -- $state $match_anything_transitions_from) + set index (contains --index -- $state $match_anything_transitions_from) set state $match_anything_transitions_to[$index] set word_index (math $word_index + 1) continue @@ -80,8 +87,8 @@ function _hyprpm end if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] for literal_id in $inputs if test -n $descriptions[$literal_id] @@ -92,14 +99,14 @@ function _hyprpm end end - set command_states 4 - set command_ids 1 + set command_states 4 3 + set command_ids 1 2 if contains $state $command_states - set --local index (contains --index $state $command_states) - set --local function_id $command_ids[$index] - set --local function_name _hyprpm_$function_id - set --local --erase inputs - set --local --erase tos + set index (contains --index $state $command_states) + set function_id $command_ids[$index] + set function_name _hyprpm_$function_id + set --erase inputs + set --erase tos $function_name "$COMP_WORDS[$COMP_CWORD]" end diff --git a/hyprpm/hyprpm.usage b/hyprpm/hyprpm.usage index 369c9d2b..24e631c5 100644 --- a/hyprpm/hyprpm.usage +++ b/hyprpm/hyprpm.usage @@ -5,10 +5,11 @@ hyprpm []... | (--help | -h) "Show help menu" | (--verbose | -v) "Enable too much loggin" | (--force | -f) "Force an operation ignoring checks (e.g. update -f)" + | (--no-shallow | -s) "Disable shallow cloning of Hyprland sources" ; ::= (add) "Install a new plugin repository from git" - | (remove) "Remove a plugin repository" + | (remove ) "Remove a plugin repository" | (update) "Check and update all plugins if needed" | (list) "List all installed plugins" | (enable ) "Load a plugin" @@ -17,3 +18,4 @@ hyprpm []... ; ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}}; + ::= {{{ hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' }}}; diff --git a/hyprpm/hyprpm.zsh b/hyprpm/hyprpm.zsh index 854e8426..859c5313 100644 --- a/hyprpm/hyprpm.zsh +++ b/hyprpm/hyprpm.zsh @@ -4,34 +4,40 @@ _hyprpm_cmd_0 () { hyprpm list | awk '/Plugin/{print $4}' } +_hyprpm_cmd_1 () { + hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' +} + _hyprpm () { - local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f") + local -a literals=("--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f") local -A descriptions - descriptions[1]="Send a hyprland notification for important events (e.g. load fail)" - descriptions[3]="List all installed plugins" + descriptions[1]="Disable shallow cloning of Hyprland sources" + descriptions[2]="Send a hyprland notification for important events (e.g. load fail)" descriptions[4]="Unload a plugin" - descriptions[5]="Show help menu" - descriptions[6]="Check and update all plugins if needed" - descriptions[7]="Install a new plugin repository from git" - descriptions[8]="Enable too much loggin" + descriptions[5]="List all installed plugins" + descriptions[6]="Show help menu" + descriptions[7]="Check and update all plugins if needed" + descriptions[8]="Install a new plugin repository from git" descriptions[9]="Enable too much loggin" - descriptions[10]="Force an operation ignoring checks (e.g. update -f)" - descriptions[11]="Remove a plugin repository" - descriptions[12]="Load a plugin" - descriptions[13]="Send a hyprland notification for important events (e.g. load fail)" - descriptions[14]="Show help menu" - descriptions[15]="Reload all plugins" - descriptions[16]="Force an operation ignoring checks (e.g. update -f)" + descriptions[10]="Enable too much loggin" + descriptions[11]="Force an operation ignoring checks (e.g. update -f)" + descriptions[12]="Disable shallow cloning of Hyprland sources" + descriptions[13]="Remove a plugin repository" + descriptions[14]="Load a plugin" + descriptions[15]="Send a hyprland notification for important events (e.g. load fail)" + descriptions[16]="Show help menu" + descriptions[17]="Reload all plugins" + descriptions[18]="Force an operation ignoring checks (e.g. update -f)" local -A literal_transitions - literal_transitions[1]="([10]=7 [3]=3 [8]=7 [9]=7 [5]=7 [11]=3 [12]=4 [6]=3 [14]=7 [4]=4 [15]=3 [16]=7 [7]=3)" - literal_transitions[2]="([11]=3 [12]=4 [4]=4 [3]=3 [15]=3 [6]=3 [7]=3)" - literal_transitions[5]="([2]=6)" - literal_transitions[6]="([1]=7 [13]=7)" + literal_transitions[1]="([1]=8 [4]=4 [5]=5 [9]=8 [10]=8 [7]=5 [8]=5 [12]=8 [6]=8 [11]=8 [13]=3 [14]=4 [16]=8 [17]=5 [18]=8)" + literal_transitions[2]="([13]=3 [14]=4 [4]=4 [5]=5 [17]=5 [7]=5 [8]=5)" + literal_transitions[6]="([3]=7)" + literal_transitions[7]="([2]=8 [15]=8)" local -A match_anything_transitions - match_anything_transitions=([4]=3 [3]=5 [1]=2 [2]=2) + match_anything_transitions=([2]=2 [5]=6 [4]=5 [3]=5 [1]=2) declare -A subword_transitions @@ -91,7 +97,7 @@ _hyprpm () { fi done fi - local -A commands=([4]=0) + local -A commands=([4]=0 [3]=1) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} From 33015546c62a7b73793d62983a84b097362cec1a Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 19 Aug 2024 12:46:36 +0000 Subject: [PATCH 060/298] config: add missing header for libc++ after 92744b5b9aa3 (#7403) In file included from src/pch/pch.hpp:1: In file included from src/Compositor.hpp:11: src/config/ConfigManager.hpp:147:10: error: no template named 'variant' in namespace 'std' 147 | std::variant data; | ~~~~~^ --- src/config/ConfigManager.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 4241031b..4d087753 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -6,6 +6,7 @@ #include "../debug/Log.hpp" #include #include "../defines.hpp" +#include #include #include #include From 01e3da4d51927427860368c88a523f47c479b710 Mon Sep 17 00:00:00 2001 From: JL2210 Date: Mon, 19 Aug 2024 09:02:09 -0400 Subject: [PATCH 061/298] examples: more systemd examples (#7409) These allow launching hyprland with a systemd service. They provide graphical-session.target which allows enabling services such as the ones for Waybar and Mako. --- example/hyprland-session.service | 14 ++++++++++++++ example/hyprland-systemd.desktop | 5 +++++ 2 files changed, 19 insertions(+) create mode 100644 example/hyprland-session.service create mode 100644 example/hyprland-systemd.desktop diff --git a/example/hyprland-session.service b/example/hyprland-session.service new file mode 100644 index 00000000..7d33f5b3 --- /dev/null +++ b/example/hyprland-session.service @@ -0,0 +1,14 @@ +[Unit] +Description=Hyprland - Tiling compositor with the looks +Documentation=man:Hyprland(1) +BindsTo=graphical-session.target +Before=graphical-session.target +Wants=graphical-session-pre.target +After=graphical-session-pre.target + +[Service] +Type=notify +ExecStart=/usr/bin/Hyprland +ExecStop=/usr/bin/hyprctl dispatch exit +Restart=on-failure +Slice=session.slice diff --git a/example/hyprland-systemd.desktop b/example/hyprland-systemd.desktop new file mode 100644 index 00000000..b36a87b2 --- /dev/null +++ b/example/hyprland-systemd.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=Hyprland +Comment=An intelligent dynamic tiling Wayland compositor +Exec=systemctl --user start --wait hyprland-session +Type=Application From 272d9048706379201b761c3159c24a20cd62fad1 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 19 Aug 2024 18:36:06 +0200 Subject: [PATCH 062/298] monitors: avoid crash on wayland output removal --- src/events/Monitors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index b2778062..60fb5bef 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -98,7 +98,7 @@ void Events::listener_monitorDestroy(void* owner, void* data) { if (!pMonitor) return; - Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); + Debug::log(LOG, "Destroy called for monitor {}", pMonitor->szName); pMonitor->onDisconnect(true); From c86db7bbb0cf14d4955ee3a4d13c0ed9f8a0e0ae Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 19 Aug 2024 18:44:22 +0200 Subject: [PATCH 063/298] monitor: avoid dangling references to old monitors being undestroyed ref #7414 --- src/Compositor.cpp | 3 +-- src/events/Events.hpp | 1 - src/events/Monitors.cpp | 25 ------------------------- src/helpers/Monitor.cpp | 21 +++++++++++++++++---- src/helpers/Monitor.hpp | 2 +- 5 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 1437a653..75c22743 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2935,7 +2935,7 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { void CCompositor::onNewMonitor(SP output) { // add it to real - auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); + auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared(output)); if (std::string("HEADLESS-1") == output->name) { g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); output->name = "FALLBACK"; // we are allowed to do this :) @@ -2944,7 +2944,6 @@ void CCompositor::onNewMonitor(SP output) { Debug::log(LOG, "New output with name {}", output->name); PNEWMONITOR->szName = output->name; - PNEWMONITOR->output = output; PNEWMONITOR->self = PNEWMONITOR; const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false; PNEWMONITOR->ID = FALLBACK ? MONITOR_INVALID : g_pCompositor->getNextAvailableMonitorID(output->name); diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 8e73f54a..0af16f64 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -27,7 +27,6 @@ namespace Events { // Monitor part 2 the sequel DYNLISTENFUNC(monitorFrame); - DYNLISTENFUNC(monitorDestroy); DYNLISTENFUNC(monitorStateRequest); DYNLISTENFUNC(monitorDamage); DYNLISTENFUNC(monitorNeedsFrame); diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 60fb5bef..9d2210f6 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -85,31 +85,6 @@ void Events::listener_monitorFrame(void* owner, void* data) { } } -void Events::listener_monitorDestroy(void* owner, void* data) { - CMonitor* pMonitor = (CMonitor*)owner; - - for (auto& m : g_pCompositor->m_vRealMonitors) { - if (m->output == pMonitor->output) { - pMonitor = m.get(); - break; - } - } - - if (!pMonitor) - return; - - Debug::log(LOG, "Destroy called for monitor {}", pMonitor->szName); - - pMonitor->onDisconnect(true); - - pMonitor->output = nullptr; - pMonitor->m_bRenderingInitPassed = false; - - Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName); - - std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == pMonitor; }); -} - void Events::listener_monitorNeedsFrame(void* owner, void* data) { const auto PMONITOR = (CMonitor*)owner; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9542d2c4..2c6282e1 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -25,7 +25,7 @@ int ratHandler(void* data) { return 1; } -CMonitor::CMonitor() : state(this) { +CMonitor::CMonitor(SP output_) : state(this), output(output_) { ; } @@ -40,16 +40,29 @@ void CMonitor::onConnect(bool noRule) { outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); } - listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); - listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); }); - listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); + listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); + listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); listeners.needsFrame = output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); + listeners.presented = output->events.present.registerListener([this](std::any d) { auto E = std::any_cast(d); PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags); }); + listeners.destroy = output->events.destroy.registerListener([this](std::any d) { + Debug::log(LOG, "Destroy called for monitor {}", szName); + + onDisconnect(true); + + output = nullptr; + m_bRenderingInitPassed = false; + + Debug::log(LOG, "Removing monitor {} from realMonitors", szName); + + std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == this; }); + }); + listeners.state = output->events.state.registerListener([this](std::any d) { auto E = std::any_cast(d); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index dcfcb63b..01a5d28d 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -59,7 +59,7 @@ class CMonitorState { class CMonitor { public: - CMonitor(); + CMonitor(SP output); ~CMonitor(); Vector2D vecPosition = Vector2D(-1, -1); // means unset From 4eff224a7f6f4baa5600f687d6f2ef4ad8340ad3 Mon Sep 17 00:00:00 2001 From: Ali Atashrooz Date: Wed, 21 Aug 2024 13:54:02 +0330 Subject: [PATCH 064/298] example/config: fix typo in default config (#7446) * Update hyprland.conf * Update defaultConfig.hpp --- example/hyprland.conf | 6 +++--- src/config/defaultConfig.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index f69309c2..d55d25fd 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -169,9 +169,9 @@ device { } -#################### -### KEYBINDINGSS ### -#################### +################### +### KEYBINDINGS ### +################### # See https://wiki.hyprland.org/Configuring/Keywords/ $mainMod = SUPER # Sets "Windows" key as main modifier diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 98b617d0..59265fee 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -182,9 +182,9 @@ device { } -#################### -### KEYBINDINGSS ### -#################### +################### +### KEYBINDINGS ### +################### # See https://wiki.hyprland.org/Configuring/Keywords/ $mainMod = SUPER # Sets "Windows" key as main modifier From 946ed1f32ae8e3840d1b3bb04c6e048ca7501fba Mon Sep 17 00:00:00 2001 From: ParaN3xus <136563585+ParaN3xus@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:24:42 +0800 Subject: [PATCH 065/298] core: add option to control which window to focus on close (#7368) --- src/config/ConfigDescriptions.hpp | 9 ++++++++- src/config/ConfigManager.cpp | 1 + src/events/Windows.cpp | 7 ++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 3c830132..73b995ae 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -453,6 +453,13 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{1, 0, 3}, }, + SConfigOptionDescription{ + .value = "input:focus_on_close", + .description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift " + "to the window under the cursor.", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "next,cursor"}, + }, SConfigOptionDescription{ .value = "input:mouse_refocus", .description = "if disabled, mouse focus won't switch to the hovered window unless the mouse crosses a window boundary when follow_mouse=1.", @@ -1341,4 +1348,4 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, -}; \ No newline at end of file +}; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1856bd49..155b75d3 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -449,6 +449,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("animations:first_launch_animation", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:follow_mouse", Hyprlang::INT{1}); + m_pConfig->addConfigValue("input:focus_on_close", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:mouse_refocus", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:special_fallthrough", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:off_window_axis_events", Hyprlang::INT{1}); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 2eb7038f..e4e3900b 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -648,7 +648,12 @@ void Events::listener_unmapWindow(void* owner, void* data) { // refocus on a new window if needed if (wasLastWindow) { - const auto PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW); + static auto FOCUSONCLOSE = CConfigValue("input:focus_on_close"); + PHLWINDOW PWINDOWCANDIDATE = nullptr; + if (*FOCUSONCLOSE) + PWINDOWCANDIDATE = (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING)); + else + PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW); Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE); From 3e7325af57c4670ebea65d2669f49526819c2260 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 21 Aug 2024 12:52:40 +0200 Subject: [PATCH 066/298] output: dont cast enum out of range (#7448) avoid casting non typed enum out of range, looks like WL_OUTPUT_MODE_CURRENT was the intention here. --- src/protocols/core/Output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 878d1484..8d0b0121 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -55,7 +55,7 @@ void CWLOutputResource::updateState() { if (resource->version() >= 2) resource->sendScale(std::ceil(monitor->scale)); - resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); + resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); if (resource->version() >= 2) resource->sendDone(); From 883463f9dd7f1cdc68c3e32017c0a71ccbe39b26 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 21 Aug 2024 14:37:50 +0200 Subject: [PATCH 067/298] animations: add workspace in/out configs --- src/config/ConfigManager.cpp | 10 +++++++++- src/desktop/Workspace.cpp | 12 ++++++++++-- src/managers/AnimationManager.cpp | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 155b75d3..e2ae2c47 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -724,7 +724,6 @@ void CConfigManager::setDefaultAnimationVars() { INITANIMCFG("fade"); INITANIMCFG("border"); INITANIMCFG("borderangle"); - INITANIMCFG("workspaces"); // windows INITANIMCFG("windowsIn"); @@ -745,7 +744,12 @@ void CConfigManager::setDefaultAnimationVars() { // border // workspaces + INITANIMCFG("workspaces"); + INITANIMCFG("workspacesIn"); + INITANIMCFG("workspacesOut"); INITANIMCFG("specialWorkspace"); + INITANIMCFG("specialWorkspaceIn"); + INITANIMCFG("specialWorkspaceOut"); } // init the values @@ -774,7 +778,11 @@ void CConfigManager::setDefaultAnimationVars() { CREATEANIMCFG("fadeLayersIn", "fadeLayers"); CREATEANIMCFG("fadeLayersOut", "fadeLayers"); + CREATEANIMCFG("workspacesIn", "workspaces"); + CREATEANIMCFG("workspacesOut", "workspaces"); CREATEANIMCFG("specialWorkspace", "workspaces"); + CREATEANIMCFG("specialWorkspaceIn", "specialWorkspace"); + CREATEANIMCFG("specialWorkspaceOut", "specialWorkspace"); } std::optional CConfigManager::resetHLConfig() { diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index d9ac7927..a9412e6d 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -22,10 +22,11 @@ CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bo void CWorkspace::init(PHLWORKSPACE self) { m_pSelf = self; - m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), + m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : + g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self, AVARDAMAGE_ENTIRE); m_fAlpha.create(AVARTYPE_FLOAT, - m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), self, + m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self, AVARDAMAGE_ENTIRE); m_fAlpha.setValueAndWarp(1.f); @@ -81,6 +82,13 @@ CWorkspace::~CWorkspace() { } void CWorkspace::startAnim(bool in, bool left, bool instant) { + if (!instant) { + const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); + + m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); + m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); + } + const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index dcc7a45f..beb880be 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -471,7 +471,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config, } return "unknown style"; - } else if (config == "workspaces" || config == "specialWorkspace") { + } else if (config.starts_with("workspaces") || config.starts_with("specialWorkspace")) { if (style == "slide" || style == "slidevert" || style == "fade") return ""; else if (style.starts_with("slidefade")) { From 1b1ecf77e0c195460eb5335652d65de6fd83cf7b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 21 Aug 2024 22:37:28 +0300 Subject: [PATCH 068/298] Nix: include xcursor regardless of xwayland --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index 9bae9d83..c8eaf731 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -136,11 +136,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov tomlplusplus wayland wayland-protocols + xorg.libXcursor ] (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals enableXWayland [ xorg.libxcb - xorg.libXcursor xorg.libXdmcp xorg.xcbutil xorg.xcbutilerrors From c5786be695224c2d2771854436844b88a6b48fc5 Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Tue, 20 Aug 2024 13:36:41 -0400 Subject: [PATCH 069/298] Fix static asan patch --- scripts/hyprlandStaticAsan.diff | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/hyprlandStaticAsan.diff b/scripts/hyprlandStaticAsan.diff index e74eb6ab..b352d65d 100644 --- a/scripts/hyprlandStaticAsan.diff +++ b/scripts/hyprlandStaticAsan.diff @@ -1,13 +1,13 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index f54cdf5d..ad7c3e73 100755 +index f26a5c3c..3dfef333 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -130,6 +130,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) - message(STATUS "Enabling ASan") +@@ -143,6 +143,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) + message(STATUS "Enabling ASan") - target_link_libraries(Hyprland asan) -+ pkg_check_modules(ffidep REQUIRED IMPORTED_TARGET libffi) -+ target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a PkgConfig::ffidep) - target_compile_options(Hyprland PUBLIC -fsanitize=address) - endif() + target_link_libraries(Hyprland asan) ++ pkg_check_modules(ffidep REQUIRED IMPORTED_TARGET libffi) ++ target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a PkgConfig::ffidep) + target_compile_options(Hyprland PUBLIC -fsanitize=address) + endif() From 8162fae37728b3ae2b1a82a32663e76c59c4ce61 Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Tue, 20 Aug 2024 13:54:51 -0400 Subject: [PATCH 070/298] Fix Makefile too ... did this ever work? --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index adf6fbe8..bc7b750b 100644 --- a/Makefile +++ b/Makefile @@ -87,8 +87,8 @@ asan: #git reset --hard @echo -en "If you want to apply a patch, input its path (leave empty for none):\n" - @read patchvar - @if [-n "$patchvar"]; then patch -p1 < $patchvar || echo ""; else echo "No patch specified"; fi + @read patchvar; \ + if [ -n "$$patchvar" ]; then patch -p1 < "$$patchvar" || echo ""; else echo "No patch specified"; fi git clone --recursive https://gitlab.freedesktop.org/wayland/wayland cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd .. From cae937c51bd220d6676c6027d05ea51fc3c821bb Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 21 Aug 2024 23:05:03 +0200 Subject: [PATCH 071/298] layersurface: dont rollover on size_t (#7451) unneded rollover on size_t if force equals -1 --- src/desktop/LayerSurface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index c352fa74..8fd448ef 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -432,8 +432,8 @@ void CLayerSurface::startAnimation(bool in, bool instant) { PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, }; - float closest = std::numeric_limits::max(); - size_t leader = force; + float closest = std::numeric_limits::max(); + int leader = force; if (leader == -1) { for (size_t i = 0; i < 4; ++i) { float dist = MIDDLE.distance(edgePoints[i]); From a437e44a6af8e8f42966ffe3a26c1d562fce6b33 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Thu, 22 Aug 2024 13:04:13 +0300 Subject: [PATCH 072/298] CMakeLists: wayland.xml is in wayland-scanner pkgdatadir See https://gitlab.freedesktop.org/wayland/wayland/-/blob/6c4a695045155583a99f3fbce7bb745f79c2e726/meson.build#L129-136 Similar fix as https://github.com/hyprwm/aquamarine/pull/55. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f26a5c3c..b1373e07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ find_package(PkgConfig REQUIRED) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") -pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) +pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Configuring Hyprland in Debug with CMake") @@ -259,7 +259,7 @@ function(protocolWayland) OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp COMMAND hyprwayland-scanner --wayland-enums - ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) target_sources(generate-protocol-headers From 4fa63104c94ca5e2d2e3baaf3b3926db246b964c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 22 Aug 2024 14:30:10 +0300 Subject: [PATCH 073/298] Nix: exclude wayland-scanner until next staging merge --- CMakeLists.txt | 13 ++++++------- nix/default.nix | 3 ++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1373e07..e8ea4797 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,8 @@ find_package(PkgConfig REQUIRED) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) +message( + STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}") if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Configuring Hyprland in Debug with CMake") @@ -87,11 +89,7 @@ else() endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) -pkg_check_modules( - hyprctl_deps - REQUIRED - IMPORTED_TARGET - hyprutils>=0.2.1) +pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) pkg_check_modules( deps @@ -258,8 +256,9 @@ function(protocolWayland) add_custom_command( OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp - COMMAND hyprwayland-scanner --wayland-enums - ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + COMMAND + hyprwayland-scanner --wayland-enums + ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) target_sources(generate-protocol-headers diff --git a/nix/default.nix b/nix/default.nix index c8eaf731..64796a90 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -97,7 +97,8 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov ninja pkg-config python3 # for udis86 - wayland-scanner + # re-add after https://github.com/NixOS/nixpkgs/pull/214906 hits nixos-unstable + # wayland-scanner ]; outputs = [ From bdb296a83c595f3814f8159d2cffd25c3edfb842 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 22 Aug 2024 14:30:17 +0300 Subject: [PATCH 074/298] flake.lock: update --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 97016819..fd06ac7d 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724006173, - "narHash": "sha256-1ROh0buuxiMyc6eIb3CIbJsmYO7PhLqSYs55mOx1XTk=", + "lastModified": 1724273991, + "narHash": "sha256-+aUSOXKGpS5CRm1oTitgNAr05ThQNbKIXalZHl3nC6Y=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7f8df01d4297b9068a9592400f16044602844f86", + "rev": "9a3161ad4c78dc420d1cbb3aae638222608c7de4", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1721324361, - "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=", + "lastModified": 1724174162, + "narHash": "sha256-fOOBLwil6M9QWMCiSULwjMQzrXhHXUnEqmjHX5ZHeVI=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086", + "rev": "16e5c9465f04477d8a3dd48a0a26bf437986336c", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1723637854, - "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=", + "lastModified": 1724224976, + "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9", + "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62", "type": "github" }, "original": { @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1722365976, - "narHash": "sha256-Khdm+mDzYA//XaU0M+hftod+rKr5q9SSHSEuiQ0/9ow=", + "lastModified": 1724073926, + "narHash": "sha256-nWlUL43jOFHf+KW6Hqrx+W/r1XdXuDyb0wC/SrHsOu4=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "7f2a77ddf60390248e2a3de2261d7102a13e5341", + "rev": "a08ecbbf33598924e93542f737fc6169a26b481e", "type": "github" }, "original": { From f634b9e61af7dae0ca70379bd207eea45bb417d1 Mon Sep 17 00:00:00 2001 From: Red <21181998+Redender64@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:36:12 +0000 Subject: [PATCH 075/298] Fix crash reports having execute permission --- src/debug/CrashReporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index c31975b8..000d8c5d 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -86,7 +86,7 @@ void CrashReporter::createAndSaveCrash(int sig) { stderr.flush(); } - reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRWXU); + reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (reportFd < 0) { exit_with_error("Failed to open crash report path for writing"); } From 3b663f4afcecb1abc93a61d6448183c5978f5cd2 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 23 Aug 2024 14:13:43 +0200 Subject: [PATCH 076/298] screencopy: fixup 10-bit sharing via shm on nvidia --- src/protocols/Screencopy.cpp | 2 +- src/protocols/ToplevelExport.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index b25d9456..1559476b 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -238,7 +238,7 @@ bool CScreencopyFrame::copyShm() { g_pHyprRenderer->makeEGLCurrent(); CFramebuffer fb; - fb.alloc(box.w, box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : pMonitor->output->state->state().drmFormat); + fb.alloc(box.w, box.h, pMonitor->output->state->state().drmFormat); if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { LOGM(ERR, "Can't copy: failed to begin rendering"); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 05e991d6..916f7395 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -245,7 +245,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { g_pHyprRenderer->makeEGLCurrent(); CFramebuffer outFB; - outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat); + outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); if (overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); From df4f222482a7c2a1116ef5c91ba6e4b55d94ad6c Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 23 Aug 2024 15:06:52 +0200 Subject: [PATCH 077/298] layersurface: remove layer on destroy from monitor (#7457) remove destroyed layer weakptrs on destroy, we can hit multiple null ptr derefs in renderering on mirroring and unmirroring displays otherwise. --- src/desktop/LayerSurface.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 8fd448ef..46aea86c 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -107,6 +107,12 @@ void CLayerSurface::onDestroy() { g_pHyprRenderer->damageBox(&geomFixed); } + for (auto& mon : g_pCompositor->m_vRealMonitors) { + for (auto& lsl : mon->m_aLayerSurfaceLayers) { + std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); + } + } + readyToDelete = true; layerSurface.reset(); if (surface) From a3b75559b35880a85149ab0b644cc0c26cdfdae1 Mon Sep 17 00:00:00 2001 From: MahouShoujoMivutilde <14999778+MahouShoujoMivutilde@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:35:52 +0300 Subject: [PATCH 078/298] input: Fix modifier keys getting stuck if depressed during config reload (#7486) The problem: If `input:numlock_by_default = true`, depressed mods will get stuck on config reload; this takes effect after some other mod is pressed. This restores 0.41.2 behavior, with the exception that selected keyboard layout is preserved. https://github.com/hyprwm/Hyprland/blob/918d8340afd652b011b937d29d5eea0be08467f5/src/managers/input/InputManager.cpp#L993-L1002 --- src/devices/IKeyboard.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index e05cbd04..13440169 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -119,7 +119,8 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { if (IDX != XKB_MOD_INVALID) modifiersState.locked |= (uint32_t)1 << IDX; - updateModifiers(modifiersState.depressed, modifiersState.latched, modifiersState.locked, modifiersState.group); + // 0 to avoid mods getting stuck if depressed during reload + updateModifiers(0, 0, modifiersState.locked, modifiersState.group); } for (size_t i = 0; i < LEDNAMES.size(); ++i) { From 688fe5c14781c63a1db23d4d02bf239283068ff6 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Sat, 24 Aug 2024 04:42:14 +0900 Subject: [PATCH 079/298] windowrules: add fullscreenstate field (#7466) * windowrules: add fullscreenstate field * fix typo --- src/Compositor.cpp | 7 ++-- src/config/ConfigManager.cpp | 62 ++++++++++++++++++++++++++++-------- src/desktop/Window.hpp | 15 +++++---- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 75c22743..c9a698ce 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2326,8 +2326,12 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS PWINDOW->m_sFullscreenState.client = state.client; g_pXWaylandManager->setWindowFullscreen(PWINDOW, state.client & FSMODE_FULLSCREEN); - if (!CHANGEINTERNAL) + if (!CHANGEINTERNAL) { + PWINDOW->updateDynamicRules(); + updateWindowAnimatedDecorationValues(PWINDOW); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); return; + } g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, CURRENT_EFFECTIVE_MODE, EFFECTIVE_MODE); @@ -2339,7 +2343,6 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS EMIT_HOOK_EVENT("fullscreen", PWINDOW); PWINDOW->updateDynamicRules(); - PWINDOW->updateWindowDecos(); updateWindowAnimatedDecorationValues(PWINDOW); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e2ae2c47..51b1e1d2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1212,6 +1212,32 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo continue; } + if (!rule.szFullscreenState.empty()) { + const auto ARGS = CVarList(rule.szFullscreenState, 2, ' '); + // + std::optional internalMode, clientMode; + + if (ARGS[0] == "*") + internalMode = {}; + else if (isNumber(ARGS[0])) + internalMode = (eFullscreenMode)std::stoi(ARGS[0]); + else + throw std::runtime_error("szFullscreenState internal mode not valid"); + + if (ARGS[1] == "*") + clientMode = {}; + else if (isNumber(ARGS[1])) + clientMode = (eFullscreenMode)std::stoi(ARGS[1]); + else + throw std::runtime_error("szFullscreenState client mode not valid"); + + if (internalMode.has_value() && pWindow->m_sFullscreenState.internal != internalMode) + continue; + + if (clientMode.has_value() && pWindow->m_sFullscreenState.client != clientMode) + continue; + } + if (!rule.szOnWorkspace.empty()) { const auto PWORKSPACE = pWindow->m_pWorkspace; if (!PWORKSPACE || !PWORKSPACE->matchesStaticSelector(rule.szOnWorkspace)) @@ -2219,17 +2245,18 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& rule.szRule = RULE; rule.szValue = VALUE; - const auto TAGPOS = VALUE.find("tag:"); - const auto TITLEPOS = VALUE.find("title:"); - const auto CLASSPOS = VALUE.find("class:"); - const auto INITIALTITLEPOS = VALUE.find("initialTitle:"); - const auto INITIALCLASSPOS = VALUE.find("initialClass:"); - const auto X11POS = VALUE.find("xwayland:"); - const auto FLOATPOS = VALUE.find("floating:"); - const auto FULLSCREENPOS = VALUE.find("fullscreen:"); - const auto PINNEDPOS = VALUE.find("pinned:"); - const auto FOCUSPOS = VALUE.find("focus:"); - const auto ONWORKSPACEPOS = VALUE.find("onworkspace:"); + const auto TAGPOS = VALUE.find("tag:"); + const auto TITLEPOS = VALUE.find("title:"); + const auto CLASSPOS = VALUE.find("class:"); + const auto INITIALTITLEPOS = VALUE.find("initialTitle:"); + const auto INITIALCLASSPOS = VALUE.find("initialClass:"); + const auto X11POS = VALUE.find("xwayland:"); + const auto FLOATPOS = VALUE.find("floating:"); + const auto FULLSCREENPOS = VALUE.find("fullscreen:"); + const auto PINNEDPOS = VALUE.find("pinned:"); + const auto FOCUSPOS = VALUE.find("focus:"); + const auto FULLSCREENSTATEPOS = VALUE.find("fullscreenstate:"); + const auto ONWORKSPACEPOS = VALUE.find("onworkspace:"); // find workspacepos that isn't onworkspacepos size_t WORKSPACEPOS = std::string::npos; @@ -2242,9 +2269,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& currentPos = VALUE.find("workspace:", currentPos + 1); } - const auto checkPos = std::unordered_set{ - TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, FULLSCREENPOS, PINNEDPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS, - }; + const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, + FULLSCREENPOS, PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS}; if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) { Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE); return "Invalid rulev2 syntax: " + VALUE; @@ -2273,6 +2299,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& min = FULLSCREENPOS; if (PINNEDPOS > pos && PINNEDPOS < min) min = PINNEDPOS; + if (FULLSCREENSTATEPOS > pos && FULLSCREENSTATEPOS < min) + min = FULLSCREENSTATEPOS; if (ONWORKSPACEPOS > pos && ONWORKSPACEPOS < min) min = ONWORKSPACEPOS; if (WORKSPACEPOS > pos && WORKSPACEPOS < min) @@ -2317,6 +2345,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (PINNEDPOS != std::string::npos) rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0; + if (FULLSCREENSTATEPOS != std::string::npos) + rule.szFullscreenState = extract(FULLSCREENSTATEPOS + 16); + if (WORKSPACEPOS != std::string::npos) rule.szWorkspace = extract(WORKSPACEPOS + 10); @@ -2358,6 +2389,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (rule.bPinned != -1 && rule.bPinned != other.bPinned) return false; + if (!rule.szFullscreenState.empty() && rule.szFullscreenState != other.szFullscreenState) + return false; + if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace) return false; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 2e5b54b1..e1850fb3 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -196,13 +196,14 @@ struct SWindowRule { std::string szInitialTitle; std::string szInitialClass; std::string szTag; - int bX11 = -1; // -1 means "ANY" - int bFloating = -1; - int bFullscreen = -1; - int bPinned = -1; - int bFocus = -1; - std::string szOnWorkspace = ""; // empty means any - std::string szWorkspace = ""; // empty means any + int bX11 = -1; // -1 means "ANY" + int bFloating = -1; + int bFullscreen = -1; + int bPinned = -1; + int bFocus = -1; + std::string szFullscreenState = ""; // empty means any + std::string szOnWorkspace = ""; // empty means any + std::string szWorkspace = ""; // empty means any }; struct SInitialWorkspaceToken { From e45e606fbd7f7e805eb5a1c81482ea44b66e88d2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 24 Aug 2024 15:22:10 +0200 Subject: [PATCH 080/298] layersurface: don't unref from monitor until dtor reee --- src/desktop/LayerSurface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 46aea86c..8d13bf19 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -71,6 +71,12 @@ CLayerSurface::~CLayerSurface() { surface->unassign(); g_pHyprRenderer->makeEGLCurrent(); std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); }); + + for (auto& mon : g_pCompositor->m_vRealMonitors) { + for (auto& lsl : mon->m_aLayerSurfaceLayers) { + std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); + } + } } void CLayerSurface::onDestroy() { @@ -107,12 +113,6 @@ void CLayerSurface::onDestroy() { g_pHyprRenderer->damageBox(&geomFixed); } - for (auto& mon : g_pCompositor->m_vRealMonitors) { - for (auto& lsl : mon->m_aLayerSurfaceLayers) { - std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); - } - } - readyToDelete = true; layerSurface.reset(); if (surface) From 82c67e61a96b23c7b962ab8e3ed9079f671942e1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 24 Aug 2024 15:24:55 +0200 Subject: [PATCH 081/298] config: fix uninitialized values with mode parsing --- src/config/ConfigManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 51b1e1d2..0390b9d9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1218,14 +1218,14 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo std::optional internalMode, clientMode; if (ARGS[0] == "*") - internalMode = {}; + internalMode = std::nullopt; else if (isNumber(ARGS[0])) internalMode = (eFullscreenMode)std::stoi(ARGS[0]); else throw std::runtime_error("szFullscreenState internal mode not valid"); if (ARGS[1] == "*") - clientMode = {}; + clientMode = std::nullopt; else if (isNumber(ARGS[1])) clientMode = (eFullscreenMode)std::stoi(ARGS[1]); else From 66586c38f53f16bcf762f019359a3c9042546a72 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 24 Aug 2024 11:45:53 -0500 Subject: [PATCH 082/298] keybinds: refactor dispatchers to be better (#7331) --- src/debug/HyprCtl.cpp | 6 +- src/managers/KeybindManager.cpp | 578 ++++++++++++++++++++------------ src/managers/KeybindManager.hpp | 171 +++++----- src/plugins/PluginAPI.cpp | 7 +- 4 files changed, 457 insertions(+), 305 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 78c8504a..a92c3a53 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -962,11 +962,11 @@ std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) { if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) return "Invalid dispatcher"; - DISPATCHER->second(DISPATCHARG); + SDispatchResult res = DISPATCHER->second(DISPATCHARG); - Debug::log(LOG, "Hyprctl: dispatcher {} : {}", DISPATCHSTR, DISPATCHARG); + Debug::log(LOG, "Hyprctl: dispatcher {} : {}{}", DISPATCHSTR, DISPATCHARG, res.success ? "" : " -> " + res.error); - return "ok"; + return res.success ? "ok" : res.error; } std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 38593497..8bf7152e 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -405,7 +405,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { m_dPressedKeys.push_back(KEY); - suppressEvent = handleKeybinds(MODS, KEY, true); + suppressEvent = !handleKeybinds(MODS, KEY, true).passEvent; if (suppressEvent) shadowKeybinds(keysym, KEYCODE); @@ -427,7 +427,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { if (!foundInPressedKeys) { Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys"); // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy - suppressEvent = handleKeybinds(MODS, KEY, false); + suppressEvent = !handleKeybinds(MODS, KEY, false).passEvent; } shadowKeybinds(); @@ -457,14 +457,14 @@ bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) { bool found = false; if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { if (e.delta < 0) - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true).passEvent; else - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true).passEvent; } else if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { if (e.delta < 0) - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true).passEvent; else - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true).passEvent; } if (found) @@ -500,7 +500,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { m_dPressedKeys.push_back(KEY); - suppressEvent = handleKeybinds(MODS, KEY, true); + suppressEvent = !handleKeybinds(MODS, KEY, true).passEvent; if (suppressEvent) shadowKeybinds(); @@ -510,7 +510,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { bool foundInPressedKeys = false; for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) { if (it->keyName == KEY_NAME) { - suppressEvent = handleKeybinds(MODS, *it, false); + suppressEvent = !handleKeybinds(MODS, *it, false).passEvent; foundInPressedKeys = true; suppressEvent = !it->sent; it = m_dPressedKeys.erase(it); @@ -521,7 +521,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { if (!foundInPressedKeys) { Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys (2)"); // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy - suppressEvent = handleKeybinds(MODS, KEY, false); + suppressEvent = !handleKeybinds(MODS, KEY, false).passEvent; } shadowKeybinds(); @@ -590,8 +590,10 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) { return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); } -bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { - bool found = false; +SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { + static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); + bool found = false; + SDispatchResult res; if (pressed) { if (keycodeToModifier(key.keycode)) @@ -605,11 +607,6 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi m_sMkKeys.erase(key.keysym); } - static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); - - if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) - Debug::log(LOG, "Keybind handling is disabled due to an inhibitor"); - for (auto& k : m_lKeybinds) { const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse"; const bool SPECIALTRIGGERED = @@ -711,10 +708,11 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi m_iPassPressed = (int)pressed; + // if the dispatchers says to pass event then we will if (k.handler == "mouse") - DISPATCHER->second((pressed ? "1" : "0") + k.arg); + res = DISPATCHER->second((pressed ? "1" : "0") + k.arg); else - DISPATCHER->second(k.arg); + res = DISPATCHER->second(k.arg); m_iPassPressed = -1; @@ -737,7 +735,18 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi found = true; } - return found; + // if keybind wasn't found (or dispatcher said to) then pass event + res.passEvent |= !found; + + if (!found && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) { + Debug::log(LOG, "Keybind handling is disabled due to an inhibitor"); + + res.success = false; + if (res.error.empty()) + res.error = "Keybind handling is disabled due to an inhibitor"; + } + + return res; } void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint32_t doesntHaveCode) { @@ -838,7 +847,7 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { // Dispatchers -void CKeybindManager::spawn(std::string args) { +SDispatchResult CKeybindManager::spawn(std::string args) { args = trim(args); @@ -850,7 +859,7 @@ void CKeybindManager::spawn(std::string args) { args = args.substr(args.find_first_of(']') + 1); } - const uint64_t PROC = spawnRaw(args); + const uint64_t PROC = spawnRawProc(args); if (!RULES.empty()) { const auto RULESLIST = CVarList(RULES, 0, ';'); @@ -861,9 +870,16 @@ void CKeybindManager::spawn(std::string args) { Debug::log(LOG, "Applied {} rule arguments for exec.", RULESLIST.size()); } + + return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; } -uint64_t CKeybindManager::spawnRaw(std::string args) { +SDispatchResult CKeybindManager::spawnRaw(std::string args) { + const uint64_t PROC = spawnRawProc(args); + return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; +} + +uint64_t CKeybindManager::spawnRawProc(std::string args) { Debug::log(LOG, "Executing {}", args); const auto HLENV = getHyprlandLaunchEnv(); @@ -924,26 +940,30 @@ uint64_t CKeybindManager::spawnRaw(std::string args) { return grandchild; } -void CKeybindManager::killActive(std::string args) { +SDispatchResult CKeybindManager::killActive(std::string args) { g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow.lock()); + + return {}; } -void CKeybindManager::kill(std::string args) { +SDispatchResult CKeybindManager::kill(std::string args) { const auto PWINDOW = g_pCompositor->getWindowByRegex(args); if (!PWINDOW) { Debug::log(ERR, "kill: no window found"); - return; + return {.success = false, .error = "kill: no window found"}; } g_pCompositor->closeWindow(PWINDOW); + + return {}; } void CKeybindManager::clearKeybinds() { m_lKeybinds.clear(); } -static void toggleActiveFloatingCore(std::string args, std::optional floatState) { +static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional floatState) { PHLWINDOW PWINDOW = nullptr; if (args != "active" && args.length() > 1) @@ -952,10 +972,10 @@ static void toggleActiveFloatingCore(std::string args, std::optional float PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; if (floatState.has_value() && floatState == PWINDOW->m_bIsFloating) - return; + return {}; // remove drag status if (!g_pInputManager->currentlyDraggedWindow.expired()) @@ -981,25 +1001,27 @@ static void toggleActiveFloatingCore(std::string args, std::optional float g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + + return {}; } -void CKeybindManager::toggleActiveFloating(std::string args) { +SDispatchResult CKeybindManager::toggleActiveFloating(std::string args) { return toggleActiveFloatingCore(args, std::nullopt); } -void CKeybindManager::setActiveFloating(std::string args) { +SDispatchResult CKeybindManager::setActiveFloating(std::string args) { return toggleActiveFloatingCore(args, true); } -void CKeybindManager::setActiveTiled(std::string args) { +SDispatchResult CKeybindManager::setActiveTiled(std::string args) { return toggleActiveFloatingCore(args, false); } -void CKeybindManager::centerWindow(std::string args) { +SDispatchResult CKeybindManager::centerWindow(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) - return; + return {.success = false, .error = "No floating window found"}; const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); @@ -1009,9 +1031,11 @@ void CKeybindManager::centerWindow(std::string args) { PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET; PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal(); + + return {}; } -void CKeybindManager::toggleActivePseudo(std::string args) { +SDispatchResult CKeybindManager::toggleActivePseudo(std::string args) { PHLWINDOW PWINDOW = nullptr; if (args != "active" && args.length() > 1) @@ -1020,12 +1044,14 @@ void CKeybindManager::toggleActivePseudo(std::string args) { PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; PWINDOW->m_bIsPseudotiled = !PWINDOW->m_bIsPseudotiled; if (!PWINDOW->isFullscreen()) g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); + + return {}; } SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCURRENTWORKSPACE) { @@ -1051,7 +1077,7 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name}; } -void CKeybindManager::changeworkspace(std::string args) { +SDispatchResult CKeybindManager::changeworkspace(std::string args) { // Workspace_back_and_forth being enabled means that an attempt to switch to // the current workspace will instead switch to the previous. static auto PBACKANDFORTH = CConfigValue("binds:workspace_back_and_forth"); @@ -1061,7 +1087,7 @@ void CKeybindManager::changeworkspace(std::string args) { const auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PMONITOR) - return; + return {.success = false, .error = "Last monitor not found"}; const auto PCURRENTWORKSPACE = PMONITOR->activeWorkspace; const bool EXPLICITPREVIOUS = args.contains("previous"); @@ -1069,18 +1095,17 @@ void CKeybindManager::changeworkspace(std::string args) { const auto& [workspaceToChangeTo, workspaceName] = getWorkspaceToChangeFromArgs(args, PCURRENTWORKSPACE); if (workspaceToChangeTo == WORKSPACE_INVALID) { Debug::log(ERR, "Error in changeworkspace, invalid value"); - return; + return {.success = false, .error = "Error in changeworkspace, invalid value"}; } - if (workspaceToChangeTo == WORKSPACE_NOT_CHANGED) { - return; - } + if (workspaceToChangeTo == WORKSPACE_NOT_CHANGED) + return {}; const auto PREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(args.contains("_per_monitor")); const bool BISWORKSPACECURRENT = workspaceToChangeTo == PCURRENTWORKSPACE->m_iID; if (BISWORKSPACECURRENT && (!(*PBACKANDFORTH || EXPLICITPREVIOUS) || PREVWS.id == -1)) - return; + return {.success = false, .error = "Previous workspace doesn't exist"}; g_pInputManager->unconstrainMouse(); g_pInputManager->m_bEmptyFocusCursorSet = false; @@ -1093,7 +1118,7 @@ void CKeybindManager::changeworkspace(std::string args) { if (!BISWORKSPACECURRENT && pWorkspaceToChangeTo->m_bIsSpecialWorkspace) { PMONITOR->setSpecialWorkspace(pWorkspaceToChangeTo); g_pInputManager->simulateMouseMovement(); - return; + return {}; } g_pInputManager->releaseAllMouseButtons(); @@ -1101,7 +1126,7 @@ void CKeybindManager::changeworkspace(std::string args) { const auto PMONITORWORKSPACEOWNER = PMONITOR->ID == pWorkspaceToChangeTo->m_iMonitorID ? PMONITOR : g_pCompositor->getMonitorFromID(pWorkspaceToChangeTo->m_iMonitorID); if (!PMONITORWORKSPACEOWNER) - return; + return {.success = false, .error = "Workspace to switch to has no monitor"}; updateRelativeCursorCoords(); @@ -1143,13 +1168,15 @@ void CKeybindManager::changeworkspace(std::string args) { if (PLAST && (!HLSurface || HLSurface->getWindow())) PLAST->warpCursor(); } + + return {}; } -void CKeybindManager::fullscreenActive(std::string args) { +SDispatchResult CKeybindManager::fullscreenActive(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; const eFullscreenMode MODE = args == "1" ? FSMODE_MAXIMIZED : FSMODE_FULLSCREEN; @@ -1157,14 +1184,16 @@ void CKeybindManager::fullscreenActive(std::string args) { g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); else g_pCompositor->setWindowFullscreenInternal(PWINDOW, MODE); + + return {}; } -void CKeybindManager::fullscreenStateActive(std::string args) { +SDispatchResult CKeybindManager::fullscreenStateActive(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto ARGS = CVarList(args, 2, ' '); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); @@ -1189,9 +1218,11 @@ void CKeybindManager::fullscreenStateActive(std::string args) { g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(PWINDOW->m_sFullscreenState.internal == PWINDOW->m_sFullscreenState.client, PRIORITY_SET_PROP); + + return {}; } -void CKeybindManager::moveActiveToWorkspace(std::string args) { +SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) { PHLWINDOW PWINDOW = nullptr; @@ -1203,17 +1234,17 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { } if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; const auto& [WORKSPACEID, workspaceName] = getWorkspaceIDNameFromString(args); if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(LOG, "Invalid workspace in moveActiveToWorkspace"); - return; + return {.success = false, .error = "Invalid workspace in moveActiveToWorkspace"}; } if (WORKSPACEID == PWINDOW->workspaceID()) { Debug::log(LOG, "Not moving to workspace because it didn't change."); - return; + return {.success = false, .error = "Not moving to workspace because it didn't change."}; } auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID); @@ -1249,9 +1280,11 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->warpCursor(); + + return {}; } -void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { +SDispatchResult CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { PHLWINDOW PWINDOW = nullptr; const auto ORIGINALARGS = args; @@ -1264,16 +1297,16 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { } if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; const auto& [WORKSPACEID, workspaceName] = getWorkspaceIDNameFromString(args); if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "Error in moveActiveToWorkspaceSilent, invalid value"); - return; + return {.success = false, .error = "Error in moveActiveToWorkspaceSilent, invalid value"}; } if (WORKSPACEID == PWINDOW->workspaceID()) - return; + return {}; g_pHyprRenderer->damageWindow(PWINDOW); @@ -1293,16 +1326,18 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { else g_pInputManager->refocus(); } + + return {}; } -void CKeybindManager::moveFocusTo(std::string args) { +SDispatchResult CKeybindManager::moveFocusTo(std::string args) { static auto PFULLCYCLE = CConfigValue("binds:movefocus_cycles_fullscreen"); static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); char arg = args[0]; if (!isDirection(args)) { Debug::log(ERR, "Cannot move focus in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move focus in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); @@ -1310,7 +1345,7 @@ void CKeybindManager::moveFocusTo(std::string args) { if (*PMONITORFALLBACK) tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg)); - return; + return {}; } const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ? @@ -1320,69 +1355,81 @@ void CKeybindManager::moveFocusTo(std::string args) { // Found window in direction, switch to it if (PWINDOWTOCHANGETO) { switchToWindow(PWINDOWTOCHANGETO); - return; + return {}; } Debug::log(LOG, "No window found in direction {}, looking for a monitor", arg); if (*PMONITORFALLBACK && tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg))) - return; + return {}; static auto PNOFALLBACK = CConfigValue("general:no_focus_fallback"); if (*PNOFALLBACK) - return; + return {.success = false, .error = std::format("Nothing to focus to in direction {}", arg)}; Debug::log(LOG, "No monitor found in direction {}, falling back to next window on current workspace", arg); const auto PWINDOWNEXT = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true); if (PWINDOWNEXT) switchToWindow(PWINDOWNEXT); + + return {}; } -void CKeybindManager::focusUrgentOrLast(std::string args) { +SDispatchResult CKeybindManager::focusUrgentOrLast(std::string args) { const auto PWINDOWURGENT = g_pCompositor->getUrgentWindow(); const auto PWINDOWPREV = g_pCompositor->m_pLastWindow.lock() ? (g_pCompositor->m_vWindowFocusHistory.size() < 2 ? nullptr : g_pCompositor->m_vWindowFocusHistory[1].lock()) : (g_pCompositor->m_vWindowFocusHistory.empty() ? nullptr : g_pCompositor->m_vWindowFocusHistory[0].lock()); if (!PWINDOWURGENT && !PWINDOWPREV) - return; + return {.success = false, .error = "Window not found"}; switchToWindow(PWINDOWURGENT ? PWINDOWURGENT : PWINDOWPREV); + + return {}; } -void CKeybindManager::focusCurrentOrLast(std::string args) { +SDispatchResult CKeybindManager::focusCurrentOrLast(std::string args) { const auto PWINDOWPREV = g_pCompositor->m_pLastWindow.lock() ? (g_pCompositor->m_vWindowFocusHistory.size() < 2 ? nullptr : g_pCompositor->m_vWindowFocusHistory[1].lock()) : (g_pCompositor->m_vWindowFocusHistory.empty() ? nullptr : g_pCompositor->m_vWindowFocusHistory[0].lock()); if (!PWINDOWPREV) - return; + return {.success = false, .error = "Window not found"}; switchToWindow(PWINDOWPREV); + + return {}; } -void CKeybindManager::swapActive(std::string args) { +SDispatchResult CKeybindManager::swapActive(std::string args) { char arg = args[0]; if (!isDirection(args)) { Debug::log(ERR, "Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } Debug::log(LOG, "Swapping active window in direction {}", arg); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + + if (!PLASTWINDOW) + return {.success = false, .error = "Window to swap with not found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Can't swap fullscreen window"}; const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); if (!PWINDOWTOCHANGETO) - return; + return {.success = false, .error = "Window to swap with not found"}; updateRelativeCursorCoords(); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO); PLASTWINDOW->warpCursor(); + + return {}; } -void CKeybindManager::moveActiveTo(std::string args) { +SDispatchResult CKeybindManager::moveActiveTo(std::string args) { char arg = args[0]; bool silent = args.ends_with(" silent"); if (silent) @@ -1391,25 +1438,28 @@ void CKeybindManager::moveActiveTo(std::string args) { if (args.starts_with("mon:")) { const auto PNEWMONITOR = g_pCompositor->getMonitorFromString(args.substr(4)); if (!PNEWMONITOR) - return; + return {.success = false, .error = std::format("Monitor {} not found", args.substr(4))}; if (silent) moveActiveToWorkspaceSilent(PNEWMONITOR->activeWorkspace->getConfigName()); else moveActiveToWorkspace(PNEWMONITOR->activeWorkspace->getConfigName()); - return; + return {}; } if (!isDirection(args)) { Debug::log(ERR, "Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + if (!PLASTWINDOW) + return {.success = false, .error = "Window to move not found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Can't move fullscreen window"}; if (PLASTWINDOW->m_bIsFloating) { std::optional vPosx, vPosy; @@ -1427,7 +1477,7 @@ void CKeybindManager::moveActiveTo(std::string args) { PLASTWINDOW->m_vRealPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_vRealPosition.goal().x), vPosy.value_or(PLASTWINDOW->m_vRealPosition.goal().y)); - return; + return {}; } // If the window to change to is on the same workspace, switch them @@ -1438,30 +1488,32 @@ void CKeybindManager::moveActiveTo(std::string args) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PLASTWINDOW, args, silent); if (!silent) PLASTWINDOW->warpCursor(); - return; + return {}; } static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); if (!*PMONITORFALLBACK) - return; + return {}; // Otherwise, we always want to move to the next monitor in that direction const auto PMONITORTOCHANGETO = g_pCompositor->getMonitorInDirection(arg); if (!PMONITORTOCHANGETO) - return; + return {.success = false, .error = "Nowhere to move active window to"}; const auto PWORKSPACE = PMONITORTOCHANGETO->activeWorkspace; if (silent) moveActiveToWorkspaceSilent(PWORKSPACE->getConfigName()); else moveActiveToWorkspace(PWORKSPACE->getConfigName()); + + return {}; } -void CKeybindManager::toggleGroup(std::string args) { +SDispatchResult CKeybindManager::toggleGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; if (PWINDOW->isFullscreen()) g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); @@ -1470,30 +1522,32 @@ void CKeybindManager::toggleGroup(std::string args) { PWINDOW->createGroup(); else PWINDOW->destroyGroup(); + + return {}; } -void CKeybindManager::changeGroupActive(std::string args) { +SDispatchResult CKeybindManager::changeGroupActive(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; if (PWINDOW->m_sGroupData.pNextWindow.expired()) - return; + return {.success = false, .error = "No next window in group"}; if (PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW) - return; + return {.success = false, .error = "Only one window in group"}; if (isNumber(args, false)) { // index starts from '1'; '0' means last window const int INDEX = std::stoi(args); if (INDEX > PWINDOW->getGroupSize()) - return; + return {}; if (INDEX == 0) PWINDOW->setGroupCurrent(PWINDOW->getGroupTail()); else PWINDOW->setGroupCurrent(PWINDOW->getGroupWindowByIndex(INDEX - 1)); - return; + return {}; } if (args != "b" && args != "prev") { @@ -1501,39 +1555,45 @@ void CKeybindManager::changeGroupActive(std::string args) { } else { PWINDOW->setGroupCurrent(PWINDOW->getGroupPrevious()); } + + return {}; } -void CKeybindManager::toggleSplit(std::string args) { +SDispatchResult CKeybindManager::toggleSplit(std::string args) { SLayoutMessageHeader header; header.pWindow = g_pCompositor->m_pLastWindow.lock(); if (!header.pWindow) - return; + return {.success = false, .error = "Window not found"}; const auto PWORKSPACE = header.pWindow->m_pWorkspace; if (PWORKSPACE->m_bHasFullscreenWindow) - return; + return {.success = false, .error = "Can't split windows that already split"}; g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "togglesplit"); + + return {}; } -void CKeybindManager::swapSplit(std::string args) { +SDispatchResult CKeybindManager::swapSplit(std::string args) { SLayoutMessageHeader header; header.pWindow = g_pCompositor->m_pLastWindow.lock(); if (!header.pWindow) - return; + return {.success = false, .error = "Window not found"}; const auto PWORKSPACE = header.pWindow->m_pWorkspace; if (PWORKSPACE->m_bHasFullscreenWindow) - return; + return {.success = false, .error = "Can't split windows that already split"}; g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "swapsplit"); + + return {}; } -void CKeybindManager::alterSplitRatio(std::string args) { +SDispatchResult CKeybindManager::alterSplitRatio(std::string args) { std::optional splitResult; bool exact = false; @@ -1545,39 +1605,43 @@ void CKeybindManager::alterSplitRatio(std::string args) { if (!splitResult.has_value()) { Debug::log(ERR, "Splitratio invalid in alterSplitRatio!"); - return; + return {.success = false, .error = "Splitratio invalid in alterSplitRatio!"}; } const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW) - return; + return {.success = false, .error = "Window not found"}; g_pLayoutManager->getCurrentLayout()->alterSplitRatio(PLASTWINDOW, splitResult.value(), exact); + + return {}; } -void CKeybindManager::focusMonitor(std::string arg) { +SDispatchResult CKeybindManager::focusMonitor(std::string arg) { const auto PMONITOR = g_pCompositor->getMonitorFromString(arg); tryMoveFocusToMonitor(PMONITOR); + + return {}; } -void CKeybindManager::moveCursorToCorner(std::string arg) { +SDispatchResult CKeybindManager::moveCursorToCorner(std::string arg) { if (!isNumber(arg)) { Debug::log(ERR, "moveCursorToCorner, arg has to be a number."); - return; + return {.success = false, .error = "moveCursorToCorner, arg has to be a number."}; } const auto CORNER = std::stoi(arg); if (CORNER < 0 || CORNER > 3) { Debug::log(ERR, "moveCursorToCorner, corner not 0 - 3."); - return; + return {.success = false, .error = "moveCursorToCorner, corner not 0 - 3."}; } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; switch (CORNER) { case 0: @@ -1598,16 +1662,18 @@ void CKeybindManager::moveCursorToCorner(std::string arg) { g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y}, true); break; } + + return {}; } -void CKeybindManager::moveCursor(std::string args) { +SDispatchResult CKeybindManager::moveCursor(std::string args) { std::string x_str, y_str; int x, y; size_t i = args.find_first_of(' '); if (i == std::string::npos) { Debug::log(ERR, "moveCursor, takes 2 arguments."); - return; + return {.success = false, .error = "moveCursor, takes 2 arguments"}; } x_str = args.substr(0, i); @@ -1615,26 +1681,28 @@ void CKeybindManager::moveCursor(std::string args) { if (!isNumber(x_str)) { Debug::log(ERR, "moveCursor, x argument has to be a number."); - return; + return {.success = false, .error = "moveCursor, x argument has to be a number."}; } if (!isNumber(y_str)) { Debug::log(ERR, "moveCursor, y argument has to be a number."); - return; + return {.success = false, .error = "moveCursor, y argument has to be a number."}; } x = std::stoi(x_str); y = std::stoi(y_str); g_pCompositor->warpCursorTo({x, y}, true); + + return {}; } -void CKeybindManager::workspaceOpt(std::string args) { +SDispatchResult CKeybindManager::workspaceOpt(std::string args) { // current workspace const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; if (!PWORKSPACE) - return; // ???? + return {.success = false, .error = "Workspace not found"}; // ???? if (args == "allpseudo") { PWORKSPACE->m_bDefaultPseudo = !PWORKSPACE->m_bDefaultPseudo; @@ -1677,14 +1745,16 @@ void CKeybindManager::workspaceOpt(std::string args) { } } else { Debug::log(ERR, "Invalid arg in workspaceOpt, opt \"{}\" doesn't exist.", args); - return; + return {.success = false, .error = std::format("Invalid arg in workspaceOpt, opt \"{}\" doesn't exist.", args)}; } // recalc mon g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID); + + return {}; } -void CKeybindManager::renameWorkspace(std::string args) { +SDispatchResult CKeybindManager::renameWorkspace(std::string args) { try { const auto FIRSTSPACEPOS = args.find_first_of(' '); if (FIRSTSPACEPOS != std::string::npos) { @@ -1694,34 +1764,42 @@ void CKeybindManager::renameWorkspace(std::string args) { } else { g_pCompositor->renameWorkspace(std::stoi(args), ""); } - } catch (std::exception& e) { Debug::log(ERR, "Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what()); } + } catch (std::exception& e) { + Debug::log(ERR, "Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what()); + return {.success = false, .error = std::format("Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what())}; + } + + return {}; } -void CKeybindManager::exitHyprland(std::string argz) { +SDispatchResult CKeybindManager::exitHyprland(std::string argz) { g_pCompositor->stopCompositor(); + return {}; } -void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { +SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { CMonitor* PMONITOR = g_pCompositor->getMonitorFromString(args); if (!PMONITOR) { Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist"); - return; + return {.success = false, .error = "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist"}; } // get the current workspace const auto PCURRENTWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; if (!PCURRENTWORKSPACE) { Debug::log(ERR, "moveCurrentWorkspaceToMonitor invalid workspace!"); - return; + return {.success = false, .error = "moveCurrentWorkspaceToMonitor invalid workspace!"}; } g_pCompositor->moveWorkspaceToMonitor(PCURRENTWORKSPACE, PMONITOR); + + return {}; } -void CKeybindManager::moveWorkspaceToMonitor(std::string args) { +SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) { if (!args.contains(' ')) - return; + return {}; std::string workspace = args.substr(0, args.find_first_of(' ')); std::string monitor = args.substr(args.find_first_of(' ') + 1); @@ -1730,38 +1808,40 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { if (!PMONITOR) { Debug::log(ERR, "Ignoring moveWorkspaceToMonitor: monitor doesnt exist"); - return; + return {.success = false, .error = "Ignoring moveWorkspaceToMonitor: monitor doesnt exist"}; } const auto WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!"); - return; + return {.success = false, .error = "moveWorkspaceToMonitor invalid workspace!"}; } const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID); if (!PWORKSPACE) { Debug::log(ERR, "moveWorkspaceToMonitor workspace doesn't exist!"); - return; + return {.success = false, .error = "moveWorkspaceToMonitor workspace doesn't exist!"}; } g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PMONITOR); + + return {}; } -void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { +SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { auto workspaceID = getWorkspaceIDNameFromString(args).id; if (workspaceID == WORKSPACE_INVALID) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); - return; + return {.success = false, .error = "focusWorkspaceOnCurrentMonitor invalid workspace!"}; } const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PCURRMONITOR) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"); - return; + return {.success = false, .error = "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"}; } auto pWorkspace = g_pCompositor->getWorkspaceByID(workspaceID); @@ -1770,7 +1850,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID); // we can skip the moving, since it's already on the current monitor changeworkspace(pWorkspace->getConfigName()); - return; + return {}; } static auto PBACKANDFORTH = CConfigValue("binds:workspace_back_and_forth"); @@ -1789,24 +1869,26 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { const auto POLDMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); if (!POLDMONITOR) { // wat Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"); - return; + return {.success = false, .error = "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"}; } if (POLDMONITOR->activeWorkspaceID() == workspaceID) { g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR); - return; + return {}; } else { g_pCompositor->moveWorkspaceToMonitor(pWorkspace, PCURRMONITOR, true); } } changeworkspace(pWorkspace->getConfigName()); + + return {}; } -void CKeybindManager::toggleSpecialWorkspace(std::string args) { +SDispatchResult CKeybindManager::toggleSpecialWorkspace(std::string args) { const auto& [workspaceID, workspaceName] = getWorkspaceIDNameFromString("special:" + args); if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) { Debug::log(ERR, "Invalid workspace passed to special"); - return; + return {.success = false, .error = "Invalid workspace passed to special"}; } bool requestedWorkspaceIsAlreadyOpen = false; @@ -1833,9 +1915,11 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { PMONITOR->setSpecialWorkspace(PSPECIALWORKSPACE); } + + return {}; } -void CKeybindManager::forceRendererReload(std::string args) { +SDispatchResult CKeybindManager::forceRendererReload(std::string args) { bool overAgain = false; for (auto& m : g_pCompositor->m_vMonitors) { @@ -1851,37 +1935,43 @@ void CKeybindManager::forceRendererReload(std::string args) { if (overAgain) forceRendererReload(args); + + return {}; } -void CKeybindManager::resizeActive(std::string args) { +SDispatchResult CKeybindManager::resizeActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + return {}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize.goal()); if (SIZ.x < 1 || SIZ.y < 1) - return; + return {}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize.goal()); if (PLASTWINDOW->m_vRealSize.goal().x > 1 && PLASTWINDOW->m_vRealSize.goal().y > 1) PLASTWINDOW->setHidden(false); + + return {}; } -void CKeybindManager::moveActive(std::string args) { +SDispatchResult CKeybindManager::moveActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + return {}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition.goal()); g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PLASTWINDOW->m_vRealPosition.goal()); + + return {}; } -void CKeybindManager::moveWindow(std::string args) { +SDispatchResult CKeybindManager::moveWindow(std::string args) { const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1); const auto MOVECMD = args.substr(0, args.find_first_of(',')); @@ -1890,18 +1980,20 @@ void CKeybindManager::moveWindow(std::string args) { if (!PWINDOW) { Debug::log(ERR, "moveWindow: no window"); - return; + return {.success = false, .error = "moveWindow: no window"}; } if (PWINDOW->isFullscreen()) - return; + return {}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal()); g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition.goal(), PWINDOW); + + return {}; } -void CKeybindManager::resizeWindow(std::string args) { +SDispatchResult CKeybindManager::resizeWindow(std::string args) { const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1); const auto MOVECMD = args.substr(0, args.find_first_of(',')); @@ -1910,24 +2002,26 @@ void CKeybindManager::resizeWindow(std::string args) { if (!PWINDOW) { Debug::log(ERR, "resizeWindow: no window"); - return; + return {.success = false, .error = "resizeWindow: no window"}; } if (PWINDOW->isFullscreen()) - return; + return {}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal()); if (SIZ.x < 1 || SIZ.y < 1) - return; + return {}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goal(), CORNER_NONE, PWINDOW); if (PWINDOW->m_vRealSize.goal().x > 1 && PWINDOW->m_vRealSize.goal().y > 1) PWINDOW->setHidden(false); + + return {}; } -void CKeybindManager::circleNext(std::string arg) { +SDispatchResult CKeybindManager::circleNext(std::string arg) { if (g_pCompositor->m_pLastWindow.expired()) { // if we have a clear focus, find the first window and get the next focusable. @@ -1937,7 +2031,7 @@ void CKeybindManager::circleNext(std::string arg) { switchToWindow(PWINDOW); } - return; + return {}; } CVarList args{arg, 0, 's', true}; @@ -1952,20 +2046,22 @@ void CKeybindManager::circleNext(std::string arg) { switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); else switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); + + return {}; } -void CKeybindManager::focusWindow(std::string regexp) { +SDispatchResult CKeybindManager::focusWindow(std::string regexp) { const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp); if (!PWINDOW) - return; + return {}; Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle); const auto PWORKSPACE = PWINDOW->m_pWorkspace; if (!PWORKSPACE) { Debug::log(ERR, "BUG THIS: null workspace in focusWindow"); - return; + return {.success = false, .error = "BUG THIS: null workspace in focusWindow"}; } updateRelativeCursorCoords(); @@ -2001,9 +2097,11 @@ void CKeybindManager::focusWindow(std::string regexp) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->warpCursor(); + + return {}; } -void CKeybindManager::tagWindow(std::string args) { +SDispatchResult CKeybindManager::tagWindow(std::string args) { PHLWINDOW PWINDOW = nullptr; CVarList vars{args, 0, 's', true}; @@ -2012,21 +2110,23 @@ void CKeybindManager::tagWindow(std::string args) { else if (vars.size() == 2) PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); else - return; + return {}; if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) { PWINDOW->updateDynamicRules(); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW->m_pSelf.lock()); } + + return {}; } -void CKeybindManager::setSubmap(std::string submap) { +SDispatchResult CKeybindManager::setSubmap(std::string submap) { if (submap == "reset" || submap == "") { m_szCurrentSelectedSubmap = ""; Debug::log(LOG, "Reset active submap to the default one."); g_pEventManager->postEvent(SHyprIPCEvent{"submap", ""}); EMIT_HOOK_EVENT("submap", m_szCurrentSelectedSubmap); - return; + return {}; } for (auto& k : g_pKeybindManager->m_lKeybinds) { @@ -2035,26 +2135,27 @@ void CKeybindManager::setSubmap(std::string submap) { Debug::log(LOG, "Changed keybind submap to {}", submap); g_pEventManager->postEvent(SHyprIPCEvent{"submap", submap}); EMIT_HOOK_EVENT("submap", m_szCurrentSelectedSubmap); - return; + return {}; } } Debug::log(ERR, "Cannot set submap {}, submap doesn't exist (wasn't registered!)", submap); + return {.success = false, .error = std::format("Cannot set submap {}, submap doesn't exist (wasn't registered!)", submap)}; } -void CKeybindManager::pass(std::string regexp) { +SDispatchResult CKeybindManager::pass(std::string regexp) { // find the first window passing the regex const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp); if (!PWINDOW) { Debug::log(ERR, "pass: window not found"); - return; + return {.success = false, .error = "pass: window not found"}; } if (!g_pSeatManager->keyboard) { Debug::log(ERR, "No kb in pass?"); - return; + return {.success = false, .error = "No kb in pass?"}; } const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; @@ -2093,7 +2194,7 @@ void CKeybindManager::pass(std::string regexp) { } if (XWTOXW) - return; + return {}; // Massive hack: // this will make g_pSeatManager NOT send the leave event to XWayland apps, provided we are not on an XWayland window already. @@ -2114,14 +2215,16 @@ void CKeybindManager::pass(std::string regexp) { g_pSeatManager->setKeyboardFocus(LASTKBSURF); else g_pSeatManager->setPointerFocus(LASTMOUSESURF, SL); + + return {}; } -void CKeybindManager::sendshortcut(std::string args) { +SDispatchResult CKeybindManager::sendshortcut(std::string args) { // args=[,WINDOW_RULES] const auto ARGS = CVarList(args, 3); if (ARGS.size() != 3) { Debug::log(ERR, "sendshortcut: invalid args"); - return; + return {.success = false, .error = "sendshortcut: invalid args"}; } const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]); @@ -2139,7 +2242,7 @@ void CKeybindManager::sendshortcut(std::string args) { isMouse = 1; if (keycode < 272) { Debug::log(ERR, "sendshortcut: invalid mouse button"); - return; + return {.success = false, .error = "sendshortcut: invalid mouse button"}; } } else { @@ -2154,7 +2257,7 @@ void CKeybindManager::sendshortcut(std::string args) { if (!KB) { Debug::log(ERR, "sendshortcut: no kb"); - return; + return {.success = false, .error = "sendshortcut: no kb"}; } const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY); @@ -2178,7 +2281,7 @@ void CKeybindManager::sendshortcut(std::string args) { if (!keycode) { Debug::log(ERR, "sendshortcut: key not found"); - return; + return {.success = false, .error = "sendshortcut: key not found"}; } } else @@ -2187,7 +2290,7 @@ void CKeybindManager::sendshortcut(std::string args) { if (!keycode) { Debug::log(ERR, "sendshortcut: invalid key"); - return; + return {.success = false, .error = "sendshortcut: invalid key"}; } const std::string regexp = ARGS[2]; @@ -2201,12 +2304,12 @@ void CKeybindManager::sendshortcut(std::string args) { if (!PWINDOW) { Debug::log(ERR, "sendshortcut: window not found"); - return; + return {.success = false, .error = "sendshortcut: window not found"}; } if (!g_pSeatManager->keyboard) { Debug::log(ERR, "No kb in sendshortcut?"); - return; + return {.success = false, .error = "No kb in sendshortcut?"}; } if (!isMouse) @@ -2247,7 +2350,7 @@ void CKeybindManager::sendshortcut(std::string args) { } if (!PWINDOW) - return; + return {}; if (PWINDOW->m_bIsX11) { //xwayland hack, see pass if (!isMouse) { @@ -2265,16 +2368,21 @@ void CKeybindManager::sendshortcut(std::string args) { g_pSeatManager->setKeyboardFocus(LASTSURFACE); else g_pSeatManager->setPointerFocus(LASTSURFACE, SL); + + return {}; } -void CKeybindManager::layoutmsg(std::string msg) { +SDispatchResult CKeybindManager::layoutmsg(std::string msg) { SLayoutMessageHeader hd = {g_pCompositor->m_pLastWindow.lock()}; g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg); + + return {}; } -void CKeybindManager::dpms(std::string arg) { - bool enable = arg.starts_with("on"); - std::string port = ""; +SDispatchResult CKeybindManager::dpms(std::string arg) { + SDispatchResult res; + bool enable = arg.starts_with("on"); + std::string port = ""; if (arg.starts_with("toggle")) enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off @@ -2294,6 +2402,8 @@ void CKeybindManager::dpms(std::string arg) { if (!m->state.commit()) { Debug::log(ERR, "Couldn't commit output {}", m->szName); + res.success = false; + res.error = "Couldn't commit output {}"; } if (enable) @@ -2305,14 +2415,16 @@ void CKeybindManager::dpms(std::string arg) { g_pCompositor->m_bDPMSStateON = enable; g_pPointerManager->recheckEnteredOutputs(); + + return res; } -void CKeybindManager::swapnext(std::string arg) { +SDispatchResult CKeybindManager::swapnext(std::string arg) { PHLWINDOW toSwap = nullptr; if (g_pCompositor->m_pLastWindow.expired()) - return; + return {}; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); @@ -2339,9 +2451,11 @@ void CKeybindManager::swapnext(std::string arg) { PLASTWINDOW->m_pLastCycledWindow = toSwap; g_pCompositor->focusWindow(PLASTWINDOW); + + return {}; } -void CKeybindManager::swapActiveWorkspaces(std::string args) { +SDispatchResult CKeybindManager::swapActiveWorkspaces(std::string args) { const auto MON1 = args.substr(0, args.find_first_of(' ')); const auto MON2 = args.substr(args.find_first_of(' ') + 1); @@ -2349,12 +2463,14 @@ void CKeybindManager::swapActiveWorkspaces(std::string args) { const auto PMON2 = g_pCompositor->getMonitorFromString(MON2); if (!PMON1 || !PMON2 || PMON1 == PMON2) - return; + return {}; g_pCompositor->swapActiveWorkspaces(PMON1, PMON2); + + return {}; } -void CKeybindManager::pinActive(std::string args) { +SDispatchResult CKeybindManager::pinActive(std::string args) { PHLWINDOW PWINDOW = nullptr; @@ -2365,11 +2481,11 @@ void CKeybindManager::pinActive(std::string args) { if (!PWINDOW) { Debug::log(ERR, "pin: window not found"); - return; + return {.success = false, .error = "pin: window not found"}; } if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) - return; + return {}; PWINDOW->m_bPinned = !PWINDOW->m_bPinned; @@ -2377,7 +2493,7 @@ void CKeybindManager::pinActive(std::string args) { if (!PMONITOR) { Debug::log(ERR, "pin: monitor not found"); - return; + return {.success = false, .error = "pin: window not found"}; } PWINDOW->m_pWorkspace = PMONITOR->activeWorkspace; @@ -2391,40 +2507,41 @@ void CKeybindManager::pinActive(std::string args) { g_pEventManager->postEvent(SHyprIPCEvent{"pin", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), (int)PWINDOW->m_bPinned)}); EMIT_HOOK_EVENT("pin", PWINDOW); + + return {}; } -void CKeybindManager::mouse(std::string args) { +SDispatchResult CKeybindManager::mouse(std::string args) { const auto ARGS = CVarList(args.substr(1), 2, ' '); const auto PRESSED = args[0] == '1'; if (!PRESSED) { - changeMouseBindMode(MBIND_INVALID); - return; + return changeMouseBindMode(MBIND_INVALID); } if (ARGS[0] == "movewindow") { - changeMouseBindMode(MBIND_MOVE); + return changeMouseBindMode(MBIND_MOVE); } else { try { switch (std::stoi(ARGS[1])) { - case 1: changeMouseBindMode(MBIND_RESIZE_FORCE_RATIO); break; - case 2: changeMouseBindMode(MBIND_RESIZE_BLOCK_RATIO); break; - default: changeMouseBindMode(MBIND_RESIZE); + case 1: return changeMouseBindMode(MBIND_RESIZE_FORCE_RATIO); break; + case 2: return changeMouseBindMode(MBIND_RESIZE_BLOCK_RATIO); break; + default: return changeMouseBindMode(MBIND_RESIZE); } - } catch (std::exception& e) { changeMouseBindMode(MBIND_RESIZE); } + } catch (std::exception& e) { return changeMouseBindMode(MBIND_RESIZE); } } } -void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { +SDispatchResult CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { if (MODE != MBIND_INVALID) { if (!g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode != MBIND_INVALID) - return; + return {}; const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const PHLWINDOW PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (!PWINDOW) - return; + return SDispatchResult{.passEvent = true}; if (!PWINDOW->isFullscreen() && MODE == MBIND_MOVE) PWINDOW->checkInputOnDecos(INPUT_TYPE_DRAG_START, MOUSECOORDS); @@ -2437,19 +2554,23 @@ void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); } else { if (g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode == MBIND_INVALID) - return; + return {}; g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); g_pInputManager->dragMode = MODE; } + + return {}; } -void CKeybindManager::bringActiveToTop(std::string args) { +SDispatchResult CKeybindManager::bringActiveToTop(std::string args) { if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating) g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow.lock(), true); + + return {}; } -void CKeybindManager::alterZOrder(std::string args) { +SDispatchResult CKeybindManager::alterZOrder(std::string args) { const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1); const auto POSITION = args.substr(0, args.find_first_of(',')); auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX); @@ -2459,7 +2580,7 @@ void CKeybindManager::alterZOrder(std::string args) { if (!PWINDOW) { Debug::log(ERR, "alterZOrder: no window"); - return; + return {.success = false, .error = "alterZOrder: no window"}; } if (POSITION == "top") @@ -2468,13 +2589,15 @@ void CKeybindManager::alterZOrder(std::string args) { g_pCompositor->changeWindowZOrder(PWINDOW, 0); else { Debug::log(ERR, "alterZOrder: bad position: {}", POSITION); - return; + return {.success = false, .error = "alterZOrder: bad position: {}"}; } g_pInputManager->simulateMouseMovement(); + + return {}; } -void CKeybindManager::lockGroups(std::string args) { +SDispatchResult CKeybindManager::lockGroups(std::string args) { if (args == "lock" || args.empty() || args == "lockgroups") g_pKeybindManager->m_bGroupsLocked = true; else if (args == "toggle") @@ -2483,13 +2606,15 @@ void CKeybindManager::lockGroups(std::string args) { g_pKeybindManager->m_bGroupsLocked = false; g_pEventManager->postEvent(SHyprIPCEvent{"lockgroups", g_pKeybindManager->m_bGroupsLocked ? "1" : "0"}); + + return {}; } -void CKeybindManager::lockActiveGroup(std::string args) { +SDispatchResult CKeybindManager::lockActiveGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return; + return {}; const auto PHEAD = PWINDOW->getGroupHead(); @@ -2501,6 +2626,8 @@ void CKeybindManager::lockActiveGroup(std::string args) { PHEAD->m_sGroupData.locked = false; g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); + + return {}; } void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection) { @@ -2573,41 +2700,43 @@ void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& g_pEventManager->postEvent(SHyprIPCEvent{"moveoutofgroup", std::format("{:x}", (uintptr_t)pWindow.get())}); } -void CKeybindManager::moveIntoGroup(std::string args) { +SDispatchResult CKeybindManager::moveIntoGroup(std::string args) { char arg = args[0]; static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) - return; + return {}; if (!isDirection(args)) { Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny) - return; + return {}; auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); if (!PWINDOWINDIR || !PWINDOWINDIR->m_sGroupData.pNextWindow.lock()) - return; + return {}; // Do not move window into locked group if binds:ignore_group_lock is false if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || (PWINDOW->m_sGroupData.pNextWindow.lock() && PWINDOW->getGroupHead()->m_sGroupData.locked))) - return; + return {}; moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); + + return {}; } -void CKeybindManager::moveOutOfGroup(std::string args) { +SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) { static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) - return; + return {}; PHLWINDOW PWINDOW = nullptr; @@ -2617,28 +2746,30 @@ void CKeybindManager::moveOutOfGroup(std::string args) { PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return; + return {}; moveWindowOutOfGroup(PWINDOW); + + return {}; } -void CKeybindManager::moveWindowOrGroup(std::string args) { +SDispatchResult CKeybindManager::moveWindowOrGroup(std::string args) { char arg = args[0]; static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!isDirection(args)) { Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || PWINDOW->isFullscreen()) - return; + return {}; if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); - return; + return {}; } const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); @@ -2670,9 +2801,11 @@ void CKeybindManager::moveWindowOrGroup(std::string args) { } g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); + + return {}; } -void CKeybindManager::setIgnoreGroupLock(std::string args) { +SDispatchResult CKeybindManager::setIgnoreGroupLock(std::string args) { static auto PIGNOREGROUPLOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock"); if (args == "toggle") @@ -2681,12 +2814,14 @@ void CKeybindManager::setIgnoreGroupLock(std::string args) { **PIGNOREGROUPLOCK = args == "on"; g_pEventManager->postEvent(SHyprIPCEvent{"ignoregrouplock", std::to_string(**PIGNOREGROUPLOCK)}); + + return {}; } -void CKeybindManager::denyWindowFromGroup(std::string args) { +SDispatchResult CKeybindManager::denyWindowFromGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || (PWINDOW && PWINDOW->m_sGroupData.pNextWindow.lock())) - return; + return {}; if (args == "toggle") PWINDOW->m_sGroupData.deny = !PWINDOW->m_sGroupData.deny; @@ -2694,28 +2829,32 @@ void CKeybindManager::denyWindowFromGroup(std::string args) { PWINDOW->m_sGroupData.deny = args == "on"; g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); + + return {}; } -void CKeybindManager::global(std::string args) { +SDispatchResult CKeybindManager::global(std::string args) { const auto APPID = args.substr(0, args.find_first_of(':')); const auto NAME = args.substr(args.find_first_of(':') + 1); if (NAME.empty()) - return; + return {}; if (!PROTO::globalShortcuts->isTaken(APPID, NAME)) - return; + return {}; PROTO::globalShortcuts->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed); + + return {}; } -void CKeybindManager::moveGroupWindow(std::string args) { +SDispatchResult CKeybindManager::moveGroupWindow(std::string args) { const auto BACK = args == "b" || args == "prev"; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW || !PLASTWINDOW->m_sGroupData.pNextWindow.lock()) - return; + return {}; if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) { std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head); @@ -2724,8 +2863,11 @@ void CKeybindManager::moveGroupWindow(std::string args) { PLASTWINDOW->switchWithWindowInGroup(BACK ? PLASTWINDOW->getGroupPrevious() : PLASTWINDOW->m_sGroupData.pNextWindow.lock()); PLASTWINDOW->updateWindowDecos(); + + return {}; } -void CKeybindManager::event(std::string args) { +SDispatchResult CKeybindManager::event(std::string args) { g_pEventManager->postEvent(SHyprIPCEvent{"custom", args}); + return {}; } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 26b42b00..d1f26c2c 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -71,33 +71,39 @@ enum eMultiKeyCase { MK_FULL_MATCH }; +struct SDispatchResult { + bool passEvent = false; + bool success = true; + std::string error; +}; + class CKeybindManager { public: CKeybindManager(); ~CKeybindManager(); - bool onKeyEvent(std::any, SP); - bool onAxisEvent(const IPointer::SAxisEvent&); - bool onMouseEvent(const IPointer::SButtonEvent&); - void resizeWithBorder(const IPointer::SButtonEvent&); - void onSwitchEvent(const std::string&); - void onSwitchOnEvent(const std::string&); - void onSwitchOffEvent(const std::string&); + bool onKeyEvent(std::any, SP); + bool onAxisEvent(const IPointer::SAxisEvent&); + bool onMouseEvent(const IPointer::SButtonEvent&); + void resizeWithBorder(const IPointer::SButtonEvent&); + void onSwitchEvent(const std::string&); + void onSwitchOnEvent(const std::string&); + void onSwitchOffEvent(const std::string&); - void addKeybind(SKeybind); - void removeKeybind(uint32_t, const SParsedKey&); - uint32_t stringToModMask(std::string); - uint32_t keycodeToModifier(xkb_keycode_t); - void clearKeybinds(); - void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); + void addKeybind(SKeybind); + void removeKeybind(uint32_t, const SParsedKey&); + uint32_t stringToModMask(std::string); + uint32_t keycodeToModifier(xkb_keycode_t); + void clearKeybinds(); + void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); - std::unordered_map> m_mDispatchers; + std::unordered_map> m_mDispatchers; - wl_event_source* m_pActiveKeybindEventSource = nullptr; + wl_event_source* m_pActiveKeybindEventSource = nullptr; - bool m_bGroupsLocked = false; + bool m_bGroupsLocked = false; - std::list m_lKeybinds; + std::list m_lKeybinds; //since we cant find keycode through keyname in xkb: //on sendshortcut call, we once search for keyname (e.g. "g") the correct keycode (e.g. 42) @@ -105,7 +111,7 @@ class CKeybindManager { //we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts) std::unordered_map m_mKeyToCodeCache; - static void changeMouseBindMode(const eMouseBindMode mode); + static SDispatchResult changeMouseBindMode(const eMouseBindMode mode); private: std::deque m_dPressedKeys; @@ -124,7 +130,7 @@ class CKeybindManager { CTimer m_tScrollTimer; - bool handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool); + SDispatchResult handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool); std::set m_sMkKeys = {}; std::set m_sMkMods = {}; @@ -143,71 +149,72 @@ class CKeybindManager { static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); + static uint64_t spawnRawProc(std::string); // -------------- Dispatchers -------------- // - static void killActive(std::string); - static void kill(std::string); - static void spawn(std::string); - static uint64_t spawnRaw(std::string); - static void toggleActiveFloating(std::string); - static void toggleActivePseudo(std::string); - static void setActiveFloating(std::string); - static void setActiveTiled(std::string); - static void changeworkspace(std::string); - static void fullscreenActive(std::string); - static void fullscreenStateActive(std::string args); - static void moveActiveToWorkspace(std::string); - static void moveActiveToWorkspaceSilent(std::string); - static void moveFocusTo(std::string); - static void focusUrgentOrLast(std::string); - static void focusCurrentOrLast(std::string); - static void centerWindow(std::string); - static void moveActiveTo(std::string); - static void swapActive(std::string); - static void toggleGroup(std::string); - static void changeGroupActive(std::string); - static void alterSplitRatio(std::string); - static void focusMonitor(std::string); - static void toggleSplit(std::string); - static void swapSplit(std::string); - static void moveCursorToCorner(std::string); - static void moveCursor(std::string); - static void workspaceOpt(std::string); - static void renameWorkspace(std::string); - static void exitHyprland(std::string); - static void moveCurrentWorkspaceToMonitor(std::string); - static void moveWorkspaceToMonitor(std::string); - static void focusWorkspaceOnCurrentMonitor(std::string); - static void toggleSpecialWorkspace(std::string); - static void forceRendererReload(std::string); - static void resizeActive(std::string); - static void moveActive(std::string); - static void moveWindow(std::string); - static void resizeWindow(std::string); - static void circleNext(std::string); - static void focusWindow(std::string); - static void tagWindow(std::string); - static void setSubmap(std::string); - static void pass(std::string); - static void sendshortcut(std::string); - static void layoutmsg(std::string); - static void dpms(std::string); - static void swapnext(std::string); - static void swapActiveWorkspaces(std::string); - static void pinActive(std::string); - static void mouse(std::string); - static void bringActiveToTop(std::string); - static void alterZOrder(std::string); - static void lockGroups(std::string); - static void lockActiveGroup(std::string); - static void moveIntoGroup(std::string); - static void moveOutOfGroup(std::string); - static void moveGroupWindow(std::string); - static void moveWindowOrGroup(std::string); - static void setIgnoreGroupLock(std::string); - static void denyWindowFromGroup(std::string); - static void global(std::string); - static void event(std::string); + static SDispatchResult killActive(std::string); + static SDispatchResult kill(std::string); + static SDispatchResult spawn(std::string); + static SDispatchResult spawnRaw(std::string); + static SDispatchResult toggleActiveFloating(std::string); + static SDispatchResult toggleActivePseudo(std::string); + static SDispatchResult setActiveFloating(std::string); + static SDispatchResult setActiveTiled(std::string); + static SDispatchResult changeworkspace(std::string); + static SDispatchResult fullscreenActive(std::string); + static SDispatchResult fullscreenStateActive(std::string args); + static SDispatchResult moveActiveToWorkspace(std::string); + static SDispatchResult moveActiveToWorkspaceSilent(std::string); + static SDispatchResult moveFocusTo(std::string); + static SDispatchResult focusUrgentOrLast(std::string); + static SDispatchResult focusCurrentOrLast(std::string); + static SDispatchResult centerWindow(std::string); + static SDispatchResult moveActiveTo(std::string); + static SDispatchResult swapActive(std::string); + static SDispatchResult toggleGroup(std::string); + static SDispatchResult changeGroupActive(std::string); + static SDispatchResult alterSplitRatio(std::string); + static SDispatchResult focusMonitor(std::string); + static SDispatchResult toggleSplit(std::string); + static SDispatchResult swapSplit(std::string); + static SDispatchResult moveCursorToCorner(std::string); + static SDispatchResult moveCursor(std::string); + static SDispatchResult workspaceOpt(std::string); + static SDispatchResult renameWorkspace(std::string); + static SDispatchResult exitHyprland(std::string); + static SDispatchResult moveCurrentWorkspaceToMonitor(std::string); + static SDispatchResult moveWorkspaceToMonitor(std::string); + static SDispatchResult focusWorkspaceOnCurrentMonitor(std::string); + static SDispatchResult toggleSpecialWorkspace(std::string); + static SDispatchResult forceRendererReload(std::string); + static SDispatchResult resizeActive(std::string); + static SDispatchResult moveActive(std::string); + static SDispatchResult moveWindow(std::string); + static SDispatchResult resizeWindow(std::string); + static SDispatchResult circleNext(std::string); + static SDispatchResult focusWindow(std::string); + static SDispatchResult tagWindow(std::string); + static SDispatchResult setSubmap(std::string); + static SDispatchResult pass(std::string); + static SDispatchResult sendshortcut(std::string); + static SDispatchResult layoutmsg(std::string); + static SDispatchResult dpms(std::string); + static SDispatchResult swapnext(std::string); + static SDispatchResult swapActiveWorkspaces(std::string); + static SDispatchResult pinActive(std::string); + static SDispatchResult mouse(std::string); + static SDispatchResult bringActiveToTop(std::string); + static SDispatchResult alterZOrder(std::string); + static SDispatchResult lockGroups(std::string); + static SDispatchResult lockActiveGroup(std::string); + static SDispatchResult moveIntoGroup(std::string); + static SDispatchResult moveOutOfGroup(std::string); + static SDispatchResult moveGroupWindow(std::string); + static SDispatchResult moveWindowOrGroup(std::string); + static SDispatchResult setIgnoreGroupLock(std::string); + static SDispatchResult denyWindowFromGroup(std::string); + static SDispatchResult global(std::string); + static SDispatchResult event(std::string); friend class CCompositor; friend class CInputManager; diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 098e3f12..398d4ce1 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -194,7 +194,10 @@ APICALL bool HyprlandAPI::addDispatcher(HANDLE handle, const std::string& name, PLUGIN->registeredDispatchers.push_back(name); - g_pKeybindManager->m_mDispatchers[name] = handler; + g_pKeybindManager->m_mDispatchers[name] = [handler](std::string arg1) -> SDispatchResult { + handler(arg1); + return {}; + }; return true; } @@ -378,4 +381,4 @@ APICALL bool HyprlandAPI::unregisterHyprCtlCommand(HANDLE handle, SPunregisterCommand(cmd); return true; -} \ No newline at end of file +} From aac90d92797825a65b9faab038586a3b88448667 Mon Sep 17 00:00:00 2001 From: "Nelo-T. Wallus" Date: Sun, 25 Aug 2024 13:13:48 +0200 Subject: [PATCH 083/298] hyprpm: Fix checking dependencies (#7504) * hyprpm: Fix checking dependencies * hyprpm: Check for dependency "pkg-config" --------- Co-authored-by: Nelo-T. Wallus --- hyprpm/src/core/PluginManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 6988547c..ab457ca6 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -904,9 +904,9 @@ std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { } bool CPluginManager::hasDeps() { - std::vector deps = {"meson", "cpio", "cmake"}; + std::vector deps = {"meson", "cpio", "cmake", "pkg-config"}; for (auto& d : deps) { - if (!execAndGet("which " + d + " 2>&1").contains("/")) + if (!execAndGet("command -v " + d).contains("/")) return false; } From b672118f9238a48a18efd741cbcda387c5552238 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Sun, 25 Aug 2024 09:37:03 -0500 Subject: [PATCH 084/298] xwayland: deactivate xwayland focus if wayland is focused (#7458) * xwayland: deactivate xwayland focus if wayland is focused * xwayland: deactivate last xwayland surface after focusing wayland --- src/managers/XWaylandManager.cpp | 5 ++++- src/xwayland/XWM.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index f329dbe1..2f0632e0 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -43,8 +43,11 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool w->m_pXWaylandSurface->restackToTop(); } w->m_pXWaylandSurface->activate(activate); - } else + } else { w->m_pXDGSurface->toplevel->setActive(activate); + if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow->m_bIsX11) + activateSurface(g_pCompositor->m_pLastFocus.lock(), false); + } } } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index f6b6864c..a409b440 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -897,7 +897,7 @@ void CXWM::activateSurface(SP surf, bool activate) { if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect)) return; - if (!surf) { + if (!surf || (!activate && g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsX11)) { setActiveWindow((uint32_t)XCB_WINDOW_NONE); focusWindow(nullptr); } else { From 83ab3ae0afeafe25ca2038888478740d0a80396a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 26 Aug 2024 10:24:45 +0200 Subject: [PATCH 085/298] xwaylandmgr: minor refactor to activateSurface Make it more efficient now that we can + fix possible nullptr deref fixes #7514 --- src/managers/XWaylandManager.cpp | 36 +++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 2f0632e0..a6fd97f5 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -28,26 +28,28 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool if (!pSurface) return; - // TODO: - // this cannot be nicely done until we rewrite wlr_surface - for (auto& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped) - continue; + auto HLSurface = CWLSurface::fromResource(pSurface); + if (!HLSurface) { + Debug::log(TRACE, "CHyprXWaylandManager::activateSurface on non-desktop surface, ignoring"); + return; + } - if (w->m_pWLSurface->resource() != pSurface) - continue; + const auto PWINDOW = HLSurface->getWindow(); + if (!PWINDOW) { + Debug::log(TRACE, "CHyprXWaylandManager::activateSurface on non-window surface, ignoring"); + return; + } - if (w->m_bIsX11) { - if (activate) { - w->m_pXWaylandSurface->setMinimized(false); - w->m_pXWaylandSurface->restackToTop(); - } - w->m_pXWaylandSurface->activate(activate); - } else { - w->m_pXDGSurface->toplevel->setActive(activate); - if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow->m_bIsX11) - activateSurface(g_pCompositor->m_pLastFocus.lock(), false); + if (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface) { + if (activate) { + PWINDOW->m_pXWaylandSurface->setMinimized(false); + PWINDOW->m_pXWaylandSurface->restackToTop(); } + PWINDOW->m_pXWaylandSurface->activate(activate); + } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) { + PWINDOW->m_pXDGSurface->toplevel->setActive(activate); + if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) + activateSurface(g_pCompositor->m_pLastFocus.lock(), false); } } From 28f6c2df5923bfe514d238399f934fc80bb1449d Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:27:34 +0000 Subject: [PATCH 086/298] sessionLock: fix misc:allow_session_lock_restore (#7511) * Revert "sessionLock: fix the check for locking a locked session (#6843)" This reverts commit 9ff83f4aa97269bf26381a84501d0b19f1926961. * sessionLock: remove early check for session beeing locked It is checked in the `onNewSessionLock` handler, which also respects the `misc:allow_session_lock_restore` option. --- src/protocols/SessionLock.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index 7b0d8b3b..fe44face 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -175,13 +175,6 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { return; } - if (locked) { - LOGM(ERR, "Tried to lock a locked session"); - RESOURCE->inert = true; - RESOURCE->resource->sendFinished(); - return; - } - events.newLock.emit(RESOURCE); locked = true; From ca85455a8ed5dbe920a47c1a48de1dd993446481 Mon Sep 17 00:00:00 2001 From: Adithya Ajith <50308085+adharmic@users.noreply.github.com> Date: Mon, 26 Aug 2024 05:25:52 -0500 Subject: [PATCH 087/298] misc: Rename all instances of "emtpy" to "empty" (#7522) --- src/Compositor.cpp | 4 ++-- src/Compositor.hpp | 2 +- src/desktop/Workspace.cpp | 10 +++++----- src/desktop/Workspace.hpp | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c9a698ce..a419e741 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2624,7 +2624,7 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) { } } -PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmtpy) { +PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmpty) { const auto NAME = name == "" ? std::to_string(id) : name; auto monID = monid; @@ -2635,7 +2635,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; - const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL, isEmtpy)); + const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL, isEmpty)); PWORKSPACE->m_fAlpha.setValueAndWarp(0); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a570a06e..bb986f5e 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -165,7 +165,7 @@ class CCompositor { Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&); PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", - bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! + bool isEmpty = true); // will be deleted next frame if left empty and unfocused! void renameWorkspace(const WORKSPACEID&, const std::string& name = ""); void setActiveMonitor(CMonitor*); bool isWorkspaceSpecial(const WORKSPACEID&); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index a9412e6d..72d9705e 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -5,18 +5,18 @@ #include using namespace Hyprutils::String; -PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { - PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy); +PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { + PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmpty); workspace->init(workspace); return workspace; } -CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { +CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { m_iMonitorID = monitorID; m_iID = id; m_szName = name; m_bIsSpecialWorkspace = special; - m_bWasCreatedEmtpy = isEmtpy; + m_bWasCreatedEmpty = isEmpty; } void CWorkspace::init(PHLWORKSPACE self) { @@ -49,7 +49,7 @@ void CWorkspace::init(PHLWORKSPACE self) { const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self); m_bPersistent = WORKSPACERULE.isPersistent; - if (self->m_bWasCreatedEmtpy) + if (self->m_bWasCreatedEmpty) if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) g_pKeybindManager->spawn(*cmd); diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 9cacb0cc..7a32459c 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -17,7 +17,7 @@ class CWindow; class CWorkspace { public: - static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmtpy = true); + static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); // use create() don't use this CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); ~CWorkspace(); @@ -57,7 +57,7 @@ class CWorkspace { // last monitor (used on reconnect) std::string m_szLastMonitor = ""; - bool m_bWasCreatedEmtpy = true; + bool m_bWasCreatedEmpty = true; bool m_bPersistent = false; From 9c5a37a797ea1f1829859ab5b07016b2f27f739c Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 14:08:30 +0200 Subject: [PATCH 088/298] build: fix 32bit builds (#7510) ensure the correct type is passed to std::clamp and std::max int64_t is different on 64bit compared to 32bit, also in presentationtime tv_sec is __time_t and on 32bit its a 32bit type so right shift count >= width of type. so only bit shift on 64bit. and avoid potential nullptr deref in the for loops, check for .end() before *it <= endID. --- src/helpers/MiscFunctions.cpp | 10 +++++----- src/protocols/PresentationTime.cpp | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 86f24e3a..ef319946 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -353,13 +353,13 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { char walkDir = in[1]; // sanitize. 0 means invalid oob in - - predictedWSID = std::max(predictedWSID, 0L); + predictedWSID = std::max(predictedWSID, static_cast(0)); // Count how many invalidWSes are in between (how bad the prediction was) WORKSPACEID beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID; WORKSPACEID endID = in[1] == '+' ? predictedWSID : activeWSID; auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= - for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { + for (auto it = begin; it != invalidWSes.end() && *it <= endID; it++) { remainingWSes++; } @@ -376,7 +376,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } currentItem += remains; - currentItem = std::max(currentItem, 0UL); + currentItem = std::max(currentItem, static_cast(0)); if (currentItem >= namedWSes.size()) { // At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0 size_t diff = currentItem - (namedWSes.size() - 1); @@ -384,7 +384,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { WORKSPACEID beginID = 1; WORKSPACEID endID = predictedWSID; auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= - for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { + for (auto it = begin; it != invalidWSes.end() && *it <= endID; it++) { remainingWSes++; } walkDir = '+'; @@ -413,7 +413,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Need remainingWSes more auto namedWSIdx = namedWSes.size() - remainingWSes; // Sanitze - namedWSIdx = std::clamp(namedWSIdx, 0UL, namedWSes.size() - 1); + namedWSIdx = std::clamp(namedWSIdx, static_cast(0), namedWSes.size() - static_cast(1)); finalWSID = namedWSes[namedWSIdx]; } else { // Couldn't find valid workspace in negative direction, search last first one back up positive direction diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 335cf557..638435c7 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -58,8 +58,12 @@ void CPresentationFeedback::sendQueued(SP data, timespe if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; + __time_t tv_sec = 0; + if (sizeof(__time_t) > 4) + tv_sec = when->tv_sec >> 32; + if (data->wasPresented) - resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), + resource->sendPresented((uint32_t)tv_sec, (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); else resource->sendDiscarded(); From 8d6c18076f3268a6c85c6085d29f898267028101 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 17:25:39 +0200 Subject: [PATCH 089/298] core: make most for loops use const references (#7527) why not let the compiler optimise things for us at hyprspeeds when we can. --- src/Compositor.cpp | 32 ++++++------- src/config/ConfigManager.cpp | 36 +++++++------- src/debug/HyprCtl.cpp | 26 +++++------ src/debug/HyprDebugOverlay.cpp | 8 ++-- src/desktop/LayerSurface.cpp | 2 +- src/desktop/Window.cpp | 16 +++---- src/helpers/Monitor.cpp | 4 +- src/layout/DwindleLayout.cpp | 2 +- src/layout/IHyprLayout.cpp | 2 +- src/layout/MasterLayout.cpp | 8 ++-- src/managers/AnimationManager.cpp | 2 +- src/managers/KeybindManager.cpp | 8 ++-- src/managers/PointerManager.cpp | 14 +++--- src/managers/SeatManager.cpp | 70 ++++++++++++++-------------- src/managers/SessionLockManager.cpp | 4 +- src/managers/XWaylandManager.cpp | 4 +- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.cpp | 6 +-- src/managers/input/Swipe.cpp | 6 +-- src/managers/input/Tablets.cpp | 4 +- src/plugins/HookSystem.cpp | 2 +- src/protocols/DRMLease.cpp | 4 +- src/protocols/DataDeviceWlr.cpp | 6 +-- src/protocols/core/Compositor.cpp | 8 ++-- src/protocols/core/DataDevice.cpp | 8 ++-- src/protocols/core/Output.cpp | 2 +- src/protocols/core/Seat.cpp | 2 +- src/render/OpenGL.cpp | 8 ++-- src/render/Renderer.cpp | 24 +++++----- src/xwayland/XSurface.cpp | 4 +- src/xwayland/XWM.cpp | 14 +++--- 31 files changed, 169 insertions(+), 169 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a419e741..0aa7f213 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -314,7 +314,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) { initManagers(STAGE_LATE); - for (auto& o : pendingOutputs) { + for (auto const& o : pendingOutputs) { onNewMonitor(o); } pendingOutputs.clear(); @@ -403,7 +403,7 @@ void CCompositor::initAllSignals() { m_bSessionActive = false; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { m->noFrameSchedule = true; m->framesToSkip = 1; } @@ -741,7 +741,7 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { float bestDistance = 0.f; SP pBestMon; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize); if (dist < bestDistance || !pBestMon) { @@ -1164,8 +1164,8 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo } SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { - for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { - for (auto& ls : lsl | std::views::reverse) { + for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { + for (auto const& ls : lsl | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) continue; @@ -1183,7 +1183,7 @@ SP CCompositor::vectorToLayerPopupSurface(const Vector2D& po } SP CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { - for (auto& ls : *layerSurfaces | std::views::reverse) { + for (auto const& ls : *layerSurfaces | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; @@ -1458,7 +1458,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { g_pHyprOpenGL->markBlurDirtyForMonitor(getMonitorFromID(monid)); if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLayers) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) { std::erase_if(lsl, [&](auto& other) { return other == ls || !other; }); @@ -1718,7 +1718,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { WORKSPACEID lowest = -1337 + 1; - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_iID < -1 && w->m_iID < lowest) lowest = w->m_iID; } @@ -1748,7 +1748,7 @@ PHLWORKSPACE CCompositor::getWorkspaceByString(const std::string& str) { } bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (VECINRECT(point, m->vecPosition.x, m->vecPosition.y, m->vecSize.x + m->vecPosition.x, m->vecSize.y + m->vecPosition.y)) return true; } @@ -1834,7 +1834,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha } void CCompositor::updateAllWindowsAnimatedDecorationValues() { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped) continue; @@ -2139,7 +2139,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon if (!SWITCHINGISACTIVE) nextWorkspaceOnMonitorID = pWorkspace->m_iID; else { - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_iMonitorID == POLDMON->ID && w->m_iID != pWorkspace->m_iID && !w->m_bIsSpecialWorkspace) { nextWorkspaceOnMonitorID = w->m_iID; break; @@ -2237,7 +2237,7 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { WORKSPACEID lowestID = INT64_MAX; WORKSPACEID highestID = INT64_MIN; - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_bIsSpecialWorkspace) continue; @@ -2271,7 +2271,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { const auto PMONITOR = getMonitorFromID(pWorkspace->m_iMonitorID); if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { - for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { if (!ls->fadingOut) ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } @@ -2376,7 +2376,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { if (!pWindow->m_bIsX11) return nullptr; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsX11) continue; @@ -2543,7 +2543,7 @@ void CCompositor::closeWindow(PHLWINDOW pWindow) { PHLLS CCompositor::getLayerSurfaceFromSurface(SP pSurface) { std::pair, bool> result = {pSurface, false}; - for (auto& ls : m_vLayers) { + for (auto const& ls : m_vLayers) { if (ls->layerSurface && ls->layerSurface->surface == pSurface) return ls; @@ -2679,7 +2679,7 @@ bool CCompositor::isWorkspaceSpecial(const WORKSPACEID& id) { WORKSPACEID CCompositor::getNewSpecialID() { WORKSPACEID highest = SPECIAL_WORKSPACE_START; - for (auto& ws : m_vWorkspaces) { + for (auto const& ws : m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) { highest = ws->m_iID; } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 0390b9d9..007869ee 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -813,11 +813,11 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); static int prevEnabledExplicit = *PENABLEEXPLICIT; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); } - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); // Update the keyboard layout to the cfg'd one if this is not the first launch @@ -901,7 +901,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { m->forceFullFrames = 2; // also force mirrors, as the aspect ratio could've changed - for (auto& mirror : m->mirrors) + for (auto const& mirror : m->mirrors) mirror->forceFullFrames = 3; } @@ -940,7 +940,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: // invalidate layouts if they changed if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) { - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } @@ -1034,7 +1034,7 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s } SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { - for (auto& r : m_dMonitorRules | std::views::reverse) { + for (auto const& r : m_dMonitorRules | std::views::reverse) { if (PMONITOR.matchesStaticSelector(r.name)) { return r; } @@ -1042,7 +1042,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName); - for (auto& r : m_dMonitorRules) { + for (auto const& r : m_dMonitorRules) { if (r.name.empty()) { return r; } @@ -1354,7 +1354,7 @@ void CConfigManager::dispatchExecOnce() { firstExecDispatched = true; isLaunchingExecOnce = true; - for (auto& c : firstExecRequests) { + for (auto const& c : firstExecRequests) { handleRawExec("", c); } @@ -1438,7 +1438,7 @@ bool CConfigManager::deviceConfigExists(const std::string& dev) { } bool CConfigManager::shouldBlurLS(const std::string& ns) { - for (auto& bls : m_dBlurLSNamespaces) { + for (auto const& bls : m_dBlurLSNamespaces) { if (bls == ns) { return true; } @@ -1553,7 +1553,7 @@ CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) { } std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) { - for (auto& wr : m_dWorkspaceRules) { + for (auto const& wr : m_dWorkspaceRules) { const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName; if (WSNAME == wsname) @@ -1624,7 +1624,7 @@ void CConfigManager::addPluginKeyword(HANDLE handle, const std::string& name, Hy } void CConfigManager::removePluginConfig(HANDLE handle) { - for (auto& k : pluginKeywords) { + for (auto const& k : pluginKeywords) { if (k.handle != handle) continue; @@ -1647,7 +1647,7 @@ std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) { if (other->monitor == name) return other->workspaceString; if (other->monitor.substr(0, 5) == "desc:") { - auto monitor = g_pCompositor->getMonitorFromDesc(other->monitor.substr(5)); + auto const monitor = g_pCompositor->getMonitorFromDesc(other->monitor.substr(5)); if (monitor && monitor->szName == name) return other->workspaceString; } @@ -2044,7 +2044,7 @@ std::optional CConfigManager::handleBind(const std::string& command bool dontInhibit = false; const auto BINDARGS = command.substr(4); - for (auto& arg : BINDARGS) { + for (auto const& arg : BINDARGS) { if (arg == 'l') { locked = true; } else if (arg == 'r') { @@ -2222,9 +2222,9 @@ std::optional CConfigManager::handleLayerRule(const std::string& co m_dLayerRules.push_back({VALUE, RULE}); - for (auto& m : g_pCompositor->m_vMonitors) - for (auto& lsl : m->m_aLayerSurfaceLayers) - for (auto& ls : lsl) + for (auto const& m : g_pCompositor->m_vMonitors) + for (auto const& lsl : m->m_aLayerSurfaceLayers) + for (auto const& ls : lsl) ls->applyRules(); return {}; @@ -2423,9 +2423,9 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl matchName = matchName.substr(8); } - for (auto& m : g_pCompositor->m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& m : g_pCompositor->m_vMonitors) { + for (auto const& lsl : m->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { if (BYADDRESS) { if (std::format("0x{:x}", (uintptr_t)ls.get()) == matchName) ls->forceBlur = forceBlur; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a92c3a53..2fc5cc7d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -146,7 +146,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { + for (auto const& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { result += CHyprCtl::getMonitorData(m, format); } @@ -154,7 +154,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { result += "]"; } else { - for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { + for (auto const& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { if (!m->output || m->ID == -1) continue; @@ -272,7 +272,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) continue; @@ -283,7 +283,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { result += "]"; } else { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) continue; @@ -381,7 +381,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { result += CHyprCtl::getWorkspaceData(w, format); result += ","; } @@ -389,7 +389,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) trimTrailingComma(result); result += "]"; } else { - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { result += CHyprCtl::getWorkspaceData(w, format); } } @@ -401,7 +401,7 @@ std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string reque std::string result = ""; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& r : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& r : g_pConfigManager->getAllWorkspaceRules()) { result += getWorkspaceRuleData(r, format); result += ","; } @@ -409,7 +409,7 @@ std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string reque trimTrailingComma(result); result += "]"; } else { - for (auto& r : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& r : g_pConfigManager->getAllWorkspaceRules()) { result += getWorkspaceRuleData(r, format); } } @@ -437,7 +437,7 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "{\n"; - for (auto& mon : g_pCompositor->m_vMonitors) { + for (auto const& mon : g_pCompositor->m_vMonitors) { result += std::format( R"#("{}": {{ "levels": {{ @@ -744,7 +744,7 @@ std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) ret += ",\n["; - for (auto& bz : g_pAnimationManager->getAllBeziers()) { + for (auto const& bz : g_pAnimationManager->getAllBeziers()) { ret += std::format(R"#( {{ "name": "{}" @@ -782,7 +782,7 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); } else { ret += "["; - for (auto& sh : SHORTCUTS) { + for (auto const& sh : SHORTCUTS) { ret += std::format(R"#( {{ "name": "{}", @@ -1286,7 +1286,7 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { g_pCompositor->focusWindow(PLASTWINDOW); } - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); return "ok"; @@ -1386,7 +1386,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { bool added = false; if (!vars[3].empty()) { - for (auto& m : g_pCompositor->m_vRealMonitors) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { if (m->szName == vars[3]) return "Name already taken"; } diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index fbd8cd71..22c741a6 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -57,7 +57,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgFrametime = 0; float maxFrametime = 0; float minFrametime = 9999; - for (auto& ft : m_dLastFrametimes) { + for (auto const& ft : m_dLastFrametimes) { if (ft > maxFrametime) maxFrametime = ft; if (ft < minFrametime) @@ -70,7 +70,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgRenderTime = 0; float maxRenderTime = 0; float minRenderTime = 9999; - for (auto& rt : m_dLastRenderTimes) { + for (auto const& rt : m_dLastRenderTimes) { if (rt > maxRenderTime) maxRenderTime = rt; if (rt < minRenderTime) @@ -83,7 +83,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgRenderTimeNoOverlay = 0; float maxRenderTimeNoOverlay = 0; float minRenderTimeNoOverlay = 9999; - for (auto& rt : m_dLastRenderTimesNoOverlay) { + for (auto const& rt : m_dLastRenderTimesNoOverlay) { if (rt > maxRenderTimeNoOverlay) maxRenderTimeNoOverlay = rt; if (rt < minRenderTimeNoOverlay) @@ -96,7 +96,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgAnimMgrTick = 0; float maxAnimMgrTick = 0; float minAnimMgrTick = 9999; - for (auto& at : m_dLastAnimationTicks) { + for (auto const& at : m_dLastAnimationTicks) { if (at > maxAnimMgrTick) maxAnimMgrTick = at; if (at < minAnimMgrTick) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 8d13bf19..331dba9c 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -72,7 +72,7 @@ CLayerSurface::~CLayerSurface() { g_pHyprRenderer->makeEGLCurrent(); std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); }); - for (auto& mon : g_pCompositor->m_vRealMonitors) { + for (auto const& mon : g_pCompositor->m_vRealMonitors) { for (auto& lsl : mon->m_aLayerSurfaceLayers) { std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); } diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index dcdcb573..64337097 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -252,7 +252,7 @@ void CWindow::updateWindowDecos() { if (!m_bIsMapped || isHidden()) return; - for (auto& wd : m_vDecosToRemove) { + for (auto const& wd : m_vDecosToRemove) { for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) { if (it->get() == wd) { g_pDecorationPositioner->uncacheDecoration(it->get()); @@ -270,11 +270,11 @@ void CWindow::updateWindowDecos() { // make a copy because updateWindow can remove decos. std::vector decos; - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { decos.push_back(wd.get()); } - for (auto& wd : decos) { + for (auto const& wd : decos) { if (std::find_if(m_dWindowDecorations.begin(), m_dWindowDecorations.end(), [wd](const auto& other) { return other.get() == wd; }) == m_dWindowDecorations.end()) continue; wd->updateWindow(m_pSelf.lock()); @@ -454,7 +454,7 @@ PHLWINDOW CWindow::X11TransientFor() { s = s->parent; } - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pXWaylandSurface != s) continue; return w; @@ -464,7 +464,7 @@ PHLWINDOW CWindow::X11TransientFor() { } void CWindow::removeDecorationByType(eDecorationType type) { - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { if (wd->getDecorationType() == type) m_vDecosToRemove.push_back(wd.get()); } @@ -617,7 +617,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { int opacityIDX = 0; - for (auto& r : vars) { + for (auto const& r : vars) { if (r == "opacity") continue; @@ -770,7 +770,7 @@ void CWindow::updateDynamicRules() { m_tags.removeDynamicTags(); m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock()); - for (auto& r : m_vMatchedRules) { + for (auto const& r : m_vMatchedRules) { applyDynamicRule(r); } @@ -881,7 +881,7 @@ void CWindow::destroyGroup() { addresses += std::format("{:x},", (uintptr_t)curr.get()); } while (curr.get() != this); - for (auto& w : members) { + for (auto const& w : members) { if (w->m_sGroupData.head) g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr); w->m_sGroupData.head = false; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 2c6282e1..8b533d8a 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -207,7 +207,7 @@ void CMonitor::onConnect(bool noRule) { // verify last mon valid bool found = false; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m == g_pCompositor->m_pLastMonitor) { found = true; break; @@ -272,7 +272,7 @@ void CMonitor::onDisconnect(bool destroy) { listeners.commit.reset(); for (size_t i = 0; i < 4; ++i) { - for (auto& ls : m_aLayerSurfaceLayers[i]) { + for (auto const& ls : m_aLayerSurfaceLayers[i]) { if (ls->layerSurface && !ls->fadingOut) ls->layerSurface->sendClosed(); } diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 20085ff7..db69cc04 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -49,7 +49,7 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque* pD int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) { int no = 0; - for (auto& n : m_lDwindleNodesData) { + for (auto const& n : m_lDwindleNodesData) { if (n.workspaceID == id && n.valid) ++no; } diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 233933d4..9b3d02b4 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -691,7 +691,7 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) { bool shouldBeFloated = g_pXWaylandManager->shouldBeFloated(pWindow, true); if (!shouldBeFloated) { - for (auto& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { + for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { if (r.szRule.starts_with("float")) { shouldBeFloated = true; break; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index e0b48e98..d234d300 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -16,7 +16,7 @@ SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(PHLWINDOW pWindow) { int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) { int no = 0; - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == ws) no++; } @@ -26,7 +26,7 @@ int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) { int CHyprMasterLayout::getMastersOnWorkspace(const WORKSPACEID& ws) { int no = 0; - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == ws && n.isMaster) no++; } @@ -381,7 +381,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { if (*PSMARTRESIZING) { // check the total width and height so that later // if larger/smaller than screen size them down/up - for (auto& nd : m_lMasterNodesData) { + for (auto const& nd : m_lMasterNodesData) { if (nd.workspaceID == pWorkspace->m_iID) { if (nd.isMaster) masterAccumulatedSize += totalSize / MASTERS * nd.percSize; @@ -552,7 +552,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { float slaveAccumulatedHeightL = 0; float slaveAccumulatedHeightR = 0; if (*PSMARTRESIZING) { - for (auto& nd : m_lMasterNodesData) { + for (auto const& nd : m_lMasterNodesData) { if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster) continue; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index beb880be..e2e98735 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -131,7 +131,7 @@ void CAnimationManager::tick() { } // damage any workspace window that is on any monitor - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE || w->m_bPinned) continue; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8bf7152e..7eb96730 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -765,7 +765,7 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3 const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - for (auto& pk : m_dPressedKeys) { + for (auto const& pk : m_dPressedKeys) { if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) { shadow = true; @@ -864,7 +864,7 @@ SDispatchResult CKeybindManager::spawn(std::string args) { if (!RULES.empty()) { const auto RULESLIST = CVarList(RULES, 0, ';'); - for (auto& r : RULESLIST) { + for (auto const& r : RULESLIST) { g_pConfigManager->addExecRule({r, (unsigned long)PROC}); } @@ -1708,7 +1708,7 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { PWORKSPACE->m_bDefaultPseudo = !PWORKSPACE->m_bDefaultPseudo; // apply - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->m_pWorkspace != PWORKSPACE) continue; @@ -2129,7 +2129,7 @@ SDispatchResult CKeybindManager::setSubmap(std::string submap) { return {}; } - for (auto& k : g_pKeybindManager->m_lKeybinds) { + for (auto const& k : g_pKeybindManager->m_lKeybinds) { if (k.submap == submap) { m_szCurrentSelectedSubmap = submap; Debug::log(LOG, "Changed keybind submap to {}", submap); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 72ff5ae7..80f1ab4f 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -90,7 +90,7 @@ void CPointerManager::unlockSoftwareAll() { } void CPointerManager::lockSoftwareForMonitor(CMonitor* Monitor) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->ID == Monitor->ID) { lockSoftwareForMonitor(m); return; @@ -107,7 +107,7 @@ void CPointerManager::lockSoftwareForMonitor(SP mon) { } void CPointerManager::unlockSoftwareForMonitor(CMonitor* Monitor) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->ID == Monitor->ID) { unlockSoftwareForMonitor(m); return; @@ -225,7 +225,7 @@ void CPointerManager::recheckEnteredOutputs() { auto box = getCursorBoxGlobal(); - for (auto& s : monitorStates) { + for (auto const& s : monitorStates) { if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled) continue; @@ -279,7 +279,7 @@ void CPointerManager::resetCursorImage(bool apply) { currentCursorImage.scale = 1.F; currentCursorImage.hotspot = {0, 0}; - for (auto& s : monitorStates) { + for (auto const& s : monitorStates) { if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled) continue; @@ -289,7 +289,7 @@ void CPointerManager::resetCursorImage(bool apply) { if (!apply) return; - for (auto& ms : monitorStates) { + for (auto const& ms : monitorStates) { if (!ms->monitor || !ms->monitor->m_bEnabled || !ms->monitor->dpmsStatus) { Debug::log(TRACE, "Not updating hw cursors: disabled / dpms off display"); continue; @@ -334,7 +334,7 @@ void CPointerManager::onCursorMoved() { if (!hasCursor()) return; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); @@ -1006,7 +1006,7 @@ void CPointerManager::detachTablet(SP tablet) { } void CPointerManager::damageCursor(SP pMonitor) { - for (auto& mw : monitorStates) { + for (auto const& mw : monitorStates) { if (mw->monitor != pMonitor) continue; diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 801ae55a..e296dcc8 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -24,7 +24,7 @@ void CSeatManager::onNewSeatResource(SP resource) { } SP CSeatManager::containerForResource(SP seatResource) { - for (auto& c : seatResources) { + for (auto const& c : seatResources) { if (c->resource == seatResource) return c; } @@ -112,11 +112,11 @@ void CSeatManager::setKeyboardFocus(SP surf) { if (state.keyboardFocusResource) { auto client = state.keyboardFocusResource->client(); - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != client) continue; - for (auto& k : s->resource->keyboards) { + for (auto const& k : s->resource->keyboards) { if (!k) continue; @@ -134,12 +134,12 @@ void CSeatManager::setKeyboardFocus(SP surf) { } auto client = surf->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.keyboardFocusResource = r->resource; - for (auto& k : r->resource->keyboards) { + for (auto const& k : r->resource->keyboards) { if (!k) continue; @@ -157,11 +157,11 @@ void CSeatManager::sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_ke if (!state.keyboardFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.keyboardFocusResource->client()) continue; - for (auto& k : s->resource->keyboards) { + for (auto const& k : s->resource->keyboards) { if (!k) continue; @@ -174,11 +174,11 @@ void CSeatManager::sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32 if (!state.keyboardFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.keyboardFocusResource->client()) continue; - for (auto& k : s->resource->keyboards) { + for (auto const& k : s->resource->keyboards) { if (!k) continue; @@ -205,11 +205,11 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& if (state.pointerFocusResource) { auto client = state.pointerFocusResource->client(); - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != client) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -230,12 +230,12 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& } auto client = surf->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.pointerFocusResource = r->resource; - for (auto& p : r->resource->pointers) { + for (auto const& p : r->resource->pointers) { if (!p) continue; @@ -257,11 +257,11 @@ void CSeatManager::sendPointerMotion(uint32_t timeMs, const Vector2D& local) { if (!state.pointerFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.pointerFocusResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -276,11 +276,11 @@ void CSeatManager::sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_b if (!state.pointerFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.pointerFocusResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -300,11 +300,11 @@ void CSeatManager::sendPointerFrame(WP pResource) { if (!pResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != pResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -318,11 +318,11 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double if (!state.pointerFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.pointerFocusResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -346,12 +346,12 @@ void CSeatManager::sendTouchDown(SP surf, uint32_t timeMs, i state.touchFocus = surf; auto client = surf->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.touchFocusResource = r->resource; - for (auto& t : r->resource->touches) { + for (auto const& t : r->resource->touches) { if (!t) continue; @@ -372,12 +372,12 @@ void CSeatManager::sendTouchUp(uint32_t timeMs, int32_t id) { return; auto client = state.touchFocusResource->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.touchFocusResource = r->resource; - for (auto& t : r->resource->touches) { + for (auto const& t : r->resource->touches) { if (!t) continue; @@ -395,11 +395,11 @@ void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -412,11 +412,11 @@ void CSeatManager::sendTouchFrame() { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -429,11 +429,11 @@ void CSeatManager::sendTouchCancel() { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -446,11 +446,11 @@ void CSeatManager::sendTouchShape(int32_t id, const Vector2D& shape) { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -463,11 +463,11 @@ void CSeatManager::sendTouchOrientation(int32_t id, double angle) { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index a82432a8..86108cac 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -137,7 +137,7 @@ bool CSessionLockManager::isSurfaceSessionLock(SP pSurface) if (!m_pSessionLock) return false; - for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { + for (auto const& sls : m_pSessionLock->vSessionLockSurfaces) { if (sls->surface->surface() == pSurface) return true; } @@ -154,7 +154,7 @@ void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) { if (g_pCompositor->m_pLastFocus) return; - for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { + for (auto const& sls : m_pSessionLock->vSessionLockSurfaces) { if (!sls->mapped) continue; diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index a6fd97f5..4654eeb7 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -147,7 +147,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { - for (auto& a : pWindow->m_pXWaylandSurface->atoms) + for (auto const& a : pWindow->m_pXWaylandSurface->atoms) if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || @@ -193,7 +193,7 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { if (!pWindow->m_bIsX11) return; - for (auto& a : pWindow->m_pXWaylandSurface->atoms) { + for (auto const& a : pWindow->m_pXWaylandSurface->atoms) { if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) { diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index 2c335a7e..4bcb4df3 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -31,7 +31,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { void CInputManager::recheckIdleInhibitorStatus() { - for (auto& ii : m_vIdleInhibitors) { + for (auto const& ii : m_vIdleInhibitors) { if (ii->nonDesktop) { PROTO::idle->setInhibit(true); return; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index e5f921a2..a4a63a84 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -919,7 +919,7 @@ void CInputManager::setupKeyboard(SP keeb) { } void CInputManager::setKeyboardLayout() { - for (auto& k : m_vKeyboards) + for (auto const& k : m_vKeyboards) applyConfigToKeyboard(k); g_pKeybindManager->updateXKBTranslationState(); @@ -1197,7 +1197,7 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { if (m_vKeyboards.size() > 0) { bool found = false; - for (auto& k : m_vKeyboards | std::views::reverse) { + for (auto const& k : m_vKeyboards | std::views::reverse) { if (!k) continue; @@ -1673,7 +1673,7 @@ void CInputManager::releaseAllMouseButtons() { if (PROTO::data->dndActive()) return; - for (auto& mb : buttonsCopy) { + for (auto const& mb : buttonsCopy) { g_pSeatManager->sendPointerButton(0, mb, WL_POINTER_BUTTON_STATE_RELEASED); } diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 6ee690cd..aa1d3274 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -14,7 +14,7 @@ void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { return; int onMonitor = 0; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && !g_pCompositor->isWorkspaceSpecial(w->m_iID)) { onMonitor++; } @@ -38,7 +38,7 @@ void CInputManager::beginWorkspaceSwipe() { m_sActiveSwipe.speedPoints = 0; if (PWORKSPACE->m_bHasFullscreenWindow) { - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { + for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = 1.f; } } @@ -193,7 +193,7 @@ void CInputManager::endWorkspaceSwipe() { g_pInputManager->refocus(); // apply alpha - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { + for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 5e50e851..23d328bc 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -14,7 +14,7 @@ static void unfocusTool(SP tool) { tool->setSurface(nullptr); if (tool->isDown) PROTO::tablet->up(tool); - for (auto& b : tool->buttonsDown) { + for (auto const& b : tool->buttonsDown) { PROTO::tablet->buttonTool(tool, b, false); } PROTO::tablet->proximityOut(tool); @@ -31,7 +31,7 @@ static void focusTool(SP tool, SP tablet, SPproximityIn(tool, tablet, surf); if (tool->isDown) PROTO::tablet->down(tool); - for (auto& b : tool->buttonsDown) { + for (auto const& b : tool->buttonsDown) { PROTO::tablet->buttonTool(tool, b, true); } } diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index 9118456b..745b2593 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -81,7 +81,7 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr std::vector finalBytes; finalBytes.resize(probe.len); - for (auto& len : probe.insSizes) { + for (auto const& len : probe.insSizes) { // copy original bytes to our finalBytes for (size_t i = 0; i < len; ++i) { diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index bc0945f1..f906740c 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -50,12 +50,12 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPmonitor->isBeingLeased = true; } listeners.destroyLease = lease->events.destroy.registerListener([this](std::any d) { - for (auto& m : requested) { + for (auto const& m : requested) { if (m && m->monitor) m->monitor->isBeingLeased = false; } diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index ad6ee89a..dce64508 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -291,7 +291,7 @@ void CDataDeviceWLRProtocol::sendSelectionToDevice(SP dev, SP source, bool primary) { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->source && o->source->hasDnd()) continue; if (o->primary != primary) @@ -302,7 +302,7 @@ void CDataDeviceWLRProtocol::setSelection(SP source, bool primary) if (!source) { LOGM(LOG, "resetting {}selection", primary ? "primary " : " "); - for (auto& d : m_vDevices) { + for (auto const& d : m_vDevices) { sendSelectionToDevice(d, nullptr, primary); } @@ -311,7 +311,7 @@ void CDataDeviceWLRProtocol::setSelection(SP source, bool primary) LOGM(LOG, "New {}selection for data source {:x}", primary ? "primary" : "", (uintptr_t)source.get()); - for (auto& d : m_vDevices) { + for (auto const& d : m_vDevices) { sendSelectionToDevice(d, source, primary); } } diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 8b6f46b1..75f1e646 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -260,7 +260,7 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std for (auto& n : nodes) { std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); // subsurfaces is sorted lowest -> highest - for (auto& c : n->subsurfaces) { + for (auto const& c : n->subsurfaces) { if (c->zIndex >= 0) break; if (c->surface.expired()) @@ -274,7 +274,7 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std nodes2.clear(); - for (auto& n : nodes) { + for (auto const& n : nodes) { Vector2D offset = {}; if (n->role->role() == SURFACE_ROLE_SUBSURFACE) { auto subsurface = ((CSubsurfaceRole*)n->role.get())->subsurface.lock(); @@ -284,8 +284,8 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std fn(n, offset, data); } - for (auto& n : nodes) { - for (auto& c : n->subsurfaces) { + for (auto const& n : nodes) { + for (auto const& c : n->subsurfaces) { if (c->zIndex < 0) continue; if (c->surface.expired()) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 4ed28f24..943c790f 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -306,7 +306,7 @@ CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SPself = RESOURCE; - for (auto& s : sources) { + for (auto const& s : sources) { if (!s) continue; s->device = RESOURCE; @@ -390,7 +390,7 @@ void CWLDataDeviceProtocol::onDestroyDataSource(WP source } void CWLDataDeviceProtocol::setSelection(SP source) { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->source && o->source->hasDnd()) continue; o->dead = true; @@ -439,7 +439,7 @@ void CWLDataDeviceProtocol::updateSelection() { } void CWLDataDeviceProtocol::onKeyboardFocus() { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { o->dead = true; } @@ -606,7 +606,7 @@ bool CWLDataDeviceProtocol::wasDragSuccessful() { if (!dnd.focusedDevice || !dnd.currentSource) return false; - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->dead || !o->source || !o->source->hasDnd()) continue; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 8d0b0121..bcf62fae 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -118,7 +118,7 @@ bool CWLOutputProtocol::isDefunct() { } void CWLOutputProtocol::sendDone() { - for (auto& r : m_vOutputs) { + for (auto const& r : m_vOutputs) { r->resource->sendDone(); } } diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index a111c12c..f7764389 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -172,7 +172,7 @@ void CWLPointerResource::sendLeave() { if (!PROTO::data->dndActive()) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - for (auto& b : pressedButtons) { + for (auto const& b : pressedButtons) { sendButton(now.tv_sec * 1000 + now.tv_nsec / 1000000, b, WL_POINTER_BUTTON_STATE_RELEASED); } } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 63cc2203..2aeda8be 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -690,7 +690,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { } if (*PBLURSPECIAL) { - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (!ws->m_bIsSpecialWorkspace || ws->m_iMonitorID != pMonitor->ID) continue; @@ -1936,9 +1936,9 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { } } - for (auto& m : g_pCompositor->m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& m : g_pCompositor->m_vMonitors) { + for (auto const& lsl : m->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { if (!ls->layerSurface || ls->xray != 1) continue; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c2ecbbf3..2ef7e208 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -331,7 +331,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) { if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) return true; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) return true; @@ -915,7 +915,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC g_pHyprOpenGL->m_RenderData.damage = preOccludedDamage; // and then special - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_iMonitorID == pMonitor->ID && ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { const auto SPECIALANIMPROGRS = ws->m_vRenderOffset.isBeingAnimated() ? ws->m_vRenderOffset.getCurveValue() : ws->m_fAlpha.getCurveValue(); const bool ANIMOUT = !pMonitor->activeSpecialWorkspace; @@ -935,7 +935,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } // special - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { if (ws->m_bHasFullscreenWindow) renderWorkspaceWindowsFullscreen(pMonitor, ws, time); @@ -1489,7 +1489,7 @@ void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, } void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface->resource()) continue; @@ -1499,8 +1499,8 @@ void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE w->m_pWLSurface->resource()->breadthfirst([now](SP r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } - for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& lsl : pMonitor->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { if (ls->fadingOut || !ls->surface->resource()) continue; @@ -1673,10 +1673,10 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; - for (auto& la : PMONITOR->m_aLayerSurfaceLayers) + for (auto const& la : PMONITOR->m_aLayerSurfaceLayers) arrangeLayerArray(PMONITOR, la, true, &usableArea); - for (auto& la : PMONITOR->m_aLayerSurfaceLayers) + for (auto const& la : PMONITOR->m_aLayerSurfaceLayers) arrangeLayerArray(PMONITOR, la, false, &usableArea); PMONITOR->vecReservedTopLeft = Vector2D(usableArea.x, usableArea.y) - PMONITOR->vecPosition; @@ -1808,7 +1808,7 @@ void CHyprRenderer::damageBox(const int& x, const int& y, const int& w, const in } void CHyprRenderer::damageRegion(const CRegion& rg) { - for (auto& RECT : rg.getRects()) { + for (auto const& RECT : rg.getRects()) { damageBox(RECT.x1, RECT.y1, RECT.x2 - RECT.x1, RECT.y2 - RECT.y1); } } @@ -2370,7 +2370,7 @@ std::tuple CHyprRenderer::getRenderTimes(CMonitor* pMonitor float avgRenderTime = 0; float maxRenderTime = 0; float minRenderTime = 9999; - for (auto& rt : POVERLAY->m_dLastRenderTimes) { + for (auto const& rt : POVERLAY->m_dLastRenderTimes) { if (rt > maxRenderTime) maxRenderTime = rt; if (rt < minRenderTime) @@ -2528,12 +2528,12 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { if (!pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty()) return; - for (auto& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { if (topls->alpha.value() != 0.f) return; } - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w == PCANDIDATE || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isHidden()) continue; diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 30ffbc68..02fe2b3b 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -151,8 +151,8 @@ bool CXWaylandSurface::wantsFocus() { HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"], }; - for (auto& searched : search) { - for (auto& a : atoms) { + for (auto const& searched : search) { + for (auto const& a : atoms) { if (a == searched) return false; } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index a409b440..995ec7f2 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -24,7 +24,7 @@ static int onX11Event(int fd, uint32_t mask, void* data) { } SP CXWM::windowForXID(xcb_window_t wid) { - for (auto& s : surfaces) { + for (auto const& s : surfaces) { if (s->xID == wid) return s; } @@ -156,7 +156,7 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ std::string propName; if (Debug::trace) { propName = std::format("{}?", atom); - for (auto& ha : HYPRATOMS) { + for (auto const& ha : HYPRATOMS) { if (ha.second != atom) continue; @@ -285,7 +285,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { return; std::string propName = "?"; - for (auto& ha : HYPRATOMS) { + for (auto const& ha : HYPRATOMS) { if (ha.second != e->type) continue; @@ -317,7 +317,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { Debug::log(LOG, "[xwm] surface {:x} requests serial {:x}", (uintptr_t)XSURF.get(), XSURF->wlSerial); - for (auto& res : shellResources) { + for (auto const& res : shellResources) { if (!res) continue; @@ -579,7 +579,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { atoms.push_back(HYPRATOMS["TIMESTAMP"]); atoms.push_back(HYPRATOMS["TARGETS"]); - for (auto& m : mimes) { + for (auto const& m : mimes) { atoms.push_back(mimeToAtom(m)); } @@ -944,7 +944,7 @@ void CXWM::onNewSurface(SP surf) { const auto WLID = surf->id(); - for (auto& sr : surfaces) { + for (auto const& sr : surfaces) { if (sr->surface || sr->wlID != WLID) continue; @@ -961,7 +961,7 @@ void CXWM::onNewResource(SP resource) { std::erase_if(shellResources, [](const auto& e) { return e.expired(); }); shellResources.push_back(resource); - for (auto& surf : surfaces) { + for (auto const& surf : surfaces) { if (surf->resource || surf->wlSerial != resource->serial) continue; From 1ea47950f4262ec1215087948c7275f8e0115af2 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 18:02:44 +0200 Subject: [PATCH 090/298] misc: fix some minor typos (#7530) * keybindmgr: fix typo in swap prev seems a suspicious extra ) got added, remove it. * configmgr: dont dereference invalid iterator i think the idea here was to print the key and not the iterator at or past .end() --- src/config/ConfigManager.cpp | 2 +- src/managers/KeybindManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 007869ee..5ce380a0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1720,7 +1720,7 @@ static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { if (it != flagsmap.end()) mode.flags |= it->second; else - Debug::log(ERR, "invalid flag {} in modeline", it->first); + Debug::log(ERR, "invalid flag {} in modeline", key); } snprintf(mode.name, sizeof(mode.name), "%dx%d@%d", mode.hdisplay, mode.vdisplay, mode.vrefresh / 1000); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 7eb96730..9fac656c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2441,7 +2441,7 @@ SDispatchResult CKeybindManager::swapnext(std::string arg) { // sometimes we may come back to ourselves. if (toSwap == PLASTWINDOW) { if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") - toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW), true; + toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true); else toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true); } From 72c7818ae66a18d126e2b4245d649fe3a93d3b8e Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 20:24:30 +0200 Subject: [PATCH 091/298] misc: constify the remaining for loops (#7534) now we roll loops at blazing constified speed. --- hyprctl/main.cpp | 4 +- hyprpm/src/core/DataState.cpp | 2 +- hyprpm/src/core/Manifest.cpp | 4 +- hyprpm/src/core/PluginManager.cpp | 38 +++--- src/Compositor.cpp | 112 +++++++++--------- src/config/ConfigManager.cpp | 26 ++-- src/debug/HyprCtl.cpp | 74 ++++++------ src/debug/HyprDebugOverlay.cpp | 2 +- src/debug/HyprNotificationOverlay.cpp | 4 +- src/desktop/LayerSurface.cpp | 2 +- src/desktop/Popup.cpp | 10 +- src/desktop/Subsurface.cpp | 6 +- src/desktop/Window.cpp | 16 +-- src/desktop/Workspace.cpp | 4 +- src/events/Windows.cpp | 4 +- src/helpers/BezierCurve.cpp | 2 +- src/helpers/Format.cpp | 4 +- src/helpers/MiscFunctions.cpp | 12 +- src/helpers/Monitor.cpp | 22 ++-- src/layout/DwindleLayout.cpp | 4 +- src/layout/IHyprLayout.cpp | 6 +- src/layout/MasterLayout.cpp | 10 +- src/managers/AnimationManager.cpp | 10 +- src/managers/CursorManager.cpp | 6 +- src/managers/HookSystemManager.cpp | 4 +- src/managers/KeybindManager.cpp | 12 +- src/managers/PointerManager.cpp | 20 ++-- src/managers/ProtocolManager.cpp | 2 +- src/managers/SeatManager.cpp | 2 +- src/managers/SessionLockManager.cpp | 6 +- src/managers/XCursorManager.cpp | 2 +- src/managers/XWaylandManager.cpp | 2 +- src/managers/eventLoop/EventLoopManager.cpp | 10 +- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.cpp | 20 ++-- src/managers/input/InputMethodRelay.cpp | 14 +-- src/managers/input/Tablets.cpp | 2 +- src/plugins/PluginAPI.cpp | 4 +- src/plugins/PluginSystem.cpp | 20 ++-- src/protocols/DRMLease.cpp | 12 +- src/protocols/DataDeviceWlr.cpp | 4 +- src/protocols/FocusGrab.cpp | 2 +- src/protocols/ForeignToplevel.cpp | 8 +- src/protocols/ForeignToplevelWlr.cpp | 16 +-- src/protocols/FractionalScale.cpp | 2 +- src/protocols/GammaControl.cpp | 4 +- src/protocols/GlobalShortcuts.cpp | 12 +- src/protocols/IdleNotify.cpp | 4 +- src/protocols/InputMethodV2.cpp | 10 +- src/protocols/LinuxDMABUF.cpp | 20 ++-- src/protocols/MesaDRM.cpp | 6 +- src/protocols/OutputManagement.cpp | 24 ++-- src/protocols/PointerGestures.cpp | 16 +-- src/protocols/PresentationTime.cpp | 4 +- src/protocols/PrimarySelection.cpp | 8 +- src/protocols/RelativePointer.cpp | 2 +- src/protocols/Screencopy.cpp | 8 +- src/protocols/SessionLock.cpp | 2 +- src/protocols/ShortcutsInhibit.cpp | 4 +- src/protocols/Tablet.cpp | 58 ++++----- src/protocols/TearingControl.cpp | 4 +- src/protocols/ToplevelExport.cpp | 6 +- src/protocols/VirtualKeyboard.cpp | 2 +- src/protocols/XDGOutput.cpp | 4 +- src/protocols/XDGShell.cpp | 6 +- src/protocols/core/Compositor.cpp | 6 +- src/protocols/core/DataDevice.cpp | 2 +- src/protocols/core/Output.cpp | 4 +- src/protocols/core/Seat.cpp | 8 +- src/protocols/core/Shm.cpp | 4 +- src/protocols/core/Subcompositor.cpp | 4 +- src/render/OpenGL.cpp | 54 ++++----- src/render/Renderer.cpp | 88 +++++++------- src/render/Texture.cpp | 2 +- .../decorations/CHyprBorderDecoration.cpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- .../decorations/DecorationPositioner.cpp | 6 +- src/xwayland/XWM.cpp | 6 +- 79 files changed, 472 insertions(+), 472 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 5d5113b8..1ad189b7 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -287,12 +287,12 @@ void instancesRequest(bool json) { std::vector inst = instances(); if (!json) { - for (auto& el : inst) { + for (auto const& el : inst) { result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket); } } else { result += '['; - for (auto& el : inst) { + for (auto const& el : inst) { result += std::format(R"#( {{ "instance": "{}", diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp index 61ad336f..05c63f4e 100644 --- a/hyprpm/src/core/DataState.cpp +++ b/hyprpm/src/core/DataState.cpp @@ -49,7 +49,7 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) { {"rev", repo.rev} }} }; - for (auto& p : repo.plugins) { + for (auto const& p : repo.plugins) { // copy .so to the good place if (std::filesystem::exists(p.filename)) std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so"); diff --git a/hyprpm/src/core/Manifest.cpp b/hyprpm/src/core/Manifest.cpp index 42a8357c..754d9d69 100644 --- a/hyprpm/src/core/Manifest.cpp +++ b/hyprpm/src/core/Manifest.cpp @@ -6,7 +6,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { auto manifest = toml::parse_file(path); if (type == MANIFEST_HYPRLOAD) { - for (auto& [key, val] : manifest) { + for (auto const& [key, val] : manifest) { if (key.str().ends_with(".build")) continue; @@ -63,7 +63,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { } } - for (auto& [key, val] : manifest) { + for (auto const& [key, val] : manifest) { if (key.str() == "repository") continue; diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index ab457ca6..669789b4 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -204,9 +204,9 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.m_iSteps = 2; progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"); - for (auto& pl : pManifest->m_vPlugins) { + for (auto const& pl : pManifest->m_vPlugins) { std::string message = std::string{Colors::RESET} + " → " + pl.name + " by "; - for (auto& a : pl.authors) { + for (auto const& a : pl.authors) { message += a + ", "; } if (pl.authors.size() > 0) { @@ -222,7 +222,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); - for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) { + for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; @@ -264,7 +264,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); - for (auto& bs : p.buildSteps) { + for (auto const& bs : p.buildSteps) { std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } @@ -299,7 +299,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& repo.url = url; repo.rev = rev; repo.hash = repohash; - for (auto& p : pManifest->m_vPlugins) { + for (auto const& p : pManifest->m_vPlugins) { repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed}); } DataState::addNewPluginRepo(repo); @@ -579,7 +579,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { const std::string USERNAME = getpwuid(getuid())->pw_name; m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME; - for (auto& repo : REPOS) { + for (auto const& repo : REPOS) { bool update = forceUpdateAll; progress.m_iSteps++; @@ -658,7 +658,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); - for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) { + for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; @@ -679,7 +679,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); - for (auto& bs : p.buildSteps) { + for (auto const& bs : p.buildSteps) { std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } @@ -709,7 +709,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { if (repohash.length() > 0) repohash.pop_back(); newrepo.hash = repohash; - for (auto& p : pManifest->m_vPlugins) { + for (auto const& p : pManifest->m_vPlugins) { const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; }); newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false}); } @@ -794,8 +794,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { const auto REPOS = DataState::getAllRepositories(); auto enabled = [REPOS](const std::string& plugin) -> bool { - for (auto& r : REPOS) { - for (auto& p : r.plugins) { + for (auto const& r : REPOS) { + for (auto const& p : r.plugins) { if (p.name == plugin && p.enabled) return true; } @@ -805,8 +805,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { }; auto repoForName = [REPOS](const std::string& name) -> std::string { - for (auto& r : REPOS) { - for (auto& p : r.plugins) { + for (auto const& r : REPOS) { + for (auto const& p : r.plugins) { if (p.name == name) return r.name; } @@ -816,7 +816,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { }; // unload disabled plugins - for (auto& p : loadedPlugins) { + for (auto const& p : loadedPlugins) { if (!enabled(p)) { // unload loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false); @@ -825,8 +825,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { } // load enabled plugins - for (auto& r : REPOS) { - for (auto& p : r.plugins) { + for (auto const& r : REPOS) { + for (auto const& p : r.plugins) { if (!p.enabled) continue; @@ -855,10 +855,10 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) { void CPluginManager::listAllPlugins() { const auto REPOS = DataState::getAllRepositories(); - for (auto& r : REPOS) { + for (auto const& r : REPOS) { std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n"; - for (auto& p : r.plugins) { + for (auto const& p : r.plugins) { std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name; @@ -905,7 +905,7 @@ std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { bool CPluginManager::hasDeps() { std::vector deps = {"meson", "cpio", "cmake", "pkg-config"}; - for (auto& d : deps) { + for (auto const& d : deps) { if (!execAndGet("command -v " + d).contains("/")) return false; } diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 0aa7f213..cacbeece 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -391,7 +391,7 @@ void CCompositor::initAllSignals() { m_bSessionActive = true; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { scheduleFrameForMonitor(m.get()); g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); } @@ -477,7 +477,7 @@ void CCompositor::cleanup() { m_vWorkspaces.clear(); m_vWindows.clear(); - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { g_pHyprOpenGL->destroyMonitorResources(m.get()); m->output->state->setEnabled(false); @@ -641,7 +641,7 @@ void CCompositor::removeLockFile() { void CCompositor::prepareFallbackOutput() { // create a backup monitor SP headless; - for (auto& impl : m_pAqBackend->getImplementations()) { + for (auto const& impl : m_pAqBackend->getImplementations()) { if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) { headless = impl; break; @@ -698,7 +698,7 @@ void CCompositor::startCompositor() { } CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->ID == id) { return m.get(); } @@ -708,7 +708,7 @@ CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { } CMonitor* CCompositor::getMonitorFromName(const std::string& name) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->szName == name) { return m.get(); } @@ -717,7 +717,7 @@ CMonitor* CCompositor::getMonitorFromName(const std::string& name) { } CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->szDescription.starts_with(desc)) return m.get(); } @@ -730,7 +730,7 @@ CMonitor* CCompositor::getMonitorFromCursor() { CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { SP mon; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { mon = m; break; @@ -771,7 +771,7 @@ void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { } bool CCompositor::monitorExists(CMonitor* pMonitor) { - for (auto& m : m_vRealMonitors) { + for (auto const& m : m_vRealMonitors) { if (m.get() == pMonitor) return true; } @@ -789,7 +789,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper // pinned windows on top of floating regardless if (properties & ALLOW_FLOATING) { - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && @@ -807,7 +807,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper auto windowForWorkspace = [&](bool special) -> PHLWINDOW { auto floating = [&](bool aboveFullscreen) -> PHLWINDOW { - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular continue; @@ -870,7 +870,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper return found; // for windows, we need to check their extensions too, first. - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (special != w->onSpecialWorkspace()) continue; @@ -881,7 +881,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper } } - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (special != w->onSpecialWorkspace()) continue; @@ -963,7 +963,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo } CMonitor* CCompositor::getMonitorFromOutput(SP out) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->output == out) { return m.get(); } @@ -973,7 +973,7 @@ CMonitor* CCompositor::getMonitorFromOutput(SP out) { } CMonitor* CCompositor::getRealMonitorFromOutput(SP out) { - for (auto& m : m_vRealMonitors) { + for (auto const& m : m_vRealMonitors) { if (m->output == out) { return m.get(); } @@ -1212,7 +1212,7 @@ PHLWINDOW CCompositor::getWindowFromSurface(SP pSurface) { } PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if ((uint32_t)(((uint64_t)w.get()) & 0xFFFFFFFF) == handle) { return w; } @@ -1222,7 +1222,7 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { } PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == ID && w->isFullscreen()) return w; } @@ -1246,7 +1246,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { } PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) { - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_iID == id && !w->inert()) return w; } @@ -1271,7 +1271,7 @@ void CCompositor::sanityCheckWorkspaces() { int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) continue; if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) @@ -1286,7 +1286,7 @@ int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) continue; if (!w->m_sGroupData.head) @@ -1301,7 +1301,7 @@ int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional } PHLWINDOW CCompositor::getUrgentWindow() { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_bIsMapped && w->m_bIsUrgent) return w; } @@ -1310,7 +1310,7 @@ PHLWINDOW CCompositor::getUrgentWindow() { } bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent) return true; } @@ -1319,7 +1319,7 @@ bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) { } PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden()) return w; } @@ -1335,7 +1335,7 @@ PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) { const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden()) continue; @@ -1400,7 +1400,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { else toMove.emplace_front(pw); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) { x11Stack(w, top, x11Stack); } @@ -1416,7 +1416,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { } void CCompositor::cleanupFadingOut(const MONITORID& monid) { - for (auto& ww : m_vWindowsFadingOut) { + for (auto const& ww : m_vWindowsFadingOut) { auto w = ww.lock(); @@ -1441,7 +1441,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { bool layersDirty = false; - for (auto& lsr : m_vSurfacesFadingOut) { + for (auto const& lsr : m_vSurfacesFadingOut) { auto ls = lsr.lock(); @@ -1530,7 +1530,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (!pWindow->m_bIsFloating) { // for tiled windows, we calc edges - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; @@ -1622,7 +1622,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { float bestAngleAbs = 2.0 * M_PI; constexpr float THRESHOLD = 0.3 * M_PI; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; @@ -1660,7 +1660,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { bool gotToWindow = false; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w != pWindow && !gotToWindow) continue; @@ -1676,7 +1676,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl return w; } - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; @@ -1689,7 +1689,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { bool gotToWindow = false; - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { if (w != pWindow && !gotToWindow) continue; @@ -1705,7 +1705,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl return w; } - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; @@ -1727,7 +1727,7 @@ WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { } PHLWORKSPACE CCompositor::getWorkspaceByName(const std::string& name) { - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_szName == name && !w->inert()) return w; } @@ -1779,7 +1779,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha auto longestIntersect = -1; CMonitor* longestIntersectMonitor = nullptr; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m == m_pLastMonitor) continue; @@ -1843,7 +1843,7 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() { } void CCompositor::updateWorkspaceWindows(const int64_t& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped || w->workspaceID() != id) continue; @@ -1968,7 +1968,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) PWORKSPACEA->m_iMonitorID = pMonitorB->ID; PWORKSPACEA->moveToMonitor(pMonitorB->ID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == PWORKSPACEA) { if (w->m_bPinned) { w->m_pWorkspace = PWORKSPACEB; @@ -1993,7 +1993,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) PWORKSPACEB->m_iMonitorID = pMonitorA->ID; PWORKSPACEB->moveToMonitor(pMonitorA->ID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == PWORKSPACEB) { if (w->m_bPinned) { w->m_pWorkspace = PWORKSPACEA; @@ -2108,7 +2108,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { return nullptr; } } else { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (!m->output) continue; @@ -2168,7 +2168,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon pWorkspace->m_iMonitorID = pMonitor->ID; pWorkspace->moveToMonitor(pMonitor->ID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == pWorkspace) { if (w->m_bPinned) { w->m_pWorkspace = g_pCompositor->getWorkspaceByID(nextWorkspaceOnMonitorID); @@ -2255,7 +2255,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pWorkspace) { if (w->m_bFadingOut || w->m_bPinned || w->isFullscreen()) @@ -2347,7 +2347,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); // make all windows on the same workspace under the fullscreen window - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == PWORKSPACE && !w->isFullscreen() && !w->m_bFadingOut && !w->m_bPinned) w->m_bCreatedOverFullscreen = false; } @@ -2388,7 +2388,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { } void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id) continue; @@ -2400,7 +2400,7 @@ void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) { const auto PWORKSPACE = getWorkspaceByID(id); const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id) continue; @@ -2453,7 +2453,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { const bool FLOAT = regexp.starts_with("floating"); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden()) continue; @@ -2463,7 +2463,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { return nullptr; } - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || (w->isHidden() && !g_pLayoutManager->getCurrentLayout()->isWindowReachable(w))) continue; @@ -2617,7 +2617,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con } void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) { g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); } @@ -2744,7 +2744,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor } PHLWINDOW CCompositor::getForceFocus() { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace)) continue; @@ -2763,7 +2763,7 @@ void CCompositor::arrangeMonitors() { std::vector toArrange; std::vector arranged; - for (auto& m : m_vMonitors) + for (auto const& m : m_vMonitors) toArrange.push_back(m.get()); Debug::log(LOG, "arrangeMonitors: {} to arrange", toArrange.size()); @@ -2795,7 +2795,7 @@ void CCompositor::arrangeMonitors() { int maxYOffsetDown = 0; // Finds the max and min values of explicitely placed monitors. - for (auto& m : arranged) { + for (auto const& m : arranged) { if (m->vecPosition.x + m->vecSize.x > maxXOffsetRight) maxXOffsetRight = m->vecPosition.x + m->vecSize.x; if (m->vecPosition.x < maxXOffsetLeft) @@ -2807,7 +2807,7 @@ void CCompositor::arrangeMonitors() { } // Iterates through all non-explicitly placed monitors. - for (auto& m : toArrange) { + for (auto const& m : toArrange) { // Moves the monitor to their appropriate position on the x/y axis and // increments/decrements the corresponding max offset. Vector2D newPosition = {0, 0}; @@ -2838,7 +2838,7 @@ void CCompositor::arrangeMonitors() { // reset maxXOffsetRight (reuse) // and set xwayland positions aka auto for all maxXOffsetRight = 0; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { Debug::log(LOG, "arrangeMonitors: {} xwayland [{}, {}]", m->szName, maxXOffsetRight, 0); m->vecXWaylandPosition = {maxXOffsetRight, 0}; maxXOffsetRight += (*PXWLFORCESCALEZERO ? m->vecTransformedSize.x : m->vecSize.x); @@ -2873,7 +2873,7 @@ void CCompositor::leaveUnsafeState() { m_bUnsafeState = false; CMonitor* pNewMonitor = nullptr; - for (auto& pMonitor : m_vMonitors) { + for (auto const& pMonitor : m_vMonitors) { if (pMonitor->output != m_pUnsafeOutput->output) { pNewMonitor = pMonitor.get(); break; @@ -2885,7 +2885,7 @@ void CCompositor::leaveUnsafeState() { if (m_pUnsafeOutput->m_bEnabled) m_pUnsafeOutput->onDisconnect(); - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { scheduleFrameForMonitor(m.get()); } } @@ -2917,7 +2917,7 @@ void CCompositor::setPreferredTransformForSurface(SP pSurfac } void CCompositor::updateSuspendedStates() { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped) continue; @@ -2926,7 +2926,7 @@ void CCompositor::updateSuspendedStates() { } PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w.get() != pWindow) continue; @@ -2970,7 +2970,7 @@ void CCompositor::onNewMonitor(SP output) { g_pConfigManager->m_bWantsMonitorReload = true; g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { w->m_iLastSurfaceMonitorID = MONITOR_INVALID; w->updateSurfaceScaleTransformDetails(); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5ce380a0..f402958b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -45,7 +45,7 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** std::string parseError = ""; - for (auto& var : varlist) { + for (auto const& var : varlist) { if (var.find("deg") != std::string::npos) { // last arg try { @@ -863,7 +863,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { refreshGroupBarGradients(); // Updates dynamic window and workspace rules - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->inert()) continue; g_pCompositor->updateWorkspaceWindows(w->m_iID); @@ -891,7 +891,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { Debug::coloredLogs = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:colored_stdout_logs")->getDataStaticPtr()); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { // mark blur dirty g_pHyprOpenGL->markBlurDirtyForMonitor(m.get()); @@ -978,7 +978,7 @@ void CConfigManager::tick() { bool parse = false; - for (auto& cf : configPaths) { + for (auto const& cf : configPaths) { struct stat fileStat; int err = stat(cf.c_str(), &fileStat); if (err != 0) { @@ -1059,7 +1059,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) { SWorkspaceRule mergedRule{}; - for (auto& rule : m_dWorkspaceRules) { + for (auto const& rule : m_dWorkspaceRules) { if (!pWorkspace->matchesStaticSelector(rule.workspaceString)) continue; @@ -1132,7 +1132,7 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo // local tags for dynamic tag rule match auto tags = pWindow->m_tags; - for (auto& rule : m_dWindowRules) { + for (auto const& rule : m_dWindowRules) { // check if we have a matching rule if (!rule.v2) { try { @@ -1297,7 +1297,7 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo bool anyExecFound = false; - for (auto& er : execRequestedRules) { + for (auto const& er : execRequestedRules) { if (std::ranges::any_of(PIDs, [&](const auto& pid) { return pid == er.iPid; })) { returns.push_back({er.szRule, "execRule"}); anyExecFound = true; @@ -1317,7 +1317,7 @@ std::vector CConfigManager::getMatchingRules(PHLLS pLS) { if (!pLS->layerSurface || pLS->fadingOut) return returns; - for (auto& lr : m_dLayerRules) { + for (auto const& lr : m_dLayerRules) { if (lr.targetNamespace.starts_with("address:0x")) { if (std::format("address:0x{:x}", (uintptr_t)pLS.get()) != lr.targetNamespace) continue; @@ -1391,7 +1391,7 @@ void CConfigManager::performMonitorReload() { bool overAgain = false; - for (auto& m : g_pCompositor->m_vRealMonitors) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { if (!m->output || m->isUnsafeFallback) continue; @@ -1448,7 +1448,7 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) { } void CConfigManager::ensureMonitorStatus() { - for (auto& rm : g_pCompositor->m_vRealMonitors) { + for (auto const& rm : g_pCompositor->m_vRealMonitors) { if (!rm->output || rm->isUnsafeFallback) continue; @@ -1531,7 +1531,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { return; } - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { ensureVRRForDisplay(m.get()); } } @@ -1632,7 +1632,7 @@ void CConfigManager::removePluginConfig(HANDLE handle) { } std::erase_if(pluginKeywords, [&](const auto& other) { return other.handle == handle; }); - for (auto& [h, n] : pluginVariables) { + for (auto const& [h, n] : pluginVariables) { if (h != handle) continue; @@ -2534,7 +2534,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin }; CVarList rulesList{rules, 0, ',', true}; - for (auto& r : rulesList) { + for (auto const& r : rulesList) { const auto R = assignRule(r); if (R.has_value()) return R; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 2fc5cc7d..40708cf8 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -57,7 +57,7 @@ static std::string formatToString(uint32_t drmFormat) { static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { std::string result; - for (auto& m : pMonitor->output->modes) { + for (auto const& m : pMonitor->output->modes) { if (format == FORMAT_NORMAL) result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0); else @@ -445,13 +445,13 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) { escapeJSONStrings(mon->szName)); int layerLevel = 0; - for (auto& level : mon->m_aLayerSurfaceLayers) { + for (auto const& level : mon->m_aLayerSurfaceLayers) { result += std::format( R"#( "{}": [ )#", layerLevel); - for (auto& layer : level) { + for (auto const& layer : level) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -484,14 +484,14 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n}\n"; } else { - for (auto& mon : g_pCompositor->m_vMonitors) { + for (auto const& mon : g_pCompositor->m_vMonitors) { result += std::format("Monitor {}:\n", mon->szName); int layerLevel = 0; static const std::array levelNames = {"background", "bottom", "top", "overlay"}; - for (auto& level : mon->m_aLayerSurfaceLayers) { + for (auto const& level : mon->m_aLayerSurfaceLayers) { result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]); - for (auto& layer : level) { + for (auto const& layer : level) { result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, layer->szNamespace); } @@ -510,7 +510,7 @@ std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& m : g_pLayoutManager->getAllLayoutNames()) { + for (auto const& m : g_pLayoutManager->getAllLayoutNames()) { result += std::format( R"#( "{}",)#", @@ -520,7 +520,7 @@ std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n]\n"; } else { - for (auto& m : g_pLayoutManager->getAllLayoutNames()) { + for (auto const& m : g_pLayoutManager->getAllLayoutNames()) { result += std::format("{}\n", m); } } @@ -557,7 +557,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "{\n"; result += "\"mice\": [\n"; - for (auto& m : g_pInputManager->m_vPointers) { + for (auto const& m : g_pInputManager->m_vPointers) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -572,7 +572,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n],\n"; result += "\"keyboards\": [\n"; - for (auto& k : g_pInputManager->m_vKeyboards) { + for (auto const& k : g_pInputManager->m_vKeyboards) { const auto KM = k->getActiveLayout(); result += std::format( R"#( {{ @@ -596,7 +596,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\"tablets\": [\n"; - for (auto& d : g_pInputManager->m_vTabletPads) { + for (auto const& d : g_pInputManager->m_vTabletPads) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -609,7 +609,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { (uintptr_t)d.get(), (uintptr_t)d->parent.get(), escapeJSONStrings(d->parent ? d->parent->hlName : "")); } - for (auto& d : g_pInputManager->m_vTablets) { + for (auto const& d : g_pInputManager->m_vTablets) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -618,7 +618,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { (uintptr_t)d.get(), escapeJSONStrings(d->hlName)); } - for (auto& d : g_pInputManager->m_vTabletTools) { + for (auto const& d : g_pInputManager->m_vTabletTools) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -632,7 +632,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\"touch\": [\n"; - for (auto& d : g_pInputManager->m_vTouches) { + for (auto const& d : g_pInputManager->m_vTouches) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -646,7 +646,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\"switches\": [\n"; - for (auto& d : g_pInputManager->m_lSwitches) { + for (auto const& d : g_pInputManager->m_lSwitches) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -663,14 +663,14 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { } else { result += "mice:\n"; - for (auto& m : g_pInputManager->m_vPointers) { + for (auto const& m : g_pInputManager->m_vPointers) { result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName, (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f)); } result += "\n\nKeyboards:\n"; - for (auto& k : g_pInputManager->m_vKeyboards) { + for (auto const& k : g_pInputManager->m_vKeyboards) { const auto KM = k->getActiveLayout(); result += std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tmain: {}\n", (uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, @@ -679,27 +679,27 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n\nTablets:\n"; - for (auto& d : g_pInputManager->m_vTabletPads) { + for (auto const& d : g_pInputManager->m_vTabletPads) { result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)d.get(), (uintptr_t)d->parent.get(), d->parent ? d->parent->hlName : ""); } - for (auto& d : g_pInputManager->m_vTablets) { + for (auto const& d : g_pInputManager->m_vTablets) { result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->aq()->physicalSize.x, d->aq()->physicalSize.y); } - for (auto& d : g_pInputManager->m_vTabletTools) { + for (auto const& d : g_pInputManager->m_vTabletTools) { result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get()); } result += "\n\nTouch:\n"; - for (auto& d : g_pInputManager->m_vTouches) { + for (auto const& d : g_pInputManager->m_vTouches) { result += std::format("\tTouch Device at {:x}:\n\t\t{}\n", (uintptr_t)d.get(), d->hlName); } result += "\n\nSwitches:\n"; - for (auto& d : g_pInputManager->m_lSwitches) { + for (auto const& d : g_pInputManager->m_lSwitches) { result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : ""); } } @@ -712,21 +712,21 @@ std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { ret += "animations:\n"; - for (auto& ac : g_pConfigManager->getAnimationConfig()) { + for (auto const& ac : g_pConfigManager->getAnimationConfig()) { ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second.overridden, ac.second.internalBezier, ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle); } ret += "beziers:\n"; - for (auto& bz : g_pAnimationManager->getAllBeziers()) { + for (auto const& bz : g_pAnimationManager->getAllBeziers()) { ret += std::format("\n\tname: {}\n", bz.first); } } else { // json ret += "[["; - for (auto& ac : g_pConfigManager->getAnimationConfig()) { + for (auto const& ac : g_pConfigManager->getAnimationConfig()) { ret += std::format(R"#( {{ "name": "{}", @@ -778,7 +778,7 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ std::string ret = ""; const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - for (auto& sh : SHORTCUTS) + for (auto const& sh : SHORTCUTS) ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); } else { ret += "["; @@ -800,7 +800,7 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { std::string ret = ""; if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - for (auto& kb : g_pKeybindManager->m_lKeybinds) { + for (auto const& kb : g_pKeybindManager->m_lKeybinds) { ret += "bind"; if (kb.locked) ret += "l"; @@ -821,7 +821,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { } else { // json ret += "["; - for (auto& kb : g_pKeybindManager->m_lKeybinds) { + for (auto const& kb : g_pKeybindManager->m_lKeybinds) { ret += std::format( R"#( {{ @@ -935,7 +935,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; result += "plugins:\n"; - for (auto& pl : g_pPluginSystem->getAllPlugins()) { + for (auto const& pl : g_pPluginSystem->getAllPlugins()) { result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); } @@ -1006,7 +1006,7 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { // decorations will probably need a repaint if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source") { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pHyprRenderer->damageMonitor(m.get()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } @@ -1359,7 +1359,7 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) std::string result = ""; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& wd : PWINDOW->m_dWindowDecorations) { + for (auto const& wd : PWINDOW->m_dWindowDecorations) { result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},"; } @@ -1367,7 +1367,7 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) result += "]"; } else { result = +"Decoration\tPriority\n"; - for (auto& wd : PWINDOW->m_dWindowDecorations) { + for (auto const& wd : PWINDOW->m_dWindowDecorations) { result += wd->getDisplayName() + "\t" + std::to_string(wd->getPositioningInfo().priority) + "\n"; } } @@ -1396,7 +1396,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { if (g_pCompositor->getMonitorFromName(vars[3])) return "A real monitor already uses that name."; - for (auto& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) { + for (auto const& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) { auto type = impl->type(); if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) { @@ -1464,7 +1464,7 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) { return "no plugins loaded"; std::string list = ""; - for (auto& p : PLUGINS) { + for (auto const& p : PLUGINS) { list += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description); } @@ -1673,7 +1673,7 @@ std::string CHyprCtl::getReply(std::string request) { std::string result = ""; // parse exact cmds first, then non-exact. - for (auto& cmd : m_vCommands) { + for (auto const& cmd : m_vCommands) { if (!cmd->exact) continue; @@ -1684,7 +1684,7 @@ std::string CHyprCtl::getReply(std::string request) { } if (result.empty()) - for (auto& cmd : m_vCommands) { + for (auto const& cmd : m_vCommands) { if (cmd->exact) continue; @@ -1715,7 +1715,7 @@ std::string CHyprCtl::getReply(std::string request) { rd.blurFBDirty = true; } - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pHyprRenderer->damageMonitor(m.get()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 22c741a6..2da64e63 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -217,7 +217,7 @@ void CHyprDebugOverlay::draw() { // draw the things int offsetY = 0; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { offsetY += m_mMonitorOverlays[m.get()].draw(offsetY); offsetY += 5; // for padding between mons } diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 3f8bb579..29da20c8 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -44,7 +44,7 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC PNOTIF->icon = icon; PNOTIF->fontSize = fontSize; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pCompositor->scheduleFrameForMonitor(m.get()); } } @@ -87,7 +87,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { const auto iconBackendID = iconBackendFromLayout(layout); const auto PBEZIER = g_pAnimationManager->getBezier("default"); - for (auto& notif : m_dNotifications) { + for (auto const& notif : m_dNotifications) { const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 331dba9c..155a2605 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -366,7 +366,7 @@ void CLayerSurface::applyRules() { xray = -1; animationStyle.reset(); - for (auto& rule : g_pConfigManager->getMatchingRules(self.lock())) { + for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) { if (rule.rule == "noanim") noAnimations = true; else if (rule.rule == "blur") diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index e48b7400..a4952ef7 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -251,7 +251,7 @@ void CPopup::recheckTree() { void CPopup::recheckChildrenRecursive() { auto cpy = m_vChildren; - for (auto& c : cpy) { + for (auto const& c : cpy) { c->onCommit(true); c->recheckChildrenRecursive(); } @@ -282,14 +282,14 @@ bool CPopup::visible() { } void CPopup::bfHelper(std::vector nodes, std::function fn, void* data) { - for (auto& n : nodes) { + for (auto const& n : nodes) { fn(n, data); } std::vector nodes2; - for (auto& n : nodes) { - for (auto& c : n->m_vChildren) { + for (auto const& n : nodes) { + for (auto const& c : n->m_vChildren) { nodes2.push_back(c.get()); } } @@ -308,7 +308,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { std::vector popups; breadthfirst([](CPopup* popup, void* data) { ((std::vector*)data)->push_back(popup); }, &popups); - for (auto& p : popups | std::views::reverse) { + for (auto const& p : popups | std::views::reverse) { if (!p->m_pResource) continue; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 71ee16f0..64dd7cf5 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -65,7 +65,7 @@ void CSubsurface::checkSiblingDamage() { const double SCALE = m_pWindowParent.lock() && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0; - for (auto& n : m_pParent->m_vChildren) { + for (auto const& n : m_pParent->m_vChildren) { if (n.get() == this) continue; @@ -75,7 +75,7 @@ void CSubsurface::checkSiblingDamage() { } void CSubsurface::recheckDamageForSubsurfaces() { - for (auto& n : m_vChildren) { + for (auto const& n : m_vChildren) { const auto COORDS = n->coordsGlobal(); g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y); } @@ -183,7 +183,7 @@ Vector2D CSubsurface::coordsGlobal() { } void CSubsurface::initExistingSubsurfaces(SP pSurface) { - for (auto& s : pSurface->subsurfaces) { + for (auto const& s : pSurface->subsurfaces) { if (!s || s->surface->hlSurface /* already assigned */) continue; onNewSubsurface(s.lock()); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 64337097..582e96a0 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -296,7 +296,7 @@ void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) { } void CWindow::uncacheWindowDecos() { - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { g_pDecorationPositioner->uncacheDecoration(wd.get()); } } @@ -305,7 +305,7 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor if (type != INPUT_TYPE_DRAG_END && hasPopupAt(mouseCoords)) return false; - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; @@ -337,7 +337,7 @@ pid_t CWindow::getPID() { } IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) { - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { if (wd->getDecorationType() == type) return wd.get(); } @@ -666,7 +666,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { return; } - for (auto& token : colorsAndAngles) { + for (auto const& token : colorsAndAngles) { // The first angle, or an explicit "0deg", splits the two gradients if (active && token.contains("deg")) { activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0); @@ -889,7 +889,7 @@ void CWindow::destroyGroup() { const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked; g_pKeybindManager->m_bGroupsLocked = true; - for (auto& w : members) { + for (auto const& w : members) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(w); w->updateWindowDecos(); } @@ -1282,7 +1282,7 @@ std::unordered_map CWindow::getEnv() { CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true); - for (auto& e : envs) { + for (auto const& e : envs) { if (!e.contains('=')) continue; @@ -1511,7 +1511,7 @@ PHLWINDOW CWindow::getSwallower() { if (!currentPid) break; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden()) continue; @@ -1536,7 +1536,7 @@ PHLWINDOW CWindow::getSwallower() { return candidates.at(0); // walk up the focus history and find the last focused - for (auto& w : g_pCompositor->m_vWindowFocusHistory) { + for (auto const& w : g_pCompositor->m_vWindowFocusHistory) { if (!w) continue; diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 72d9705e..35fc5727 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -94,7 +94,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { // set floating windows offset callbacks m_vRenderOffset.setUpdateCallback([&](void*) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->workspaceID() != m_iID) continue; @@ -386,7 +386,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { bool wantsCountVisible = false; int flagCount = 0; - for (auto& flag : prop) { + for (auto const& flag : prop) { if (flag == 't' && wantsOnlyTiled == -1) { wantsOnlyTiled = 1; flagCount++; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index e4e3900b..cd000223 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -139,7 +139,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen)) requestedClientFSMode = FSMODE_FULLSCREEN; - for (auto& r : PWINDOW->m_vMatchedRules) { + for (auto const& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("monitor")) { try { const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' '))); @@ -326,7 +326,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bCreatedOverFullscreen = true; // size and move rules - for (auto& r : PWINDOW->m_vMatchedRules) { + for (auto const& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("size")) { try { const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); diff --git a/src/helpers/BezierCurve.cpp b/src/helpers/BezierCurve.cpp index dd0ff2b0..ea567ad6 100644 --- a/src/helpers/BezierCurve.cpp +++ b/src/helpers/BezierCurve.cpp @@ -12,7 +12,7 @@ void CBezierCurve::setup(std::vector* pVec) { m_dPoints.emplace_back(Vector2D(0, 0)); - for (auto& p : *pVec) { + for (auto const& p : *pVec) { m_dPoints.push_back(p); } diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index afc8b1c5..bc54b76e 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -252,7 +252,7 @@ DRMFormat FormatUtils::shmToDRM(SHMFormat shm) { } const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) { - for (auto& fmt : GLES3_FORMATS) { + for (auto const& fmt : GLES3_FORMATS) { if (fmt.drmFormat == drm) return &fmt; } @@ -261,7 +261,7 @@ const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) { } const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) { - for (auto& fmt : GLES3_FORMATS) { + for (auto const& fmt : GLES3_FORMATS) { if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha) return &fmt; } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index ef319946..b9970399 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -180,7 +180,7 @@ void handleNoop(struct wl_listener* listener, void* data) { std::string escapeJSONStrings(const std::string& str) { std::ostringstream oss; - for (auto& c : str) { + for (auto const& c : str) { switch (c) { case '"': oss << "\\\""; break; case '\\': oss << "\\\\"; break; @@ -251,7 +251,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::set invalidWSes; if (same_mon) { - for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) { const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); if (PMONITOR && (PMONITOR->ID != g_pCompositor->m_pLastMonitor->ID)) invalidWSes.insert(rule.workspaceId); @@ -301,13 +301,13 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::set invalidWSes; // Collect all the workspaces we can't jump to. - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)) { // Can't jump to this workspace invalidWSes.insert(ws->m_iID); } } - for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) { const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); if (!PMONITOR || PMONITOR->ID == g_pCompositor->m_pLastMonitor->ID) { // Can't be invalid @@ -319,7 +319,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Prepare all named workspaces in case when we need them std::vector namedWSes; - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0) continue; @@ -463,7 +463,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { int remains = (int)result.id; std::vector validWSes; - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors)) continue; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 8b533d8a..d81ccb3d 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -171,7 +171,7 @@ void CMonitor::onConnect(bool noRule) { setupDefaultWS(monitorRule); - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (!valid(ws)) continue; @@ -242,7 +242,7 @@ void CMonitor::onDisconnect(bool destroy) { // Cleanup everything. Move windows back, snap cursor, shit. CMonitor* BACKUPMON = nullptr; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m.get() != this) { BACKUPMON = m.get(); break; @@ -259,7 +259,7 @@ void CMonitor::onDisconnect(bool destroy) { } if (!mirrors.empty()) { - for (auto& m : mirrors) { + for (auto const& m : mirrors) { m->setMirror(""); } @@ -298,13 +298,13 @@ void CMonitor::onDisconnect(bool destroy) { // move workspaces std::deque wspToMove; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) { wspToMove.push_back(w); } } - for (auto& w : wspToMove) { + for (auto const& w : wspToMove) { w->m_szLastMonitor = szName; g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON); w->startAnim(true, true, true); @@ -332,7 +332,7 @@ void CMonitor::onDisconnect(bool destroy) { int mostHz = 0; CMonitor* pMonitorMostHz = nullptr; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->refreshRate > mostHz && m.get() != this) { pMonitorMostHz = m.get(); mostHz = m->refreshRate; @@ -516,7 +516,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff } else { CMonitor* BACKUPMON = nullptr; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m.get() != this) { BACKUPMON = m.get(); break; @@ -525,13 +525,13 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // move all the WS std::deque wspToMove; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->m_iMonitorID == ID) { wspToMove.push_back(w); } } - for (auto& w : wspToMove) { + for (auto const& w : wspToMove) { g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON); w->startAnim(true, true, true); } @@ -605,7 +605,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo pWorkspace->startAnim(true, ANIMTOLEFT); // move pinned windows - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == POLDWORKSPACE && w->m_bPinned) w->moveToWorkspace(pWorkspace); } @@ -714,7 +714,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { if (animate) pWorkspace->startAnim(true, true); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pWorkspace) { w->m_iMonitorID = ID; w->updateSurfaceScaleTransformDetails(); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index db69cc04..c936d59c 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -104,7 +104,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for CMonitor* PMONITOR = nullptr; if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { PMONITOR = m.get(); break; @@ -1075,7 +1075,7 @@ std::string CHyprDwindleLayout::getLayoutName() { } void CHyprDwindleLayout::onEnable() { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden()) continue; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 9b3d02b4..f6339beb 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -591,7 +591,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { if (pWindow->m_bIsFloating) { // find whether there is a floating window below this one - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) { if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, @@ -611,7 +611,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { return PWINDOWCANDIDATE; // if not, floating window - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) return w; @@ -660,7 +660,7 @@ void IHyprLayout::requestFocusForWindow(PHLWINDOW pWindow) { Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // get all rules, see if we have any size overrides. Vector2D sizeOverride = {}; if (g_pCompositor->m_pLastMonitor) { - for (auto& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { + for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { if (r.szRule.starts_with("size")) { try { const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index d234d300..8fa324b0 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -172,7 +172,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire } else if (WINDOWSONWORKSPACE == 2) { // when dropping as the second tiled window in the workspace, // make it the master only if the cursor is on the master side of the screen - for (auto& nd : m_lMasterNodesData) { + for (auto const& nd : m_lMasterNodesData) { if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { switch (orientation) { case ORIENTATION_LEFT: @@ -619,7 +619,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { CMonitor* PMONITOR = nullptr; if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { PMONITOR = m.get(); break; @@ -1106,7 +1106,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri const auto NEWFOCUS = newFocusToChild ? NEWCHILD : NEWMASTER; switchToWindow(NEWFOCUS); } else { - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) { const auto NEWMASTER = n.pWindow.lock(); switchWindows(NEWMASTER, NEWCHILD); @@ -1141,7 +1141,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri return 0; } else { // if master is focused keep master focused (don't do anything) - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) { switchToWindow(n.pWindow.lock()); break; @@ -1469,7 +1469,7 @@ Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() { } void CHyprMasterLayout::onEnable() { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden()) continue; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index e2e98735..e2fe7089 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -70,7 +70,7 @@ void CAnimationManager::tick() { std::vector animationEndedVars; - for (auto& av : m_vActiveAnimatedVariables) { + for (auto const& av : m_vActiveAnimatedVariables) { if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) { av->warp(false); @@ -113,7 +113,7 @@ void CAnimationManager::tick() { g_pHyprRenderer->damageMonitor(PMONITOR); // TODO: just make this into a damn callback already vax... - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PWORKSPACE) continue; @@ -214,7 +214,7 @@ void CAnimationManager::tick() { PWINDOW->updateWindowDecos(); g_pHyprRenderer->damageWindow(PWINDOW); } else if (PWORKSPACE) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE) continue; @@ -263,7 +263,7 @@ void CAnimationManager::tick() { } // do it here, because if this alters the animation vars deque we would be in trouble above. - for (auto& ave : animationEndedVars) { + for (auto const& ave : animationEndedVars) { ave->onAnimationEnd(); } } @@ -293,7 +293,7 @@ bool CAnimationManager::deltazero(const CColor& a, const CColor& b) { } bool CAnimationManager::bezierExists(const std::string& bezier) { - for (auto& [bc, bz] : m_mBezierCurves) { + for (auto const& [bc, bz] : m_mBezierCurves) { if (bc == bezier) return true; } diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 1c047f85..6f8292f7 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -193,7 +193,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { // fallback to a default if available constexpr const std::array fallbackShapes = {"default", "left_ptr", "left-ptr"}; - for (auto& s : fallbackShapes) { + for (auto const& s : fallbackShapes) { m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo); if (m_sCurrentCursorShapeData.images.size() > 0) @@ -288,7 +288,7 @@ void CCursorManager::updateTheme() { static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); float highestScale = 1.0; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->scale > highestScale) highestScale = m->scale; } @@ -307,7 +307,7 @@ void CCursorManager::updateTheme() { setCursorFromName("left_ptr"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { m->forceFullFrames = 5; g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); } diff --git a/src/managers/HookSystemManager.cpp b/src/managers/HookSystemManager.cpp index 208c79ae..624d2fe1 100644 --- a/src/managers/HookSystemManager.cpp +++ b/src/managers/HookSystemManager.cpp @@ -30,7 +30,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal std::vector faultyHandles; volatile bool needsDeadCleanup = false; - for (auto& cb : *callbacks) { + for (auto const& cb : *callbacks) { m_bCurrentEventPlugin = false; @@ -70,7 +70,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal std::erase_if(*callbacks, [](const auto& fn) { return !fn.fn.lock(); }); if (!faultyHandles.empty()) { - for (auto& h : faultyHandles) + for (auto const& h : faultyHandles) g_pPluginSystem->unloadPlugin(g_pPluginSystem->getPluginByHandle(h), true); } } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 9fac656c..df3f2572 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -908,7 +908,7 @@ uint64_t CKeybindManager::spawnRawProc(std::string args) { grandchild = fork(); if (grandchild == 0) { // run in grandchild - for (auto& e : HLENV) { + for (auto const& e : HLENV) { setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); @@ -1720,10 +1720,10 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { // we make a copy because changeWindowFloatingMode might invalidate the iterator std::deque ptrs; - for (auto& w : g_pCompositor->m_vWindows) + for (auto const& w : g_pCompositor->m_vWindows) ptrs.push_back(w); - for (auto& w : ptrs) { + for (auto const& w : ptrs) { if (!w->m_bIsMapped || w->m_pWorkspace != PWORKSPACE || w->isHidden()) continue; @@ -1895,7 +1895,7 @@ SDispatchResult CKeybindManager::toggleSpecialWorkspace(std::string args) { const auto PMONITOR = g_pCompositor->m_pLastMonitor; auto specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID(); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == workspaceID) { requestedWorkspaceIsAlreadyOpen = true; break; @@ -1922,7 +1922,7 @@ SDispatchResult CKeybindManager::toggleSpecialWorkspace(std::string args) { SDispatchResult CKeybindManager::forceRendererReload(std::string args) { bool overAgain = false; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!m->output) continue; @@ -2390,7 +2390,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) { if (arg.find_first_of(' ') != std::string::npos) port = arg.substr(arg.find_first_of(' ') + 1); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!port.empty() && m->szName != port) continue; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 80f1ab4f..f0f74428 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -76,14 +76,14 @@ void CPointerManager::checkDefaultCursorWarp(SP monitor, std::string m } void CPointerManager::lockSoftwareAll() { - for (auto& state : monitorStates) + for (auto const& state : monitorStates) state->softwareLocks++; updateCursorBackend(); } void CPointerManager::unlockSoftwareAll() { - for (auto& state : monitorStates) + for (auto const& state : monitorStates) state->softwareLocks--; updateCursorBackend(); @@ -261,7 +261,7 @@ void CPointerManager::resetCursorImage(bool apply) { damageIfSoftware(); if (currentCursorImage.surface) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { currentCursorImage.surface->resource()->leave(m); } @@ -306,7 +306,7 @@ void CPointerManager::resetCursorImage(bool apply) { void CPointerManager::updateCursorBackend() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); if (!m->m_bEnabled || !m->dpmsStatus) { @@ -600,7 +600,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { // static auto INSIDE_LAYOUT = [this](const CBox& box) -> bool { - for (auto& b : currentMonitorLayout.monitorBoxes) { + for (auto const& b : currentMonitorLayout.monitorBoxes) { if (box.inside(b)) return true; } @@ -608,7 +608,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { }; static auto INSIDE_LAYOUT_COORD = [this](const Vector2D& vec) -> bool { - for (auto& b : currentMonitorLayout.monitorBoxes) { + for (auto const& b : currentMonitorLayout.monitorBoxes) { if (b.containsPoint(vec)) return true; } @@ -619,7 +619,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { Vector2D leader; float distanceSq = __FLT_MAX__; - for (auto& b : currentMonitorLayout.monitorBoxes) { + for (auto const& b : currentMonitorLayout.monitorBoxes) { auto p = b.closestPoint(vec); auto distSq = p.distanceSq(vec); @@ -673,7 +673,7 @@ void CPointerManager::damageIfSoftware() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); - for (auto& mw : monitorStates) { + for (auto const& mw : monitorStates) { if (mw->monitor.expired()) continue; @@ -748,7 +748,7 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { if (POINTER->boundOutput == "entire") { // find x and y size of the entire space Vector2D bottomRight = {-9999999, -9999999}, topLeft = {9999999, 9999999}; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { const auto EXTENT = m->logicalBox().extent(); const auto POS = m->logicalBox().pos(); if (EXTENT.x > bottomRight.x) @@ -787,7 +787,7 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { void CPointerManager::onMonitorLayoutChange() { currentMonitorLayout.monitorBoxes.clear(); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->isMirror() || !m->m_bEnabled) continue; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6e5cd16f..bace4451 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -151,7 +151,7 @@ CProtocolManager::CProtocolManager() { PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); - for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index e296dcc8..3e4063f4 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -483,7 +483,7 @@ void CSeatManager::refocusGrab() { if (seatGrab->surfs.size() > 0) { // try to find a surf in focus first const auto MOUSE = g_pInputManager->getMouseCoordsInternal(); - for (auto& s : seatGrab->surfs) { + for (auto const& s : seatGrab->surfs) { auto hlSurf = CWLSurface::fromResource(s.lock()); if (!hlSurf) continue; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 86108cac..81e22889 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -67,7 +67,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { m_pSessionLock.reset(); g_pInputManager->refocus(); - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pHyprRenderer->damageMonitor(m.get()); }); @@ -75,7 +75,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { m_pSessionLock.reset(); g_pCompositor->focusSurface(nullptr); - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pHyprRenderer->damageMonitor(m.get()); }); @@ -90,7 +90,7 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64 if (!m_pSessionLock) return nullptr; - for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { + for (auto const& sls : m_pSessionLock->vSessionLockSurfaces) { if (sls->iMonitorID == id) { if (sls->mapped) return sls.get(); diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 6f000f9f..7fc21a28 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -304,7 +304,7 @@ std::unordered_set CXCursorManager::themePaths(std::string const& t scanTheme(theme); while (!inherits.empty()) { auto oldInherits = inherits; - for (auto& i : oldInherits) + for (auto const& i : oldInherits) scanTheme(i); if (oldInherits.size() == inherits.size()) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 4654eeb7..b37e796b 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -255,7 +255,7 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { CMonitor* pMonitor = nullptr; double bestDistance = __FLT_MAX__; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { const auto SIZ = *PXWLFORCESCALEZERO ? m->vecTransformedSize : m->vecSize; double distance = diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index d1b85cf2..e9b0fa3e 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -19,7 +19,7 @@ CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEvent } CEventLoopManager::~CEventLoopManager() { - for (auto& eventSource : m_sWayland.aqEventSources) { + for (auto const& eventSource : m_sWayland.aqEventSources) { wl_event_source_remove(eventSource); } @@ -46,7 +46,7 @@ void CEventLoopManager::enterLoop() { m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); - for (auto& fd : aqPollFDs) { + for (auto const& fd : aqPollFDs) { m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); } @@ -56,7 +56,7 @@ void CEventLoopManager::enterLoop() { } void CEventLoopManager::onTimerFire() { - for (auto& t : m_sTimers.timers) { + for (auto const& t : m_sTimers.timers) { if (t.strongRef() > 1 /* if it's 1, it was lost. Don't call it. */ && t->passed() && !t->cancelled()) t->call(t); } @@ -93,7 +93,7 @@ void CEventLoopManager::nudgeTimers() { long nextTimerUs = 10 * 1000 * 1000; // 10s - for (auto& t : m_sTimers.timers) { + for (auto const& t : m_sTimers.timers) { if (const auto µs = t->leftUs(); µs < nextTimerUs) nextTimerUs = µs; } @@ -122,7 +122,7 @@ void CEventLoopManager::doLater(const std::function& fn) { auto cpy = IDLE->fns; IDLE->fns.clear(); IDLE->eventSource = nullptr; - for (auto& c : cpy) { + for (auto const& c : cpy) { if (c) c(); } diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index 4bcb4df3..a6f25142 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -49,7 +49,7 @@ void CInputManager::recheckIdleInhibitorStatus() { } // check manual user-set inhibitors - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_eIdleInhibitMode == IDLEINHIBIT_NONE) continue; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index a4a63a84..6b04c13f 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1033,7 +1033,7 @@ void CInputManager::setupMouse(SP mauz) { } void CInputManager::setPointerConfigs() { - for (auto& m : m_vPointers) { + for (auto const& m : m_vPointers) { auto devname = m->hlName; const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname); @@ -1268,7 +1268,7 @@ void CInputManager::updateKeyboardsLeds(SP pKeyboard) { if (!leds.has_value()) return; - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { k->updateLEDs(leds.value()); } } @@ -1402,7 +1402,7 @@ void CInputManager::unconstrainMouse() { if (g_pSeatManager->mouse.expired()) return; - for (auto& c : m_vConstraints) { + for (auto const& c : m_vConstraints) { const auto C = c.lock(); if (!C) @@ -1416,7 +1416,7 @@ void CInputManager::unconstrainMouse() { } bool CInputManager::isConstrained() { - for (auto& c : m_vConstraints) { + for (auto const& c : m_vConstraints) { const auto C = c.lock(); if (!C) @@ -1434,7 +1434,7 @@ bool CInputManager::isConstrained() { void CInputManager::updateCapabilities() { uint32_t caps = 0; - for (auto& h : m_vHIDs) { + for (auto const& h : m_vHIDs) { if (h.expired()) continue; @@ -1449,7 +1449,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() { uint32_t finalMask = 0; - for (auto& kb : m_vKeyboards) { + for (auto const& kb : m_vKeyboards) { if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) continue; @@ -1464,7 +1464,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() { void CInputManager::disableAllKeyboards(bool virt) { - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { if (k->isVirtual() != virt) continue; @@ -1540,13 +1540,13 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { return; } - for (auto& m : m_vTouches) { + for (auto const& m : m_vTouches) { setConfig(m); } } void CInputManager::setTabletConfigs() { - for (auto& t : m_vTablets) { + for (auto const& t : m_vTablets) { if (t->aq()->getLibinputHandle()) { const auto NAME = t->hlName; const auto LIBINPUTDEV = t->aq()->getLibinputHandle(); @@ -1711,7 +1711,7 @@ void CInputManager::setCursorIconOnBorder(PHLWINDOW w) { bool onDeco = false; - for (auto& wd : w->m_dWindowDecorations) { + for (auto const& wd : w->m_dWindowDecorations) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 7cfd54b4..1608e123 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -57,7 +57,7 @@ void CInputMethodRelay::onNewIME(SP pIME) { if (!g_pCompositor->m_pLastFocus) return; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (ti->client() != g_pCompositor->m_pLastFocus->client()) continue; @@ -80,7 +80,7 @@ CTextInput* CInputMethodRelay::getFocusedTextInput() { if (!g_pCompositor->m_pLastFocus) return nullptr; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (ti->focusedSurface() == g_pCompositor->m_pLastFocus) return ti.get(); } @@ -101,7 +101,7 @@ void CInputMethodRelay::removeTextInput(CTextInput* pInput) { } void CInputMethodRelay::updateAllPopups() { - for (auto& p : m_vIMEPopups) { + for (auto const& p : m_vIMEPopups) { p->onCommit(); } } @@ -138,7 +138,7 @@ void CInputMethodRelay::onKeyboardFocus(SP pSurface) { m_pLastKbFocus = pSurface; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (!ti->focusedSurface()) continue; @@ -148,7 +148,7 @@ void CInputMethodRelay::onKeyboardFocus(SP pSurface) { if (!pSurface) return; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (!ti->isV3()) continue; @@ -160,7 +160,7 @@ void CInputMethodRelay::onKeyboardFocus(SP pSurface) { } CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) { - for (auto& p : m_vIMEPopups) { + for (auto const& p : m_vIMEPopups) { if (p->isVecInPopup(point)) return p.get(); } @@ -169,7 +169,7 @@ CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) { } CInputPopup* CInputMethodRelay::popupFromSurface(const SP surface) { - for (auto& p : m_vIMEPopups) { + for (auto const& p : m_vIMEPopups) { if (p->getSurface() == surface) return p.get(); } diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 23d328bc..f33937e8 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -229,7 +229,7 @@ void CInputManager::newTablet(SP pDevice) { SP CInputManager::ensureTabletToolPresent(SP pTool) { - for (auto& t : m_vTabletTools) { + for (auto const& t : m_vTabletTools) { if (t->aq() == pTool) return t; } diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 398d4ce1..ef3ae06a 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -124,8 +124,8 @@ APICALL bool HyprlandAPI::removeWindowDecoration(HANDLE handle, IHyprWindowDecor if (!PLUGIN) return false; - for (auto& w : g_pCompositor->m_vWindows) { - for (auto& d : w->m_dWindowDecorations) { + for (auto const& w : g_pCompositor->m_vWindows) { + for (auto const& d : w->m_dWindowDecorations) { if (d.get() == pDecoration) { w->removeWindowDeco(pDecoration); return true; diff --git a/src/plugins/PluginSystem.cpp b/src/plugins/PluginSystem.cpp index 122faafd..0f1f97a2 100644 --- a/src/plugins/PluginSystem.cpp +++ b/src/plugins/PluginSystem.cpp @@ -98,27 +98,27 @@ void CPluginSystem::unloadPlugin(const CPlugin* plugin, bool eject) { exitFunc(); } - for (auto& [k, v] : plugin->registeredCallbacks) { + for (auto const& [k, v] : plugin->registeredCallbacks) { if (const auto SHP = v.lock()) g_pHookSystem->unhook(SHP); } const auto ls = plugin->registeredLayouts; - for (auto& l : ls) + for (auto const& l : ls) g_pLayoutManager->removeLayout(l); g_pFunctionHookSystem->removeAllHooksFrom(plugin->m_pHandle); const auto rd = plugin->registeredDecorations; - for (auto& d : rd) + for (auto const& d : rd) HyprlandAPI::removeWindowDecoration(plugin->m_pHandle, d); const auto rdi = plugin->registeredDispatchers; - for (auto& d : rdi) + for (auto const& d : rdi) HyprlandAPI::removeDispatcher(plugin->m_pHandle, d); const auto rhc = plugin->registeredHyprctlCommands; - for (auto& c : rhc) + for (auto const& c : rhc) HyprlandAPI::unregisterHyprCtlCommand(plugin->m_pHandle, c); g_pConfigManager->removePluginConfig(plugin->m_pHandle); @@ -139,7 +139,7 @@ void CPluginSystem::unloadPlugin(const CPlugin* plugin, bool eject) { } void CPluginSystem::unloadAllPlugins() { - for (auto& p : m_vLoadedPlugins | std::views::reverse) + for (auto const& p : m_vLoadedPlugins | std::views::reverse) unloadPlugin(p.get(), false); // Unload remaining plugins gracefully } @@ -147,7 +147,7 @@ std::vector CPluginSystem::updateConfigPlugins(const std::vector failures; // unload all plugins that are no longer present - for (auto& p : m_vLoadedPlugins | std::views::reverse) { + for (auto const& p : m_vLoadedPlugins | std::views::reverse) { if (p->m_bLoadedWithConfig && std::find(plugins.begin(), plugins.end(), p->path) == plugins.end()) { Debug::log(LOG, "Unloading plugin {} which is no longer present in config", p->path); unloadPlugin(p.get(), false); @@ -156,7 +156,7 @@ std::vector CPluginSystem::updateConfigPlugins(const std::vectorpath == path; }) == m_vLoadedPlugins.end()) { Debug::log(LOG, "Loading plugin {} which is now present in config", path); const auto plugin = loadPlugin(path); @@ -173,7 +173,7 @@ std::vector CPluginSystem::updateConfigPlugins(const std::vectorpath == path) return p.get(); } @@ -182,7 +182,7 @@ CPlugin* CPluginSystem::getPluginByPath(const std::string& path) { } CPlugin* CPluginSystem::getPluginByHandle(HANDLE handle) { - for (auto& p : m_vLoadedPlugins) { + for (auto const& p : m_vLoadedPlugins) { if (p->m_pHandle == handle) return p.get(); } diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index f906740c..37f2e2eb 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -14,7 +14,7 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPparent; requested = request->requested; - for (auto& m : requested) { + for (auto const& m : requested) { if (!m->monitor || m->monitor->isBeingLeased) { LOGM(ERR, "Rejecting lease: no monitor or monitor is being leased for {}", (m->monitor ? m->monitor->szName : "null")); resource->sendFinished(); @@ -26,14 +26,14 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPmonitor->szName); } return roll; }()); std::vector> outputs; - for (auto& m : requested) { + for (auto const& m : requested) { outputs.emplace_back(m->monitor->output); } @@ -184,7 +184,7 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc resource->sendDrmFd(fd); close(fd); - for (auto& m : PROTO::lease->primaryDevice->offeredOutputs) { + for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { sendConnector(m.lock()); } @@ -234,7 +234,7 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backe } CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { - for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; @@ -292,7 +292,7 @@ void CDRMLeaseProtocol::offer(SP monitor) { primaryDevice->offeredOutputs.emplace_back(monitor); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->sendConnector(monitor); m->resource->sendDone(); } diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index dce64508..d2d06644 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -37,7 +37,7 @@ void CWLRDataOffer::sendData() { if (!source) return; - for (auto& m : source->mimes()) { + for (auto const& m : source->mimes()) { resource->sendOffer(m.c_str()); } } @@ -191,7 +191,7 @@ CWLRDataControlManagerResource::CWLRDataControlManagerResource(SPself = RESOURCE; device = RESOURCE; - for (auto& s : sources) { + for (auto const& s : sources) { if (!s) continue; s->device = RESOURCE; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 2d6b2ee2..aff232e4 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -103,7 +103,7 @@ void CFocusGrab::refocusKeyboard() { return; SP surface = nullptr; - for (auto& [surf, state] : m_mSurfaces) { + for (auto const& [surf, state] : m_mSurfaces) { if (state->state == CFocusGrabSurfaceState::Comitted) { surface = surf.lock(); break; diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 59888ce2..1f8cbcbe 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -30,7 +30,7 @@ CForeignToplevelList::CForeignToplevelList(SP resourc LOGM(LOG, "CForeignToplevelList: finished"); }); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->m_bFadingOut) continue; @@ -112,19 +112,19 @@ bool CForeignToplevelList::good() { CForeignToplevelProtocol::CForeignToplevelProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) { - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onMap(std::any_cast(data)); } }); static auto P1 = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) { - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onUnmap(std::any_cast(data)); } }); static auto P2 = g_pHookSystem->hookDynamic("windowTitle", [this](void* self, SCallbackInfo& info, std::any data) { - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onTitle(std::any_cast(data)); } }); diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index bd597a91..291969db 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -179,7 +179,7 @@ CForeignToplevelWlrManager::CForeignToplevelWlrManager(SPonManagerResourceDestroy(this); }); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->m_bFadingOut) continue; @@ -313,42 +313,42 @@ bool CForeignToplevelWlrManager::good() { CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onMap(PWINDOW); } }); static auto P1 = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onUnmap(PWINDOW); } }); static auto P2 = g_pHookSystem->hookDynamic("windowTitle", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onTitle(PWINDOW); } }); static auto P3 = g_pHookSystem->hookDynamic("activeWindow", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onNewFocus(PWINDOW); } }); static auto P4 = g_pHookSystem->hookDynamic("moveWindow", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(std::any_cast>(data).at(0)); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onMoveMonitor(PWINDOW); } }); static auto P5 = g_pHookSystem->hookDynamic("fullscreen", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onFullscreen(PWINDOW); } }); @@ -374,7 +374,7 @@ void CForeignToplevelWlrProtocol::destroyHandle(CForeignToplevelHandleWlr* handl } PHLWINDOW CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res) { - for (auto& h : m_vHandles) { + for (auto const& h : m_vHandles) { if (h->res() != res) continue; diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index d39fa67c..d8010eac 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -24,7 +24,7 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) { } void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP surface) { - for (auto& [k, v] : m_mAddons) { + for (auto const& [k, v] : m_mAddons) { if (k == surface) { LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface.get()); pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists"); diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index c902d00e..cb75a202 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -25,7 +25,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out return; } - for (auto& g : PROTO::gamma->m_vGammaControllers) { + for (auto const& g : PROTO::gamma->m_vGammaControllers) { if (g->pMonitor == pMonitor) { resource->sendFailed(); return; @@ -180,7 +180,7 @@ void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, } void CGammaControlProtocol::applyGammaToState(CMonitor* pMonitor) { - for (auto& g : m_vGammaControllers) { + for (auto const& g : m_vGammaControllers) { if (g->getMonitor() != pMonitor) continue; diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 92bfbae4..b02126ef 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -54,8 +54,8 @@ void CGlobalShortcutsProtocol::destroyResource(CShortcutClient* client) { } bool CGlobalShortcutsProtocol::isTaken(std::string appid, std::string trigger) { - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { + for (auto const& c : m_vClients) { + for (auto const& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { return true; } @@ -66,8 +66,8 @@ bool CGlobalShortcutsProtocol::isTaken(std::string appid, std::string trigger) { } void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) { - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { + for (auto const& c : m_vClients) { + for (auto const& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -84,8 +84,8 @@ void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::s std::vector CGlobalShortcutsProtocol::getAllShortcuts() { std::vector copy; - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { + for (auto const& c : m_vClients) { + for (auto const& sh : c->shortcuts) { copy.push_back(*sh); } } diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index 8d915ac6..3517a62d 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -86,14 +86,14 @@ void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t i } void CIdleNotifyProtocol::onActivity() { - for (auto& n : m_vNotifications) { + for (auto const& n : m_vNotifications) { n->onActivity(); } } void CIdleNotifyProtocol::setInhibit(bool inhibited) { isInhibited = inhibited; - for (auto& n : m_vNotifications) { + for (auto const& n : m_vNotifications) { n->onActivity(); } } \ No newline at end of file diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index a0820e0b..5fd1e893 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -268,7 +268,7 @@ wl_client* CInputMethodV2::grabClient() { if (grabs.empty()) return nullptr; - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) @@ -282,7 +282,7 @@ wl_client* CInputMethodV2::grabClient() { void CInputMethodV2::sendInputRectangle(const CBox& box) { inputRectangle = box; - for (auto& wp : popups) { + for (auto const& wp : popups) { auto p = wp.lock(); if (!p) @@ -293,7 +293,7 @@ void CInputMethodV2::sendInputRectangle(const CBox& box) { } void CInputMethodV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) { - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) @@ -304,7 +304,7 @@ void CInputMethodV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state } void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) @@ -315,7 +315,7 @@ void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t loc } void CInputMethodV2::setKeyboard(SP keyboard) { - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 32625792..d9dd1d01 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -31,8 +31,8 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec size_t i = 0; rendererTranche.indicies.clear(); - for (auto& fmt : rendererTranche.formats) { - for (auto& mod : fmt.modifiers) { + for (auto const& fmt : rendererTranche.formats) { + for (auto const& mod : fmt.modifiers) { auto format = std::make_pair<>(fmt.drmFormat, mod); auto [_, inserted] = formats.insert(format); if (inserted) { @@ -53,8 +53,8 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec for (auto& [monitor, tranche] : monitorTranches) { tranche.indicies.clear(); - for (auto& fmt : tranche.formats) { - for (auto& mod : fmt.modifiers) { + for (auto const& fmt : tranche.formats) { + for (auto const& mod : fmt.modifiers) { // apparently these can implode on planes, so dont use them if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) continue; @@ -270,7 +270,7 @@ bool CLinuxDMABBUFParamsResource::verify() { } bool empty = false; - for (auto& plane : attrs->fds) { + for (auto const& plane : attrs->fds) { if (empty && plane != -1) { resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "Gap in planes"); return false; @@ -402,8 +402,8 @@ bool CLinuxDMABUFResource::good() { } void CLinuxDMABUFResource::sendMods() { - for (auto& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { - for (auto& mod : fmt.modifiers) { + for (auto const& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { + for (auto const& mod : fmt.modifiers) { if (resource->version() < 3) { if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) resource->sendFormat(fmt.drmFormat); @@ -442,7 +442,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const // this assumes there's only 1 device used for both scanout and rendering // also that each monitor never changes its primary plane - for (auto& mon : g_pCompositor->m_vMonitors) { + for (auto const& mon : g_pCompositor->m_vMonitors) { auto tranche = SDMABUFTranche{ .device = mainDevice, .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, @@ -505,7 +505,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { // this might be a big copy auto newFormatTable = std::make_unique(formatTable->rendererTranche, formatTable->monitorTranches); - for (auto& feedback : m_vFeedbacks) { + for (auto const& feedback : m_vFeedbacks) { feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); if (feedback->lastFeedbackWasScanout) { SP mon; @@ -562,7 +562,7 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, SP pMonitor) { SP feedbackResource; - for (auto& f : m_vFeedbacks) { + for (auto const& f : m_vFeedbacks) { if (f->surface != surface) continue; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index 9fcd5f9b..b4efd2c8 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -60,11 +60,11 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { uint64_t mod = DRM_FORMAT_MOD_INVALID; auto fmts = g_pHyprOpenGL->getDRMFormats(); - for (auto& f : fmts) { + for (auto const& f : fmts) { if (f.drmFormat != fmt) continue; - for (auto& m : f.modifiers) { + for (auto const& m : f.modifiers) { if (m == DRM_FORMAT_MOD_LINEAR) continue; @@ -100,7 +100,7 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { resource->sendCapabilities(WL_DRM_CAPABILITY_PRIME); auto fmts = g_pHyprOpenGL->getDRMFormats(); - for (auto& fmt : fmts) { + for (auto const& fmt : fmts) { resource->sendFormat(fmt.drmFormat); } } diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index cfe388fa..09552b19 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -28,7 +28,7 @@ COutputManager::COutputManager(SP resource_) : resource(re }); // send all heads at start - for (auto& m : g_pCompositor->m_vRealMonitors) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { if (m.get() == g_pCompositor->m_pUnsafeOutput) continue; @@ -67,7 +67,7 @@ void COutputManager::ensureMonitorSent(CMonitor* pMonitor) { if (pMonitor == g_pCompositor->m_pUnsafeOutput) return; - for (auto& hw : heads) { + for (auto const& hw : heads) { auto h = hw.lock(); if (!h) @@ -96,7 +96,7 @@ COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any d) { resource->sendFinished(); - for (auto& mw : modes) { + for (auto const& mw : modes) { auto m = mw.lock(); if (!m) @@ -106,7 +106,7 @@ COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : } pMonitor = nullptr; - for (auto& m : PROTO::outputManagement->m_vManagers) { + for (auto const& m : PROTO::outputManagement->m_vManagers) { m->sendDone(); } }); @@ -147,7 +147,7 @@ void COutputHead::sendAllData() { if (modes.empty()) { if (!pMonitor->output->modes.empty()) { - for (auto& m : pMonitor->output->modes) { + for (auto const& m : pMonitor->output->modes) { makeAndSendNewMode(m); } } else if (pMonitor->output->state->state().customMode) { @@ -158,7 +158,7 @@ void COutputHead::sendAllData() { // send current mode if (pMonitor->m_bEnabled) { - for (auto& mw : modes) { + for (auto const& mw : modes) { auto m = mw.lock(); if (!m) @@ -189,7 +189,7 @@ void COutputHead::updateMode() { resource->sendAdaptiveSync(pMonitor->vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED); if (pMonitor->m_bEnabled) { - for (auto& mw : modes) { + for (auto const& mw : modes) { auto m = mw.lock(); if (!m) @@ -346,7 +346,7 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { LOGM(LOG, "Applying configuration"); - for (auto& headw : heads) { + for (auto const& headw : heads) { auto head = headw.lock(); if (!head) @@ -577,15 +577,15 @@ void COutputManagementProtocol::destroyResource(COutputConfigurationHead* resour } void COutputManagementProtocol::updateAllOutputs() { - for (auto& m : g_pCompositor->m_vRealMonitors) { - for (auto& mgr : m_vManagers) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { + for (auto const& mgr : m_vManagers) { mgr->ensureMonitorSent(m.get()); } } } SP COutputManagementProtocol::headFromResource(wl_resource* r) { - for (auto& h : m_vHeads) { + for (auto const& h : m_vHeads) { if (h->resource->resource() == r) return h; } @@ -594,7 +594,7 @@ SP COutputManagementProtocol::headFromResource(wl_resource* r) { } SP COutputManagementProtocol::modeFromResource(wl_resource* r) { - for (auto& h : m_vModes) { + for (auto const& h : m_vModes) { if (h->resource->resource() == r) return h; } diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index c83e3887..4eb74102 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -111,7 +111,7 @@ void CPointerGesturesProtocol::swipeBegin(uint32_t timeMs, uint32_t fingers) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vSwipes) { + for (auto const& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -125,7 +125,7 @@ void CPointerGesturesProtocol::swipeUpdate(uint32_t timeMs, const Vector2D& delt const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - for (auto& sw : m_vSwipes) { + for (auto const& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -141,7 +141,7 @@ void CPointerGesturesProtocol::swipeEnd(uint32_t timeMs, bool cancelled) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vSwipes) { + for (auto const& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -157,7 +157,7 @@ void CPointerGesturesProtocol::pinchBegin(uint32_t timeMs, uint32_t fingers) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vPinches) { + for (auto const& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -171,7 +171,7 @@ void CPointerGesturesProtocol::pinchUpdate(uint32_t timeMs, const Vector2D& delt const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - for (auto& sw : m_vPinches) { + for (auto const& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -187,7 +187,7 @@ void CPointerGesturesProtocol::pinchEnd(uint32_t timeMs, bool cancelled) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vPinches) { + for (auto const& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -203,7 +203,7 @@ void CPointerGesturesProtocol::holdBegin(uint32_t timeMs, uint32_t fingers) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vHolds) { + for (auto const& sw : m_vHolds) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -219,7 +219,7 @@ void CPointerGesturesProtocol::holdEnd(uint32_t timeMs, bool cancelled) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vHolds) { + for (auto const& sw : m_vHolds) { if (sw->resource->client() != FOCUSEDCLIENT) continue; diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 638435c7..b1108042 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -114,11 +114,11 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint when = &now; } - for (auto& feedback : m_vFeedbacks) { + for (auto const& feedback : m_vFeedbacks) { if (!feedback->surface) continue; - for (auto& data : m_vQueue) { + for (auto const& data : m_vQueue) { if (!data->surface || data->surface != feedback->surface) continue; diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 4fede706..f1db2d65 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -38,7 +38,7 @@ void CPrimarySelectionOffer::sendData() { if (!source) return; - for (auto& m : source->mimes()) { + for (auto const& m : source->mimes()) { resource->sendOffer(m.c_str()); } } @@ -177,7 +177,7 @@ CPrimarySelectionManager::CPrimarySelectionManager(SPself = RESOURCE; device = RESOURCE; - for (auto& s : sources) { + for (auto const& s : sources) { if (!s) continue; s->device = RESOURCE; @@ -272,7 +272,7 @@ void CPrimarySelectionProtocol::sendSelectionToDevice(SP source) { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->source && o->source->hasDnd()) continue; o->dead = true; @@ -321,7 +321,7 @@ void CPrimarySelectionProtocol::updateSelection() { } void CPrimarySelectionProtocol::onPointerFocus() { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { o->dead = true; } diff --git a/src/protocols/RelativePointer.cpp b/src/protocols/RelativePointer.cpp index e4818758..16248c02 100644 --- a/src/protocols/RelativePointer.cpp +++ b/src/protocols/RelativePointer.cpp @@ -65,7 +65,7 @@ void CRelativePointerProtocol::sendRelativeMotion(uint64_t time, const Vector2D& const auto FOCUSED = g_pSeatManager->state.pointerFocusResource->client(); - for (auto& rp : m_vRelativePointers) { + for (auto const& rp : m_vRelativePointers) { if (FOCUSED != rp->client()) continue; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 1559476b..63024541 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -155,7 +155,7 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_ lockedSWCursors = true; // TODO: make it per-monitor if (!PROTO::screencopy->m_bTimerArmed) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pPointerManager->lockSoftwareForMonitor(m); } PROTO::screencopy->m_bTimerArmed = true; @@ -365,7 +365,7 @@ CScreencopyProtocol::CScreencopyProtocol(const wl_interface* iface, const int& v std::nullopt, [this](SP self, void* data) { // TODO: make it per-monitor - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pPointerManager->unlockSoftwareForMonitor(m); } m_bTimerArmed = false; @@ -411,7 +411,7 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { std::vector> framesToRemove; // share frame if correct output - for (auto& f : m_vFramesAwaitingWrite) { + for (auto const& f : m_vFramesAwaitingWrite) { if (!f->pMonitor || !f->buffer) { framesToRemove.push_back(f); continue; @@ -428,7 +428,7 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { framesToRemove.push_back(f); } - for (auto& f : framesToRemove) { + for (auto const& f : framesToRemove) { destroyResource(f.get()); } } diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index fe44face..b1f701bf 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -187,7 +187,7 @@ void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id auto PMONITOR = CWLOutputResource::fromResource(output)->monitor.get(); SP sessionLock; - for (auto& l : m_vLocks) { + for (auto const& l : m_vLocks) { if (l->resource.get() == lock) { sessionLock = l; break; diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index e4424ed7..308b385d 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -48,7 +48,7 @@ void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitMa SP surf = CWLSurfaceResource::fromResource(surface); const auto CLIENT = pMgr->client(); - for (auto& in : m_vInhibitors) { + for (auto const& in : m_vInhibitors) { if (in->surface() != surf) continue; @@ -74,7 +74,7 @@ bool CKeyboardShortcutsInhibitProtocol::isInhibited() { if (const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock()); PWINDOW && PWINDOW->m_sWindowData.noShortcutsInhibit.valueOrDefault()) return false; - for (auto& in : m_vInhibitors) { + for (auto const& in : m_vInhibitors) { if (in->surface() != g_pCompositor->m_pLastFocus) continue; diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index b974152e..d7f741b9 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -96,7 +96,7 @@ bool CTabletPadV2Resource::good() { void CTabletPadV2Resource::sendData() { // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - for (auto& p : pad->aq()->paths) { + for (auto const& p : pad->aq()->paths) { resource->sendPath(p.c_str()); } @@ -140,7 +140,7 @@ void CTabletV2Resource::sendData() { resource->sendName(tablet->deviceName.c_str()); resource->sendId(tablet->aq()->usbVendorID, tablet->aq()->usbProductID); - for (auto& p : tablet->aq()->paths) { + for (auto const& p : tablet->aq()->paths) { resource->sendPath(p.c_str()); } @@ -287,21 +287,21 @@ void CTabletSeat::sendTablet(SP tablet) { } void CTabletSeat::sendData() { - for (auto& tw : PROTO::tablet->tablets) { + for (auto const& tw : PROTO::tablet->tablets) { if (tw.expired()) continue; sendTablet(tw.lock()); } - for (auto& tw : PROTO::tablet->tools) { + for (auto const& tw : PROTO::tablet->tools) { if (tw.expired()) continue; sendTool(tw.lock()); } - for (auto& tw : PROTO::tablet->pads) { + for (auto const& tw : PROTO::tablet->pads) { if (tw.expired()) continue; @@ -367,7 +367,7 @@ void CTabletV2Protocol::onGetSeat(CZwpTabletManagerV2* pMgr, uint32_t id, wl_res } void CTabletV2Protocol::registerDevice(SP tablet) { - for (auto& s : m_vSeats) { + for (auto const& s : m_vSeats) { s->sendTablet(tablet); } @@ -375,7 +375,7 @@ void CTabletV2Protocol::registerDevice(SP tablet) { } void CTabletV2Protocol::registerDevice(SP tool) { - for (auto& s : m_vSeats) { + for (auto const& s : m_vSeats) { s->sendTool(tool); } @@ -383,7 +383,7 @@ void CTabletV2Protocol::registerDevice(SP tool) { } void CTabletV2Protocol::registerDevice(SP pad) { - for (auto& s : m_vSeats) { + for (auto const& s : m_vSeats) { s->sendPad(pad); } @@ -391,7 +391,7 @@ void CTabletV2Protocol::registerDevice(SP pad) { } void CTabletV2Protocol::unregisterDevice(SP tablet) { - for (auto& t : m_vTablets) { + for (auto const& t : m_vTablets) { if (t->tablet == tablet) { t->resource->sendRemoved(); t->inert = true; @@ -401,7 +401,7 @@ void CTabletV2Protocol::unregisterDevice(SP tablet) { } void CTabletV2Protocol::unregisterDevice(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool == tool) { t->resource->sendRemoved(); t->inert = true; @@ -411,7 +411,7 @@ void CTabletV2Protocol::unregisterDevice(SP tool) { } void CTabletV2Protocol::unregisterDevice(SP pad) { - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (t->pad == pad) { t->resource->sendRemoved(); t->inert = true; @@ -426,7 +426,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { std::erase_if(pads, [](const auto& e) { return e.expired(); }); // now we need to send removed events - for (auto& t : m_vTablets) { + for (auto const& t : m_vTablets) { if (!t->tablet.expired() || t->inert) continue; @@ -434,7 +434,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { t->inert = true; } - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (!t->tool.expired() || t->inert) continue; @@ -448,7 +448,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { t->inert = true; } - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (!t->pad.expired() || t->inert) continue; @@ -458,7 +458,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { } void CTabletV2Protocol::pressure(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -468,7 +468,7 @@ void CTabletV2Protocol::pressure(SP tool, double value) { } void CTabletV2Protocol::distance(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -478,7 +478,7 @@ void CTabletV2Protocol::distance(SP tool, double value) { } void CTabletV2Protocol::rotation(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -488,7 +488,7 @@ void CTabletV2Protocol::rotation(SP tool, double value) { } void CTabletV2Protocol::slider(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -498,7 +498,7 @@ void CTabletV2Protocol::slider(SP tool, double value) { } void CTabletV2Protocol::wheel(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -508,7 +508,7 @@ void CTabletV2Protocol::wheel(SP tool, double value) { } void CTabletV2Protocol::tilt(SP tool, const Vector2D& value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -518,7 +518,7 @@ void CTabletV2Protocol::tilt(SP tool, const Vector2D& value) { } void CTabletV2Protocol::up(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -528,7 +528,7 @@ void CTabletV2Protocol::up(SP tool) { } void CTabletV2Protocol::down(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -545,7 +545,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, SP SP toolResource; SP tabletResource; - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || t->resource->client() != CLIENT) continue; @@ -559,7 +559,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, SP toolResource = t; - for (auto& tab : m_vTablets) { + for (auto const& tab : m_vTablets) { if (tab->tablet != tablet) continue; @@ -587,7 +587,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, SP } void CTabletV2Protocol::proximityOut(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -599,7 +599,7 @@ void CTabletV2Protocol::proximityOut(SP tool) { } void CTabletV2Protocol::buttonTool(SP tool, uint32_t button, uint32_t state) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -610,7 +610,7 @@ void CTabletV2Protocol::buttonTool(SP tool, uint32_t button, uint32 } void CTabletV2Protocol::motion(SP tool, const Vector2D& value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -620,7 +620,7 @@ void CTabletV2Protocol::motion(SP tool, const Vector2D& value) { } void CTabletV2Protocol::mode(SP pad, uint32_t group, uint32_t mode, uint32_t timeMs) { - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (t->pad != pad) continue; if (t->groups.size() <= group) { @@ -633,7 +633,7 @@ void CTabletV2Protocol::mode(SP pad, uint32_t group, uint32_t mode, } void CTabletV2Protocol::buttonPad(SP pad, uint32_t button, uint32_t timeMs, uint32_t state) { - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (t->pad != pad) continue; t->resource->sendButton(timeMs, button, zwpTabletToolV2ButtonState{state}); diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index 7f3c0a18..66a4efd2 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -38,7 +38,7 @@ void CTearingControlProtocol::onControllerDestroy(CTearingControl* control) { } void CTearingControlProtocol::onWindowDestroy(PHLWINDOW pWindow) { - for (auto& c : m_vTearingControllers) { + for (auto const& c : m_vTearingControllers) { if (c->pWindow.lock() == pWindow) c->pWindow.reset(); } @@ -52,7 +52,7 @@ CTearingControl::CTearingControl(SP resource_, SPsetDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); }); resource->setSetPresentationHint([this](CWpTearingControlV1* res, wpTearingControlV1PresentationHint hint) { this->onHint(hint); }); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWLSurface->resource() == surf_) { pWindow = w; break; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 916f7395..b28a827a 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -369,7 +369,7 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { std::vector> framesToRemove; // share frame if correct output - for (auto& f : m_vFramesAwaitingWrite) { + for (auto const& f : m_vFramesAwaitingWrite) { if (!f->pWindow || !validMapped(f->pWindow)) { framesToRemove.push_back(f); continue; @@ -393,13 +393,13 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { framesToRemove.push_back(f); } - for (auto& f : framesToRemove) { + for (auto const& f : framesToRemove) { destroyResource(f.get()); } } void CToplevelExportProtocol::onWindowUnmap(PHLWINDOW pWindow) { - for (auto& f : m_vFrames) { + for (auto const& f : m_vFrames) { if (f->pWindow == pWindow) f->pWindow.reset(); } diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 27a4f248..bb51315d 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -108,7 +108,7 @@ void CVirtualKeyboardV1Resource::releasePressed() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - for (auto& p : pressed) { + for (auto const& p : pressed) { events.key.emit(IKeyboard::SKeyEvent{ .timeMs = now.tv_sec * 1000 + now.tv_nsec / 1000000, .keycode = p, diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 9c2c353c..5d620667 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -39,7 +39,7 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P3 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { const auto PMONITOR = std::any_cast(param); - for (auto& o : m_vXDGOutputs) { + for (auto const& o : m_vXDGOutputs) { if (o->monitor == PMONITOR) o->monitor = nullptr; } @@ -84,7 +84,7 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 } void CXDGOutputProtocol::updateAllOutputs() { - for (auto& o : m_vXDGOutputs) { + for (auto const& o : m_vXDGOutputs) { if (!o->monitor) continue; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index eaf5c333..39a511c3 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -388,7 +388,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPm_vWindows.emplace_back(CWindow::create(self.lock())); - for (auto& p : popups) { + for (auto const& p : popups) { if (!p) continue; events.newPopup.emit(p); @@ -714,7 +714,7 @@ CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, grab->keyboard = true; grab->pointer = true; grab->setCallback([this]() { - for (auto& g : grabbed) { + for (auto const& g : grabbed) { g->done(); } grabbed.clear(); @@ -779,7 +779,7 @@ void CXDGShellProtocol::addOrStartGrab(SP popup) { void CXDGShellProtocol::onPopupDestroy(WP popup) { if (popup == grabOwner) { g_pSeatManager->setGrab(nullptr); - for (auto& g : grabbed) { + for (auto const& g : grabbed) { g->done(); } grabbed.clear(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 75f1e646..f7f6dcda 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -241,7 +241,7 @@ void CWLSurfaceResource::frame(timespec* now) { if (callbacks.empty()) return; - for (auto& c : callbacks) { + for (auto const& c : callbacks) { c->send(now); } @@ -257,7 +257,7 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std std::vector> nodes2; // first, gather all nodes below - for (auto& n : nodes) { + for (auto const& n : nodes) { std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); // subsurfaces is sorted lowest -> highest for (auto const& c : n->subsurfaces) { @@ -310,7 +310,7 @@ std::pair, Vector2D> CWLSurfaceResource::at(const Vector2 void* data) { ((std::vector, Vector2D>>*)data)->emplace_back(std::make_pair<>(surf, offset)); }, &surfs); - for (auto& [surf, pos] : surfs | std::views::reverse) { + for (auto const& [surf, pos] : surfs | std::views::reverse) { if (!allowsInput) { const auto BOX = CBox{pos, surf->current.size}; if (BOX.containsPoint(localCoords)) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 943c790f..b7640af3 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -80,7 +80,7 @@ void CWLDataOfferResource::sendData() { resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); } - for (auto& m : source->mimes()) { + for (auto const& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); resource->sendOffer(m.c_str()); } diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index bcf62fae..394dc8e2 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -65,7 +65,7 @@ CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, IWaylandProtocol(iface, ver, name), monitor(pMonitor), szName(pMonitor->szName) { listeners.modeChanged = monitor->events.modeChanged.registerListener([this](std::any d) { - for (auto& o : m_vOutputs) { + for (auto const& o : m_vOutputs) { o->updateState(); } }); @@ -95,7 +95,7 @@ void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) { } SP CWLOutputProtocol::outputResourceFrom(wl_client* client) { - for (auto& r : m_vOutputs) { + for (auto const& r : m_vOutputs) { if (r->client() != client) continue; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index f7764389..6ae0ddc4 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -525,7 +525,7 @@ void CWLSeatProtocol::updateCapabilities(uint32_t caps) { currentCaps = caps; - for (auto& s : m_vSeatResources) { + for (auto const& s : m_vSeatResources) { s->sendCapabilities(caps); } } @@ -534,7 +534,7 @@ void CWLSeatProtocol::updateKeymap() { if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { k->sendKeymap(g_pSeatManager->keyboard.lock()); } } @@ -543,13 +543,13 @@ void CWLSeatProtocol::updateRepeatInfo(uint32_t rate, uint32_t delayMs) { if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { k->repeatInfo(rate, delayMs); } } SP CWLSeatProtocol::seatResourceForClient(wl_client* client) { - for (auto& r : m_vSeatResources) { + for (auto const& r : m_vSeatResources) { if (r->client() == client) return r; } diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 9996a607..b09326bd 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -171,7 +171,7 @@ CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { }); // send a few supported formats. No need for any other I think? - for (auto& s : PROTO::shm->shmFormats) { + for (auto const& s : PROTO::shm->shmFormats) { resource->sendFormat((wl_shm_format)s); } } @@ -193,7 +193,7 @@ void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, ui DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, }; - for (auto& fmt : g_pHyprOpenGL->getDRMFormats()) { + for (auto const& fmt : g_pHyprOpenGL->getDRMFormats()) { if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) continue; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index e0679eff..46e20305 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -22,7 +22,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP void { - for (auto& c : parent->subsurfaces) { + for (auto const& c : parent->subsurfaces) { if (c->zIndex >= idx) c->zIndex++; } @@ -53,7 +53,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP void { - for (auto& c : parent->subsurfaces) { + for (auto const& c : parent->subsurfaces) { if (c->zIndex <= idx) c->zIndex--; } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 2aeda8be..67c11c23 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -213,7 +213,7 @@ EGLDeviceEXT CHyprOpenGLImpl::eglDeviceFromDRMFD(int drmFD) { return EGL_NO_DEVICE_EXT; } - for (auto& d : devices) { + for (auto const& d : devices) { auto devName = m_sProc.eglQueryDeviceStringEXT(d, EGL_DRM_DEVICE_FILE_EXT); if (!devName) continue; @@ -435,7 +435,7 @@ void CHyprOpenGLImpl::initDRMFormats() { std::vector dmaFormats; - for (auto& fmt : formats) { + for (auto const& fmt : formats) { std::vector mods; if (!DISABLE_MODS) { auto ret = getModsForFormat(fmt); @@ -460,7 +460,7 @@ void CHyprOpenGLImpl::initDRMFormats() { auto fmtName = drmGetFormatName(fmt); Debug::log(LOG, "EGL: GPU Supports Format {} (0x{:x})", fmtName ? fmtName : "?unknown?", fmt); - for (auto& mod : mods) { + for (auto const& mod : mods) { auto modName = drmGetFormatModifierName(mod); modifierData.emplace_back(std::make_pair<>(mod, modName ? modName : "?unknown?")); free(modName); @@ -476,7 +476,7 @@ void CHyprOpenGLImpl::initDRMFormats() { return true; }); - for (auto& [m, name] : modifierData) { + for (auto const& [m, name] : modifierData) { Debug::log(LOG, "EGL: | with modifier {} (0x{:x})", name, m); mods.emplace_back(m); } @@ -654,7 +654,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { if (!pMonitor->solitaryClient.expired()) return false; - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; if (ls->forceBlur && !XRAYMODE) return true; @@ -663,7 +663,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return true; } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; if (ls->forceBlur && !XRAYMODE) return true; @@ -673,7 +673,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { } // these two block optimization - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { if (ls->forceBlur) return true; @@ -681,7 +681,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return true; } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { if (ls->forceBlur) return true; @@ -704,7 +704,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { if (*PXRAY) return false; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden()) continue; @@ -1168,7 +1168,7 @@ void CHyprOpenGLImpl::clear(const CColor& color) { glClearColor(color.r, color.g, color.b, color.a); if (!m_RenderData.damage.empty()) { - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glClear(GL_COLOR_BUFFER_BIT); } @@ -1327,13 +1327,13 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion damageClip.intersect(*damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : damage->getRects()) { + for (auto const& RECT : damage->getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1523,13 +1523,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB damageClip.intersect(*damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : damage->getRects()) { + for (auto const& RECT : damage->getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1582,7 +1582,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->texAttrib); - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1640,7 +1640,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->texAttrib); - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1725,7 +1725,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib); if (!damage.empty()) { - for (auto& RECT : damage.getRects()) { + for (auto const& RECT : damage.getRects()) { scissor(&RECT, false /* this region is already transformed */); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1778,7 +1778,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glEnableVertexAttribArray(pShader->texAttrib); if (!pDamage->empty()) { - for (auto& RECT : pDamage->getRects()) { + for (auto const& RECT : pDamage->getRects()) { scissor(&RECT, false /* this region is already transformed */); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1848,7 +1848,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib); if (!damage.empty()) { - for (auto& RECT : damage.getRects()) { + for (auto const& RECT : damage.getRects()) { scissor(&RECT, false /* this region is already transformed */); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1924,7 +1924,7 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { }; bool hasWindows = false; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pMonitor->activeWorkspace && !w->isHidden() && w->m_bIsMapped && (!w->m_bIsFloating || *PBLURXRAY)) { // check if window is valid @@ -2215,13 +2215,13 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in damageClip.intersect(m_RenderData.damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -2512,13 +2512,13 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const damageClip.intersect(m_RenderData.damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -2928,7 +2928,7 @@ void SRenderModifData::applyToBox(CBox& box) { if (!enabled) return; - for (auto& [type, val] : modifs) { + for (auto const& [type, val] : modifs) { try { switch (type) { case RMOD_TYPE_SCALE: box.scale(std::any_cast(val)); break; @@ -2953,7 +2953,7 @@ void SRenderModifData::applyToRegion(CRegion& rg) { if (!enabled) return; - for (auto& [type, val] : modifs) { + for (auto const& [type, val] : modifs) { try { switch (type) { case RMOD_TYPE_SCALE: rg.scale(std::any_cast(val)); break; @@ -2971,7 +2971,7 @@ float SRenderModifData::combinedScale() { return 1; float scale = 1.f; - for (auto& [type, val] : modifs) { + for (auto const& [type, val] : modifs) { try { switch (type) { case RMOD_TYPE_SCALE: scale *= std::any_cast(val); break; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2ef7e208..c601e369 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -35,7 +35,7 @@ static int cursorTicker(void* data) { CHyprRenderer::CHyprRenderer() { if (g_pCompositor->m_pAqBackend->hasSession()) { - for (auto& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) { + for (auto const& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) { const auto DRMV = drmGetVersion(dev->fd); if (!DRMV) continue; @@ -348,7 +348,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOWS); // loop over the tiled windows that are fading out - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!shouldRenderWindow(w, pMonitor)) continue; @@ -365,7 +365,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK } // and floating ones too - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!shouldRenderWindow(w, pMonitor)) continue; @@ -385,7 +385,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK } // TODO: this pass sucks - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { const auto PWORKSPACE = w->m_pWorkspace; if (w->m_pWorkspace != pWorkspace || !w->isFullscreen()) { @@ -418,7 +418,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK } // then render windows over fullscreen. - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) continue; @@ -438,7 +438,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOWS); // Non-floating main - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) continue; @@ -465,7 +465,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor renderWindow(lastWindow, pMonitor, time, true, RENDER_PASS_MAIN); // Non-floating popup - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) continue; @@ -483,7 +483,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor } // floating on top - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) continue; @@ -585,20 +585,20 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (TRANSFORMERSPRESENT) { g_pHyprOpenGL->bindOffMain(); - for (auto& t : pWindow->m_vTransformers) { + for (auto const& t : pWindow->m_vTransformers) { t->preWindowRender(&renderdata); } } if (renderdata.decorate) { - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_BOTTOM) continue; wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha); } - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_UNDER) continue; @@ -625,7 +625,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; if (renderdata.decorate) { - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_OVER) continue; @@ -636,7 +636,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (TRANSFORMERSPRESENT) { CFramebuffer* last = g_pHyprOpenGL->m_RenderData.currentFB; - for (auto& t : pWindow->m_vTransformers) { + for (auto const& t : pWindow->m_vTransformers) { last = t->transform(last); } @@ -700,7 +700,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec } if (decorate) { - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_OVERLAY) continue; @@ -852,16 +852,16 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } g_pHyprOpenGL->blend(true); - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { renderLayer(ls.lock(), pMonitor, time); } @@ -892,10 +892,10 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } g_pHyprOpenGL->blend(true); - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { renderLayer(ls.lock(), pMonitor, time); } @@ -945,7 +945,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } // pinned always above - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut) continue; @@ -962,21 +962,21 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC EMIT_HOOK_EVENT("render", RENDER_POST_WINDOWS); // Render surfaces above windows for monitor - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { renderLayer(ls.lock(), pMonitor, time); } // Render IME popups - for (auto& imep : g_pInputManager->m_sIMERelay.m_vIMEPopups) { + for (auto const& imep : g_pInputManager->m_sIMERelay.m_vIMEPopups) { renderIMEPopup(imep.get(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& lsl : pMonitor->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { renderLayer(ls.lock(), pMonitor, time, true); } } @@ -1456,7 +1456,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { if (!sync) Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); else { - for (auto& e : explicitPresented) { + for (auto const& e : explicitPresented) { if (!e->current.buffer || !e->current.buffer->releaser) continue; @@ -1579,7 +1579,7 @@ static void applyExclusive(CBox& usableArea, uint32_t anchor, int32_t exclusive, void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { CBox full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; - for (auto& ls : layerSurfaces) { + for (auto const& ls : layerSurfaces) { if (!ls || ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) continue; @@ -1725,7 +1725,7 @@ void CHyprRenderer::damageSurface(SP pSurface, double x, dou CRegion damageBoxForEach; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!m->output) continue; @@ -1752,7 +1752,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); windowBox.translate(pWindow->m_vFloatingOffset); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (forceFull || g_pHyprRenderer->shouldRenderWindow(pWindow, m.get())) { // only damage if window is rendered on monitor CBox fixedDamageBox = {windowBox.x - m->vecPosition.x, windowBox.y - m->vecPosition.y, windowBox.width, windowBox.height}; fixedDamageBox.scale(m->scale); @@ -1760,7 +1760,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { } } - for (auto& wd : pWindow->m_dWindowDecorations) + for (auto const& wd : pWindow->m_dWindowDecorations) wd->damageEntire(); static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); @@ -1786,7 +1786,7 @@ void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) { if (g_pCompositor->m_bUnsafeState) return; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->isMirror()) continue; // don't damage mirrors traditionally @@ -1814,7 +1814,7 @@ void CHyprRenderer::damageRegion(const CRegion& rg) { } void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion) { - for (auto& mirror : pMonitor->mirrors) { + for (auto const& mirror : pMonitor->mirrors) { // transform the damage here, so it won't get clipped by the monitor damage ring auto monitor = mirror; @@ -1932,7 +1932,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { bool found = false; - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { // if delta of refresh rate, w and h chosen and mode is < 1 we accept it if (DELTALESSTHAN(mode->pixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(mode->pixelSize.y, RULE->resolution.y, 1) && DELTALESSTHAN(mode->refreshRate / 1000.f, RULE->refreshRate, 1)) { @@ -2035,7 +2035,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR //(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution if (RULE->resolution == Vector2D(-1, -1)) { - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || mode->refreshRate > (currentRefresh + 3000.f)) { pMonitor->output->state->setMode(mode); @@ -2048,7 +2048,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } } else { - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || (mode->pixelSize.x > currentWidth && mode->pixelSize.y > currentHeight)) { pMonitor->output->state->setMode(mode); @@ -2099,7 +2099,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name); if (!pMonitor->output->modes.empty()) { - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { pMonitor->output->state->setMode(mode); if (!pMonitor->state.test()) { @@ -2148,7 +2148,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR bool set10bit = false; - for (auto& fmt : formats[(int)!RULE->enable10bit]) { + for (auto const& fmt : formats[(int)!RULE->enable10bit]) { pMonitor->output->state->setFormat(fmt.second); pMonitor->drmFormat = fmt.second; @@ -2245,7 +2245,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // Set scale for all surfaces on this monitor, needed for some clients // but not on unsafe state to avoid crashes if (!g_pCompositor->m_bUnsafeState) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { w->updateSurfaceScaleTransformDetails(); } } @@ -2317,7 +2317,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { if (HIDE) { Debug::log(LOG, "Hiding the cursor (hl-mandated)"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pPointerManager->softwareLockedFor(m)) continue; @@ -2329,7 +2329,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { } else { Debug::log(LOG, "Showing the cursor (hl-mandated)"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pPointerManager->softwareLockedFor(m)) continue; @@ -2421,7 +2421,7 @@ void CHyprRenderer::setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pW if (!PMONITOR->activeSpecialWorkspace) return; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PMONITOR->activeSpecialWorkspace) continue; @@ -2452,7 +2452,7 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWork static auto PBLURPASSES = CConfigValue("decoration:blur:passes"); const auto BLURRADIUS = *PBLUR ? (*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES)) : 0; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != pWorkspace) continue; @@ -2476,7 +2476,7 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWork } bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { if (!ls->layerSurface) continue; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 94d00184..91e70afa 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -120,7 +120,7 @@ void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, cons } #endif - for (auto& rect : rects) { + for (auto const& rect : rects) { GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1)); GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1)); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index f5e6e945..1eaaa0af 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -118,7 +118,7 @@ void CHyprBorderDecoration::damageEntire() { CRegion borderRegion(surfaceBoxExpandedBorder); borderRegion.subtract(surfaceBoxShrunkRounding); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pHyprRenderer->shouldRenderWindow(m_pWindow.lock(), m.get())) { const CRegion monitorRegion({m->vecPosition, m->vecSize}); borderRegion.subtract(monitorRegion); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 423256d7..628a579a 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -66,7 +66,7 @@ void CHyprDropShadowDecoration::damageEntire() { shadowRegion.subtract(CRegion(surfaceBox)); } - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pHyprRenderer->shouldRenderWindow(PWINDOW, m.get())) { const CRegion monitorRegion({m->vecPosition, m->vecSize}); shadowRegion.subtract(monitorRegion); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 8163a8c1..4cdb9043 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -192,7 +192,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { } CTitleTex* CHyprGroupBarDecoration::textureFromTitle(const std::string& title) { - for (auto& tex : m_sTitleTexs.titleTexs) { + for (auto const& tex : m_sTitleTexs.titleTexs) { if (tex->szContent == title) return tex.get(); } diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index d66a5760..4666a59e 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -125,7 +125,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { // std::vector datas; - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { datas.push_back(getDataFor(wd.get(), pWindow)); } @@ -296,7 +296,7 @@ SBoxExtents CDecorationPositioner::getWindowDecorationReserved(PHLWINDOW pWindow SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, bool inputOnly) { CBox accum = pWindow->getWindowMainSurfaceBox(); - for (auto& data : m_vWindowPositioningDatas) { + for (auto const& data : m_vWindowPositioningDatas) { if (data->pWindow.lock() != pWindow) continue; @@ -337,7 +337,7 @@ SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, CBox CDecorationPositioner::getBoxWithIncludedDecos(PHLWINDOW pWindow) { CBox accum = pWindow->getWindowMainSurfaceBox(); - for (auto& data : m_vWindowPositioningDatas) { + for (auto const& data : m_vWindowPositioningDatas) { if (data->pWindow.lock() != pWindow) continue; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 995ec7f2..07208072 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -417,7 +417,7 @@ void CXWM::focusWindow(SP surf) { // send state to all toplevel surfaces, sometimes we might lose some // that could still stick with the focused atom - for (auto& s : mappedSurfaces) { + for (auto const& s : mappedSurfaces) { if (!s || s->overrideRedirect) continue; @@ -1025,7 +1025,7 @@ void CXWM::updateClientList() { std::erase_if(mappedSurfacesStacking, [](const auto& e) { return e.expired() || !e->mapped; }); std::vector windows; - for (auto& m : mappedSurfaces) { + for (auto const& m : mappedSurfaces) { windows.push_back(m->xID); } @@ -1033,7 +1033,7 @@ void CXWM::updateClientList() { windows.clear(); - for (auto& m : mappedSurfacesStacking) { + for (auto const& m : mappedSurfacesStacking) { windows.push_back(m->xID); } From 09dbcabcc71f412dcaf86dbed7b67d58a273fa50 Mon Sep 17 00:00:00 2001 From: raf Date: Mon, 26 Aug 2024 18:24:57 +0000 Subject: [PATCH 092/298] CI: disable stale workflow on forks (#7535) The stale workflow will run unconditionally, but will fail on forks due to `STALEBOT_PAT` not being set. Trigger the workflow *only* if we are on the main repo, where we can guarantee the PAT. Also formats the YML syntax to be slightly more readable. --- .github/workflows/stale.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 51f6b91e..b8be5f55 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,22 +7,22 @@ name: Mark stale issues and pull requests on: schedule: - - cron: '7 */4 * * *' + - cron: "7 */4 * * *" workflow_dispatch: jobs: stale: - + if: github.repository == 'hyprwm/Hyprland' runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - - uses: actions/stale@v5 - with: - repo-token: ${{ secrets.STALEBOT_PAT }} - stale-issue-label: 'stale' - stale-pr-label: 'stale' - operations-per-run: 40 - days-before-close: -1 + - uses: actions/stale@v5 + with: + repo-token: ${{ secrets.STALEBOT_PAT }} + stale-issue-label: "stale" + stale-pr-label: "stale" + operations-per-run: 40 + days-before-close: -1 From eb42adc4c090918ad6be9fcb24066da8cdfd9bd0 Mon Sep 17 00:00:00 2001 From: Serenity Braesch Date: Sat, 24 Aug 2024 01:53:08 -0600 Subject: [PATCH 093/298] Fix missing include needed by clang --- src/managers/XCursorManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 7fc21a28..1e7ca535 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -1,3 +1,4 @@ +#include #include #include #include From 6a8824253c38584d233380ece1e090dd9e7f2e3e Mon Sep 17 00:00:00 2001 From: Nick H Date: Tue, 27 Aug 2024 21:41:46 +0300 Subject: [PATCH 094/298] build: Fix NO_XWAYLAND compilation (#7538) --- src/xwayland/XWayland.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index d1cc4421..40c0ba65 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -3,6 +3,7 @@ #include #include "../helpers/signal/Signal.hpp" #include "../helpers/memory/Memory.hpp" +#include "../macros.hpp" #include "XSurface.hpp" From 17ed4fc04cedbaad365bdebf6bfe0160c527f3fe Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Tue, 27 Aug 2024 20:42:30 +0200 Subject: [PATCH 095/298] hyprctl: avoid parsing string::npos on invalid cmd (#7544) * hyprctl: avoid parsing string::npos on invalid cmd invalid lines passed to hyprctl keyword made the string parsing try to parse std::string::npos, avoid that and return an error text instead. * style --------- Co-authored-by: Vaxry --- src/debug/HyprCtl.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 40708cf8..ddd1c1ab 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -970,12 +970,26 @@ std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) { } std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { - // get rid of the keyword keyword - in = in.substr(in.find_first_of(' ') + 1); + // Find the first space to strip the keyword keyword + auto const firstSpacePos = in.find_first_of(' '); + if (firstSpacePos == std::string::npos) // Handle the case where there's no space found (invalid input) + return "Invalid input: no space found"; - const auto COMMAND = in.substr(0, in.find_first_of(' ')); + // Strip the keyword + in = in.substr(firstSpacePos + 1); - const auto VALUE = in.substr(in.find_first_of(' ') + 1); + // Find the next space for the COMMAND and VALUE + auto const secondSpacePos = in.find_first_of(' '); + if (secondSpacePos == std::string::npos) // Handle the case where there's no second space (invalid input) + return "Invalid input: command and value not properly formatted"; + + // Extract COMMAND and VALUE + const auto COMMAND = in.substr(0, secondSpacePos); + const auto VALUE = in.substr(secondSpacePos + 1); + + // If either COMMAND or VALUE is empty, handle accordingly + if (COMMAND.empty() || VALUE.empty()) + return "Invalid input: command or value is empty"; std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE); From 7dd0f76e5aa1e3726f9d9fd1871bc667237ef6a8 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 28 Aug 2024 06:19:06 -0500 Subject: [PATCH 096/298] logs: don't get timezone every time logging (#7550) its expensive cause cpp dum --- src/debug/Log.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 4fc8ed5b..d3190d4f 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -55,8 +55,9 @@ namespace Debug { // print date and time to the ofs if (disableTime && !**disableTime) { #ifndef _LIBCPP_VERSION - const auto zt = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()}; - const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor(zt.get_local_time())}; + static auto current_zone = std::chrono::current_zone(); + const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()}; + const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor(zt.get_local_time())}; #else // TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready const auto hms = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())}; From 00ee1cf98e3d8ef7cf71a9a505ba8d1382697e35 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 13:45:06 +0200 Subject: [PATCH 097/298] data-device: send dndFinished when dnd offer is destroyed while unfinished fixes #7496 see https://invent.kde.org/plasma/kwin/-/commit/711c5bb43f2823766d5189dc8d567c8f4cec253c see https://bugs.kde.org/show_bug.cgi\?id\=482142 --- src/protocols/core/DataDevice.cpp | 8 ++++++++ src/protocols/core/DataDevice.hpp | 4 +++- src/protocols/types/DataDevice.cpp | 4 ++++ src/protocols/types/DataDevice.hpp | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index b7640af3..8c1a48d8 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -67,6 +67,13 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPhasDnd() || dead) + return; + + source->sendDndFinished(); +} + bool CWLDataOfferResource::good() { return resource->resource(); } @@ -173,6 +180,7 @@ void CWLDataSourceResource::sendDndDropPerformed() { if (resource->version() < 3) return; resource->sendDndDropPerformed(); + dropped = true; } void CWLDataSourceResource::sendDndFinished() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 22bb9376..8aaf46be 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -29,6 +29,7 @@ class CMonitor; class CWLDataOfferResource { public: CWLDataOfferResource(SP resource_, SP source_); + ~CWLDataOfferResource(); bool good(); void sendData(); @@ -63,14 +64,15 @@ class CWLDataSourceResource : public IDataSource { virtual bool hasDnd(); virtual bool dndDone(); virtual void error(uint32_t code, const std::string& msg); + virtual void sendDndFinished(); void sendDndDropPerformed(); - void sendDndFinished(); void sendDndAction(wl_data_device_manager_dnd_action a); bool used = false; bool dnd = false; bool dndSuccess = false; + bool dropped = false; WP device; WP self; diff --git a/src/protocols/types/DataDevice.cpp b/src/protocols/types/DataDevice.cpp index eb6969cc..e95f1c76 100644 --- a/src/protocols/types/DataDevice.cpp +++ b/src/protocols/types/DataDevice.cpp @@ -19,3 +19,7 @@ void IDataSource::markUsed() { eDataSourceType IDataSource::type() { return DATA_SOURCE_TYPE_WAYLAND; } + +void IDataSource::sendDndFinished() { + ; +} diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index 948f47a0..f6757e1c 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -21,6 +21,7 @@ class IDataSource { virtual void cancelled() = 0; virtual bool hasDnd(); virtual bool dndDone(); + virtual void sendDndFinished(); virtual bool used(); virtual void markUsed(); virtual void error(uint32_t code, const std::string& msg) = 0; From d105c7403c2b700e4572149ecadd21e1d1ad24d3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 14:05:31 +0200 Subject: [PATCH 098/298] hyprctl: add next and all to switchxkblayout fixes #7555 --- src/debug/HyprCtl.cpp | 95 ++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index ddd1c1ab..683665be 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1136,46 +1136,77 @@ std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) } std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) { - CVarList vars(request, 0, ' '); + CVarList vars(request, 0, ' '); - const auto KB = vars[1]; - const auto CMD = vars[2]; + const auto KB = vars[1]; + const auto CMD = vars[2]; - // get kb - const auto PKEYBOARD = std::find_if(g_pInputManager->m_vKeyboards.begin(), g_pInputManager->m_vKeyboards.end(), - [&](const auto& other) { return other->hlName == g_pInputManager->deviceNameToInternalString(KB); }); + SP pKeyboard; - if (PKEYBOARD == g_pInputManager->m_vKeyboards.end()) - return "device not found"; + auto updateKeyboard = [](const SP KEEB, const std::string& CMD) -> std::optional { + const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap); + xkb_layout_index_t activeLayout = 0; + while (activeLayout < LAYOUTS) { + if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) + break; - const auto KEEB = *PKEYBOARD; - - const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap); - xkb_layout_index_t activeLayout = 0; - while (activeLayout < LAYOUTS) { - if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) - break; - - activeLayout++; - } - - if (CMD == "next") - KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1); - else if (CMD == "prev") - KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); - else { - int requestedLayout = 0; - try { - requestedLayout = std::stoi(CMD); - } catch (std::exception& e) { return "invalid arg 2"; } - - if (requestedLayout < 0 || (uint64_t)requestedLayout > LAYOUTS - 1) { - return "layout idx out of range of " + std::to_string(LAYOUTS); + activeLayout++; } - KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout); + if (CMD == "next") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1); + else if (CMD == "prev") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); + else { + int requestedLayout = 0; + try { + requestedLayout = std::stoi(CMD); + } catch (std::exception& e) { return "invalid arg 2"; } + + if (requestedLayout < 0 || (uint64_t)requestedLayout > LAYOUTS - 1) { + return "layout idx out of range of " + std::to_string(LAYOUTS); + } + + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout); + } + + return std::nullopt; + }; + + if (KB == "main" || KB == "active" || KB == "current") { + for (auto const& k : g_pInputManager->m_vKeyboards) { + if (!k->active) + continue; + + pKeyboard = k; + break; + } + } else if (KB == "all") { + std::string result = ""; + for (auto const& k : g_pInputManager->m_vKeyboards) { + auto res = updateKeyboard(k, CMD); + if (res.has_value()) + result += *res + "\n"; + } + return result.empty() ? "ok" : result; + } else { + auto k = std::find_if(g_pInputManager->m_vKeyboards.begin(), g_pInputManager->m_vKeyboards.end(), + [&](const auto& other) { return other->hlName == g_pInputManager->deviceNameToInternalString(KB); }); + + if (k == g_pInputManager->m_vKeyboards.end()) + return "device not found"; + + pKeyboard = *k; } + if (!pKeyboard) + return "no device"; + + auto result = updateKeyboard(pKeyboard, CMD); + + if (result.has_value()) + return *result; + return "ok"; } From 8210a1d7ac38f6af76ccbb831dc1d62b1ebc53db Mon Sep 17 00:00:00 2001 From: diniamo Date: Tue, 27 Aug 2024 09:48:38 +0200 Subject: [PATCH 099/298] nix(flake): update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index fd06ac7d..0eb6ba07 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724273991, - "narHash": "sha256-+aUSOXKGpS5CRm1oTitgNAr05ThQNbKIXalZHl3nC6Y=", + "lastModified": 1724781866, + "narHash": "sha256-ItgACCJCwn8Rx7p8hJBpnU9eCtrdmkg4AbqMZL/rXlY=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "9a3161ad4c78dc420d1cbb3aae638222608c7de4", + "rev": "7cc3d3179c06caf3769afb3eb0c69aa55676c96a", "type": "github" }, "original": { From 98e99cd03df5b4421f72f2a3f2d7de53f8261f1f Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 28 Aug 2024 08:07:13 -0500 Subject: [PATCH 100/298] renderer: ensure buffer format on commit (#7556) --- src/helpers/Monitor.cpp | 11 +++++++---- src/render/Renderer.cpp | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index d81ccb3d..2b8404ee 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -915,17 +915,20 @@ CMonitorState::~CMonitorState() { } void CMonitorState::ensureBufferPresent() { - if (!m_pOwner->output->state->state().enabled) { + const auto STATE = m_pOwner->output->state->state(); + if (!STATE.enabled) { Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled"); return; } - if (m_pOwner->output->state->state().buffer) - return; + if (STATE.buffer) { + if (const auto params = STATE.buffer->dmabuf(); params.success && params.format == m_pOwner->drmFormat) + return; + } // this is required for modesetting being possible and might be missing in case of first tests in the renderer // where we test modes and buffers - Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible"); + Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer or mismatched format, attaching one from the swapchain for modeset being possible"); m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr)); m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c601e369..7d63468e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1910,6 +1910,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->currentMode = nullptr; pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + pMonitor->drmFormat = DRM_FORMAT_XRGB8888; pMonitor->output->state->resetExplicitFences(); bool autoScale = false; From 9642311ac2ffa6605d84fef2bb5179f6588ae074 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 20:33:29 +0200 Subject: [PATCH 101/298] window: don't focus on activate if window isn't mapped yet ref #7089 --- src/desktop/Window.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 582e96a0..7da616c1 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1307,6 +1307,11 @@ void CWindow::activate(bool force) { if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) return; + if (!m_bIsMapped) { + Debug::log(LOG, "Ignoring CWindow::activate focus/warp, window is not mapped yet."); + return; + } + if (m_bIsFloating) g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); From a95df6b57e68785c13fd2d7f93d9eba28b9406ed Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 20:37:07 +0200 Subject: [PATCH 102/298] xwm: don't mark selection events as succeeded fixes #7401 --- src/xwayland/XWM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 07208072..5ad146e4 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -539,7 +539,7 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { // Debug::log(ERR, "[xwm] FIXME: CXWM::handleSelectionPropertyNotify stub"); - return true; + return false; } void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { From b9b8e6220f55af34e862b541a5a4b30ae6d8f15f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 21:54:49 +0200 Subject: [PATCH 103/298] renderer: fade out windows on silent moves --- src/desktop/Window.cpp | 10 ++++++++++ src/desktop/Window.hpp | 4 ++++ src/render/Renderer.cpp | 21 +++++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7da616c1..a4ba366a 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -31,6 +31,7 @@ PHLWINDOW CWindow::create(SP surface) { pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -52,6 +53,7 @@ PHLWINDOW CWindow::create(SP resource) { pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -407,6 +409,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; + m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->m_iMonitorID : -1; + m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F); + m_fMovingToWorkspaceAlpha = 0.F; + m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; }); + m_pWorkspace = pWorkspace; setAnimationsToMove(); @@ -502,6 +509,7 @@ void CWindow::onUnmap() { m_fAlpha.setCallbackOnEnd(unregisterVar); m_cRealShadowColor.setCallbackOnEnd(unregisterVar); m_fDimPercent.setCallbackOnEnd(unregisterVar); + m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar); m_vRealSize.setCallbackOnBegin(nullptr); @@ -542,6 +550,7 @@ void CWindow::onMap() { m_fAlpha.resetAllCallbacks(); m_cRealShadowColor.resetAllCallbacks(); m_fDimPercent.resetAllCallbacks(); + m_fMovingToWorkspaceAlpha.resetAllCallbacks(); m_vRealPosition.registerVar(); m_vRealSize.registerVar(); @@ -551,6 +560,7 @@ void CWindow::onMap() { m_fAlpha.registerVar(); m_cRealShadowColor.registerVar(); m_fDimPercent.registerVar(); + m_fMovingToWorkspaceAlpha.registerVar(); m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index e1850fb3..bdc275bf 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -352,6 +352,10 @@ class CWindow { // animated tint CAnimatedVariable m_fDimPercent; + // animate moving to an invisible workspace + int m_iMonitorMovedFrom = -1; // -1 means not moving + CAnimatedVariable m_fMovingToWorkspaceAlpha; + // swallowing PHLWINDOWREF m_pSwallowed; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7d63468e..33679731 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -266,6 +266,11 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { if (pWindow->m_bPinned) return true; + // if the window is being moved to a workspace that is not invisible, and the alpha is > 0.F, render it. + if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha.isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha.value() > 0.F && + !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + return true; + const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_iMonitorID == pMonitor->ID) { if (PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) @@ -540,14 +545,18 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (ignoreAllGeometry) decorate = false; + // whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws + const bool USE_WORKSPACE_FADE_ALPHA = pWindow->m_iMonitorMovedFrom != -1 && !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace); + renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); - renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value()); - renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); - renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); - renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; - renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later - renderdata.pWindow = pWindow; + renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha.value()) * + (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha.value() : 1.F); + renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); + renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); + renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; + renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later + renderdata.pWindow = pWindow; if (ignoreAllGeometry) { renderdata.alpha = 1.f; From 92a0dd164e9cc74060b63abae67b0204b6b6074c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 29 Aug 2024 13:41:03 +0000 Subject: [PATCH 104/298] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 0eb6ba07..219cc08b 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724781866, - "narHash": "sha256-ItgACCJCwn8Rx7p8hJBpnU9eCtrdmkg4AbqMZL/rXlY=", + "lastModified": 1724850097, + "narHash": "sha256-3BHxvFb3NJzch1X8puRMkVZujOoarQ1llu3ZcwuvsKU=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7cc3d3179c06caf3769afb3eb0c69aa55676c96a", + "rev": "23c7925dd31e79e8c06086ace3edb129a070ac01", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1722869141, - "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=", + "lastModified": 1724863980, + "narHash": "sha256-7Ke9wFRYPUIXwm5ZndGHkWBKj6BsFTkSEXUNXQRHE54=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "0252fd13e78e60fb0da512a212e56007515a49f7", + "rev": "aadf9a27dddd2272ca354ba5a22a0c2d1f919039", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1724224976, - "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=", + "lastModified": 1724819573, + "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62", + "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", "type": "github" }, "original": { From 604eb21a7e55d85ec7f6cb8cba39fc4c20a07a9d Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 29 Aug 2024 23:30:12 +0200 Subject: [PATCH 105/298] renderer: better lockscreen dead behavior (#7574) --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 10 ++- assets/install/lockdead.png | Bin 0 -> 113201 bytes assets/install/lockdead2.png | Bin 0 -> 49466 bytes assets/install/meson.build | 6 ++ assets/{ => install}/wall0.png | Bin assets/{ => install}/wall1.png | Bin assets/{ => install}/wall2.png | Bin assets/meson.build | 7 +- src/managers/SessionLockManager.cpp | 5 ++ src/managers/SessionLockManager.hpp | 1 + src/render/OpenGL.cpp | 119 +++++++++++++++++++++++++--- src/render/OpenGL.hpp | 6 +- src/render/Renderer.cpp | 53 +++++++++---- src/render/Renderer.hpp | 1 + 14 files changed, 171 insertions(+), 37 deletions(-) create mode 100755 assets/install/lockdead.png create mode 100644 assets/install/lockdead2.png create mode 100644 assets/install/meson.build rename assets/{ => install}/wall0.png (100%) rename assets/{ => install}/wall1.png (100%) rename assets/{ => install}/wall2.png (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8ea4797..84a856b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,12 +336,14 @@ install( install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) -# allow Hyprland to find wallpapers +# allow Hyprland to find assets add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") -# wallpapers -file(GLOB_RECURSE WALLPAPERS "assets/wall*") -install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr) +# installable assets +file(GLOB_RECURSE INSTALLABLE_ASSETS "assets/install/*") +list(FILTER INSTALLABLE_ASSETS EXCLUDE REGEX "meson.build") +install(FILES ${INSTALLABLE_ASSETS} + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr) # default config install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf diff --git a/assets/install/lockdead.png b/assets/install/lockdead.png new file mode 100755 index 0000000000000000000000000000000000000000..f8bae2255f9a4f576011355c8242cbb8a88079ce GIT binary patch literal 113201 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 z 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

Wp^;@NCnr|!yMD0gtmz@37hF(x7FBMPZd`; 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†hJi}L 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 literal 0 HcmV?d00001 diff --git a/assets/install/lockdead2.png b/assets/install/lockdead2.png new file mode 100644 index 0000000000000000000000000000000000000000..3f46c434aabbc47344a9e870766805d94505db73 GIT binary patch literal 49466 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 LTeIr#uipGGxM=s2 literal 0 HcmV?d00001 diff --git a/assets/install/meson.build b/assets/install/meson.build new file mode 100644 index 00000000..19b49638 --- /dev/null +++ b/assets/install/meson.build @@ -0,0 +1,6 @@ +globber = run_command('sh', '-c', 'find -type f -not -name "*.build"', check: true) +files = globber.stdout().strip().split('\n') + +foreach file : files + install_data(file, install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') +endforeach diff --git a/assets/wall0.png b/assets/install/wall0.png similarity index 100% rename from assets/wall0.png rename to assets/install/wall0.png diff --git a/assets/wall1.png b/assets/install/wall1.png similarity index 100% rename from assets/wall1.png rename to assets/install/wall1.png diff --git a/assets/wall2.png b/assets/install/wall2.png similarity index 100% rename from assets/wall2.png rename to assets/install/wall2.png diff --git a/assets/meson.build b/assets/meson.build index 47de3d02..0648037a 100644 --- a/assets/meson.build +++ b/assets/meson.build @@ -1,7 +1,2 @@ -wallpapers = ['0', '1', '2'] - -foreach type : wallpapers - install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') -endforeach - install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') +subdir('install') diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 81e22889..7267b8f2 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -4,6 +4,7 @@ #include "../protocols/FractionalScale.hpp" #include "../protocols/SessionLock.hpp" #include +#include SSessionLockSurface::SSessionLockSurface(SP surface_) : surface(surface_) { pWlrSurface = surface->surface(); @@ -166,3 +167,7 @@ void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) { bool CSessionLockManager::isSessionLockPresent() { return m_pSessionLock && !m_pSessionLock->vSessionLockSurfaces.empty(); } + +bool CSessionLockManager::anySessionLockSurfacesPresent() { + return m_pSessionLock && std::ranges::any_of(m_pSessionLock->vSessionLockSurfaces, [](const auto& surf) { return surf->mapped; }); +} diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index b01ee288..9b3b882c 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -55,6 +55,7 @@ class CSessionLockManager { bool isSessionLocked(); bool isSessionLockPresent(); bool isSurfaceSessionLock(SP); + bool anySessionLockSurfacesPresent(); void removeSessionLockSurface(SSessionLockSurface*); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 67c11c23..91849701 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -338,6 +338,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { initDRMFormats(); + initAssets(); + static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast(data)); }); RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); @@ -2614,14 +2616,17 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const cairo_surface_flush(CAIROSURFACE); } -void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { - const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str()); - const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); +SP CHyprOpenGLImpl::loadAsset(const std::string& file) { + const auto CAIROSURFACE = cairo_image_surface_create_from_png(file.c_str()); - m_pBackgroundTexture = makeShared(); + if (!CAIROSURFACE) + return nullptr; - m_pBackgroundTexture->allocate(); - m_pBackgroundTexture->m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); + auto tex = makeShared(); + + tex->allocate(); + tex->m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? #ifdef GLES2 @@ -2634,7 +2639,7 @@ void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - glBindTexture(GL_TEXTURE_2D, m_pBackgroundTexture->m_iTexID); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifndef GLES2 @@ -2643,9 +2648,105 @@ void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); } #endif - glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, m_pBackgroundTexture->m_vSize.x, m_pBackgroundTexture->m_vSize.y, 0, glFormat, glType, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); cairo_surface_destroy(CAIROSURFACE); + + return tex; +} + +SP CHyprOpenGLImpl::renderText(const std::string& text, CColor col, int pt, bool italic) { + SP tex = makeShared(); + + static auto FONT = CConfigValue("misc:font_family"); + + const auto FONTFAMILY = *FONT; + const auto FONTSIZE = pt; + const auto COLOR = col; + + auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* arbitrary, just for size */); + auto CAIRO = cairo_create(CAIROSURFACE); + + PangoLayout* layoutText = pango_cairo_create_layout(CAIRO); + PangoFontDescription* pangoFD = pango_font_description_new(); + + pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); + + cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a); + + int textW = 0, textH = 0; + pango_layout_set_text(layoutText, text.c_str(), -1); + pango_layout_get_size(layoutText, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; + + pango_font_description_free(pangoFD); + g_object_unref(layoutText); + cairo_destroy(CAIRO); + cairo_surface_destroy(CAIROSURFACE); + + CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, textW, textH); + CAIRO = cairo_create(CAIROSURFACE); + + layoutText = pango_cairo_create_layout(CAIRO); + pangoFD = pango_font_description_new(); + + pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); + pango_layout_set_text(layoutText, text.c_str(), -1); + + cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a); + + cairo_move_to(CAIRO, 0, 0); + pango_cairo_show_layout(CAIRO, layoutText); + + pango_font_description_free(pangoFD); + g_object_unref(layoutText); + + cairo_surface_flush(CAIROSURFACE); + + tex->allocate(); + tex->m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + + const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#ifndef GLES2 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->m_vSize.x, tex->m_vSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + + cairo_destroy(CAIRO); + cairo_surface_destroy(CAIROSURFACE); + + return tex; +} + +void CHyprOpenGLImpl::initAssets() { + std::string assetsPath = ""; +#ifndef DATAROOTDIR + assetsPath = "/usr/share/hypr/"; +#else + assetsPath = std::format("{}{}", DATAROOTDIR, "/hypr/"); +#endif + + m_pLockDeadTexture = loadAsset(assetsPath + "lockdead.png"); + m_pLockDead2Texture = loadAsset(assetsPath + "lockdead2.png"); + + m_pLockTtyTextTexture = renderText(std::format("Running on tty {}", + g_pCompositor->m_pAqBackend->hasSession() && g_pCompositor->m_pAqBackend->session->vt > 0 ? + std::to_string(g_pCompositor->m_pAqBackend->session->vt) : + "unknown"), + CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); } void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { @@ -2694,7 +2795,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { return; // the texture will be empty, oh well. We'll clear with a solid color anyways. } - createBackgroundTexture(texPath); + m_pBackgroundTexture = loadAsset(texPath); } // create a new one with cairo diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index f405cb7c..06078a00 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -277,7 +277,7 @@ class CHyprOpenGLImpl { CShader m_sFinalScreenShader; CTimer m_tGlobalTimer; - SP m_pBackgroundTexture; + SP m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture; void logShaderError(const GLuint&, bool program = false); GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); @@ -287,7 +287,9 @@ class CHyprOpenGLImpl { void initDRMFormats(); void initEGL(bool gbm); EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); - void createBackgroundTexture(const std::string& path); + SP loadAsset(const std::string& file); + SP renderText(const std::string& text, CColor col, int pt, bool italic = false); + void initAssets(); // std::optional> getModsForFormat(EGLint format); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 33679731..2854a973 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -839,9 +839,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSessionLockPresent()) { // locked with no exclusive, draw only red - CBox boxe = {0, 0, INT16_MAX, INT16_MAX}; - const float A = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); - g_pHyprOpenGL->renderRect(&boxe, CColor(1.0, 0.2, 0.2, A)); + renderSessionLockMissing(pMonitor); return; } @@ -1001,27 +999,50 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB if (g_pSessionLockManager->isSessionLocked()) { Vector2D translate = {geometry.x, geometry.y}; - float scale = (float)geometry.width / pMonitor->vecPixelSize.x; const auto PSLS = g_pSessionLockManager->getSessionLockSurfaceForMonitor(pMonitor->ID); - if (!PSLS) { - // locked with no surface, fill with red - const auto ALPHA = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); - - CBox monbox = {translate.x, translate.y, pMonitor->vecTransformedSize.x * scale, pMonitor->vecTransformedSize.y * scale}; - g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); - - if (ALPHA < 1.f) /* animate */ - damageMonitor(pMonitor); - else - g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); - } else { + if (!PSLS) + renderSessionLockMissing(pMonitor); + else { renderSessionLockSurface(PSLS, pMonitor, now); g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } } } +void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) { + const auto ALPHA = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); + + CBox monbox = {{}, pMonitor->vecPixelSize}; + + const bool ANY_PRESENT = g_pSessionLockManager->anySessionLockSurfacesPresent(); + + if (ANY_PRESENT) { + // render image2, without instructions. Lock still "alive", unless texture dead + if (g_pHyprOpenGL->m_pLockDead2Texture) + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, &monbox, ALPHA); + else + g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); + } else { + // render image, with instructions. Lock is gone. + if (g_pHyprOpenGL->m_pLockDeadTexture) { + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, &monbox, ALPHA); + + // also render text for the tty number + if (g_pHyprOpenGL->m_pLockTtyTextTexture) { + CBox texbox = {{}, g_pHyprOpenGL->m_pLockTtyTextTexture->m_vSize}; + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, &texbox, 1.F); + } + } else + g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); + } + + if (ALPHA < 1.f) /* animate */ + damageMonitor(pMonitor); + else + g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); +} + void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 0b16efea..d00c0a17 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -123,6 +123,7 @@ class CHyprRenderer { void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); + void renderSessionLockMissing(CMonitor* pMonitor); bool commitPendingAndDoExplicitSync(CMonitor* pMonitor); From ef33198e8f9fa874b3ad2e2775f8474af62d7fee Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 30 Aug 2024 14:10:46 +0300 Subject: [PATCH 106/298] flake.lock: update aquamarine and hyprutils --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 219cc08b..b26cd5e3 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724850097, - "narHash": "sha256-3BHxvFb3NJzch1X8puRMkVZujOoarQ1llu3ZcwuvsKU=", + "lastModified": 1725016199, + "narHash": "sha256-2TMk7F2a27ZtOUW/bftkDyZKp3OQ71E5XnfKSUT8HZQ=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "23c7925dd31e79e8c06086ace3edb129a070ac01", + "rev": "cff00196f0fcf734a2bf164eb0dfdb6e58c5c906", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1724863980, - "narHash": "sha256-7Ke9wFRYPUIXwm5ZndGHkWBKj6BsFTkSEXUNXQRHE54=", + "lastModified": 1724966483, + "narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "aadf9a27dddd2272ca354ba5a22a0c2d1f919039", + "rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2", "type": "github" }, "original": { From 259dcd838eef8d6eb2f88f2c0935e32bf7985ebd Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Fri, 30 Aug 2024 07:04:09 -0500 Subject: [PATCH 107/298] xwayland: update overrideRedirect on map and configure (#7575) --- src/xwayland/XWM.cpp | 15 ++++++++++++++- src/xwayland/XWM.hpp | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 5ad146e4..b5762762 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -81,6 +81,7 @@ void CXWM::handleConfigureNotify(xcb_configure_notify_event_t* e) { return; XSURF->geometry = {e->x, e->y, e->width, e->height}; + updateOverrideRedirect(XSURF, e->override_redirect); XSURF->events.setGeometry.emit(); } @@ -115,7 +116,12 @@ void CXWM::handleMapRequest(xcb_map_request_event_t* e) { void CXWM::handleMapNotify(xcb_map_notify_event_t* e) { const auto XSURF = windowForXID(e->window); - if (!XSURF || XSURF->overrideRedirect) + if (!XSURF) + return; + + updateOverrideRedirect(XSURF, e->override_redirect); + + if (XSURF->overrideRedirect) return; XSURF->setWithdrawn(false); @@ -1044,6 +1050,13 @@ bool CXWM::isWMWindow(xcb_window_t w) { return w == wmWindow || w == clipboard.window; } +void CXWM::updateOverrideRedirect(SP surf, bool overrideRedirect) { + if (!surf || surf->overrideRedirect == overrideRedirect) + return; + + surf->overrideRedirect = overrideRedirect; +} + void CXWM::initSelection() { clipboard.window = xcb_generate_id(connection); uint32_t mask[1] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE}; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 4f6f3f7c..7d6b63ed 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -82,6 +82,7 @@ class CXWM { void focusWindow(SP surf); void activateSurface(SP surf, bool activate); bool isWMWindow(xcb_window_t w); + void updateOverrideRedirect(SP surf, bool overrideRedirect); void sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask); From 25e72949a1cc2368425ed81712a394cb277f514f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 14:12:23 +0200 Subject: [PATCH 108/298] window/xwayland: minor property cleanup fixes #6921 --- src/Compositor.cpp | 14 +++++++------- src/desktop/Window.cpp | 13 ++++++++++--- src/desktop/Window.hpp | 4 ++-- src/events/Windows.cpp | 8 ++++---- src/helpers/Monitor.cpp | 2 +- src/layout/IHyprLayout.cpp | 14 +++++++------- src/managers/AnimationManager.cpp | 2 +- src/managers/XWaylandManager.cpp | 11 ++++------- src/managers/input/InputManager.cpp | 4 ++-- 9 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index cacbeece..7ae3070d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -791,7 +791,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & ALLOW_FLOATING) { for (auto const& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); - CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) @@ -821,16 +821,16 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) continue; - CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent - if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) + if (w->m_bX11ShouldntFocus && !w->isX11OverrideRedirect()) continue; if (box.containsPoint(g_pPointerManager->position())) { - if (w->m_bIsX11 && w->m_iX11Type == 2 && !w->m_pXWaylandSurface->wantsFocus()) { + if (w->m_bIsX11 && w->isX11OverrideRedirect() && !w->m_pXWaylandSurface->wantsFocus()) { // Override Redirect return g_pCompositor->m_pLastWindow.lock(); // we kinda trick everything here. // TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases. @@ -997,7 +997,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface return; } - if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !pWindow->m_pXWaylandSurface->wantsFocus()) + if (pWindow && pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect() && !pWindow->m_pXWaylandSurface->wantsFocus()) return; g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow); @@ -1071,7 +1071,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface updateWindowAnimatedDecorationValues(PLASTWINDOW); - if (!pWindow->m_bIsX11 || pWindow->m_iX11Type == 1) + if (!pWindow->m_bIsX11 || !pWindow->isX11OverrideRedirect()) g_pXWaylandManager->activateWindow(PLASTWINDOW, false); } @@ -1928,7 +1928,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // shadow - if (pWindow->m_iX11Type != 2 && !pWindow->m_bX11DoesntWantBorders) { + if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { if (pWindow == m_pLastWindow) { pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL); } else { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index a4ba366a..7623d45e 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -19,9 +19,8 @@ using namespace Hyprutils::String; PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); - pWindow->m_pSelf = pWindow; - pWindow->m_bIsX11 = true; - pWindow->m_iX11Type = surface->overrideRedirect ? 2 : 1; + pWindow->m_pSelf = pWindow; + pWindow->m_bIsX11 = true; pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); @@ -1571,3 +1570,11 @@ void CWindow::unsetWindowData(eOverridePriority priority) { element.second(m_pSelf.lock())->unset(priority); } } + +bool CWindow::isX11OverrideRedirect() { + return m_pXWaylandSurface && m_pXWaylandSurface->overrideRedirect; +} + +bool CWindow::isModal() { + return (m_pXWaylandSurface && m_pXWaylandSurface->modal); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index bdc275bf..7197ba26 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -288,8 +288,6 @@ class CWindow { // XWayland stuff bool m_bIsX11 = false; PHLWINDOWREF m_pX11Parent; - uint64_t m_iX11Type = 0; - bool m_bIsModal = false; bool m_bX11DoesntWantBorders = false; bool m_bX11ShouldntFocus = false; float m_fX11SurfaceScaledBy = 1.f; @@ -468,6 +466,8 @@ class CWindow { void warpCursor(); PHLWINDOW getSwallower(); void unsetWindowData(eOverridePriority priority); + bool isX11OverrideRedirect(); + bool isModal(); // listeners void onAck(uint32_t serial); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index cd000223..034920a2 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -120,7 +120,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bRequestsFloat = true; } - PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !PWINDOW->m_pXWaylandSurface->wantsFocus()); + PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->isX11OverrideRedirect() && !PWINDOW->m_pXWaylandSurface->wantsFocus()); if (PWORKSPACE->m_bDefaultFloating) PWINDOW->m_bIsFloating = true; @@ -477,7 +477,7 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus && - (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && + (!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); @@ -577,7 +577,7 @@ void Events::listener_mapWindow(void* owner, void* data) { g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); - if (PMONITOR && PWINDOW->m_iX11Type == 2) + if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; } @@ -816,7 +816,7 @@ void Events::listener_activateX11(void* owner, void* data) { Debug::log(LOG, "X11 Activate request for window {}", PWINDOW); - if (PWINDOW->m_iX11Type == 2) { + if (PWINDOW->isX11OverrideRedirect()) { Debug::log(LOG, "Unmanaged X11 {} requests activate", PWINDOW); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 2b8404ee..8af0bc62 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -721,7 +721,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { w->setAnimationsToMove(); const auto MIDDLE = w->middle(); - if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) { + if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && !w->isX11OverrideRedirect()) { // if it's floating and the middle isnt on the current mon, move it to the center const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE); Vector2D pos = w->m_vRealPosition.goal(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f6339beb..c5a5373c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -104,7 +104,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { pWindow->m_vRealSize = PWINDOWSURFACE->current.size; if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && - pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms? + pWindow->isX11OverrideRedirect()) { // XDG windows should be fine. TODO: check for weird atoms? pWindow->setHidden(true); return; } @@ -113,7 +113,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5) pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; - if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { + if (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect()) { if (pWindow->m_pXWaylandSurface->geometry.x != 0 && pWindow->m_pXWaylandSurface->geometry.y != 0) pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos()); @@ -163,12 +163,12 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale; - if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2)) { + if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect())) { pWindow->m_vRealPosition.warp(); pWindow->m_vRealSize.warp(); } - if (pWindow->m_iX11Type != 2) { + if (!pWindow->isX11OverrideRedirect()) { g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal()); g_pCompositor->changeWindowZOrder(pWindow, true); @@ -592,7 +592,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { // find whether there is a floating window below this one for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && + if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && !w->isX11OverrideRedirect() && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) { if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, w->m_vPosition.y + w->m_vSize.y)) { @@ -612,7 +612,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { // if not, floating window for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && + if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && !w->isX11OverrideRedirect() && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) return w; } @@ -631,7 +631,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus || - pWindowCandidate->m_iX11Type == 2 || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) + pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) return nullptr; return pWindowCandidate; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index e2fe7089..092d9721 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -194,7 +194,7 @@ void CAnimationManager::tick() { default: UNREACHABLE(); } // set size and pos if valid, but only if damage policy entire (dont if border for example) - if (validMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2) + if (validMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && !PWINDOW->isX11OverrideRedirect()) g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); // check if we did not finish animating. If so, trigger onAnimationEnd. diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index b37e796b..144343f8 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -59,7 +59,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (activate) { pWindow->m_pXWaylandSurface->setMinimized(false); - if (pWindow->m_iX11Type != 2) + if (!pWindow->isX11OverrideRedirect()) pWindow->m_pXWaylandSurface->restackToTop(); } @@ -80,7 +80,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { if (pWindow->m_bIsX11) { const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); - if (SIZEHINTS && pWindow->m_iX11Type != 2) { + if (SIZEHINTS && !pWindow->isX11OverrideRedirect()) { // WM_SIZE_HINTS' x,y,w,h is deprecated it seems. // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property pbox->x = pWindow->m_pXWaylandSurface->geometry.x; @@ -160,10 +160,8 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { return true; } - if (pWindow->m_pXWaylandSurface->modal) { - pWindow->m_bIsModal = true; + if (pWindow->isModal()) return true; - } if (pWindow->m_pXWaylandSurface->transient) return true; @@ -203,9 +201,8 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { } } - if (pWindow->m_iX11Type == 2) { + if (pWindow->isX11OverrideRedirect()) pWindow->m_bX11DoesntWantBorders = true; - } } void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) { diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 6b04c13f..78c9e437 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -675,7 +675,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // clicking on border triggers resize // TODO detect click on LS properly - if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) { + if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || !w->isX11OverrideRedirect())) { if (w && !w->isFullscreen()) { const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; @@ -1688,7 +1688,7 @@ void CInputManager::setCursorIconOnBorder(PHLWINDOW w) { } // ignore X11 OR windows, they shouldn't be touched - if (w->m_bIsX11 && w->m_iX11Type == 2) + if (w->m_bIsX11 && w->isX11OverrideRedirect()) return; static auto PEXTENDBORDERGRAB = CConfigValue("general:extend_border_grab_area"); From 242e06b24212b61e7afbdf5cf4adae8886a28abd Mon Sep 17 00:00:00 2001 From: darkwater Date: Fri, 30 Aug 2024 15:06:49 +0200 Subject: [PATCH 109/298] keybinds: release mods after sendshortcut (#7581) --- src/managers/KeybindManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index df3f2572..72799f1d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2349,6 +2349,8 @@ SDispatchResult CKeybindManager::sendshortcut(std::string args) { } } + g_pSeatManager->sendKeyboardMods(0, 0, 0, 0); + if (!PWINDOW) return {}; From 1c9d56998dbf3a9b61e13573e9e91d149fe65969 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 15:18:12 +0200 Subject: [PATCH 110/298] xdg-dialog: implement new protocol --- CMakeLists.txt | 1 + protocols/meson.build | 1 + src/Compositor.cpp | 17 ++++-- src/managers/ProtocolManager.cpp | 2 + src/protocols/XDGDialog.cpp | 88 ++++++++++++++++++++++++++++++++ src/protocols/XDGDialog.hpp | 57 +++++++++++++++++++++ src/protocols/XDGShell.cpp | 18 ++++++- src/protocols/XDGShell.hpp | 8 ++- src/render/OpenGL.cpp | 5 +- 9 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 src/protocols/XDGDialog.cpp create mode 100644 src/protocols/XDGDialog.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 84a856b8..dba14813 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,6 +315,7 @@ protocolnew("stable/viewporter" "viewporter" false) protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) +protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolwayland() diff --git a/protocols/meson.build b/protocols/meson.build index 5b807914..de650230 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -60,6 +60,7 @@ new_protocols = [ [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], [wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'], [wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'], + [wl_protocol_dir, 'staging/xdg-dialog/xdg-dialog-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7ae3070d..eac75bd4 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1888,6 +1888,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { pWindow->m_fBorderFadeAnimationProgress = 1.f; }; + const bool IS_SHADOWED_BY_MODAL = pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel && pWindow->m_pXDGSurface->toplevel->anyChildModal(); + // border const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow); if (RENDERDATA.isBorderGradient) @@ -1921,11 +1923,16 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // dim - if (pWindow == m_pLastWindow.lock() || pWindow->m_sWindowData.noDim.valueOrDefault() || !*PDIMENABLED) { - pWindow->m_fDimPercent = 0; - } else { - pWindow->m_fDimPercent = *PDIMSTRENGTH; - } + float goalDim = 1.F; + if (pWindow == m_pLastWindow.lock() || pWindow->m_sWindowData.noDim.valueOrDefault() || !*PDIMENABLED) + goalDim = 0; + else + goalDim = *PDIMSTRENGTH; + + if (IS_SHADOWED_BY_MODAL) + goalDim += (1.F - goalDim) / 2.F; + + pWindow->m_fDimPercent = goalDim; // shadow if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index bace4451..2c421abe 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -43,6 +43,7 @@ #include "../protocols/ToplevelExport.hpp" #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" +#include "../protocols/XDGDialog.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -150,6 +151,7 @@ CProtocolManager::CProtocolManager() { PROTO::screencopy = std::make_unique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); + PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) diff --git a/src/protocols/XDGDialog.cpp b/src/protocols/XDGDialog.cpp new file mode 100644 index 00000000..237cf3f3 --- /dev/null +++ b/src/protocols/XDGDialog.cpp @@ -0,0 +1,88 @@ +#include "XDGDialog.hpp" +#include "XDGShell.hpp" +#include "../desktop/WLSurface.hpp" +#include "../Compositor.hpp" +#include + +CXDGDialogV1Resource::CXDGDialogV1Resource(SP resource_, SP toplevel_) : resource(resource_), toplevel(toplevel_) { + if (!good()) + return; + + resource->setDestroy([this](CXdgDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + resource->setOnDestroy([this](CXdgDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + + resource->setSetModal([this](CXdgDialogV1* r) { + modal = true; + updateWindow(); + }); + + resource->setUnsetModal([this](CXdgDialogV1* r) { + modal = false; + updateWindow(); + }); +} + +void CXDGDialogV1Resource::updateWindow() { + if (!toplevel || !toplevel->parent || !toplevel->parent->owner) + return; + + auto HLSurface = CWLSurface::fromResource(toplevel->parent->owner->surface.lock()); + if (!HLSurface || !HLSurface->getWindow()) + return; + + g_pCompositor->updateWindowAnimatedDecorationValues(HLSurface->getWindow()); +} + +bool CXDGDialogV1Resource::good() { + return resource->resource(); +} + +CXDGWmDialogManagerResource::CXDGWmDialogManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CXdgWmDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + resource->setOnDestroy([this](CXdgWmDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + + resource->setGetXdgDialog([this](CXdgWmDialogV1* r, uint32_t id, wl_resource* toplevel) { + auto tl = CXDGToplevelResource::fromResource(toplevel); + if (!tl) { + r->error(-1, "Toplevel inert"); + return; + } + + const auto RESOURCE = PROTO::xdgDialog->m_vDialogs.emplace_back(makeShared(makeShared(r->client(), r->version(), id), tl)); + + if (!RESOURCE->good()) { + r->noMemory(); + return; + } + + tl->dialog = RESOURCE; + }); +} + +bool CXDGWmDialogManagerResource::good() { + return resource->resource(); +} + +CXDGDialogProtocol::CXDGDialogProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CXDGDialogProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + return; + } +} + +void CXDGDialogProtocol::destroyResource(CXDGWmDialogManagerResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CXDGDialogProtocol::destroyResource(CXDGDialogV1Resource* res) { + std::erase_if(m_vDialogs, [&](const auto& other) { return other.get() == res; }); +} diff --git a/src/protocols/XDGDialog.hpp b/src/protocols/XDGDialog.hpp new file mode 100644 index 00000000..a635bfac --- /dev/null +++ b/src/protocols/XDGDialog.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "xdg-dialog-v1.hpp" + +class CXDGToplevelResource; + +class CXDGDialogV1Resource { + public: + CXDGDialogV1Resource(SP resource_, SP toplevel_); + + bool good(); + + bool modal = false; + + private: + SP resource; + WP toplevel; + + void updateWindow(); +}; + +class CXDGWmDialogManagerResource { + public: + CXDGWmDialogManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CXDGDialogProtocol : public IWaylandProtocol { + public: + CXDGDialogProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CXDGWmDialogManagerResource* res); + void destroyResource(CXDGDialogV1Resource* res); + + // + std::vector> m_vManagers; + std::vector> m_vDialogs; + + friend class CXDGWmDialogManagerResource; + friend class CXDGDialogV1Resource; +}; + +namespace PROTO { + inline UP xdgDialog; +}; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 39a511c3..25d8b1ba 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -1,10 +1,12 @@ #include "XDGShell.hpp" +#include "XDGDialog.hpp" #include #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include +#include void SXDGPositionerState::setAnchor(xdgPositionerAnchor edges) { anchor.setTop(edges == XDG_POSITIONER_ANCHOR_TOP || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT); @@ -207,15 +209,25 @@ CXDGToplevelResource::CXDGToplevelResource(SP resource_, SPsetSetParent([this](CXdgToplevel* r, wl_resource* parentR) { + auto oldParent = parent; + + if (parent) + std::erase(parent->children, self); + auto newp = parentR ? CXDGToplevelResource::fromResource(parentR) : nullptr; parent = newp; - LOGM(LOG, "Toplevel {:x} sets parent to {:x}", (uintptr_t)this, (uintptr_t)newp.get()); + if (parent) + parent->children.emplace_back(self); + + LOGM(LOG, "Toplevel {:x} sets parent to {:x}{}", (uintptr_t)this, (uintptr_t)newp.get(), (oldParent ? std::format(" (was {:x})", (uintptr_t)oldParent.get()) : "")); }); } CXDGToplevelResource::~CXDGToplevelResource() { events.destroy.emit(); + if (parent) + std::erase_if(parent->children, [this](const auto& other) { return !other || other.get() == this; }); } SP CXDGToplevelResource::fromResource(wl_resource* res) { @@ -227,6 +239,10 @@ bool CXDGToplevelResource::good() { return resource->resource(); } +bool CXDGToplevelResource::anyChildModal() { + return std::ranges::any_of(children, [](const auto& child) { return child && child->dialog && child->dialog->modal; }); +} + uint32_t CXDGToplevelResource::setSize(const Vector2D& size) { pendingApply.size = size; applyState(); diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 81d10613..9c766c20 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -18,6 +18,7 @@ class CXDGToplevelResource; class CXDGPopupResource; class CSeatGrab; class CWLSurfaceResource; +class CXDGDialogV1Resource; struct SXDGPositionerState { Vector2D requestedSize; @@ -134,7 +135,12 @@ class CXDGToplevelResource { Vector2D maxSize = {1337420, 694200}; } pending, current; - WP parent; + WP parent; + WP dialog; + + bool anyChildModal(); + + std::vector> children; private: SP resource; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 91849701..74d3d3cd 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1378,8 +1378,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB CBox newBox = *pBox; m_RenderData.renderModif.applyToBox(newBox); - static auto PDIMINACTIVE = CConfigValue("decoration:dim_inactive"); - static auto PDT = CConfigValue("debug:damage_tracking"); + static auto PDT = CConfigValue("debug:damage_tracking"); // get the needed transform for this texture const bool TRANSFORMS_MATCH = wlTransformToHyprutils(m_RenderData.pMonitor->transform) == tex->m_eTransform; // FIXME: combine them properly!!! @@ -1493,7 +1492,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y); glUniform1f(shader->radius, round); - if (allowDim && m_pCurrentWindow.lock() && *PDIMINACTIVE) { + if (allowDim && m_pCurrentWindow.lock()) { glUniform1i(shader->applyTint, 1); const auto DIM = m_pCurrentWindow->m_fDimPercent.value(); glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); From fd8d8e122ed9cf49f3f84d4d264f1b810c355a07 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 15:26:00 +0200 Subject: [PATCH 111/298] keybinds: fixup misused kb state fixes #7369 --- src/managers/KeybindManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 72799f1d..7ee5ae7e 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -372,7 +372,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput - const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbStaticState : m_pXKBTranslationState, KEYCODE); + const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); if (handleInternalKeybinds(internalKeysym)) From fbd63543930417f3cefe36bdb9f2cdd20fc3693a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 15:50:25 +0200 Subject: [PATCH 112/298] presentation-feedback: minor fixups --- src/helpers/Monitor.cpp | 4 ++-- src/protocols/PresentationTime.cpp | 12 +++++++----- src/protocols/PresentationTime.hpp | 8 +++++--- src/protocols/core/Compositor.cpp | 2 +- src/protocols/core/Compositor.hpp | 2 +- src/render/Renderer.cpp | 4 ++-- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 8af0bc62..685009fd 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -47,7 +47,7 @@ void CMonitor::onConnect(bool noRule) { listeners.presented = output->events.present.registerListener([this](std::any d) { auto E = std::any_cast(d); - PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags); + PROTO::presentation->onPresented(self.lock(), E.when, E.refresh, E.seq, E.flags); }); listeners.destroy = output->events.destroy.registerListener([this](std::any d) { @@ -861,7 +861,7 @@ bool CMonitor::attemptDirectScanout() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - PSURFACE->presentFeedback(&now, this); + PSURFACE->presentFeedback(&now, self.lock()); output->state->addDamage(CBox{{}, vecPixelSize}); output->state->resetExplicitFences(); diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index b1108042..e1ff52cd 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -14,7 +14,7 @@ void CQueuedPresentationData::setPresentationType(bool zeroCopy_) { zeroCopy = zeroCopy_; } -void CQueuedPresentationData::attachMonitor(CMonitor* pMonitor_) { +void CQueuedPresentationData::attachMonitor(SP pMonitor_) { pMonitor = pMonitor_; } @@ -67,12 +67,14 @@ void CPresentationFeedback::sendQueued(SP data, timespe (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); else resource->sendDiscarded(); + + done = true; } CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { const auto PMONITOR = std::any_cast(param); - std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); + std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor.get() == PMONITOR; }); }); } @@ -105,7 +107,7 @@ void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* su } } -void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { +void CPresentationProtocol::onPresented(SP pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { timespec now; timespec* presentedAt = when; if (!presentedAt) { @@ -119,7 +121,7 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint continue; for (auto const& data : m_vQueue) { - if (!data->surface || data->surface != feedback->surface) + if (!data->surface || data->surface != feedback->surface || (data->pMonitor && data->pMonitor != pMonitor)) continue; feedback->sendQueued(data, when, untilRefreshNs, seq, reportedFlags); @@ -129,7 +131,7 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint } std::erase_if(m_vFeedbacks, [](const auto& other) { return !other->surface || other->done; }); - std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; }); + std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor || other->done; }); } void CPresentationProtocol::queueData(SP data) { diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index 2c6ce3e9..06c71c9a 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -14,15 +14,17 @@ class CQueuedPresentationData { CQueuedPresentationData(SP surf); void setPresentationType(bool zeroCopy); - void attachMonitor(CMonitor* pMonitor); + void attachMonitor(SP pMonitor); void presented(); void discarded(); + bool done = false; + private: bool wasPresented = false; bool zeroCopy = false; - CMonitor* pMonitor = nullptr; + WP pMonitor; WP surface; DYNLISTENER(destroySurface); @@ -53,7 +55,7 @@ class CPresentationProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); - void onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); + void onPresented(SP pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); void queueData(SP data); private: diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index f7f6dcda..37a4bdf1 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -509,7 +509,7 @@ void CWLSurfaceResource::updateCursorShm() { memcpy(shmData.data(), pixelData, bufLen); } -void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor) { +void CWLSurfaceResource::presentFeedback(timespec* when, SP pMonitor) { frame(when); auto FEEDBACK = makeShared(self.lock()); FEEDBACK->attachMonitor(pMonitor); diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index a3245399..dc1c851f 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -124,7 +124,7 @@ class CWLSurfaceResource { void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); - void presentFeedback(timespec* when, CMonitor* pMonitor); + void presentFeedback(timespec* when, SP pMonitor); void lockPendingState(); void unlockPendingState(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2854a973..420f8d4c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -185,7 +185,7 @@ static void renderSurface(SP surface, int x, int y, void* da if (windowBox.width <= 1 || windowBox.height <= 1) { if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { Debug::log(TRACE, "presentFeedback for invisible surface"); - surface->presentFeedback(RDATA->when, RDATA->pMonitor); + surface->presentFeedback(RDATA->when, RDATA->pMonitor->self.lock()); } return; // invisible @@ -240,7 +240,7 @@ static void renderSurface(SP surface, int x, int y, void* da } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) - surface->presentFeedback(RDATA->when, RDATA->pMonitor); + surface->presentFeedback(RDATA->when, RDATA->pMonitor->self.lock()); g_pHyprOpenGL->blend(true); From c5fd5771814958ad274ea9abb961fff621a35b9c Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:37:52 +0200 Subject: [PATCH 113/298] config: Add a window rule to render while unfocused (#7582) --- src/config/ConfigDescriptions.hpp | 6 +++ src/config/ConfigManager.cpp | 3 +- src/desktop/Window.cpp | 5 +++ src/desktop/Window.hpp | 1 + src/managers/eventLoop/EventLoopTimer.cpp | 4 ++ src/managers/eventLoop/EventLoopTimer.hpp | 1 + src/render/Renderer.cpp | 50 +++++++++++++++++++++++ src/render/Renderer.hpp | 4 ++ 8 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 73b995ae..73f3c9a3 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1037,6 +1037,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "misc:render_unfocused_fps", + .description = "the maximum limit for renderunfocused windows' fps in the background", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{15, 1, 120}, + }, /* * binds: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f402958b..5940a6fe 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -357,6 +357,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:exit_window_retains_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); + m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); @@ -2155,7 +2156,7 @@ std::optional CConfigManager::handleUnbind(const std::string& comma bool windowRuleValid(const std::string& RULE) { static const auto rules = std::unordered_set{ - "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", + "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", }; static const auto rulesPrefix = std::vector{ "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7623d45e..a9e389a6 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -757,6 +757,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { if (m_sGroupData.pNextWindow.expired()) setHidden(false); } catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); } + } else if (r.szRule == "renderunfocused") { + m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority); + g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock()); } } @@ -774,6 +777,8 @@ void CWindow::updateDynamicRules() { m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE); m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE); + m_sWindowData.renderUnfocused.unset(PRIORITY_WINDOW_RULE); + m_eIdleInhibitMode = IDLEINHIBIT_NONE; m_tags.removeDynamicTags(); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 7197ba26..d14248c5 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -174,6 +174,7 @@ struct SWindowData { CWindowOverridableVar syncFullscreen = true; CWindowOverridableVar tearing = false; CWindowOverridableVar xray = false; + CWindowOverridableVar renderUnfocused = false; CWindowOverridableVar rounding; CWindowOverridableVar borderSize; diff --git a/src/managers/eventLoop/EventLoopTimer.cpp b/src/managers/eventLoop/EventLoopTimer.cpp index d3cfdf8d..b8943b7c 100644 --- a/src/managers/eventLoop/EventLoopTimer.cpp +++ b/src/managers/eventLoop/EventLoopTimer.cpp @@ -49,3 +49,7 @@ float CEventLoopTimer::leftUs() { return std::chrono::duration_cast(*expires - std::chrono::steady_clock::now()).count(); } + +bool CEventLoopTimer::armed() { + return expires.has_value(); +} diff --git a/src/managers/eventLoop/EventLoopTimer.hpp b/src/managers/eventLoop/EventLoopTimer.hpp index ad7d3986..e5a8c5e3 100644 --- a/src/managers/eventLoop/EventLoopTimer.hpp +++ b/src/managers/eventLoop/EventLoopTimer.hpp @@ -16,6 +16,7 @@ class CEventLoopTimer { void cancel(); bool passed(); + bool armed(); float leftUs(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 420f8d4c..c5866e4a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -97,6 +97,44 @@ CHyprRenderer::CHyprRenderer() { m_pCursorTicker = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, cursorTicker, nullptr); wl_event_source_timer_update(m_pCursorTicker, 500); + + m_tRenderUnfocusedTimer = makeShared( + std::nullopt, + [this](SP self, void* data) { + static auto PFPS = CConfigValue("misc:render_unfocused_fps"); + + if (m_vRenderUnfocused.empty()) + return; + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + bool dirty = false; + for (auto& w : m_vRenderUnfocused) { + if (!w) { + dirty = true; + continue; + } + + if (!w->m_pWLSurface || !w->m_pWLSurface->resource() || shouldRenderWindow(w.lock())) + continue; + + w->m_pWLSurface->resource()->frame(&now); + auto FEEDBACK = makeShared(w->m_pWLSurface->resource()); + FEEDBACK->attachMonitor(g_pCompositor->m_pLastMonitor.lock()); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + } + + if (dirty) + std::erase_if(m_vRenderUnfocused, [](const auto& e) { return !e || !e->m_sWindowData.renderUnfocused.valueOr(false); }); + + if (!m_vRenderUnfocused.empty()) + m_tRenderUnfocusedTimer->updateTimeout(std::chrono::milliseconds(1000 / *PFPS)); + }, + nullptr); + + g_pEventLoopManager->addTimer(m_tRenderUnfocusedTimer); } CHyprRenderer::~CHyprRenderer() { @@ -2800,3 +2838,15 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { return settings; } + +void CHyprRenderer::addWindowToRenderUnfocused(PHLWINDOW window) { + static auto PFPS = CConfigValue("misc:render_unfocused_fps"); + + if (std::find(m_vRenderUnfocused.begin(), m_vRenderUnfocused.end(), window) != m_vRenderUnfocused.end()) + return; + + m_vRenderUnfocused.emplace_back(window); + + if (!m_tRenderUnfocusedTimer->armed()) + m_tRenderUnfocusedTimer->updateTimeout(std::chrono::milliseconds(1000 / *PFPS)); +} diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index d00c0a17..b730d589 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -13,6 +13,7 @@ class CWorkspace; class CWindow; class CInputPopup; class IHLBuffer; +class CEventLoopTimer; // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { @@ -78,6 +79,7 @@ class CHyprRenderer { void makeEGLCurrent(); void unsetEGL(); SExplicitSyncSettings getExplicitSyncSettings(); + void addWindowToRenderUnfocused(PHLWINDOW window); // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. @@ -143,6 +145,8 @@ class CHyprRenderer { SP getOrCreateRenderbuffer(SP buffer, uint32_t fmt); std::vector> m_vRenderbuffers; + std::vector m_vRenderUnfocused; + SP m_tRenderUnfocusedTimer; friend class CHyprOpenGLImpl; friend class CToplevelExportFrame; From 76b82fdde7d3f38cb70db0bec3318a7fb6c27a0c Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 31 Aug 2024 09:01:02 +0000 Subject: [PATCH 114/298] meson: explicitly specify path for find(1) (#7590) assets/install/meson.build:1:10: ERROR: Command `/bin/sh -c 'find -type f -not -name "*.build"'` failed with status 1. --- assets/install/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/install/meson.build b/assets/install/meson.build index 19b49638..1d4fb917 100644 --- a/assets/install/meson.build +++ b/assets/install/meson.build @@ -1,4 +1,4 @@ -globber = run_command('sh', '-c', 'find -type f -not -name "*.build"', check: true) +globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check: true) files = globber.stdout().strip().split('\n') foreach file : files From 838ed87d6ffae0dbdc8a3ecaac2c8be006f6d053 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 31 Aug 2024 08:07:52 -0500 Subject: [PATCH 115/298] renderer: minor direct scanout fixes (#7594) --- src/helpers/Monitor.cpp | 15 +++++++++++++++ src/helpers/Monitor.hpp | 3 ++- src/render/Renderer.cpp | 9 ++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 685009fd..5b01d651 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -832,6 +832,21 @@ bool CMonitor::attemptDirectScanout() { // FIXME: make sure the buffer actually follows the available scanout dmabuf formats // and comes from the appropriate device. This may implode on multi-gpu!! + + const auto params = PSURFACE->current.buffer->buffer->dmabuf(); + // scanout buffer isn't dmabuf, so no scanout + if (!params.success) + return false; + + // entering into scanout, so save monitor format + if (lastScanout.expired()) + prevDrmFormat = drmFormat; + + if (drmFormat != params.format) { + output->state->setFormat(params.format); + drmFormat = params.format; + } + output->state->setBuffer(PSURFACE->current.buffer->buffer.lock()); output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 01a5d28d..203cac90 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -100,7 +100,8 @@ class CMonitor { std::optional forceSize; SP currentMode; SP cursorSwapchain; - uint32_t drmFormat = DRM_FORMAT_INVALID; + uint32_t drmFormat = DRM_FORMAT_INVALID; + uint32_t prevDrmFormat = DRM_FORMAT_INVALID; bool dpmsStatus = true; bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c5866e4a..27fde129 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1277,7 +1277,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->lastScanout.reset(); // reset DRM format, make sure it's the one we want. - pMonitor->output->state->setFormat(pMonitor->drmFormat); + pMonitor->output->state->setFormat(pMonitor->prevDrmFormat); + pMonitor->drmFormat = pMonitor->prevDrmFormat; } } @@ -1978,7 +1979,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->currentMode = nullptr; pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); - pMonitor->drmFormat = DRM_FORMAT_XRGB8888; + pMonitor->prevDrmFormat = pMonitor->drmFormat; + pMonitor->drmFormat = DRM_FORMAT_XRGB8888; pMonitor->output->state->resetExplicitFences(); bool autoScale = false; @@ -2219,7 +2221,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR for (auto const& fmt : formats[(int)!RULE->enable10bit]) { pMonitor->output->state->setFormat(fmt.second); - pMonitor->drmFormat = fmt.second; + pMonitor->prevDrmFormat = pMonitor->drmFormat; + pMonitor->drmFormat = fmt.second; if (!pMonitor->state.test()) { Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); From 10d7219807dd726d231e8df53a357018f5526432 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sat, 31 Aug 2024 13:51:19 +0300 Subject: [PATCH 116/298] CI: clarify Nix CI jobs; disable on forked repositories --- .github/workflows/nix-build.yml | 4 +++- .github/workflows/nix-ci.yml | 4 ++-- .github/workflows/nix-update-inputs.yml | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index d0234498..ed0c2ae1 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -1,3 +1,5 @@ +name: Nix (Build) + on: workflow_call: secrets: @@ -25,6 +27,6 @@ jobs: - uses: cachix/cachix-action@v15 with: name: hyprland - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index b25ed9aa..2f35337d 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -1,10 +1,10 @@ -name: Nix +name: Nix (CI) on: [push, pull_request, workflow_dispatch] jobs: update-inputs: - if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') uses: ./.github/workflows/nix-update-inputs.yml secrets: inherit diff --git a/.github/workflows/nix-update-inputs.yml b/.github/workflows/nix-update-inputs.yml index 000900d9..a8f68f3b 100644 --- a/.github/workflows/nix-update-inputs.yml +++ b/.github/workflows/nix-update-inputs.yml @@ -1,4 +1,4 @@ -name: Nix +name: Nix (Update Inputs) on: workflow_call: @@ -8,6 +8,7 @@ on: jobs: update: + if: github.repository == 'hyprwm/Hyprland' name: inputs runs-on: ubuntu-latest steps: From cf6a1716ae719f9c59b1d175ca84a79015fab8e1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 31 Aug 2024 18:32:57 +0200 Subject: [PATCH 117/298] syncobj: wait for deadline instead of available avoids slow apps from lagging the desktop --- src/protocols/DRMSyncobj.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 4993f1a4..e0c90a3b 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -58,8 +58,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPtimeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + // wait for the buffer to be released by the gpu before sending a commit to avoid lagging the desktop + auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); if (!materialized.has_value()) { LOGM(ERR, "Failed to check the acquire timeline"); resource->noMemory(); @@ -70,7 +70,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); - pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); }); listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) { From 1ac2fc3f7e538e47a5cb8fdef60d701987fe63ed Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:07:23 -0500 Subject: [PATCH 118/298] protocols: destroy new xdgDialog protocol at right time (#7600) --- src/managers/ProtocolManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 2c421abe..6b6d5acf 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -221,6 +221,7 @@ CProtocolManager::~CProtocolManager() { PROTO::screencopy.reset(); PROTO::toplevelExport.reset(); PROTO::globalShortcuts.reset(); + PROTO::xdgDialog.reset(); PROTO::lease.reset(); PROTO::sync.reset(); From cac59fefecaefe34be45e65713d54676444f88a2 Mon Sep 17 00:00:00 2001 From: TheMical <85638851+TheMical@users.noreply.github.com> Date: Sat, 31 Aug 2024 15:43:02 -0400 Subject: [PATCH 119/298] data-device: Fix selection mismatch when wlr resets primary selection (#7598) --- src/protocols/DataDeviceWlr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index d2d06644..69e28772 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -133,7 +133,7 @@ CWLRDataDevice::CWLRDataDevice(SP resource_) : resourc auto source = sourceR ? CWLRDataSource::fromResource(sourceR) : CSharedPointer{}; if (!source) { LOGM(LOG, "wlr reset primary selection received"); - g_pSeatManager->setCurrentSelection(nullptr); + g_pSeatManager->setCurrentPrimarySelection(nullptr); return; } From a6315b0af4e417cf396649d9c5792d3c5420b713 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:55:08 -0500 Subject: [PATCH 120/298] core: fix crash on monitor removed with gammaControl (#7601) * fix crash on monitor removed with gammaControl * Update GammaControl.cpp --- src/protocols/GammaControl.cpp | 14 +++++++------- src/protocols/GammaControl.hpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index cb75a202..d7992981 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -17,7 +17,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out return; } - pMonitor = OUTPUTRES->monitor.get(); + pMonitor = OUTPUTRES->monitor; if (!pMonitor) { LOGM(ERR, "No CMonitor"); @@ -103,7 +103,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->sendGammaSize(gammaSize); listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); }); - listeners.monitorDisconnect = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); }); + listeners.monitorDisconnect = pMonitor->events.disconnect.registerListener([this](std::any) { this->onMonitorDestroy(); }); } CGammaControl::~CGammaControl() { @@ -119,7 +119,7 @@ bool CGammaControl::good() { } void CGammaControl::applyToMonitor() { - if (!pMonitor) + if (!pMonitor || !pMonitor->output) return; // ?? LOGM(LOG, "setting to monitor {}", pMonitor->szName); @@ -136,16 +136,16 @@ void CGammaControl::applyToMonitor() { pMonitor->output->state->setGammaLut({}); } - g_pHyprRenderer->damageMonitor(pMonitor); + g_pHyprRenderer->damageMonitor(pMonitor.get()); } CMonitor* CGammaControl::getMonitor() { - return pMonitor; + return pMonitor ? pMonitor.get() : nullptr; } void CGammaControl::onMonitorDestroy() { + LOGM(LOG, "Destroying gamma control for {}", pMonitor->szName); resource->sendFailed(); - pMonitor = nullptr; } CGammaControlProtocol::CGammaControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { @@ -187,4 +187,4 @@ void CGammaControlProtocol::applyGammaToState(CMonitor* pMonitor) { g->applyToMonitor(); break; } -} \ No newline at end of file +} diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 963eea5c..bbdc0139 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -20,7 +20,7 @@ class CGammaControl { private: SP resource; - CMonitor* pMonitor = nullptr; + WP pMonitor; size_t gammaSize = 0; bool gammaTableSet = false; std::vector gammaTable; // [r,g,b]+ From 4af9410dc2d0e241276a0797d3f3d276310d956e Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 1 Sep 2024 12:04:28 +0200 Subject: [PATCH 121/298] xwm: read atom name from xcb (#7546) expand the debug trace logging by actually reading the atom name from xcb if not found in HYPRATOMS, will also print the proper atom for xcb internal ones and not just the HYPRATOMS ones. --- src/xwayland/XWM.cpp | 34 ++++++++++++++++++++++++---------- src/xwayland/XWM.hpp | 1 + 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index b5762762..cb4d8f4d 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -158,18 +158,32 @@ static bool lookupParentExists(SP XSURF, SP return false; } +std::string CXWM::getAtomName(uint32_t atom) { + for (auto const& ha : HYPRATOMS) { + if (ha.second != atom) + continue; + + return ha.first; + } + + // Get the name of the atom + auto const atom_name_cookie = xcb_get_atom_name(connection, atom); + auto* atom_name_reply = xcb_get_atom_name_reply(connection, atom_name_cookie, NULL); + + if (!atom_name_reply) + return "Unknown"; + + auto const name_len = xcb_get_atom_name_name_length(atom_name_reply); + auto* name = xcb_get_atom_name_name(atom_name_reply); + free(atom_name_reply); + + return {name, name_len}; +} + void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply) { std::string propName; - if (Debug::trace) { - propName = std::format("{}?", atom); - for (auto const& ha : HYPRATOMS) { - if (ha.second != atom) - continue; - - propName = ha.first; - break; - } - } + if (Debug::trace) + propName = getAtomName(atom); if (atom == XCB_ATOM_WM_CLASS) { size_t len = xcb_get_property_value_length(reply); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 7d6b63ed..59695720 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -119,6 +119,7 @@ class CXWM { std::string mimeFromAtom(xcb_atom_t atom); void setClipboardToWayland(SXSelection& sel); void getTransferData(SXSelection& sel); + std::string getAtomName(uint32_t atom); void readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply); // From 5b1375141bd77c26023fb4a8dc087272be82849a Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 1 Sep 2024 17:18:50 +0300 Subject: [PATCH 122/298] flake.lock: update --- flake.lock | 18 +++++++++--------- nix/default.nix | 7 +++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index b26cd5e3..a3f905d8 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1725016199, - "narHash": "sha256-2TMk7F2a27ZtOUW/bftkDyZKp3OQ71E5XnfKSUT8HZQ=", + "lastModified": 1725199881, + "narHash": "sha256-jsmipf/u1GFZE5tBUkr56CHMN6VpUWCAjfLIhvQijU0=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "cff00196f0fcf734a2bf164eb0dfdb6e58c5c906", + "rev": "f8a687dd29ff019657498f1bd14da2fbbf0e604b", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1724174162, - "narHash": "sha256-fOOBLwil6M9QWMCiSULwjMQzrXhHXUnEqmjHX5ZHeVI=", + "lastModified": 1725188252, + "narHash": "sha256-yBH8c4GDaEAtBrh+BqIlrx5vp6gG/Gu8fQQK63KAQgs=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "16e5c9465f04477d8a3dd48a0a26bf437986336c", + "rev": "c12ab785ce1982f82594aff03b3104c598186ddd", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1724819573, - "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", + "lastModified": 1725103162, + "narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", + "rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", "type": "github" }, "original": { diff --git a/nix/default.nix b/nix/default.nix index 64796a90..6a4979f1 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -89,6 +89,10 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov DIRTY = lib.optionalString (commit == "") "dirty"; HASH = commit; + depsBuildBuild = [ + pkg-config + ]; + nativeBuildInputs = [ hyprwayland-scanner jq @@ -97,8 +101,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov ninja pkg-config python3 # for udis86 - # re-add after https://github.com/NixOS/nixpkgs/pull/214906 hits nixos-unstable - # wayland-scanner + wayland-scanner ]; outputs = [ From 4b5b8a763073593ac48af3bdcf04cf65b219120b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 1 Sep 2024 18:14:14 +0300 Subject: [PATCH 123/298] flake.lock: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index a3f905d8..5921488e 100644 --- a/flake.lock +++ b/flake.lock @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1724073926, - "narHash": "sha256-nWlUL43jOFHf+KW6Hqrx+W/r1XdXuDyb0wC/SrHsOu4=", + "lastModified": 1725203619, + "narHash": "sha256-Am4gwnu5q+6GFKQ3NnEkXeZYKIZ9rv9mRLk+DYqX9Zs=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "a08ecbbf33598924e93542f737fc6169a26b481e", + "rev": "8e5ca2a299e95a3bdcdb84cfbe08f31b0690ecd5", "type": "github" }, "original": { From 7a24e564f43d4c24abf2ec4e5351007df2f8926c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 1 Sep 2024 19:37:25 +0300 Subject: [PATCH 124/298] flake.lock: update xdph again --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 5921488e..99a544e2 100644 --- a/flake.lock +++ b/flake.lock @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1725203619, - "narHash": "sha256-Am4gwnu5q+6GFKQ3NnEkXeZYKIZ9rv9mRLk+DYqX9Zs=", + "lastModified": 1725203932, + "narHash": "sha256-VLULC/OnI+6R9KEP2OIGk+uLJJsfRlaLouZ5gyFd2+Y=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "8e5ca2a299e95a3bdcdb84cfbe08f31b0690ecd5", + "rev": "2425e8f541525fa7409d9f26a8ffaf92a3767251", "type": "github" }, "original": { From 8bbeee20414bc0e20992076632d7d44ede443a1c Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 2 Sep 2024 01:44:33 +0900 Subject: [PATCH 125/298] textinput: send deactivate to ime on destory ti (#7614) --- src/managers/input/TextInput.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 5bff9fed..711935a7 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -23,9 +23,7 @@ void CTextInput::initCallbacks() { listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { - const auto INPUT = pV3Input.lock(); - if (INPUT && INPUT->current.enabled && focusedSurface()) - g_pInputManager->m_sIMERelay.deactivateIME(this); + g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); }); } else { @@ -40,6 +38,7 @@ void CTextInput::initCallbacks() { listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); }); } @@ -192,7 +191,7 @@ wl_client* CTextInput::client() { } void CTextInput::commitStateToIME(SP ime) { - if (isV3()) { + if (isV3() && !pV3Input.expired()) { const auto INPUT = pV3Input.lock(); if (INPUT->current.surrounding.updated) @@ -202,7 +201,7 @@ void CTextInput::commitStateToIME(SP ime) { if (INPUT->current.contentType.updated) ime->textContentType(INPUT->current.contentType.hint, INPUT->current.contentType.purpose); - } else { + } else if (!pV1Input.expired()) { const auto INPUT = pV1Input.lock(); if (INPUT->pendingSurrounding.isPending) From 6934e7aa2b300bc4565855a4092fb34de8a9a8d2 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 2 Sep 2024 04:33:31 +0900 Subject: [PATCH 126/298] textinput: don't deactivate ime if another ti is focused (#7617) --- src/managers/input/TextInput.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 711935a7..de14f1ab 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -23,8 +23,9 @@ void CTextInput::initCallbacks() { listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { - g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); } else { const auto INPUT = pV1Input.lock(); @@ -38,8 +39,9 @@ void CTextInput::initCallbacks() { listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); } } From f7249bd3317e79b9cb1564f2497df510f7a166bb Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 2 Sep 2024 14:51:56 +0200 Subject: [PATCH 127/298] CMake: drop duplicate -luuid after 5262292abc56 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dba14813..ef3f4021 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,7 +266,7 @@ function(protocolWayland) endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads - libudis86 uuid) + libudis86) protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-global-shortcuts-v1" true) From fa39df4731e200fab031f01757ded9920a1d473d Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 2 Sep 2024 15:05:39 +0200 Subject: [PATCH 128/298] CMake: drop unused deps after 016da234d0e8 Found via LDFLAGS += -Wl,--as-needed (default in Meson). Some dependencies are only used by aquamarine. --- CMakeLists.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef3f4021..d8424d91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,8 +99,6 @@ pkg_check_modules( xkbcommon uuid wayland-server - wayland-client - wayland-cursor wayland-protocols cairo pango @@ -109,11 +107,6 @@ pkg_check_modules( xcursor libdrm libinput - hwdata - libseat - libdisplay-info - libliftoff - libudev gbm gio-2.0 hyprlang>=0.3.2 @@ -200,14 +193,11 @@ else() REQUIRED IMPORTED_TARGET xcb - xwayland - xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res - xcb-ewmh xcb-errors) target_link_libraries(Hyprland PkgConfig::xdeps) endif() From 8f9887b0c9443d6c2559feeec411daecb9780a97 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 2 Sep 2024 23:09:44 +0300 Subject: [PATCH 129/298] Nix: remove unused dependencies --- nix/default.nix | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 6a4979f1..e1a348b0 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -9,33 +9,22 @@ aquamarine, binutils, cairo, - expat, - fribidi, git, - hwdata, hyprcursor, hyprlang, hyprutils, hyprwayland-scanner, jq, libGL, - libdatrie, - libdisplay-info, libdrm, libexecinfo, libinput, - libliftoff, - libselinux, - libsepol, - libthai, - libuuid, libxkbcommon, + libuuid, mesa, pango, pciutils, - pcre2, python3, - seatd, systemd, tomlplusplus, wayland, @@ -114,29 +103,25 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov [ aquamarine cairo - expat - fribidi + # expat + # fribidi git - hwdata hyprcursor hyprlang hyprutils - libdatrie - libdisplay-info + # libdatrie libdrm libGL libinput - libliftoff - libselinux - libsepol - libthai + # libselinux + # libsepol + # libthai libuuid libxkbcommon mesa pango pciutils - pcre2 - seatd + # pcre2 tomlplusplus wayland wayland-protocols @@ -146,7 +131,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.optionals enableXWayland [ xorg.libxcb xorg.libXdmcp - xorg.xcbutil xorg.xcbutilerrors xorg.xcbutilrenderutil xorg.xcbutilwm From 9b54342baa27d8de0460e1103ec4c3cc65592ed8 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 3 Sep 2024 14:47:34 +0200 Subject: [PATCH 130/298] Revert "syncobj: wait for deadline instead of available" This reverts commit cf6a1716ae719f9c59b1d175ca84a79015fab8e1. Fixes #7628 --- src/protocols/DRMSyncobj.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index e0c90a3b..4993f1a4 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -58,8 +58,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPtimeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); + // wait for the acquire timeline to materialize + auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); if (!materialized.has_value()) { LOGM(ERR, "Failed to check the acquire timeline"); resource->noMemory(); @@ -70,7 +70,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); - pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); + pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); }); listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) { From ea10592ad3c861ff2ce73ad7785bcb5a45a9e400 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:23:29 +0000 Subject: [PATCH 131/298] input: don't emit idle activity when calling simulateMouseMovement (#7649) --- src/managers/input/InputManager.cpp | 6 +++--- src/managers/input/InputManager.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 78c9e437..d7ccc5e4 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -111,7 +111,7 @@ void CInputManager::simulateMouseMovement() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); m_vLastCursorPosFloored = m_vLastCursorPosFloored - Vector2D(1, 1); // hack: force the mouseMoveUnified to report without making this a refocus. - mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000); + mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000, false, true); } void CInputManager::sendMotionEventsToFocused() { @@ -132,7 +132,7 @@ void CInputManager::sendMotionEventsToFocused() { g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus.lock(), LOCAL); } -void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { +void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); @@ -171,7 +171,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED); - if (time) + if (time && !silent) PROTO::idle->onActivity(); m_vLastCursorPosFloored = MOUSECOORDSFLOORED; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index ebf00b2d..70e4d40f 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -237,7 +237,7 @@ class CInputManager { uint32_t m_uiCapabilities = 0; - void mouseMoveUnified(uint32_t, bool refocus = false); + void mouseMoveUnified(uint32_t, bool refocus = false, bool silent = false); SP ensureTabletToolPresent(SP); From 027140b7315efe3cd2e7b78fa608bd36da839894 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:59:00 +0000 Subject: [PATCH 132/298] sessionLock: ensure sls focus in some edge cases (#7647) * input: return early in mouseMoveUnified when the session is locked * sessionLock: make make a commit an opportunity to focus session lock surfaces * compositor: allow resetting focus when session is locked * input: remove redundant PMONITOR checks PMONITOR is checked above * input: check isSessionLocked earlier in mouseMoveUnified A bit of reordering, so that we don't call some stuff that is irrelevant when the session is locked --- src/Compositor.cpp | 2 +- src/managers/SessionLockManager.cpp | 3 ++ src/managers/input/InputManager.cpp | 56 ++++++++++++++--------------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index eac75bd4..ba9ff96b 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1117,7 +1117,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface->resource())) return; // Don't focus when already focused on this. - if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) + if (g_pSessionLockManager->isSessionLocked() && pSurface && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) return; if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) { diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 7267b8f2..260a3992 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -30,6 +30,9 @@ SSessionLockSurface::SSessionLockSurface(SP surface_) : sur listeners.commit = surface_->events.commit.registerListener([this](std::any data) { const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID); + if (mapped && pWlrSurface != g_pCompositor->m_pLastFocus) + g_pInputManager->simulateMouseMovement(); + if (PMONITOR) g_pHyprRenderer->damageMonitor(PMONITOR); }); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index d7ccc5e4..cdf7d615 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -153,7 +153,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { Vector2D surfacePos = Vector2D(-1337, -1337); PHLWINDOW pFoundWindow; PHLLS pFoundLayerSurface; - SSessionLockSurface* pSessionLock = nullptr; if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; @@ -190,17 +189,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) && !skipFrameSchedule) g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); - PHLWINDOW forcedFocus = m_pForcedFocus.lock(); - - if (!forcedFocus) - forcedFocus = g_pCompositor->getForceFocus(); - - if (forcedFocus) { - pFoundWindow = forcedFocus; - surfacePos = pFoundWindow->m_vRealPosition.value(); - foundSurface = pFoundWindow->m_pWLSurface->resource(); - } - // constraints if (!g_pSeatManager->mouse.expired() && isConstrained()) { const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); @@ -227,6 +215,33 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF.get(), (uintptr_t)CONSTRAINT.get()); } + if (PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) + g_pCompositor->setActiveMonitor(PMONITOR); + + if (g_pSessionLockManager->isSessionLocked()) { + const auto PSESSIONLOCKSURFACE = g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID); + surfacePos = PMONITOR->vecPosition; + + foundSurface = PSESSIONLOCKSURFACE ? PSESSIONLOCKSURFACE->surface->surface() : nullptr; + g_pCompositor->focusSurface(foundSurface); + + const auto SURFACELOCAL = mouseCoords - surfacePos; + g_pSeatManager->setPointerFocus(foundSurface, SURFACELOCAL); + g_pSeatManager->sendPointerMotion(time, SURFACELOCAL); + return; + } + + PHLWINDOW forcedFocus = m_pForcedFocus.lock(); + + if (!forcedFocus) + forcedFocus = g_pCompositor->getForceFocus(); + + if (forcedFocus) { + pFoundWindow = forcedFocus; + surfacePos = pFoundWindow->m_vRealPosition.value(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); + } + // if we are holding a pointer button, // and we're not dnd-ing, don't refocus. Keep focus on last surface. if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) { @@ -258,19 +273,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal()); - if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) - g_pCompositor->setActiveMonitor(PMONITOR); - - if (g_pSessionLockManager->isSessionLocked()) { - pSessionLock = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr; - - if (!pSessionLock) - return; - - foundSurface = pSessionLock->surface->surface(); - surfacePos = PMONITOR->vecPosition; - } - if (!foundSurface) foundSurface = g_pCompositor->vectorToLayerPopupSurface(mouseCoords, PMONITOR, &surfaceCoords, &pFoundLayerSurface); @@ -460,9 +462,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { restoreCursorIconToApp(); } - if (pSessionLock != nullptr) - g_pCompositor->focusSurface(foundSurface); - else if (pFoundWindow) { + if (pFoundWindow) { // change cursor icon if hovering over border if (*PRESIZEONBORDER && *PRESIZECURSORICON) { if (!pFoundWindow->isFullscreen() && !pFoundWindow->hasPopupAt(mouseCoords)) { From bd6d6e7f3378c08fe48c179ba4ec3517fe10ae3f Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:26:46 -0500 Subject: [PATCH 133/298] xwayland: add option to enable/disable xwayland (#7633) * config: add xwayland enabled option to config * xwayland: use DISPLAY env variable for enable/disable of new launches * xwayland: close X11 windows when turning of XWayland * clang: format fix * config: add better description for xwayland:enabled * xwayland: close X11 windows on disable without crashes * xwayland: better method of informing CXWayland if xwayland enabled * xwayland: prevent closing non-xwayland windows on disable * misc: loop formatting --- src/Compositor.cpp | 2 +- src/Compositor.hpp | 1 + src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 25 +++++++++++++++++++++++++ src/xwayland/Server.cpp | 3 ++- src/xwayland/XWM.cpp | 4 ++++ src/xwayland/XWayland.cpp | 9 +++++++-- src/xwayland/XWayland.hpp | 4 ++-- 8 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index ba9ff96b..da659654 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -615,7 +615,7 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pCursorManager = std::make_unique(); Debug::log(LOG, "Starting XWayland"); - g_pXWayland = std::make_unique(); + g_pXWayland = std::make_unique(g_pCompositor->m_bEnableXwayland); } break; default: UNREACHABLE(); } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index bb986f5e..f17d86e5 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -92,6 +92,7 @@ class CCompositor { CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state bool m_bIsShuttingDown = false; bool m_bDesktopEnvSet = false; + bool m_bEnableXwayland = true; // ------------------------------------------------- // diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 73f3c9a3..00ebde6a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1115,6 +1115,12 @@ inline static const std::vector CONFIG_OPTIONS = { * xwayland: */ + SConfigOptionDescription{ + .value = "xwayland:enabled", + .description = "allow running applications using X11", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "xwayland:use_nearest_neighbor", .description = "uses the nearest neighbor filtering for xwayland apps, making them pixelated rather than blurry", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5940a6fe..740dbbdf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -6,6 +6,7 @@ #include "config/ConfigValue.hpp" #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" +#include "../xwayland/XWayland.hpp" #include #include @@ -523,6 +524,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_touch_invert", Hyprlang::INT{0}); + m_pConfig->addConfigValue("xwayland:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); @@ -860,6 +862,29 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { ensureVRR(); } +#ifndef NO_XWAYLAND + const auto PENABLEXWAYLAND = std::any_cast(m_pConfig->getConfigValue("xwayland:enabled")); + // enable/disable xwayland usage + if (!isFirstLaunch) { + bool prevEnabledXwayland = g_pCompositor->m_bEnableXwayland; + if (PENABLEXWAYLAND != prevEnabledXwayland) { + g_pCompositor->m_bEnableXwayland = PENABLEXWAYLAND; + if (PENABLEXWAYLAND) { + Debug::log(LOG, "xwayland has been enabled"); + } else { + Debug::log(LOG, "xwayland has been disabled, cleaning up..."); + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_pXDGSurface || !w->m_bIsX11) + continue; + g_pCompositor->closeWindow(w); + } + } + g_pXWayland = std::make_unique(g_pCompositor->m_bEnableXwayland); + } + } else + g_pCompositor->m_bEnableXwayland = PENABLEXWAYLAND; +#endif + if (!isFirstLaunch && !g_pCompositor->m_bUnsafeState) refreshGroupBarGradients(); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 200bec70..f3bf5768 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -432,7 +432,8 @@ int CXWaylandServer::ready(int fd, uint32_t mask) { pipeSource = nullptr; // start the wm - g_pXWayland->pWM = std::make_unique(); + if (!g_pXWayland->pWM) + g_pXWayland->pWM = std::make_unique(); g_pCursorManager->setXWaylandCursor(); diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index cb4d8f4d..e8e2258a 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -890,6 +890,10 @@ CXWM::~CXWM() { if (eventSource) wl_event_source_remove(eventSource); + + for (auto const& sr : surfaces) { + sr->events.destroy.emit(); + } } void CXWM::setActiveWindow(xcb_window_t window) { diff --git a/src/xwayland/XWayland.cpp b/src/xwayland/XWayland.cpp index 8d45fa63..8cdb1fca 100644 --- a/src/xwayland/XWayland.cpp +++ b/src/xwayland/XWayland.cpp @@ -1,12 +1,17 @@ #include "XWayland.hpp" #include "../debug/Log.hpp" -CXWayland::CXWayland() { +CXWayland::CXWayland(const bool enabled) { #ifndef NO_XWAYLAND Debug::log(LOG, "Starting up the XWayland server"); pServer = std::make_unique(); + if (!enabled) { + unsetenv("DISPLAY"); + return; + } + if (!pServer->create()) { Debug::log(ERR, "XWayland failed to start: it will not work."); return; @@ -25,4 +30,4 @@ void CXWayland::setCursor(unsigned char* pixData, uint32_t stride, const Vector2 pWM->setCursor(pixData, stride, size, hotspot); #endif -} \ No newline at end of file +} diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index 40c0ba65..96253d19 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -17,7 +17,7 @@ class CXWM; class CXWayland { public: - CXWayland(); + CXWayland(const bool enabled); #ifndef NO_XWAYLAND std::unique_ptr pServer; @@ -126,4 +126,4 @@ inline std::unordered_map HYPRATOMS = { HYPRATOM("DELETE"), HYPRATOM("TEXT"), HYPRATOM("INCR"), -}; \ No newline at end of file +}; From 4a42c5ed20a6852e5e51c0f3893024f3b5c03500 Mon Sep 17 00:00:00 2001 From: Parola Marco Date: Thu, 5 Sep 2024 18:29:33 +0200 Subject: [PATCH 134/298] config: Add a variable to prevent groups from merging after being dragged (#7650) * config: Add a variable to prevent groups from merging after being dragged * Fixed code style for [f777f028] --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/desktop/Window.cpp | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 00ebde6a..44b5ee4a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -742,6 +742,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "group:merge_groups_on_drag", + .description = "whether window groups can be dragged into other groups", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "general:col.border_active", .description = "border color for inactive windows", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 740dbbdf..b16b7747 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -362,6 +362,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index a9e389a6..cc5b48af 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -951,12 +951,16 @@ int CWindow::getGroupSize() { } bool CWindow::canBeGroupedInto(PHLWINDOW pWindow) { + static auto ALLOWGROUPMERGE = CConfigValue("group:merge_groups_on_drag"); + bool isGroup = m_sGroupData.pNextWindow; + bool disallowDragIntoGroup = g_pInputManager->m_bWasDraggingWindow && isGroup && !bool(*ALLOWGROUPMERGE); return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged && ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or || (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked && !(m_sGroupData.pNextWindow.lock() && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group && !m_sGroupData.deny // source is not denied entry - && !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window + && !(m_eGroupRules & GROUP_BARRED && m_bFirstMap) // group rule doesn't prevent adding window + && !disallowDragIntoGroup; // config allows groups to be merged } PHLWINDOW CWindow::getGroupWindowByIndex(int index) { From c80457be02e7b75b590e025708fad38d84c99026 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 21 Jul 2024 20:54:57 +0300 Subject: [PATCH 135/298] nix: add COMMITS var --- nix/default.nix | 3 ++- nix/overlays.nix | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index e1a348b0..1c6a0113 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -39,6 +39,7 @@ wrapRuntimeDeps ? true, version ? "git", commit, + revCount, date, # deprecated flags enableNvidiaPatches ? false, @@ -73,7 +74,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov sed -i "s#@PREFIX@/##g" hyprland.pc.in ''; - COMMITS = commit; + COMMITS = revCount; DATE = date; DIRTY = lib.optionalString (commit == "") "dirty"; HASH = commit; diff --git a/nix/overlays.nix b/nix/overlays.nix index 36206f46..d6e078fa 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -34,6 +34,7 @@ in { stdenv = final.gcc14Stdenv; version = "${version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; + revCount = self.sourceInfo.revCount or ""; inherit date; }; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; From 727f1b54cd1ba48774092a5d54acc0e55f3ffe0f Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Fri, 6 Sep 2024 04:04:23 +0900 Subject: [PATCH 136/298] textinput: fix ime activation in some edge cases (#7660) * textinput: clear ti3 state when focused surface gets destroyed * textinput: send enter to newly created ti in focus --- src/managers/input/TextInput.cpp | 46 +++++++++++++++++++++++--------- src/protocols/TextInputV3.cpp | 13 +++++---- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index de14f1ab..4c2e326a 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -23,10 +23,15 @@ void CTextInput::initCallbacks() { listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); g_pInputManager->m_sIMERelay.removeTextInput(this); if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); }); + + if (!g_pCompositor->m_pLastFocus.expired() && g_pCompositor->m_pLastFocus->client() == INPUT->client()) + enter(g_pCompositor->m_pLastFocus.lock()); } else { const auto INPUT = pV1Input.lock(); @@ -72,15 +77,19 @@ void CTextInput::onDisabled() { return; } - if (!focusedSurface()) - return; - if (!isV3()) leave(); listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + if (!focusedSurface()) + return; + + const auto PFOCUSEDTI = g_pInputManager->m_sIMERelay.getFocusedTextInput(); + if (!PFOCUSEDTI || PFOCUSEDTI != this) + return; + g_pInputManager->m_sIMERelay.deactivateIME(this); } @@ -104,12 +113,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { pFocusedSurface = pSurface; - listeners.surfaceUnmap.reset(); - listeners.surfaceDestroy.reset(); - if (!pSurface) return; + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); + listeners.surfaceUnmap = pSurface->events.unmap.registerListener([this](std::any d) { Debug::log(LOG, "Unmap TI owner1"); @@ -118,6 +127,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { pFocusedSurface.reset(); listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) + pV3Input->current.enabled = false; + + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) { @@ -128,6 +143,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { pFocusedSurface.reset(); listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) + pV3Input->current.enabled = false; + + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); } @@ -142,10 +163,8 @@ void CTextInput::enter(SP pSurface) { if (pSurface == focusedSurface()) return; - if (focusedSurface()) { + if (focusedSurface()) leave(); - setFocusedSurface(nullptr); - } enterLocks++; if (enterLocks != 1) { @@ -173,11 +192,14 @@ void CTextInput::leave() { enterLocks = 0; } - if (isV3() && focusedSurface()) + if (isV3()) { pV3Input->leave(focusedSurface()); - else if (focusedSurface() && pV1Input) { + if (pV3Input->current.enabled) { + pV3Input->current.enabled = false; + onDisabled(); + } + } else pV1Input->leave(); - } setFocusedSurface(nullptr); diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 99d799f3..42dc659e 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -24,10 +24,9 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) current = pending; serial++; - if (wasEnabled && !current.enabled) { - current.reset(); + if (wasEnabled && !current.enabled) events.disable.emit(); - } else if (!wasEnabled && current.enabled) + else if (!wasEnabled && current.enabled) events.enable.emit(); else events.onCommit.emit(); @@ -53,12 +52,12 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) pending.box.cursorBox = {x, y, w, h}; }); - resource->setEnable([this](CZwpTextInputV3* r) { pending.enabled = true; }); - - resource->setDisable([this](CZwpTextInputV3* r) { - pending.enabled = false; + resource->setEnable([this](CZwpTextInputV3* r) { pending.reset(); + pending.enabled = true; }); + + resource->setDisable([this](CZwpTextInputV3* r) { pending.enabled = false; }); } CTextInputV3::~CTextInputV3() { From 0fad7a0bb03d4181901952a0df620d42ab6bbe4d Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Fri, 6 Sep 2024 08:54:01 +0900 Subject: [PATCH 137/298] workspacerules: fix on-created-empty window focus (#7657) --- src/desktop/Workspace.cpp | 2 +- src/managers/KeybindManager.cpp | 32 ++++++++++++++++++++------------ src/managers/KeybindManager.hpp | 3 ++- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 35fc5727..2d92659c 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -51,7 +51,7 @@ void CWorkspace::init(PHLWORKSPACE self) { if (self->m_bWasCreatedEmpty) if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) - g_pKeybindManager->spawn(*cmd); + g_pKeybindManager->spawnWithRules(*cmd, self); g_pEventManager->postEvent({"createworkspace", m_szName}); g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 7ee5ae7e..2db9f375 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -34,7 +34,7 @@ using namespace Hyprutils::String; #include #endif -static std::vector> getHyprlandLaunchEnv() { +static std::vector> getHyprlandLaunchEnv(PHLWORKSPACE pInitialWorkspace) { static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); if (!*PINITIALWSTRACKING || g_pConfigManager->isLaunchingExecOnce) @@ -46,11 +46,15 @@ static std::vector> getHyprlandLaunchEnv() { std::vector> result; - result.push_back(std::make_pair<>( - "HL_INITIAL_WORKSPACE_TOKEN", - g_pTokenManager->registerNewToken( - SInitialWorkspaceToken{{}, PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace->getConfigName() : PMONITOR->activeWorkspace->getConfigName()}, - std::chrono::months(1337)))); + if (!pInitialWorkspace) { + if (PMONITOR->activeSpecialWorkspace) + pInitialWorkspace = PMONITOR->activeSpecialWorkspace; + else + pInitialWorkspace = PMONITOR->activeWorkspace; + } + + result.push_back(std::make_pair<>("HL_INITIAL_WORKSPACE_TOKEN", + g_pTokenManager->registerNewToken(SInitialWorkspaceToken{{}, pInitialWorkspace->getConfigName()}, std::chrono::months(1337)))); return result; } @@ -846,8 +850,12 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { } // Dispatchers - SDispatchResult CKeybindManager::spawn(std::string args) { + const uint64_t PROC = spawnWithRules(args, nullptr); + return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; +} + +uint64_t CKeybindManager::spawnWithRules(std::string args, PHLWORKSPACE pInitialWorkspace) { args = trim(args); @@ -859,7 +867,7 @@ SDispatchResult CKeybindManager::spawn(std::string args) { args = args.substr(args.find_first_of(']') + 1); } - const uint64_t PROC = spawnRawProc(args); + const uint64_t PROC = spawnRawProc(args, pInitialWorkspace); if (!RULES.empty()) { const auto RULESLIST = CVarList(RULES, 0, ';'); @@ -871,18 +879,18 @@ SDispatchResult CKeybindManager::spawn(std::string args) { Debug::log(LOG, "Applied {} rule arguments for exec.", RULESLIST.size()); } - return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; + return PROC; } SDispatchResult CKeybindManager::spawnRaw(std::string args) { - const uint64_t PROC = spawnRawProc(args); + const uint64_t PROC = spawnRawProc(args, nullptr); return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; } -uint64_t CKeybindManager::spawnRawProc(std::string args) { +uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWorkspace) { Debug::log(LOG, "Executing {}", args); - const auto HLENV = getHyprlandLaunchEnv(); + const auto HLENV = getHyprlandLaunchEnv(pInitialWorkspace); int socket[2]; if (pipe(socket) != 0) { diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index d1f26c2c..bf3b049f 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -149,7 +149,8 @@ class CKeybindManager { static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); - static uint64_t spawnRawProc(std::string); + static uint64_t spawnRawProc(std::string, PHLWORKSPACE pInitialWorkspace); + static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace); // -------------- Dispatchers -------------- // static SDispatchResult killActive(std::string); From 4988e00b1d72edb8ca8e87eecdbed8c2ecc6a7dc Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:58:57 +0000 Subject: [PATCH 138/298] input: move idle notify to input handlers (#7659) * Revert "input: don't emit idle activity when calling simulateMouseMovement (#7649)" This reverts commit ea10592ad3c861ff2ce73ad7785bcb5a45a9e400. * input: move idle notify calls to input event listeners * input: don't post idle activity when keyboard is not enabled --- src/managers/PointerManager.cpp | 39 +++++++++++++++++++++++++++++ src/managers/input/InputManager.cpp | 19 ++++++-------- src/managers/input/InputManager.hpp | 2 +- src/managers/input/Tablets.cpp | 9 ------- src/managers/input/Touch.cpp | 3 --- 5 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index f0f74428..ce9ea4a4 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/PointerGestures.hpp" #include "../protocols/FractionalScale.hpp" +#include "../protocols/IdleNotify.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/core/Seat.hpp" #include "eventLoop/EventLoopManager.hpp" @@ -833,24 +834,32 @@ void CPointerManager::attachPointer(SP pointer) { auto E = std::any_cast(e); g_pInputManager->onMouseMoved(E); + + PROTO::idle->onActivity(); }); listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onMouseWarp(E); + + PROTO::idle->onActivity(); }); listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onMouseButton(E); + + PROTO::idle->onActivity(); }); listener->axis = pointer->pointerEvents.axis.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onMouseWheel(E); + + PROTO::idle->onActivity(); }); listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { @@ -861,48 +870,64 @@ void CPointerManager::attachPointer(SP pointer) { auto E = std::any_cast(e); g_pInputManager->onSwipeBegin(E); + + PROTO::idle->onActivity(); }); listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onSwipeEnd(E); + + PROTO::idle->onActivity(); }); listener->swipeUpdate = pointer->pointerEvents.swipeUpdate.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onSwipeUpdate(E); + + PROTO::idle->onActivity(); }); listener->pinchBegin = pointer->pointerEvents.pinchBegin.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers); + + PROTO::idle->onActivity(); }); listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->pinchEnd(E.timeMs, E.cancelled); + + PROTO::idle->onActivity(); }); listener->pinchUpdate = pointer->pointerEvents.pinchUpdate.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->pinchUpdate(E.timeMs, E.delta, E.scale, E.rotation); + + PROTO::idle->onActivity(); }); listener->holdBegin = pointer->pointerEvents.holdBegin.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->holdBegin(E.timeMs, E.fingers); + + PROTO::idle->onActivity(); }); listener->holdEnd = pointer->pointerEvents.holdEnd.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->holdEnd(E.timeMs, E.cancelled); + + PROTO::idle->onActivity(); }); // clang-format on @@ -926,18 +951,24 @@ void CPointerManager::attachTouch(SP touch) { auto E = std::any_cast(e); g_pInputManager->onTouchDown(E); + + PROTO::idle->onActivity(); }); listener->up = touch->touchEvents.up.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTouchUp(E); + + PROTO::idle->onActivity(); }); listener->motion = touch->touchEvents.motion.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTouchMove(E); + + PROTO::idle->onActivity(); }); listener->cancel = touch->touchEvents.cancel.registerListener([this] (std::any e) { @@ -969,24 +1000,32 @@ void CPointerManager::attachTablet(SP tablet) { auto E = std::any_cast(e); g_pInputManager->onTabletAxis(E); + + PROTO::idle->onActivity(); }); listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTabletProximity(E); + + PROTO::idle->onActivity(); }); listener->tip = tablet->tabletEvents.tip.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTabletTip(E); + + PROTO::idle->onActivity(); }); listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTabletButton(E); + + PROTO::idle->onActivity(); }); // clang-format on diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index cdf7d615..66ca4eb2 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -111,7 +111,7 @@ void CInputManager::simulateMouseMovement() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); m_vLastCursorPosFloored = m_vLastCursorPosFloored - Vector2D(1, 1); // hack: force the mouseMoveUnified to report without making this a refocus. - mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000, false, true); + mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000); } void CInputManager::sendMotionEventsToFocused() { @@ -132,7 +132,7 @@ void CInputManager::sendMotionEventsToFocused() { g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus.lock(), LOCAL); } -void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { +void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); @@ -170,9 +170,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED); - if (time && !silent) - PROTO::idle->onActivity(); - m_vLastCursorPosFloored = MOUSECOORDSFLOORED; const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); @@ -531,8 +528,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { void CInputManager::onMouseButton(IPointer::SButtonEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("mouseButton", e); - PROTO::idle->onActivity(); - m_tmrLastCursorMovement.reset(); if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { @@ -767,8 +762,6 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { bool passEvent = g_pKeybindManager->onAxisEvent(e); - PROTO::idle->onActivity(); - if (!passEvent) return; @@ -883,6 +876,9 @@ void CInputManager::setupKeyboard(SP keeb) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); onKeyboardKey(data, PKEEB); + + if (PKEEB->enabled) + PROTO::idle->onActivity(); }, keeb.get()); @@ -891,6 +887,9 @@ void CInputManager::setupKeyboard(SP keeb) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); onKeyboardMod(PKEEB); + + if (PKEEB->enabled) + PROTO::idle->onActivity(); }, keeb.get()); @@ -1292,8 +1291,6 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { auto e = std::any_cast(event); - PROTO::idle->onActivity(); - if (passEvent) { const auto IME = m_sIMERelay.m_pIME.lock(); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 70e4d40f..ebf00b2d 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -237,7 +237,7 @@ class CInputManager { uint32_t m_uiCapabilities = 0; - void mouseMoveUnified(uint32_t, bool refocus = false, bool silent = false); + void mouseMoveUnified(uint32_t, bool refocus = false); SP ensureTabletToolPresent(SP); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index f33937e8..9f80726e 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -1,6 +1,5 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" -#include "../../protocols/IdleNotify.hpp" #include "../../protocols/Tablet.hpp" #include "../../devices/Tablet.hpp" #include "../../managers/PointerManager.hpp" @@ -155,8 +154,6 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { if (e.updatedAxes & (CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X | CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y)) PROTO::tablet->tilt(PTOOL, PTOOL->tilt); - - PROTO::idle->onActivity(); } void CInputManager::onTabletTip(CTablet::STipEvent e) { @@ -171,8 +168,6 @@ void CInputManager::onTabletTip(CTablet::STipEvent e) { PROTO::tablet->up(PTOOL); PTOOL->isDown = e.in; - - PROTO::idle->onActivity(); } void CInputManager::onTabletButton(CTablet::SButtonEvent e) { @@ -184,8 +179,6 @@ void CInputManager::onTabletButton(CTablet::SButtonEvent e) { PTOOL->buttonsDown.push_back(e.button); else std::erase(PTOOL->buttonsDown, e.button); - - PROTO::idle->onActivity(); } void CInputManager::onTabletProximity(CTablet::SProximityEvent e) { @@ -201,8 +194,6 @@ void CInputManager::onTabletProximity(CTablet::SProximityEvent e) { simulateMouseMovement(); refocusTablet(PTAB, PTOOL); } - - PROTO::idle->onActivity(); } void CInputManager::newTablet(SP pDevice) { diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 40af4b1e..9b03168e 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -1,7 +1,6 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" -#include "../../protocols/IdleNotify.hpp" #include "../../devices/ITouch.hpp" #include "../SeatManager.hpp" @@ -78,8 +77,6 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { return; // oops, nothing found. g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface.lock(), e.timeMs, e.touchID, local); - - PROTO::idle->onActivity(); } void CInputManager::onTouchUp(ITouch::SUpEvent e) { From b0fca6eaf00a2c5061f499c76ec8d60772b6a719 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Thu, 5 Sep 2024 17:03:12 -0700 Subject: [PATCH 139/298] input: kb focus mouse focused window if unset (#7666) Normally it shouldn't be possible to have mouse focus with no kb focus, but it does happen, and when it does this makes it considerably less annoying. --- src/managers/input/InputManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 66ca4eb2..f1035c82 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -505,6 +505,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } } + if (g_pSeatManager->state.keyboardFocus == nullptr) + g_pCompositor->focusWindow(pFoundWindow, foundSurface); + m_bLastFocusOnLS = false; } else { if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) { From 0500213086f8402ccbdb2acb4748dbc6d22e21f6 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Fri, 6 Sep 2024 17:06:55 -0700 Subject: [PATCH 140/298] input: try to refocus a focusable window when seat grabs are reset (#7669) --- src/desktop/Popup.cpp | 7 +++++++ src/desktop/Popup.hpp | 23 ++++++++++++----------- src/managers/SeatManager.cpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index a4952ef7..9e254fa6 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -202,6 +202,13 @@ void CPopup::reposition() { m_pResource->applyPositioning(box, COORDS); } +SP CPopup::getT1Owner() { + if (m_pWindowOwner) + return m_pWindowOwner->m_pWLSurface; + else + return m_pLayerOwner->surface; +} + Vector2D CPopup::coordsRelativeToParent() { Vector2D offset; diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index eea3fb84..04996612 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -18,21 +18,22 @@ class CPopup { ~CPopup(); - Vector2D coordsRelativeToParent(); - Vector2D coordsGlobal(); + SP getT1Owner(); + Vector2D coordsRelativeToParent(); + Vector2D coordsGlobal(); - Vector2D size(); + Vector2D size(); - void onNewPopup(SP popup); - void onDestroy(); - void onMap(); - void onUnmap(); - void onCommit(bool ignoreSiblings = false); - void onReposition(); + void onNewPopup(SP popup); + void onDestroy(); + void onMap(); + void onUnmap(); + void onCommit(bool ignoreSiblings = false); + void onReposition(); - void recheckTree(); + void recheckTree(); - bool visible(); + bool visible(); // will also loop over this node void breadthfirst(std::function fn, void* data); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 3e4063f4..b40d6cad 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -6,6 +6,7 @@ #include "../protocols/core/Compositor.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" +#include "wlr-layer-shell-unstable-v1.hpp" #include #include @@ -584,6 +585,36 @@ void CSeatManager::setGrab(SP grab) { auto oldGrab = seatGrab; seatGrab.reset(); g_pInputManager->refocus(); + + auto currentFocus = state.keyboardFocus.lock(); + auto refocus = !currentFocus; + + SP surf; + PHLLS layer; + + if (!refocus) { + surf = CWLSurface::fromResource(currentFocus); + layer = surf->getLayer(); + } + + if (!refocus && !layer) { + auto popup = surf->getPopup(); + if (popup) { + auto parent = popup->getT1Owner(); + layer = parent->getLayer(); + } + } + + if (!refocus && layer) + refocus = layer->interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; + + if (refocus) { + auto candidate = g_pCompositor->m_pLastWindow.lock(); + + if (candidate) + g_pCompositor->focusWindow(candidate); + } + if (oldGrab->onEnd) oldGrab->onEnd(); } From 5ca48231287d67e75a3f21dbdbc47d6dc65752c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darth=20=C5=A0=C4=8C!?= Date: Sat, 7 Sep 2024 17:14:23 +0200 Subject: [PATCH 141/298] config: Added default button mapping for xf86 keys (#7672) * Added default button mapping for laptop multimedia keys for volume and brightness * Added default button mapping for laptop multimedia keys for volume and brightness into example config --- example/hyprland.conf | 8 ++++++++ src/config/defaultConfig.hpp | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/example/hyprland.conf b/example/hyprland.conf index d55d25fd..76e5bcdb 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -228,6 +228,14 @@ bind = $mainMod, mouse_up, workspace, e-1 bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow +# Laptop multimedia keys for volume and LCD brightness +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ +bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- + ############################## ### WINDOWS AND WORKSPACES ### diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 59265fee..b8d215d1 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -241,6 +241,13 @@ bind = $mainMod, mouse_up, workspace, e-1 bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow +# Laptop multimedia keys for volume and LCD brightness +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ +bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- ############################## ### WINDOWS AND WORKSPACES ### From 70add904c40924a761059e4009a8c0f1e43d76a3 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Sat, 7 Sep 2024 14:54:33 -0500 Subject: [PATCH 142/298] config: add exec-shutdown for running commands on shutdown (#7683) * config: add exec-shutdown for running commands on shutdown * compositor: delay stopping until after exec-shutdown --- src/Compositor.hpp | 1 + src/config/ConfigManager.cpp | 42 +++++++++++++++++++++++++++++++++ src/config/ConfigManager.hpp | 3 +++ src/managers/KeybindManager.cpp | 5 ++++ 4 files changed, 51 insertions(+) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index f17d86e5..a57450f1 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -91,6 +91,7 @@ class CCompositor { bool m_bNextIsUnsafe = false; CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state bool m_bIsShuttingDown = false; + bool m_bFinalRequests = false; bool m_bDesktopEnvSet = false; bool m_bEnableXwayland = true; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b16b7747..852994a7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -141,6 +141,18 @@ static Hyprlang::CParseResult handleExecOnce(const char* c, const char* v) { return result; } +static Hyprlang::CParseResult handleExecShutdown(const char* c, const char* v) { + const std::string VALUE = v; + const std::string COMMAND = c; + + const auto RESULT = g_pConfigManager->handleExecShutdown(COMMAND, VALUE); + + Hyprlang::CParseResult result; + if (RESULT.has_value()) + result.setError(RESULT.value().c_str()); + return result; +} + static Hyprlang::CParseResult handleMonitor(const char* c, const char* v) { const std::string VALUE = v; const std::string COMMAND = c; @@ -609,6 +621,7 @@ CConfigManager::CConfigManager() { // keywords m_pConfig->registerHandler(&::handleRawExec, "exec", {false}); m_pConfig->registerHandler(&::handleExecOnce, "exec-once", {false}); + m_pConfig->registerHandler(&::handleExecShutdown, "exec-shutdown", {false}); m_pConfig->registerHandler(&::handleMonitor, "monitor", {false}); m_pConfig->registerHandler(&::handleBind, "bind", {true}); m_pConfig->registerHandler(&::handleUnbind, "unbind", {false}); @@ -801,6 +814,7 @@ std::optional CConfigManager::resetHLConfig() { m_vDeclaredPlugins.clear(); m_dLayerRules.clear(); m_vFailedPluginConfigValues.clear(); + finalExecRequests.clear(); // paths configPaths.clear(); @@ -1398,6 +1412,24 @@ void CConfigManager::dispatchExecOnce() { g_pCompositor->performUserChecks(); } +void CConfigManager::dispatchExecShutdown() { + if (finalExecRequests.empty()) { + g_pCompositor->m_bFinalRequests = false; + return; + } + + g_pCompositor->m_bFinalRequests = true; + + for (auto const& c : finalExecRequests) { + handleExecShutdown("", c); + } + + finalExecRequests.clear(); + + // Actually exit now + handleExecShutdown("", "hyprctl dispatch exit"); +} + void CConfigManager::appendMonitorRule(const SMonitorRule& r) { m_dMonitorRules.emplace_back(r); } @@ -1700,6 +1732,16 @@ std::optional CConfigManager::handleExecOnce(const std::string& com return {}; } +std::optional CConfigManager::handleExecShutdown(const std::string& command, const std::string& args) { + if (g_pCompositor->m_bFinalRequests) { + g_pKeybindManager->spawn(args); + return {}; + } + + finalExecRequests.push_back(args); + return {}; +} + static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { auto args = CVarList(modeline, 0, 's'); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 4d087753..da450e39 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -192,6 +192,7 @@ class CConfigManager { // no-op when done. void dispatchExecOnce(); + void dispatchExecShutdown(); void performMonitorReload(); void appendMonitorRule(const SMonitorRule&); @@ -213,6 +214,7 @@ class CConfigManager { // keywords std::optional handleRawExec(const std::string&, const std::string&); std::optional handleExecOnce(const std::string&, const std::string&); + std::optional handleExecShutdown(const std::string&, const std::string&); std::optional handleMonitor(const std::string&, const std::string&); std::optional handleBind(const std::string&, const std::string&); std::optional handleUnbind(const std::string&, const std::string&); @@ -289,6 +291,7 @@ class CConfigManager { bool firstExecDispatched = false; bool m_bManualCrashInitiated = false; std::deque firstExecRequests; + std::deque finalExecRequests; std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins std::string m_szConfigErrors = ""; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2db9f375..2f593d74 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1781,6 +1781,11 @@ SDispatchResult CKeybindManager::renameWorkspace(std::string args) { } SDispatchResult CKeybindManager::exitHyprland(std::string argz) { + g_pConfigManager->dispatchExecShutdown(); + + if (g_pCompositor->m_bFinalRequests) + return {}; // Exiting deferred until requests complete + g_pCompositor->stopCompositor(); return {}; } From 312411fc7073143a8bf1fc3ba23ef403b7d15eee Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 8 Sep 2024 00:46:16 +0100 Subject: [PATCH 143/298] windows: support size with pseudo tiled fixes #7690 --- src/events/Windows.cpp | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 034920a2..544483b1 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -344,7 +344,8 @@ void Events::listener_mapWindow(void* owner, void* data) { Debug::log(LOG, "Rule size, applying to {}", PWINDOW); - PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); + PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal(); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); PWINDOW->setHidden(false); @@ -449,8 +450,36 @@ void Events::listener_mapWindow(void* owner, void* data) { } else { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); - // Set the pseudo size here too so that it doesnt end up being 0x0 - PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10); + bool setPseudo = false; + + for (auto const& r : PWINDOW->m_vMatchedRules) { + if (r.szRule.starts_with("size")) { + try { + const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); + const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); + const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); + + const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); + + const auto SIZEX = SIZEXSTR == "max" ? + std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : + (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x); + const auto SIZEY = SIZEYSTR == "max" ? + std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : + (!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y); + + Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW); + + setPseudo = true; + PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY); + + PWINDOW->setHidden(false); + } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); } + } + } + + if (!setPseudo) + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10); } const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); From 0f594732b063a90d44df8c5d402d658f27471dfe Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 8 Sep 2024 17:48:21 +0100 Subject: [PATCH 144/298] props: bump version to 0.43.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 787ffc30..8298bb08 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.42.0 +0.43.0 From 07a21fdfa9e4d3827457dc3f08a4910703fedd35 Mon Sep 17 00:00:00 2001 From: diniamo <55629891+diniamo@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:20:45 +0200 Subject: [PATCH 145/298] github(nix-build): switch to better nix installer, attempt at fixing hash mismatch (#7701) * github(nix-build): switch to DeterminateSystems/nix-installer-action * github(nix-build): switch to a direct git reference instead of cloning * github(nix-ci): attempt to fix CI for pull requests --- .github/workflows/nix-build.yml | 11 +++-------- .github/workflows/nix-ci.yml | 3 +-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index ed0c2ae1..50823629 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -16,17 +16,12 @@ jobs: runs-on: ubuntu-latest steps: - - name: Clone repository - uses: actions/checkout@v4 - with: - ref: ${{ github.ref }} - submodules: recursive - - - uses: cachix/install-nix-action@v27 + - uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/magic-nix-cache-action@main + - uses: cachix/cachix-action@v15 with: name: hyprland authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" + - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index 2f35337d..75c19790 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -9,7 +9,6 @@ jobs: secrets: inherit build: - if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure') - needs: update-inputs + if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) uses: ./.github/workflows/nix-build.yml secrets: inherit From 05b48d48d9074041fd7987c36f04bdc1dafa575c Mon Sep 17 00:00:00 2001 From: Davide Conti Date: Sun, 8 Sep 2024 20:36:33 +0200 Subject: [PATCH 146/298] config: Limit max volume to 100% --- example/hyprland.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 76e5bcdb..1179a274 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -229,7 +229,7 @@ bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow # Laptop multimedia keys for volume and LCD brightness -bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle From 6179b17903647d7659749f9f7c79bb9aff97a806 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Sun, 8 Sep 2024 22:12:01 +0200 Subject: [PATCH 147/298] github: improve issue template (#7699) * github: improve issue template Require to check that you have searched through open and closed issues before committing. * fix yaml syntax * clarify text * validation * revert validation * markdown * done --- .github/ISSUE_TEMPLATE/bug.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index e3e97bef..7d402904 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -2,12 +2,13 @@ name: Bug Report description: Something is not working right labels: ["bug"] body: - - type: markdown + - type: checkboxes attributes: - value: | - ## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists. - - --- + label: Already reported ? * + description: Before opening a new bug report, please take a moment to search through the current open and closed issues to check if it already exists. + options: + - label: I have searched the existing open and closed issues. + required: true - type: dropdown id: type From 7c4c402bd7f24241c096d809cc80408a469f15cb Mon Sep 17 00:00:00 2001 From: Richard Ayotte Date: Sun, 8 Sep 2024 17:04:07 -0400 Subject: [PATCH 148/298] config: include XF86Audio* key bindings to default cfg (#7695) --- example/hyprland.conf | 13 +++++++++---- src/config/defaultConfig.hpp | 14 ++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 1179a274..4adc2d40 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -59,7 +59,7 @@ env = HYPRCURSOR_SIZE,24 # Refer to https://wiki.hyprland.org/Configuring/Variables/ # https://wiki.hyprland.org/Configuring/Variables/#general -general { +general { gaps_in = 5 gaps_out = 20 @@ -70,7 +70,7 @@ general { col.inactive_border = rgba(595959aa) # Set to true enable resizing windows by clicking and dragging on borders and gaps - resize_on_border = false + resize_on_border = false # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on allow_tearing = false @@ -96,7 +96,7 @@ decoration { enabled = true size = 3 passes = 1 - + vibrancy = 0.1696 } } @@ -129,7 +129,7 @@ master { } # https://wiki.hyprland.org/Configuring/Variables/#misc -misc { +misc { force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( } @@ -236,6 +236,11 @@ bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- +# Requires playerctl +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPause, exec, playerctl play-pause +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioPrev, exec, playerctl previous ############################## ### WINDOWS AND WORKSPACES ### diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index b8d215d1..5843caa3 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -72,7 +72,7 @@ env = HYPRCURSOR_SIZE,24 # Refer to https://wiki.hyprland.org/Configuring/Variables/ # https://wiki.hyprland.org/Configuring/Variables/#general -general { +general { gaps_in = 5 gaps_out = 20 @@ -83,7 +83,7 @@ general { col.inactive_border = rgba(595959aa) # Set to true enable resizing windows by clicking and dragging on borders and gaps - resize_on_border = false + resize_on_border = false # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on allow_tearing = false @@ -109,7 +109,7 @@ decoration { enabled = true size = 3 passes = 1 - + vibrancy = 0.1696 } } @@ -142,7 +142,7 @@ master { } # https://wiki.hyprland.org/Configuring/Variables/#misc -misc { +misc { force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( } @@ -249,6 +249,12 @@ bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- +# Requires playerctl +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPause, exec, playerctl play-pause +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioPrev, exec, playerctl previous + ############################## ### WINDOWS AND WORKSPACES ### ############################## From e1448732b3a463fc3aafc162d456a3db593253c8 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 9 Sep 2024 17:58:44 +0900 Subject: [PATCH 149/298] tiv1: fix deleting first character (#7716) --- src/managers/input/TextInput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 4c2e326a..d488f173 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -264,7 +264,7 @@ void CTextInput::updateIMEState(SP ime) { INPUT->preeditStyling(0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditString(pV1Input->serial, ime->current.preeditString.string.c_str(), ""); } else { - INPUT->preeditCursor(ime->current.preeditString.begin); + INPUT->preeditCursor(0); INPUT->preeditStyling(0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditString(pV1Input->serial, "", ""); } From 43e1415e715bb6c6c4ea722ba839210938ac2b07 Mon Sep 17 00:00:00 2001 From: davc0n Date: Mon, 9 Sep 2024 11:01:26 +0200 Subject: [PATCH 150/298] assets: Remove execute permission from lockdead.png (#7715) --- assets/install/lockdead.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 assets/install/lockdead.png diff --git a/assets/install/lockdead.png b/assets/install/lockdead.png old mode 100755 new mode 100644 From 04421063af2941c6e27e6dca2bdc2c387778a3a5 Mon Sep 17 00:00:00 2001 From: darkwater Date: Mon, 9 Sep 2024 11:10:08 +0200 Subject: [PATCH 151/298] config: add order rule for layers (#7697) --- src/config/ConfigManager.cpp | 2 +- src/desktop/LayerSurface.cpp | 5 +++++ src/desktop/LayerSurface.hpp | 1 + src/render/Renderer.cpp | 4 ++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 852994a7..57cd2350 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2239,7 +2239,7 @@ bool windowRuleValid(const std::string& RULE) { bool layerRuleValid(const std::string& RULE) { static const auto rules = std::unordered_set{"noanim", "blur", "blurpopups", "dimaround"}; - static const auto rulesPrefix = std::vector{"ignorealpha", "ignorezero", "xray", "animation"}; + static const auto rulesPrefix = std::vector{"ignorealpha", "ignorezero", "xray", "animation", "order"}; return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }); } diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 155a2605..0e7e71b6 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -394,6 +394,11 @@ void CLayerSurface::applyRules() { } else if (rule.rule.starts_with("animation")) { CVarList vars{rule.rule, 2, 's'}; animationStyle = vars[1]; + } else if (rule.rule.starts_with("order")) { + CVarList vars{rule.rule, 2, 's'}; + try { + order = std::stoi(vars[1]); + } catch (...) { Debug::log(ERR, "Invalid value passed to order"); } } } } diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 84935b34..e0f17039 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -55,6 +55,7 @@ class CLayerSurface { bool ignoreAlpha = false; float ignoreAlphaValue = 0.f; bool dimAround = false; + int64_t order = 0; std::optional animationStyle; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 27fde129..08bf76cb 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1742,6 +1742,10 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + for (auto& la : PMONITOR->m_aLayerSurfaceLayers) { + std::stable_sort(la.begin(), la.end(), [](const PHLLSREF& a, const PHLLSREF& b) { return a->order > b->order; }); + } + for (auto const& la : PMONITOR->m_aLayerSurfaceLayers) arrangeLayerArray(PMONITOR, la, true, &usableArea); From 9609b04ff9e63d16f9b2b9ecfdc732c2c7ebbf2f Mon Sep 17 00:00:00 2001 From: justmessingaround <69480361+DemonKingSwarn@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:49:17 +0530 Subject: [PATCH 152/298] man: Fixed the man page to show the new information (#7713) * Update Hyprland.1.rst * Update Hyprland.1 --- docs/Hyprland.1 | 4 ++-- docs/Hyprland.1.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index 92061da2..465671e1 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]]. .SH DESCRIPTION .PP -\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on -wlroots that doesn\[aq]t sacrifice on its looks. +\f[B]Hyprland\f[R] is an independent, highly customizable, +dynamic tiling Wayland compositor that doesn\[aq]t sacrifice on its looks. .PP You can launch Hyprland by either going into a TTY and executing \f[B]Hyprland\f[R], or with a login manager. diff --git a/docs/Hyprland.1.rst b/docs/Hyprland.1.rst index c73b4343..e10d9c6a 100644 --- a/docs/Hyprland.1.rst +++ b/docs/Hyprland.1.rst @@ -14,8 +14,8 @@ SYNOPSIS DESCRIPTION =========== -**Hyprland** is a dynamic tiling Wayland compositor based on -wlroots that doesn't sacrifice on its looks. +**Hyprland** is an independent, highly customizable, +dynamic tiling Wayland compositor that doesn't sacrifice on its looks. You can launch Hyprland by either going into a TTY and executing **Hyprland**, or with a login manager. From 85da1a17d831e2b5db9c1c1e4ce6427d63563562 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 9 Sep 2024 15:19:44 +0000 Subject: [PATCH 153/298] [gha] build man pages --- docs/Hyprland.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index 465671e1..2d6e1444 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]]. .SH DESCRIPTION .PP -\f[B]Hyprland\f[R] is an independent, highly customizable, -dynamic tiling Wayland compositor that doesn\[aq]t sacrifice on its looks. +\f[B]Hyprland\f[R] is an independent, highly customizable, dynamic +tiling Wayland compositor that doesn\[aq]t sacrifice on its looks. .PP You can launch Hyprland by either going into a TTY and executing \f[B]Hyprland\f[R], or with a login manager. From 8237d7e1a4994f70636b2e91584775308f24a584 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:29:00 +0000 Subject: [PATCH 154/298] input: move dmps activation to input listeners (#7721) --- src/managers/KeybindManager.hpp | 1 + src/managers/PointerManager.cpp | 30 +++++++++++++++++++++++++++++ src/managers/input/InputManager.cpp | 21 +++++++++----------- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index bf3b049f..096cd4f9 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -221,6 +221,7 @@ class CKeybindManager { friend class CInputManager; friend class CConfigManager; friend class CWorkspace; + friend class CPointerManager; }; inline std::unique_ptr g_pKeybindManager; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index ce9ea4a4..e48c77d5 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -821,6 +821,9 @@ void CPointerManager::attachPointer(SP pointer) { if (!pointer) return; + static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); + + // auto listener = pointerListeners.emplace_back(makeShared()); listener->pointer = pointer; @@ -836,6 +839,9 @@ void CPointerManager::attachPointer(SP pointer) { g_pInputManager->onMouseMoved(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) { @@ -844,6 +850,9 @@ void CPointerManager::attachPointer(SP pointer) { g_pInputManager->onMouseWarp(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) { @@ -872,6 +881,9 @@ void CPointerManager::attachPointer(SP pointer) { g_pInputManager->onSwipeBegin(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) { @@ -896,6 +908,9 @@ void CPointerManager::attachPointer(SP pointer) { PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) { @@ -938,6 +953,9 @@ void CPointerManager::attachTouch(SP touch) { if (!touch) return; + static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); + + // auto listener = touchListeners.emplace_back(makeShared()); listener->touch = touch; @@ -953,6 +971,9 @@ void CPointerManager::attachTouch(SP touch) { g_pInputManager->onTouchDown(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->up = touch->touchEvents.up.registerListener([this] (std::any e) { @@ -987,6 +1008,9 @@ void CPointerManager::attachTablet(SP tablet) { if (!tablet) return; + static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); + + // auto listener = tabletListeners.emplace_back(makeShared()); listener->tablet = tablet; @@ -1002,6 +1026,9 @@ void CPointerManager::attachTablet(SP tablet) { g_pInputManager->onTabletAxis(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) { @@ -1018,6 +1045,9 @@ void CPointerManager::attachTablet(SP tablet) { g_pInputManager->onTabletTip(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) { diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index f1035c82..03c72919 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -28,6 +28,7 @@ #include "../../managers/PointerManager.hpp" #include "../../managers/SeatManager.hpp" +#include "../../managers/KeybindManager.hpp" #include @@ -135,7 +136,6 @@ void CInputManager::sendMotionEventsToFocused() { void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); - static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); static auto PFOLLOWONDND = CConfigValue("misc:always_follow_on_dnd"); static auto PFLOATBEHAVIOR = CConfigValue("input:float_switch_override_focus"); static auto PMOUSEFOCUSMON = CConfigValue("misc:mouse_move_focuses_monitor"); @@ -157,11 +157,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; - if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) { - // enable dpms - g_pKeybindManager->dpms("on"); - } - Vector2D mouseCoords = getMouseCoordsInternal(); const auto MOUSECOORDSFLOORED = mouseCoords.floor(); @@ -854,6 +849,8 @@ void CInputManager::newVirtualKeyboard(SP keyboard) } void CInputManager::setupKeyboard(SP keeb) { + static auto PDPMS = CConfigValue("misc:key_press_enables_dpms"); + m_vHIDs.push_back(keeb); try { @@ -882,6 +879,9 @@ void CInputManager::setupKeyboard(SP keeb) { if (PKEEB->enabled) PROTO::idle->onActivity(); + + if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON) + g_pKeybindManager->dpms("on"); }, keeb.get()); @@ -893,6 +893,9 @@ void CInputManager::setupKeyboard(SP keeb) { if (PKEEB->enabled) PROTO::idle->onActivity(); + + if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON) + g_pKeybindManager->dpms("on"); }, keeb.get()); @@ -1284,12 +1287,6 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { const auto EMAP = std::unordered_map{{"keyboard", pKeyboard}, {"event", event}}; EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP); - static auto PDPMS = CConfigValue("misc:key_press_enables_dpms"); - if (*PDPMS && !g_pCompositor->m_bDPMSStateON) { - // enable dpms - g_pKeybindManager->dpms("on"); - } - bool passEvent = DISALLOWACTION || g_pKeybindManager->onKeyEvent(event, pKeyboard); auto e = std::any_cast(event); From c67b257e51133a2aaeec050fc4d283e2eaea6375 Mon Sep 17 00:00:00 2001 From: davc0n Date: Tue, 10 Sep 2024 12:06:37 +0200 Subject: [PATCH 155/298] build: Set cmake_minimum_required to version 3.30 (#7709) * build: Set cmake_minimum_required to version 3.30 * Nix: add patch for CMake min ver --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- nix/cmake-version.patch | 10 ++++++++++ nix/default.nix | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 nix/cmake-version.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index d8424d91..6fdf98db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.27) +cmake_minimum_required(VERSION 3.30) # Get version file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) diff --git a/nix/cmake-version.patch b/nix/cmake-version.patch new file mode 100644 index 00000000..ccc9c738 --- /dev/null +++ b/nix/cmake-version.patch @@ -0,0 +1,10 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 6fdf98db..d8424d91 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.30) ++cmake_minimum_required(VERSION 3.27) + + # Get version + file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) diff --git a/nix/default.nix b/nix/default.nix index 1c6a0113..985a4cbb 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -64,6 +64,8 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov patches = [ # forces GCC to use -std=c++26 ./stdcxx.patch + # Nix does not have CMake 3.30 yet, so override the minimum version + ./cmake-version.patch ]; postPatch = '' From 13f90bb87a697866f1bbbacd1473d04f33ec2aa7 Mon Sep 17 00:00:00 2001 From: Alexandre Acebedo Date: Sun, 8 Sep 2024 20:54:12 +0200 Subject: [PATCH 156/298] update xdph commit in flake.lock --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 99a544e2..239ec219 100644 --- a/flake.lock +++ b/flake.lock @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1725203932, - "narHash": "sha256-VLULC/OnI+6R9KEP2OIGk+uLJJsfRlaLouZ5gyFd2+Y=", + "lastModified": 1725228143, + "narHash": "sha256-kbSiPA5oXiz1+1eVoRslMi5wylHD6SDT8dS9eZAxXAM=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "2425e8f541525fa7409d9f26a8ffaf92a3767251", + "rev": "11e15b437e7efc39e452f36e15a183225d6bfa39", "type": "github" }, "original": { From 155d44016d0cb11332c454db73d59030cdbd7b13 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Tue, 10 Sep 2024 22:49:10 +0900 Subject: [PATCH 157/298] textinput: handle IME resetting (#7731) --- src/managers/input/InputMethodRelay.cpp | 10 ++++++---- src/managers/input/InputMethodRelay.hpp | 4 ++-- src/managers/input/TextInput.cpp | 24 +++++++++++++++++------- src/managers/input/TextInput.hpp | 2 ++ src/protocols/TextInputV1.cpp | 1 + src/protocols/TextInputV1.hpp | 1 + src/protocols/TextInputV3.cpp | 19 ++++++++++++++----- src/protocols/TextInputV3.hpp | 7 ++++++- 8 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 1608e123..5ef7f331 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -106,20 +106,22 @@ void CInputMethodRelay::updateAllPopups() { } } -void CInputMethodRelay::activateIME(CTextInput* pInput) { +void CInputMethodRelay::activateIME(CTextInput* pInput, bool shouldCommit) { if (m_pIME.expired()) return; m_pIME->activate(); - commitIMEState(pInput); + if (shouldCommit) + commitIMEState(pInput); } -void CInputMethodRelay::deactivateIME(CTextInput* pInput) { +void CInputMethodRelay::deactivateIME(CTextInput* pInput, bool shouldCommit) { if (m_pIME.expired()) return; m_pIME->deactivate(); - commitIMEState(pInput); + if (shouldCommit) + commitIMEState(pInput); } void CInputMethodRelay::commitIMEState(CTextInput* pInput) { diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index 5ecc11a2..3d706563 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -21,8 +21,8 @@ class CInputMethodRelay { void onNewTextInput(WP tiv3); void onNewTextInput(WP pTIV1); - void activateIME(CTextInput* pInput); - void deactivateIME(CTextInput* pInput); + void activateIME(CTextInput* pInput, bool shouldCommit = true); + void deactivateIME(CTextInput* pInput, bool shouldCommit = true); void commitIMEState(CTextInput* pInput); void removeTextInput(CTextInput* pInput); diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index d488f173..2769fad0 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -22,6 +22,7 @@ void CTextInput::initCallbacks() { listeners.enable = INPUT->events.enable.registerListener([this](std::any p) { onEnabled(); }); listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); + listeners.reset = INPUT->events.reset.registerListener([this](std::any p) { onReset(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); @@ -41,6 +42,7 @@ void CTextInput::initCallbacks() { }); listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); + listeners.reset = INPUT->events.reset.registerListener([this](std::any p) { onReset(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); @@ -93,13 +95,21 @@ void CTextInput::onDisabled() { g_pInputManager->m_sIMERelay.deactivateIME(this); } +void CTextInput::onReset() { + if (g_pInputManager->m_sIMERelay.m_pIME.expired()) + return; + + g_pInputManager->m_sIMERelay.deactivateIME(this, false); + g_pInputManager->m_sIMERelay.activateIME(this); +} + void CTextInput::onCommit() { if (g_pInputManager->m_sIMERelay.m_pIME.expired()) { // Debug::log(WARN, "Committing TextInput on no IME!"); return; } - if (!(isV3() ? pV3Input->current.enabled : pV1Input->active)) { + if (!(isV3() ? pV3Input->current.enabled.value : pV1Input->active)) { Debug::log(WARN, "Disabled TextInput commit?"); return; } @@ -128,8 +138,8 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) - pV3Input->current.enabled = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) + pV3Input->current.enabled.value = false; if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -144,8 +154,8 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) - pV3Input->current.enabled = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) + pV3Input->current.enabled.value = false; if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -194,8 +204,8 @@ void CTextInput::leave() { if (isV3()) { pV3Input->leave(focusedSurface()); - if (pV3Input->current.enabled) { - pV3Input->current.enabled = false; + if (pV3Input->current.enabled.value) { + pV3Input->current.enabled.value = false; onDisabled(); } } else diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 0f69866e..f920adc7 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -29,6 +29,7 @@ class CTextInput { void onEnabled(SP surfV1 = nullptr); void onDisabled(); void onCommit(); + void onReset(); bool hasCursorRectangle(); CBox cursorBox(); @@ -47,6 +48,7 @@ class CTextInput { struct { CHyprSignalListener enable; CHyprSignalListener disable; + CHyprSignalListener reset; CHyprSignalListener commit; CHyprSignalListener destroy; CHyprSignalListener surfaceUnmap; diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index f25f5aca..dad74b53 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -31,6 +31,7 @@ CTextInputV1::CTextInputV1(SP resource_) : resource(resource_) resource->setReset([this](CZwpTextInputV1* pMgr) { pendingSurrounding.isPending = false; pendingContentType.isPending = false; + events.reset.emit(); }); resource->setSetSurroundingText( diff --git a/src/protocols/TextInputV1.hpp b/src/protocols/TextInputV1.hpp index c85a1f31..9bee452c 100644 --- a/src/protocols/TextInputV1.hpp +++ b/src/protocols/TextInputV1.hpp @@ -37,6 +37,7 @@ class CTextInputV1 { CSignal onCommit; CSignal enable; CSignal disable; + CSignal reset; CSignal destroy; } events; diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 42dc659e..30374104 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -19,17 +19,22 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) resource->setOnDestroy([this](CZwpTextInputV3* r) { PROTO::textInputV3->destroyTextInput(this); }); resource->setCommit([this](CZwpTextInputV3* r) { - bool wasEnabled = current.enabled; + bool wasEnabled = current.enabled.value; current = pending; serial++; - if (wasEnabled && !current.enabled) + if (wasEnabled && !current.enabled.value) events.disable.emit(); - else if (!wasEnabled && current.enabled) + else if (!wasEnabled && current.enabled.value) events.enable.emit(); + else if (current.enabled.value && current.enabled.isEnablePending && current.enabled.isDisablePending) + events.reset.emit(); else events.onCommit.emit(); + + pending.enabled.isEnablePending = false; + pending.enabled.isDisablePending = false; }); resource->setSetSurroundingText([this](CZwpTextInputV3* r, const char* text, int32_t cursor, int32_t anchor) { @@ -54,10 +59,14 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) resource->setEnable([this](CZwpTextInputV3* r) { pending.reset(); - pending.enabled = true; + pending.enabled.value = true; + pending.enabled.isEnablePending = true; }); - resource->setDisable([this](CZwpTextInputV3* r) { pending.enabled = false; }); + resource->setDisable([this](CZwpTextInputV3* r) { + pending.enabled.value = false; + pending.enabled.isDisablePending = true; + }); } CTextInputV3::~CTextInputV3() { diff --git a/src/protocols/TextInputV3.hpp b/src/protocols/TextInputV3.hpp index 9f6284dc..ba8b75e6 100644 --- a/src/protocols/TextInputV3.hpp +++ b/src/protocols/TextInputV3.hpp @@ -31,6 +31,7 @@ class CTextInputV3 { CSignal onCommit; CSignal enable; CSignal disable; + CSignal reset; CSignal destroy; } events; @@ -53,7 +54,11 @@ class CTextInputV3 { CBox cursorBox; } box; - bool enabled = false; + struct { + bool isEnablePending = false; + bool isDisablePending = false; + bool value = false; + } enabled; zwpTextInputV3ChangeCause cause = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD; From 518399a95bada8bad8a4c29514da9962ce442307 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 11 Sep 2024 09:30:21 +0100 Subject: [PATCH 158/298] pointermgr: avoid derefing null outputs --- src/managers/PointerManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index e48c77d5..6b2a40f5 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -675,7 +675,7 @@ void CPointerManager::damageIfSoftware() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); for (auto const& mw : monitorStates) { - if (mw->monitor.expired()) + if (mw->monitor.expired() || !mw->monitor->output) continue; if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { @@ -789,7 +789,7 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { void CPointerManager::onMonitorLayoutChange() { currentMonitorLayout.monitorBoxes.clear(); for (auto const& m : g_pCompositor->m_vMonitors) { - if (m->isMirror() || !m->m_bEnabled) + if (m->isMirror() || !m->m_bEnabled || !m->output) continue; currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize}); From 7a8c013edcbc59804a98fffa0436efcb268e1cda Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 11 Sep 2024 18:50:59 +0300 Subject: [PATCH 159/298] Meson: fix protocols, clean up --- protocols/meson.build | 147 ++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 77 deletions(-) diff --git a/protocols/meson.build b/protocols/meson.build index de650230..d686bacd 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -1,77 +1,75 @@ -wayland_protos = dependency('wayland-protocols', +wayland_protos = dependency( + 'wayland-protocols', version: '>=1.32', fallback: 'wayland-protocols', default_options: ['tests=false'], ) -hyprland_protos = dependency('hyprland-protocols', +hyprland_protos = dependency( + 'hyprland-protocols', version: '>=0.2', - fallback: 'hyprland-protocols', + fallback: 'hyprland-protocols', ) -wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') -hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir') +wayland_protocol_dir = wayland_protos.get_variable('pkgdatadir') +hyprland_protocol_dir = hyprland_protos.get_variable('pkgdatadir') -hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) +hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.10', native: true) hyprwayland_scanner = find_program( hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), native: true, ) -new_protocols = [ - ['wlr-gamma-control-unstable-v1.xml'], - ['wlr-foreign-toplevel-management-unstable-v1.xml'], - ['wlr-output-power-management-unstable-v1.xml'], - ['input-method-unstable-v2.xml'], - ['virtual-keyboard-unstable-v1.xml'], - ['wlr-virtual-pointer-unstable-v1.xml'], - ['wlr-output-management-unstable-v1.xml'], - ['kde-server-decoration.xml'], - ['wlr-layer-shell-unstable-v1.xml'], - ['wayland-drm.xml'], - ['wlr-data-control-unstable-v1.xml'], - ['wlr-screencopy-unstable-v1.xml'], - [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'], - [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], - [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], - [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], - [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], - [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], - [wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'], - [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'], - [wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'], - [wl_protocol_dir, 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml'], - [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], - [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], - [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], - [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], - [wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], - [wl_protocol_dir, 'stable/tablet/tablet-v2.xml'], - [wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], - [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], - [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'], - [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], - [wl_protocol_dir, 'stable/viewporter/viewporter.xml'], - [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], - [wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'], - [wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'], - [wl_protocol_dir, 'staging/xdg-dialog/xdg-dialog-v1.xml'], +protocols = [ + 'wlr-gamma-control-unstable-v1.xml', + 'wlr-foreign-toplevel-management-unstable-v1.xml', + 'wlr-output-power-management-unstable-v1.xml', + 'input-method-unstable-v2.xml', + 'virtual-keyboard-unstable-v1.xml', + 'wlr-virtual-pointer-unstable-v1.xml', + 'wlr-output-management-unstable-v1.xml', + 'kde-server-decoration.xml', + 'wlr-layer-shell-unstable-v1.xml', + 'wayland-drm.xml', + 'wlr-data-control-unstable-v1.xml', + 'wlr-screencopy-unstable-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', + wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', + wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', + wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', + wayland_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', + wayland_protocol_dir / 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml', + wayland_protocol_dir / 'unstable/relative-pointer/relative-pointer-unstable-v1.xml', + wayland_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml', + wayland_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml', + wayland_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml', + wayland_protocol_dir / 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml', + wayland_protocol_dir / 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml', + wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml', + wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v1.xml', + wayland_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', + wayland_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', + wayland_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml', + wayland_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', + wayland_protocol_dir / 'stable/tablet/tablet-v2.xml', + wayland_protocol_dir / 'stable/presentation-time/presentation-time.xml', + wayland_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', + wayland_protocol_dir / 'unstable/primary-selection/primary-selection-unstable-v1.xml', + wayland_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml', + wayland_protocol_dir / 'stable/viewporter/viewporter.xml', + wayland_protocol_dir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml', + wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', + wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', + wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', ] -wl_protos_src = [] -wl_protos_headers = [] - -new_wl_protos = [] -foreach p : new_protocols - xml = join_paths(p) - new_wl_protos += custom_target( - xml.underscorify(), - input: xml, +wl_protocols = [] +foreach protocol : protocols + wl_protocols += custom_target( + protocol.underscorify(), + input: protocol, install: true, install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], @@ -79,31 +77,26 @@ foreach p : new_protocols ) endforeach -wayland_server_dep = dependency('wayland-server', version: '>=1.20.0') -wayland_server_dir = wayland_server_dep.get_variable('pkgdatadir') +# wayland.xml generation +wayland_scanner = dependency('wayland-scanner') +wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir') -wl_server_protos = [ - wayland_server_dir / 'wayland.xml' -] -wl_server_protos_gen = [] -foreach p : wl_server_protos - wl_server_protos_gen += custom_target( - p.underscorify(), - input: p, - install: true, - install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], - output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], - command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], - ) -endforeach +wayland_xml = wayland_scanner_datadir / 'wayland.xml' +wayland_protocol = custom_target( + wayland_xml.underscorify(), + input: wayland_xml, + install: true, + install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], + output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], + command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], +) lib_server_protos = static_library( 'server_protos', - wl_protos_src + wl_protos_headers + new_wl_protos + wl_server_protos_gen, - dependencies: wayland_server_dep.partial_dependency(compile_args: true), + wl_protocols + wayland_protocol, ) server_protos = declare_dependency( link_with: lib_server_protos, - sources: wl_protos_headers + new_wl_protos, + sources: wl_protocols + wayland_protocol, ) From e01da1fd7a50ab0baeaba074f2a14c826b05bf1c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 11 Sep 2024 19:00:47 +0300 Subject: [PATCH 160/298] Meson: format --- assets/install/meson.build | 6 +++++- assets/meson.build | 7 ++++++- docs/meson.build | 4 ++-- example/meson.build | 12 ++++++++++-- hyprctl/meson.build | 26 +++++++++++++++++++++----- hyprpm/src/meson.build | 28 ++++++++++++++++++++++------ meson.build | 26 +++++++++++++++++--------- src/meson.build | 6 ++++-- 8 files changed, 87 insertions(+), 28 deletions(-) diff --git a/assets/install/meson.build b/assets/install/meson.build index 1d4fb917..45076469 100644 --- a/assets/install/meson.build +++ b/assets/install/meson.build @@ -2,5 +2,9 @@ globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check: files = globber.stdout().strip().split('\n') foreach file : files - install_data(file, install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') + install_data( + file, + install_dir: join_paths(get_option('datadir'), 'hypr'), + install_tag: 'runtime', + ) endforeach diff --git a/assets/meson.build b/assets/meson.build index 0648037a..2a28121d 100644 --- a/assets/meson.build +++ b/assets/meson.build @@ -1,2 +1,7 @@ -install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') +install_data( + 'hyprland-portals.conf', + install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), + install_tag: 'runtime', +) + subdir('install') diff --git a/docs/meson.build b/docs/meson.build index a5d7e737..6ff51d1a 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -1,2 +1,2 @@ -install_man ('Hyprland.1') -install_man ('hyprctl.1') +install_man('Hyprland.1') +install_man('hyprctl.1') diff --git a/example/meson.build b/example/meson.build index 2fb3a35e..a338644e 100644 --- a/example/meson.build +++ b/example/meson.build @@ -1,2 +1,10 @@ -install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') -install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime') +install_data( + 'hyprland.conf', + install_dir: join_paths(get_option('datadir'), 'hypr'), + install_tag: 'runtime', +) +install_data( + 'hyprland.desktop', + install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), + install_tag: 'runtime', +) diff --git a/hyprctl/meson.build b/hyprctl/meson.build index 5488845f..455f5739 100644 --- a/hyprctl/meson.build +++ b/hyprctl/meson.build @@ -1,10 +1,26 @@ -executable('hyprctl', 'main.cpp', +executable( + 'hyprctl', + 'main.cpp', dependencies: [ dependency('hyprutils', version: '>= 0.1.1'), ], - install: true + install: true, ) -install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprctl') -install_data('hyprctl.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime') -install_data('hyprctl.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprctl') +install_data( + 'hyprctl.bash', + install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), + install_tag: 'runtime', + rename: 'hyprctl', +) +install_data( + 'hyprctl.fish', + install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), + install_tag: 'runtime', +) +install_data( + 'hyprctl.zsh', + install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), + install_tag: 'runtime', + rename: '_hyprctl', +) diff --git a/hyprpm/src/meson.build b/hyprpm/src/meson.build index e2c512a5..2ef6c323 100644 --- a/hyprpm/src/meson.build +++ b/hyprpm/src/meson.build @@ -1,15 +1,31 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) src = globber.stdout().strip().split('\n') -executable('hyprpm', src, +executable( + 'hyprpm', + src, dependencies: [ dependency('hyprutils', version: '>= 0.1.1'), dependency('threads'), - dependency('tomlplusplus') + dependency('tomlplusplus'), ], - install : true + install: true, ) -install_data('../hyprpm.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprpm') -install_data('../hyprpm.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime') -install_data('../hyprpm.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprpm') +install_data( + '../hyprpm.bash', + install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), + install_tag: 'runtime', + rename: 'hyprpm', +) +install_data( + '../hyprpm.fish', + install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), + install_tag: 'runtime', +) +install_data( + '../hyprpm.zsh', + install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), + install_tag: 'runtime', + rename: '_hyprpm', +) diff --git a/meson.build b/meson.build index 6a9b7ac5..123c31ae 100644 --- a/meson.build +++ b/meson.build @@ -1,13 +1,17 @@ -project('Hyprland', 'cpp', 'c', - version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(), - default_options : [ +project( + 'Hyprland', + 'cpp', + 'c', + version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(), + default_options: [ 'warning_level=2', 'default_library=static', 'optimization=3', 'buildtype=release', 'debug=false', 'cpp_std=c++26', - ]) + ], +) datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"' add_project_arguments( @@ -16,10 +20,10 @@ add_project_arguments( '-Wno-unused-value', '-Wno-missing-field-initializers', '-Wno-narrowing', - '-Wno-pointer-arith', - datarootdir, + '-Wno-pointer-arith', datarootdir, ], - language: 'cpp') + language: 'cpp', +) cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.check_header('execinfo.h') @@ -34,7 +38,7 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland')) xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) -gio_dep = dependency('gio-2.0', required:true) +gio_dep = dependency('gio-2.0', required: true) cmake = import('cmake') udis = cmake.subproject('udis86') @@ -47,6 +51,7 @@ endif backtrace_dep = cpp_compiler.find_library('execinfo', required: false) epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs +# Handle options if get_option('systemd').enabled() add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') endif @@ -59,8 +64,10 @@ if get_option('buildtype') == 'debug' add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp') endif -version_h = run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) +# Generate hyprland version and populate version.h +run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) +# Install headers globber = run_command('find', 'src', '-name', '*.h*', check: true) headers = globber.stdout().strip().split('\n') foreach file : headers @@ -75,6 +82,7 @@ subdir('assets') subdir('example') subdir('docs') +# Generate hyprland.pc pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') import('pkgconfig').generate( diff --git a/src/meson.build b/src/meson.build index 475ecc24..3821bd60 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,7 +1,9 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) src = globber.stdout().strip().split('\n') -executable('Hyprland', src, +executable( + 'Hyprland', + src, link_args: '-rdynamic', cpp_pch: 'pch/pch.hpp', dependencies: [ @@ -38,5 +40,5 @@ executable('Hyprland', src, dependency('pangocairo'), dependency('uuid'), ], - install : true + install: true, ) From 8b9e385943d1a9fd0f8c6070fa1eae507ae26145 Mon Sep 17 00:00:00 2001 From: fufexan Date: Wed, 11 Sep 2024 16:10:51 +0000 Subject: [PATCH 161/298] [gha] Nix: update inputs --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 239ec219..55dc6939 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1725199881, - "narHash": "sha256-jsmipf/u1GFZE5tBUkr56CHMN6VpUWCAjfLIhvQijU0=", + "lastModified": 1725753098, + "narHash": "sha256-/NO/h/qD/eJXAQr/fHA4mdDgYsNT9thHQ+oT6KPi2ac=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "f8a687dd29ff019657498f1bd14da2fbbf0e604b", + "rev": "e4a13203112a036fc7f437d391c7810f3dd5ab52", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1725188252, - "narHash": "sha256-yBH8c4GDaEAtBrh+BqIlrx5vp6gG/Gu8fQQK63KAQgs=", + "lastModified": 1725997860, + "narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "c12ab785ce1982f82594aff03b3104c598186ddd", + "rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725103162, - "narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", + "lastModified": 1725983898, + "narHash": "sha256-4b3A9zPpxAxLnkF9MawJNHDtOOl6ruL0r6Og1TEDGCE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", + "rev": "1355a0cbfeac61d785b7183c0caaec1f97361b43", "type": "github" }, "original": { @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1725228143, - "narHash": "sha256-kbSiPA5oXiz1+1eVoRslMi5wylHD6SDT8dS9eZAxXAM=", + "lastModified": 1726046979, + "narHash": "sha256-6SEsjurq9cdTkITA6d49ncAJe4O/8CgRG5/F//s6Xh8=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "11e15b437e7efc39e452f36e15a183225d6bfa39", + "rev": "e695669fd8e1d1be9eaae40f35e00f8bd8b64c18", "type": "github" }, "original": { From 73b9756b8d7ee06fc1c9f072f2a41f2dd1aeb2c9 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Thu, 12 Sep 2024 04:15:01 -0500 Subject: [PATCH 162/298] xwayland: remove extra x11 deactivation (#7755) --- src/managers/XWaylandManager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 144343f8..fad7e451 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -46,11 +46,8 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool PWINDOW->m_pXWaylandSurface->restackToTop(); } PWINDOW->m_pXWaylandSurface->activate(activate); - } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) { + } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) PWINDOW->m_pXDGSurface->toplevel->setActive(activate); - if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) - activateSurface(g_pCompositor->m_pLastFocus.lock(), false); - } } void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { From 118be4dea048df88fd21b84580fe62950c868c8f Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Fri, 13 Sep 2024 01:41:24 +0900 Subject: [PATCH 163/298] textinput: fix tiv3 leave (#7761) --- src/managers/input/TextInput.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 2769fad0..e601ad9a 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -138,8 +138,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) - pV3Input->current.enabled.value = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) { + pV3Input->pending.enabled.value = false; + pV3Input->pending.enabled.isDisablePending = false; + pV3Input->pending.enabled.isEnablePending = false; + pV3Input->current.enabled.value = false; + } if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -154,8 +158,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) - pV3Input->current.enabled.value = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) { + pV3Input->pending.enabled.value = false; + pV3Input->pending.enabled.isDisablePending = false; + pV3Input->pending.enabled.isEnablePending = false; + pV3Input->current.enabled.value = false; + } if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -202,13 +210,9 @@ void CTextInput::leave() { enterLocks = 0; } - if (isV3()) { + if (isV3()) pV3Input->leave(focusedSurface()); - if (pV3Input->current.enabled.value) { - pV3Input->current.enabled.value = false; - onDisabled(); - } - } else + else pV1Input->leave(); setFocusedSurface(nullptr); From d505b3366533b71d57156469c926e8b2b75afb89 Mon Sep 17 00:00:00 2001 From: diniamo Date: Fri, 13 Sep 2024 16:21:33 +0200 Subject: [PATCH 164/298] nix: use meson --- nix/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nix/default.nix b/nix/default.nix index 985a4cbb..d3c7dd5f 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -4,6 +4,7 @@ pkg-config, pkgconf, makeWrapper, + meson, cmake, ninja, aquamarine, @@ -89,6 +90,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov hyprwayland-scanner jq makeWrapper + meson cmake ninja pkg-config From c35ed8363f321bb9925bc5e6f5ff03a903593802 Mon Sep 17 00:00:00 2001 From: diniamo Date: Fri, 13 Sep 2024 17:29:41 +0200 Subject: [PATCH 165/298] nix: adapt cmake options --- nix/cmake-version.patch | 10 ---------- nix/default.nix | 21 +++++++-------------- nix/stdcxx.patch | 12 ------------ 3 files changed, 7 insertions(+), 36 deletions(-) delete mode 100644 nix/cmake-version.patch delete mode 100644 nix/stdcxx.patch diff --git a/nix/cmake-version.patch b/nix/cmake-version.patch deleted file mode 100644 index ccc9c738..00000000 --- a/nix/cmake-version.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 6fdf98db..d8424d91 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -1,4 +1,4 @@ --cmake_minimum_required(VERSION 3.30) -+cmake_minimum_required(VERSION 3.27) - - # Get version - file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) diff --git a/nix/default.nix b/nix/default.nix index d3c7dd5f..8d912fe6 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -62,13 +62,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov src = lib.cleanSource ../.; }; - patches = [ - # forces GCC to use -std=c++26 - ./stdcxx.patch - # Nix does not have CMake 3.30 yet, so override the minimum version - ./cmake-version.patch - ]; - postPatch = '' # Fix hardcoded paths to /usr installation sed -i "s#/usr#$out#" src/render/OpenGL.cpp @@ -144,18 +137,18 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.optionals withSystemd [systemd]) ]; - cmakeBuildType = + mesonBuildType = if debug - then "Debug" - else "RelWithDebInfo"; + then "debug" + else "release"; # we want as much debug info as possible dontStrip = debug; - cmakeFlags = [ - (lib.cmakeBool "NO_XWAYLAND" (!enableXWayland)) - (lib.cmakeBool "LEGACY_RENDERER" legacyRenderer) - (lib.cmakeBool "NO_SYSTEMD" (!withSystemd)) + mesonFlags = [ + (lib.mesonEnable "xwayland" enableXWayland) + (lib.mesonEnable "legacy_renderer" legacyRenderer) + (lib.mesonEnable "systemd" withSystemd) ]; postInstall = '' diff --git a/nix/stdcxx.patch b/nix/stdcxx.patch deleted file mode 100644 index 032e494d..00000000 --- a/nix/stdcxx.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index cfbd431f..73e8e0c2 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -64,6 +64,7 @@ endif() - include_directories(. "src/" "subprojects/udis86/" "protocols/") - set(CMAKE_CXX_STANDARD 26) - add_compile_options( -+ -std=c++26 - -Wall - -Wextra - -Wno-unused-parameter From d35e70a8c6599bb058cf86eb87c783ce1cf72471 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 13 Sep 2024 17:56:39 +0100 Subject: [PATCH 166/298] cmake: drop ninja dep --- Makefile | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index bc7b750b..59efc0ef 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,24 @@ PREFIX = /usr/local legacyrenderer: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` legacyrendererdebug: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` release: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` debug: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja - cmake --build ./build --config Debug --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build + cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` nopch: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` clear: rm -rf build From 5ee4b19691f413072f6877940ed709774333f84b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 14 Sep 2024 23:35:45 +0100 Subject: [PATCH 167/298] data-device: send clock time in motion events remove hack --- src/protocols/core/DataDevice.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 8c1a48d8..43a63949 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -513,7 +513,10 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource if (!box.has_value()) return; - dnd.focusedDevice->sendMotion(0 /* this is a hack */, V - box->pos()); + timespec timeNow; + clock_gettime(CLOCK_MONOTONIC, &timeNow); + + dnd.focusedDevice->sendMotion(timeNow.tv_sec * 1000 + timeNow.tv_nsec / 1000000, V - box->pos()); LOGM(LOG, "Drag motion {}", V - box->pos()); } }); From 4dbdb556fe441506ec5cf129c65b14e514dbcc5a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 14 Sep 2024 23:36:06 +0100 Subject: [PATCH 168/298] data-device: don't send default action of move gtk doesn't like it? --- src/protocols/core/DataDevice.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 43a63949..eac80a83 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -82,10 +82,8 @@ void CWLDataOfferResource::sendData() { if (!source) return; - if (resource->version() >= 3) { + if (resource->version() >= 3) resource->sendSourceActions(7); - resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); - } for (auto const& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); From e74efd87e5aa38f9cf84cb3848ee1ab26e5e4bcb Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 14 Sep 2024 17:37:18 -0500 Subject: [PATCH 169/298] internal: fix initial cursor warping (#7793) --- src/Compositor.cpp | 34 ++++++++++++++++++++++++++++ src/managers/PointerManager.cpp | 40 +-------------------------------- src/managers/PointerManager.hpp | 1 - 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index da659654..8e1b11b0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2943,6 +2943,38 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { return {}; } +static void checkDefaultCursorWarp(SP monitor) { + static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); + static bool cursorDefaultDone = false; + static bool firstLaunch = true; + + const auto POS = monitor->middle(); + + // by default, cursor should be set to first monitor detected + // this is needed as a default if the monitor given in config above doesn't exist + if (firstLaunch) { + firstLaunch = false; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + + if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) { + if (*PCURSORMONITOR == monitor->szName) { + cursorDefaultDone = true; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + } + + // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. + if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } +} + void CCompositor::onNewMonitor(SP output) { // add it to real auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared(output)); @@ -2977,6 +3009,8 @@ void CCompositor::onNewMonitor(SP output) { g_pConfigManager->m_bWantsMonitorReload = true; g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); + checkDefaultCursorWarp(PNEWMONITOR); + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { w->m_iLastSurfaceMonitorID = MONITOR_INVALID; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 6b2a40f5..5a192e13 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -18,13 +18,7 @@ CPointerManager::CPointerManager() { onMonitorLayoutChange(); PMONITOR->events.modeChanged.registerStaticListener( - [this, PMONITOR](void* owner, std::any data) { - g_pEventLoopManager->doLater([this, PMONITOR]() { - onMonitorLayoutChange(); - checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name); - }); - }, - nullptr); + [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.disconnect.registerStaticListener( [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.destroy.registerStaticListener( @@ -44,38 +38,6 @@ CPointerManager::CPointerManager() { }); } -void CPointerManager::checkDefaultCursorWarp(SP monitor, std::string monitorName) { - static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); - static bool cursorDefaultDone = false; - static bool firstLaunch = true; - - const auto POS = monitor->middle(); - - // by default, cursor should be set to first monitor detected - // this is needed as a default if the monitor given in config above doesn't exist - if (firstLaunch) { - firstLaunch = false; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - return; - } - - if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) { - if (*PCURSORMONITOR == monitorName) { - cursorDefaultDone = true; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - return; - } - } - - // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. - if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } -} - void CPointerManager::lockSoftwareAll() { for (auto const& state : monitorStates) state->softwareLocks++; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 082855b5..4a4c4f61 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -26,7 +26,6 @@ class CPointerManager { public: CPointerManager(); - void checkDefaultCursorWarp(SP monitor, std::string monitorName); void attachPointer(SP pointer); void attachTouch(SP touch); void attachTablet(SP tablet); From eb97d949aa31b900d9735bcb8ead47acddc1f339 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 16 Sep 2024 01:31:38 +0900 Subject: [PATCH 170/298] textinput: don't reset if ti isn't enabled (#7798) --- src/managers/input/TextInput.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index e601ad9a..f7a6a350 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -99,6 +99,13 @@ void CTextInput::onReset() { if (g_pInputManager->m_sIMERelay.m_pIME.expired()) return; + if (!focusedSurface()) + return; + + const auto PFOCUSEDTI = g_pInputManager->m_sIMERelay.getFocusedTextInput(); + if (!PFOCUSEDTI || PFOCUSEDTI != this) + return; + g_pInputManager->m_sIMERelay.deactivateIME(this, false); g_pInputManager->m_sIMERelay.activateIME(this); } From e87758529e9d2dc70f318346c66a9d895d4503ce Mon Sep 17 00:00:00 2001 From: AlvinaNancy <152092635+AlvinaNancy@users.noreply.github.com> Date: Sun, 15 Sep 2024 17:25:06 +0000 Subject: [PATCH 171/298] internal: Fix change group current fullscreen state query (#7802) --- src/desktop/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index cc5b48af..feced807 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -991,7 +991,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { const auto PCURRENT = getGroupCurrent(); const bool FULLSCREEN = PCURRENT->isFullscreen(); const auto WORKSPACE = PCURRENT->m_pWorkspace; - const auto MODE = PCURRENT->m_sFullscreenState.client; + const auto MODE = PCURRENT->m_sFullscreenState.internal; const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); From 9e356562446f44c471ae38a80506a9df039305d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leiser=20Fern=C3=A1ndez=20Gallo?= Date: Sun, 15 Sep 2024 22:03:42 +0200 Subject: [PATCH 172/298] internal: Delay monitor events/hooks (#7797) * Delay monitor messages * Format --- src/helpers/Monitor.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 5b01d651..708a5cc8 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -192,10 +192,6 @@ void CMonitor::onConnect(bool noRule) { if (!activeMonitorRule.mirrorOf.empty()) setMirror(activeMonitorRule.mirrorOf); - g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); - EMIT_HOOK_EVENT("monitorAdded", this); - if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet g_pCompositor->setActiveMonitor(this); @@ -224,6 +220,10 @@ void CMonitor::onConnect(bool noRule) { PROTO::gamma->applyGammaToState(this); events.connect.emit(); + + g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); + g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); + EMIT_HOOK_EVENT("monitorAdded", this); } void CMonitor::onDisconnect(bool destroy) { @@ -281,9 +281,6 @@ void CMonitor::onDisconnect(bool destroy) { Debug::log(LOG, "Removed monitor {}!", szName); - g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); - EMIT_HOOK_EVENT("monitorRemoved", this); - if (!BACKUPMON) { Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend."); g_pCompositor->enterUnsafeState(); @@ -342,6 +339,9 @@ void CMonitor::onDisconnect(bool destroy) { g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; } std::erase_if(g_pCompositor->m_vMonitors, [&](SP& el) { return el.get() == this; }); + + g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); + EMIT_HOOK_EVENT("monitorRemoved", this); } void CMonitor::addDamage(const pixman_region32_t* rg) { From e72ae6b25fe019404df31e783ae980f80d3eaa3c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 17 Sep 2024 11:24:54 +0100 Subject: [PATCH 173/298] hyprctl: allow parsing empty value fixes #7821 --- src/debug/HyprCtl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 683665be..3d4d8092 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -987,9 +987,9 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { const auto COMMAND = in.substr(0, secondSpacePos); const auto VALUE = in.substr(secondSpacePos + 1); - // If either COMMAND or VALUE is empty, handle accordingly - if (COMMAND.empty() || VALUE.empty()) - return "Invalid input: command or value is empty"; + // If COMMAND is empty, handle accordingly + if (COMMAND.empty()) + return "Invalid input: command is empty"; std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE); From 581f6659f8541476da82ebd819a564780b3a969e Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 17 Sep 2024 12:55:48 +0100 Subject: [PATCH 174/298] data-device: conform to reported source actions fixes #7815 --- src/protocols/core/DataDevice.cpp | 21 ++++++++++++++++++--- src/protocols/core/DataDevice.hpp | 3 ++- src/protocols/types/DataDevice.cpp | 4 ++++ src/protocols/types/DataDevice.hpp | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index eac80a83..5644f243 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -82,8 +82,19 @@ void CWLDataOfferResource::sendData() { if (!source) return; - if (resource->version() >= 3) - resource->sendSourceActions(7); + const auto SOURCEACTIONS = source->actions(); + + if (resource->version() >= 3 && SOURCEACTIONS > 0) { + resource->sendSourceActions(SOURCEACTIONS); + if (SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + else if (SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); + else { + LOGM(ERR, "Client bug? dnd source has no action move or copy. Sending move, f this."); + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + } + } for (auto const& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); @@ -111,7 +122,7 @@ CWLDataSourceResource::CWLDataSourceResource(SP resource_, SPsetOffer([this](CWlDataSource* r, const char* mime) { mimeTypes.push_back(mime); }); resource->setSetActions([this](CWlDataSource* r, uint32_t a) { LOGM(LOG, "DataSource {:x} actions {}", (uintptr_t)this, a); - actions = (wl_data_device_manager_dnd_action)a; + supportedActions = a; }); } @@ -193,6 +204,10 @@ void CWLDataSourceResource::sendDndAction(wl_data_device_manager_dnd_action a) { resource->sendAction(a); } +uint32_t CWLDataSourceResource::actions() { + return supportedActions; +} + CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 8aaf46be..50e9ac61 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -65,6 +65,7 @@ class CWLDataSourceResource : public IDataSource { virtual bool dndDone(); virtual void error(uint32_t code, const std::string& msg); virtual void sendDndFinished(); + virtual uint32_t actions(); // wl_data_device_manager.dnd_action void sendDndDropPerformed(); void sendDndAction(wl_data_device_manager_dnd_action a); @@ -78,7 +79,7 @@ class CWLDataSourceResource : public IDataSource { WP self; std::vector mimeTypes; - uint32_t actions = 0; + uint32_t supportedActions = 0; private: SP resource; diff --git a/src/protocols/types/DataDevice.cpp b/src/protocols/types/DataDevice.cpp index e95f1c76..36a7a157 100644 --- a/src/protocols/types/DataDevice.cpp +++ b/src/protocols/types/DataDevice.cpp @@ -23,3 +23,7 @@ eDataSourceType IDataSource::type() { void IDataSource::sendDndFinished() { ; } + +uint32_t IDataSource::actions() { + return 7; // all +} diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index f6757e1c..a62cc35e 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -26,6 +26,7 @@ class IDataSource { virtual void markUsed(); virtual void error(uint32_t code, const std::string& msg) = 0; virtual eDataSourceType type(); + virtual uint32_t actions(); // wl_data_device_manager.dnd_action struct { CSignal destroy; From 3c9716acfd00c6ea1b7bcd1dc63f97b51cc09998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:37:20 +0100 Subject: [PATCH 175/298] gammactrl: fix potential crash on monitor removed (#7828) --- src/protocols/GammaControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index d7992981..077d6e2f 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -19,7 +19,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out pMonitor = OUTPUTRES->monitor; - if (!pMonitor) { + if (!pMonitor || !pMonitor->output) { LOGM(ERR, "No CMonitor"); resource->sendFailed(); return; From 0564b46a5e9afbf2fb51a7198452342e43ba4637 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 18 Sep 2024 12:05:17 +0200 Subject: [PATCH 176/298] dispatchers: allow moveintogroup when floating (#7818) This allows to use the moveintogroup dispatcher when windows are floating. I don't know why was this disabled in the first place though. Cheers! --- src/managers/KeybindManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2f593d74..dd35bc19 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2730,7 +2730,7 @@ SDispatchResult CKeybindManager::moveIntoGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny) + if (!PWINDOW || PWINDOW->m_sGroupData.deny) return {}; auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); From 883d01084c52fdc5da0e6bfff7fd0f5cf0f62352 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 18 Sep 2024 11:22:07 +0100 Subject: [PATCH 177/298] userchecks: add an xdg_current_desktop check ref https://github.com/hyprwm/xdg-desktop-portal-hyprland/issues/251 if the XDG_CURRENT_DESKTOP is externally managed (e.g. DE, DM, etc) Hyprland will not overwrite it. In those cases, if that's undesired, portals and other apps depending on it might break. --- src/Compositor.cpp | 12 +++++++++++- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 8e1b11b0..232ba4a6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2696,7 +2696,17 @@ WORKSPACEID CCompositor::getNewSpecialID() { } void CCompositor::performUserChecks() { - ; // intentional + static auto PNOCHECKXDG = CConfigValue("misc:disable_xdg_env_checks"); + + if (!*PNOCHECKXDG) { + const auto CURRENT_DESKTOP_ENV = getenv("XDG_CURRENT_DESKTOP"); + if (!CURRENT_DESKTOP_ENV || std::string{CURRENT_DESKTOP_ENV} != "Hyprland") { + g_pHyprNotificationOverlay->addNotification( + std::format("Your XDG_CURRENT_DESKTOP environment seems to be managed externally, and the current value is {}.\nThis might cause issues unless it's intentional.", + CURRENT_DESKTOP_ENV ? CURRENT_DESKTOP_ENV : "unset"), + CColor{}, 15000, ICON_WARNING); + } + } } void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) { diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 44b5ee4a..84ac1a41 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1049,6 +1049,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{15, 1, 120}, }, + SConfigOptionDescription{ + .value = "misc:disable_xdg_env_checks", + .description = "disable the warning if XDG environment is externally managed", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * binds: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 57cd2350..27e8fdb0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -371,6 +371,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15}); + m_pConfig->addConfigValue("misc:disable_xdg_env_checks", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); From d936eb437b5d33cda21e1502a96dc7d83446aca5 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 18 Sep 2024 17:26:51 +0300 Subject: [PATCH 178/298] flake.lock: update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 55dc6939..35974921 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1725753098, - "narHash": "sha256-/NO/h/qD/eJXAQr/fHA4mdDgYsNT9thHQ+oT6KPi2ac=", + "lastModified": 1726665257, + "narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "e4a13203112a036fc7f437d391c7810f3dd5ab52", + "rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e", "type": "github" }, "original": { From 6b6554adb8c2fba5d89554af6fc467dcd15cedc0 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 14 Sep 2024 00:06:43 +0300 Subject: [PATCH 179/298] flake.nix: inherit stdenv from package Means we no longer have to change the base stdenv in two places. --- flake.nix | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 9e1e3ab4..ef914627 100644 --- a/flake.nix +++ b/flake.nix @@ -95,13 +95,9 @@ devShells = eachSystem (system: { default = pkgsFor.${system}.mkShell.override { - stdenv = pkgsFor.${system}.gcc14Stdenv; + inherit (self.packages.${system}.default) stdenv; } { name = "hyprland-shell"; - nativeBuildInputs = with pkgsFor.${system}; [ - expat - libxml2 - ]; hardeningDisable = ["fortify"]; inputsFrom = [pkgsFor.${system}.hyprland]; packages = [pkgsFor.${system}.clang-tools]; From cbc0ff6ec0670e904758069c3844b05086bb15d3 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 18 Sep 2024 18:54:00 +0300 Subject: [PATCH 180/298] Nix: disable PCH --- nix/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/default.nix b/nix/default.nix index 8d912fe6..b167a4df 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -149,6 +149,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.mesonEnable "xwayland" enableXWayland) (lib.mesonEnable "legacy_renderer" legacyRenderer) (lib.mesonEnable "systemd" withSystemd) + (lib.mesonEnable "b_pch" false) ]; postInstall = '' From b248d59713d99a8338d25f4765fd2f564069f98b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 18 Sep 2024 19:43:56 +0300 Subject: [PATCH 181/298] Nix: fix meson PCH flag --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index b167a4df..11e18e6c 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -149,7 +149,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.mesonEnable "xwayland" enableXWayland) (lib.mesonEnable "legacy_renderer" legacyRenderer) (lib.mesonEnable "systemd" withSystemd) - (lib.mesonEnable "b_pch" false) + "-Db_pch=false" ]; postInstall = '' From 94140e886ea8c4ac34478d290c212f0f5454ab2e Mon Sep 17 00:00:00 2001 From: Jasson Date: Wed, 18 Sep 2024 13:12:26 -0400 Subject: [PATCH 182/298] xwayland: Some readability improvements (#7807) * Readability improvements xwayland server * Made requested changes * removed braces * fix * Ok this time is fixed * Formatting --- src/xwayland/Server.cpp | 194 ++++++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 89 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index f3bf5768..97caf9e3 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -1,105 +1,115 @@ +#include #ifndef NO_XWAYLAND -#include "Server.hpp" -#include "../defines.hpp" -#include "../Compositor.hpp" -#include "../managers/CursorManager.hpp" -#include "XWayland.hpp" - +#include +#include #include #include +#include +#include #include #include #include -#include #include -#include -#include -#include #include #include +#include #include -#include +#include +#include +#include -// TODO: cleanup -static bool set_cloexec(int fd, bool cloexec) { +#include "Server.hpp" +#include "XWayland.hpp" +#include "debug/Log.hpp" +#include "../defines.hpp" +#include "../Compositor.hpp" +#include "../managers/CursorManager.hpp" + +// Constants +constexpr int SOCKET_DIR_PERMISSIONS = 0755; +constexpr int SOCKET_BACKLOG = 1; +constexpr int MAX_SOCKET_RETRIES = 32; +constexpr int LOCK_FILE_MODE = 044; + +static bool setCloseOnExec(int fd, bool cloexec) { int flags = fcntl(fd, F_GETFD); if (flags == -1) { Debug::log(ERR, "fcntl failed"); return false; } - if (cloexec) { + + if (cloexec) flags = flags | FD_CLOEXEC; - } else { + else flags = flags & ~FD_CLOEXEC; - } + if (fcntl(fd, F_SETFD, flags) == -1) { Debug::log(ERR, "fcntl failed"); return false; } + return true; } -static int openSocket(struct sockaddr_un* addr, size_t path_size) { - int fd, rc; - socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; +void cleanUpSocket(int fd, const char* path) { + close(fd); + if (path[0]) + unlink(path); +} - fd = socket(AF_UNIX, SOCK_STREAM, 0); +static int createSocket(struct sockaddr_un* addr, size_t path_size) { + socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; + int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { - Debug::log(ERR, "failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); return -1; } - if (!set_cloexec(fd, true)) { + + if (!setCloseOnExec(fd, true)) { close(fd); return -1; } - if (addr->sun_path[0]) { + if (addr->sun_path[0]) unlink(addr->sun_path); - } + if (bind(fd, (struct sockaddr*)addr, size) < 0) { - rc = errno; - Debug::log(ERR, "failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - goto cleanup; + Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + cleanUpSocket(fd, addr->sun_path); + return -1; } - if (listen(fd, 1) < 0) { - rc = errno; - Debug::log(ERR, "failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - goto cleanup; + + if (listen(fd, SOCKET_BACKLOG) < 0) { + Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + cleanUpSocket(fd, addr->sun_path); + return -1; } return fd; - -cleanup: - close(fd); - if (addr->sun_path[0]) { - unlink(addr->sun_path); - } - errno = rc; - return -1; } static bool checkPermissionsForSocketDir(void) { struct stat buf; if (lstat("/tmp/.X11-unix", &buf)) { - Debug::log(ERR, "Failed statting X11 socket dir"); + Debug::log(ERR, "Failed to stat X11 socket dir"); return false; } if (!(buf.st_mode & S_IFDIR)) { - Debug::log(ERR, "X11 socket dir is not a dir"); + Debug::log(ERR, "X11 socket dir is not a directory"); return false; } if (!((buf.st_uid == 0) || (buf.st_uid == getuid()))) { - Debug::log(ERR, "X11 socket dir is not ours"); + Debug::log(ERR, "X11 socket dir is not owned by root or current user"); return false; } if (!(buf.st_mode & S_ISVTX)) { if ((buf.st_mode & (S_IWGRP | S_IWOTH))) { - Debug::log(ERR, "X11 socket dir is sticky by others"); + Debug::log(ERR, "X11 socket dir is writable by others"); return false; } } @@ -107,38 +117,51 @@ static bool checkPermissionsForSocketDir(void) { return true; } -static bool openSockets(std::array& sockets, int display) { - auto ret = mkdir("/tmp/.X11-unix", 755); - - if (ret != 0) { - if (errno == EEXIST) { - if (!checkPermissionsForSocketDir()) - return false; - } else { - Debug::log(ERR, "XWayland: couldn't create socket dir"); +static bool ensureSocketDirExists() { + if (mkdir("/tmp/.X11-unix", SOCKET_DIR_PERMISSIONS) != 0) { + if (errno == EEXIST) + return checkPermissionsForSocketDir(); + else { + Debug::log(ERR, "XWayland: Couldn't create socket dir"); return false; } } - std::string path; + return true; +} + +static std::string getSocketPath(int display, bool isLinux) { + if (isLinux) + return std::format("/tmp/.X11-unix{}", display); + + return std::format("/tmp/.X11-unix{}_", display); +} + +static bool openSockets(std::array& sockets, int display) { + if (!ensureSocketDirExists()) + return false; + sockaddr_un addr = {.sun_family = AF_UNIX}; + std::string path; #ifdef __linux__ // cursed... addr.sun_path[0] = 0; - path = std::format("/tmp/.X11-unix/X{}", display); + path = getSocketPath(display, true); strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1); #else - path = std::format("/tmp/.X11-unix/X{}_", display); + path = getSocketPath(display, false); strncpy(addr.sun_path, path.c_str(), path.length() + 1); #endif - sockets[0] = openSocket(&addr, path.length()); + + sockets[0] = createSocket(&addr, path.length()); if (sockets[0] < 0) return false; - path = std::format("/tmp/.X11-unix/X{}", display); + path = getSocketPath(display, true); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[1] = openSocket(&addr, path.length()); + + sockets[1] = createSocket(&addr, path.length()); if (sockets[1] < 0) { close(sockets[0]); sockets[0] = -1; @@ -160,39 +183,37 @@ static int xwaylandReady(int fd, uint32_t mask, void* data) { static bool safeRemove(const std::string& path) { try { return std::filesystem::remove(path); - } catch (std::exception& e) { Debug::log(ERR, "[XWayland] failed to remove {}", path); } - + } catch (const std::exception& e) { Debug::log(ERR, "[XWayland] Failed to remove {}", path); } return false; } bool CXWaylandServer::tryOpenSockets() { - for (size_t i = 0; i <= 32; ++i) { - auto LOCK = std::format("/tmp/.X{}-lock", i); + for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) { + std::string lockPath = std::format("/tmp/.X{}-lock", i); - if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) { + int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE); + if (fd >= 0) { // we managed to open the lock if (!openSockets(xFDs, i)) { - safeRemove(LOCK); + safeRemove(lockPath); close(fd); continue; } - const auto PIDSTR = std::format("{}", getpid()); - - if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) { - safeRemove(LOCK); + const std::string pidStr = std::to_string(getpid()); + if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { + safeRemove(lockPath); close(fd); continue; } close(fd); - display = i; displayName = std::format(":{}", display); break; } - int fd = open(LOCK.c_str(), O_RDONLY | O_CLOEXEC); + fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC); if (fd < 0) continue; @@ -201,21 +222,20 @@ bool CXWaylandServer::tryOpenSockets() { read(fd, pidstr, sizeof(pidstr) - 1); close(fd); - uint64_t pid = 0; + int32_t pid = 0; try { pid = std::stoi(std::string{pidstr, 11}); } catch (...) { continue; } if (kill(pid, 0) != 0 && errno == ESRCH) { - if (!safeRemove(LOCK)) + if (!safeRemove(lockPath)) continue; - i--; } } if (display < 0) { - Debug::log(ERR, "Failed to find a suitable socket for xwayland"); + Debug::log(ERR, "Failed to find a suitable socket for XWayland"); return false; } @@ -232,19 +252,17 @@ CXWaylandServer::~CXWaylandServer() { if (display < 0) return; - if (xFDs[0]) - close(xFDs[0]); - if (xFDs[1]) - close(xFDs[1]); + close(xFDs[0]); + close(xFDs[1]); - auto LOCK = std::format("/tmp/.X{}-lock", display); - safeRemove(LOCK); + std::string lockPath = std::format("/tmp/.X{}-lock", display); + safeRemove(lockPath); std::string path; #ifdef __linux__ - path = std::format("/tmp/.X11-unix/X{}", display); + path = getSocketPath(display, true); #else - path = std::format("/tmp/.X11-unix/X{}_", display); + path = getSocketPath(display, false); #endif safeRemove(path); } @@ -256,7 +274,6 @@ void CXWaylandServer::die() { if (xFDReadEvents[0]) { wl_event_source_remove(xFDReadEvents[0]); wl_event_source_remove(xFDReadEvents[1]); - xFDReadEvents = {nullptr, nullptr}; } @@ -298,7 +315,7 @@ bool CXWaylandServer::create() { } void CXWaylandServer::runXWayland(int notifyFD) { - if (!set_cloexec(xFDs[0], false) || !set_cloexec(xFDs[1], false) || !set_cloexec(waylandFDs[1], false) || !set_cloexec(xwmFDs[1], false)) { + if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) { Debug::log(ERR, "Failed to unset cloexec on fds"); _exit(EXIT_FAILURE); } @@ -325,7 +342,7 @@ bool CXWaylandServer::start() { return false; } - if (!set_cloexec(waylandFDs[0], true) || !set_cloexec(waylandFDs[1], true)) { + if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) { Debug::log(ERR, "set_cloexec failed (1)"); die(); return false; @@ -337,7 +354,7 @@ bool CXWaylandServer::start() { return false; } - if (!set_cloexec(xwmFDs[0], true) || !set_cloexec(xwmFDs[1], true)) { + if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) { Debug::log(ERR, "set_cloexec failed (2)"); die(); return false; @@ -359,7 +376,7 @@ bool CXWaylandServer::start() { return false; } - if (!set_cloexec(notify[0], true)) { + if (!setCloseOnExec(notify[0], true)) { Debug::log(ERR, "set_cloexec failed (3)"); close(notify[0]); close(notify[1]); @@ -382,9 +399,8 @@ bool CXWaylandServer::start() { if (pid < 0) { Debug::log(ERR, "second fork failed"); _exit(1); - } else if (pid == 0) { + } else if (pid == 0) runXWayland(notify[1]); - } _exit(0); } From e6cf643f5ab1c1545fb858ab1fd9d7538ef9e0f3 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:47:53 +0100 Subject: [PATCH 183/298] pointermgr: Hide hardware cursor on leave (#7806) --- src/managers/PointerManager.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 5a192e13..3dcee431 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -208,9 +208,8 @@ void CPointerManager::recheckEnteredOutputs() { // if we are using hw cursors, prevent // the cursor from being stuck at the last point. - // if we are leaving it, move it to narnia. if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) - s->monitor->output->moveCursor({-1337, -420}); + setHWCursorBuffer(s, nullptr); if (!currentCursorImage.surface) continue; @@ -269,6 +268,8 @@ void CPointerManager::resetCursorImage(bool apply) { void CPointerManager::updateCursorBackend() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + const auto CURSORBOX = getCursorBoxGlobal(); + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); @@ -277,6 +278,15 @@ void CPointerManager::updateCursorBackend() { continue; } + auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty(); + + if (!CROSSES) { + if (state->cursorFrontBuffer) + setHWCursorBuffer(state, nullptr); + + continue; + } + if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); @@ -297,17 +307,34 @@ void CPointerManager::onCursorMoved() { if (!hasCursor()) return; + const auto CURSORBOX = getCursorBoxGlobal(); + bool recalc = false; + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); + auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty(); + + if (!CROSSES && state->cursorFrontBuffer) { + Debug::log(TRACE, "onCursorMoved for output {}: cursor left the viewport, removing it from the backend", m->szName); + setHWCursorBuffer(state, nullptr); + continue; + } else if (CROSSES && !state->cursorFrontBuffer) { + Debug::log(TRACE, "onCursorMoved for output {}: cursor entered the output, but no front buffer, forcing recalc", m->szName); + recalc = true; + } + if (state->hardwareFailed || !state->entered) continue; const auto CURSORPOS = getCursorPosForMonitor(m); m->output->moveCursor(CURSORPOS); } + + if (recalc) + updateCursorBackend(); } bool CPointerManager::attemptHardwareCursor(SP state) { From 1bc05b1f9fd55f2a7371082e6914622e4584ed54 Mon Sep 17 00:00:00 2001 From: Arisa Snowbell Date: Thu, 19 Sep 2024 12:08:02 +0200 Subject: [PATCH 184/298] xwayland: use proper path for the XWayland sockets (#7852) fixes #7849 --- src/xwayland/Server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 97caf9e3..5ad9ff23 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -132,9 +132,9 @@ static bool ensureSocketDirExists() { static std::string getSocketPath(int display, bool isLinux) { if (isLinux) - return std::format("/tmp/.X11-unix{}", display); + return std::format("/tmp/.X11-unix/X{}", display); - return std::format("/tmp/.X11-unix{}_", display); + return std::format("/tmp/.X11-unix/X{}_", display); } static bool openSockets(std::array& sockets, int display) { From 71963972bff15acccd9abd0dfd3e70504609b7cc Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 19 Sep 2024 11:25:58 +0100 Subject: [PATCH 185/298] args: add --version to binary args --- src/main.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 820a248c..525ad4ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,9 @@ #include "config/ConfigManager.hpp" #include "init/initHelpers.hpp" +#include +using namespace Hyprutils::String; + #include #include #include @@ -20,6 +23,7 @@ void help() { std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; + std::cout << " --version -v - Print this binary's version\n"; } int main(int argc, char** argv) { @@ -109,6 +113,24 @@ int main(int argc, char** argv) { } else if (it->compare("-h") == 0 || it->compare("--help") == 0) { help(); + return 0; + } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { + auto commitMsg = trim(GIT_COMMIT_MESSAGE); + std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); + std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + + ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n"; + +#ifdef LEGACY_RENDERER + result += "legacyrenderer\n"; +#endif +#ifndef ISDEBUG + result += "debug\n"; +#endif +#ifdef NO_XWAYLAND + result += "no xwayland\n"; +#endif + + std::cout << result; return 0; } else { std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; From 92df6b0dce1b81b130c2b0e46d206c8c3dbb2971 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 19 Sep 2024 11:39:54 +0100 Subject: [PATCH 186/298] version: log build aquamarine version log the built against aq version, might be useful when it's mismatched to identify the problem --- CMakeLists.txt | 7 +++++-- src/debug/HyprCtl.cpp | 7 +++++-- src/main.cpp | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fdf98db..b6ac8efc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,11 +91,14 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) +pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine) + +add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") + pkg_check_modules( deps REQUIRED IMPORTED_TARGET - aquamarine xkbcommon uuid wayland-server @@ -220,7 +223,7 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") -target_link_libraries(Hyprland rt PkgConfig::deps) +target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps) # used by `make installheaders`, to ensure the headers are generated add_custom_target(generate-protocol-headers) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 3d4d8092..9faefe26 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -858,7 +858,8 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n"; + ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + + "\n\nflags: (if any)\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; @@ -881,8 +882,10 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { "commit_date": "{}", "tag": "{}", "commits": "{}", + "buildAquamarine": "{}", "flags": [)#", - GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS); + GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, + AQUAMARINE_VERSION); #ifdef LEGACY_RENDERER result += "\"legacyrenderer\","; diff --git a/src/main.cpp b/src/main.cpp index 525ad4ff..ba6fe505 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,7 +118,8 @@ int main(int argc, char** argv) { auto commitMsg = trim(GIT_COMMIT_MESSAGE); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n"; + ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + + "\n\nflags: (if any)\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; From dfa1bd0cd48253a446fbe455a46f0f4d23368c02 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 19 Sep 2024 13:48:31 +0000 Subject: [PATCH 187/298] Meson: pass AQUAMARINE_VERSION argument --- meson.build | 3 +++ src/meson.build | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 123c31ae..9449c241 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,9 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif +aquamarine = dependency('aquamarine') +add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') + xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) diff --git a/src/meson.build b/src/meson.build index 3821bd60..928cd5a7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,7 +8,7 @@ executable( cpp_pch: 'pch/pch.hpp', dependencies: [ server_protos, - dependency('aquamarine'), + aquamarine, dependency('gbm'), dependency('xcursor'), dependency('wayland-server'), From 9856378384539e35cd943604e6a4d696a9d25447 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 19 Sep 2024 18:53:34 +0300 Subject: [PATCH 188/298] Nix: use mold linker --- nix/default.nix | 237 +++++++++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 115 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 11e18e6c..3d621db6 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -1,6 +1,7 @@ { lib, stdenv, + stdenvAdapters, pkg-config, pkgconf, makeWrapper, @@ -46,130 +47,136 @@ enableNvidiaPatches ? false, nvidiaPatches ? false, hidpiXWayland ? false, -}: -assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; -assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; -assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; - stdenv.mkDerivation { - pname = "hyprland${lib.optionalString debug "-debug"}"; - inherit version; +}: let + adapters = lib.flatten [ + stdenvAdapters.useMoldLinker + ]; - src = lib.cleanSourceWith { - filter = name: type: let - baseName = baseNameOf (toString name); - in - ! (lib.hasSuffix ".nix" baseName); - src = lib.cleanSource ../.; - }; + customStdenv = builtins.foldl' (acc: adapter: adapter acc) stdenv adapters; +in + assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; + assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; + assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; + customStdenv.mkDerivation { + pname = "hyprland${lib.optionalString debug "-debug"}"; + inherit version; - postPatch = '' - # Fix hardcoded paths to /usr installation - sed -i "s#/usr#$out#" src/render/OpenGL.cpp + src = lib.cleanSourceWith { + filter = name: type: let + baseName = baseNameOf (toString name); + in + ! (lib.hasSuffix ".nix" baseName); + src = lib.cleanSource ../.; + }; - # Remove extra @PREFIX@ to fix pkg-config paths - sed -i "s#@PREFIX@/##g" hyprland.pc.in - ''; + postPatch = '' + # Fix hardcoded paths to /usr installation + sed -i "s#/usr#$out#" src/render/OpenGL.cpp - COMMITS = revCount; - DATE = date; - DIRTY = lib.optionalString (commit == "") "dirty"; - HASH = commit; + # Remove extra @PREFIX@ to fix pkg-config paths + sed -i "s#@PREFIX@/##g" hyprland.pc.in + ''; - depsBuildBuild = [ - pkg-config - ]; + COMMITS = revCount; + DATE = date; + DIRTY = lib.optionalString (commit == "") "dirty"; + HASH = commit; - nativeBuildInputs = [ - hyprwayland-scanner - jq - makeWrapper - meson - cmake - ninja - pkg-config - python3 # for udis86 - wayland-scanner - ]; + depsBuildBuild = [ + pkg-config + ]; - outputs = [ - "out" - "man" - "dev" - ]; + nativeBuildInputs = [ + hyprwayland-scanner + jq + makeWrapper + meson + cmake + ninja + pkg-config + python3 # for udis86 + wayland-scanner + ]; - buildInputs = lib.concatLists [ - [ - aquamarine - cairo - # expat - # fribidi - git - hyprcursor - hyprlang - hyprutils - # libdatrie - libdrm - libGL - libinput - # libselinux - # libsepol - # libthai - libuuid - libxkbcommon - mesa - pango - pciutils - # pcre2 - tomlplusplus - wayland - wayland-protocols - xorg.libXcursor - ] - (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) - (lib.optionals enableXWayland [ - xorg.libxcb - xorg.libXdmcp - xorg.xcbutilerrors - xorg.xcbutilrenderutil - xorg.xcbutilwm - xwayland - ]) - (lib.optionals withSystemd [systemd]) - ]; + outputs = [ + "out" + "man" + "dev" + ]; - mesonBuildType = - if debug - then "debug" - else "release"; - - # we want as much debug info as possible - dontStrip = debug; - - mesonFlags = [ - (lib.mesonEnable "xwayland" enableXWayland) - (lib.mesonEnable "legacy_renderer" legacyRenderer) - (lib.mesonEnable "systemd" withSystemd) - "-Db_pch=false" - ]; - - postInstall = '' - ${lib.optionalString wrapRuntimeDeps '' - wrapProgram $out/bin/Hyprland \ - --suffix PATH : ${lib.makeBinPath [ - binutils + buildInputs = lib.concatLists [ + [ + aquamarine + cairo + # expat + # fribidi + git + hyprcursor + hyprlang + hyprutils + # libdatrie + libdrm + libGL + libinput + # libselinux + # libsepol + # libthai + libuuid + libxkbcommon + mesa + pango pciutils - pkgconf - ]} - ''} - ''; + # pcre2 + tomlplusplus + wayland + wayland-protocols + xorg.libXcursor + ] + (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) + (lib.optionals enableXWayland [ + xorg.libxcb + xorg.libXdmcp + xorg.xcbutilerrors + xorg.xcbutilrenderutil + xorg.xcbutilwm + xwayland + ]) + (lib.optionals withSystemd [systemd]) + ]; - passthru.providedSessions = ["hyprland"]; + mesonBuildType = + if debug + then "debug" + else "release"; - meta = { - homepage = "https://github.com/hyprwm/Hyprland"; - description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; - license = lib.licenses.bsd3; - platforms = lib.platforms.linux; - mainProgram = "Hyprland"; - }; - } + # we want as much debug info as possible + dontStrip = debug; + + mesonFlags = [ + (lib.mesonEnable "xwayland" enableXWayland) + (lib.mesonEnable "legacy_renderer" legacyRenderer) + (lib.mesonEnable "systemd" withSystemd) + "-Db_pch=false" + ]; + + postInstall = '' + ${lib.optionalString wrapRuntimeDeps '' + wrapProgram $out/bin/Hyprland \ + --suffix PATH : ${lib.makeBinPath [ + binutils + pciutils + pkgconf + ]} + ''} + ''; + + passthru.providedSessions = ["hyprland"]; + + meta = { + homepage = "https://github.com/hyprwm/Hyprland"; + description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; + license = lib.licenses.bsd3; + platforms = lib.platforms.linux; + mainProgram = "Hyprland"; + }; + } From 9e98fb0167f8bc6c5eb4510a65b42aaa3b743421 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 20 Sep 2024 10:47:34 +0100 Subject: [PATCH 189/298] dmabuffer: attempt importing failed dmabufs as implicit don't ask me why, vulkan doesn't like this. funny note, broken on wlroots :P fixes #7037 --- src/protocols/types/DMABuffer.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 63a26c76..a8c7248e 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -16,8 +16,15 @@ CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs auto eglImage = g_pHyprOpenGL->createEGLImage(attrs); - if (!eglImage) - return; + if (!eglImage) { + Debug::log(ERR, "CDMABuffer: failed to import EGLImage, retrying as implicit"); + attrs.modifier = DRM_FORMAT_MOD_INVALID; + eglImage = g_pHyprOpenGL->createEGLImage(attrs); + if (!eglImage) { + Debug::log(ERR, "CDMABuffer: failed to import EGLImage"); + return; + } + } texture = makeShared(attrs, eglImage); // texture takes ownership of the eglImage opaque = FormatUtils::isFormatOpaque(attrs.format); From 4414cd07e257a57362e73d1f6efe1df692ae3762 Mon Sep 17 00:00:00 2001 From: Jasson Date: Fri, 20 Sep 2024 07:32:04 -0400 Subject: [PATCH 190/298] xwm: Minor cleanup, add wrappers for basic types (#7856) --- src/xwayland/XDataSource.cpp | 2 +- src/xwayland/XSurface.cpp | 13 ++++---- src/xwayland/XWM.cpp | 37 +++++++++------------ src/xwayland/XWM.hpp | 62 ++++++++++++++++++++++++++++++------ 4 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index f4059ee1..c6495435 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -1,8 +1,8 @@ #ifndef NO_XWAYLAND -#include "XDataSource.hpp" #include "XWayland.hpp" #include "../defines.hpp" +#include "XDataSource.hpp" #include diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 02fe2b3b..e734c153 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -5,8 +5,8 @@ #ifndef NO_XWAYLAND -#include "../Compositor.hpp" #include +#include "../Compositor.hpp" CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) { xcb_res_query_client_ids_cookie_t client_id_cookie = {0}; @@ -196,12 +196,11 @@ void CXWaylandSurface::restackToTop() { xcb_configure_window(g_pXWayland->pWM->connection, xID, XCB_CONFIG_WINDOW_STACK_MODE, values); - for (auto it = g_pXWayland->pWM->mappedSurfacesStacking.begin(); it != g_pXWayland->pWM->mappedSurfacesStacking.end(); ++it) { - if (*it == self) { - std::rotate(it, it + 1, g_pXWayland->pWM->mappedSurfacesStacking.end()); - break; - } - } + auto& stack = g_pXWayland->pWM->mappedSurfacesStacking; + auto it = std::find(stack.begin(), stack.end(), self); + + if (it != stack.end()) + std::rotate(it, it + 1, stack.end()); g_pXWayland->pWM->updateClientList(); diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index e8e2258a..dcb22eae 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1,20 +1,21 @@ #include "helpers/math/Math.hpp" +#include #ifndef NO_XWAYLAND +#include +#include +#include +#include +#include +#include + #include "XWayland.hpp" #include "../defines.hpp" -#include #include "../Compositor.hpp" +#include "../protocols/core/Seat.hpp" +#include "../managers/SeatManager.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Compositor.hpp" -#include "../managers/SeatManager.hpp" -#include "../protocols/core/Seat.hpp" -#include -#include -#include -#include - -#include #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define INCR_CHUNK_SIZE (64 * 1024) @@ -830,15 +831,15 @@ void CXWM::getRenderFormat() { free(reply); } -CXWM::CXWM() { - connection = xcb_connect_to_fd(g_pXWayland->pServer->xwmFDs[0], nullptr); +CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { - if (int ret = xcb_connection_has_error(connection); ret) { - Debug::log(ERR, "[xwm] Couldn't start, error {}", ret); + if (connection.hasError()) { + Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError()); return; } - if (xcb_errors_context_new(connection, &errors)) { + CXCBErrorContext xcbErrCtx(connection); + if (!xcbErrCtx.isValid()) { Debug::log(ERR, "[xwm] Couldn't allocate errors context"); return; } @@ -867,10 +868,7 @@ CXWM::CXWM() { }; xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_SUPPORTED"], XCB_ATOM_ATOM, 32, sizeof(supported) / sizeof(*supported), supported); - xcb_flush(connection); - setActiveWindow(XCB_WINDOW_NONE); - initSelection(); listeners.newWLSurface = PROTO::compositor->events.newSurface.registerListener([this](std::any d) { onNewSurface(std::any_cast>(d)); }); @@ -882,11 +880,6 @@ CXWM::CXWM() { } CXWM::~CXWM() { - if (errors) - xcb_errors_context_free(errors); - - if (connection) - xcb_disconnect(connection); if (eventSource) wl_event_source_remove(eventSource); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 59695720..ba00dd8d 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -1,17 +1,16 @@ #pragma once -#include "../helpers/signal/Signal.hpp" -#include "../helpers/memory/Memory.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" - #include "XDataSource.hpp" +#include "../helpers/WLListener.hpp" +#include "../helpers/memory/Memory.hpp" +#include "../helpers/signal/Signal.hpp" #include -#include -#include -#include #include +#include +#include +#include struct wl_event_source; class CXWaylandSurfaceResource; @@ -58,6 +57,49 @@ struct SXSelection { std::unique_ptr transfer; }; +class CXCBConnection { + public: + CXCBConnection(int fd) { + connection = xcb_connect_to_fd(fd, nullptr); + } + + ~CXCBConnection() { + if (connection) + xcb_disconnect(connection); + } + + bool hasError() const { + return xcb_connection_has_error(connection); + } + + operator xcb_connection_t*() const { + return connection; + } + + private: + xcb_connection_t* connection = nullptr; +}; + +class CXCBErrorContext { + public: + explicit CXCBErrorContext(xcb_connection_t* connection) { + if (xcb_errors_context_new(connection, &errors) != 0) + errors = nullptr; + } + + ~CXCBErrorContext() { + if (errors) + xcb_errors_context_free(errors); + } + + bool isValid() const { + return errors != nullptr; + } + + private: + xcb_errors_context_t* errors = nullptr; +}; + class CXWM { public: CXWM(); @@ -123,9 +165,9 @@ class CXWM { void readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply); // - xcb_connection_t* connection = nullptr; - xcb_errors_context_t* errors = nullptr; - xcb_screen_t* screen = nullptr; + CXCBConnection connection; + xcb_errors_context_t* errors = nullptr; + xcb_screen_t* screen = nullptr; xcb_window_t wmWindow; From 278583b8a1ab66272a4c437ed1acd7936a6a5c36 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 20 Sep 2024 20:16:13 +0300 Subject: [PATCH 191/298] flake.lock: update --- flake.lock | 24 +++++++++++++++--------- flake.nix | 2 ++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 35974921..608c5bbb 100644 --- a/flake.lock +++ b/flake.lock @@ -139,11 +139,11 @@ ] }, "locked": { - "lastModified": 1721324119, - "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=", + "lastModified": 1726840673, + "narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30", + "rev": "b68dab23fc922eae99306988133ee80a40b39ca5", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725983898, - "narHash": "sha256-4b3A9zPpxAxLnkF9MawJNHDtOOl6ruL0r6Og1TEDGCE=", + "lastModified": 1726755586, + "narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1355a0cbfeac61d785b7183c0caaec1f97361b43", + "rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e", "type": "github" }, "original": { @@ -201,6 +201,12 @@ "hyprlang": [ "hyprlang" ], + "hyprutils": [ + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprwayland-scanner" + ], "nixpkgs": [ "nixpkgs" ], @@ -209,11 +215,11 @@ ] }, "locked": { - "lastModified": 1726046979, - "narHash": "sha256-6SEsjurq9cdTkITA6d49ncAJe4O/8CgRG5/F//s6Xh8=", + "lastModified": 1726851729, + "narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "e695669fd8e1d1be9eaae40f35e00f8bd8b64c18", + "rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index ef914627..ef48b2d1 100644 --- a/flake.nix +++ b/flake.nix @@ -46,6 +46,8 @@ inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; inputs.hyprlang.follows = "hyprlang"; + inputs.hyprutils.follows = "hyprutils"; + inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; }; }; From db0b764a5ac22e752d8557cc1e1e5a42ac58c7e4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 20 Sep 2024 22:56:10 +0100 Subject: [PATCH 192/298] shm: send a static list of shm formats fixes #7733 --- src/protocols/core/Shm.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index b09326bd..a8c98bb0 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -193,11 +193,8 @@ void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, ui DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, }; - for (auto const& fmt : g_pHyprOpenGL->getDRMFormats()) { - if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) - continue; - - shmFormats.push_back(fmt.drmFormat); + for (auto const& fmt : supportedShmFourccFormats) { + shmFormats.push_back(fmt); } } From 9232bc2c00a57b99ac876b43fdfedfa25c2de774 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 21 Sep 2024 00:33:48 +0100 Subject: [PATCH 193/298] internal: move to hyprutils' scopeguard bumps hyprutils dep to 0.2.2 --- CMakeLists.txt | 2 +- flake.lock | 6 +++--- src/helpers/Monitor.cpp | 3 ++- src/helpers/ScopeGuard.cpp | 10 ---------- src/helpers/ScopeGuard.hpp | 13 ------------- src/render/Renderer.cpp | 4 +++- 6 files changed, 9 insertions(+), 29 deletions(-) delete mode 100644 src/helpers/ScopeGuard.cpp delete mode 100644 src/helpers/ScopeGuard.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b6ac8efc..e1718b2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ pkg_check_modules( gio-2.0 hyprlang>=0.3.2 hyprcursor>=0.1.7 - hyprutils>=0.2.1) + hyprutils>=0.2.2) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/flake.lock b/flake.lock index 608c5bbb..024bcf50 100644 --- a/flake.lock +++ b/flake.lock @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1724966483, - "narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=", + "lastModified": 1726874949, + "narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2", + "rev": "d97af4f6bd068c03a518b597675e598f57ea2291", "type": "github" }, "original": { diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 708a5cc8..223a3f94 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -2,7 +2,6 @@ #include "MiscFunctions.hpp" #include "math/Math.hpp" #include "sync/SyncReleaser.hpp" -#include "ScopeGuard.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" @@ -17,7 +16,9 @@ #include "sync/SyncTimeline.hpp" #include #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::Utils; int ratHandler(void* data) { g_pHyprRenderer->renderMonitor((CMonitor*)data); diff --git a/src/helpers/ScopeGuard.cpp b/src/helpers/ScopeGuard.cpp deleted file mode 100644 index 319255cd..00000000 --- a/src/helpers/ScopeGuard.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "ScopeGuard.hpp" - -CScopeGuard::CScopeGuard(const std::function& fn_) : fn(fn_) { - ; -} - -CScopeGuard::~CScopeGuard() { - if (fn) - fn(); -} diff --git a/src/helpers/ScopeGuard.hpp b/src/helpers/ScopeGuard.hpp deleted file mode 100644 index 8a1468eb..00000000 --- a/src/helpers/ScopeGuard.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -// calls a function when it goes out of scope -class CScopeGuard { - public: - CScopeGuard(const std::function& fn_); - ~CScopeGuard(); - - private: - std::function fn; -}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 08bf76cb..417a3ff8 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,7 +1,6 @@ #include "Renderer.hpp" #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" -#include "../helpers/ScopeGuard.hpp" #include "../helpers/sync/SyncReleaser.hpp" #include #include @@ -23,6 +22,9 @@ #include "../helpers/sync/SyncTimeline.hpp" #include "debug/Log.hpp" +#include +using namespace Hyprutils::Utils; + extern "C" { #include } From 8579066c7a1ceb745499ea4e11d5d420b1387ec0 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 21 Sep 2024 14:27:13 +0300 Subject: [PATCH 194/298] Nix: clean up derivation --- nix/default.nix | 58 +++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 3d621db6..40675d9a 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -48,25 +48,32 @@ nvidiaPatches ? false, hidpiXWayland ? false, }: let - adapters = lib.flatten [ + inherit (builtins) baseNameOf foldl'; + inherit (lib.asserts) assertMsg; + inherit (lib.attrsets) mapAttrsToList; + inherit (lib.lists) flatten concatLists optional optionals; + inherit (lib.sources) cleanSourceWith cleanSource; + inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable; + + adapters = flatten [ stdenvAdapters.useMoldLinker ]; - customStdenv = builtins.foldl' (acc: adapter: adapter acc) stdenv adapters; + customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters; in - assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; - assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; - assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; + assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; + assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; + assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; customStdenv.mkDerivation { - pname = "hyprland${lib.optionalString debug "-debug"}"; + pname = "hyprland${optionalString debug "-debug"}"; inherit version; - src = lib.cleanSourceWith { + src = cleanSourceWith { filter = name: type: let baseName = baseNameOf (toString name); in - ! (lib.hasSuffix ".nix" baseName); - src = lib.cleanSource ../.; + ! (hasSuffix ".nix" baseName); + src = cleanSource ../.; }; postPatch = '' @@ -79,7 +86,7 @@ in COMMITS = revCount; DATE = date; - DIRTY = lib.optionalString (commit == "") "dirty"; + DIRTY = optionalString (commit == "") "dirty"; HASH = commit; depsBuildBuild = [ @@ -104,36 +111,29 @@ in "dev" ]; - buildInputs = lib.concatLists [ + buildInputs = concatLists [ [ aquamarine cairo - # expat - # fribidi git hyprcursor hyprlang hyprutils - # libdatrie libdrm libGL libinput - # libselinux - # libsepol - # libthai libuuid libxkbcommon mesa pango pciutils - # pcre2 tomlplusplus wayland wayland-protocols xorg.libXcursor ] - (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) - (lib.optionals enableXWayland [ + (optionals customStdenv.hostPlatform.isMusl [libexecinfo]) + (optionals enableXWayland [ xorg.libxcb xorg.libXdmcp xorg.xcbutilerrors @@ -141,7 +141,7 @@ in xorg.xcbutilwm xwayland ]) - (lib.optionals withSystemd [systemd]) + (optional withSystemd systemd) ]; mesonBuildType = @@ -152,17 +152,19 @@ in # we want as much debug info as possible dontStrip = debug; - mesonFlags = [ - (lib.mesonEnable "xwayland" enableXWayland) - (lib.mesonEnable "legacy_renderer" legacyRenderer) - (lib.mesonEnable "systemd" withSystemd) - "-Db_pch=false" + mesonFlags = flatten [ + (mapAttrsToList mesonEnable { + "xwayland" = enableXWayland; + "legacy_renderer" = legacyRenderer; + "systemd" = withSystemd; + }) + (mesonBool "b_pch" false) ]; postInstall = '' - ${lib.optionalString wrapRuntimeDeps '' + ${optionalString wrapRuntimeDeps '' wrapProgram $out/bin/Hyprland \ - --suffix PATH : ${lib.makeBinPath [ + --suffix PATH : ${makeBinPath [ binutils pciutils pkgconf From e5ff19ac0f2c8d53a0c847d06a17676e636d6447 Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 21 Sep 2024 16:52:11 +0200 Subject: [PATCH 195/298] flake: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 024bcf50..76351cc9 100644 --- a/flake.lock +++ b/flake.lock @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1726851729, - "narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=", + "lastModified": 1726933538, + "narHash": "sha256-xTqnMoJsEojuvqJLuM+U7EZ7q71efaj3pbvjutq4TXc=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf", + "rev": "4880c50146d0c2a3152d2b02f79253810c330c11", "type": "github" }, "original": { From 508bde1f61b1264c9621b937657088f09f318ce0 Mon Sep 17 00:00:00 2001 From: Artur Manuel Date: Mon, 23 Sep 2024 16:40:19 +0100 Subject: [PATCH 196/298] core: add HYPRLAND_CONFIG environment variable (#7851) --- src/config/ConfigManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 27e8fdb0..21a3a21e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -683,6 +683,10 @@ std::string CConfigManager::getMainConfigPath() { if (!g_pCompositor->explicitConfigPath.empty()) return g_pCompositor->explicitConfigPath; + if (const auto CFG_ENV = getenv("HYPRLAND_CONFIG"); CFG_ENV) + return CFG_ENV; + Debug::log(TRACE, "Seems as if HYPRLAND_CONFIG isn't set, let's see what we can do with HOME."); + static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland"); if (paths.first.has_value()) { return paths.first.value(); From f79497087bdea3ea2706606362ba99cfe7a956a0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 23 Sep 2024 17:59:35 +0100 Subject: [PATCH 197/298] internal: nuke wlsignal and related old semi-wrappers for wl_signal, they are no longer used --- src/defines.hpp | 1 - src/desktop/Subsurface.cpp | 8 +--- src/desktop/Subsurface.hpp | 4 -- src/devices/IKeyboard.hpp | 1 - src/devices/IPointer.hpp | 1 - src/devices/ITouch.hpp | 1 - src/devices/Tablet.hpp | 1 - src/helpers/WLListener.cpp | 62 ------------------------- src/helpers/WLListener.hpp | 39 ---------------- src/managers/SeatManager.hpp | 1 - src/managers/input/InputMethodPopup.hpp | 1 - src/managers/input/TextInput.hpp | 1 - src/protocols/FocusGrab.hpp | 3 -- src/protocols/PresentationTime.hpp | 2 - src/render/Renderbuffer.hpp | 1 - src/xwayland/XSurface.hpp | 1 - src/xwayland/XWM.hpp | 1 - 17 files changed, 1 insertion(+), 128 deletions(-) delete mode 100644 src/helpers/WLListener.cpp delete mode 100644 src/helpers/WLListener.hpp diff --git a/src/defines.hpp b/src/defines.hpp index 0b2c0e0c..41ee4502 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -1,6 +1,5 @@ #include "includes.hpp" #include "debug/Log.hpp" -#include "helpers/WLListener.hpp" #include "helpers/Color.hpp" #include "macros.hpp" #include "desktop/DesktopTypes.hpp" diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 64dd7cf5..893411bd 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -30,13 +30,7 @@ CSubsurface::CSubsurface(SP pSubsurface, CPopup* pOwner) } CSubsurface::~CSubsurface() { - hyprListener_newSubsurface.removeCallback(); - - if (!m_pSubsurface) - return; - - hyprListener_commitSubsurface.removeCallback(); - hyprListener_destroySubsurface.removeCallback(); + ; } void CSubsurface::initSignals() { diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index 101f4f19..7829c489 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -35,10 +35,6 @@ class CSubsurface { void recheckDamageForSubsurfaces(); private: - DYNLISTENER(destroySubsurface); - DYNLISTENER(commitSubsurface); - DYNLISTENER(newSubsurface); - struct { CHyprSignalListener destroySubsurface; CHyprSignalListener commitSubsurface; diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index ad8eaf7e..759b2f58 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index 760ec8dc..f38ef55a 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index cb8a6e90..bf969b2f 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index 0efbe796..01901721 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/helpers/WLListener.cpp b/src/helpers/WLListener.cpp deleted file mode 100644 index 2ea5c0b6..00000000 --- a/src/helpers/WLListener.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "WLListener.hpp" -#include "MiscFunctions.hpp" -#include -#include "../debug/Log.hpp" -#include "Watchdog.hpp" - -void handleWrapped(wl_listener* listener, void* data) { - CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener); - - if (g_pWatchdog) - g_pWatchdog->startWatching(); - - try { - pWrap->m_pSelf->emit(data); - } catch (std::exception& e) { Debug::log(ERR, "Listener {} threw or timed out and was killed by Watchdog!!! This is bad. what(): {}", (uintptr_t)listener, e.what()); } - - if (g_pWatchdog) - g_pWatchdog->endWatching(); -} - -CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function const& callback, void* pOwner) { - initCallback(pSignal, callback, pOwner); -} - -CHyprWLListener::CHyprWLListener() { - m_swWrapper.m_pSelf = this; - m_swWrapper.m_sListener.notify = &handleWrapped; - wl_list_init(&m_swWrapper.m_sListener.link); -} - -CHyprWLListener::~CHyprWLListener() { - removeCallback(); -} - -void CHyprWLListener::removeCallback() { - if (isConnected()) { - Debug::log(LOG, "Callback {:x} -> {:x}, {} removed.", (uintptr_t)&m_pCallback, (uintptr_t)&m_pOwner, m_szAuthor); - wl_list_remove(&m_swWrapper.m_sListener.link); - wl_list_init(&m_swWrapper.m_sListener.link); - } -} - -bool CHyprWLListener::isConnected() { - return !wl_list_empty(&m_swWrapper.m_sListener.link); -} - -void CHyprWLListener::initCallback(wl_signal* pSignal, std::function const& callback, void* pOwner, std::string author) { - if (isConnected()) { - Debug::log(ERR, "Tried to connect a listener twice?!"); - return; - } - - m_pOwner = pOwner; - m_pCallback = callback; - m_szAuthor = author; - - addWLSignal(pSignal, &m_swWrapper.m_sListener, pOwner, m_szAuthor); -} - -void CHyprWLListener::emit(void* data) { - m_pCallback(m_pOwner, data); -} diff --git a/src/helpers/WLListener.hpp b/src/helpers/WLListener.hpp deleted file mode 100644 index 621458e6..00000000 --- a/src/helpers/WLListener.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include - -class CHyprWLListener { - public: - CHyprWLListener(wl_signal*, std::function const&, void* owner); - CHyprWLListener(); - ~CHyprWLListener(); - - CHyprWLListener(const CHyprWLListener&) = delete; - CHyprWLListener(CHyprWLListener&&) = delete; - CHyprWLListener& operator=(const CHyprWLListener&) = delete; - CHyprWLListener& operator=(CHyprWLListener&&) = delete; - - void initCallback(wl_signal*, std::function const&, void* owner, std::string author = ""); - - void removeCallback(); - - bool isConnected(); - - struct SWrapper { - wl_listener m_sListener; - CHyprWLListener* m_pSelf; - }; - - void emit(void*); - - private: - SWrapper m_swWrapper; - - void* m_pOwner = nullptr; - - std::function m_pCallback = nullptr; - - std::string m_szAuthor = ""; -}; \ No newline at end of file diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 43ebe8b5..5cc7eee0 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -2,7 +2,6 @@ #include #include -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/signal/Signal.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index f8e4b962..53c11cff 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../../helpers/WLListener.hpp" #include "../../desktop/WLSurface.hpp" #include "../../macros.hpp" #include "../../helpers/math/Math.hpp" diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index f920adc7..3cf07006 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../../helpers/WLListener.hpp" #include "../../macros.hpp" #include "../../helpers/math/Math.hpp" #include "../../helpers/signal/Signal.hpp" diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index a2d545c5..6fe8780f 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -53,9 +53,6 @@ class CFocusGrab { bool m_bGrabActive = false; - DYNLISTENER(pointerGrabStarted); - DYNLISTENER(keyboardGrabStarted); - DYNLISTENER(touchGrabStarted); friend class CFocusGrabSurfaceState; }; diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index 06c71c9a..421bb838 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -27,8 +27,6 @@ class CQueuedPresentationData { WP pMonitor; WP surface; - DYNLISTENER(destroySurface); - friend class CPresentationFeedback; friend class CPresentationProtocol; }; diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index e6bfa909..ff06bd5a 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -2,7 +2,6 @@ #include "../helpers/signal/Signal.hpp" #include "../helpers/memory/Memory.hpp" -#include "../helpers/WLListener.hpp" #include "Framebuffer.hpp" #include diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 61eee984..7584354e 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../helpers/WLListener.hpp" #include "../helpers/signal/Signal.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index ba00dd8d..37c61416 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -2,7 +2,6 @@ #include "../macros.hpp" #include "XDataSource.hpp" -#include "../helpers/WLListener.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/signal/Signal.hpp" From 6c78b03bb7810e074d21d5c41f088bd317c28906 Mon Sep 17 00:00:00 2001 From: diniamo Date: Mon, 23 Sep 2024 18:52:30 +0200 Subject: [PATCH 198/298] flake: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 76351cc9..68bb0ed2 100644 --- a/flake.lock +++ b/flake.lock @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1726933538, - "narHash": "sha256-xTqnMoJsEojuvqJLuM+U7EZ7q71efaj3pbvjutq4TXc=", + "lastModified": 1727109343, + "narHash": "sha256-1PFckA8Im7wMSl26okwOKqBZeCFLD3LvZZFaxswDhbY=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "4880c50146d0c2a3152d2b02f79253810c330c11", + "rev": "4adb6c4c41ee5014bfe608123bfeddb26e5f5cea", "type": "github" }, "original": { From d279d7c4c6fe27c1944d8e9b51c4730612c8a9ae Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 24 Sep 2024 00:49:29 +0100 Subject: [PATCH 199/298] eventloop: dispatch pending in session on start fixes #7855 #7391 --- src/managers/eventLoop/EventLoopManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index e9b0fa3e..081268c3 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -50,6 +50,10 @@ void CEventLoopManager::enterLoop() { m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); } + // if we have a session, dispatch it to get the pending input devices + if (g_pCompositor->m_pAqBackend->hasSession()) + g_pCompositor->m_pAqBackend->session->dispatchPendingEventsAsync(); + wl_display_run(m_sWayland.display); Debug::log(LOG, "Kicked off the event loop! :("); From 0a211f29f5952322925b9f982cbf9b0326d45f0f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 24 Sep 2024 01:19:05 +0100 Subject: [PATCH 200/298] hyprctl: add defaultName to workspacerules fixes #7886 --- src/debug/HyprCtl.cpp | 67 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 9faefe26..4de9143d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -320,45 +320,48 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputFormat format) { const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; }; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { - const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor)); - const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : ""; - const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : ""; - const std::string gapsIn = (bool)(r.gapsIn) ? - std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) : + const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor)); + const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : ""; + const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : ""; + const std::string gapsIn = (bool)(r.gapsIn) ? + std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) : + ""; + const std::string gapsOut = (bool)(r.gapsOut) ? + std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) : ""; - const std::string gapsOut = (bool)(r.gapsOut) ? - std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) : - ""; - const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; - const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : ""; - const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : ""; - const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; - const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : ""; + const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; + const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : ""; + const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : ""; + const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; + const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : ""; + const std::string defaultName = r.defaultName.has_value() ? std::format(",\n \"defaultName\": \"{}\"", escapeJSONStrings(r.defaultName.value())) : ""; - std::string result = std::format(R"#({{ - "workspaceString": "{}"{}{}{}{}{}{}{}{} + std::string result = + std::format(R"#({{ + "workspaceString": "{}"{}{}{}{}{}{}{}{}{}{}{} }})#", - escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow); + escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow, defaultName); return result; } else { - const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "" : escapeJSONStrings(r.monitor)); - const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : ""); - const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : ""); - const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right), - std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) : - std::format("\tgapsIn: \n"); - const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right), - std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : - std::format("\tgapsOut: \n"); - const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : ""); - const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : ""); - const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : ""); - const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : ""); - const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : ""); + const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "" : escapeJSONStrings(r.monitor)); + const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : ""); + const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : ""); + const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right), + std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) : + std::format("\tgapsIn: \n"); + const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right), + std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : + std::format("\tgapsOut: \n"); + const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : ""); + const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : ""); + const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : ""); + const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : ""); + const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : ""); + const std::string defaultName = std::format("\tdefaultName: {}\n", r.defaultName.value_or("")); - std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, - borderSize, border, rounding, decorate, shadow); + std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, + borderSize, border, rounding, decorate, shadow, defaultName); return result; } From 00c862686354d139a53222d41a1c80d698a50c43 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 24 Sep 2024 11:25:05 +0100 Subject: [PATCH 201/298] hyprctl: add submap request fixes #7898 --- src/debug/HyprCtl.cpp | 9 +++++++++ src/managers/KeybindManager.cpp | 4 ++++ src/managers/KeybindManager.hpp | 1 + 3 files changed, 14 insertions(+) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 4de9143d..87e071d7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1627,6 +1627,14 @@ std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) { return json; } +std::string submapRequest(eHyprCtlOutputFormat format, std::string request) { + std::string submap = g_pKeybindManager->getCurrentSubmap(); + if (submap.empty()) + submap = "default"; + + return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n"); +} + CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); @@ -1648,6 +1656,7 @@ CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); + registerCommand(SHyprCtlCommand{"submap", true, submapRequest}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index dd35bc19..02e2f5e7 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -594,6 +594,10 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) { return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); } +std::string CKeybindManager::getCurrentSubmap() { + return m_szCurrentSelectedSubmap; +} + SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); bool found = false; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 096cd4f9..c81ca86f 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -96,6 +96,7 @@ class CKeybindManager { uint32_t keycodeToModifier(xkb_keycode_t); void clearKeybinds(); void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); + std::string getCurrentSubmap(); std::unordered_map> m_mDispatchers; From 8f5188269b7d58a90c569fd150435b4330dff7df Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 25 Sep 2024 09:59:18 +0100 Subject: [PATCH 202/298] hyprctl: add solitary field to hyprctl monitors --- src/debug/HyprCtl.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 87e071d7..178e9ba8 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -103,6 +103,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer "focused": {}, "dpmsStatus": {}, "vrr": {}, + "solitary": "{:x}", "activelyTearing": {}, "disabled": {}, "currentFormat": "{}", @@ -114,19 +115,20 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), - (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), - (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(), + (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), + availableModesForOutput(m.get(), format)); } else { result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing, - !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(), + m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); } return result; From 2320b2241c0713b8d81e8f467cb99bd4179ad23b Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:01:13 +0100 Subject: [PATCH 203/298] Internal: move to Mat3x3 from hyprutils (#7902) * Meson: require hyprutils >= 0.2.3 * flake.lock: update hyprutils --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- flake.lock | 6 +- src/helpers/MiscFunctions.cpp | 21 ----- src/helpers/MiscFunctions.hpp | 1 - src/helpers/Monitor.cpp | 9 +-- src/helpers/Monitor.hpp | 2 +- src/helpers/math/Math.cpp | 120 ---------------------------- src/helpers/math/Math.hpp | 10 +-- src/meson.build | 2 +- src/render/OpenGL.cpp | 142 ++++++++++++++-------------------- src/render/OpenGL.hpp | 46 +++++------ 11 files changed, 93 insertions(+), 268 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1718b2d..8055271e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ pkg_check_modules( gio-2.0 hyprlang>=0.3.2 hyprcursor>=0.1.7 - hyprutils>=0.2.2) + hyprutils>=0.2.3) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/flake.lock b/flake.lock index 68bb0ed2..a1f0d88d 100644 --- a/flake.lock +++ b/flake.lock @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1726874949, - "narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=", + "lastModified": 1727219120, + "narHash": "sha256-wmT+JpnDk6EjgASU2VGfS0nnu6oKA4Cw25o5fzpDD/Q=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "d97af4f6bd068c03a518b597675e598f57ea2291", + "rev": "db956287d3aa194dda91d05c8eb286de2a569edf", "type": "github" }, "original": { diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index b9970399..20c79a2b 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -628,27 +628,6 @@ void logSystemInfo() { Debug::log(NONE, "{}", execAndGet("cat /etc/os-release")); } -void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) { - memset(mat, 0, sizeof(*mat) * 9); - - const float* t = transforms[tr]; - float x = 2.0f / w; - float y = 2.0f / h; - - // Rotation + reflection - mat[0] = x * t[0]; - mat[1] = x * t[1]; - mat[3] = y * t[3]; - mat[4] = y * t[4]; - - // Translation - mat[2] = -copysign(1.0f, mat[0] + mat[1]); - mat[5] = -copysign(1.0f, mat[3] + mat[4]); - - // Identity - mat[8] = 1.0f; -} - int64_t getPPIDof(int64_t pid) { #if defined(KERN_PROC_PID) int mib[] = { diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 8b2ea0d1..f696fc5d 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -34,7 +34,6 @@ int64_t getPPIDof(int64_t pid); int64_t configStringToInt(const std::string&); Vector2D configStringToVector2D(const std::string&); std::optional getPlusMinusKeywordResult(std::string in, float relative); -void matrixProjection(float mat[9], int w, int h, wl_output_transform tr); double normalizeAngleRad(double ang); std::vector getBacktrace(); void throwError(const std::string& err); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 223a3f94..a2d4c504 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -772,12 +772,9 @@ Vector2D CMonitor::middle() { } void CMonitor::updateMatrix() { - matrixIdentity(projMatrix.data()); - if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { - matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); - matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform)); - matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); - } + projMatrix = Mat3x3::identity(); + if (transform != WL_OUTPUT_TRANSFORM_NORMAL) + projMatrix.translate(vecPixelSize / 2.0).transform(wlTransformToHyprutils(transform)).translate(-vecTransformedSize / 2.0); } WORKSPACEID CMonitor::activeWorkspaceID() { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 203cac90..97d9f8ab 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -96,7 +96,7 @@ class CMonitor { bool scheduledRecalc = false; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; float xwaylandScale = 1.f; - std::array projMatrix = {0}; + Mat3x3 projMatrix; std::optional forceSize; SP currentMode; SP cursorSwapchain; diff --git a/src/helpers/math/Math.cpp b/src/helpers/math/Math.cpp index fccfd636..d111690e 100644 --- a/src/helpers/math/Math.cpp +++ b/src/helpers/math/Math.cpp @@ -1,6 +1,4 @@ #include "Math.hpp" -#include -#include Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { switch (t) { @@ -17,124 +15,6 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; } -void matrixIdentity(float mat[9]) { - static const float identity[9] = { - 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - }; - memcpy(mat, identity, sizeof(identity)); -} - -void matrixMultiply(float mat[9], const float a[9], const float b[9]) { - float product[9]; - - product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6]; - product[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7]; - product[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8]; - - product[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6]; - product[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7]; - product[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8]; - - product[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6]; - product[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7]; - product[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8]; - - memcpy(mat, product, sizeof(product)); -} - -void matrixTranspose(float mat[9], const float a[9]) { - float transposition[9] = { - a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8], - }; - memcpy(mat, transposition, sizeof(transposition)); -} - -void matrixTranslate(float mat[9], float x, float y) { - float translate[9] = { - 1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f, - }; - matrixMultiply(mat, mat, translate); -} - -void matrixScale(float mat[9], float x, float y) { - float scale[9] = { - x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f, - }; - matrixMultiply(mat, mat, scale); -} - -void matrixRotate(float mat[9], float rad) { - float rotate[9] = { - cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f, - }; - matrixMultiply(mat, mat, rotate); -} - -const std::unordered_map>& getTransforms() { - static std::unordered_map> transforms = { - {HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - }; - return transforms; -} - -void matrixTransform(float mat[9], eTransform transform) { - matrixMultiply(mat, mat, getTransforms().at(transform).data()); -} - -void matrixProjection(float mat[9], int width, int height, eTransform transform) { - memset(mat, 0, sizeof(*mat) * 9); - - const float* t = getTransforms().at(transform).data(); - float x = 2.0f / width; - float y = 2.0f / height; - - // Rotation + reflection - mat[0] = x * t[0]; - mat[1] = x * t[1]; - mat[3] = y * -t[3]; - mat[4] = y * -t[4]; - - // Translation - mat[2] = -copysign(1.0f, mat[0] + mat[1]); - mat[5] = -copysign(1.0f, mat[3] + mat[4]); - - // Identity - mat[8] = 1.0f; -} - -void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]) { - double x = box.x; - double y = box.y; - double width = box.width; - double height = box.height; - - matrixIdentity(mat); - matrixTranslate(mat, x, y); - - if (rotation != 0) { - matrixTranslate(mat, width / 2, height / 2); - matrixRotate(mat, rotation); - matrixTranslate(mat, -width / 2, -height / 2); - } - - matrixScale(mat, width, height); - - if (transform != HYPRUTILS_TRANSFORM_NORMAL) { - matrixTranslate(mat, 0.5, 0.5); - matrixTransform(mat, transform); - matrixTranslate(mat, -0.5, -0.5); - } - - matrixMultiply(mat, projection, mat); -} - wl_output_transform invertTransform(wl_output_transform tr) { if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180); diff --git a/src/helpers/math/Math.hpp b/src/helpers/math/Math.hpp index f57cef93..9b73a20f 100644 --- a/src/helpers/math/Math.hpp +++ b/src/helpers/math/Math.hpp @@ -4,17 +4,9 @@ // includes box and vector as well #include +#include using namespace Hyprutils::Math; eTransform wlTransformToHyprutils(wl_output_transform t); -void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); -void matrixProjection(float mat[9], int width, int height, eTransform transform); -void matrixTransform(float mat[9], eTransform transform); -void matrixRotate(float mat[9], float rad); -void matrixScale(float mat[9], float x, float y); -void matrixTranslate(float mat[9], float x, float y); -void matrixTranspose(float mat[9], const float a[9]); -void matrixMultiply(float mat[9], const float a[9], const float b[9]); -void matrixIdentity(float mat[9]); wl_output_transform invertTransform(wl_output_transform tr); diff --git a/src/meson.build b/src/meson.build index 928cd5a7..da46c38c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,7 +16,7 @@ executable( dependency('cairo'), dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprlang', version: '>= 0.3.2'), - dependency('hyprutils', version: '>= 0.2.1'), + dependency('hyprutils', version: '>= 0.2.3'), dependency('libdrm'), dependency('egl'), dependency('xkbcommon'), diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 74d3d3cd..ff3d52e4 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -755,14 +755,12 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP< glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL); - matrixIdentity(m_RenderData.monitorProjection.data()); + m_RenderData.monitorProjection = Mat3x3::identity(); if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) { const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize; - matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); - matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform)); - matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0); + m_RenderData.monitorProjection.translate(FBO->m_vSize / 2.0).transform(wlTransformToHyprutils(pMonitor->transform)).translate(-tfmd / 2.0); } m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; @@ -809,7 +807,7 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL); m_RenderData.monitorProjection = pMonitor->projMatrix; @@ -1289,20 +1287,17 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion box = &newBox; - float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( + newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif // premultiply the color as well as we don't work with straight alpha @@ -1386,11 +1381,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB if (m_bEndFrame || TRANSFORMS_MATCH) TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); - float matrix[9]; - projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Debug::log(LOG, "internal:\nmat: {},\nglmat: {}", matrix.toString(), glMatrix.toString()); if (waitTimeline != nullptr) { if (!waitForTimelinePoint(waitTimeline, waitPoint)) { @@ -1442,10 +1436,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glUseProgram(shader->program); #ifndef GLES2 - glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1i(shader->tex, 0); @@ -1556,13 +1550,10 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { // get transform const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); - float matrix[9]; - projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); - - CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; + CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); @@ -1570,10 +1561,10 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { glUseProgram(shader->program); #ifndef GLES2 - glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1i(shader->tex, 0); @@ -1610,21 +1601,18 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf // get transform const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); - float matrix[9]; - projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); - - CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; + CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; glUseProgram(shader->program); #ifndef GLES2 - glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1i(shader->tex, 0); glUniform1i(shader->alphaMatte, 1); @@ -1667,13 +1655,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glDisable(GL_STENCIL_TEST); // get transforms for the full monitor - const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); - float matrix[9]; + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(MONITORBOX, TRANSFORM); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); // get the config settings static auto PBLURSIZE = CConfigValue("decoration:blur:size"); @@ -1710,10 +1695,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS); @@ -1755,10 +1740,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // prep two shaders #ifndef GLES2 - glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) { @@ -1832,10 +1817,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS); @@ -2165,12 +2150,9 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in round += round == 0 ? 0 : scaledBorderSize; - float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( + newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); const auto BLEND = m_bBlend; blend(true); @@ -2178,10 +2160,10 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail @@ -2471,22 +2453,19 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const const auto col = color; - float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( + newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); glEnable(GL_BLEND); glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); @@ -2565,11 +2544,11 @@ void CHyprOpenGLImpl::renderMirrored() { return; // replace monitor projection to undo the mirrored monitor's projection - matrixIdentity(m_RenderData.monitorProjection.data()); - matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0); - matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform)); - matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform))); - matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0); + m_RenderData.monitorProjection = Mat3x3::identity() + .translate(monitor->vecPixelSize / 2.0) + .transform(wlTransformToHyprutils(monitor->transform)) + .transform(wlTransformToHyprutils(invertTransform(mirrored->transform))) + .translate(-monitor->vecTransformedSize / 2.0); // clear stuff outside of mirrored area (e.g. when changing to mirrored) clear(CColor(0, 0, 0, 0)); @@ -2920,16 +2899,15 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { } void CHyprOpenGLImpl::saveMatrix() { - memcpy(m_RenderData.savedProjection, m_RenderData.projection, 9 * sizeof(float)); + m_RenderData.savedProjection = m_RenderData.projection; } void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) { - matrixScale(m_RenderData.projection, scale, scale); - matrixTranslate(m_RenderData.projection, translate.x, translate.y); + m_RenderData.projection.scale(scale).translate(translate); } void CHyprOpenGLImpl::restoreMatrix() { - memcpy(m_RenderData.projection, m_RenderData.savedProjection, 9 * sizeof(float)); + m_RenderData.projection = m_RenderData.savedProjection; } void CHyprOpenGLImpl::bindOffMain() { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 06078a00..0d1c267b 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -94,35 +94,35 @@ struct SMonitorRenderData { }; struct SCurrentRenderData { - CMonitor* pMonitor = nullptr; - PHLWORKSPACE pWorkspace = nullptr; - float projection[9]; - float savedProjection[9]; - std::array monitorProjection; + CMonitor* pMonitor = nullptr; + PHLWORKSPACE pWorkspace = nullptr; + Mat3x3 projection; + Mat3x3 savedProjection; + Mat3x3 monitorProjection; - SMonitorRenderData* pCurrentMonData = nullptr; - CFramebuffer* currentFB = nullptr; // current rendering to - CFramebuffer* mainFB = nullptr; // main to render to - CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) + SMonitorRenderData* pCurrentMonData = nullptr; + CFramebuffer* currentFB = nullptr; // current rendering to + CFramebuffer* mainFB = nullptr; // main to render to + CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) - CRegion damage; - CRegion finalDamage; // damage used for funal off -> main + CRegion damage; + CRegion finalDamage; // damage used for funal off -> main - SRenderModifData renderModif; - float mouseZoomFactor = 1.f; - bool mouseZoomUseMouse = true; // true by default - bool useNearestNeighbor = false; - bool forceIntrospection = false; // cleaned in ::end() - bool blockScreenShader = false; - bool simplePass = false; + SRenderModifData renderModif; + float mouseZoomFactor = 1.f; + bool mouseZoomUseMouse = true; // true by default + bool useNearestNeighbor = false; + bool forceIntrospection = false; // cleaned in ::end() + bool blockScreenShader = false; + bool simplePass = false; - Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); - Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); + Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); + Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); - CBox clipBox = {}; // scaled coordinates + CBox clipBox = {}; // scaled coordinates - uint32_t discardMode = DISCARD_OPAQUE; - float discardOpacity = 0.f; + uint32_t discardMode = DISCARD_OPAQUE; + float discardOpacity = 0.f; }; class CEGLSync { From 2a052c69f36a71fb473262f57039b8ac81518ad3 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 25 Sep 2024 10:36:43 +0100 Subject: [PATCH 204/298] core: add a --systeminfo parameter to gather systeminfo without running --- src/debug/HyprCtl.cpp | 11 +++++++---- src/debug/HyprCtl.hpp | 3 +++ src/main.cpp | 5 +++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 178e9ba8..0229a803 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -943,11 +943,14 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; result += "plugins:\n"; - for (auto const& pl : g_pPluginSystem->getAllPlugins()) { - result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); - } + if (g_pPluginSystem) { + for (auto const& pl : g_pPluginSystem->getAllPlugins()) { + result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); + } + } else + result += "\tunknown: not runtime\n"; - if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { + if (g_pHyprCtl && g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { result += "\n======Config-Start======\n"; result += g_pConfigManager->getConfigString(); result += "\n======Config-End========\n"; diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index cbacd7cb..d68bf14f 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -5,6 +5,9 @@ #include "../helpers/MiscFunctions.hpp" #include +// exposed for main.cpp +std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); + class CHyprCtl { public: CHyprCtl(); diff --git a/src/main.cpp b/src/main.cpp index ba6fe505..279e1ce1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "Compositor.hpp" #include "config/ConfigManager.hpp" #include "init/initHelpers.hpp" +#include "debug/HyprCtl.hpp" #include using namespace Hyprutils::String; @@ -133,6 +134,10 @@ int main(int argc, char** argv) { std::cout << result; return 0; + } else if (it->compare("--systeminfo") == 0) { + const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""); + std::cout << SYSINFO << "\n"; + return 0; } else { std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; help(); From 8b86ee8bf08eaf8b57d0a7f12af876216323cc3d Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 25 Sep 2024 10:37:58 +0100 Subject: [PATCH 205/298] github: encourage usage of --systeminfo if Hyprland won't launch --- .github/ISSUE_TEMPLATE/bug.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 7d402904..ce6d9d3e 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -29,10 +29,10 @@ body: attributes: label: System Info and Version description: | - Paste the output of `hyprctl systeminfo -c` here (If you are on a - version that shows you help menu, omit the `-c` and attach config files - to the issue). If you have configs outside of the main config shown - here, please attach. + Paste the output of `hyprctl systeminfo -c` here. If you can't + launch Hyprland, paste the output of `Hyprland --systeminfo`. + If `Hyprland --systeminfo` errors out (added in 0.44.0), find + and paste the Hyprland version manually. value: "

System/Version info From 49713fab045f7bd41466ddedd83ad5cb81142853 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 25 Sep 2024 23:15:36 +0100 Subject: [PATCH 206/298] pointermgr: avoid hogging CMonitor refs --- src/managers/PointerManager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3dcee431..736b629c 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -17,10 +17,8 @@ CPointerManager::CPointerManager() { onMonitorLayoutChange(); - PMONITOR->events.modeChanged.registerStaticListener( - [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); - PMONITOR->events.disconnect.registerStaticListener( - [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); + PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); + PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.destroy.registerStaticListener( [this](void* owner, std::any data) { if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) From 22746b304614b313a78d740f4536e809a4df90e2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 25 Sep 2024 23:38:11 +0100 Subject: [PATCH 207/298] hyprctl: use the getMonitorData helper everywhere --- src/debug/HyprCtl.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 0229a803..d9274727 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -160,16 +160,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (!m->output || m->ID == -1) continue; - result += std::format( - "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" - "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n", - m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, - m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), - m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, - (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), - (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled, - formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + result += CHyprCtl::getMonitorData(m, format); } } From b1ad2d806634edff656cb5ddc9850ae2c73324e8 Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Thu, 26 Sep 2024 04:08:50 +0500 Subject: [PATCH 208/298] dispatchers: fixup dpms toggle (#7875) now toggles every monitor individually --- src/managers/KeybindManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 02e2f5e7..48c4517a 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2403,9 +2403,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) { bool enable = arg.starts_with("on"); std::string port = ""; - if (arg.starts_with("toggle")) - enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off - + bool isToggle = arg.starts_with("toggle"); if (arg.find_first_of(' ') != std::string::npos) port = arg.substr(arg.find_first_of(' ') + 1); @@ -2414,6 +2412,9 @@ SDispatchResult CKeybindManager::dpms(std::string arg) { if (!port.empty() && m->szName != port) continue; + if (isToggle) + enable = !m->dpmsStatus; + m->output->state->resetExplicitFences(); m->output->state->setEnabled(enable); From caaa9b11e4763ed0367f81bf97ceaad5175806fc Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:10:53 +0100 Subject: [PATCH 209/298] wlr-output-configuration: Improve output configuration (#7571) --- src/config/ConfigManager.cpp | 66 ++++++++++++++--- src/config/ConfigManager.hpp | 2 +- src/helpers/Monitor.cpp | 4 +- src/managers/KeybindManager.cpp | 2 +- src/protocols/OutputManagement.cpp | 115 +++++++++++++++++++---------- src/protocols/OutputManagement.hpp | 69 +++++++++++------ 6 files changed, 181 insertions(+), 77 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 21a3a21e..ab5905c2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -7,6 +7,7 @@ #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" #include "../xwayland/XWayland.hpp" +#include "../protocols/OutputManagement.hpp" #include #include @@ -1079,28 +1080,69 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s return VAL; } -SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { +SMonitorRule CConfigManager::getMonitorRuleFor(const SP PMONITOR) { + auto applyWlrOutputConfig = [PMONITOR](SMonitorRule rule) -> SMonitorRule { + const auto CONFIG = PROTO::outputManagement->getOutputStateFor(PMONITOR); + + if (!CONFIG) + return rule; + + Debug::log(LOG, "CConfigManager::getMonitorRuleFor: found a wlr_output_manager override for {}", PMONITOR->szName); + + Debug::log(LOG, " > overriding enabled: {} -> {}", !rule.disabled, !CONFIG->enabled); + rule.disabled = !CONFIG->enabled; + + if ((CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_MODE) || (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE)) { + Debug::log(LOG, " > overriding mode: {:.0f}x{:.0f}@{:.2f}Hz -> {:.0f}x{:.0f}@{:.2f}Hz", rule.resolution.x, rule.resolution.y, rule.refreshRate, CONFIG->resolution.x, + CONFIG->resolution.y, CONFIG->refresh / 1000.F); + rule.resolution = CONFIG->resolution; + rule.refreshRate = CONFIG->refresh / 1000.F; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) { + Debug::log(LOG, " > overriding offset: {:.0f}, {:.0f} -> {:.0f}, {:.0f}", rule.offset.x, rule.offset.y, CONFIG->position.x, CONFIG->position.y); + rule.offset = CONFIG->position; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) { + Debug::log(LOG, " > overriding transform: {} -> {}", (uint8_t)rule.transform, (uint8_t)CONFIG->transform); + rule.transform = CONFIG->transform; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) { + Debug::log(LOG, " > overriding scale: {} -> {}", (uint8_t)rule.scale, (uint8_t)CONFIG->scale); + rule.scale = CONFIG->scale; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) { + Debug::log(LOG, " > overriding vrr: {} -> {}", rule.vrr.value_or(0), CONFIG->adaptiveSync); + rule.vrr = (int)CONFIG->adaptiveSync; + } + + return rule; + }; + for (auto const& r : m_dMonitorRules | std::views::reverse) { - if (PMONITOR.matchesStaticSelector(r.name)) { - return r; + if (PMONITOR->matchesStaticSelector(r.name)) { + return applyWlrOutputConfig(r); } } - Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName); + Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR->szName); for (auto const& r : m_dMonitorRules) { if (r.name.empty()) { - return r; + return applyWlrOutputConfig(r); } } Debug::log(WARN, "No rules configured. Using the default hardcoded one."); - return SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT, - .name = "", - .resolution = Vector2D(0, 0), - .offset = Vector2D(-INT32_MAX, -INT32_MAX), - .scale = -1}; // 0, 0 is preferred and -1, -1 is auto + return applyWlrOutputConfig(SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT, + .name = "", + .resolution = Vector2D(0, 0), + .offset = Vector2D(-INT32_MAX, -INT32_MAX), + .scale = -1}); // 0, 0 is preferred and -1, -1 is auto } SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) { @@ -1459,7 +1501,7 @@ void CConfigManager::performMonitorReload() { if (!m->output || m->isUnsafeFallback) continue; - auto rule = getMonitorRuleFor(*m); + auto rule = getMonitorRuleFor(m); if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { overAgain = true; @@ -1516,7 +1558,7 @@ void CConfigManager::ensureMonitorStatus() { if (!rm->output || rm->isUnsafeFallback) continue; - auto rule = getMonitorRuleFor(*rm); + auto rule = getMonitorRuleFor(rm); if (rule.disabled == rm->m_bEnabled) g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index da450e39..2134acf4 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -169,7 +169,7 @@ class CConfigManager { static std::string getMainConfigPath(); const std::string getConfigString(); - SMonitorRule getMonitorRuleFor(const CMonitor&); + SMonitorRule getMonitorRuleFor(const SP); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); std::string getDefaultWorkspaceFor(const std::string&); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a2d4c504..a9569699 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -114,7 +114,7 @@ void CMonitor::onConnect(bool noRule) { createdByUser = true; // should be true. WL and Headless backends should be addable / removable // get monitor rule that matches - SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this); + SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(self.lock()); // if it's disabled, disable and ignore if (monitorRule.disabled) { @@ -489,7 +489,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { pMirrorOf = nullptr; // set rule - const auto RULE = g_pConfigManager->getMonitorRuleFor(*this); + const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock()); vecPosition = RULE.offset; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 48c4517a..cd47bf71 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1943,7 +1943,7 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) { if (!m->output) continue; - auto rule = g_pConfigManager->getMonitorRuleFor(*m); + auto rule = g_pConfigManager->getMonitorRuleFor(m); if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { overAgain = true; break; diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 09552b19..dcc7a62d 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -307,10 +307,15 @@ COutputConfiguration::COutputConfiguration(SP resour LOGM(LOG, "disableHead on {}", PMONITOR->szName); - PMONITOR->activeMonitorRule.disabled = true; - if (!g_pConfigManager->replaceMonitorRule(PMONITOR->activeMonitorRule)) - g_pConfigManager->appendMonitorRule(PMONITOR->activeMonitorRule); - g_pHyprRenderer->applyMonitorRule(PMONITOR, &PMONITOR->activeMonitorRule, false); + SWlrManagerSavedOutputState newState; + if (owner->monitorStates.contains(PMONITOR->szName)) + newState = owner->monitorStates.at(PMONITOR->szName); + + newState.enabled = false; + + g_pConfigManager->m_bWantsMonitorReload = true; + + owner->monitorStates[PMONITOR->szName] = newState; }); resource->setTest([this](CZwlrOutputConfigurationV1* r) { @@ -346,6 +351,11 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { LOGM(LOG, "Applying configuration"); + if (!owner) { + LOGM(ERR, "applyTestConfiguration: no owner?!"); + return false; + } + for (auto const& headw : heads) { auto head = headw.lock(); @@ -357,41 +367,59 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { if (!PMONITOR) continue; - LOGM(LOG, "Applying config for monitor {}", PMONITOR->szName); + LOGM(LOG, "Saving config for monitor {}", PMONITOR->szName); - SMonitorRule newRule = PMONITOR->activeMonitorRule; - newRule.name = PMONITOR->szName; - newRule.disabled = false; + SWlrManagerSavedOutputState newState; + if (owner->monitorStates.contains(PMONITOR->szName)) + newState = owner->monitorStates.at(PMONITOR->szName); - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { - newRule.resolution = head->state.mode->getMode()->pixelSize; - newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F; - } else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { - newRule.resolution = head->state.customMode.size; - newRule.refreshRate = head->state.customMode.refresh / 1000.F; + newState.enabled = true; + + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { + newState.resolution = head->state.mode->getMode()->pixelSize; + newState.refresh = head->state.mode->getMode()->refreshRate; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE; + LOGM(LOG, " > Mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh); + } else if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { + newState.resolution = head->state.customMode.size; + newState.refresh = head->state.customMode.refresh; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE; + LOGM(LOG, " > Custom mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh); } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION) - newRule.offset = head->state.position; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION) { + newState.position = head->state.position; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION; + LOGM(LOG, " > Position: {:.0f}, {:.0f}", head->state.position.x, head->state.position.y); + } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) - newRule.vrr = head->state.adaptiveSync; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) { + newState.adaptiveSync = head->state.adaptiveSync; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC; + LOGM(LOG, " > vrr: {}", newState.adaptiveSync); + } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE) - newRule.scale = head->state.scale; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE) { + newState.scale = head->state.scale; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE; + LOGM(LOG, " > scale: {:.2f}", newState.scale); + } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM) - newRule.transform = head->state.transform; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM) { + newState.transform = head->state.transform; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM; + LOGM(LOG, " > transform: {}", (uint8_t)newState.transform); + } // reset properties for next set. - head->committedProperties = 0; + head->state.committedProperties = 0; - if (!g_pConfigManager->replaceMonitorRule(newRule)) - g_pConfigManager->appendMonitorRule(newRule); g_pConfigManager->m_bWantsMonitorReload = true; + + owner->monitorStates[PMONITOR->szName] = newState; } - LOGM(LOG, "Applied configuration"); + LOGM(LOG, "Saved configuration"); return true; } @@ -417,12 +445,12 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } - committedProperties |= OUTPUT_HEAD_COMMITTED_MODE; + state.committedProperties |= OUTPUT_HEAD_COMMITTED_MODE; state.mode = MODE; LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate); @@ -434,7 +462,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -444,7 +472,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, w, h, refresh); @@ -456,12 +484,12 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } - committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION; + state.committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION; state.position = {x, y}; LOGM(LOG, " | configHead for {}: set pos to {}, {}", pMonitor->szName, x, y); @@ -473,7 +501,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -483,7 +511,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, transform); @@ -495,7 +523,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -507,7 +535,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, scale); @@ -519,7 +547,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -529,7 +557,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, as); @@ -601,3 +629,14 @@ SP COutputManagementProtocol::modeFromResource(wl_resource* r) { return nullptr; } + +SP COutputManagementProtocol::getOutputStateFor(SP pMonitor) { + for (auto const& m : m_vManagers) { + if (!m->monitorStates.contains(pMonitor->szName)) + continue; + + return makeShared(m->monitorStates.at(pMonitor->szName)); + } + + return nullptr; +} diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 36478d0b..f4a84475 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "WaylandProtocol.hpp" #include "wlr-output-management-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" @@ -13,6 +14,43 @@ class CMonitor; class COutputHead; class COutputMode; +struct SMonitorRule; + +enum eWlrOutputCommittedProperties : uint32_t { + OUTPUT_HEAD_COMMITTED_MODE = (1 << 0), + OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1), + OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2), + OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3), + OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4), + OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5), +}; + +struct SWlrManagerOutputState { + uint32_t committedProperties = 0; + + WP mode; + struct { + Vector2D size; + uint32_t refresh = 0; + } customMode; + Vector2D position; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + float scale = 1.F; + bool adaptiveSync = false; + bool enabled = true; +}; + +struct SWlrManagerSavedOutputState { + uint32_t committedProperties = 0; + Vector2D resolution; + uint32_t refresh = 0; + Vector2D position; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + float scale = 1.F; + bool adaptiveSync = false; + bool enabled = true; +}; + class COutputManager { public: COutputManager(SP resource_); @@ -21,6 +59,9 @@ class COutputManager { void ensureMonitorSent(CMonitor* pMonitor); void sendDone(); + // holds the states for this manager. + std::unordered_map monitorStates; + private: SP resource; bool stopped = false; @@ -80,30 +121,9 @@ class COutputConfigurationHead { public: COutputConfigurationHead(SP resource_, CMonitor* pMonitor_); - bool good(); + bool good(); - enum eCommittedProperties : uint32_t { - OUTPUT_HEAD_COMMITTED_MODE = (1 << 0), - OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1), - OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2), - OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3), - OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4), - OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5), - }; - - uint32_t committedProperties = 0; - - struct { - WP mode; - struct { - Vector2D size; - uint32_t refresh = 0; - } customMode; - Vector2D position; - wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - float scale = 1.F; - bool adaptiveSync = false; - } state; + SWlrManagerOutputState state; private: SP resource; @@ -136,6 +156,9 @@ class COutputManagementProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + // doesn't have to return one + SP getOutputStateFor(SP pMonitor); + private: void destroyResource(COutputManager* resource); void destroyResource(COutputHead* resource); From 32a8caf7e7a0609629eb08c91de9f9b23a10c455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Thu, 6 Jun 2024 10:07:53 +0200 Subject: [PATCH 210/298] Nix: also test cross build --- flake.nix | 10 ++++++++++ nix/default.nix | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index ef48b2d1..eca45675 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,15 @@ hyprland-extras ]; }); + pkgsCrossFor = eachSystem (system: crossSystem: + import nixpkgs { + localSystem = system; + crossSystem = crossSystem; + overlays = with self.overlays; [ + hyprland-packages + hyprland-extras + ]; + }); in { overlays = import ./nix/overlays.nix {inherit self lib inputs;}; @@ -92,6 +101,7 @@ xdg-desktop-portal-hyprland ; + hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland; }); devShells = eachSystem (system: { diff --git a/nix/default.nix b/nix/default.nix index 40675d9a..be7394e4 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -102,7 +102,6 @@ in ninja pkg-config python3 # for udis86 - wayland-scanner ]; outputs = [ @@ -130,6 +129,7 @@ in tomlplusplus wayland wayland-protocols + wayland-scanner xorg.libXcursor ] (optionals customStdenv.hostPlatform.isMusl [libexecinfo]) From 7b56ce6521e5ad3b0a2dab6f79a045e79c7aeb82 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 11 Jun 2024 18:49:12 +0300 Subject: [PATCH 211/298] CI/Nix: add cross build --- .github/workflows/nix-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 50823629..6351216f 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -12,6 +12,7 @@ jobs: matrix: package: - hyprland + - hyprland-cross - xdg-desktop-portal-hyprland runs-on: ubuntu-latest From 77f2a01304f33a2dc7c9002ca9fb20a7653e6ae1 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 26 Sep 2024 16:52:02 +0300 Subject: [PATCH 212/298] flake.lock: update nixpkgs --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index a1f0d88d..4ebdc734 100644 --- a/flake.lock +++ b/flake.lock @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1726755586, - "narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=", + "lastModified": 1727122398, + "narHash": "sha256-o8VBeCWHBxGd4kVMceIayf5GApqTavJbTa44Xcg5Rrk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e", + "rev": "30439d93eb8b19861ccbe3e581abf97bdc91b093", "type": "github" }, "original": { From 14942bca60cc7d85e8238a151bd444112601ebe6 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 21:19:09 +0300 Subject: [PATCH 213/298] Nix: re-add hyprland-protocols --- flake.lock | 26 +++++++++++++++++++++++++- flake.nix | 6 ++++++ nix/default.nix | 2 ++ nix/overlays.nix | 1 + 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/flake.lock b/flake.lock index 4ebdc734..7e0f093e 100644 --- a/flake.lock +++ b/flake.lock @@ -56,6 +56,29 @@ } }, "hyprland-protocols": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1721326555, + "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", + "owner": "hyprwm", + "repo": "hyprland-protocols", + "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-protocols", + "type": "github" + } + }, + "hyprland-protocols_2": { "inputs": { "nixpkgs": [ "xdph", @@ -172,6 +195,7 @@ "inputs": { "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", + "hyprland-protocols": "hyprland-protocols", "hyprlang": "hyprlang", "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", @@ -197,7 +221,7 @@ }, "xdph": { "inputs": { - "hyprland-protocols": "hyprland-protocols", + "hyprland-protocols": "hyprland-protocols_2", "hyprlang": [ "hyprlang" ], diff --git a/flake.nix b/flake.nix index eca45675..ee5af6a1 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,12 @@ inputs.hyprlang.follows = "hyprlang"; }; + hyprland-protocols = { + url = "github:hyprwm/hyprland-protocols"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + }; + hyprlang = { url = "github:hyprwm/hyprlang"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/nix/default.nix b/nix/default.nix index be7394e4..85a3105d 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -13,6 +13,7 @@ cairo, git, hyprcursor, + hyprland-protocols, hyprlang, hyprutils, hyprwayland-scanner, @@ -116,6 +117,7 @@ in cairo git hyprcursor + hyprland-protocols hyprlang hyprutils libdrm diff --git a/nix/overlays.nix b/nix/overlays.nix index d6e078fa..71b5f59f 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -22,6 +22,7 @@ in { # Dependencies inputs.aquamarine.overlays.default inputs.hyprcursor.overlays.default + inputs.hyprland-protocols.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default From 27211c71e92e1bacf111d8a815e958f80969ce6e Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 21:20:35 +0300 Subject: [PATCH 214/298] Meson: try to find udis86 through pkgconfig, fallback to subproject Only the fork provides a .pc file, so there's no risk of linking the wrong lib version. If pkg-config can't find it (most cases), fall back to using the subproject through the wrap file. --- meson.build | 4 ---- nix/default.nix | 8 ++------ nix/overlays.nix | 17 +++++++++++++++++ src/meson.build | 6 +++++- subprojects/udis86.wrap | 5 +++++ 5 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 subprojects/udis86.wrap diff --git a/meson.build b/meson.build index 9449c241..42ed519d 100644 --- a/meson.build +++ b/meson.build @@ -43,10 +43,6 @@ xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) gio_dep = dependency('gio-2.0', required: true) -cmake = import('cmake') -udis = cmake.subproject('udis86') -udis86 = udis.dependency('libudis86') - if not xcb_dep.found() add_project_arguments('-DNO_XWAYLAND', language: 'cpp') endif diff --git a/nix/default.nix b/nix/default.nix index 85a3105d..df270f28 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -6,7 +6,6 @@ pkgconf, makeWrapper, meson, - cmake, ninja, aquamarine, binutils, @@ -17,7 +16,6 @@ hyprlang, hyprutils, hyprwayland-scanner, - jq, libGL, libdrm, libexecinfo, @@ -27,9 +25,9 @@ mesa, pango, pciutils, - python3, systemd, tomlplusplus, + udis86-hyprland, wayland, wayland-protocols, wayland-scanner, @@ -96,13 +94,10 @@ in nativeBuildInputs = [ hyprwayland-scanner - jq makeWrapper meson - cmake ninja pkg-config - python3 # for udis86 ]; outputs = [ @@ -129,6 +124,7 @@ in pango pciutils tomlplusplus + udis86-hyprland wayland wayland-protocols wayland-scanner diff --git a/nix/overlays.nix b/nix/overlays.nix index 71b5f59f..2b2788e7 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -26,6 +26,7 @@ in { inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default + self.overlays.udis86 # Hyprland packages themselves (final: prev: let @@ -64,4 +65,20 @@ in { hyprland-extras = lib.composeManyExtensions [ inputs.xdph.overlays.xdg-desktop-portal-hyprland ]; + + # udis86 from nixpkgs is too old, and also does not provide a .pc file + # this version is the one used in the git submodule, and allows us to + # fetch the source without '?submodules=1' + udis86 = final: prev: { + udis86-hyprland = prev.udis86.overrideAttrs (self: super: { + src = final.fetchFromGitHub { + owner = "canihavesomecoffee"; + repo = "udis86"; + rev = "5336633af70f3917760a6d441ff02d93477b0c86"; + hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g="; + }; + + patches = []; + }); + }; } diff --git a/src/meson.build b/src/meson.build index da46c38c..7c71a735 100644 --- a/src/meson.build +++ b/src/meson.build @@ -31,7 +31,11 @@ executable( backtrace_dep, epoll_dep, gio_dep, - udis86, + + # Try to find canihavesomecoffee's udis86 using pkgconfig + # vmt/udis86 does not provide a .pc file and won't be detected this way + # Falls back to using the subproject through udis86.wrap + dependency('udis86'), dependency('pixman-1'), dependency('gl', 'opengl'), diff --git a/subprojects/udis86.wrap b/subprojects/udis86.wrap new file mode 100644 index 00000000..dfb63984 --- /dev/null +++ b/subprojects/udis86.wrap @@ -0,0 +1,5 @@ +[wrap-file] +method = cmake + +[provide] +udis86 = libudis86_dep From 89d945aabe632387f113ac500bfee573d51cc4f7 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 18:00:02 +0300 Subject: [PATCH 215/298] CMake: use hyprland-protocols from pkg-config, fallback to subproject protocolnew: fix external path, which may not be in $CMAKE_SOURCE_DIR --- CMakeLists.txt | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8055271e..08eb93cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,7 +230,7 @@ add_custom_target(generate-protocol-headers) function(protocolnew protoPath protoName external) if(external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + set(path ${protoPath}) else() set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) endif() @@ -261,11 +261,20 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads libudis86) -protocolnew("subprojects/hyprland-protocols/protocols" - "hyprland-global-shortcuts-v1" true) +pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0) +if(hyprland_protocols_dep_FOUND) + pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) + message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") +else() + set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols") + message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}") +endif() + +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1" + true) protocolnew("unstable/text-input" "text-input-unstable-v1" false) -protocolnew("subprojects/hyprland-protocols/protocols" - "hyprland-toplevel-export-v1" true) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1" + true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) @@ -276,8 +285,7 @@ protocolnew("protocols" "input-method-unstable-v2" true) protocolnew("protocols" "wlr-output-management-unstable-v1" true) protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true) -protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" - true) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wayland-drm" true) protocolnew("staging/tearing-control" "tearing-control-v1" false) From be96787ed086f751455cf713739296b5c6e3a235 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 18:01:44 +0300 Subject: [PATCH 216/298] CMake: use udis86 from pkg-config, fallback to subproject Only canihavesomecoffee's fork (the one the subproject uses) provides a .pc file, so we either find the correct version or we use the subproject. --- CMakeLists.txt | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08eb93cf..8115d01c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,8 +25,18 @@ message(STATUS "Gathering git info") execute_process(COMMAND ./scripts/generateVersion.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) -# udis -add_subdirectory("subprojects/udis86") +find_package(PkgConfig REQUIRED) + +# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not +# provide a .pc file and won't be detected this way +pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2) + +# Fallback to subproject +if(NOT udis_dep_FOUND) + add_subdirectory("subprojects/udis86") + include_directories("subprojects/udis86") + message(STATUS "udis86 dependency not found, falling back to subproject") +endif() if(CMAKE_BUILD_TYPE) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) @@ -47,8 +57,6 @@ else() set(BUILDTYPE_LOWER "release") endif() -find_package(PkgConfig REQUIRED) - pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) @@ -63,7 +71,8 @@ else() message(STATUS "Configuring Hyprland in Release with CMake") endif() -include_directories(. "src/" "subprojects/udis86/" "protocols/") +include_directories(. "src/" "protocols/") + set(CMAKE_CXX_STANDARD 26) add_compile_options( -Wall @@ -224,6 +233,11 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps) +if(udis_dep_FOUND) + target_link_libraries(Hyprland PkgConfig::udis_dep) +else() + target_link_libraries(Hyprland libudis86) +endif() # used by `make installheaders`, to ensure the headers are generated add_custom_target(generate-protocol-headers) @@ -258,8 +272,7 @@ function(protocolWayland) PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) endfunction() -target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads - libudis86) +target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0) if(hyprland_protocols_dep_FOUND) From f75f8efb1be227e586cc0ba2ce6153ce56e04314 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 20:53:34 +0300 Subject: [PATCH 217/298] Meson: add tracy dependency --- meson.build | 6 ++++++ meson_options.txt | 1 + nix/default.nix | 7 +++++-- src/meson.build | 1 + subprojects/tracy.wrap | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 subprojects/tracy.wrap diff --git a/meson.build b/meson.build index 42ed519d..3545f46a 100644 --- a/meson.build +++ b/meson.build @@ -73,6 +73,12 @@ foreach file : headers install_headers(file, subdir: 'hyprland', preserve_path: true) endforeach +tracy = dependency('tracy', static: true, required: get_option('tracy_enable')) + +if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized' + warning('Profiling builds should set -- buildtype = debugoptimized') +endif + subdir('protocols') subdir('src') subdir('hyprctl') diff --git a/meson_options.txt b/meson_options.txt index 16a34a54..d8c9d5e6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,4 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration') option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer') +option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling') diff --git a/nix/default.nix b/nix/default.nix index df270f28..6f086ccc 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -144,7 +144,7 @@ in mesonBuildType = if debug - then "debug" + then "debugoptimized" else "release"; # we want as much debug info as possible @@ -156,7 +156,10 @@ in "legacy_renderer" = legacyRenderer; "systemd" = withSystemd; }) - (mesonBool "b_pch" false) + (mapAttrsToList mesonBool { + "b_pch" = false; + "tracy_enable" = false; + }) ]; postInstall = '' diff --git a/src/meson.build b/src/meson.build index 7c71a735..2dbe2f44 100644 --- a/src/meson.build +++ b/src/meson.build @@ -31,6 +31,7 @@ executable( backtrace_dep, epoll_dep, gio_dep, + tracy, # Try to find canihavesomecoffee's udis86 using pkgconfig # vmt/udis86 does not provide a .pc file and won't be detected this way diff --git a/subprojects/tracy.wrap b/subprojects/tracy.wrap new file mode 100644 index 00000000..11b21787 --- /dev/null +++ b/subprojects/tracy.wrap @@ -0,0 +1 @@ +[wrap-file] From b2143a98e2719012f8c36211a066f8ebccc950b8 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 26 Sep 2024 23:00:20 +0300 Subject: [PATCH 218/298] CI/Nix: no longer build with submodules --- .github/workflows/nix-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 6351216f..73adb497 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -25,4 +25,4 @@ jobs: name: hyprland authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" + - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" From e20aef7d53fcde1470e8d7672e6a03d814fca97f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 26 Sep 2024 22:34:33 +0100 Subject: [PATCH 219/298] opengl: remove debug log --- src/render/OpenGL.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ff3d52e4..4f22d6aa 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1384,8 +1384,6 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - Debug::log(LOG, "internal:\nmat: {},\nglmat: {}", matrix.toString(), glMatrix.toString()); - if (waitTimeline != nullptr) { if (!waitForTimelinePoint(waitTimeline, waitPoint)) { Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint); From 58669fef77ac17ea205ce3570f48e17de736111f Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 27 Sep 2024 18:35:29 +0300 Subject: [PATCH 220/298] flake.lock: update --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 7e0f093e..5adaa350 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1726665257, - "narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=", + "lastModified": 1727261104, + "narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e", + "rev": "b82fdaff917582a9d568969e15e61b398c71e990", "type": "github" }, "original": { @@ -65,11 +65,11 @@ ] }, "locked": { - "lastModified": 1721326555, - "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", + "lastModified": 1727451107, + "narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", + "rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3", "type": "github" }, "original": { @@ -139,11 +139,11 @@ ] }, "locked": { - "lastModified": 1727219120, - "narHash": "sha256-wmT+JpnDk6EjgASU2VGfS0nnu6oKA4Cw25o5fzpDD/Q=", + "lastModified": 1727300645, + "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "db956287d3aa194dda91d05c8eb286de2a569edf", + "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c", "type": "github" }, "original": { @@ -162,11 +162,11 @@ ] }, "locked": { - "lastModified": 1726840673, - "narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=", + "lastModified": 1726874836, + "narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "b68dab23fc922eae99306988133ee80a40b39ca5", + "rev": "500c81a9e1a76760371049a8d99e008ea77aa59e", "type": "github" }, "original": { From 2cf6e7862a844ad96aa060d63f6774df7e2234a6 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 27 Sep 2024 20:49:40 -0400 Subject: [PATCH 221/298] dwindle: add config option `split_bias` (#7920) If `default_split_ratio` is greater than 1.0, `split_bias` will give the bigger half to a specific window: 0 - positional (default) 1 - current window 2 - opening window --- src/config/ConfigManager.cpp | 1 + src/layout/DwindleLayout.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ab5905c2..ad6e1871 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -446,6 +446,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f}); + m_pConfig->addConfigValue("dwindle:split_bias", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:smart_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:smart_resizing", Hyprlang::INT{1}); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index c936d59c..69b044b4 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -1,7 +1,7 @@ #include "DwindleLayout.hpp" -#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "../render/decorations/CHyprGroupBarDecoration.hpp" void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { if (children[0]) { @@ -459,6 +459,12 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir } } + // split in favor of a specific window + const auto first = NEWPARENT->children[0]; + static auto PSPLITBIAS = CConfigValue("dwindle:split_bias"); + if ((*PSPLITBIAS == 1 && first == PNODE) || (*PSPLITBIAS == 2 && first == OPENINGON)) + NEWPARENT->splitRatio = 2.f - NEWPARENT->splitRatio; + // and update the previous parent if it exists if (OPENINGON->pParent) { if (OPENINGON->pParent->children[0] == OPENINGON) { From 6f313de952311282e82461a342c74ea702d9f13a Mon Sep 17 00:00:00 2001 From: bivsk <141476105+bivsk@users.noreply.github.com> Date: Sat, 28 Sep 2024 08:46:31 -0400 Subject: [PATCH 222/298] core: Fix Musl builds (#7934) Musl does not include the internal type `__time_t`. Use `time_t` instead. --- src/protocols/PresentationTime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index e1ff52cd..71f74cd5 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -58,8 +58,8 @@ void CPresentationFeedback::sendQueued(SP data, timespe if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; - __time_t tv_sec = 0; - if (sizeof(__time_t) > 4) + time_t tv_sec = 0; + if (sizeof(time_t) > 4) tv_sec = when->tv_sec >> 32; if (data->wasPresented) From d73c14751ad40fd54d93baac2226f550142b0e74 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 28 Sep 2024 21:53:08 +0300 Subject: [PATCH 223/298] CI/Nix: git+https -> github --- .github/workflows/nix-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 73adb497..d1f47ee4 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -25,4 +25,4 @@ jobs: name: hyprland authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" + - run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" From 9e418671e12549156d0735a6b23732f66d5647c7 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Sun, 29 Sep 2024 09:42:10 -0400 Subject: [PATCH 224/298] config: add descriptions for dwindle and master layout options (#7933) --- src/config/ConfigDescriptions.hpp | 160 ++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 84ac1a41..3a91a808 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1372,4 +1372,164 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + + /* + * dwindle: + */ + + SConfigOptionDescription{ + .value = "dwindle:pseudotile", + .description = "enable pseudotiling. Pseudotiled windows retain their floating size when tiled.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:force_split", + .description = "0 -> split follows mouse, 1 -> always split to the left (new = left or top) 2 -> always split to the right (new = right or bottom)", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "follow mouse,left or top,right or bottom"}, + }, + SConfigOptionDescription{ + .value = "dwindle:preserve_split", + .description = "if enabled, the split (side/top) will not change regardless of what happens to the container.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:smart_split", + .description = "if enabled, allows a more precise control over the window split direction based on the cursor's position. The window is conceptually divided into four " + "triangles, and cursor's triangle determines the split direction. This feature also turns on preserve_split.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:smart_resizing", + .description = + "if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "dwindle:permanent_direction_override", + .description = "if enabled, makes the preselect direction persist until either this mode is turned off, another direction is specified, or a non-direction is specified " + "(anything other than l,r,u/t,d/b)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:special_scale_factor", + .description = "specifies the scale factor of windows on the special workspace [0 - 1]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "dwindle:split_width_multiplier", + .description = "specifies the auto-split width multiplier", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0.1, 3}, + }, + SConfigOptionDescription{ + .value = "dwindle:no_gaps_when_only", + .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, + }, + SConfigOptionDescription{ + .value = "dwindle:use_active_for_splits", + .description = "whether to prefer the active window or the mouse position for splits", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "dwindle:default_split_ratio", + .description = "the default split ratio on window open. 1 means even 50/50 split. [0.1 - 1.9]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0.1, 1.9}, + }, + SConfigOptionDescription{ + .value = "dwindle:split_bias", + .description = "specifies which window will receive the larger half of a split. positional - 0, current window - 1, opening window - 2 [0/1/2]", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"}, + }, + + /* + * master: + */ + + SConfigOptionDescription{ + .value = "master:allow_small_split", + .description = "enable adding additional master windows in a horizontal split style", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "master:special_scale_factor", + .description = "the scale of the special workspace windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "master:mfact", + .description = + "the size as a percentage of the master window, for example `mfact = 0.70` would mean 70% of the screen will be the master window, and 30% the slave [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.55, 0, 1}, + }, + SConfigOptionDescription{ + .value = "master:new_status", + .description = "`master`: new window becomes master; `slave`: new windows are added to slave stack; `inherit`: inherit from focused window", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"slave"}, + }, + SConfigOptionDescription{ + .value = "master:new_on_top", + .description = "whether a newly open window should be on the top of the stack", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "master:new_on_active", + .description = "`before`, `after`: place new window relative to the focused window; `none`: place new window according to the value of `new_on_top`. ", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"none"}, + }, + SConfigOptionDescription{ + .value = "master:no_gaps_when_only", + .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, + }, + SConfigOptionDescription{ + .value = "master:orientation", + .description = "default placement of the master area, can be left, right, top, bottom or center", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"left"}, + }, + SConfigOptionDescription{ + .value = "master:inherit_fullscreen", + .description = "inherit fullscreen status when cycling/swapping to another window (e.g. monocle layout)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "master:always_center_master", + .description = "when using orientation=center, keep the master window centered, even when it is the only window in the workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "master:smart_resizing", + .description = + "if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "master:drop_at_cursor", + .description = "when enabled, dragging and dropping windows will put them at the cursor position. Otherwise, when dropped at the stack side, they will go to the " + "top/bottom of the stack depending on new_on_top.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, }; From 4b00cba319dc44294567d06df7c378cf5e4e5338 Mon Sep 17 00:00:00 2001 From: Luke Chen <3363954+LukeXuan@users.noreply.github.com> Date: Sun, 29 Sep 2024 09:47:59 -0400 Subject: [PATCH 225/298] dwindle: add movetoroot method to layout messages (#7903) --- src/layout/DwindleLayout.cpp | 42 ++++++++++++++++++++++++++++++++++++ src/layout/DwindleLayout.hpp | 1 + 2 files changed, 43 insertions(+) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 69b044b4..ed47fa44 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -998,6 +998,10 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str toggleSplit(header.pWindow); } else if (ARGS[0] == "swapsplit") { swapSplit(header.pWindow); + } else if (ARGS[0] == "movetoroot") { + const auto WINDOW = ARGS[1].empty() ? header.pWindow : g_pCompositor->getWindowByRegex(ARGS[1]); + const auto STABLE = ARGS[2].empty() || ARGS[2] != "unstable"; + moveToRoot(WINDOW, STABLE); } else if (ARGS[0] == "preselect") { std::string direction = ARGS[1]; @@ -1065,6 +1069,44 @@ void CHyprDwindleLayout::swapSplit(PHLWINDOW pWindow) { PNODE->pParent->recalcSizePosRecursive(); } +// goal: maximize the chosen window within current dwindle layout +// impl: swap the selected window with the other sub-tree below root +void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) { + const auto PNODE = getNodeFromWindow(pWindow); + + if (!PNODE || !PNODE->pParent) + return; + + if (pWindow->isFullscreen()) + return; + + // already at root + if (!PNODE->pParent->pParent) + return; + + auto& pNode = PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[0] : PNODE->pParent->children[1]; + + // instead of [getMasterNodeOnWorkspace], we walk back to root since we need + // to know which children of root is our ancestor + auto pAncestor = PNODE, pRoot = PNODE->pParent; + while (pRoot->pParent) { + pAncestor = pRoot; + pRoot = pRoot->pParent; + } + + auto& pSwap = pRoot->children[0] == pAncestor ? pRoot->children[1] : pRoot->children[0]; + std::swap(pNode, pSwap); + std::swap(pNode->pParent, pSwap->pParent); + + // [stable] in that the focused window occupies same side of screen + if (stable) + std::swap(pRoot->children[0], pRoot->children[1]); + + // if the workspace is visible, recalculate layout + if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + pRoot->recalcSizePosRecursive(); +} + void CHyprDwindleLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { const auto PNODE = getNodeFromWindow(from); diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index bbd511c2..953ba3a2 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -87,6 +87,7 @@ class CHyprDwindleLayout : public IHyprLayout { void toggleSplit(PHLWINDOW); void swapSplit(PHLWINDOW); + void moveToRoot(PHLWINDOW, bool stable = true); eDirection overrideDirection = DIRECTION_DEFAULT; From 6649255d54f45a7e2fedd9b4be85fe5d11229c04 Mon Sep 17 00:00:00 2001 From: Gliczy <129636582+Gliczy@users.noreply.github.com> Date: Sun, 29 Sep 2024 15:45:19 +0200 Subject: [PATCH 226/298] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 5adaa350..2579dd11 100644 --- a/flake.lock +++ b/flake.lock @@ -42,11 +42,11 @@ ] }, "locked": { - "lastModified": 1722623071, - "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", + "lastModified": 1727532803, + "narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "912d56025f03d41b1ad29510c423757b4379eb1c", + "rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f", "type": "github" }, "original": { @@ -177,11 +177,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1727122398, - "narHash": "sha256-o8VBeCWHBxGd4kVMceIayf5GApqTavJbTa44Xcg5Rrk=", + "lastModified": 1727348695, + "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "30439d93eb8b19861ccbe3e581abf97bdc91b093", + "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", "type": "github" }, "original": { @@ -239,11 +239,11 @@ ] }, "locked": { - "lastModified": 1727109343, - "narHash": "sha256-1PFckA8Im7wMSl26okwOKqBZeCFLD3LvZZFaxswDhbY=", + "lastModified": 1727524473, + "narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "4adb6c4c41ee5014bfe608123bfeddb26e5f5cea", + "rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26", "type": "github" }, "original": { From 488efab63654a643d76df4997cd932d6fddd8faf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 00:57:51 +0100 Subject: [PATCH 227/298] single-pixel-buffer: new protocol impl fixes #6624 --- CMakeLists.txt | 1 + src/helpers/Color.hpp | 3 +- src/managers/ProtocolManager.cpp | 2 + src/protocols/SinglePixel.cpp | 125 +++++++++++++++++++++++++++++++ src/protocols/SinglePixel.hpp | 79 +++++++++++++++++++ 5 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/protocols/SinglePixel.cpp create mode 100644 src/protocols/SinglePixel.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8115d01c..ee9cd2e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,6 +330,7 @@ protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) +protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) protocolwayland() diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp index 8abfe748..32ed39ee 100644 --- a/src/helpers/Color.hpp +++ b/src/helpers/Color.hpp @@ -8,8 +8,9 @@ class CColor { CColor(float r, float g, float b, float a); CColor(uint64_t); - float r = 0, g = 0, b = 0, a = 1.f; + float r = 0, g = 0, b = 0, a = 1.f; + // AR32 uint32_t getAsHex() const; CColor operator-(const CColor& c2) const { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6b6d5acf..8bcc857a 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -44,6 +44,7 @@ #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/XDGDialog.hpp" +#include "../protocols/SinglePixel.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -152,6 +153,7 @@ CProtocolManager::CProtocolManager() { PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); + PROTO::singlePixel = std::make_unique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp new file mode 100644 index 00000000..7dd3748f --- /dev/null +++ b/src/protocols/SinglePixel.cpp @@ -0,0 +1,125 @@ +#include "SinglePixel.hpp" +#include + +CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) { + LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex()); + + color = col_.getAsHex(); + + g_pHyprRenderer->makeEGLCurrent(); + + opaque = col_.a >= 1.F; + + texture = makeShared(DRM_FORMAT_ARGB8888, (uint8_t*)&color, 4, Vector2D{1, 1}); + + resource = CWLBufferResource::create(makeShared(client, 1, id)); + + success = texture->m_iTexID; + + if (!success) + Debug::log(ERR, "Failed creating a single pixel texture: null texture id"); +} + +CSinglePixelBuffer::~CSinglePixelBuffer() { + ; +} + +Aquamarine::eBufferCapability CSinglePixelBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; +} + +Aquamarine::eBufferType CSinglePixelBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; +} + +bool CSinglePixelBuffer::isSynchronous() { + return true; +} + +void CSinglePixelBuffer::update(const CRegion& damage) { + ; +} + +Aquamarine::SDMABUFAttrs CSinglePixelBuffer::dmabuf() { + return {.success = false}; +} + +std::tuple CSinglePixelBuffer::beginDataPtr(uint32_t flags) { + return {(uint8_t*)&color, DRM_FORMAT_ARGB8888, 4}; +} + +void CSinglePixelBuffer::endDataPtr() { + ; +} + +bool CSinglePixelBuffer::good() { + return resource->good(); +} + +CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color) { + buffer = makeShared(id, client, color); + + if (!buffer->good()) + return; + + buffer->resource->buffer = buffer; + + listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::singlePixel->destroyResource(this); + }); +} + +CSinglePixelBufferResource::~CSinglePixelBufferResource() { + ; +} + +bool CSinglePixelBufferResource::good() { + return buffer->good(); +} + +CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); }); + resource->setOnDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); }); + + resource->setCreateU32RgbaBuffer([this](CWpSinglePixelBufferManagerV1* res, uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a) { + CColor color{r / (float)std::numeric_limits::max(), g / (float)std::numeric_limits::max(), b / (float)std::numeric_limits::max(), + a / (float)std::numeric_limits::max()}; + const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared(id, resource->client(), color)); + + if (!RESOURCE->good()) { + res->noMemory(); + PROTO::singlePixel->m_vBuffers.pop_back(); + return; + } + }); +} + +bool CSinglePixelBufferManagerResource::good() { + return resource->resource(); +} + +CSinglePixelProtocol::CSinglePixelProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CSinglePixelProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CSinglePixelProtocol::destroyResource(CSinglePixelBufferManagerResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CSinglePixelProtocol::destroyResource(CSinglePixelBufferResource* surf) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == surf; }); +} diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp new file mode 100644 index 00000000..ab74825c --- /dev/null +++ b/src/protocols/SinglePixel.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "single-pixel-buffer-v1.hpp" +#include "types/Buffer.hpp" + +class CSinglePixelBuffer : public IHLBuffer { + public: + CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col); + virtual ~CSinglePixelBuffer(); + + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); + virtual bool isSynchronous(); + virtual void update(const CRegion& damage); + virtual Aquamarine::SDMABUFAttrs dmabuf(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + // + bool good(); + bool success = false; + + private: + uint32_t color = 0x00000000; + + struct { + CHyprSignalListener resourceDestroy; + } listeners; +}; + +class CSinglePixelBufferResource { + public: + CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color); + ~CSinglePixelBufferResource(); + + bool good(); + + private: + SP buffer; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; +}; + +class CSinglePixelBufferManagerResource { + public: + CSinglePixelBufferManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CSinglePixelProtocol : public IWaylandProtocol { + public: + CSinglePixelProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CSinglePixelBufferManagerResource* resource); + void destroyResource(CSinglePixelBufferResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vBuffers; + + friend class CSinglePixelBufferManagerResource; + friend class CSinglePixelBufferResource; +}; + +namespace PROTO { + inline UP singlePixel; +}; \ No newline at end of file From 968f6a6013409a6e6eab1545b28cd5e0cc49ce87 Mon Sep 17 00:00:00 2001 From: Trianta <56975502+Trimutex@users.noreply.github.com> Date: Sun, 29 Sep 2024 23:52:58 -0500 Subject: [PATCH 228/298] meson: fix arch build with new protocol --- protocols/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/protocols/meson.build b/protocols/meson.build index d686bacd..6990b5a7 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -63,6 +63,7 @@ protocols = [ wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', + wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', ] wl_protocols = [] From f6387536f62454f82039b42f641cd8c44153ad47 Mon Sep 17 00:00:00 2001 From: Trianta <56975502+Trimutex@users.noreply.github.com> Date: Mon, 30 Sep 2024 00:15:25 -0500 Subject: [PATCH 229/298] protocol: fix missing include --- src/protocols/SinglePixel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 7dd3748f..0595cce5 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -1,5 +1,6 @@ #include "SinglePixel.hpp" #include +#include "render/Renderer.hpp" CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) { LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex()); From 3ddb16bd5bb7146d125a7d68e4e9f3b54c381a20 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:25:39 +0100 Subject: [PATCH 230/298] compositor/wayland: up the max buffer size to avoid disconnects when app hangs --- CMakeLists.txt | 2 +- src/Compositor.cpp | 4 +++ src/helpers/ByteOperations.hpp | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/helpers/ByteOperations.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ee9cd2e2..3440af4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ pkg_check_modules( IMPORTED_TARGET xkbcommon uuid - wayland-server + wayland-server>=1.22.90 wayland-protocols cairo pango diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 232ba4a6..25d73db0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -28,6 +28,7 @@ #include "desktop/LayerSurface.hpp" #include "render/Renderer.hpp" #include "xwayland/XWayland.hpp" +#include "helpers/ByteOperations.hpp" #include #include @@ -229,6 +230,9 @@ void CCompositor::initServer(std::string socketName, int socketFd) { if (envEnabled("HYPRLAND_TRACE")) Debug::trace = true; + // set the buffer size to 1MB to avoid disconnects due to an app hanging for a short while + wl_display_set_default_max_buffer_size(m_sWLDisplay, 1_MB); + Aquamarine::SBackendOptions options; options.logFunction = aqLog; diff --git a/src/helpers/ByteOperations.hpp b/src/helpers/ByteOperations.hpp new file mode 100644 index 00000000..6d9507ff --- /dev/null +++ b/src/helpers/ByteOperations.hpp @@ -0,0 +1,52 @@ +#pragma once + +#define ULL unsigned long long +#define LD long double + +constexpr ULL operator""_kB(const ULL BYTES) { + return BYTES * 1024; +} +constexpr ULL operator""_MB(const ULL BYTES) { + return BYTES * 1024 * 1024; +} +constexpr ULL operator""_GB(const ULL BYTES) { + return BYTES * 1024 * 1024 * 1024; +} +constexpr ULL operator""_TB(const ULL BYTES) { + return BYTES * 1024 * 1024 * 1024 * 1024; +} +constexpr LD operator""_kB(const LD BYTES) { + return BYTES * 1024; +} +constexpr LD operator""_MB(const LD BYTES) { + return BYTES * 1024 * 1024; +} +constexpr LD operator""_GB(const LD BYTES) { + return BYTES * 1024 * 1024 * 1024; +} +constexpr LD operator""_TB(const LD BYTES) { + return BYTES * 1024 * 1024 * 1024 * 1024; +} + +template +using __acceptable_byte_operation_type = typename std::enable_if::value || std::is_trivially_constructible::value>::type; + +template > +constexpr X kBtoBytes(const X kB) { + return kB * 1024; +} +template > +constexpr X MBtoBytes(const X MB) { + return MB * 1024 * 1024; +} +template > +constexpr X GBtoBytes(const X GB) { + return GB * 1024 * 1024 * 1024; +} +template > +constexpr X TBtoBytes(const X TB) { + return TB * 1024 * 1024 * 1024 * 1024; +} + +#undef ULL +#undef LD \ No newline at end of file From 68fd32c81013541f237e2046779185b41db1538e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:27:10 +0100 Subject: [PATCH 231/298] byteoperations: add missing header --- src/helpers/ByteOperations.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/ByteOperations.hpp b/src/helpers/ByteOperations.hpp index 6d9507ff..13e98500 100644 --- a/src/helpers/ByteOperations.hpp +++ b/src/helpers/ByteOperations.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #define ULL unsigned long long #define LD long double From 6bd339714160505ab1c4aade659eca6fe426fea5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:40:38 +0100 Subject: [PATCH 232/298] wlr-output-management: accept 0 refresh rates fixes #7879 --- src/protocols/OutputManagement.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index dcc7a62d..3fd0cf6c 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -467,11 +467,16 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE, "Invalid mode"); return; } + if (refresh == 0) { + LOGM(LOG, " | configHead for {}: refreshRate 0, using old refresh rate of {:.2f}Hz", pMonitor->szName, pMonitor->refreshRate); + refresh = std::round(pMonitor->refreshRate * 1000.F); + } + state.committedProperties |= OUTPUT_HEAD_COMMITTED_CUSTOM_MODE; state.customMode = {{w, h}, (uint32_t)refresh}; From 5c6c300abfea2539ffad9bcbf857325eec5ab765 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:42:36 +0100 Subject: [PATCH 233/298] wayland/output: send geometry in updateState --- src/protocols/core/Output.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 394dc8e2..7b88e0a8 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -21,8 +21,6 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni PROTO::outputs.at(monitor->szName)->destroyResource(this); }); - resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(), - monitor->output->model.c_str(), monitor->transform); if (resource->version() >= 4) { resource->sendName(monitor->szName.c_str()); resource->sendDescription(monitor->szDescription.c_str()); @@ -57,6 +55,9 @@ void CWLOutputResource::updateState() { resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); + resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(), + monitor->output->model.c_str(), monitor->transform); + if (resource->version() >= 2) resource->sendDone(); } From e2426942e5716a742ea353d2a1de7d7760fbbb41 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 2 Oct 2024 11:22:19 +0200 Subject: [PATCH 234/298] layout: add auto_group to control default grouping (#7883) --- src/config/ConfigDescriptions.hpp | 6 +++ src/config/ConfigManager.cpp | 1 + src/events/Windows.cpp | 2 +- src/layout/DwindleLayout.cpp | 21 +-------- src/layout/IHyprLayout.cpp | 73 ++++++++++++++++++++++++------- src/layout/IHyprLayout.hpp | 1 + src/layout/MasterLayout.cpp | 20 --------- 7 files changed, 68 insertions(+), 56 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 3a91a808..385d4e59 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -772,6 +772,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_GRADIENT, .data = SConfigOptionDescription::SGradientData{"0x66775500"}, }, + SConfigOptionDescription{ + .value = "group:auto_group", + .description = "automatically group new windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, /* * group:groupbar: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ad6e1871..2ce07ff0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -377,6 +377,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 544483b1..1c2c7cfa 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -322,7 +322,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->updateWindowData(); if (PWINDOW->m_bIsFloating) { - g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); + g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); PWINDOW->m_bCreatedOverFullscreen = true; // size and move rules diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index ed47fa44..04cbf21d 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -340,26 +340,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir return; } - // if it's a group, add the window - if (OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group - && pWindow->canBeGroupedInto(OPENINGON->pWindow.lock()) && !m_vOverrideFocalPoint) { // we are not moving window - m_lDwindleNodesData.remove(*PNODE); - - static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - - OPENINGON->pWindow->setGroupCurrent(pWindow); - pWindow->applyGroupRules(); - pWindow->updateWindowDecos(); - recalculateWindow(pWindow); - - if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); - - return; - } - - // If it's not, get the node under our cursor + // get the node under our cursor m_lDwindleNodesData.push_back(SDwindleNodeData()); const auto NEWPARENT = &m_lDwindleNodesData.back(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index c5a5373c..0fb78d02 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -9,23 +9,25 @@ #include "../xwayland/XSurface.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { - if (pWindow->m_bIsFloating) { + CBox desiredGeometry = {}; + g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); + + if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; + } else + pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height); + + pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; + + bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow); + if (autoGrouped) + return; + + if (pWindow->m_bIsFloating) onWindowCreatedFloating(pWindow); - } else { - CBox desiredGeometry = {}; - g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); - - if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; - } else { - pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height); - } - - pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; - + else onWindowCreatedTiling(pWindow, direction); - } } void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { @@ -178,6 +180,47 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } } +bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { + static auto AUTOGROUP = CConfigValue("group:auto_group"); + if ((*AUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. + && g_pCompositor->m_pLastWindow.lock() // check if a focused window exists. + && g_pCompositor->m_pLastWindow != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && g_pCompositor->m_pLastWindow->m_pWorkspace == + pWindow + ->m_pWorkspace // fix for multimonitor: when there is a focused group in monitor 1 and monitor 2 is empty, this enables adding the first window of monitor 2 when using the mouse to focus it. + && g_pCompositor->m_pLastWindow->m_sGroupData.pNextWindow.lock() // check if the focused window is a group + && pWindow->canBeGroupedInto(g_pCompositor->m_pLastWindow.lock()) // check if the new window can be grouped into the focused group + && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + + switch (pWindow->m_bIsFloating) { + case false: + if (g_pCompositor->m_pLastWindow->m_bIsFloating) + pWindow->m_bIsFloating = true; + break; + + case true: + if (!g_pCompositor->m_pLastWindow->m_bIsFloating) + pWindow->m_bIsFloating = false; + break; + } + + static auto USECURRPOS = CConfigValue("group:insert_after_current"); + (*USECURRPOS ? g_pCompositor->m_pLastWindow : g_pCompositor->m_pLastWindow->getGroupTail())->insertWindowToGroup(pWindow); + + g_pCompositor->m_pLastWindow->setGroupCurrent(pWindow); + pWindow->applyGroupRules(); + pWindow->updateWindowDecos(); + recalculateWindow(pWindow); + + if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) + pWindow->addWindowDeco(std::make_unique(pWindow)); + + return true; + } + + return false; +} + void IHyprLayout::onBeginDragWindow() { const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock(); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 7e0d5704..f9e2de0d 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -47,6 +47,7 @@ class IHyprLayout { virtual void onWindowCreated(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT) = 0; virtual void onWindowCreatedFloating(PHLWINDOW); + virtual bool onWindowCreatedAutoGroup(PHLWINDOW); /* Return tiled status diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 8fa324b0..04a6ea29 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -116,26 +116,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire return; } - // if it's a group, add the window - if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group - && pWindow->canBeGroupedInto(OPENINGON->pWindow.lock())) { - - m_lMasterNodesData.remove(*PNODE); - - static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - - OPENINGON->pWindow->setGroupCurrent(pWindow); - pWindow->applyGroupRules(); - pWindow->updateWindowDecos(); - recalculateWindow(pWindow); - - if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); - - return; - } - pWindow->applyGroupRules(); static auto PDROPATCURSOR = CConfigValue("master:drop_at_cursor"); From de68e065fe861d7ca01eca267df4c305bc6e73c2 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 2 Oct 2024 22:25:25 +0200 Subject: [PATCH 235/298] layout: fix dragging a window into a group after e242694 (#7976) --- src/layout/IHyprLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 0fb78d02..4b5c9d4f 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -552,10 +552,10 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_vLastFloatingSize = PSAVEDSIZE; - // move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back. + // move to narnia because we don't wanna find our own node. onWindowCreated should apply the coords back. pWindow->m_vPosition = Vector2D(-999999, -999999); - onWindowCreatedTiling(pWindow); + onWindowCreated(pWindow); pWindow->m_vRealPosition.setValue(PSAVEDPOS); pWindow->m_vRealSize.setValue(PSAVEDSIZE); From aed529f695bc62f5fa45dc94c545275ebb49bc48 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 3 Oct 2024 22:00:44 +0000 Subject: [PATCH 236/298] renderer: fix uvBR calculation (#7975) --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 417a3ff8..b081fd81 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1134,7 +1134,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPcurrent.size.y; const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); - uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y)); + uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y)); uvTL = uvTL + TOADDTL; // TODO: make this passed to the func. Might break in the future. From 1ed925b69c2854a3f345cbeb7dca29a6286ca926 Mon Sep 17 00:00:00 2001 From: Theo Paris Date: Fri, 4 Oct 2024 01:41:27 -0700 Subject: [PATCH 237/298] internal: fix missing include directive (#7984) This should fix building with clang. --- src/helpers/SdDaemon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index 48c23e6b..80944794 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace Systemd { From 8e237b006fa7dd348a58c85f1aa46a8a835533c2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 00:43:59 +0100 Subject: [PATCH 238/298] xdg-output: minor cleanups --- src/protocols/XDGOutput.cpp | 32 ++++++++++++++------------------ src/protocols/XDGOutput.hpp | 6 +++--- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 5d620667..0cdadd43 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -29,29 +29,20 @@ void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver return; } - RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); - RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); - RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { this->onManagerGetXDGOutput(mgr, id, output); }); + RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); }); + RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); }); + RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { onManagerGetXDGOutput(mgr, id, output); }); } CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); - static auto P3 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { - const auto PMONITOR = std::any_cast(param); - for (auto const& o : m_vXDGOutputs) { - if (o->monitor == PMONITOR) - o->monitor = nullptr; - } - }); } void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) { - const auto OUTPUT = CWLOutputResource::fromResource(outputResource); - - const auto PMONITOR = OUTPUT->monitor.get(); - - const auto CLIENT = mgr->client(); + const auto OUTPUT = CWLOutputResource::fromResource(outputResource); + const auto PMONITOR = OUTPUT->monitor.lock(); + const auto CLIENT = mgr->client(); CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique(makeShared(CLIENT, mgr->version(), id), PMONITOR)).get(); #ifndef NO_XWAYLAND @@ -66,8 +57,12 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 return; } - if (!PMONITOR) + if (!PMONITOR) { + LOGM(ERR, "New xdg_output from client {:x} ({}) has no CMonitor?!", (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland"); return; + } + + LOGM(LOG, "New xdg_output for {}: client {:x} ({})", PMONITOR->szName, (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland"); const auto XDGVER = pXDGOutput->resource->version(); @@ -84,8 +79,9 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 } void CXDGOutputProtocol::updateAllOutputs() { - for (auto const& o : m_vXDGOutputs) { + LOGM(LOG, "updating all xdg_output heads"); + for (auto const& o : m_vXDGOutputs) { if (!o->monitor) continue; @@ -97,7 +93,7 @@ void CXDGOutputProtocol::updateAllOutputs() { // -CXDGOutput::CXDGOutput(SP resource_, CMonitor* monitor_) : monitor(monitor_), resource(resource_) { +CXDGOutput::CXDGOutput(SP resource_, SP monitor_) : monitor(monitor_), resource(resource_) { if (!resource->resource()) return; diff --git a/src/protocols/XDGOutput.hpp b/src/protocols/XDGOutput.hpp index 73e7d53e..15d86cc7 100644 --- a/src/protocols/XDGOutput.hpp +++ b/src/protocols/XDGOutput.hpp @@ -9,12 +9,12 @@ class CXDGOutputProtocol; class CXDGOutput { public: - CXDGOutput(SP resource, CMonitor* monitor_); + CXDGOutput(SP resource, SP monitor_); void sendDetails(); private: - CMonitor* monitor = nullptr; + WP monitor; SP resource; std::optional overridePosition; @@ -30,12 +30,12 @@ class CXDGOutputProtocol : public IWaylandProtocol { CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void updateAllOutputs(); private: void onManagerResourceDestroy(wl_resource* res); void onOutputResourceDestroy(wl_resource* res); void onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource); - void updateAllOutputs(); // std::vector> m_vManagerResources; From 3a5052a714e2a6a2b002dddcac1204960b298f8b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 00:44:16 +0100 Subject: [PATCH 239/298] compositor: update all xdg outputs on arrange --- src/Compositor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 25d73db0..b4d10c88 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -23,6 +23,7 @@ #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" #include "protocols/XDGShell.hpp" +#include "protocols/XDGOutput.hpp" #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" @@ -2869,6 +2870,8 @@ void CCompositor::arrangeMonitors() { else m->xwaylandScale = 1.f; } + + PROTO::xdgOutput->updateAllOutputs(); } void CCompositor::enterUnsafeState() { From a815b14bf1b69b92f82bd09f6845fbdbb2fbe516 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 00:44:30 +0100 Subject: [PATCH 240/298] monitor: cleanup and modernize scheduleDone --- src/helpers/Monitor.cpp | 25 ++++++++++++++----------- src/helpers/Monitor.hpp | 6 +++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a9569699..03a1d92b 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -12,6 +12,7 @@ #include "../protocols/DRMSyncobj.hpp" #include "../protocols/core/Output.hpp" #include "../managers/PointerManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../protocols/core/Compositor.hpp" #include "sync/SyncTimeline.hpp" #include @@ -789,20 +790,22 @@ CBox CMonitor::logicalBox() { return {vecPosition, vecSize}; } -static void onDoneSource(void* data) { - auto pMonitor = (CMonitor*)data; - - if (!PROTO::outputs.contains(pMonitor->szName)) - return; - - PROTO::outputs.at(pMonitor->szName)->sendDone(); -} - void CMonitor::scheduleDone() { - if (doneSource) + if (doneScheduled) return; - doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this); + doneScheduled = true; + + g_pEventLoopManager->doLater([M = self] { + if (!M) // if M is gone, we got destroyed, doesn't matter. + return; + + if (!PROTO::outputs.contains(M->szName)) + return; + + PROTO::outputs.at(M->szName)->sendDone(); + M->doneScheduled = false; + }); } bool CMonitor::attemptDirectScanout() { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 97d9f8ab..2a2edab6 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -190,10 +190,10 @@ class CMonitor { } private: - void setupDefaultWS(const SMonitorRule&); - WORKSPACEID findAvailableDefaultWS(); + void setupDefaultWS(const SMonitorRule&); + WORKSPACEID findAvailableDefaultWS(); - wl_event_source* doneSource = nullptr; + bool doneScheduled = false; struct { CHyprSignalListener frame; From 595eb89f6e16df0e19916e3c02bf5ceac5a61c57 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 5 Oct 2024 00:52:53 +0100 Subject: [PATCH 241/298] renderer: Fix resize artifacts (stretching, bumps) (#7499) --- src/desktop/WLSurface.cpp | 2 +- src/render/OpenGL.cpp | 3 +++ src/render/Renderer.cpp | 42 +++++++++++++++++++++++---------------- src/render/Renderer.hpp | 33 +++++++++++++++--------------- 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 45050e35..5e88f507 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -62,7 +62,7 @@ bool CWLSurface::small() const { const auto O = m_pWindowOwner.lock(); - return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1; + return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1; } Vector2D CWLSurface::correctSmallVec() const { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 4f22d6aa..a16c2d62 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1423,6 +1423,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, 0x2900 /* GL_CLAMP */); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, 0x2900); + if (m_RenderData.useNearestNeighbor) { glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b081fd81..310d45af 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -150,7 +150,7 @@ static void renderSurface(SP surface, int x, int y, void* da const auto& TEXTURE = surface->current.texture; const auto RDATA = (SRenderData*)data; - const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; + const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; // this is bad, probably has been logged elsewhere. Means the texture failed // uploading to the GPU. @@ -180,6 +180,7 @@ static void renderSurface(SP surface, int x, int y, void* da // however, if surface buffer w / h < box, we need to adjust them const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr; + // center the surface if it's smaller than the viewport we assign it if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) { const auto CORRECT = PSURFACE->correctSmallVec(); const auto SIZE = PSURFACE->getViewporterCorrectedSize(); @@ -195,17 +196,6 @@ static void renderSurface(SP surface, int x, int y, void* da } } - if (!INTERACTIVERESIZEINPROGRESS && PSURFACE && PWINDOW && PWINDOW->m_vRealSize.goal().floor() > PWINDOW->m_vReportedSize && PWINDOW->m_vReportedSize > Vector2D{1, 1}) { - Vector2D size = - Vector2D{windowBox.w * (PWINDOW->m_vReportedSize.x / PWINDOW->m_vRealSize.value().x), windowBox.h * (PWINDOW->m_vReportedSize.y / PWINDOW->m_vRealSize.value().y)}; - Vector2D correct = Vector2D{windowBox.w, windowBox.h} - size; - - windowBox.translate(correct / 2.0); - - windowBox.w = size.x; - windowBox.h = size.y; - } - } else { // here we clamp to 2, these might be some tiny specks windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)}; if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { @@ -231,6 +221,8 @@ static void renderSurface(SP surface, int x, int y, void* da return; // invisible } + const auto PROJSIZEUNSCALED = windowBox.size(); + windowBox.scale(RDATA->pMonitor->scale); windowBox.round(); @@ -239,7 +231,7 @@ static void renderSurface(SP surface, int x, int y, void* da DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; - g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); + g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->pMonitor->self.lock(), RDATA->surface == surface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); // check for fractional scale surfaces misaligning the buffer size // in those cases it's better to just force nearest neighbor @@ -1083,7 +1075,8 @@ void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) { g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } -void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { +void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, SP pMonitor, bool main, const Vector2D& projSize, + const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; Vector2D uvBR = Vector2D(1, 1); @@ -1112,6 +1105,22 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPscale); + const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->current.scale && !pSurface->current.viewport.hasDestination; + const auto EXPECTED_SIZE = + ((pSurface->current.viewport.hasDestination ? pSurface->current.viewport.destination : pSurface->current.bufferSize / pSurface->current.scale) * pMonitor->scale) + .round(); + if (!SCALE_UNAWARE && (EXPECTED_SIZE.x < projSize.x || EXPECTED_SIZE.y < projSize.y)) { + // this will not work with shm AFAIK, idk why. + // NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much + const auto FIX = projSize / EXPECTED_SIZE; + uvBR = uvBR * FIX; + } + g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL; g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR; @@ -1127,7 +1136,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPm_pXDGSurface->current.geometry; // ignore X and Y, adjust uv - if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { + if (geom.x != 0 || geom.y != 0 || geom.width > projSizeUnscaled.x || geom.height > projSizeUnscaled.y) { const auto XPERC = (double)geom.x / (double)pSurface->current.size.x; const auto YPERC = (double)geom.y / (double)pSurface->current.size.y; const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x; @@ -1137,8 +1146,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPm_vRealSize.value(); + auto maxSize = projSizeUnscaled; if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize(); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b730d589..7d1ae4b1 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -49,22 +49,23 @@ class CHyprRenderer { CHyprRenderer(); ~CHyprRenderer(); - void renderMonitor(CMonitor* pMonitor); - void arrangeLayersForMonitor(const MONITORID&); - void damageSurface(SP, double, double, double scale = 1.0); - void damageWindow(PHLWINDOW, bool forceFull = false); - void damageBox(CBox*, bool skipFrameSchedule = false); - void damageBox(const int& x, const int& y, const int& w, const int& h); - void damageRegion(const CRegion&); - void damageMonitor(CMonitor*); - void damageMirrorsWith(CMonitor*, const CRegion&); - bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); - bool shouldRenderWindow(PHLWINDOW, CMonitor*); - bool shouldRenderWindow(PHLWINDOW); - void ensureCursorRenderingMode(); - bool shouldRenderCursor(); - void setCursorHidden(bool hide); - void calculateUVForSurface(PHLWINDOW, SP, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); + void renderMonitor(CMonitor* pMonitor); + void arrangeLayersForMonitor(const MONITORID&); + void damageSurface(SP, double, double, double scale = 1.0); + void damageWindow(PHLWINDOW, bool forceFull = false); + void damageBox(CBox*, bool skipFrameSchedule = false); + void damageBox(const int& x, const int& y, const int& w, const int& h); + void damageRegion(const CRegion&); + void damageMonitor(CMonitor*); + void damageMirrorsWith(CMonitor*, const CRegion&); + bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); + bool shouldRenderWindow(PHLWINDOW, CMonitor*); + bool shouldRenderWindow(PHLWINDOW); + void ensureCursorRenderingMode(); + bool shouldRenderCursor(); + void setCursorHidden(bool hide); + void calculateUVForSurface(PHLWINDOW, SP, SP pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, + bool fixMisalignedFSV1 = false); std::tuple getRenderTimes(CMonitor* pMonitor); // avg max min void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); From 46bf87c8d1f053284a266d5f0b470073a48a92f6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:37:12 +0100 Subject: [PATCH 242/298] monitor: use a scope guard for disconnect events --- src/helpers/Monitor.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 03a1d92b..f105ea66 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -229,6 +229,12 @@ void CMonitor::onConnect(bool noRule) { } void CMonitor::onDisconnect(bool destroy) { + CScopeGuard x = {[this]() { + if (g_pCompositor->m_bIsShuttingDown) + return; + g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); + EMIT_HOOK_EVENT("monitorRemoved", this); + }}; if (renderTimer) { wl_event_source_remove(renderTimer); @@ -341,9 +347,6 @@ void CMonitor::onDisconnect(bool destroy) { g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; } std::erase_if(g_pCompositor->m_vMonitors, [&](SP& el) { return el.get() == this; }); - - g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); - EMIT_HOOK_EVENT("monitorRemoved", this); } void CMonitor::addDamage(const pixman_region32_t* rg) { From 6fbfeefc7119ff86411b765aa26b4bffbaa825ec Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:40:03 +0100 Subject: [PATCH 243/298] protocolmgr: don't expose the fallback output --- src/managers/ProtocolManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 8bcc857a..157fa76c 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -86,7 +86,8 @@ CProtocolManager::CProtocolManager() { // ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after // this event is emitted iirc. - if (M->isMirror()) + // also ignore the fallback + if (M->isMirror() || M == g_pCompositor->m_pUnsafeOutput) return; if (PROTO::outputs.contains(M->szName)) From 52c09196219313aec2ec1d3d543669bff834d746 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:41:44 +0100 Subject: [PATCH 244/298] monitor: arrange monitors on connect and disconnect --- src/helpers/Monitor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index f105ea66..c6cef41f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -36,6 +36,7 @@ CMonitor::~CMonitor() { } void CMonitor::onConnect(bool noRule) { + CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }}; if (output->supportsExplicit) { inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); @@ -234,6 +235,7 @@ void CMonitor::onDisconnect(bool destroy) { return; g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); EMIT_HOOK_EVENT("monitorRemoved", this); + g_pCompositor->arrangeMonitors(); }}; if (renderTimer) { From 3ca699debffbb97085888835a33f20d0c542128d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:57:18 +0100 Subject: [PATCH 245/298] opengl: use GL_CLAMP_TO_EDGE instead of GL_CLAMP avoid error spam on select hw --- src/render/OpenGL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a16c2d62..833e2ccb 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1423,8 +1423,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); - glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, 0x2900 /* GL_CLAMP */); - glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, 0x2900); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (m_RenderData.useNearestNeighbor) { glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); From 0ec6072a290051a03ab66cfb9bc616b2f5540e64 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 16:36:57 +0100 Subject: [PATCH 246/298] single-pixel: set buffer size to 1,1 --- src/protocols/SinglePixel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 0595cce5..d800539d 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -17,6 +17,8 @@ CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor co success = texture->m_iTexID; + size = {1, 1}; + if (!success) Debug::log(ERR, "Failed creating a single pixel texture: null texture id"); } From 0c7a7e2d569eeed9d6025f3eef4ea0690d90845d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 6 Oct 2024 12:04:13 +0100 Subject: [PATCH 247/298] version: bump to 0.44.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 8298bb08..a8ab6c96 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.43.0 +0.44.0 From da86aac0f5c5c3604351961b901f62cdf7186a10 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 6 Oct 2024 14:07:07 +0100 Subject: [PATCH 248/298] security-context: implement protocol fixes #7318 --- CMakeLists.txt | 1 + protocols/meson.build | 1 + src/Compositor.cpp | 12 ++ src/managers/ProtocolManager.cpp | 55 ++++++++ src/managers/ProtocolManager.hpp | 2 + src/protocols/SecurityContext.cpp | 214 ++++++++++++++++++++++++++++++ src/protocols/SecurityContext.hpp | 83 ++++++++++++ src/protocols/TextInputV1.hpp | 2 +- src/protocols/WaylandProtocol.cpp | 4 + src/protocols/WaylandProtocol.hpp | 1 + 10 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 src/protocols/SecurityContext.cpp create mode 100644 src/protocols/SecurityContext.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3440af4a..1bac29ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -331,6 +331,7 @@ protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) +protocolnew("staging/security-context" "security-context-v1" false) protocolwayland() diff --git a/protocols/meson.build b/protocols/meson.build index 6990b5a7..3fa2ef2f 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -64,6 +64,7 @@ protocols = [ wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', + wayland_protocol_dir / 'staging/security-context/security-context-v1.xml', ] wl_protocols = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index b4d10c88..f00e1e34 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -24,6 +24,7 @@ #include "protocols/LayerShell.hpp" #include "protocols/XDGShell.hpp" #include "protocols/XDGOutput.hpp" +#include "protocols/SecurityContext.hpp" #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" @@ -210,11 +211,22 @@ void CCompositor::setRandomSplash() { static std::vector> pendingOutputs; +// + +static bool filterGlobals(const wl_client* client, const wl_global* global, void* data) { + if (!PROTO::securityContext->isClientSandboxed(client)) + return true; + + return !g_pProtocolManager || !g_pProtocolManager->isGlobalPrivileged(global); +} + // void CCompositor::initServer(std::string socketName, int socketFd) { m_sWLDisplay = wl_display_create(); + wl_display_set_global_filter(m_sWLDisplay, ::filterGlobals, nullptr); + m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay); // register crit signal handler diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 157fa76c..6366eefe 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -45,6 +45,7 @@ #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/XDGDialog.hpp" #include "../protocols/SinglePixel.hpp" +#include "../protocols/SecurityContext.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -155,6 +156,7 @@ CProtocolManager::CProtocolManager() { PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); PROTO::singlePixel = std::make_unique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); + PROTO::securityContext = std::make_unique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) @@ -225,9 +227,62 @@ CProtocolManager::~CProtocolManager() { PROTO::toplevelExport.reset(); PROTO::globalShortcuts.reset(); PROTO::xdgDialog.reset(); + PROTO::singlePixel.reset(); + PROTO::securityContext.reset(); PROTO::lease.reset(); PROTO::sync.reset(); PROTO::mesaDRM.reset(); PROTO::linuxDma.reset(); } + +bool CProtocolManager::isGlobalPrivileged(const wl_global* global) { + if (!global) + return false; + + for (auto& [k, v] : PROTO::outputs) { + if (global == v->getGlobal()) + return false; + } + + // this is a static whitelist of allowed protocols, + // outputs are dynamic so we checked them above + // clang-format off + static const std::vector ALLOWED_WHITELIST = { + PROTO::seat->getGlobal(), + PROTO::data->getGlobal(), + PROTO::compositor->getGlobal(), + PROTO::subcompositor->getGlobal(), + PROTO::shm->getGlobal(), + PROTO::viewport->getGlobal(), + PROTO::tearing->getGlobal(), + PROTO::fractional->getGlobal(), + PROTO::cursorShape->getGlobal(), + PROTO::idleInhibit->getGlobal(), + PROTO::relativePointer->getGlobal(), + PROTO::xdgDecoration->getGlobal(), + PROTO::alphaModifier->getGlobal(), + PROTO::pointerGestures->getGlobal(), + PROTO::shortcutsInhibit->getGlobal(), + PROTO::textInputV1->getGlobal(), + PROTO::textInputV3->getGlobal(), + PROTO::constraints->getGlobal(), + PROTO::activation->getGlobal(), + PROTO::idle->getGlobal(), + PROTO::ime->getGlobal(), + PROTO::virtualKeyboard->getGlobal(), + PROTO::virtualPointer->getGlobal(), + PROTO::serverDecorationKDE->getGlobal(), + PROTO::tablet->getGlobal(), + PROTO::presentation->getGlobal(), + PROTO::xdgShell->getGlobal(), + PROTO::xdgDialog->getGlobal(), + PROTO::singlePixel->getGlobal(), + PROTO::sync ? PROTO::sync->getGlobal() : nullptr, + PROTO::mesaDRM ? PROTO::mesaDRM->getGlobal() : nullptr, + PROTO::linuxDma ? PROTO::linuxDma->getGlobal() : nullptr, + }; + // clang-format on + + return std::find(ALLOWED_WHITELIST.begin(), ALLOWED_WHITELIST.end(), global) == ALLOWED_WHITELIST.end(); +} diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 1b6d31b6..d5629e9e 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -11,6 +11,8 @@ class CProtocolManager { CProtocolManager(); ~CProtocolManager(); + bool isGlobalPrivileged(const wl_global* global); + private: std::unordered_map m_mModeChangeListeners; diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp new file mode 100644 index 00000000..b93ef448 --- /dev/null +++ b/src/protocols/SecurityContext.cpp @@ -0,0 +1,214 @@ +#include "SecurityContext.hpp" +#include "../Compositor.hpp" +#include + +static int onListenFdEvent(int fd, uint32_t mask, void* data) { + auto sc = (CSecurityContext*)data; + sc->onListen(mask); + return 0; +} + +static int onCloseFdEvent(int fd, uint32_t mask, void* data) { + auto sc = (CSecurityContext*)data; + sc->onClose(mask); + return 0; +} + +SP CSecurityContextSandboxedClient::create(int clientFD) { + auto p = SP(new CSecurityContextSandboxedClient(clientFD)); + if (!p->client) + return nullptr; + return p; +} + +static void onSecurityContextClientDestroy(wl_listener* l, void* d) { + CSecurityContextSandboxedClient* client = wl_container_of(l, client, destroyListener); + client->onDestroy(); +} + +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD) { + client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); + if (!client) + return; + + destroyListener.notify = ::onSecurityContextClientDestroy; + wl_client_add_destroy_late_listener(client, &destroyListener); +} + +CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { + wl_list_remove(&destroyListener.link); +} + +void CSecurityContextSandboxedClient::onDestroy() { + std::erase_if(PROTO::securityContext->m_vSandboxedClients, [this](const auto& e) { return e.get() == this; }); +} + +CSecurityContext::CSecurityContext(SP resource_, int listenFD_, int closeFD_) : listenFD(listenFD_), closeFD(closeFD_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpSecurityContextV1* r) { + LOGM(LOG, "security_context at 0x{:x}: resource destroyed, keeping context until fd hangup", (uintptr_t)this); + resource = nullptr; + }); + resource->setOnDestroy([this](CWpSecurityContextV1* r) { + LOGM(LOG, "security_context at 0x{:x}: resource destroyed, keeping context until fd hangup", (uintptr_t)this); + resource = nullptr; + }); + + LOGM(LOG, "New security_context at 0x{:x}", (uintptr_t)this); + + resource->setSetSandboxEngine([this](CWpSecurityContextV1* r, const char* engine) { + if (!sandboxEngine.empty()) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox engine already set"); + return; + } + + if (committed) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); + return; + } + + sandboxEngine = engine ? engine : "(null)"; + LOGM(LOG, "security_context at 0x{:x} sets engine to {}", (uintptr_t)this, sandboxEngine); + }); + + resource->setSetAppId([this](CWpSecurityContextV1* r, const char* appid) { + if (!appID.empty()) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox appid already set"); + return; + } + + if (committed) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); + return; + } + + appID = appid ? appid : "(null)"; + LOGM(LOG, "security_context at 0x{:x} sets appid to {}", (uintptr_t)this, appID); + }); + + resource->setSetInstanceId([this](CWpSecurityContextV1* r, const char* instance) { + if (!instanceID.empty()) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox instance already set"); + return; + } + + if (committed) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); + return; + } + + instanceID = instance ? instance : "(null)"; + LOGM(LOG, "security_context at 0x{:x} sets instance to {}", (uintptr_t)this, instanceID); + }); + + resource->setCommit([this](CWpSecurityContextV1* r) { + committed = true; + + LOGM(LOG, "security_context at 0x{:x} commits", (uintptr_t)this); + + listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD, WL_EVENT_READABLE, ::onListenFdEvent, this); + closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD, 0, ::onCloseFdEvent, this); + + if (!listenSource || !closeSource) { + r->noMemory(); + return; + } + }); +} + +CSecurityContext::~CSecurityContext() { + if (listenSource) + wl_event_source_remove(listenSource); + if (closeSource) + wl_event_source_remove(closeSource); +} + +bool CSecurityContext::good() { + return resource->resource(); +} + +void CSecurityContext::onListen(uint32_t mask) { + if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) { + LOGM(ERR, "security_context at 0x{:x} got an error in listen", (uintptr_t)this); + PROTO::securityContext->destroyContext(this); + return; + } + + if (!(mask & WL_EVENT_READABLE)) + return; + + int clientFD = accept(listenFD, nullptr, nullptr); + if (clientFD < 0) { + LOGM(ERR, "security_context at 0x{:x} couldn't accept", (uintptr_t)this); + return; + } + + auto newClient = CSecurityContextSandboxedClient::create(clientFD); + if (!newClient) { + LOGM(ERR, "security_context at 0x{:x} couldn't create a client", (uintptr_t)this); + close(clientFD); + return; + } + + PROTO::securityContext->m_vSandboxedClients.emplace_back(newClient); + + LOGM(LOG, "security_context at 0x{:x} got a new wl_client 0x{:x}", (uintptr_t)this, (uintptr_t)newClient->client); +} + +void CSecurityContext::onClose(uint32_t mask) { + if (!(mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP))) + return; + + PROTO::securityContext->destroyContext(this); +} + +CSecurityContextManagerResource::CSecurityContextManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpSecurityContextManagerV1* r) { PROTO::securityContext->destroyResource(this); }); + resource->setOnDestroy([this](CWpSecurityContextManagerV1* r) { PROTO::securityContext->destroyResource(this); }); + + resource->setCreateListener([](CWpSecurityContextManagerV1* r, uint32_t id, int32_t lfd, int32_t cfd) { + const auto RESOURCE = + PROTO::securityContext->m_vContexts.emplace_back(makeShared(makeShared(r->client(), r->version(), id), lfd, cfd)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::securityContext->m_vContexts.pop_back(); + return; + } + }); +} + +bool CSecurityContextManagerResource::good() { + return resource->resource(); +} + +CSecurityContextProtocol::CSecurityContextProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CSecurityContextProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CSecurityContextProtocol::destroyResource(CSecurityContextManagerResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CSecurityContextProtocol::destroyContext(CSecurityContext* context) { + std::erase_if(m_vContexts, [&](const auto& other) { return other.get() == context; }); +} + +bool CSecurityContextProtocol::isClientSandboxed(const wl_client* client) { + return std::find_if(m_vSandboxedClients.begin(), m_vSandboxedClients.end(), [client](const auto& e) { return e->client == client; }) != m_vSandboxedClients.end(); +} diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp new file mode 100644 index 00000000..bcbb69b2 --- /dev/null +++ b/src/protocols/SecurityContext.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "security-context-v1.hpp" + +class CSecurityContext { + public: + CSecurityContext(SP resource_, int listenFD_, int closeFD_); + ~CSecurityContext(); + + bool good(); + + std::string sandboxEngine, appID, instanceID; + int listenFD = -1, closeFD = -1; + + void onListen(uint32_t mask); + void onClose(uint32_t mask); + + private: + SP resource; + + wl_event_source * listenSource = nullptr, *closeSource = nullptr; + + bool committed = false; +}; + +class CSecurityContextManagerResource { + public: + CSecurityContextManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CSecurityContextSandboxedClient { + public: + static SP create(int clientFD); + ~CSecurityContextSandboxedClient(); + + void onDestroy(); + + wl_listener destroyListener; + + private: + CSecurityContextSandboxedClient(int clientFD); + + wl_client* client = nullptr; + + friend class CSecurityContextProtocol; + friend class CSecurityContext; +}; + +class CSecurityContextProtocol : public IWaylandProtocol { + public: + CSecurityContextProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + bool isClientSandboxed(const wl_client* client); + + private: + void destroyResource(CSecurityContextManagerResource* resource); + + void destroyContext(CSecurityContext* context); + + // + std::vector> m_vManagers; + std::vector> m_vContexts; + std::vector> m_vSandboxedClients; + + friend class CSecurityContextManagerResource; + friend class CSecurityContext; + friend class CSecurityContextSandboxedClient; +}; + +namespace PROTO { + inline UP securityContext; +}; \ No newline at end of file diff --git a/src/protocols/TextInputV1.hpp b/src/protocols/TextInputV1.hpp index 9bee452c..d3b0d71b 100644 --- a/src/protocols/TextInputV1.hpp +++ b/src/protocols/TextInputV1.hpp @@ -60,7 +60,7 @@ class CTextInputV1 { friend class CTextInputV1Protocol; }; -class CTextInputV1Protocol : IWaylandProtocol { +class CTextInputV1Protocol : public IWaylandProtocol { public: CTextInputV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 0782d323..00b112b0 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -40,3 +40,7 @@ IWaylandProtocol::~IWaylandProtocol() { void IWaylandProtocol::removeGlobal() { wl_global_remove(m_pGlobal); } + +wl_global* IWaylandProtocol::getGlobal() { + return m_pGlobal; +} diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index 87c75ed8..056322ac 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -53,6 +53,7 @@ class IWaylandProtocol { virtual void onDisplayDestroy(); virtual void removeGlobal(); + virtual wl_global* getGlobal(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; From 4e41cda27ed4176005082436cb35878335e63fae Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 6 Oct 2024 15:08:26 +0100 Subject: [PATCH 249/298] security-context: close client fds after disconnect --- src/protocols/SecurityContext.cpp | 7 ++++--- src/protocols/SecurityContext.hpp | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index b93ef448..b42c3a97 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -14,8 +14,8 @@ static int onCloseFdEvent(int fd, uint32_t mask, void* data) { return 0; } -SP CSecurityContextSandboxedClient::create(int clientFD) { - auto p = SP(new CSecurityContextSandboxedClient(clientFD)); +SP CSecurityContextSandboxedClient::create(int clientFD_) { + auto p = SP(new CSecurityContextSandboxedClient(clientFD_)); if (!p->client) return nullptr; return p; @@ -26,7 +26,7 @@ static void onSecurityContextClientDestroy(wl_listener* l, void* d) { client->onDestroy(); } -CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD) { +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) : clientFD(clientFD_) { client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); if (!client) return; @@ -37,6 +37,7 @@ CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD) { CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { wl_list_remove(&destroyListener.link); + close(clientFD); } void CSecurityContextSandboxedClient::onDestroy() { diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index bcbb69b2..76313bcf 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -47,9 +47,10 @@ class CSecurityContextSandboxedClient { wl_listener destroyListener; private: - CSecurityContextSandboxedClient(int clientFD); + CSecurityContextSandboxedClient(int clientFD_); - wl_client* client = nullptr; + wl_client* client = nullptr; + int clientFD = -1; friend class CSecurityContextProtocol; friend class CSecurityContext; From 97444ed7a8a83406970fcc05907db1110435b59b Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Mon, 7 Oct 2024 14:22:55 +0200 Subject: [PATCH 250/298] layout: fix auto group when opening a new window in a non-focused workspace using window rules (#8006) --- src/layout/IHyprLayout.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 4b5c9d4f..f090e87d 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -181,33 +181,34 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { - static auto AUTOGROUP = CConfigValue("group:auto_group"); - if ((*AUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. - && g_pCompositor->m_pLastWindow.lock() // check if a focused window exists. - && g_pCompositor->m_pLastWindow != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. - && g_pCompositor->m_pLastWindow->m_pWorkspace == - pWindow - ->m_pWorkspace // fix for multimonitor: when there is a focused group in monitor 1 and monitor 2 is empty, this enables adding the first window of monitor 2 when using the mouse to focus it. - && g_pCompositor->m_pLastWindow->m_sGroupData.pNextWindow.lock() // check if the focused window is a group - && pWindow->canBeGroupedInto(g_pCompositor->m_pLastWindow.lock()) // check if the new window can be grouped into the focused group - && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + static auto PAUTOGROUP = CConfigValue("group:auto_group"); + PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? + g_pCompositor->m_pLastWindow.lock() : + g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); + + if ((*PAUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. + && OPENINGON // check if OPENINGON exists. + && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group + && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON + && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. switch (pWindow->m_bIsFloating) { case false: - if (g_pCompositor->m_pLastWindow->m_bIsFloating) + if (OPENINGON->m_bIsFloating) pWindow->m_bIsFloating = true; break; case true: - if (!g_pCompositor->m_pLastWindow->m_bIsFloating) + if (!OPENINGON->m_bIsFloating) pWindow->m_bIsFloating = false; break; } static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? g_pCompositor->m_pLastWindow : g_pCompositor->m_pLastWindow->getGroupTail())->insertWindowToGroup(pWindow); + (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); - g_pCompositor->m_pLastWindow->setGroupCurrent(pWindow); + OPENINGON->setGroupCurrent(pWindow); pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); From 5bf7b1e1fadf743f41ec765f7545370e3d7ccf96 Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Mon, 7 Oct 2024 15:44:03 +0000 Subject: [PATCH 251/298] flake.nix: add xdph follows fixes a duplicate hyprland-protocols instance sometimes being created due to xdph not following hyprlands instance --- flake.lock | 29 +++-------------------------- flake.nix | 5 +++-- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/flake.lock b/flake.lock index 2579dd11..2f9fbbc6 100644 --- a/flake.lock +++ b/flake.lock @@ -78,31 +78,6 @@ "type": "github" } }, - "hyprland-protocols_2": { - "inputs": { - "nixpkgs": [ - "xdph", - "nixpkgs" - ], - "systems": [ - "xdph", - "systems" - ] - }, - "locked": { - "lastModified": 1721326555, - "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", - "owner": "hyprwm", - "repo": "hyprland-protocols", - "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprland-protocols", - "type": "github" - } - }, "hyprlang": { "inputs": { "hyprutils": [ @@ -221,7 +196,9 @@ }, "xdph": { "inputs": { - "hyprland-protocols": "hyprland-protocols_2", + "hyprland-protocols": [ + "hyprland-protocols" + ], "hyprlang": [ "hyprlang" ], diff --git a/flake.nix b/flake.nix index ee5af6a1..cfd003f8 100644 --- a/flake.nix +++ b/flake.nix @@ -51,6 +51,7 @@ url = "github:hyprwm/xdg-desktop-portal-hyprland"; inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; + inputs.hyprland-protocols.follows = "hyprland-protocols"; inputs.hyprlang.follows = "hyprlang"; inputs.hyprutils.follows = "hyprutils"; inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; @@ -98,13 +99,13 @@ inherit (pkgsFor.${system}) # hyprland-packages - + hyprland hyprland-debug hyprland-legacy-renderer hyprland-unwrapped # hyprland-extras - + xdg-desktop-portal-hyprland ; hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland; From 46d990f1b632dc52a667d876a32cffb24ef72bd8 Mon Sep 17 00:00:00 2001 From: Artur Manuel Date: Mon, 7 Oct 2024 19:49:19 +0100 Subject: [PATCH 252/298] feat: add a custom made treewide formatter (#7992) --- .gitignore | 4 +++ flake.lock | 77 +++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 22 ++++++++++++-- nix/default.nix | 2 +- nix/formatter.nix | 64 +++++++++++++++++++++++++++++++++++++++ nix/overlays.nix | 4 +-- 6 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 nix/formatter.nix diff --git a/.gitignore b/.gitignore index 2e158a4e..a7934790 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ _deps build/ result* +/.pre-commit-config.yaml /.vscode/ /.idea/ .envrc @@ -39,3 +40,6 @@ PKGBUILD src/version.h hyprpm/Makefile hyprctl/Makefile + +**/.#*.* +**/#*.*# diff --git a/flake.lock b/flake.lock index 2f9fbbc6..85069a74 100644 --- a/flake.lock +++ b/flake.lock @@ -29,6 +29,43 @@ "type": "github" } }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "hyprcursor": { "inputs": { "hyprlang": [ @@ -166,6 +203,45 @@ "type": "github" } }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1728092656, + "narHash": "sha256-eMeCTJZ5xBeQ0f9Os7K8DThNVSo9gy4umZLDfF5q6OM=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "1211305a5b237771e13fcca0c51e60ad47326a9a", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "aquamarine": "aquamarine", @@ -175,6 +251,7 @@ "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks", "systems": "systems", "xdph": "xdph" } diff --git a/flake.nix b/flake.nix index cfd003f8..e3419ef8 100644 --- a/flake.nix +++ b/flake.nix @@ -56,6 +56,11 @@ inputs.hyprutils.follows = "hyprutils"; inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; }; + + pre-commit-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = inputs @ { @@ -77,7 +82,7 @@ pkgsCrossFor = eachSystem (system: crossSystem: import nixpkgs { localSystem = system; - crossSystem = crossSystem; + inherit crossSystem; overlays = with self.overlays; [ hyprland-packages hyprland-extras @@ -92,6 +97,18 @@ self.packages.${system}) // { inherit (self.packages.${system}) xdg-desktop-portal-hyprland; + pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { + src = ./.; + hooks = { + hyprland-treewide-formatter = { + enable = true; + entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter"; + pass_filenames = false; + excludes = ["subprojects"]; + always_run = true; + }; + }; + }; }); packages = eachSystem (system: { @@ -120,10 +137,11 @@ hardeningDisable = ["fortify"]; inputsFrom = [pkgsFor.${system}.hyprland]; packages = [pkgsFor.${system}.clang-tools]; + inherit (self.checks.${system}.pre-commit-check) shellHook; }; }); - formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra); + formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix {}); nixosModules.default = import ./nix/module.nix inputs; homeManagerModules.default = import ./nix/hm-module.nix self; diff --git a/nix/default.nix b/nix/default.nix index 6f086ccc..d463e271 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -68,7 +68,7 @@ in inherit version; src = cleanSourceWith { - filter = name: type: let + filter = name: _type: let baseName = baseNameOf (toString name); in ! (hasSuffix ".nix" baseName); diff --git a/nix/formatter.nix b/nix/formatter.nix new file mode 100644 index 00000000..66721c2c --- /dev/null +++ b/nix/formatter.nix @@ -0,0 +1,64 @@ +{ + writeShellApplication, + deadnix, + statix, + alejandra, + llvmPackages_19, + fd, +}: +writeShellApplication { + name = "hyprland-treewide-formatter"; + runtimeInputs = [ + deadnix + statix + alejandra + llvmPackages_19.clang-tools + fd + ]; + text = '' + # shellcheck disable=SC2148 + + # common excludes + excludes="subprojects" + + nix_format() { + if [ "$*" = 0 ]; then + fd '.*\.nix' . -E "$excludes" -x statix fix -- {} \; + fd '.*\.nix' . -E "$excludes" -X deadnix -e -- {} \; -X alejandra {} \; + elif [ -d "$1" ]; then + fd '.*\.nix' "$1" -E "$excludes" -i -x statix fix -- {} \; + fd '.*\.nix' "$1" -E "$excludes" -i -X deadnix -e -- {} \; -X alejandra {} \; + else + statix fix -- "$1" + deadnix -e "$1" + alejandra "$1" + fi + } + + cpp_format() { + if [ "$*" = 0 ] || [ "$1" = "." ]; then + fd '.*\.cpp' . -E "$excludes" | xargs clang-format --verbose -i + elif [ -d "$1" ]; then + fd '.*\.cpp' "$1" -E "$excludes" | xargs clang-format --verbose -i + else + clang-format --verbose -i "$1" + fi + } + + for i in "$@"; do + case ''${i##*.} in + "nix") + nix_format "$i" + ;; + "cpp") + cpp_format "$i" + ;; + *) + nix_format "$i" + cpp_format "$i" + ;; + esac + + done + ''; +} diff --git a/nix/overlays.nix b/nix/overlays.nix index 2b2788e7..a78f3003 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -29,7 +29,7 @@ in { self.overlays.udis86 # Hyprland packages themselves - (final: prev: let + (final: _prev: let date = mkDate (self.lastModifiedDate or "19700101"); in { hyprland = final.callPackage ./default.nix { @@ -70,7 +70,7 @@ in { # this version is the one used in the git submodule, and allows us to # fetch the source without '?submodules=1' udis86 = final: prev: { - udis86-hyprland = prev.udis86.overrideAttrs (self: super: { + udis86-hyprland = prev.udis86.overrideAttrs (_self: _super: { src = final.fetchFromGitHub { owner = "canihavesomecoffee"; repo = "udis86"; From a364df4c9e9a73f0460665463028539e3abe4a8b Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:52:49 +0000 Subject: [PATCH 253/298] internal: use clampWindowSize to unify min/maxsize handling (#8014) modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp --- src/desktop/Window.cpp | 20 ++++++++++++++------ src/desktop/Window.hpp | 1 + src/events/Windows.cpp | 22 ++-------------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index feced807..fa85dc07 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -736,9 +736,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority); - m_vRealSize = - Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); + clampWindowSize(std::nullopt, m_sWindowData.maxSize.value()); + } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); } } else if (r.szRule.starts_with("minsize")) { try { @@ -751,9 +750,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } m_sWindowData.minSize = CWindowOverridableVar(VEC, priority); - m_vRealSize = - Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); + clampWindowSize(m_sWindowData.minSize.value(), std::nullopt); + if (m_sGroupData.pNextWindow.expired()) setHidden(false); } catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); } @@ -1253,6 +1251,16 @@ int CWindow::surfacesCount() { return no; } +void CWindow::clampWindowSize(const std::optional minSize, const std::optional maxSize) { + const Vector2D REALSIZE = m_vRealSize.goal(); + const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{0.f, 0.f}), maxSize.value_or(Vector2D{INFINITY, INFINITY})); + const Vector2D DELTA = REALSIZE - NEWSIZE; + + m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0; + m_vRealSize = NEWSIZE; + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE); +} + bool CWindow::isFullscreen() { return m_sFullscreenState.internal != FSMODE_NONE; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index d14248c5..9baf57c4 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -429,6 +429,7 @@ class CWindow { bool onSpecialWorkspace(); void activate(bool force = false); int surfacesCount(); + void clampWindowSize(const std::optional minSize, const std::optional maxSize); bool isFullscreen(); bool isEffectiveInternalFSMode(const eFullscreenMode); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 1c2c7cfa..37f29130 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -751,26 +751,8 @@ void Events::listener_commitWindow(void* owner, void* data) { const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; - if (MAXSIZE > Vector2D{1, 1}) { - const auto REALSIZE = PWINDOW->m_vRealSize.goal(); - Vector2D newSize = REALSIZE; - - if (MAXSIZE.x < newSize.x) - newSize.x = MAXSIZE.x; - if (MAXSIZE.y < newSize.y) - newSize.y = MAXSIZE.y; - if (MINSIZE.x > newSize.x) - newSize.x = MINSIZE.x; - if (MINSIZE.y > newSize.y) - newSize.y = MINSIZE.y; - - const Vector2D DELTA = REALSIZE - newSize; - - PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0; - PWINDOW->m_vRealSize = newSize; - g_pXWaylandManager->setWindowSize(PWINDOW, newSize); - g_pHyprRenderer->damageWindow(PWINDOW); - } + PWINDOW->clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional{MAXSIZE} : std::nullopt); + g_pHyprRenderer->damageWindow(PWINDOW); } if (!PWINDOW->m_pWorkspace->m_bVisible) From 0d70c442538ba0d1efc63558c859c184367c95ad Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:23:48 -0500 Subject: [PATCH 254/298] screencopy: fix screencopy frames not being cleaned up (#8017) --------- Co-authored-by: Vaxry --- src/protocols/Screencopy.cpp | 13 ++++++++----- src/protocols/Screencopy.hpp | 4 ++-- src/protocols/ToplevelExport.cpp | 16 +++++++++++----- src/protocols/ToplevelExport.hpp | 4 ++-- subprojects/hyprland-protocols | 2 +- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 63024541..1b06a1fa 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -394,12 +394,12 @@ void CScreencopyProtocol::bindManager(wl_client* client, void* data, uint32_t ve void CScreencopyProtocol::destroyResource(CScreencopyClient* client) { std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; }); } void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) { std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; }); } void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { @@ -412,8 +412,11 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { // share frame if correct output for (auto const& f : m_vFramesAwaitingWrite) { + if (!f) + continue; + if (!f->pMonitor || !f->buffer) { - framesToRemove.push_back(f); + framesToRemove.emplace_back(f); continue; } @@ -425,10 +428,10 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { f->client->lastFrame.reset(); ++f->client->frameCounter; - framesToRemove.push_back(f); + framesToRemove.emplace_back(f); } for (auto const& f : framesToRemove) { - destroyResource(f.get()); + std::erase(m_vFramesAwaitingWrite, f); } } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index cbc56edb..e121d0fd 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -54,7 +54,7 @@ class CScreencopyFrame { bool good(); - SP self; + WP self; WP client; private: @@ -92,7 +92,7 @@ class CScreencopyProtocol : public IWaylandProtocol { private: std::vector> m_vFrames; - std::vector> m_vFramesAwaitingWrite; + std::vector> m_vFramesAwaitingWrite; std::vector> m_vClients; SP m_pSoftwareCursorTimer; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index b28a827a..66df5926 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -354,12 +354,12 @@ void CToplevelExportProtocol::bindManager(wl_client* client, void* data, uint32_ void CToplevelExportProtocol::destroyResource(CToplevelExportClient* client) { std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; }); } void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) { std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; }); } void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { @@ -370,11 +370,17 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { // share frame if correct output for (auto const& f : m_vFramesAwaitingWrite) { - if (!f->pWindow || !validMapped(f->pWindow)) { - framesToRemove.push_back(f); + if (!f) + continue; + + if (!validMapped(f->pWindow)) { + framesToRemove.emplace_back(f); continue; } + if (!f->pWindow) + continue; + const auto PWINDOW = f->pWindow; if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) @@ -394,7 +400,7 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { } for (auto const& f : framesToRemove) { - destroyResource(f.get()); + std::erase(m_vFramesAwaitingWrite, f); } } diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 638b69f0..9686431b 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -45,7 +45,7 @@ class CToplevelExportFrame { bool good(); - SP self; + WP self; WP client; private: @@ -85,7 +85,7 @@ class CToplevelExportProtocol : IWaylandProtocol { private: std::vector> m_vClients; std::vector> m_vFrames; - std::vector> m_vFramesAwaitingWrite; + std::vector> m_vFramesAwaitingWrite; void shareFrame(CToplevelExportFrame* frame); bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now); diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index e06482e0..c7c3f4cd 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit e06482e0e611130cd1929f75e8c1cf679e57d161 +Subproject commit c7c3f4cd0faed21fc90ba6bd06fe4f3e0e057ea8 From 4711796d3800f1a6673eccbd50e8e8a02bb0fd85 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 09:54:25 +0100 Subject: [PATCH 255/298] config: give simple help for super+q not working only on default config :P --- src/config/ConfigManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 2ce07ff0..018deaa7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -867,8 +867,10 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { if (result.error && !std::any_cast(m_pConfig->getConfigValue("debug:suppress_errors"))) g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1) - g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", - CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); + g_pHyprError->queueCreate( + "Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + + " )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland", + CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); else if (*PENABLEEXPLICIT != prevEnabledExplicit) g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); else From 45e82199fb29f422ebbbfe06ce03022dfb6d645e Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Tue, 8 Oct 2024 12:20:41 +0200 Subject: [PATCH 256/298] layout: add drag_into_group to control merging dragging windows (#8004) --- src/config/ConfigDescriptions.hpp | 6 ++ src/config/ConfigManager.cpp | 1 + src/layout/IHyprLayout.cpp | 65 +++++++++++++------ .../decorations/CHyprGroupBarDecoration.cpp | 16 +++-- 4 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 385d4e59..2ca230be 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -778,6 +778,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "group:drag_into_group", + .description = "whether dragging a window into a unlocked group will merge them. Options: 0 (disabled), 1 (enabled), 2 (only when dragging into the groupbar)", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"}, + }, /* * group:groupbar: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 018deaa7..9a5283fa 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -378,6 +378,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:drag_into_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f090e87d..f249d2b5 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -193,17 +193,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. - switch (pWindow->m_bIsFloating) { - case false: - if (OPENINGON->m_bIsFloating) - pWindow->m_bIsFloating = true; - break; - - case true: - if (!OPENINGON->m_bIsFloating) - pWindow->m_bIsFloating = false; - break; - } + pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); @@ -335,21 +325,47 @@ void IHyprLayout::onEndDragWindow() { g_pInputManager->currentlyDraggedWindow.reset(); g_pInputManager->m_bWasDraggingWindow = true; - if (DRAGGINGWINDOW->m_bDraggingTiled) { - DRAGGINGWINDOW->m_bIsFloating = false; - g_pInputManager->refocus(); - changeWindowFloatingMode(DRAGGINGWINDOW); - DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; - } else if (g_pInputManager->dragMode == MBIND_MOVE) { + if (g_pInputManager->dragMode == MBIND_MOVE) { g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); - PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING | FLOATING_ONLY, DRAGGINGWINDOW); + PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING, DRAGGINGWINDOW); if (pWindow) { if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW)) return; - if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) { + bool denied = false; + if (!pWindow->m_bIsFloating && !DRAGGINGWINDOW->m_bDraggingTiled) + denied = true; + + static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !denied) { + if (DRAGGINGWINDOW->m_bDraggingTiled) { + changeWindowFloatingMode(DRAGGINGWINDOW); + DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; + DRAGGINGWINDOW->m_bDraggingTiled = false; + } + + if (DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock()) { + std::vector members; + PHLWINDOW curr = DRAGGINGWINDOW->getGroupHead(); + do { + members.push_back(curr); + curr = curr->m_sGroupData.pNextWindow.lock(); + } while (curr != members[0]); + + for (auto it = members.begin(); it != members.end(); ++it) { + (*it)->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members + if (pWindow->m_bIsFloating) + (*it)->m_vRealSize = pWindow->m_vRealSize.goal(); // match the size of group members + } + } + + DRAGGINGWINDOW->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of the window + + if (pWindow->m_bIsFloating) + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize.goal()); // match the size of the window + static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); pWindow->setGroupCurrent(DRAGGINGWINDOW); @@ -361,6 +377,13 @@ void IHyprLayout::onEndDragWindow() { } } + if (DRAGGINGWINDOW->m_bDraggingTiled) { + DRAGGINGWINDOW->m_bIsFloating = false; + g_pInputManager->refocus(); + changeWindowFloatingMode(DRAGGINGWINDOW); + DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; + } + g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pCompositor->focusWindow(DRAGGINGWINDOW); @@ -553,10 +576,10 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_vLastFloatingSize = PSAVEDSIZE; - // move to narnia because we don't wanna find our own node. onWindowCreated should apply the coords back. + // move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back. pWindow->m_vPosition = Vector2D(-999999, -999999); - onWindowCreated(pWindow); + onWindowCreatedTiling(pWindow); pWindow->m_vRealPosition.setValue(PSAVEDPOS); pWindow->m_vRealSize.setValue(PSAVEDSIZE); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 4cdb9043..ef6c81e6 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -402,8 +402,9 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { } bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWINDOW pDraggedWindow) { - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); - if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock())) + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2)) return false; const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_fBarHeight + BAR_PADDING_OUTER_VERT) / 2 : pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; @@ -435,6 +436,9 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND // restores the group for (auto it = members.begin(); it != members.end(); ++it) { + (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members + if (pWindowInsertAfter->m_bIsFloating) + (*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize.goal(); // match the size of group members if (std::next(it) != members.end()) (*it)->m_sGroupData.pNextWindow = *std::next(it); else @@ -442,9 +446,13 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND } members[0]->m_sGroupData.head = true; members[0]->m_sGroupData.locked = WASLOCKED; - } else { + } else g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pDraggedWindow); - } + + pDraggedWindow->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of the window + + if (pWindowInsertAfter->m_bIsFloating) + g_pXWaylandManager->setWindowSize(pDraggedWindow, pWindowInsertAfter->m_vRealSize.goal()); // match the size of the window pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); From b3a7e3109bf2b7b4422424471130197dc08baeb1 Mon Sep 17 00:00:00 2001 From: davc0n Date: Tue, 8 Oct 2024 12:42:51 +0200 Subject: [PATCH 257/298] misc: refactor version command (#8027) Fixes a minor spacing issue if git status is not dirty. Additionally now should be easier to extend it eventually. --- src/main.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 279e1ce1..57bb5507 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -116,11 +116,20 @@ int main(int argc, char** argv) { return 0; } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { + auto result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH; + auto dirty = std::string(GIT_DIRTY); + if (!dirty.empty()) + result += " " + dirty; + auto commitMsg = trim(GIT_COMMIT_MESSAGE); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); - std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + - "\n\nflags: (if any)\n"; + result += " (" + commitMsg + ")."; + + result += "\nDate: " + std::string(GIT_COMMIT_DATE); + result += "\nTag: " + std::string(GIT_TAG) + ", commits: " + std::string(GIT_COMMITS); + result += "\nbuilt against aquamarine " + std::string(AQUAMARINE_VERSION); + + result += "\n\nflags: (if any)\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; From e0cfbec66b97edb2957508152f32e77a1b181afc Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 8 Oct 2024 13:15:53 +0100 Subject: [PATCH 258/298] keybinds: fixup xkb_states for resolve_by_sym fixes #7750 --- src/devices/IKeyboard.cpp | 10 ++++++++++ src/devices/IKeyboard.hpp | 5 +++-- src/managers/KeybindManager.cpp | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 13440169..3300f252 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -178,13 +178,18 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { if (xkbState) xkb_state_unref(xkbState); + if (xkbSymState) + xkb_state_unref(xkbSymState); + xkbState = nullptr; xkbStaticState = nullptr; + xkbSymState = nullptr; if (keymap) { Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); xkbStaticState = xkb_state_new(keymap); xkbState = xkb_state_new(keymap); + xkbSymState = xkb_state_new(keymap); return; } @@ -230,6 +235,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { xkbState = xkb_state_new(KEYMAP); xkbStaticState = xkb_state_new(KEYMAP); + xkbSymState = xkb_state_new(KEYMAP); xkb_keymap_unref(KEYMAP); xkb_context_unref(PCONTEXT); @@ -252,6 +258,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { xkbState = xkb_state_new(NEWKEYMAP); xkbStaticState = xkb_state_new(NEWKEYMAP); + xkbSymState = xkb_state_new(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP); xkb_context_unref(PCONTEXT); @@ -332,6 +339,9 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); + if (xkbSymState) + xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group); + if (!updateModifiersState()) return; diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index 759b2f58..76d2c31b 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -82,8 +82,9 @@ class IKeyboard : public IHID { bool keymapOverridden = false; xkb_layout_index_t activeLayout = 0; - xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr; - xkb_keymap* xkbKeymap = nullptr; + xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr, + *xkbSymState = nullptr /* Same as static but gets layouts */; + xkb_keymap* xkbKeymap = nullptr; struct { uint32_t depressed = 0, latched = 0, locked = 0, group = 0; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index cd47bf71..d893e258 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -376,7 +376,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput - const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE); + const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); if (handleInternalKeybinds(internalKeysym)) From 1bf63dfdcd76c09137b4647f9af2c5ebc9fc6e34 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:59:15 +0100 Subject: [PATCH 259/298] protocols: Add support for hyprland-ctm-control-v1 (#8023) * initial ctm support * flake.lock: update * Meson: bump required versions and add ctm proto --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 6 ++- flake.lock | 36 ++++++------- meson.build | 2 +- protocols/meson.build | 3 +- src/helpers/Monitor.cpp | 6 +++ src/helpers/Monitor.hpp | 5 ++ src/managers/ProtocolManager.cpp | 3 ++ src/protocols/CTMControl.cpp | 86 ++++++++++++++++++++++++++++++++ src/protocols/CTMControl.hpp | 44 ++++++++++++++++ src/render/Renderer.cpp | 5 ++ 10 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 src/protocols/CTMControl.cpp create mode 100644 src/protocols/CTMControl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bac29ab..4de449dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) -pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine) +pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") @@ -274,7 +274,7 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) -pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0) +pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0) if(hyprland_protocols_dep_FOUND) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") @@ -301,6 +301,8 @@ protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wayland-drm" true) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) + protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false) protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false) diff --git a/flake.lock b/flake.lock index 85069a74..de9a4dce 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1727261104, - "narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=", + "lastModified": 1728326504, + "narHash": "sha256-dQXAj+4d6neY7ldCiH6gNym3upP49PVxRzEPxXlD9Aw=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "b82fdaff917582a9d568969e15e61b398c71e990", + "rev": "65dd97b5d21e917295159bbef1d52e06963f4eb0", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1727532803, - "narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=", + "lastModified": 1727821604, + "narHash": "sha256-hNw5J6xatedqytYowx0mJKgctjA4lQARZFdgnzM2RpM=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f", + "rev": "d60e1e01e6e6633ef1c87148b9137cc1dd39263d", "type": "github" }, "original": { @@ -102,11 +102,11 @@ ] }, "locked": { - "lastModified": 1727451107, - "narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=", + "lastModified": 1728345020, + "narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3", + "rev": "a7c183800e74f337753de186522b9017a07a8cee", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1725997860, - "narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=", + "lastModified": 1728168612, + "narHash": "sha256-AnB1KfiXINmuiW7BALYrKqcjCnsLZPifhb/7BsfPbns=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876", + "rev": "f054f2e44d6a0b74607a6bc0f52dba337a3db38e", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1727348695, - "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", + "lastModified": 1728018373, + "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", + "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", "type": "github" }, "original": { @@ -293,11 +293,11 @@ ] }, "locked": { - "lastModified": 1727524473, - "narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=", + "lastModified": 1728166987, + "narHash": "sha256-w6dVTguAn9zJ+7aPOhBQgDz8bn6YZ7b56cY8Kg5HJRI=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26", + "rev": "fb9c8d665af0588bb087f97d0f673ddf0d501787", "type": "github" }, "original": { diff --git a/meson.build b/meson.build index 3545f46a..e9bbb99d 100644 --- a/meson.build +++ b/meson.build @@ -30,7 +30,7 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif -aquamarine = dependency('aquamarine') +aquamarine = dependency('aquamarine', version: '>=0.4.2') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') xcb_dep = dependency('xcb', required: get_option('xwayland')) diff --git a/protocols/meson.build b/protocols/meson.build index 3fa2ef2f..2c0d06d1 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -7,7 +7,7 @@ wayland_protos = dependency( hyprland_protos = dependency( 'hyprland-protocols', - version: '>=0.2', + version: '>=0.4', fallback: 'hyprland-protocols', ) @@ -36,6 +36,7 @@ protocols = [ hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml', wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index c6cef41f..f3e7de4e 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -813,6 +813,12 @@ void CMonitor::scheduleDone() { }); } +void CMonitor::setCTM(const Mat3x3& ctm_) { + ctm = ctm_; + ctmUpdated = true; + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME); +} + bool CMonitor::attemptDirectScanout() { if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked) return false; // do not DS if this monitor is being mirrored. Will break the functionality. diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2a2edab6..f5068dba 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -131,6 +131,10 @@ class CMonitor { CMonitor* pMirrorOf = nullptr; std::vector mirrors; + // ctm + Mat3x3 ctm = Mat3x3::identity(); + bool ctmUpdated = false; + // for tearing PHLWINDOWREF solitaryClient; @@ -179,6 +183,7 @@ class CMonitor { CBox logicalBox(); void scheduleDone(); bool attemptDirectScanout(); + void setCTM(const Mat3x3& ctm); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6366eefe..25a34657 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -46,6 +46,7 @@ #include "../protocols/XDGDialog.hpp" #include "../protocols/SinglePixel.hpp" #include "../protocols/SecurityContext.hpp" +#include "../protocols/CTMControl.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -157,6 +158,7 @@ CProtocolManager::CProtocolManager() { PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); PROTO::singlePixel = std::make_unique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::securityContext = std::make_unique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); + PROTO::ctm = std::make_unique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) @@ -229,6 +231,7 @@ CProtocolManager::~CProtocolManager() { PROTO::xdgDialog.reset(); PROTO::singlePixel.reset(); PROTO::securityContext.reset(); + PROTO::ctm.reset(); PROTO::lease.reset(); PROTO::sync.reset(); diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp new file mode 100644 index 00000000..f2a54c6f --- /dev/null +++ b/src/protocols/CTMControl.cpp @@ -0,0 +1,86 @@ +#include "CTMControl.hpp" +#include "../Compositor.hpp" +#include "core/Output.hpp" + +CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CHyprlandCtmControlManagerV1* pMgr) { PROTO::ctm->destroyResource(this); }); + resource->setOnDestroy([this](CHyprlandCtmControlManagerV1* pMgr) { PROTO::ctm->destroyResource(this); }); + + resource->setSetCtmForOutput([this](CHyprlandCtmControlManagerV1* r, wl_resource* output, wl_fixed_t mat0, wl_fixed_t mat1, wl_fixed_t mat2, wl_fixed_t mat3, wl_fixed_t mat4, + wl_fixed_t mat5, wl_fixed_t mat6, wl_fixed_t mat7, wl_fixed_t mat8) { + const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output); + + if (!OUTPUTRESOURCE) + return; // ?! + + const auto PMONITOR = OUTPUTRESOURCE->monitor.lock(); + + if (!PMONITOR) + return; // ?!?! + + const std::array MAT = {wl_fixed_to_double(mat0), wl_fixed_to_double(mat1), wl_fixed_to_double(mat2), wl_fixed_to_double(mat3), wl_fixed_to_double(mat4), + wl_fixed_to_double(mat5), wl_fixed_to_double(mat6), wl_fixed_to_double(mat7), wl_fixed_to_double(mat8)}; + + for (auto& el : MAT) { + if (el < 0.F) { + resource->error(HYPRLAND_CTM_CONTROL_MANAGER_V1_ERROR_INVALID_MATRIX, "a matrix component was < 0"); + return; + } + } + + ctms[PMONITOR->szName] = MAT; + + LOGM(LOG, "CTM set for output {}: {}", PMONITOR->szName, ctms.at(PMONITOR->szName).toString()); + }); + + resource->setCommit([this](CHyprlandCtmControlManagerV1* r) { + LOGM(LOG, "Committing ctms to outputs"); + + for (auto& m : g_pCompositor->m_vMonitors) { + if (!ctms.contains(m->szName)) { + PROTO::ctm->setCTM(m, Mat3x3::identity()); + continue; + } + + PROTO::ctm->setCTM(m, ctms.at(m->szName)); + } + }); +} + +CHyprlandCTMControlResource::~CHyprlandCTMControlResource() { + for (auto& m : g_pCompositor->m_vMonitors) { + PROTO::ctm->setCTM(m, Mat3x3::identity()); + } +} + +bool CHyprlandCTMControlResource::good() { + return resource->resource(); +} + +CHyprlandCTMControlProtocol::CHyprlandCTMControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(LOG, "New CTM Manager at 0x{:x}", (uintptr_t)RESOURCE.get()); +} + +void CHyprlandCTMControlProtocol::destroyResource(CHyprlandCTMControlResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CHyprlandCTMControlProtocol::setCTM(SP monitor, const Mat3x3& ctm) { + monitor->setCTM(ctm); +} diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp new file mode 100644 index 00000000..08f1b0e8 --- /dev/null +++ b/src/protocols/CTMControl.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "hyprland-ctm-control-v1.hpp" +#include + +class CMonitor; + +class CHyprlandCTMControlResource { + public: + CHyprlandCTMControlResource(SP resource_); + ~CHyprlandCTMControlResource(); + + bool good(); + + private: + SP resource; + + std::unordered_map ctms; +}; + +class CHyprlandCTMControlProtocol : public IWaylandProtocol { + public: + CHyprlandCTMControlProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CHyprlandCTMControlResource* resource); + + void setCTM(SP monitor, const Mat3x3& ctm); + + // + std::vector> m_vManagers; + + friend class CHyprlandCTMControlResource; +}; + +namespace PROTO { + inline UP ctm; +}; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 310d45af..f388ec37 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1498,6 +1498,11 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { if (inFD >= 0) pMonitor->output->state->setExplicitInFence(inFD); + if (pMonitor->ctmUpdated) { + pMonitor->ctmUpdated = false; + pMonitor->output->state->setCTM(pMonitor->ctm); + } + bool ok = pMonitor->state.commit(); if (!ok) { if (inFD >= 0) { From 57b632ead88b4558a53e52aa9c098d48362ee768 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 17:02:55 +0100 Subject: [PATCH 260/298] pointer: expand sw cursor damage box fixes #8031 just a bit, rounding errors I guess --- src/managers/PointerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 736b629c..cc9deec7 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -657,7 +657,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { } void CPointerManager::damageIfSoftware() { - auto b = getCursorBoxGlobal(); + auto b = getCursorBoxGlobal().expand(4); static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); From e4a26f4f1d9d30569b9e7e6c265fccfd42fa5d72 Mon Sep 17 00:00:00 2001 From: JManch <61563764+JManch@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:50:06 +0100 Subject: [PATCH 261/298] dispatchers: allow leading whitespace in window parameter (#8016) --- src/Compositor.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f00e1e34..459aca11 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2445,13 +2445,31 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleF pMonitor->output->scheduleFrame(reason); } -PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { +PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp_) { + auto regexp = trim(regexp_); + if (regexp.starts_with("active")) return m_pLastWindow.lock(); + else if (regexp.starts_with("floating") || regexp.starts_with("tiled")) { + // first floating on the current ws + if (!valid(m_pLastWindow)) + return nullptr; + + const bool FLOAT = regexp.starts_with("floating"); + + for (auto const& w : m_vWindows) { + if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden()) + continue; + + return w; + } + + return nullptr; + } eFocusWindowMode mode = MODE_CLASS_REGEX; - std::regex regexCheck(regexp); + std::regex regexCheck(regexp_); std::string matchCheck; if (regexp.starts_with("class:")) { regexCheck = std::regex(regexp.substr(6)); @@ -2470,21 +2488,6 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { } else if (regexp.starts_with("pid:")) { mode = MODE_PID; matchCheck = regexp.substr(4); - } else if (regexp.starts_with("floating") || regexp.starts_with("tiled")) { - // first floating on the current ws - if (!valid(m_pLastWindow)) - return nullptr; - - const bool FLOAT = regexp.starts_with("floating"); - - for (auto const& w : m_vWindows) { - if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden()) - continue; - - return w; - } - - return nullptr; } for (auto const& w : g_pCompositor->m_vWindows) { From 613eac4603f4a15868c88a47a8ee8dcb84ee2dd3 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Tue, 8 Oct 2024 20:31:15 +0200 Subject: [PATCH 262/298] layout: remove unnecessary check after 45e8219 (#8037) --- src/layout/IHyprLayout.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f249d2b5..24ee13f4 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -186,12 +186,12 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { g_pCompositor->m_pLastWindow.lock() : g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); - if ((*PAUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. - && OPENINGON // check if OPENINGON exists. - && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. - && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group - && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON - && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + if (*PAUTOGROUP // check if auto_group is enabled. + && OPENINGON // check if OPENINGON exists. + && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group + && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON + && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state From 60308a2bb576413cbc787d4bde4f8d0e3fa3c9d6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 20:28:30 +0100 Subject: [PATCH 263/298] defaultConfig: add a nofocus rule for weird X windows ref #6543 --- example/hyprland.conf | 6 +++++- src/config/defaultConfig.hpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 4adc2d40..3478bcff 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -255,4 +255,8 @@ bindl = , XF86AudioPrev, exec, playerctl previous # Example windowrule v2 # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ -windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. +# Ignore maximize requests from apps. You'll probably like this. +windowrulev2 = suppressevent maximize, class:.* + +# Fix some dragging issues with XWayland +windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 5843caa3..54ce6642 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -268,5 +268,9 @@ bindl = , XF86AudioPrev, exec, playerctl previous # Example windowrule v2 # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ -windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. +# Ignore maximize requests from apps. You'll probably like this. +windowrulev2 = suppressevent maximize, class:.* + +# Fix some dragging issues with XWayland +windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 )#"; From 91299f7039d80b25b3f0296d3d0f4d2059d41869 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:20:25 +0100 Subject: [PATCH 264/298] hyprerror: make hyprerror reserve space (#8040) --- src/hyprerror/HyprError.cpp | 20 ++++++++++++++++++++ src/hyprerror/HyprError.hpp | 12 ++++++++---- src/render/Renderer.cpp | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index bbc3a006..5f63de24 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -3,6 +3,9 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include +using namespace Hyprutils::Utils; + CHyprError::CHyprError() { m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); m_fFadeOpacity.registerVar(); @@ -130,6 +133,8 @@ void CHyprError::createQueued() { } m_szQueued = ""; + m_fLastHeight = yoffset + PAD + 1; + pango_font_description_free(pangoFD); g_object_unref(layoutText); @@ -158,6 +163,8 @@ void CHyprError::createQueued() { m_cQueued = CColor(); g_pHyprRenderer->damageMonitor(PMONITOR); + + g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); } void CHyprError::draw() { @@ -174,6 +181,11 @@ void CHyprError::draw() { m_pTexture->destroyTexture(); m_bIsCreated = false; m_szQueued = ""; + + for (auto& m : g_pCompositor->m_vMonitors) { + g_pHyprRenderer->arrangeLayersForMonitor(m->ID); + } + return; } else { m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); @@ -203,3 +215,11 @@ void CHyprError::destroy() { else m_szQueued = ""; } + +bool CHyprError::active() { + return m_bIsCreated; +} + +float CHyprError::height() { + return m_fLastHeight; +} diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index 8dbb4521..a553614c 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -11,9 +11,12 @@ class CHyprError { CHyprError(); ~CHyprError(); - void queueCreate(std::string message, const CColor& color); - void draw(); - void destroy(); + void queueCreate(std::string message, const CColor& color); + void draw(); + void destroy(); + + bool active(); + float height(); // logical private: void createQueued(); @@ -23,7 +26,8 @@ class CHyprError { bool m_bIsCreated = false; SP m_pTexture; CAnimatedVariable m_fFadeOpacity; - CBox m_bDamageBox = {0, 0, 0, 0}; + CBox m_bDamageBox = {0, 0, 0, 0}; + float m_fLastHeight = 0.F; bool m_bMonitorChanged = false; }; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index f388ec37..61f94014 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -97,6 +97,16 @@ CHyprRenderer::CHyprRenderer() { ensureCursorRenderingMode(); }); + static auto P3 = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { + g_pEventLoopManager->doLater([this]() { + if (!g_pHyprError->active()) + return; + for (auto& m : g_pCompositor->m_vMonitors) { + arrangeLayersForMonitor(m->ID); + } + }); + }); + m_pCursorTicker = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, cursorTicker, nullptr); wl_event_source_timer_update(m_pCursorTicker, 500); @@ -1757,6 +1767,13 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + if (g_pHyprError->active() && g_pCompositor->m_pLastMonitor == PMONITOR->self) { + const auto HEIGHT = g_pHyprError->height(); + PMONITOR->vecReservedTopLeft.y = HEIGHT; + usableArea.y += HEIGHT; + usableArea.h -= HEIGHT; + } + for (auto& la : PMONITOR->m_aLayerSurfaceLayers) { std::stable_sort(la.begin(), la.end(), [](const PHLLSREF& a, const PHLLSREF& b) { return a->order > b->order; }); } From 8cced091f53c92bc8de97b9d3dac20b31980af70 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 21:58:40 +0100 Subject: [PATCH 265/298] renderer: reserve space for error at the bottom if that's set ref #8040 --- src/render/Renderer.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 61f94014..bc95abc6 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1756,7 +1756,9 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgetMonitorFromID(monitor); + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitor); + + static auto BAR_POSITION = CConfigValue("debug:error_position"); if (!PMONITOR) return; @@ -1768,10 +1770,15 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; if (g_pHyprError->active() && g_pCompositor->m_pLastMonitor == PMONITOR->self) { - const auto HEIGHT = g_pHyprError->height(); - PMONITOR->vecReservedTopLeft.y = HEIGHT; - usableArea.y += HEIGHT; - usableArea.h -= HEIGHT; + const auto HEIGHT = g_pHyprError->height(); + if (*BAR_POSITION == 0) { + PMONITOR->vecReservedTopLeft.y = HEIGHT; + usableArea.y += HEIGHT; + usableArea.h -= HEIGHT; + } else { + PMONITOR->vecReservedBottomRight.y = HEIGHT; + usableArea.h -= HEIGHT; + } } for (auto& la : PMONITOR->m_aLayerSurfaceLayers) { From ac658500fbebe607f2db83f11c37f0a3a05ef734 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 23:33:10 +0100 Subject: [PATCH 266/298] keyboard: update group state on change for the sym resolve state fixes #8038 --- src/devices/IKeyboard.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 3300f252..d1119772 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -392,6 +392,9 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) { xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); if (updateModifiersState()) { + if (xkbSymState) + xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group); + keyboardEvents.modifiers.emit(SModifiersEvent{ .depressed = modifiersState.depressed, .latched = modifiersState.latched, From bc299928ad5571300180eb8edb6742ed3bbf0282 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 9 Oct 2024 00:26:40 +0100 Subject: [PATCH 267/298] output/xdg-output: avoid sending events to released globals ref #6835 --- src/protocols/XDGOutput.cpp | 4 +++- src/protocols/XDGOutput.hpp | 2 ++ src/protocols/core/Output.cpp | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 0cdadd43..0598e713 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -51,6 +51,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 #endif pXDGOutput->client = CLIENT; + pXDGOutput->outputProto = OUTPUT->owner; + if (!pXDGOutput->resource->resource()) { m_vXDGOutputs.pop_back(); mgr->noMemory(); @@ -104,7 +106,7 @@ CXDGOutput::CXDGOutput(SP resource_, SP monitor_) : mon void CXDGOutput::sendDetails() { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - if (!monitor) + if (!monitor || !outputProto || outputProto->isDefunct()) return; const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition; diff --git a/src/protocols/XDGOutput.hpp b/src/protocols/XDGOutput.hpp index 15d86cc7..520f3aaa 100644 --- a/src/protocols/XDGOutput.hpp +++ b/src/protocols/XDGOutput.hpp @@ -6,6 +6,7 @@ class CMonitor; class CXDGOutputProtocol; +class CWLOutputProtocol; class CXDGOutput { public: @@ -16,6 +17,7 @@ class CXDGOutput { private: WP monitor; SP resource; + WP outputProto; std::optional overridePosition; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 7b88e0a8..4047774a 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -47,7 +47,7 @@ SP CWLOutputResource::getResource() { } void CWLOutputResource::updateState() { - if (!monitor || (owner && owner->defunct)) + if (!monitor || !owner || owner->defunct) return; if (resource->version() >= 2) @@ -119,6 +119,9 @@ bool CWLOutputProtocol::isDefunct() { } void CWLOutputProtocol::sendDone() { + if (defunct) + return; + for (auto const& r : m_vOutputs) { r->resource->sendDone(); } From 6ce07ee86453e8ef01faa7b4e1eb8f09475f32b7 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 9 Oct 2024 12:00:43 +0300 Subject: [PATCH 268/298] CI/release: remove script backup line --- .github/workflows/release.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1f52b4ff..d5ff1aa0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,7 +20,6 @@ jobs: run: | git fetch --unshallow || echo "failed unshallowing" bash -c scripts/generateVersion.sh - mv scripts/generateVersion.sh scripts/generateVersion.sh.bak - name: Create tarball with submodules id: tar From 223dcc8bac7fee90aa6aa7596d9379e56b526e62 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Wed, 9 Oct 2024 04:24:05 -0500 Subject: [PATCH 269/298] output: update state even if no owner exists (#8044) --- src/protocols/core/Output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 4047774a..3e68937f 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -47,7 +47,7 @@ SP CWLOutputResource::getResource() { } void CWLOutputResource::updateState() { - if (!monitor || !owner || owner->defunct) + if (!monitor || (owner && owner->defunct)) return; if (resource->version() >= 2) From 3d28879c2640cdb6e8426127692240100793bfef Mon Sep 17 00:00:00 2001 From: JManch <61563764+JManch@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:24:35 +0100 Subject: [PATCH 270/298] hyprerror: fix height calc with bottom bar (#8043) --- src/hyprerror/HyprError.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 5f63de24..4044bcc9 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -133,7 +133,7 @@ void CHyprError::createQueued() { } m_szQueued = ""; - m_fLastHeight = yoffset + PAD + 1; + m_fLastHeight = yoffset + PAD + 1 - (TOPBAR ? 0 : Y - PAD); pango_font_description_free(pangoFD); g_object_unref(layoutText); From 6ae89940c761d4ed4317df0af29e8df41d472091 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 9 Oct 2024 11:58:49 +0200 Subject: [PATCH 271/298] layout: add merge_floated_into_tiled_on_groupbar (#8042) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/render/decorations/CHyprGroupBarDecoration.cpp | 12 +++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 2ca230be..d684e44a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -784,6 +784,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_CHOICE, .data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"}, }, + SConfigOptionDescription{ + .value = "group:merge_floated_into_tiled_on_groupbar", + .description = "whether dragging a floating window into a tiled window groupbar will merge them", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * group:groupbar: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 9a5283fa..e973f1ab 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -377,6 +377,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:merge_floated_into_tiled_on_groupbar", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:drag_into_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index ef6c81e6..eca3f2cb 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -402,9 +402,15 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { } bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWINDOW pDraggedWindow) { - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); - static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); - if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2)) + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + static auto PMERGEFLOATEDINTOTILEDONGROUPBAR = CConfigValue("group:merge_floated_into_tiled_on_groupbar"); + + bool denied = false; + if (!m_pWindow->m_bIsFloating && !pDraggedWindow->m_bDraggingTiled && !*PMERGEFLOATEDINTOTILEDONGROUPBAR) + denied = true; + + if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || denied) return false; const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_fBarHeight + BAR_PADDING_OUTER_VERT) / 2 : pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; From c4eb1940336cd88ca65ba65582ce104e49dfc7c9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 9 Oct 2024 22:00:06 +0100 Subject: [PATCH 272/298] gammactrl: guard pMonitor in setGamma --- src/protocols/GammaControl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 077d6e2f..e794e543 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -46,6 +46,13 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); }); resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) { + if (!pMonitor) { + LOGM(ERR, "setGamma for a dead monitor"); + resource->sendFailed(); + close(fd); + return; + } + LOGM(LOG, "setGamma for {}", pMonitor->szName); int fdFlags = fcntl(fd, F_GETFL, 0); From b65773bea9b912a41cfcbc789fb2e60a07e3d0c1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 10 Oct 2024 11:01:13 +0100 Subject: [PATCH 273/298] hyprpm: disallow shallow on unknown branch --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 669789b4..612995dc 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -436,7 +436,7 @@ bool CPluginManager::updateHeaders(bool force) { progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); - const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow; + const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; // let us give a bit of leg-room for shallowing // due to timezones, etc. From d655a10381f01212635f2eadd69e1f22930f8f06 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:56:19 +0100 Subject: [PATCH 274/298] config/layout: nuke no_gaps_when_only (#8072) --- src/config/ConfigDescriptions.hpp | 12 ------------ src/config/ConfigManager.cpp | 2 -- src/layout/DwindleLayout.cpp | 30 ++++-------------------------- src/layout/MasterLayout.cpp | 30 +++++------------------------- src/managers/input/Touch.cpp | 1 - 5 files changed, 9 insertions(+), 66 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index d684e44a..bef5ee53 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1446,12 +1446,6 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_FLOAT, .data = SConfigOptionDescription::SFloatData{1, 0.1, 3}, }, - SConfigOptionDescription{ - .value = "dwindle:no_gaps_when_only", - .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", - .type = CONFIG_OPTION_CHOICE, - .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, - }, SConfigOptionDescription{ .value = "dwindle:use_active_for_splits", .description = "whether to prefer the active window or the mouse position for splits", @@ -1512,12 +1506,6 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_STRING_SHORT, .data = SConfigOptionDescription::SStringData{"none"}, }, - SConfigOptionDescription{ - .value = "master:no_gaps_when_only", - .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", - .type = CONFIG_OPTION_CHOICE, - .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, - }, SConfigOptionDescription{ .value = "master:orientation", .description = "default placement of the master area, can be left, right, top, bottom or center", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e973f1ab..6ec63d4c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -446,7 +446,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("dwindle:preserve_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:special_scale_factor", {1.f}); m_pConfig->addConfigValue("dwindle:split_width_multiplier", {1.0f}); - m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f}); m_pConfig->addConfigValue("dwindle:split_bias", Hyprlang::INT{0}); @@ -459,7 +458,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); - m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:orientation", {"left"}); m_pConfig->addConfigValue("master:inherit_fullscreen", Hyprlang::INT{1}); m_pConfig->addConfigValue("master:allow_small_split", Hyprlang::INT{0}); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 04cbf21d..76b26af1 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -142,11 +142,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); - static auto PNOGAPSWHENONLY = CConfigValue("dwindle:no_gaps_when_only"); - static auto PGAPSINDATA = CConfigValue("general:gaps_in"); - static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); - auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); - auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); + static auto PGAPSINDATA = CConfigValue("general:gaps_in"); + static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); + auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); + auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN); auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT); @@ -156,27 +155,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for PWINDOW->m_vSize = nodeBox.size(); PWINDOW->m_vPosition = nodeBox.pos(); - const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->workspaceID()); - - if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (NODESONWORKSPACE == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) { - - PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT); - - PWINDOW->updateWindowDecos(); - - const auto RESERVED = PWINDOW->getFullWindowReservedArea(); - - PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft; - PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight); - - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - - return; - } - PWINDOW->updateWindowDecos(); auto calcPos = PWINDOW->m_vPosition; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 04a6ea29..8fde960d 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -631,12 +631,11 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); - static auto PNOGAPSWHENONLY = CConfigValue("master:no_gaps_when_only"); - static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); - static auto PGAPSINDATA = CConfigValue("general:gaps_in"); - static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); - auto* PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); - auto* PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); + static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); + static auto PGAPSINDATA = CConfigValue("general:gaps_in"); + static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); + auto* PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); + auto* PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN); auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT); @@ -649,25 +648,6 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { PWINDOW->m_vSize = pNode->size; PWINDOW->m_vPosition = pNode->position; - if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) { - - PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT); - - PWINDOW->updateWindowDecos(); - - const auto RESERVED = PWINDOW->getFullWindowReservedArea(); - - PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft; - PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight); - - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - - return; - } - PWINDOW->updateWindowDecos(); auto calcPos = PWINDOW->m_vPosition; diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 9b03168e..0333648a 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -39,7 +39,6 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { const auto PWORKSPACE = PMONITOR->activeWorkspace; const bool VERTANIMS = PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - // TODO: support no_gaps_when_only? const double TARGETLEFT = ((VERTANIMS ? gapsOut.top : gapsOut.left) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x); const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.bottom : gapsOut.right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x)); const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x); From 178a300eeaf006fed4c8c9a599657b4530f65559 Mon Sep 17 00:00:00 2001 From: Jasson Date: Fri, 11 Oct 2024 07:07:25 -0400 Subject: [PATCH 275/298] xwayland: minor cleanups and fixes (#8076) --- src/managers/XWaylandManager.cpp | 110 +++++++++++++++---------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index fad7e451..8b63d37e 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -5,14 +5,13 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" +#include #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 #define OUTPUT_DESCRIPTION_MUTABLE_SINCE_VERSION 3 -CHyprXWaylandManager::CHyprXWaylandManager() { - ; -} +CHyprXWaylandManager::CHyprXWaylandManager() = default; CHyprXWaylandManager::~CHyprXWaylandManager() { #ifndef NO_XWAYLAND @@ -21,7 +20,7 @@ CHyprXWaylandManager::~CHyprXWaylandManager() { } SP CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { - return pWindow->m_pWLSurface->resource(); + return pWindow ? pWindow->m_pWLSurface->resource() : nullptr; } void CHyprXWaylandManager::activateSurface(SP pSurface, bool activate) { @@ -40,27 +39,31 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool return; } - if (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface) { - if (activate) { - PWINDOW->m_pXWaylandSurface->setMinimized(false); - PWINDOW->m_pXWaylandSurface->restackToTop(); + if (PWINDOW->m_bIsX11) { + if (PWINDOW->m_pXWaylandSurface) { + if (activate) { + PWINDOW->m_pXWaylandSurface->setMinimized(false); + PWINDOW->m_pXWaylandSurface->restackToTop(); + } + PWINDOW->m_pXWaylandSurface->activate(activate); } - PWINDOW->m_pXWaylandSurface->activate(activate); - } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) + } else if (PWINDOW->m_pXDGSurface) PWINDOW->m_pXDGSurface->toplevel->setActive(activate); } void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { - setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos if (activate) { + setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); + if (!pWindow->isX11OverrideRedirect()) pWindow->m_pXWaylandSurface->restackToTop(); } pWindow->m_pXWaylandSurface->activate(activate); + } else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) pWindow->m_pXDGSurface->toplevel->setActive(activate); @@ -74,6 +77,9 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { } void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { + if (!pWindow) + return; + if (pWindow->m_bIsX11) { const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); @@ -83,7 +89,10 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { pbox->x = pWindow->m_pXWaylandSurface->geometry.x; pbox->y = pWindow->m_pXWaylandSurface->geometry.y; - if ((SIZEHINTS->flags & 0x2 /* ICCCM USSize */) || (SIZEHINTS->flags & 0x8 /* ICCCM PSize */)) { + constexpr int ICCCM_USSize = 0x2; + constexpr int ICCCM_PSize = 0x8; + + if ((SIZEHINTS->flags & ICCCM_USSize) || (SIZEHINTS->flags & ICCCM_PSize)) { pbox->w = SIZEHINTS->base_width; pbox->h = SIZEHINTS->base_height; } else { @@ -117,34 +126,34 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool Vector2D windowPos = pWindow->m_vRealPosition.value(); if (pWindow->m_bIsX11 && PMONITOR) { - windowPos = windowPos - PMONITOR->vecPosition; // normalize to monitor + windowPos -= PMONITOR->vecPosition; // normalize to monitor if (*PXWLFORCESCALEZERO) - windowPos = windowPos * PMONITOR->scale; // scale if applicable - windowPos = windowPos + PMONITOR->vecXWaylandPosition; // move to correct position for xwayland + windowPos *= PMONITOR->scale; // scale if applicable + windowPos += PMONITOR->vecXWaylandPosition; // move to correct position for xwayland } - if (!force && ((pWindow->m_vPendingReportedSize == size && windowPos == pWindow->m_vReportedPosition) || (pWindow->m_vPendingReportedSize == size && !pWindow->m_bIsX11))) + if (!force && pWindow->m_vPendingReportedSize == size && (windowPos == pWindow->m_vReportedPosition || !pWindow->m_bIsX11)) return; pWindow->m_vReportedPosition = windowPos; pWindow->m_vPendingReportedSize = size; - pWindow->m_fX11SurfaceScaledBy = 1.f; + pWindow->m_fX11SurfaceScaledBy = 1.0f; if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11 && PMONITOR) { - size = size * PMONITOR->scale; + size *= PMONITOR->scale; pWindow->m_fX11SurfaceScaledBy = PMONITOR->scale; } if (pWindow->m_bIsX11) pWindow->m_pXWaylandSurface->configure({windowPos, size}); else if (pWindow->m_pXDGSurface->toplevel) - pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor())); + pWindow->m_vPendingSizeAcks.emplace_back(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor()); } bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { - for (auto const& a : pWindow->m_pXWaylandSurface->atoms) + for (const auto& a : pWindow->m_pXWaylandSurface->atoms) if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || @@ -157,16 +166,8 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { return true; } - if (pWindow->isModal()) - return true; - - if (pWindow->m_pXWaylandSurface->transient) - return true; - - if (pWindow->m_pXWaylandSurface->role.contains("task_dialog") || pWindow->m_pXWaylandSurface->role.contains("pop-up")) - return true; - - if (pWindow->m_pXWaylandSurface->overrideRedirect) + if (pWindow->isModal() || pWindow->m_pXWaylandSurface->transient || + (pWindow->m_pXWaylandSurface->role.contains("task_dialog") || pWindow->m_pXWaylandSurface->role.contains("pop-up")) || pWindow->m_pXWaylandSurface->overrideRedirect) return true; const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); @@ -203,6 +204,9 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { } void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) { + if (!pWindow) + return; + if (pWindow->m_bIsX11) pWindow->m_pXWaylandSurface->setFullscreen(fullscreen); else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) @@ -210,37 +214,33 @@ void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscree } Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) { - if (!validMapped(pWindow)) - return Vector2D(99999, 99999); + constexpr int NO_MAX_SIZE_LIMIT = 99999; + if (!validMapped(pWindow) || + ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || + pWindow->m_sWindowData.noMaxSize.valueOrDefault())) + return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT); - if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || - pWindow->m_sWindowData.noMaxSize.valueOrDefault()) - return Vector2D(99999, 99999); + Vector2D maxSize = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : + pWindow->m_pXDGSurface->toplevel->current.maxSize; - auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : - pWindow->m_pXDGSurface->toplevel->current.maxSize; + if (maxSize.x < 5) + maxSize.x = NO_MAX_SIZE_LIMIT; + if (maxSize.y < 5) + maxSize.y = NO_MAX_SIZE_LIMIT; - if (MAXSIZE.x < 5) - MAXSIZE.x = 99999; - if (MAXSIZE.y < 5) - MAXSIZE.y = 99999; - - return MAXSIZE; + return maxSize; } Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) { - if (!validMapped(pWindow)) + if (!validMapped(pWindow) || ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))) return Vector2D(0, 0); - if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel)) - return Vector2D(0, 0); + Vector2D minSize = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) : + pWindow->m_pXDGSurface->toplevel->current.minSize; - auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) : - pWindow->m_pXDGSurface->toplevel->current.minSize; + minSize = minSize.clamp({1, 1}); - MINSIZE = MINSIZE.clamp({1, 1}); - - return MINSIZE; + return minSize; } Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { @@ -249,7 +249,7 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { CMonitor* pMonitor = nullptr; double bestDistance = __FLT_MAX__; - for (auto const& m : g_pCompositor->m_vMonitors) { + for (const auto& m : g_pCompositor->m_vMonitors) { const auto SIZ = *PXWLFORCESCALEZERO ? m->vecTransformedSize : m->vecSize; double distance = @@ -268,9 +268,9 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { Vector2D result = coord - pMonitor->vecXWaylandPosition; // if scaled, unscale if (*PXWLFORCESCALEZERO) - result = result / pMonitor->scale; + result /= pMonitor->scale; // add pos - result = result + pMonitor->vecPosition; + result += pMonitor->vecPosition; return result; -} +} \ No newline at end of file From 7564b26b7d386d248eaa47c1a481c09eefd8e3ca Mon Sep 17 00:00:00 2001 From: Toni500github <88878648+Toni500github@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:19:16 +0200 Subject: [PATCH 276/298] internal: improve version query and define HYPRLAND_VERSION (#8034) --- CMakeLists.txt | 2 ++ hyprpm/src/core/PluginManager.cpp | 3 +-- meson.build | 1 + src/debug/HyprCtl.cpp | 23 +++++++++++++-------- src/debug/HyprCtl.hpp | 1 + src/main.cpp | 34 +++++-------------------------- 6 files changed, 25 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4de449dc..df919d76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,8 @@ else() message(STATUS "Configuring Hyprland in Release with CMake") endif() +add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}") + include_directories(. "src/" "protocols/") set(CMAKE_CXX_STANDARD 26) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 612995dc..96ec60ad 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -440,8 +440,7 @@ bool CPluginManager::updateHeaders(bool force) { // let us give a bit of leg-room for shallowing // due to timezones, etc. - const std::string SHALLOW_DATE = - trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); + const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'"); if (m_bVerbose && bShallow) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); diff --git a/meson.build b/meson.build index e9bbb99d..33e8fdbe 100644 --- a/meson.build +++ b/meson.build @@ -21,6 +21,7 @@ add_project_arguments( '-Wno-missing-field-initializers', '-Wno-narrowing', '-Wno-pointer-arith', datarootdir, + '-DHYPRLAND_VERSION="' + meson.project_version() + '"', ], language: 'cpp', ) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d9274727..e0bb2b83 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -853,26 +853,33 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + - "\n\nflags: (if any)\n"; + std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n" + "Date: {}\n" + "Tag: {}, commits: {}\n" + "built against aquamarine {}\n\n\n", + HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION); +#if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND)) + result += "no flags were set\n"; +#else + result += "flags set:\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; #endif -#ifndef ISDEBUG +#ifdef ISDEBUG result += "debug\n"; #endif #ifdef NO_XWAYLAND result += "no xwayland\n"; #endif - +#endif return result; } else { std::string result = std::format( R"#({{ "branch": "{}", "commit": "{}", + "version": "{}", "dirty": {}, "commit_message": "{}", "commit_date": "{}", @@ -880,13 +887,13 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { "commits": "{}", "buildAquamarine": "{}", "flags": [)#", - GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, - AQUAMARINE_VERSION); + GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, + GIT_COMMITS, AQUAMARINE_VERSION); #ifdef LEGACY_RENDERER result += "\"legacyrenderer\","; #endif -#ifndef ISDEBUG +#ifdef ISDEBUG result += "\"debug\","; #endif #ifdef NO_XWAYLAND diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index d68bf14f..c1bf51ca 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -7,6 +7,7 @@ // exposed for main.cpp std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); +std::string versionRequest(eHyprCtlOutputFormat format, std::string request); class CHyprCtl { public: diff --git a/src/main.cpp b/src/main.cpp index 57bb5507..45f212d3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ void help() { std::cout << " --config FILE -c FILE - Specify config file to use\n"; std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; + std::cout << " --systeminfo - Prints system infos\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; std::cout << " --version -v - Print this binary's version\n"; } @@ -33,9 +34,9 @@ int main(int argc, char** argv) { throwError("XDG_RUNTIME_DIR is not set!"); // export HYPRLAND_CMD - std::string cmd = ""; - for (auto i = 0; i < argc; ++i) - cmd += std::string(i == 0 ? "" : " ") + argv[i]; + std::string cmd = argv[0]; + for (int i = 1; i < argc; ++i) + cmd += std::string(" ") + argv[i]; setenv("HYPRLAND_CMD", cmd.c_str(), 1); setenv("XDG_BACKEND", "wayland", 1); @@ -116,32 +117,7 @@ int main(int argc, char** argv) { return 0; } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { - auto result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH; - auto dirty = std::string(GIT_DIRTY); - if (!dirty.empty()) - result += " " + dirty; - - auto commitMsg = trim(GIT_COMMIT_MESSAGE); - std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); - result += " (" + commitMsg + ")."; - - result += "\nDate: " + std::string(GIT_COMMIT_DATE); - result += "\nTag: " + std::string(GIT_TAG) + ", commits: " + std::string(GIT_COMMITS); - result += "\nbuilt against aquamarine " + std::string(AQUAMARINE_VERSION); - - result += "\n\nflags: (if any)\n"; - -#ifdef LEGACY_RENDERER - result += "legacyrenderer\n"; -#endif -#ifndef ISDEBUG - result += "debug\n"; -#endif -#ifdef NO_XWAYLAND - result += "no xwayland\n"; -#endif - - std::cout << result; + std::cout << versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "") << std::endl; return 0; } else if (it->compare("--systeminfo") == 0) { const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""); From f5db4839730643169b7e8b7fb6ae2fbb8743ebe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgars=20C=C4=ABrulis?= Date: Sat, 12 Oct 2024 03:12:07 +0300 Subject: [PATCH 277/298] drm-timeline: Add check for conflicting acquire and release points (#8083) Signed-off-by: Edgars Cirulis --- src/protocols/DRMSyncobj.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 4993f1a4..a7f242ee 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -55,8 +55,13 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP= pending.releasePoint) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release"); + surface->pending.rejected = true; + return; + } + } // wait for the acquire timeline to materialize auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); From ee8116ac5dc412dce924a0163074ce7988dd0cfc Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:29:51 +0300 Subject: [PATCH 278/298] input: Fix VRR for constrained cursors (#6877) --- src/Compositor.cpp | 4 +++ src/events/Windows.cpp | 19 +++++++++++-- src/helpers/Monitor.cpp | 8 +++++- src/helpers/Monitor.hpp | 2 ++ src/helpers/Timer.cpp | 5 ++-- src/helpers/Timer.hpp | 2 +- src/managers/AnimationManager.cpp | 2 +- src/managers/PointerManager.cpp | 43 +++++++++++++++++++++++++---- src/managers/PointerManager.hpp | 7 +++++ src/managers/SeatManager.hpp | 3 ++ src/managers/input/InputManager.cpp | 21 ++++++++++++-- src/managers/input/InputManager.hpp | 1 + 12 files changed, 100 insertions(+), 17 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 459aca11..dcc6422d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1,4 +1,5 @@ #include "Compositor.hpp" +#include "debug/Log.hpp" #include "helpers/Splashes.hpp" #include "config/ConfigValue.hpp" #include "managers/CursorManager.hpp" @@ -1380,6 +1381,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { if (!validMapped(pWindow)) return; + if (pWindow == (top ? m_vWindows.back() : m_vWindows.front())) + return; + auto moveToZ = [&](PHLWINDOW pw, bool top) -> void { if (top) { for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 37f29130..e549907e 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -12,6 +12,7 @@ #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" #include "../xwayland/XSurface.hpp" +#include "managers/PointerManager.hpp" #include using namespace Hyprutils::String; @@ -758,8 +759,21 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_pWorkspace->m_bVisible) return; - g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, - PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); + const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + + PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow"); + if (g_pSeatManager->isPointerFrameCommit) { + g_pSeatManager->isPointerFrameSkipped = false; + g_pSeatManager->isPointerFrameCommit = false; + } else + g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, + PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); + + if (g_pSeatManager->isPointerFrameSkipped) { + g_pPointerManager->sendStoredMovement(); + g_pSeatManager->sendPointerFrame(); + g_pSeatManager->isPointerFrameCommit = true; + } if (!PWINDOW->m_bIsX11) { PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces(); @@ -767,7 +781,6 @@ void Events::listener_commitWindow(void* owner, void* data) { } // tearing: if solitary, redraw it. This still might be a single surface window - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) { CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index f3e7de4e..091745df 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -16,6 +16,7 @@ #include "../protocols/core/Compositor.hpp" #include "sync/SyncTimeline.hpp" #include +#include "debug/Log.hpp" #include #include using namespace Hyprutils::String; @@ -384,7 +385,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; // keep requested minimum refresh rate - if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { + if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { // damage whole screen because some previous cursor box damages were skipped damage.damageEntire(); return false; @@ -933,6 +934,11 @@ bool CMonitor::attemptDirectScanout() { return true; } +void CMonitor::debugLastPresentation(const std::string& message) { + Debug::log(TRACE, "{} (last presentation {} - {} fps)", message, lastPresentationTimer.getMillis(), + lastPresentationTimer.getMillis() > 0 ? 1000.0f / lastPresentationTimer.getMillis() : 0.0f); +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index f5068dba..ad8a823b 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -185,6 +185,8 @@ class CMonitor { bool attemptDirectScanout(); void setCTM(const Mat3x3& ctm); + void debugLastPresentation(const std::string& message); + bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp index 7b1726df..e00c5918 100644 --- a/src/helpers/Timer.cpp +++ b/src/helpers/Timer.cpp @@ -1,4 +1,5 @@ #include "Timer.hpp" +#include void CTimer::reset() { m_tpLastReset = std::chrono::steady_clock::now(); @@ -8,8 +9,8 @@ std::chrono::steady_clock::duration CTimer::getDuration() { return std::chrono::steady_clock::now() - m_tpLastReset; } -long CTimer::getMillis() { - return std::chrono::duration_cast(getDuration()).count(); +float CTimer::getMillis() { + return std::chrono::duration_cast(getDuration()).count() / 1000.f; } float CTimer::getSeconds() { diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp index 827e7625..a58225d0 100644 --- a/src/helpers/Timer.hpp +++ b/src/helpers/Timer.hpp @@ -6,7 +6,7 @@ class CTimer { public: void reset(); float getSeconds(); - long getMillis(); + float getMillis(); const std::chrono::steady_clock::time_point& chrono() const; private: diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 092d9721..0ff94f1f 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -259,7 +259,7 @@ void CAnimationManager::tick() { // manually schedule a frame if (PMONITOR) - g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION); } // do it here, because if this alters the animation vars deque we would be in trouble above. diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index cc9deec7..8c2a1bad 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/PointerGestures.hpp" +#include "../protocols/RelativePointer.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/IdleNotify.hpp" #include "../protocols/core/Compositor.hpp" @@ -328,7 +329,7 @@ void CPointerManager::onCursorMoved() { continue; const auto CURSORPOS = getCursorPosForMonitor(m); - m->output->moveCursor(CURSORPOS); + m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent()); } if (recalc) @@ -342,7 +343,7 @@ bool CPointerManager::attemptHardwareCursor(SPmonitor.lock()); - state->monitor->output->moveCursor(CURSORPOS); + state->monitor->output->moveCursor(CURSORPOS, state->monitor->shouldSkipScheduleFrameOnMouseEvent()); auto texture = getCurrentCursorTexture(); @@ -385,7 +386,8 @@ bool CPointerManager::setHWCursorBuffer(SP state, SPcursorFrontBuffer = buf; - g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); + if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent()) + g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); return true; } @@ -676,8 +678,11 @@ void CPointerManager::warpTo(const Vector2D& logical) { damageIfSoftware(); pointerPos = closestValid(logical); - recheckEnteredOutputs(); - onCursorMoved(); + + if (!g_pInputManager->isLocked()) { + recheckEnteredOutputs(); + onCursorMoved(); + } damageIfSoftware(); } @@ -859,7 +864,14 @@ void CPointerManager::attachPointer(SP pointer) { }); listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { - g_pSeatManager->sendPointerFrame(); + bool shouldSkip = false; + if (!g_pSeatManager->mouse.expired() && g_pInputManager->isLocked()) { + auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); + shouldSkip = PMONITOR && PMONITOR->shouldSkipScheduleFrameOnMouseEvent(); + } + g_pSeatManager->isPointerFrameSkipped = shouldSkip; + if (!g_pSeatManager->isPointerFrameSkipped) + g_pSeatManager->sendPointerFrame(); }); listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) { @@ -1080,3 +1092,22 @@ void CPointerManager::damageCursor(SP pMonitor) { Vector2D CPointerManager::cursorSizeLogical() { return currentCursorImage.size / currentCursorImage.scale; } + +void CPointerManager::storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) { + storedTime = time; + storedDelta += delta; + storedUnaccel += deltaUnaccel; +} + +void CPointerManager::setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) { + storedTime = time; + storedDelta = delta; + storedUnaccel = deltaUnaccel; +} + +void CPointerManager::sendStoredMovement() { + PROTO::relativePointer->sendRelativeMotion((uint64_t)storedTime * 1000, storedDelta, storedUnaccel); + storedTime = 0; + storedDelta = Vector2D{}; + storedUnaccel = Vector2D{}; +} diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 4a4c4f61..6b89eb16 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -61,6 +61,9 @@ class CPointerManager { // Vector2D position(); Vector2D cursorSizeLogical(); + void storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel); + void setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel); + void sendStoredMovement(); void recheckEnteredOutputs(); @@ -154,6 +157,10 @@ class CPointerManager { Vector2D pointerPos = {0, 0}; + uint64_t storedTime = 0; + Vector2D storedDelta = {0, 0}; + Vector2D storedUnaccel = {0, 0}; + struct SMonitorPointerState { SMonitorPointerState(SP m) : monitor(m) {} ~SMonitorPointerState() {} diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 5cc7eee0..e50f123f 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -128,6 +128,9 @@ class CSeatManager { void setGrab(SP grab); // nullptr removes SP seatGrab; + bool isPointerFrameSkipped = false; + bool isPointerFrameCommit = false; + private: struct SSeatResourceContainer { SSeatResourceContainer(SP); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 03c72919..eef5e040 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -87,6 +87,11 @@ void CInputManager::onMouseMoved(IPointer::SMotionEvent e) { const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta; + if (g_pSeatManager->isPointerFrameSkipped) + g_pPointerManager->storeMovement((uint64_t)e.timeMs, DELTA, e.unaccel); + else + g_pPointerManager->setStoredMovement((uint64_t)e.timeMs, DELTA, e.unaccel); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); g_pPointerManager->move(DELTA); @@ -167,7 +172,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_vLastCursorPosFloored = MOUSECOORDSFLOORED; - const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); + const auto PMONITOR = isLocked() && g_pCompositor->m_pLastMonitor ? g_pCompositor->m_pLastMonitor.get() : g_pCompositor->getMonitorFromCursor(); // this can happen if there are no displays hooked up to Hyprland if (PMONITOR == nullptr) @@ -184,9 +189,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // constraints if (!g_pSeatManager->mouse.expired() && isConstrained()) { const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); - const auto CONSTRAINT = SURF->constraint(); + const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr; - if (SURF && CONSTRAINT) { + if (CONSTRAINT) { if (CONSTRAINT->isLocked()) { const auto HINT = CONSTRAINT->logicPositionHint(); g_pCompositor->warpCursorTo(HINT, true); @@ -1428,6 +1433,16 @@ bool CInputManager::isConstrained() { return false; } +bool CInputManager::isLocked() { + if (!isConstrained()) + return false; + + const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); + const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr; + + return CONSTRAINT && CONSTRAINT->isLocked(); +} + void CInputManager::updateCapabilities() { uint32_t caps = 0; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index ebf00b2d..d5634796 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -108,6 +108,7 @@ class CInputManager { void unconstrainMouse(); bool isConstrained(); + bool isLocked(); Vector2D getMouseCoordsInternal(); void refocus(); From c3f7c9bbb52b9ad3d24ccfcc5c552ed16c9985a5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 12 Oct 2024 15:18:34 +0100 Subject: [PATCH 279/298] xcursor: don't crash on broken permissions in X themes ref #8079 --- src/managers/XCursorManager.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 1e7ca535..93ee7965 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -117,9 +117,11 @@ void CXCursorManager::loadTheme(std::string const& name, int size, float scale) cursors = loadStandardCursors(themeName, lastLoadSize); } else { for (auto const& p : paths) { - auto dirCursors = loadAllFromDir(p, lastLoadSize); - std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(cursors), - [this](auto const& p) { return std::none_of(cursors.begin(), cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); }); + try { + auto dirCursors = loadAllFromDir(p, lastLoadSize); + std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(cursors), + [this](auto const& p) { return std::none_of(cursors.begin(), cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); }); + } catch (std::exception& e) { Debug::log(ERR, "XCursor path {} can't be loaded: threw error {}", p, e.what()); } } } From 1822707c7e7394ce8c7572f2fe890763a307f499 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 12 Oct 2024 17:56:46 +0100 Subject: [PATCH 280/298] drm-syncobj: fix crash on missing timelines fixes #8092 --- src/protocols/DRMSyncobj.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index a7f242ee..1da4baaf 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -55,6 +55,9 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP= pending.releasePoint) { resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release"); From e79d3cd2ef5632e2e6b3b20fd0b5dc4d2843f956 Mon Sep 17 00:00:00 2001 From: Toni500git Date: Sun, 13 Oct 2024 14:23:33 +0200 Subject: [PATCH 281/298] hyprpm: convert std::cout and std::cerr to std::println() --- hyprpm/src/core/DataState.cpp | 6 +- hyprpm/src/core/PluginManager.cpp | 267 ++++++++++++++------------- hyprpm/src/core/PluginManager.hpp | 3 +- hyprpm/src/helpers/StringUtils.hpp | 32 ++++ hyprpm/src/main.cpp | 35 ++-- hyprpm/src/progress/CProgressBar.cpp | 16 +- hyprpm/src/progress/CProgressBar.hpp | 2 +- 7 files changed, 202 insertions(+), 159 deletions(-) create mode 100644 hyprpm/src/helpers/StringUtils.hpp diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp index 05c63f4e..fb8679d6 100644 --- a/hyprpm/src/core/DataState.cpp +++ b/hyprpm/src/core/DataState.cpp @@ -1,6 +1,6 @@ #include "DataState.hpp" #include -#include +#include #include #include #include "PluginManager.hpp" @@ -8,7 +8,7 @@ std::string DataState::getDataStatePath() { const auto HOME = getenv("HOME"); if (!HOME) { - std::cerr << "DataState: no $HOME\n"; + std::println(stderr, "DataState: no $HOME"); throw std::runtime_error("no $HOME"); return ""; } @@ -242,4 +242,4 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) { } return false; -} \ No newline at end of file +} diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 96ec60ad..359b2c78 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -1,12 +1,15 @@ #include "PluginManager.hpp" #include "../helpers/Colors.hpp" +#include "../helpers/StringUtils.hpp" #include "../progress/CProgressBar.hpp" #include "Manifest.hpp" #include "DataState.hpp" +#include #include #include #include +#include #include #include #include @@ -31,6 +34,7 @@ static std::string execAndGet(std::string cmd) { if (!pipe) return ""; + result.reserve(buffer.size()); while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } @@ -47,10 +51,10 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() { once = true; const auto HLVERCALL = execAndGet("hyprctl version"); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n"; + std::println("{}", verboseString("version returned: {}", HLVERCALL)); if (!HLVERCALL.contains("Tag:")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " You don't seem to be running Hyprland."; + std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland.")); return SHyprlandVersion{}; } @@ -76,7 +80,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() { } catch (...) { ; } if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n"; + std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits)); ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits}; return ver; @@ -102,20 +106,21 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& const auto HLVER = getHyprlandVersion(); if (!hasDeps()) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n"; + std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio")); return false; } if (DataState::pluginRepoExists(url)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n"; + std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed.")); return false; } auto GLOBALSTATE = DataState::getGlobalState(); if (!GLOBALSTATE.dontWarnInstall) { - std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET - << "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n " - << "This message will not appear again.\n"; + std::println("{}!{} Disclaimer: {}", Colors::YELLOW, Colors::RED, Colors::RESET); + std::println("plugins, especially not official, have no guarantee of stability, availablity or security.\n" + "Run them at your own risk.\n" + "This message will not appear again."); GLOBALSTATE.dontWarnInstall = true; DataState::updateGlobalState(GLOBALSTATE); } @@ -129,7 +134,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::getline(std::cin, input); if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { - std::cout << "Aborting.\n"; + std::println(stderr, "Aborting."); return false; } @@ -144,7 +149,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::filesystem::create_directory("/tmp/hyprpm"); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace); } else if (!std::filesystem::is_directory("/tmp/hyprpm")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for hyprpm\n"; + std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm")); return false; } @@ -153,59 +158,59 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME; if (!createSafeDirectory(m_szWorkingPluginDirectory)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for repo\n"; + std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo")); return false; } - progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + url); + progress.printMessageAbove(infoString("Cloning {}", url)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n"; + std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret)); return false; } if (!rev.empty()) { std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev); if (ret.compare(0, 6, "fatal:") == 0) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n"; + std::println(stderr, "\n{}", failureString("Could not check out revision {}. shell returned:\n{}", rev, ret)); return false; } ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; + std::println("{}", verboseString("git submodule update --init returned: {}", ret)); } progress.m_iSteps = 1; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned"); + progress.printMessageAbove(successString("cloned")); progress.m_szCurrentMessage = "Reading the manifest"; progress.print(); std::unique_ptr pManifest; if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest"); + progress.printMessageAbove(successString("found hyprpm manifest")); pManifest = std::make_unique(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest"); + progress.printMessageAbove(successString("found hyprload manifest")); pManifest = std::make_unique(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); } if (!pManifest) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); return false; } if (!pManifest->m_bGood) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); return false; } progress.m_iSteps = 2; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"); + progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:")); for (auto const& pl : pManifest->m_vPlugins) { - std::string message = std::string{Colors::RESET} + " → " + pl.name + " by "; + std::string message = "→ " + pl.name + " by "; for (auto const& a : pl.authors) { message += a + ", "; } @@ -220,19 +225,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& if (!pManifest->m_sRepository.commitPins.empty()) { // check commit pins - progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); + progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); + progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; + std::println("{}", verboseString("git submodule update --init returned: {}", ret)); break; } @@ -244,12 +249,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& const auto HEADERSSTATUS = headersValid(); if (HEADERSSTATUS != HEADERS_OK) { - std::cerr << "\n" << headerError(HEADERSSTATUS); + std::println("\n{}", headerError(HEADERSSTATUS)); return false; } progress.m_iSteps = 3; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " Hyprland headers OK"); + progress.printMessageAbove(successString("Hyprland headers OK")); progress.m_szCurrentMessage = "Building plugin(s)"; progress.print(); @@ -257,35 +262,36 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::string out; if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n"); + progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); + progress.printMessageAbove(infoString("Building {}", p.name)); for (auto const& bs : p.buildSteps) { - std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); + const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; + std::println("{}", verboseString("shell returned: " + out)); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" + - " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update " - "first.\n Try re-running with -v to see " - "more verbose output.\n"); + progress.printMessageAbove(failureString("Plugin {} failed to build.\n" + " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" + " If you are on -git, update first\n" + " Try re-running with -v to see more verbose output.\n", + p.name)); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output); + progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " all plugins built"); + progress.printMessageAbove(successString("all plugins built")); progress.m_iSteps = 4; progress.m_szCurrentMessage = "Installing repository"; progress.print(); @@ -304,13 +310,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& } DataState::addNewPluginRepo(repo); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed repository"); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable"); + progress.printMessageAbove(successString("installed repository")); + progress.printMessageAbove(successString("you can now enable the plugin(s) with hyprpm enable")); progress.m_iSteps = 5; progress.m_szCurrentMessage = "Done!"; progress.print(); - std::cout << "\n"; + std::print("\n"); // remove build files std::filesystem::remove_all(m_szWorkingPluginDirectory); @@ -320,7 +326,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& bool CPluginManager::removePluginRepo(const std::string& urlOrName) { if (!DataState::pluginRepoExists(urlOrName)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n"; + std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed.")); return false; } @@ -331,7 +337,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) { std::getline(std::cin, input); if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { - std::cout << "Aborting.\n"; + std::println("Aborting."); return false; } @@ -347,15 +353,15 @@ eHeadersErrors CPluginManager::headersValid() { return HEADERS_MISSING; // find headers commit - std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); - auto headers = execAndGet(cmd.c_str()); + const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); + auto headers = execAndGet(cmd.c_str()); if (!headers.contains("-I/")) return HEADERS_MISSING; headers.pop_back(); // pop newline - std::string verHeader = ""; + std::string verHeader; while (!headers.empty()) { const auto PATH = headers.substr(0, headers.find(" -I/", 3)); @@ -406,7 +412,7 @@ bool CPluginManager::updateHeaders(bool force) { const auto HLVER = getHyprlandVersion(); if (!hasDeps()) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n"; + std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio")); return false; } @@ -416,7 +422,7 @@ bool CPluginManager::updateHeaders(bool force) { } if (!force && headersValid() == HEADERS_OK) { - std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Headers up to date.\n"; + std::println("\n{}", successString("Headers up to date.")); return true; } @@ -430,11 +436,11 @@ bool CPluginManager::updateHeaders(bool force) { const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME; if (!createSafeDirectory(WORKINGDIR)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for hl\n"; + std::println("\n{}", failureString("Could not prepare working dir for hl")); return false; } - progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); + progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment.")); const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; @@ -443,60 +449,60 @@ bool CPluginManager::updateHeaders(bool force) { const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'"); if (m_bVerbose && bShallow) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); + progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); std::string ret = - execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")); + execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")); if (!std::filesystem::exists(WORKINGDIR)) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Clone failed. Retrying without shallow."); + progress.printMessageAbove(failureString("Clone failed. Retrying without shallow.")); ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME); } if (!std::filesystem::exists(WORKINGDIR + "/.git")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n"; + std::println(stderr, "\n{}", failureString("Could not clone the Hyprland repository. shell returned:\n{}", ret)); return false; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned"); + progress.printMessageAbove(successString("Hyprland cloned")); progress.m_iSteps = 2; progress.m_szCurrentMessage = "Checking out sources"; progress.print(); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); + progress.printMessageAbove(verboseString("will run: cd {} && git checkout {} 2>&1", WORKINGDIR, HLVER.hash)); ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); if (ret.contains("fatal: unable to read tree")) { - std::cerr << "\n" - << Colors::RED << "✖" << Colors::RESET - << " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n"; + std::println(stderr, "\n{}", + failureString("Could not checkout the running Hyprland commit. If you are on -git, try updating.\n" + "You can also try re-running hyprpm update with --no-shallow.")); return false; } if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); + progress.printMessageAbove(verboseString("git returned (co): {}", ret)); ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret); + progress.printMessageAbove(verboseString("git returned (rs): {}", ret)); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " checked out to running ver"); + progress.printMessageAbove(successString("checked out to running ver")); progress.m_iSteps = 3; progress.m_szCurrentMessage = "Building Hyprland"; progress.print(); - progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland"); + progress.printMessageAbove(statusString("!", Colors::YELLOW, "configuring Hyprland")); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath()); + progress.printMessageAbove(verboseString("setting PREFIX for cmake to {}", DataState::getHeadersPath())); ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR, DataState::getHeadersPath())); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); + progress.printMessageAbove(verboseString("cmake returned: {}", ret)); if (ret.contains("CMake Error at")) { // missing deps, let the user know. @@ -505,48 +511,46 @@ bool CPluginManager::updateHeaders(bool force) { missing = missing.substr(0, missing.find("-- Configuring incomplete")); missing = missing.substr(0, missing.find_last_of('\n')); - std::cerr << "\n" - << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" - << missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n"; + std::println(stderr, "\n{}", + failureString("Could not configure the hyprland source, cmake complained:\n{}\n\n" + "This likely means that you are missing the above dependencies or they are out of date.", + missing)); return false; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland"); + progress.printMessageAbove(successString("configured Hyprland")); progress.m_iSteps = 4; progress.m_szCurrentMessage = "Installing sources"; progress.print(); - std::string cmd = + const std::string& cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd); + progress.printMessageAbove(verboseString("installation will run: {}", cmd)); ret = execAndGet(cmd); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n"; + std::println("{}", verboseString("installer returned: {}", ret)); // remove build files std::filesystem::remove_all(WORKINGDIR); auto HEADERSVALID = headersValid(); if (HEADERSVALID == HEADERS_OK) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed headers"); + progress.printMessageAbove(successString("installed headers")); progress.m_iSteps = 5; progress.m_szCurrentMessage = "Done!"; progress.print(); - std::cout << "\n"; + std::print("\n"); } else { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" + - headerErrorShort(HEADERSVALID) + ")"); + progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID))); progress.m_iSteps = 5; progress.m_szCurrentMessage = "Failed"; progress.print(); - std::cout << "\n"; - - std::cerr << "\n" << headerError(HEADERSVALID); + std::print(stderr, "\n\n{}", headerError(HEADERSVALID)); return false; } @@ -556,14 +560,14 @@ bool CPluginManager::updateHeaders(bool force) { bool CPluginManager::updatePlugins(bool forceUpdateAll) { if (headersValid() != HEADERS_OK) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n"; + std::println("{}", failureString("headers are not up-to-date, please run hyprpm update.")); return false; } const auto REPOS = DataState::getAllRepositories(); if (REPOS.size() < 1) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " No repos to update.\n"; + std::println("{}", failureString("No repos to update.")); return true; } @@ -585,25 +589,26 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.m_szCurrentMessage = "Updating " + repo.name; progress.print(); - progress.printMessageAbove(std::string{Colors::RESET} + " → checking for updates for " + repo.name); + progress.printMessageAbove(infoString("checking for updates for {}", repo.name)); createSafeDirectory(m_szWorkingPluginDirectory); - progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + repo.url); + progress.printMessageAbove(infoString("Cloning {}", repo.url)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not clone repo: shell returned:\n" + ret; + std::println("{}", failureString("could not clone repo: shell returned: {}", ret)); return false; } if (!repo.rev.empty()) { - progress.printMessageAbove(std::string{Colors::RESET} + " → Plugin has revision set, resetting: " + repo.rev); + progress.printMessageAbove(infoString("Plugin has revision set, resetting: {}", repo.rev)); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev); if (ret.compare(0, 6, "fatal:") == 0) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret; + std::println(stderr, "\n{}", failureString("could not check out revision {}: shell returned:\n{}", repo.rev, ret)); + return false; } } @@ -619,7 +624,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { if (!update) { std::filesystem::remove_all(m_szWorkingPluginDirectory); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " is up-to-date."); + progress.printMessageAbove(successString("repository {} is up-to-date.", repo.name)); progress.m_iSteps++; progress.print(); continue; @@ -627,41 +632,41 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { // we need to update - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " has updates."); - progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + repo.name); + progress.printMessageAbove(successString("repository {} has updates.", repo.name)); + progress.printMessageAbove(infoString("Building {}", repo.name)); progress.m_iSteps++; progress.print(); std::unique_ptr pManifest; if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest"); + progress.printMessageAbove(successString("found hyprpm manifest")); pManifest = std::make_unique(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest"); + progress.printMessageAbove(successString("found hyprload manifest")); pManifest = std::make_unique(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); } if (!pManifest) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); continue; } if (!pManifest->m_bGood) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); continue; } if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) { // check commit pins unless a revision is specified - progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); + progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); + progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); } @@ -671,32 +676,33 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { std::string out; if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n"); + progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); + progress.printMessageAbove(infoString("Building {}", p.name)); for (auto const& bs : p.buildSteps) { - std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); + const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; + std::println("{}", verboseString("shell returned: {}", out)); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { - std::cerr << "\n" - << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n" - << " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try " - "re-running with -v to see more verbose " - "output.\n"; + std::println(stderr, + "\n{}\n" + " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" + "If you are on -git, update first.\n" + "Try re-running with -v to see more verbose output.", + failureString("Plugin {} failed to build.")); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output); + progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); } // add repo toml to DataState @@ -717,7 +723,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { std::filesystem::remove_all(m_szWorkingPluginDirectory); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name); + progress.printMessageAbove(successString("updated {}", repo.name)); } progress.m_iSteps++; @@ -732,7 +738,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.m_szCurrentMessage = "Done!"; progress.print(); - std::cout << "\n"; + std::print("\n"); return true; } @@ -740,27 +746,27 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { bool CPluginManager::enablePlugin(const std::string& name) { bool ret = DataState::setPluginEnabled(name, true); if (ret) - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Enabled " << name << "\n"; + std::println("{}", successString("Enabled {}", name)); return ret; } bool CPluginManager::disablePlugin(const std::string& name) { bool ret = DataState::setPluginEnabled(name, false); if (ret) - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Disabled " << name << "\n"; + std::println("{}", successString("Disabled {}", name)); return ret; } ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { if (headersValid() != HEADERS_OK) { - std::cerr << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n"; + std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update.")); return LOADSTATE_HEADERS_OUTDATED; } const auto HOME = getenv("HOME"); const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE"); if (!HOME || !HIS) { - std::cerr << "PluginManager: no $HOME or HIS\n"; + std::println(stderr, "PluginManager: no $HOME or HIS"); return LOADSTATE_FAIL; } const auto HYPRPMPATH = DataState::getDataStatePath() + "/"; @@ -769,14 +775,14 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { std::vector loadedPlugins; - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Ensuring plugin load state\n"; + std::println("{}", successString("Ensuring plugin load state")); // iterate line by line while (!pluginLines.empty()) { - auto plLine = pluginLines.substr(0, pluginLines.find("\n")); + auto plLine = pluginLines.substr(0, pluginLines.find('\n')); - if (pluginLines.find("\n") != std::string::npos) - pluginLines = pluginLines.substr(pluginLines.find("\n") + 1); + if (pluginLines.find('\n') != std::string::npos) + pluginLines = pluginLines.substr(pluginLines.find('\n') + 1); else pluginLines = ""; @@ -819,7 +825,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { if (!enabled(p)) { // unload loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false); - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Unloaded " << p << "\n"; + std::println("{}", successString("Unloaded {}", p)); } } @@ -833,11 +839,11 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { continue; loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true); - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Loaded " << p.name << "\n"; + std::println("{}", successString("Loaded {}"), p.name); } } - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Plugin load state ensured\n"; + std::println("{}", successString("Plugin load state ensured")); return LOADSTATE_OK; } @@ -855,16 +861,17 @@ void CPluginManager::listAllPlugins() { const auto REPOS = DataState::getAllRepositories(); for (auto const& r : REPOS) { - std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n"; + std::println("{}", infoString("Repository {}:", r.name)); for (auto const& p : r.plugins) { - - std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name; + std::println(" │ Plugin {}", p.name); if (!p.failed) - std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n"; + std::println(" └─ enabled: {}", (p.enabled ? std::string{Colors::GREEN} + "true" : std::string{Colors::RED} + "false")); else - std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n"; + std::println(" └─ enabled: {}Plugin failed to build", Colors::RED); + + std::println("{}", Colors::RESET); } } } @@ -875,19 +882,19 @@ void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int duratio std::string CPluginManager::headerError(const eHeadersErrors err) { switch (err) { - case HEADERS_CORRUPTED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n"; - case HEADERS_MISMATCHED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n"; - case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "✖" + Colors::RESET + " It doesn't seem you are running on hyprland.\n"; - case HEADERS_MISSING: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n"; + case HEADERS_CORRUPTED: return failureString("Headers corrupted. Please run hyprpm update to fix those.\n"); + case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n"); + case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n"); + case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n"); case HEADERS_DUPLICATED: { - return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" + - " This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" + - " If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n"; + return failureString("Headers duplicated!!! This is a very bad sign.\n" + "This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" + "If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n"); } default: break; } - return std::string{Colors::RED} + "✖" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n"; + return failureString("Unknown header error. Please run hyprpm update to fix those.\n"); } std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp index c16a9d0f..d4603084 100644 --- a/hyprpm/src/core/PluginManager.hpp +++ b/hyprpm/src/core/PluginManager.hpp @@ -2,6 +2,7 @@ #include #include +#include enum eHeadersErrors { HEADERS_OK = 0, @@ -68,7 +69,7 @@ class CPluginManager { std::string headerError(const eHeadersErrors err); std::string headerErrorShort(const eHeadersErrors err); - std::string m_szWorkingPluginDirectory = ""; + std::string m_szWorkingPluginDirectory; }; inline std::unique_ptr g_pPluginManager; diff --git a/hyprpm/src/helpers/StringUtils.hpp b/hyprpm/src/helpers/StringUtils.hpp new file mode 100644 index 00000000..c1a5fd98 --- /dev/null +++ b/hyprpm/src/helpers/StringUtils.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include "Colors.hpp" + +template +std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) { + std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET); + ret += std::vformat(fmt, std::make_format_args(args...)); + return ret; +} + +template +std::string successString(const std::string_view fmt, Args&&... args) { + return statusString("✔", Colors::GREEN, fmt, args...); +} + +template +std::string failureString(const std::string_view fmt, Args&&... args) { + return statusString("✖", Colors::RED, fmt, args...); +} + +template +std::string verboseString(const std::string_view fmt, Args&&... args) { + return statusString("[v]", Colors::BLUE, fmt, args...); +} + +template +std::string infoString(const std::string_view fmt, Args&&... args) { + return statusString("→", Colors::RESET, fmt, args...); +} diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp index 4f00f708..67f14aed 100644 --- a/hyprpm/src/main.cpp +++ b/hyprpm/src/main.cpp @@ -1,15 +1,16 @@ -#include "progress/CProgressBar.hpp" #include "helpers/Colors.hpp" +#include "helpers/StringUtils.hpp" #include "core/PluginManager.hpp" #include "core/DataState.hpp" -#include +#include #include #include +#include #include #include -const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager +constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager ┃ ┣ add [url] [git rev] → Install a new plugin repository from git. Git revision ┃ is optional, when set, commit locks are ignored. @@ -30,14 +31,14 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager ┗ )#"; -int main(int argc, char** argv, char** envp) { +int main(int argc, char** argv, char** envp) { std::vector ARGS{argc}; for (int i = 0; i < argc; ++i) { ARGS[i] = std::string{argv[i]}; } if (ARGS.size() < 2) { - std::cout << HELP; + std::println(stderr, "{}", HELP); return 1; } @@ -47,7 +48,7 @@ int main(int argc, char** argv, char** envp) { for (int i = 1; i < argc; ++i) { if (ARGS[i].starts_with("-")) { if (ARGS[i] == "--help" || ARGS[i] == "-h") { - std::cout << HELP; + std::println("{}", HELP); return 0; } else if (ARGS[i] == "--notify" || ARGS[i] == "-n") { notify = true; @@ -57,9 +58,9 @@ int main(int argc, char** argv, char** envp) { noShallow = true; } else if (ARGS[i] == "--force" || ARGS[i] == "-f") { force = true; - std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n"; + std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing.")); } else { - std::cerr << "Unrecognized option " << ARGS[i] << "\n"; + std::println(stderr, "Unrecognized option {}", ARGS[i]); return 1; } } else { @@ -68,7 +69,7 @@ int main(int argc, char** argv, char** envp) { } if (command.empty()) { - std::cout << HELP; + std::println(stderr, "{}", HELP); return 0; } @@ -78,7 +79,7 @@ int main(int argc, char** argv, char** envp) { if (command[0] == "add") { if (command.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for add.\n"; + std::println(stderr, "{}", failureString("Not enough args for add.")); return 1; } @@ -90,7 +91,7 @@ int main(int argc, char** argv, char** envp) { return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; } else if (command[0] == "remove") { if (ARGS.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for remove.\n"; + std::println(stderr, "{}", failureString("Not enough args for remove.")); return 1; } @@ -116,12 +117,12 @@ int main(int argc, char** argv, char** envp) { g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers"); } else if (command[0] == "enable") { if (ARGS.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for enable.\n"; + std::println(stderr, "{}", failureString("Not enough args for enable.")); return 1; } if (!g_pPluginManager->enablePlugin(command[1])) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't enable plugin (missing?)\n"; + std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)")); return 1; } @@ -130,12 +131,12 @@ int main(int argc, char** argv, char** envp) { return 1; } else if (command[0] == "disable") { if (command.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for disable.\n"; + std::println(stderr, "{}", failureString("Not enough args for disable.")); return 1; } if (!g_pPluginManager->disablePlugin(command[1])) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't disable plugin (missing?)\n"; + std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)")); return 1; } @@ -160,9 +161,9 @@ int main(int argc, char** argv, char** envp) { } else if (command[0] == "list") { g_pPluginManager->listAllPlugins(); } else { - std::cout << HELP; + std::println(stderr, "{}", HELP); return 1; } return 0; -} \ No newline at end of file +} diff --git a/hyprpm/src/progress/CProgressBar.cpp b/hyprpm/src/progress/CProgressBar.cpp index 45602f82..9f2df08a 100644 --- a/hyprpm/src/progress/CProgressBar.cpp +++ b/hyprpm/src/progress/CProgressBar.cpp @@ -1,11 +1,11 @@ #include "CProgressBar.hpp" -#include +#include #include #include #include -#include +#include #include #include @@ -16,11 +16,12 @@ void CProgressBar::printMessageAbove(const std::string& msg) { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); std::string spaces; + spaces.reserve(w.ws_col); for (size_t i = 0; i < w.ws_col; ++i) { spaces += ' '; } - std::cout << "\r" << spaces << "\r" << msg << "\n"; + std::println("\r{}\r{}", spaces, msg); print(); } @@ -29,15 +30,16 @@ void CProgressBar::print() { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); if (m_bFirstPrint) - std::cout << "\n"; + std::print("\n"); m_bFirstPrint = false; std::string spaces; + spaces.reserve(w.ws_col); for (size_t i = 0; i < w.ws_col; ++i) { spaces += ' '; } - std::cout << "\r" << spaces << "\r"; + std::print("\r{}\r", spaces); std::string message = ""; @@ -74,7 +76,7 @@ void CProgressBar::print() { message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " "; // draw message - std::cout << message + " " + m_szCurrentMessage; + std::print("{} {}", message, m_szCurrentMessage); std::fflush(stdout); -} \ No newline at end of file +} diff --git a/hyprpm/src/progress/CProgressBar.hpp b/hyprpm/src/progress/CProgressBar.hpp index 6ac18f21..dfcb36f7 100644 --- a/hyprpm/src/progress/CProgressBar.hpp +++ b/hyprpm/src/progress/CProgressBar.hpp @@ -14,4 +14,4 @@ class CProgressBar { private: bool m_bFirstPrint = true; -}; \ No newline at end of file +}; From b61d4c363679a880e8577a3d983d73dbab367a9d Mon Sep 17 00:00:00 2001 From: Toni500git Date: Sun, 13 Oct 2024 14:23:56 +0200 Subject: [PATCH 282/298] hyprctl: convert std::cout and std::cerr to std::println() --- hyprctl/Strings.hpp | 2 ++ hyprctl/main.cpp | 37 +++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/hyprctl/Strings.hpp b/hyprctl/Strings.hpp index 17725e77..f77626a5 100644 --- a/hyprctl/Strings.hpp +++ b/hyprctl/Strings.hpp @@ -1,5 +1,7 @@ #pragma once +#include + const std::string_view USAGE = R"#(usage: hyprctl [flags] [args...|--help] commands: diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 1ad189b7..1f7f8d74 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -44,11 +45,11 @@ struct SInstanceData { bool valid = true; }; -void log(std::string str) { +void log(const std::string& str) { if (quiet) return; - std::cout << str << "\n"; + std::println("{}", str); } std::string getRuntimeDir() { @@ -105,7 +106,7 @@ std::vector instances() { static volatile bool sigintReceived = false; void intHandler(int sig) { sigintReceived = true; - std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl; + std::println("[hyprctl] SIGINT received, closing connection"); } int rollingRead(const int socket) { @@ -115,12 +116,12 @@ int rollingRead(const int socket) { constexpr size_t BUFFER_SIZE = 8192; std::array buffer = {0}; long sizeWritten = 0; - std::cout << "[hyprctl] reading from socket following up log:" << std::endl; + std::println("[hyprctl] reading from socket following up log:"); while (!sigintReceived) { sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); if (sizeWritten < 0 && errno != EAGAIN) { if (errno != EINTR) - std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl; + std::println("Couldn't read (5): {}: {}", strerror(errno), errno); close(socket); return 5; } @@ -129,7 +130,7 @@ int rollingRead(const int socket) { break; if (sizeWritten > 0) { - std::cout << std::string(buffer.data(), sizeWritten); + std::println("{}", std::string(buffer.data(), sizeWritten)); buffer.fill('\0'); } @@ -323,7 +324,7 @@ int main(int argc, char** argv) { bool parseArgs = true; if (argc < 2) { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -360,7 +361,7 @@ int main(int argc, char** argv) { ++i; if (i >= ARGS.size()) { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -371,24 +372,24 @@ int main(int argc, char** argv) { const std::string& cmd = ARGS[0]; if (cmd == "hyprpaper") { - std::cout << HYPRPAPER_HELP << std::endl; + std::println("{}", HYPRPAPER_HELP); } else if (cmd == "notify") { - std::cout << NOTIFY_HELP << std::endl; + std::println("{}", NOTIFY_HELP); } else if (cmd == "output") { - std::cout << OUTPUT_HELP << std::endl; + std::println("{}", OUTPUT_HELP); } else if (cmd == "plugin") { - std::cout << PLUGIN_HELP << std::endl; + std::println("{}", PLUGIN_HELP); } else if (cmd == "setprop") { - std::cout << SETPROP_HELP << std::endl; + std::println("{}", SETPROP_HELP); } else if (cmd == "switchxkblayout") { - std::cout << SWITCHXKBLAYOUT_HELP << std::endl; + std::println("{}", SWITCHXKBLAYOUT_HELP); } else { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); } return 1; } else { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -399,7 +400,7 @@ int main(int argc, char** argv) { } if (fullRequest.empty()) { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -476,7 +477,7 @@ int main(int argc, char** argv) { else if (fullRequest.contains("/decorations")) exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/--help")) - std::cout << USAGE << std::endl; + std::println("{}", USAGE); else if (fullRequest.contains("/rollinglog") && needRoll) exitStatus = request(fullRequest, 0, true); else { From 05a5e0b4f1ced12f2a0330132f37b0081d7a5e4d Mon Sep 17 00:00:00 2001 From: Toni500git Date: Sun, 13 Oct 2024 14:24:10 +0200 Subject: [PATCH 283/298] hyprland: convert std::cout and std::cerr to std::println() --- src/Compositor.cpp | 14 +++++++------ src/debug/Log.cpp | 4 ++-- src/main.cpp | 51 ++++++++++++++++++++++++---------------------- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index dcc6422d..fd4979b0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -9,7 +9,9 @@ #include "managers/eventLoop/EventLoopManager.hpp" #include #include +#include #include +#include #include #include #include @@ -138,37 +140,37 @@ CCompositor::CCompositor() { m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; if (m_szHyprTempDataRoot.starts_with("/hypr")) { - std::cout << "Bailing out, XDG_RUNTIME_DIR is invalid\n"; + std::println("Bailing out, $XDG_RUNTIME_DIR is invalid"); throw std::runtime_error("CCompositor() failed"); } if (!m_szHyprTempDataRoot.starts_with("/run/user")) - std::cout << "[!!WARNING!!] XDG_RUNTIME_DIR looks non-standard. Proceeding anyways...\n"; + std::println("[!!WARNING!!] XDG_RUNTIME_DIR looks non-standard. Proceeding anyways..."); std::random_device dev; std::mt19937 engine(dev()); std::uniform_int_distribution<> distribution(0, INT32_MAX); - m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL)) + "_" + std::to_string(distribution(engine)); + m_szInstanceSignature = std::format("{}_{}_{}", GIT_COMMIT_HASH, std::time(NULL), distribution(engine)); setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true); if (!std::filesystem::exists(m_szHyprTempDataRoot)) mkdir(m_szHyprTempDataRoot.c_str(), S_IRWXU); else if (!std::filesystem::is_directory(m_szHyprTempDataRoot)) { - std::cout << "Bailing out, " << m_szHyprTempDataRoot << " is not a directory\n"; + std::println("Bailing out, {} is not a directory", m_szHyprTempDataRoot); throw std::runtime_error("CCompositor() failed"); } m_szInstancePath = m_szHyprTempDataRoot + "/" + m_szInstanceSignature; if (std::filesystem::exists(m_szInstancePath)) { - std::cout << "Bailing out, " << m_szInstancePath << " exists??\n"; + std::println("Bailing out, {} exists??", m_szInstancePath); throw std::runtime_error("CCompositor() failed"); } if (mkdir(m_szInstancePath.c_str(), S_IRWXU) < 0) { - std::cout << "Bailing out, couldn't create " << m_szInstancePath << "\n"; + std::println("Bailing out, couldn't create {}", m_szInstancePath); throw std::runtime_error("CCompositor() failed"); } diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index a4c5b08e..5a314833 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -4,7 +4,7 @@ #include "RollingLogFollow.hpp" #include -#include +#include #include void Debug::init(const std::string& IS) { @@ -69,5 +69,5 @@ void Debug::log(LogLevel level, std::string str) { // log it to the stdout too. if (!disableStdout) - std::cout << ((coloredLogs && !**coloredLogs) ? str : coloredStr) << "\n"; + std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr)); } diff --git a/src/main.cpp b/src/main.cpp index 45f212d3..6bbf73fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,9 @@ #include "init/initHelpers.hpp" #include "debug/HyprCtl.hpp" +#include #include +#include using namespace Hyprutils::String; #include @@ -17,15 +19,15 @@ using namespace Hyprutils::String; #include void help() { - std::cout << "usage: Hyprland [arg [...]].\n"; - std::cout << "\nArguments:\n"; - std::cout << " --help -h - Show this message again\n"; - std::cout << " --config FILE -c FILE - Specify config file to use\n"; - std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; - std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; - std::cout << " --systeminfo - Prints system infos\n"; - std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; - std::cout << " --version -v - Print this binary's version\n"; + std::println("usage: Hyprland [arg [...]].\n"); + std::println(R"(Arguments: + --help -h - Show this message again + --config FILE -c FILE - Specify config file to use + --socket NAME - Sets the Wayland socket name (for Wayland socket handover) + --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover) + --systeminfo - Prints system infos + --i-am-really-stupid - Omits root user privileges check (why would you do that?) + --version -v - Print this binary's version)"); } int main(int argc, char** argv) { @@ -53,7 +55,7 @@ int main(int argc, char** argv) { for (auto it = args.begin(); it != args.end(); it++) { if (it->compare("--i-am-really-stupid") == 0 && !ignoreSudo) { - std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n"; + std::println("[ WARNING ] Running Hyprland with superuser privileges might damage your system"); ignoreSudo = true; } else if (it->compare("--socket") == 0) { @@ -79,7 +81,7 @@ int main(int argc, char** argv) { if (fcntl(socketFd, F_GETFD) == -1) throw std::exception(); } catch (...) { - std::cerr << "[ ERROR ] Invalid Wayland FD!\n"; + std::println(stderr, "[ ERROR ] Invalid Wayland FD!"); help(); return 1; @@ -101,7 +103,7 @@ int main(int argc, char** argv) { throw std::exception(); } } catch (...) { - std::cerr << "[ ERROR ] Config file '" << configPath << "' doesn't exist!\n"; + std::println(stderr, "[ ERROR ] Config file '{}' doesn't exist!", configPath); help(); return 1; @@ -117,14 +119,13 @@ int main(int argc, char** argv) { return 0; } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { - std::cout << versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "") << std::endl; + std::println("{}", versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0; } else if (it->compare("--systeminfo") == 0) { - const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""); - std::cout << SYSINFO << "\n"; + std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0; } else { - std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; + std::println(stderr, "[ ERROR ] Unknown option '{}' !", it->c_str()); help(); return 1; @@ -132,30 +133,32 @@ int main(int argc, char** argv) { } if (!ignoreSudo && Init::isSudo()) { - std::cerr << "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n"; - std::cerr << " Hint: Use the --i-am-really-stupid flag to omit that check.\n"; + std::println(stderr, + "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n" + " Hint: Use the --i-am-really-stupid flag to omit that check."); return 1; } else if (ignoreSudo && Init::isSudo()) { - std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n"; + std::println("Superuser privileges check is omitted. I hope you know what you're doing."); } if (socketName.empty() ^ (socketFd == -1)) { - std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n"; - std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n"; + std::println(stderr, + "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n" + " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover."); return 1; } - std::cout << "Welcome to Hyprland!\n"; + std::println("Welcome to Hyprland!"); // let's init the compositor. // it initializes basic Wayland stuff in the constructor. try { g_pCompositor = std::make_unique(); g_pCompositor->explicitConfigPath = configPath; - } catch (std::exception& e) { - std::cout << "Hyprland threw in ctor: " << e.what() << "\nCannot continue.\n"; + } catch (const std::exception& e) { + std::println(stderr, "Hyprland threw in ctor: {}\nCannot continue.", e.what()); return 1; } From 5c3bd8e93d9f25be3e16a0445ba6fce8d30b6d73 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 13 Oct 2024 17:26:39 +0100 Subject: [PATCH 284/298] notif-overlay: add a bit of padding for icons --- src/debug/HyprNotificationOverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 29da20c8..16f80ab6 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -37,7 +37,7 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() { void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) { const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique()).get(); - PNOTIF->text = text; + PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text; PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->started.reset(); PNOTIF->timeMs = timeMs; From 8e51a36c7fd500e865e34f08ab4dc4331dca59cf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 14 Oct 2024 00:19:10 +0100 Subject: [PATCH 285/298] config/example: add optional smart gaps to the default config ref #8106 #8114 --- example/hyprland.conf | 7 +++++++ src/config/defaultConfig.hpp | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/example/hyprland.conf b/example/hyprland.conf index 3478bcff..6d7bddb8 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -117,6 +117,13 @@ animations { animation = workspaces, 1, 6, default } +# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ +# "Smart gaps" / "No gaps when only" +# uncomment all three if you wish to use that. +# workspace = w[t1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = w[tg1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = f[1], gapsout:0, gapsin:0, border: 0, rounding:0 + # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 54ce6642..5c8b0e68 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -130,6 +130,13 @@ animations { animation = workspaces, 1, 6, default } +# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ +# "Smart gaps" / "No gaps when only" +# uncomment all three if you wish to use that. +# workspace = w[t1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = w[tg1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = f[1], gapsout:0, gapsin:0, border: 0, rounding:0 + # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below From abfd550ee228ea23058039790e792b45d2467c8d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 14 Oct 2024 00:24:32 +0100 Subject: [PATCH 286/298] xwm: avoid infinite parent lookup loop in lookupParentExists ref #8045 --- src/xwayland/XWM.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index dcb22eae..248813bf 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -150,10 +150,17 @@ void CXWM::handleUnmapNotify(xcb_unmap_notify_event_t* e) { } static bool lookupParentExists(SP XSURF, SP prospectiveChild) { + std::vector> visited; + while (XSURF->parent) { if (XSURF->parent == prospectiveChild) return true; + visited.emplace_back(XSURF); + XSURF = XSURF->parent.lock(); + + if (std::find(visited.begin(), visited.end(), XSURF) != visited.end()) + return false; } return false; From e7fd0f5aec85c11a8eaf5e1abf8504f0a6d0710e Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Sun, 13 Oct 2024 23:25:19 +0000 Subject: [PATCH 287/298] layout: deny auto-grouping a new floating window into a tiled group (#8108) --- src/layout/IHyprLayout.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 24ee13f4..80c9abff 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -186,12 +186,17 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { g_pCompositor->m_pLastWindow.lock() : g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); - if (*PAUTOGROUP // check if auto_group is enabled. - && OPENINGON // check if OPENINGON exists. - && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. - && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group - && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON - && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + bool denied = false; + if (pWindow->m_bIsFloating && !OPENINGON->m_bIsFloating) + denied = true; + + if (*PAUTOGROUP // check if auto_group is enabled. + && OPENINGON // check if OPENINGON exists. + && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. + && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. + && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group a new window that should be floated. + && !denied) { // don't group a new floated window into a tiled group. pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state From ce62521883e217aab4da305d71e40e4a50567dfb Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 14 Oct 2024 05:37:42 -0500 Subject: [PATCH 288/298] drm-lease: fix crashes and implementation (#8116) --- src/protocols/DRMLease.cpp | 28 ++++++++++++++++++++-------- src/protocols/DRMLease.hpp | 3 ++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 37f2e2eb..d0114ce7 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -44,10 +44,6 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPleaseFD); - - resource->sendLeaseFd(aqlease->leaseFD); - lease = aqlease; for (auto const& m : requested) { @@ -61,8 +57,13 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPsendFinished(); + LOGM(LOG, "Revoking lease for fd {}", lease->leaseFD); }); + LOGM(LOG, "Granting lease, sending fd {}", lease->leaseFD); + + resource->sendLeaseFd(lease->leaseFD); + close(lease->leaseFD); } @@ -70,6 +71,12 @@ bool CDRMLeaseResource::good() { return resource->resource(); } +CDRMLeaseResource::~CDRMLeaseResource() { + // destroy in this order to ensure listener gets called + lease.reset(); + listeners.destroyLease.reset(); +} + CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP resource_) : resource(resource_) { if (!good()) return; @@ -100,7 +107,7 @@ CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP reso return; } - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), self.lock()); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), self.lock()); if (!RESOURCE) { resource->noMemory(); return; @@ -185,7 +192,8 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc close(fd); for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { - sendConnector(m.lock()); + if (m) + sendConnector(m.lock()); } resource->sendDone(); @@ -196,10 +204,10 @@ bool CDRMLeaseDeviceResource::good() { } void CDRMLeaseDeviceResource::sendConnector(SP monitor) { - if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e->monitor == monitor; }) != connectorsSent.end()) + if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e && !e->dead && e->monitor == monitor; }) != connectorsSent.end()) return; - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), monitor); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), 0), monitor); if (!RESOURCE) { resource->noMemory(); return; @@ -267,6 +275,9 @@ void CDRMLeaseProtocol::destroyResource(CDRMLeaseDeviceResource* resource) { } void CDRMLeaseProtocol::destroyResource(CDRMLeaseConnectorResource* resource) { + for (const auto& m : m_vManagers) { + std::erase_if(m->connectorsSent, [resource](const auto& e) { return e.expired() || e->dead || e.get() == resource; }); + } std::erase_if(m_vConnectors, [resource](const auto& e) { return e.get() == resource; }); } @@ -279,6 +290,7 @@ void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) { } void CDRMLeaseProtocol::offer(SP monitor) { + std::erase_if(primaryDevice->offeredOutputs, [](const auto& e) { return e.expired(); }); if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end()) return; diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index 56eaa3db..3671cfce 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -22,12 +22,13 @@ class CDRMLeaseRequestResource; class CDRMLeaseResource { public: CDRMLeaseResource(SP resource_, SP request); + ~CDRMLeaseResource(); bool good(); WP parent; std::vector> requested; - WP lease; + SP lease; int leaseFD = -1; From f309681d4a78d1c12d8a04fe37075a50a750c2ec Mon Sep 17 00:00:00 2001 From: deadacute <6218316+deadacute@users.noreply.github.com> Date: Sun, 13 Oct 2024 20:40:09 +0200 Subject: [PATCH 289/298] example: update desktop file to include DesktopNames --- example/hyprland.desktop | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/example/hyprland.desktop b/example/hyprland.desktop index 57ad076f..bb2801a9 100644 --- a/example/hyprland.desktop +++ b/example/hyprland.desktop @@ -2,4 +2,6 @@ Name=Hyprland Comment=An intelligent dynamic tiling Wayland compositor Exec=Hyprland -Type=Application \ No newline at end of file +Type=Application +DesktopNames=Hyprland +Keywords=tiling;wayland;compositor; From 22b1370ae512c92d84bbcd4cff2a3f8a4496c994 Mon Sep 17 00:00:00 2001 From: "fanlumaster(Fany Full)" <1730976608@qq.com> Date: Tue, 15 Oct 2024 01:03:16 +0800 Subject: [PATCH 290/298] IME: Fixup IME popup candidate windows position when scale is not 1.0 (#8117) --- src/managers/input/InputMethodPopup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index a8757030..cf48f2a5 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -100,14 +100,14 @@ void CInputPopup::updateBox() { cursorBoxParent = {0, 0, (int)parentBox.w, (int)parentBox.h}; } - Vector2D currentPopupSize = surface->getViewporterCorrectedSize(); + Vector2D currentPopupSize = surface->getViewporterCorrectedSize() / surface->resource()->current.scale; CMonitor* pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle()); Vector2D popupOffset(0, 0); if (parentBox.y + cursorBoxParent.y + cursorBoxParent.height + currentPopupSize.y > pMonitor->vecPosition.y + pMonitor->vecSize.y) - popupOffset.y = -currentPopupSize.y; + popupOffset.y -= currentPopupSize.y; else popupOffset.y = cursorBoxParent.height; From 01c2ff34ddcb5995409c33c2b549e93b98b56d6b Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Mon, 14 Oct 2024 18:31:17 +0000 Subject: [PATCH 291/298] layout: simplify the conditions to autogroup (#8120) --- src/layout/IHyprLayout.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 80c9abff..fa3f8b8d 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -191,14 +191,12 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { denied = true; if (*PAUTOGROUP // check if auto_group is enabled. - && OPENINGON // check if OPENINGON exists. - && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. - && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group a new window that should be floated. - && !denied) { // don't group a new floated window into a tiled group. + && !g_pXWaylandManager->shouldBeFloated(pWindow) // fixes the popups of XWayland programs running in a floating group. + && !denied) { // don't group a new floated window into a tiled group (for convenience). - pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state + pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state. Needed to autogroup a new tiled window into a floated group. static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); From ace803948aaed6328342ea57e81adc1a01236c71 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 16 Oct 2024 09:59:47 +0000 Subject: [PATCH 292/298] layout: enable group rules for new floating windows (#8122) * layout: enable group rules for new floating windows * fix comment * do not apply group rules to a new floating window if it shouldBeFloated. fixes child windows * comment --- src/layout/IHyprLayout.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index fa3f8b8d..892ed12c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -82,6 +82,8 @@ void IHyprLayout::onWindowRemovedFloating(PHLWINDOW pWindow) { } void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { + if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows + pWindow->applyGroupRules(); CBox desiredGeometry = {0}; g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); @@ -193,7 +195,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { if (*PAUTOGROUP // check if auto_group is enabled. && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. - && !g_pXWaylandManager->shouldBeFloated(pWindow) // fixes the popups of XWayland programs running in a floating group. + && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !denied. && !denied) { // don't group a new floated window into a tiled group (for convenience). pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state. Needed to autogroup a new tiled window into a floated group. From 0baf166d39260c6d1d422cf528fb5fedc3010cdb Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 16 Oct 2024 10:01:31 +0000 Subject: [PATCH 293/298] [gha] Nix: update inputs --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index de9a4dce..0a12fe0a 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1728326504, - "narHash": "sha256-dQXAj+4d6neY7ldCiH6gNym3upP49PVxRzEPxXlD9Aw=", + "lastModified": 1728902391, + "narHash": "sha256-44bnoY0nAvbBQ/lVjmn511yL39Sv7SknV0BDxn34P3Q=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "65dd97b5d21e917295159bbef1d52e06963f4eb0", + "rev": "9874e08eec85b5542ca22494e127b0cdce46b786", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1727821604, - "narHash": "sha256-hNw5J6xatedqytYowx0mJKgctjA4lQARZFdgnzM2RpM=", + "lastModified": 1728669738, + "narHash": "sha256-EDNAU9AYcx8OupUzbTbWE1d3HYdeG0wO6Msg3iL1muk=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "d60e1e01e6e6633ef1c87148b9137cc1dd39263d", + "rev": "0264e698149fcb857a66a53018157b41f8d97bb0", "type": "github" }, "original": { @@ -151,11 +151,11 @@ ] }, "locked": { - "lastModified": 1727300645, - "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=", + "lastModified": 1728941256, + "narHash": "sha256-WRypmcZ2Bw94lLmcmxYokVOHPJSZ7T06V49QZ4tkZeQ=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c", + "rev": "fd4be8b9ca932f7384e454bcd923c5451ef2aa85", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728018373, - "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", + "lastModified": 1728888510, + "narHash": "sha256-nsNdSldaAyu6PE3YUA+YQLqUDJh+gRbBooMMekZJwvI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", + "rev": "a3c0b3b21515f74fd2665903d4ce6bc4dc81c77c", "type": "github" }, "original": { @@ -229,11 +229,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1728092656, - "narHash": "sha256-eMeCTJZ5xBeQ0f9Os7K8DThNVSo9gy4umZLDfF5q6OM=", + "lastModified": 1728778939, + "narHash": "sha256-WybK5E3hpGxtCYtBwpRj1E9JoiVxe+8kX83snTNaFHE=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "1211305a5b237771e13fcca0c51e60ad47326a9a", + "rev": "ff68f91754be6f3427e4986d7949e6273659be1d", "type": "github" }, "original": { From 781828a56e495439bfe9c0a701cb29f5e4e2df24 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 16 Oct 2024 21:59:29 +0100 Subject: [PATCH 294/298] output: send enter events on late wl_output binds fixes #6560 --- src/protocols/core/Compositor.cpp | 6 ++++++ src/protocols/core/Compositor.hpp | 2 ++ src/protocols/core/Output.cpp | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 37a4bdf1..3d4b63c1 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -589,3 +589,9 @@ void CWLCompositorProtocol::destroyResource(CWLSurfaceResource* resource) { void CWLCompositorProtocol::destroyResource(CWLRegionResource* resource) { std::erase_if(m_vRegions, [&](const auto& other) { return other.get() == resource; }); } + +void CWLCompositorProtocol::forEachSurface(std::function)> fn) { + for (auto& surf : m_vSurfaces) { + fn(surf); + } +} diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index dc1c851f..b3c067c9 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -169,6 +169,8 @@ class CWLCompositorProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void forEachSurface(std::function)> fn); + struct { CSignal newSurface; // SP } events; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 3e68937f..e9f35abc 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -1,4 +1,6 @@ #include "Output.hpp" +#include "Compositor.hpp" +#include "../../Compositor.hpp" #include "../../helpers/Monitor.hpp" CWLOutputResource::CWLOutputResource(SP resource_, SP pMonitor) : monitor(pMonitor), resource(resource_) { @@ -27,6 +29,25 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni } updateState(); + + PROTO::compositor->forEachSurface([](SP surf) { + auto HLSurf = CWLSurface::fromResource(surf); + + if (!HLSurf) + return; + + const auto GEOMETRY = HLSurf->getSurfaceBoxGlobal(); + + if (!GEOMETRY.has_value()) + return; + + for (auto& m : g_pCompositor->m_vMonitors) { + if (!m->logicalBox().overlaps(*GEOMETRY)) + continue; + + surf->enter(m); + } + }); } SP CWLOutputResource::fromResource(wl_resource* res) { From 86e9f69a69990feb880dadd0c2b8c067b2a96fa9 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 16 Oct 2024 21:13:35 +0000 Subject: [PATCH 295/298] layout: move applyGroupRules() to onWindowCreated() (#8139) --- src/layout/DwindleLayout.cpp | 4 ---- src/layout/IHyprLayout.cpp | 7 ++++--- src/layout/MasterLayout.cpp | 2 -- src/render/decorations/CHyprGroupBarDecoration.cpp | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 76b26af1..8a7426eb 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -308,8 +308,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir applyNodeDataToWindow(PNODE); - pWindow->applyGroupRules(); - return; } @@ -450,8 +448,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride); recalculateMonitor(pWindow->m_iMonitorID); - - pWindow->applyGroupRules(); } void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 892ed12c..b8d92636 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -20,6 +20,9 @@ void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; + if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows + pWindow->applyGroupRules(); + bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow); if (autoGrouped) return; @@ -82,8 +85,6 @@ void IHyprLayout::onWindowRemovedFloating(PHLWINDOW pWindow) { } void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { - if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows - pWindow->applyGroupRules(); CBox desiredGeometry = {0}; g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); @@ -194,6 +195,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { if (*PAUTOGROUP // check if auto_group is enabled. && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. + && OPENINGON != pWindow // prevent freeze when the "group set" window rule makes the new window to be already a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !denied. && !denied) { // don't group a new floated window into a tiled group (for convenience). @@ -204,7 +206,6 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); OPENINGON->setGroupCurrent(pWindow); - pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 8fde960d..f983770b 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -116,8 +116,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire return; } - pWindow->applyGroupRules(); - static auto PDROPATCURSOR = CConfigValue("master:drop_at_cursor"); eOrientation orientation = getDynamicOrientation(pWindow->m_pWorkspace); const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index eca3f2cb..74a1e2e9 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -466,7 +466,6 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND std::swap(pDraggedHead->m_sGroupData.head, pWindowInsertEnd->m_sGroupData.head); m_pWindow->setGroupCurrent(pDraggedWindow); - pDraggedWindow->applyGroupRules(); pDraggedWindow->updateWindowDecos(); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow); From 09581d32fd465c5c4ff868090369ee67516c38a9 Mon Sep 17 00:00:00 2001 From: zakk4223 Date: Wed, 16 Oct 2024 16:13:59 -0500 Subject: [PATCH 296/298] hyprpm: Fix crashes due to misplaced fmt argument(s) (#8140) --- hyprpm/src/core/PluginManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 359b2c78..57c67641 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -697,7 +697,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" "If you are on -git, update first.\n" "Try re-running with -v to see more verbose output.", - failureString("Plugin {} failed to build.")); + failureString("Plugin {} failed to build.", p.name)); p.failed = true; continue; } @@ -839,7 +839,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { continue; loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true); - std::println("{}", successString("Loaded {}"), p.name); + std::println("{}", successString("Loaded {}", p.name)); } } From b57086aa4362117c1f1025246f618d760e44b026 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 16 Oct 2024 22:22:36 +0100 Subject: [PATCH 297/298] window: properly break cycles in X11TransientFor ref #8045 --- src/desktop/Window.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index fa85dc07..a393f361 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -451,15 +451,21 @@ PHLWINDOW CWindow::X11TransientFor() { if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent) return nullptr; - auto s = m_pXWaylandSurface->parent; - auto oldParent = s; + auto s = m_pXWaylandSurface->parent; + std::vector> visited; while (s) { - // break cyclic loop of m_pXWaylandSurface being parent of itself, #TODO reject this from even being created? - if (!s->parent || s->parent == oldParent) + // break loops. Some X apps make them, and it seems like it's valid behavior?!?!?! + // TODO: we should reject loops being created in the first place. + if (std::find(visited.begin(), visited.end(), s) != visited.end()) break; + + visited.emplace_back(s.lock()); s = s->parent; } + if (s == m_pXWaylandSurface) + return nullptr; // dead-ass circle + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pXWaylandSurface != s) continue; From 495b92fb535f51a38e5130e6b89bd1fb01ce8cfb Mon Sep 17 00:00:00 2001 From: Behzad Date: Thu, 17 Oct 2024 17:50:18 +0330 Subject: [PATCH 298/298] makefile: fix typo (#8127) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 59efc0ef..98267eea 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ PREFIX = /usr/local legacyrenderer: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` legacyrendererdebug: