diff --git a/changelog/next.md b/changelog/next.md index cbfd51b..e9b297c 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -26,7 +26,6 @@ set shell id. - Added Quickshell version checking and version gated preprocessing. - Added a way to detect if an icon is from the system icon theme or not. - Added vulkan support to screencopy. -- Added generic WindowManager interface implementing ext-workspace. ## Other Changes diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0c05419..4b13d45 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,6 @@ add_subdirectory(window) add_subdirectory(io) add_subdirectory(widgets) add_subdirectory(ui) -add_subdirectory(windowmanager) if (CRASH_HANDLER) add_subdirectory(crash) diff --git a/src/core/debuginfo.cpp b/src/core/debuginfo.cpp index ae227f8..f26c72e 100644 --- a/src/core/debuginfo.cpp +++ b/src/core/debuginfo.cpp @@ -1,7 +1,4 @@ #include "debuginfo.hpp" -#include -#include -#include #include #include @@ -17,8 +14,6 @@ #include "build.hpp" -extern char** environ; // NOLINT - namespace qs::debuginfo { QString qsVersion() { @@ -124,31 +119,6 @@ QString systemInfo() { return info; } -QString envInfo() { - QString info; - auto stream = QTextStream(&info); - - for (auto** envp = environ; *envp != nullptr; ++envp) { // NOLINT - auto prefixes = std::array { - "QS_", - "QT_", - "QML_", - "QML2_", - "QSG_", - }; - - for (const auto& prefix: prefixes) { - if (strncmp(prefix.data(), *envp, prefix.length()) == 0) goto print; - } - continue; - - print: - stream << *envp << '\n'; - } - - return info; -} - QString combinedInfo() { QString info; auto stream = QTextStream(&info); @@ -166,9 +136,6 @@ QString combinedInfo() { stream << "\n===== System Information =====\n"; stream << systemInfo(); - stream << "\n===== Environment (trimmed) =====\n"; - stream << envInfo(); - return info; } diff --git a/src/core/debuginfo.hpp b/src/core/debuginfo.hpp index fc766fc..cc13f97 100644 --- a/src/core/debuginfo.hpp +++ b/src/core/debuginfo.hpp @@ -8,7 +8,6 @@ QString qsVersion(); QString qtVersion(); QString gpuInfo(); QString systemInfo(); -QString envInfo(); QString combinedInfo(); } // namespace qs::debuginfo diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index db53f37..ca49c8f 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -123,8 +123,6 @@ list(APPEND WAYLAND_MODULES Quickshell.Wayland._IdleNotify) add_subdirectory(shortcuts_inhibit) list(APPEND WAYLAND_MODULES Quickshell.Wayland._ShortcutsInhibitor) -add_subdirectory(windowmanager) - # widgets for qmenu target_link_libraries(quickshell-wayland PRIVATE Qt::Quick Qt::Widgets Qt::WaylandClient Qt::WaylandClientPrivate diff --git a/src/wayland/windowmanager/CMakeLists.txt b/src/wayland/windowmanager/CMakeLists.txt deleted file mode 100644 index 76d1d89..0000000 --- a/src/wayland/windowmanager/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -qt_add_library(quickshell-wayland-windowsystem STATIC - windowmanager.cpp - windowset.cpp - ext_workspace.cpp -) - -add_library(quickshell-wayland-windowsystem-init OBJECT init.cpp) -target_link_libraries(quickshell-wayland-windowsystem-init PRIVATE Qt::Quick) - -wl_proto(wlp-ext-workspace ext-workspace-v1 "${WAYLAND_PROTOCOLS}/staging/ext-workspace") - -target_link_libraries(quickshell-wayland-windowsystem PRIVATE - Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client - wlp-ext-workspace -) - -qs_pch(quickshell-wayland-windowsystem SET large) - -target_link_libraries(quickshell PRIVATE quickshell-wayland-windowsystem quickshell-wayland-windowsystem-init) diff --git a/src/wayland/windowmanager/ext_workspace.cpp b/src/wayland/windowmanager/ext_workspace.cpp deleted file mode 100644 index fcb9ffa..0000000 --- a/src/wayland/windowmanager/ext_workspace.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "ext_workspace.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../core/logcat.hpp" - -namespace qs::wayland::workspace { - -QS_LOGGING_CATEGORY(logWorkspace, "quickshell.wm.wayland.workspace", QtWarningMsg); - -WorkspaceManager::WorkspaceManager(): QWaylandClientExtensionTemplate(1) { this->initialize(); } - -WorkspaceManager* WorkspaceManager::instance() { - static auto* instance = new WorkspaceManager(); - return instance; -} - -void WorkspaceManager::ext_workspace_manager_v1_workspace_group( - ::ext_workspace_group_handle_v1* handle -) { - auto* group = new WorkspaceGroup(handle); - qCDebug(logWorkspace) << "Created group" << group; - this->mGroups.insert(handle, group); - emit this->groupCreated(group); -} - -void WorkspaceManager::ext_workspace_manager_v1_workspace(::ext_workspace_handle_v1* handle) { - auto* workspace = new Workspace(handle); - qCDebug(logWorkspace) << "Created workspace" << workspace; - this->mWorkspaces.insert(handle, workspace); - emit this->workspaceCreated(workspace); -}; - -void WorkspaceManager::destroyWorkspace(Workspace* workspace) { - this->mWorkspaces.remove(workspace->object()); - this->destroyedWorkspaces.append(workspace); - emit this->workspaceDestroyed(workspace); -} - -void WorkspaceManager::destroyGroup(WorkspaceGroup* group) { - this->mGroups.remove(group->object()); - this->destroyedGroups.append(group); - emit this->groupDestroyed(group); -} - -void WorkspaceManager::ext_workspace_manager_v1_done() { - qCDebug(logWorkspace) << "Workspace changes done"; - emit this->serverCommit(); - - for (auto* workspace: this->destroyedWorkspaces) delete workspace; - for (auto* group: this->destroyedGroups) delete group; - this->destroyedWorkspaces.clear(); - this->destroyedGroups.clear(); -} - -void WorkspaceManager::ext_workspace_manager_v1_finished() { - qCWarning(logWorkspace) << "ext_workspace_manager_v1.finished() was received"; -} - -Workspace::~Workspace() { - if (this->isInitialized()) this->destroy(); -} - -void Workspace::ext_workspace_handle_v1_id(const QString& id) { - qCDebug(logWorkspace) << "Updated id for workspace" << this << "to" << id; - this->id = id; -} - -void Workspace::ext_workspace_handle_v1_name(const QString& name) { - qCDebug(logWorkspace) << "Updated name for workspace" << this << "to" << name; - this->name = name; -} - -void Workspace::ext_workspace_handle_v1_coordinates(wl_array* coordinates) { - this->coordinates.clear(); - - auto* data = static_cast(coordinates->data); - auto size = static_cast(coordinates->size / sizeof(qint32)); - - for (auto i = 0; i != size; ++i) { - this->coordinates.append(data[i]); // NOLINT - } - - qCDebug(logWorkspace) << "Updated coordinates for workspace" << this << "to" << this->coordinates; -} - -void Workspace::ext_workspace_handle_v1_state(quint32 state) { - this->active = state & ext_workspace_handle_v1::state_active; - this->urgent = state & ext_workspace_handle_v1::state_urgent; - this->hidden = state & ext_workspace_handle_v1::state_hidden; - - qCDebug(logWorkspace).nospace() << "Updated state for workspace " << this - << " to [active: " << this->active << ", urgent: " << this->urgent - << ", hidden: " << this->hidden << ']'; -} - -void Workspace::ext_workspace_handle_v1_capabilities(quint32 capabilities) { - this->canActivate = capabilities & ext_workspace_handle_v1::workspace_capabilities_activate; - this->canDeactivate = capabilities & ext_workspace_handle_v1::workspace_capabilities_deactivate; - this->canRemove = capabilities & ext_workspace_handle_v1::workspace_capabilities_remove; - this->canAssign = capabilities & ext_workspace_handle_v1::workspace_capabilities_assign; - - qCDebug(logWorkspace).nospace() << "Updated capabilities for workspace " << this - << " to [activate: " << this->canActivate - << ", deactivate: " << this->canDeactivate - << ", remove: " << this->canRemove - << ", assign: " << this->canAssign << ']'; -} - -void Workspace::ext_workspace_handle_v1_removed() { - qCDebug(logWorkspace) << "Destroyed workspace" << this; - WorkspaceManager::instance()->destroyWorkspace(this); - this->destroy(); -} - -void Workspace::enterGroup(WorkspaceGroup* group) { this->group = group; } - -void Workspace::leaveGroup(WorkspaceGroup* group) { - if (this->group == group) this->group = nullptr; -} - -WorkspaceGroup::~WorkspaceGroup() { - if (this->isInitialized()) this->destroy(); -} - -void WorkspaceGroup::ext_workspace_group_handle_v1_capabilities(quint32 capabilities) { - this->canCreateWorkspace = - capabilities & ext_workspace_group_handle_v1::group_capabilities_create_workspace; - - qCDebug(logWorkspace).nospace() << "Updated capabilities for group " << this - << " to [create_workspace: " << this->canCreateWorkspace << ']'; -} - -void WorkspaceGroup::ext_workspace_group_handle_v1_output_enter(::wl_output* output) { - qCDebug(logWorkspace) << "Output" << output << "added to group" << this; - this->screens.addOutput(output); -} - -void WorkspaceGroup::ext_workspace_group_handle_v1_output_leave(::wl_output* output) { - qCDebug(logWorkspace) << "Output" << output << "removed from group" << this; - this->screens.removeOutput(output); -} - -void WorkspaceGroup::ext_workspace_group_handle_v1_workspace_enter( - ::ext_workspace_handle_v1* handle -) { - auto* workspace = WorkspaceManager::instance()->mWorkspaces.value(handle); - qCDebug(logWorkspace) << "Workspace" << workspace << "added to group" << this; - - if (workspace) workspace->enterGroup(this); -} - -void WorkspaceGroup::ext_workspace_group_handle_v1_workspace_leave( - ::ext_workspace_handle_v1* handle -) { - auto* workspace = WorkspaceManager::instance()->mWorkspaces.value(handle); - qCDebug(logWorkspace) << "Workspace" << workspace << "removed from group" << this; - - if (workspace) workspace->leaveGroup(this); -} - -void WorkspaceGroup::ext_workspace_group_handle_v1_removed() { - qCDebug(logWorkspace) << "Destroyed group" << this; - WorkspaceManager::instance()->destroyGroup(this); - this->destroy(); -} - -} // namespace qs::wayland::workspace diff --git a/src/wayland/windowmanager/ext_workspace.hpp b/src/wayland/windowmanager/ext_workspace.hpp deleted file mode 100644 index 6aff209..0000000 --- a/src/wayland/windowmanager/ext_workspace.hpp +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../core/logcat.hpp" -#include "../output_tracking.hpp" - -namespace qs::wayland::workspace { - -QS_DECLARE_LOGGING_CATEGORY(logWorkspace); - -class WorkspaceGroup; -class Workspace; - -class WorkspaceManager - : public QWaylandClientExtensionTemplate - , public QtWayland::ext_workspace_manager_v1 { - Q_OBJECT; - -public: - static WorkspaceManager* instance(); - - [[nodiscard]] QList workspaces() { return this->mWorkspaces.values(); } - -signals: - void serverCommit(); - void workspaceCreated(Workspace* workspace); - void workspaceDestroyed(Workspace* workspace); - void groupCreated(WorkspaceGroup* group); - void groupDestroyed(WorkspaceGroup* group); - -protected: - void ext_workspace_manager_v1_workspace_group(::ext_workspace_group_handle_v1* handle) override; - void ext_workspace_manager_v1_workspace(::ext_workspace_handle_v1* handle) override; - void ext_workspace_manager_v1_done() override; - void ext_workspace_manager_v1_finished() override; - -private: - WorkspaceManager(); - - void destroyGroup(WorkspaceGroup* group); - void destroyWorkspace(Workspace* workspace); - - QHash<::ext_workspace_handle_v1*, Workspace*> mWorkspaces; - QHash<::ext_workspace_group_handle_v1*, WorkspaceGroup*> mGroups; - QList destroyedGroups; - QList destroyedWorkspaces; - - friend class Workspace; - friend class WorkspaceGroup; -}; - -class Workspace: public QtWayland::ext_workspace_handle_v1 { -public: - Workspace(::ext_workspace_handle_v1* handle): QtWayland::ext_workspace_handle_v1(handle) {} - ~Workspace() override; - Q_DISABLE_COPY_MOVE(Workspace); - - QString id; - QString name; - QList coordinates; - WorkspaceGroup* group = nullptr; - - bool active : 1 = false; - bool urgent : 1 = false; - bool hidden : 1 = false; - - bool canActivate : 1 = false; - bool canDeactivate : 1 = false; - bool canRemove : 1 = false; - bool canAssign : 1 = false; - -protected: - void ext_workspace_handle_v1_id(const QString& id) override; - void ext_workspace_handle_v1_name(const QString& name) override; - void ext_workspace_handle_v1_coordinates(wl_array* coordinates) override; - void ext_workspace_handle_v1_state(quint32 state) override; - void ext_workspace_handle_v1_capabilities(quint32 capabilities) override; - void ext_workspace_handle_v1_removed() override; - -private: - void enterGroup(WorkspaceGroup* group); - void leaveGroup(WorkspaceGroup* group); - - friend class WorkspaceGroup; -}; - -class WorkspaceGroup: public QtWayland::ext_workspace_group_handle_v1 { -public: - WorkspaceGroup(::ext_workspace_group_handle_v1* handle) - : QtWayland::ext_workspace_group_handle_v1(handle) {} - - ~WorkspaceGroup() override; - Q_DISABLE_COPY_MOVE(WorkspaceGroup); - - WlOutputTracker screens; - bool canCreateWorkspace : 1 = false; - -protected: - void ext_workspace_group_handle_v1_capabilities(quint32 capabilities) override; - void ext_workspace_group_handle_v1_output_enter(::wl_output* output) override; - void ext_workspace_group_handle_v1_output_leave(::wl_output* output) override; - void ext_workspace_group_handle_v1_workspace_enter(::ext_workspace_handle_v1* handle) override; - void ext_workspace_group_handle_v1_workspace_leave(::ext_workspace_handle_v1* handle) override; - void ext_workspace_group_handle_v1_removed() override; -}; - -} // namespace qs::wayland::workspace diff --git a/src/wayland/windowmanager/init.cpp b/src/wayland/windowmanager/init.cpp deleted file mode 100644 index 88be01a..0000000 --- a/src/wayland/windowmanager/init.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -#include "../../core/plugin.hpp" - -namespace qs::wm::wayland { -void installWmProvider(); -} - -namespace { - -class WaylandWmPlugin: public QsEnginePlugin { - QList dependencies() override { return {"window"}; } - - bool applies() override { return QGuiApplication::platformName() == "wayland"; } - - void init() override { qs::wm::wayland::installWmProvider(); } -}; - -QS_REGISTER_PLUGIN(WaylandWmPlugin); - -} // namespace diff --git a/src/wayland/windowmanager/windowmanager.cpp b/src/wayland/windowmanager/windowmanager.cpp deleted file mode 100644 index 16245d0..0000000 --- a/src/wayland/windowmanager/windowmanager.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "windowmanager.hpp" - -#include "../../windowmanager/windowmanager.hpp" -#include "windowset.hpp" - -namespace qs::wm::wayland { - -WaylandWindowManager* WaylandWindowManager::instance() { - static auto* instance = []() { - auto* wm = new WaylandWindowManager(); - WindowsetManager::instance(); - return wm; - }(); - return instance; -} - -void installWmProvider() { // NOLINT (misc-use-internal-linkage) - qs::wm::WindowManager::setProvider([]() { return WaylandWindowManager::instance(); }); -} - -} // namespace qs::wm::wayland diff --git a/src/wayland/windowmanager/windowmanager.hpp b/src/wayland/windowmanager/windowmanager.hpp deleted file mode 100644 index 9d48efd..0000000 --- a/src/wayland/windowmanager/windowmanager.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include "../../windowmanager/windowmanager.hpp" -#include "windowset.hpp" - -namespace qs::wm::wayland { - -class WaylandWindowManager: public WindowManager { - Q_OBJECT; - -public: - static WaylandWindowManager* instance(); -}; - -} // namespace qs::wm::wayland diff --git a/src/wayland/windowmanager/windowset.cpp b/src/wayland/windowmanager/windowset.cpp deleted file mode 100644 index 796cfe2..0000000 --- a/src/wayland/windowmanager/windowset.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include "windowset.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../../windowmanager/windowmanager.hpp" -#include "../../windowmanager/windowset.hpp" -#include "../../windowmanager/screenprojection.hpp" -#include "ext_workspace.hpp" - -namespace qs::wm::wayland { - -WindowsetManager::WindowsetManager() { - auto* impl = impl::WorkspaceManager::instance(); - - QObject::connect( - impl, - &impl::WorkspaceManager::serverCommit, - this, - &WindowsetManager::onServerCommit - ); - - QObject::connect( - impl, - &impl::WorkspaceManager::workspaceCreated, - this, - &WindowsetManager::onWindowsetCreated - ); - - QObject::connect( - impl, - &impl::WorkspaceManager::workspaceDestroyed, - this, - &WindowsetManager::onWindowsetDestroyed - ); - - QObject::connect( - impl, - &impl::WorkspaceManager::groupCreated, - this, - &WindowsetManager::onProjectionCreated - ); - - QObject::connect( - impl, - &impl::WorkspaceManager::groupDestroyed, - this, - &WindowsetManager::onProjectionDestroyed - ); -} - -void WindowsetManager::scheduleCommit() { - if (this->commitScheduled) { - qCDebug(impl::logWorkspace) << "Workspace commit already scheduled."; - return; - } - - qCDebug(impl::logWorkspace) << "Scheduling workspace commit..."; - this->commitScheduled = true; - QMetaObject::invokeMethod(this, &WindowsetManager::doCommit, Qt::QueuedConnection); -} - -void WindowsetManager::doCommit() { // NOLINT - qCDebug(impl::logWorkspace) << "Committing workspaces..."; - impl::WorkspaceManager::instance()->commit(); - this->commitScheduled = false; -} - -void WindowsetManager::onServerCommit() { - // Projections are created/destroyed around windowsets to avoid any nulls making it - // to the qml engine. - - Qt::beginPropertyUpdateGroup(); - - auto* wm = WindowManager::instance(); - auto windowsets = wm->bWindowsets.value(); - auto projections = wm->bWindowsetProjections.value(); - - for (auto* projImpl: this->pendingProjectionCreations) { - auto* projection = new WlWindowsetProjection(this, projImpl); - this->projectionsByImpl.insert(projImpl, projection); - projections.append(projection); - } - - for (auto* wsImpl: this->pendingWindowsetCreations) { - auto* ws = new WlWindowset(this, wsImpl); - this->windowsetByImpl.insert(wsImpl, ws); - windowsets.append(ws); - } - - for (auto* wsImpl: this->pendingWindowsetDestructions) { - windowsets.removeOne(this->windowsetByImpl.value(wsImpl)); - this->windowsetByImpl.remove(wsImpl); - } - - for (auto* projImpl: this->pendingProjectionDestructions) { - projections.removeOne(this->projectionsByImpl.value(projImpl)); - this->projectionsByImpl.remove(projImpl); - } - - for (auto* ws: windowsets) { - static_cast(ws)->commitImpl(); // NOLINT - } - - for (auto* projection: projections) { - static_cast(projection)->commitImpl(); // NOLINT - } - - this->pendingWindowsetCreations.clear(); - this->pendingWindowsetDestructions.clear(); - this->pendingProjectionCreations.clear(); - this->pendingProjectionDestructions.clear(); - - wm->bWindowsets = windowsets; - wm->bWindowsetProjections = projections; - - Qt::endPropertyUpdateGroup(); -} - -void WindowsetManager::onWindowsetCreated(impl::Workspace* workspace) { - this->pendingWindowsetCreations.append(workspace); -} - -void WindowsetManager::onWindowsetDestroyed(impl::Workspace* workspace) { - if (!this->pendingWindowsetCreations.removeOne(workspace)) { - this->pendingWindowsetDestructions.append(workspace); - } -} - -void WindowsetManager::onProjectionCreated(impl::WorkspaceGroup* group) { - this->pendingProjectionCreations.append(group); -} - -void WindowsetManager::onProjectionDestroyed(impl::WorkspaceGroup* group) { - if (!this->pendingProjectionCreations.removeOne(group)) { - this->pendingProjectionDestructions.append(group); - } -} - -WindowsetManager* WindowsetManager::instance() { - static auto* instance = new WindowsetManager(); - return instance; -} - -WlWindowset::WlWindowset(WindowsetManager* manager, impl::Workspace* impl) - : Windowset(manager) - , impl(impl) { - this->commitImpl(); -} - -void WlWindowset::commitImpl() { - Qt::beginPropertyUpdateGroup(); - this->bId = this->impl->id; - this->bName = this->impl->name; - this->bCoordinates = this->impl->coordinates; - this->bActive = this->impl->active; - this->bShouldDisplay = !this->impl->hidden; - this->bUrgent = this->impl->urgent; - this->bCanActivate = this->impl->canActivate; - this->bCanDeactivate = this->impl->canDeactivate; - this->bCanSetProjection = this->impl->canAssign; - this->bProjection = this->manager()->projectionsByImpl.value(this->impl->group); - Qt::endPropertyUpdateGroup(); -} - -void WlWindowset::activate() { - if (!this->bCanActivate) { - qCritical(logWorkspace) << this << "cannot be activated"; - return; - } - - qCDebug(impl::logWorkspace) << "Calling activate() for" << this; - this->impl->activate(); - WindowsetManager::instance()->scheduleCommit(); -} - -void WlWindowset::deactivate() { - if (!this->bCanDeactivate) { - qCritical(logWorkspace) << this << "cannot be deactivated"; - return; - } - - qCDebug(impl::logWorkspace) << "Calling deactivate() for" << this; - this->impl->deactivate(); - WindowsetManager::instance()->scheduleCommit(); -} - -void WlWindowset::remove() { - if (!this->bCanRemove) { - qCritical(logWorkspace) << this << "cannot be removed"; - return; - } - - qCDebug(impl::logWorkspace) << "Calling remove() for" << this; - this->impl->remove(); - WindowsetManager::instance()->scheduleCommit(); -} - -void WlWindowset::setProjection(WindowsetProjection* projection) { - if (!this->bCanSetProjection) { - qCritical(logWorkspace) << this << "cannot be assigned to a projection"; - return; - } - - if (!projection) { - qCritical(logWorkspace) << "Cannot set a windowset's projection to null"; - return; - } - - WlWindowsetProjection* wlProjection = nullptr; - if (auto* p = dynamic_cast(projection)) { - wlProjection = p; - } else if (auto* p = dynamic_cast(projection)) { - // In the 99% case, there will only be a single windowset on a screen. - // In the 1% case, the oldest projection (first in list) is most likely the desired one. - auto* screen = p->screen(); - for (const auto& proj: WindowsetManager::instance()->projectionsByImpl.values()) { - if (proj->bQScreens.value().contains(screen)) { - wlProjection = proj; - break; - } - } - } - - if (!wlProjection) { - qCritical(logWorkspace) << "Cannot set a windowset's projection to" << projection - << "as no wayland projection could be derived."; - return; - } - - qCDebug(impl::logWorkspace) << "Assigning" << this << "to" << projection; - this->impl->assign(wlProjection->impl->object()); - WindowsetManager::instance()->scheduleCommit(); -} - -WlWindowsetProjection::WlWindowsetProjection(WindowsetManager* manager, impl::WorkspaceGroup* impl) - : WindowsetProjection(manager) - , impl(impl) { - this->commitImpl(); -} - -void WlWindowsetProjection::commitImpl() { - // TODO: will not commit the correct screens if missing qt repr at commit time - this->bQScreens = this->impl->screens.screens(); -} - -} // namespace qs::wm::wayland diff --git a/src/wayland/windowmanager/windowset.hpp b/src/wayland/windowmanager/windowset.hpp deleted file mode 100644 index 52d1c63..0000000 --- a/src/wayland/windowmanager/windowset.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "../../windowmanager/windowset.hpp" -#include "ext_workspace.hpp" - -namespace qs::wm::wayland { -namespace impl = qs::wayland::workspace; - -class WlWindowset; -class WlWindowsetProjection; - -class WindowsetManager: public QObject { - Q_OBJECT; - -public: - static WindowsetManager* instance(); - - void scheduleCommit(); - -private slots: - void doCommit(); - void onServerCommit(); - void onWindowsetCreated(impl::Workspace* workspace); - void onWindowsetDestroyed(impl::Workspace* workspace); - void onProjectionCreated(impl::WorkspaceGroup* group); - void onProjectionDestroyed(impl::WorkspaceGroup* group); - -private: - WindowsetManager(); - - bool commitScheduled = false; - - QList pendingWindowsetCreations; - QList pendingWindowsetDestructions; - QHash windowsetByImpl; - - QList pendingProjectionCreations; - QList pendingProjectionDestructions; - QHash projectionsByImpl; - - friend class WlWindowset; -}; - -class WlWindowset: public Windowset { -public: - WlWindowset(WindowsetManager* manager, impl::Workspace* impl); - - void commitImpl(); - - void activate() override; - void deactivate() override; - void remove() override; - void setProjection(WindowsetProjection* projection) override; - - [[nodiscard]] WindowsetManager* manager() { - return static_cast(this->parent()); // NOLINT - } - -private: - impl::Workspace* impl = nullptr; -}; - -class WlWindowsetProjection: public WindowsetProjection { -public: - WlWindowsetProjection(WindowsetManager* manager, impl::WorkspaceGroup* impl); - - void commitImpl(); - - [[nodiscard]] WindowsetManager* manager() { - return static_cast(this->parent()); // NOLINT - } - -private: - impl::WorkspaceGroup* impl = nullptr; - - friend class WlWindowset; -}; - -} // namespace qs::wm::wayland diff --git a/src/windowmanager/CMakeLists.txt b/src/windowmanager/CMakeLists.txt deleted file mode 100644 index 3c032f4..0000000 --- a/src/windowmanager/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -qt_add_library(quickshell-windowmanager STATIC - screenprojection.cpp - windowmanager.cpp - windowset.cpp -) - -qt_add_qml_module(quickshell-windowmanager - URI Quickshell.WindowManager - VERSION 0.1 - DEPENDENCIES QtQuick -) - -qs_add_module_deps_light(quickshell-windowmanager Quickshell) - -install_qml_module(quickshell-windowmanager) - -qs_module_pch(quickshell-windowmanager SET large) - -target_link_libraries(quickshell-windowmanager PRIVATE Qt::Quick) -target_link_libraries(quickshell PRIVATE quickshell-windowmanagerplugin) diff --git a/src/windowmanager/module.md b/src/windowmanager/module.md deleted file mode 100644 index 3480d60..0000000 --- a/src/windowmanager/module.md +++ /dev/null @@ -1,10 +0,0 @@ -name = "Quickshell.WindowManager" -description = "Window manager interface" -headers = [ - "windowmanager.hpp", - "windowset.hpp", - "screenprojection.hpp", -] ------ -Currently only supports the [ext-workspace-v1](https://wayland.app/protocols/ext-workspace-v1) wayland protocol. -Support will be expanded in future releases. diff --git a/src/windowmanager/screenprojection.cpp b/src/windowmanager/screenprojection.cpp deleted file mode 100644 index c09e6f0..0000000 --- a/src/windowmanager/screenprojection.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "screenprojection.hpp" - -#include -#include -#include - -#include "windowmanager.hpp" -#include "windowset.hpp" - -namespace qs::wm { - -ScreenProjection::ScreenProjection(QScreen* screen, QObject* parent) - : WindowsetProjection(parent) - , mScreen(screen) { - this->bQScreens = {screen}; - this->bWindowsets.setBinding([this]() { - QList result; - for (auto* ws: WindowManager::instance()->bindableWindowsets().value()) { - auto* proj = ws->bindableProjection().value(); - if (proj && proj->bindableQScreens().value().contains(this->mScreen)) { - result.append(ws); - } - } - return result; - }); -} - -QScreen* ScreenProjection::screen() const { return this->mScreen; } - -} // namespace qs::wm diff --git a/src/windowmanager/screenprojection.hpp b/src/windowmanager/screenprojection.hpp deleted file mode 100644 index 6b0f31e..0000000 --- a/src/windowmanager/screenprojection.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "windowset.hpp" - -namespace qs::wm { - -///! WindowsetProjection covering one specific screen. -/// A ScreenProjection is a special type of @@WindowsetProjection which aggregates -/// all windowsets across all projections covering a specific screen. -/// -/// When used with @@Windowset.setProjection(), an arbitrary projection on the screen -/// will be picked. Usually there is only one. -/// -/// Use @@WindowManager.screenProjection() to get a ScreenProjection for a given screen. -class ScreenProjection: public WindowsetProjection { - Q_OBJECT; - QML_ELEMENT; - QML_UNCREATABLE(""); - -public: - ScreenProjection(QScreen* screen, QObject* parent); - - [[nodiscard]] QScreen* screen() const; - -private: - QScreen* mScreen; -}; - -} // namespace qs::wm diff --git a/src/windowmanager/test/manual/WorkspaceDelegate.qml b/src/windowmanager/test/manual/WorkspaceDelegate.qml deleted file mode 100644 index 4ebd7f2..0000000 --- a/src/windowmanager/test/manual/WorkspaceDelegate.qml +++ /dev/null @@ -1,86 +0,0 @@ -import QtQuick -import QtQuick.Controls.Fusion -import QtQuick.Layouts -import Quickshell -import Quickshell.Widgets -import Quickshell.WindowManager - -WrapperRectangle { - id: delegate - required property Windowset modelData; - color: modelData.active ? "green" : "gray" - - ColumnLayout { - Label { text: delegate.modelData.toString() } - Label { text: `Id: ${delegate.modelData.id} Name: ${delegate.modelData.name}` } - Label { text: `Coordinates: ${delegate.modelData.coordinates.toString()}`} - - RowLayout { - Label { text: "Group:" } - ComboBox { - Layout.fillWidth: true - implicitContentWidthPolicy: ComboBox.WidestText - enabled: delegate.modelData.canSetProjection - model: [...WindowManager.windowsetProjections].map(w => w.toString()) - currentIndex: WindowManager.windowsetProjections.indexOf(delegate.modelData.projection) - onActivated: i => delegate.modelData.setProjection(WindowManager.windowsetProjections[i]) - } - } - - RowLayout { - Label { text: "Screen:" } - ComboBox { - Layout.fillWidth: true - implicitContentWidthPolicy: ComboBox.WidestText - enabled: delegate.modelData.canSetProjection - model: [...Quickshell.screens].map(w => w.name) - currentIndex: Quickshell.screens.indexOf(delegate.modelData.projection.screens[0]) - onActivated: i => delegate.modelData.setProjection(WindowManager.screenProjection(Quickshell.screens[i])) - } - } - - - RowLayout { - DisplayCheckBox { - text: "Active" - checked: delegate.modelData.active - } - - DisplayCheckBox { - text: "Urgent" - checked: delegate.modelData.urgent - } - - DisplayCheckBox { - text: "Should Display" - checked: delegate.modelData.shouldDisplay - } - } - - RowLayout { - Button { - text: "Activate" - enabled: delegate.modelData.canActivate - onClicked: delegate.modelData.activate() - } - - Button { - text: "Deactivate" - enabled: delegate.modelData.canDeactivate - onClicked: delegate.modelData.deactivate() - } - - Button { - text: "Remove" - enabled: delegate.modelData.canRemove - onClicked: delegate.modelData.remove() - } - } - } - - component DisplayCheckBox: CheckBox { - enabled: false - palette.disabled.text: parent.palette.active.text - palette.disabled.windowText: parent.palette.active.windowText - } -} diff --git a/src/windowmanager/test/manual/screenproj.qml b/src/windowmanager/test/manual/screenproj.qml deleted file mode 100644 index d06036c..0000000 --- a/src/windowmanager/test/manual/screenproj.qml +++ /dev/null @@ -1,45 +0,0 @@ -import QtQuick -import QtQuick.Controls.Fusion -import QtQuick.Layouts -import Quickshell -import Quickshell.Widgets -import Quickshell.WindowManager - -FloatingWindow { - ScrollView { - anchors.fill: parent - - ColumnLayout { - Repeater { - model: Quickshell.screens - - WrapperRectangle { - id: delegate - required property ShellScreen modelData - color: "slategray" - margin: 5 - - ColumnLayout { - Label { text: `Screen: ${delegate.modelData.name}` } - - Repeater { - model: ScriptModel { - values: WindowManager.screenProjection(delegate.modelData).windowsets - } - - WorkspaceDelegate {} - } - } - } - } - - Repeater { - model: ScriptModel { - values: WindowManager.windowsets.filter(w => w.projection == null) - } - - WorkspaceDelegate {} - } - } - } -} diff --git a/src/windowmanager/test/manual/workspaces.qml b/src/windowmanager/test/manual/workspaces.qml deleted file mode 100644 index d6fdf05..0000000 --- a/src/windowmanager/test/manual/workspaces.qml +++ /dev/null @@ -1,46 +0,0 @@ -import QtQuick -import QtQuick.Controls.Fusion -import QtQuick.Layouts -import Quickshell -import Quickshell.Widgets -import Quickshell.WindowManager - -FloatingWindow { - ScrollView { - anchors.fill: parent - - ColumnLayout { - Repeater { - model: WindowManager.windowsetProjections - - WrapperRectangle { - id: delegate - required property WindowsetProjection modelData - color: "slategray" - margin: 5 - - ColumnLayout { - Label { text: delegate.modelData.toString() } - Label { text: `Screens: ${delegate.modelData.screens.map(s => s.name)}` } - - Repeater { - model: ScriptModel { - values: delegate.modelData.windowsets - } - - WorkspaceDelegate {} - } - } - } - } - - Repeater { - model: ScriptModel { - values: WindowManager.windowsets.filter(w => w.projection == null) - } - - WorkspaceDelegate {} - } - } - } -} diff --git a/src/windowmanager/windowmanager.cpp b/src/windowmanager/windowmanager.cpp deleted file mode 100644 index 6b51db1..0000000 --- a/src/windowmanager/windowmanager.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "windowmanager.hpp" -#include -#include - -#include - -#include "../core/qmlscreen.hpp" -#include "screenprojection.hpp" - -namespace qs::wm { - -std::function WindowManager::provider; - -void WindowManager::setProvider(std::function provider) { - WindowManager::provider = std::move(provider); -} - -WindowManager* WindowManager::instance() { - static auto* instance = WindowManager::provider(); - return instance; -} - -ScreenProjection* WindowManager::screenProjection(QuickshellScreenInfo* screen) { - auto* qscreen = screen->screen; - auto it = this->mScreenProjections.find(qscreen); - if (it != this->mScreenProjections.end()) { - return *it; - } - - auto* projection = new ScreenProjection(qscreen, this); - this->mScreenProjections.insert(qscreen, projection); - - QObject::connect(qscreen, &QObject::destroyed, this, [this, projection, qscreen]() { - this->mScreenProjections.remove(qscreen); - delete projection; - }); - - return projection; -} - -} // namespace qs::wm diff --git a/src/windowmanager/windowmanager.hpp b/src/windowmanager/windowmanager.hpp deleted file mode 100644 index 054e485..0000000 --- a/src/windowmanager/windowmanager.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../core/qmlscreen.hpp" -#include "screenprojection.hpp" -#include "windowset.hpp" - -namespace qs::wm { - -class WindowManager: public QObject { - Q_OBJECT; - -public: - static void setProvider(std::function provider); - static WindowManager* instance(); - - Q_INVOKABLE ScreenProjection* screenProjection(QuickshellScreenInfo* screen); - - [[nodiscard]] QBindable> bindableWindowsets() const { - return &this->bWindowsets; - } - - [[nodiscard]] QBindable> bindableWindowsetProjections() const { - return &this->bWindowsetProjections; - } - -signals: - void windowsetsChanged(); - void windowsetProjectionsChanged(); - -public: - Q_OBJECT_BINDABLE_PROPERTY( - WindowManager, - QList, - bWindowsets, - &WindowManager::windowsetsChanged - ); - - Q_OBJECT_BINDABLE_PROPERTY( - WindowManager, - QList, - bWindowsetProjections, - &WindowManager::windowsetProjectionsChanged - ); - -private: - static std::function provider; - QHash mScreenProjections; -}; - -///! Window management interfaces exposed by the window manager. -class WindowManagerQml: public QObject { - Q_OBJECT; - QML_NAMED_ELEMENT(WindowManager); - QML_SINGLETON; - // clang-format off - /// All windowsets tracked by the WM across all projections. - Q_PROPERTY(QList windowsets READ default BINDABLE bindableWindowsets); - /// All windowset projections tracked by the WM. Does not include - /// internal projections from @@screenProjection(). - Q_PROPERTY(QList windowsetProjections READ default BINDABLE bindableWindowsetProjections); - // clang-format on - -public: - /// Returns an internal WindowsetProjection that covers a single screen and contains all - /// windowsets on that screen, regardless of the WM-specified projection. Depending on - /// how the WM lays out its actual projections, multiple ScreenProjections may contain - /// the same Windowsets. - Q_INVOKABLE static ScreenProjection* screenProjection(QuickshellScreenInfo* screen) { - return WindowManager::instance()->screenProjection(screen); - } - - [[nodiscard]] static QBindable> bindableWindowsets() { - return WindowManager::instance()->bindableWindowsets(); - } - - [[nodiscard]] static QBindable> bindableWindowsetProjections() { - return WindowManager::instance()->bindableWindowsetProjections(); - } -}; - -} // namespace qs::wm diff --git a/src/windowmanager/windowset.cpp b/src/windowmanager/windowset.cpp deleted file mode 100644 index 6231c40..0000000 --- a/src/windowmanager/windowset.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "windowset.hpp" - -#include -#include -#include -#include - -#include "../core/qmlglobal.hpp" -#include "windowmanager.hpp" - -namespace qs::wm { - -Q_LOGGING_CATEGORY(logWorkspace, "quickshell.wm.workspace", QtWarningMsg); - -void Windowset::activate() { qCCritical(logWorkspace) << this << "cannot be activated"; } -void Windowset::deactivate() { qCCritical(logWorkspace) << this << "cannot be deactivated"; } -void Windowset::remove() { qCCritical(logWorkspace) << this << "cannot be removed"; } - -void Windowset::setProjection(WindowsetProjection* /*projection*/) { - qCCritical(logWorkspace) << this << "cannot be assigned to a projection"; -} - -WindowsetProjection::WindowsetProjection(QObject* parent): QObject(parent) { - this->bWindowsets.setBinding([this] { - QList result; - for (auto* ws: WindowManager::instance()->bindableWindowsets().value()) { - if (ws->bindableProjection().value() == this) { - result.append(ws); - } - } - return result; - }); - - this->bScreens.setBinding([this] { - QList screens; - - for (auto* screen: this->bQScreens.value()) { - screens.append(QuickshellTracked::instance()->screenInfo(screen)); - } - - return screens; - }); -} - -} // namespace qs::wm diff --git a/src/windowmanager/windowset.hpp b/src/windowmanager/windowset.hpp deleted file mode 100644 index 51cbd9b..0000000 --- a/src/windowmanager/windowset.hpp +++ /dev/null @@ -1,175 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class QuickshellScreenInfo; - -namespace qs::wm { - -Q_DECLARE_LOGGING_CATEGORY(logWorkspace); - -class WindowsetProjection; - -///! A group of windows worked with by a user, usually known as a Workspace or Tag. -/// A Windowset is a generic type that encompasses both "Workspaces" and "Tags" in window managers. -/// Because the definition encompasses both you may not necessarily need all features. -class Windowset: public QObject { - Q_OBJECT; - QML_ELEMENT; - QML_UNCREATABLE(""); - // clang-format off - /// A persistent internal identifier for the windowset. This property should be identical - /// across restarts and destruction/recreation of a windowset. - Q_PROPERTY(QString id READ default NOTIFY idChanged BINDABLE bindableId); - /// Human readable name of the windowset. - Q_PROPERTY(QString name READ default NOTIFY nameChanged BINDABLE bindableName); - /// Coordinates of the workspace, represented as an N-dimensional array. Most WMs - /// will only expose one coordinate. If more than one is exposed, the first is - /// conventionally X, the second Y, and the third Z. - Q_PROPERTY(QList coordinates READ default NOTIFY coordinatesChanged BINDABLE bindableCoordinates); - /// True if the windowset is currently active. In a workspace based WM, this means the - /// represented workspace is current. In a tag based WM, this means the represented tag - /// is active. - Q_PROPERTY(bool active READ default NOTIFY activeChanged BINDABLE bindableActive); - /// The projection this windowset is a member of. A projection is the set of screens covered by - /// a windowset. - Q_PROPERTY(WindowsetProjection* projection READ default NOTIFY projectionChanged BINDABLE bindableProjection); - /// If false, this windowset should generally be hidden from workspace pickers. - Q_PROPERTY(bool shouldDisplay READ default NOTIFY shouldDisplayChanged BINDABLE bindableShouldDisplay); - /// If true, a window in this windowset has been marked as urgent. - Q_PROPERTY(bool urgent READ default NOTIFY urgentChanged BINDABLE bindableUrgent); - /// If true, the windowset can be activated. In a workspace based WM, this will make the workspace - /// current, in a tag based wm, the tag will be activated. - Q_PROPERTY(bool canActivate READ default NOTIFY canActivateChanged BINDABLE bindableCanActivate); - /// If true, the windowset can be deactivated. In a workspace based WM, deactivation is usually implicit - /// and based on activation of another workspace. - Q_PROPERTY(bool canDeactivate READ default NOTIFY canDeactivateChanged BINDABLE bindableCanDeactivate); - /// If true, the windowset can be removed. This may be done implicitly by the WM as well. - Q_PROPERTY(bool canRemove READ default NOTIFY canRemoveChanged BINDABLE bindableCanRemove); - /// If true, the windowset can be moved to a different projection. - Q_PROPERTY(bool canSetProjection READ default NOTIFY canSetProjectionChanged BINDABLE bindableCanSetProjection); - // clang-format on - -public: - explicit Windowset(QObject* parent): QObject(parent) {} - - /// Activate the windowset, making it the current workspace on a workspace based WM, or activating - /// the tag on a tag based WM. Requires @@canActivate. - Q_INVOKABLE virtual void activate(); - /// Deactivate the windowset, hiding it. Requires @@canDeactivate. - Q_INVOKABLE virtual void deactivate(); - /// Remove or destroy the windowset. Requires @@canRemove. - Q_INVOKABLE virtual void remove(); - /// Move the windowset to a different projection. A projection represents the set of screens - /// a workspace spans. Requires @@canSetProjection. - Q_INVOKABLE virtual void setProjection(WindowsetProjection* projection); - - [[nodiscard]] QBindable bindableId() const { return &this->bId; } - [[nodiscard]] QBindable bindableName() const { return &this->bName; } - [[nodiscard]] QBindable> bindableCoordinates() const { return &this->bCoordinates; } - [[nodiscard]] QBindable bindableActive() const { return &this->bActive; } - - [[nodiscard]] QBindable bindableProjection() const { - return &this->bProjection; - } - - [[nodiscard]] QBindable bindableShouldDisplay() const { return &this->bShouldDisplay; } - [[nodiscard]] QBindable bindableUrgent() const { return &this->bUrgent; } - [[nodiscard]] QBindable bindableCanActivate() const { return &this->bCanActivate; } - [[nodiscard]] QBindable bindableCanDeactivate() const { return &this->bCanDeactivate; } - [[nodiscard]] QBindable bindableCanRemove() const { return &this->bCanRemove; } - - [[nodiscard]] QBindable bindableCanSetProjection() const { - return &this->bCanSetProjection; - } - -signals: - void idChanged(); - void nameChanged(); - void coordinatesChanged(); - void activeChanged(); - void projectionChanged(); - void shouldDisplayChanged(); - void urgentChanged(); - void canActivateChanged(); - void canDeactivateChanged(); - void canRemoveChanged(); - void canSetProjectionChanged(); - -protected: - // clang-format off - Q_OBJECT_BINDABLE_PROPERTY(Windowset, QString, bId, &Windowset::idChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, QString, bName, &Windowset::nameChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, QList, bCoordinates); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, bool, bActive, &Windowset::activeChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, WindowsetProjection*, bProjection, &Windowset::projectionChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, bool, bShouldDisplay, &Windowset::shouldDisplayChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, bool, bUrgent, &Windowset::urgentChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, bool, bCanActivate, &Windowset::canActivateChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, bool, bCanDeactivate, &Windowset::canDeactivateChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, bool, bCanRemove, &Windowset::canRemoveChanged); - Q_OBJECT_BINDABLE_PROPERTY(Windowset, bool, bCanSetProjection, &Windowset::canSetProjectionChanged); - // clang-format on -}; - -///! A space occupiable by a Windowset. -/// A WindowsetProjection represents a space that can be occupied by one or more @@Windowset$s. -/// The space is one or more screens. Multiple projections may occupy the same screens. -/// -/// @@WindowManager.screenProjection() can be used to get a projection representing all -/// @@Windowset$s on a given screen regardless of the WM's actual projection layout. -class WindowsetProjection: public QObject { - Q_OBJECT; - QML_ELEMENT; - QML_UNCREATABLE(""); - // clang-format off - /// Screens the windowset projection spans, often a single screen or all screens. - Q_PROPERTY(QList screens READ default NOTIFY screensChanged BINDABLE bindableScreens); - /// Windowsets that are currently present on the projection. - Q_PROPERTY(QList windowsets READ default NOTIFY windowsetsChanged BINDABLE bindableWindowsets); - // clang-format on - -public: - explicit WindowsetProjection(QObject* parent); - - [[nodiscard]] QBindable> bindableScreens() const { - return &this->bScreens; - } - - [[nodiscard]] QBindable> bindableQScreens() const { return &this->bQScreens; } - - [[nodiscard]] QBindable> bindableWindowsets() const { - return &this->bWindowsets; - } - -signals: - void screensChanged(); - void windowsetsChanged(); - -protected: - Q_OBJECT_BINDABLE_PROPERTY(WindowsetProjection, QList, bQScreens); - - Q_OBJECT_BINDABLE_PROPERTY( - WindowsetProjection, - QList, - bScreens, - &WindowsetProjection::screensChanged - ); - - Q_OBJECT_BINDABLE_PROPERTY( - WindowsetProjection, - QList, - bWindowsets, - &WindowsetProjection::windowsetsChanged - ); -}; - -} // namespace qs::wm