Skip to content

Commit 49fe1ca

Browse files
committed
wip ext-ws
1 parent 05fbead commit 49fe1ca

18 files changed

+1040
-0
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_subdirectory(window)
1111
add_subdirectory(io)
1212
add_subdirectory(widgets)
1313
add_subdirectory(ui)
14+
add_subdirectory(windowmanager)
1415

1516
if (CRASH_REPORTER)
1617
add_subdirectory(crash)

src/wayland/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ if (HYPRLAND)
114114
add_subdirectory(hyprland)
115115
endif()
116116

117+
add_subdirectory(windowmanager)
118+
117119
# widgets for qmenu
118120
target_link_libraries(quickshell-wayland PRIVATE
119121
Qt::Quick Qt::Widgets Qt::WaylandClient Qt::WaylandClientPrivate
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
qt_add_library(quickshell-wayland-windowsystem STATIC
2+
windowmanager.cpp
3+
workspace.cpp
4+
ext_workspace.cpp
5+
)
6+
7+
add_library(quickshell-wayland-windowsystem-init OBJECT init.cpp)
8+
target_link_libraries(quickshell-wayland-windowsystem-init PRIVATE Qt::Quick)
9+
10+
#wl_proto(wlp-ext-foreign-toplevel ext-foreign-toplevel-list-v1 "${WAYLAND_PROTOCOLS}/staging/ext-foreign-toplevel-list")
11+
wl_proto(wlp-ext-workspace ext-workspace-v1 "${WAYLAND_PROTOCOLS}/staging/ext-workspace")
12+
13+
target_link_libraries(quickshell-wayland-windowsystem PRIVATE
14+
Qt::WaylandClient Qt::WaylandClientPrivate wayland-client
15+
Qt::Quick # for pch? potentially, check w/ gcc
16+
17+
wlp-ext-foreign-toplevel wlp-ext-workspace
18+
)
19+
20+
target_link_libraries(quickshell PRIVATE quickshell-wayland-windowsystem quickshell-wayland-windowsystem-init)
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#include "ext_workspace.hpp"
2+
3+
#include <qloggingcategory.h>
4+
#include <qobject.h>
5+
#include <qtmetamacros.h>
6+
#include <qtypes.h>
7+
#include <qwayland-ext-workspace-v1.h>
8+
#include <wayland-ext-workspace-v1-client-protocol.h>
9+
10+
namespace qs::wayland::workspace {
11+
12+
Q_LOGGING_CATEGORY(logWorkspace, "quickshell.wm.wayland.workspace");
13+
14+
WorkspaceManager::WorkspaceManager(): QWaylandClientExtensionTemplate(1) { this->initialize(); }
15+
16+
WorkspaceManager* WorkspaceManager::instance() {
17+
static auto* instance = new WorkspaceManager();
18+
return instance;
19+
}
20+
21+
void WorkspaceManager::ext_workspace_manager_v1_workspace_group(
22+
::ext_workspace_group_handle_v1* handle
23+
) {
24+
auto* group = new WorkspaceGroup(handle);
25+
qCDebug(logWorkspace) << "Created group" << group;
26+
this->mGroups.insert(handle, group);
27+
emit this->groupCreated(group);
28+
}
29+
30+
void WorkspaceManager::ext_workspace_manager_v1_workspace(::ext_workspace_handle_v1* handle) {
31+
auto* workspace = new Workspace(handle);
32+
qCDebug(logWorkspace) << "Created workspace" << workspace;
33+
this->mWorkspaces.insert(handle, workspace);
34+
emit this->workspaceCreated(workspace);
35+
};
36+
37+
void WorkspaceManager::destroyWorkspace(Workspace* workspace) {
38+
this->mWorkspaces.remove(workspace->object());
39+
this->destroyedWorkspaces.append(workspace);
40+
emit this->workspaceDestroyed(workspace);
41+
}
42+
43+
void WorkspaceManager::destroyGroup(WorkspaceGroup* group) {
44+
this->mGroups.remove(group->object());
45+
this->destroyedGroups.append(group);
46+
emit this->groupDestroyed(group);
47+
}
48+
49+
void WorkspaceManager::ext_workspace_manager_v1_done() {
50+
qCDebug(logWorkspace) << "Workspace changes done";
51+
emit this->serverCommit();
52+
53+
for (auto* workspace: this->destroyedWorkspaces) delete workspace;
54+
for (auto* group: this->destroyedGroups) delete group;
55+
this->destroyedWorkspaces.clear();
56+
this->destroyedGroups.clear();
57+
}
58+
59+
void WorkspaceManager::ext_workspace_manager_v1_finished() {
60+
qCWarning(logWorkspace) << "ext_workspace_manager_v1.finished() was received";
61+
}
62+
63+
Workspace::~Workspace() {
64+
if (this->isInitialized()) this->destroy();
65+
}
66+
67+
void Workspace::ext_workspace_handle_v1_id(const QString& id) {
68+
qCDebug(logWorkspace) << "Updated id for workspace" << this << "to" << id;
69+
this->id = id;
70+
}
71+
72+
void Workspace::ext_workspace_handle_v1_name(const QString& name) {
73+
qCDebug(logWorkspace) << "Updated name for workspace" << this << "to" << name;
74+
this->name = name;
75+
}
76+
77+
void Workspace::ext_workspace_handle_v1_coordinates(wl_array* coordinates) {
78+
this->coordinates.clear();
79+
80+
auto* data = static_cast<qint32*>(coordinates->data);
81+
auto size = static_cast<qsizetype>(coordinates->size / sizeof(qint32));
82+
83+
for (auto i = 0; i != size; ++i) {
84+
this->coordinates.append(data[i]); // NOLINT
85+
}
86+
87+
qCDebug(logWorkspace) << "Updated coordinates for workspace" << this << "to" << this->coordinates;
88+
}
89+
90+
void Workspace::ext_workspace_handle_v1_state(quint32 state) {
91+
this->active = state & ext_workspace_handle_v1::state_active;
92+
this->urgent = state & ext_workspace_handle_v1::state_urgent;
93+
this->hidden = state & ext_workspace_handle_v1::state_hidden;
94+
95+
qCDebug(logWorkspace).nospace() << "Updated state for workspace " << this
96+
<< " to [active: " << this->active << ", urgent: " << this->urgent
97+
<< ", hidden: " << this->hidden << ']';
98+
}
99+
100+
void Workspace::ext_workspace_handle_v1_capabilities(quint32 capabilities) {
101+
this->canActivate = capabilities & ext_workspace_handle_v1::workspace_capabilities_activate;
102+
this->canDeactivate = capabilities & ext_workspace_handle_v1::workspace_capabilities_deactivate;
103+
this->canRemove = capabilities & ext_workspace_handle_v1::workspace_capabilities_remove;
104+
this->canAssign = capabilities & ext_workspace_handle_v1::workspace_capabilities_assign;
105+
106+
qCDebug(logWorkspace).nospace() << "Updated capabilities for workspace " << this
107+
<< " to [activate: " << this->canActivate
108+
<< ", deactivate: " << this->canDeactivate
109+
<< ", remove: " << this->canRemove
110+
<< ", assign: " << this->canAssign << ']';
111+
}
112+
113+
void Workspace::ext_workspace_handle_v1_removed() {
114+
qCDebug(logWorkspace) << "Destroyed workspace" << this;
115+
WorkspaceManager::instance()->destroyWorkspace(this);
116+
this->destroy();
117+
}
118+
119+
void Workspace::enterGroup(WorkspaceGroup* group) { this->group = group; }
120+
121+
void Workspace::leaveGroup(WorkspaceGroup* group) {
122+
if (this->group == group) this->group = nullptr;
123+
}
124+
125+
WorkspaceGroup::~WorkspaceGroup() {
126+
if (this->isInitialized()) this->destroy();
127+
}
128+
129+
void WorkspaceGroup::ext_workspace_group_handle_v1_capabilities(uint32_t capabilities) {
130+
this->canCreateWorkspace =
131+
capabilities & ext_workspace_group_handle_v1::group_capabilities_create_workspace;
132+
133+
qCDebug(logWorkspace).nospace() << "Updated capabilities for group " << this
134+
<< " to [create_workspace: " << this->canCreateWorkspace << ']';
135+
}
136+
137+
void WorkspaceGroup::ext_workspace_group_handle_v1_output_enter(::wl_output* output) {
138+
qCDebug(logWorkspace) << "Output" << output << "added to group" << this;
139+
this->screens.addOutput(output);
140+
}
141+
142+
void WorkspaceGroup::ext_workspace_group_handle_v1_output_leave(::wl_output* output) {
143+
qCDebug(logWorkspace) << "Output" << output << "removed from group" << this;
144+
this->screens.removeOutput(output);
145+
}
146+
147+
void WorkspaceGroup::ext_workspace_group_handle_v1_workspace_enter(::ext_workspace_handle_v1* handle
148+
) {
149+
auto* workspace = WorkspaceManager::instance()->mWorkspaces.value(handle);
150+
qCDebug(logWorkspace) << "Workspace" << workspace << "added to group" << this;
151+
152+
if (workspace) workspace->enterGroup(this);
153+
}
154+
155+
void WorkspaceGroup::ext_workspace_group_handle_v1_workspace_leave(::ext_workspace_handle_v1* handle
156+
) {
157+
auto* workspace = WorkspaceManager::instance()->mWorkspaces.value(handle);
158+
qCDebug(logWorkspace) << "Workspace" << workspace << "removed from group" << this;
159+
160+
if (workspace) workspace->leaveGroup(this);
161+
}
162+
163+
void WorkspaceGroup::ext_workspace_group_handle_v1_removed() {
164+
qCDebug(logWorkspace) << "Destroyed group" << this;
165+
WorkspaceManager::instance()->destroyGroup(this);
166+
this->destroy();
167+
}
168+
169+
} // namespace qs::wayland::workspace
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
3+
#include <qcontainerfwd.h>
4+
#include <qlist.h>
5+
#include <qloggingcategory.h>
6+
#include <qscreen.h>
7+
#include <qscreen_platform.h>
8+
#include <qtclasshelpermacros.h>
9+
#include <qtmetamacros.h>
10+
#include <qtypes.h>
11+
#include <qwayland-ext-workspace-v1.h>
12+
#include <qwaylandclientextension.h>
13+
#include <wayland-ext-workspace-v1-client-protocol.h>
14+
15+
#include "../output_tracking.hpp"
16+
17+
namespace qs::wayland::workspace {
18+
19+
Q_DECLARE_LOGGING_CATEGORY(logWorkspace);
20+
21+
class WorkspaceGroup;
22+
class Workspace;
23+
24+
class WorkspaceManager
25+
: public QWaylandClientExtensionTemplate<WorkspaceManager>
26+
, public QtWayland::ext_workspace_manager_v1 {
27+
Q_OBJECT;
28+
29+
public:
30+
static WorkspaceManager* instance();
31+
32+
[[nodiscard]] QList<Workspace*> workspaces() { return this->mWorkspaces.values(); }
33+
34+
signals:
35+
void serverCommit();
36+
void workspaceCreated(Workspace* workspace);
37+
void workspaceDestroyed(Workspace* workspace);
38+
void groupCreated(WorkspaceGroup* group);
39+
void groupDestroyed(WorkspaceGroup* group);
40+
41+
protected:
42+
void ext_workspace_manager_v1_workspace_group(::ext_workspace_group_handle_v1* handle) override;
43+
void ext_workspace_manager_v1_workspace(::ext_workspace_handle_v1* handle) override;
44+
void ext_workspace_manager_v1_done() override;
45+
void ext_workspace_manager_v1_finished() override;
46+
47+
private:
48+
WorkspaceManager();
49+
50+
void destroyGroup(WorkspaceGroup* group);
51+
void destroyWorkspace(Workspace* workspace);
52+
53+
QHash<::ext_workspace_handle_v1*, Workspace*> mWorkspaces;
54+
QHash<::ext_workspace_group_handle_v1*, WorkspaceGroup*> mGroups;
55+
QList<WorkspaceGroup*> destroyedGroups;
56+
QList<Workspace*> destroyedWorkspaces;
57+
58+
friend class Workspace;
59+
friend class WorkspaceGroup;
60+
};
61+
62+
class Workspace: public QtWayland::ext_workspace_handle_v1 {
63+
public:
64+
Workspace(::ext_workspace_handle_v1* handle): QtWayland::ext_workspace_handle_v1(handle) {}
65+
~Workspace() override;
66+
Q_DISABLE_COPY_MOVE(Workspace);
67+
68+
QString id;
69+
QString name;
70+
QList<qint32> coordinates;
71+
WorkspaceGroup* group = nullptr;
72+
73+
bool active : 1 = false;
74+
bool urgent : 1 = false;
75+
bool hidden : 1 = false;
76+
77+
bool canActivate : 1 = false;
78+
bool canDeactivate : 1 = false;
79+
bool canRemove : 1 = false;
80+
bool canAssign : 1 = false;
81+
82+
protected:
83+
void ext_workspace_handle_v1_id(const QString& id) override;
84+
void ext_workspace_handle_v1_name(const QString& name) override;
85+
void ext_workspace_handle_v1_coordinates(wl_array* coordinates) override;
86+
void ext_workspace_handle_v1_state(uint32_t state) override;
87+
void ext_workspace_handle_v1_capabilities(uint32_t capabilities) override;
88+
void ext_workspace_handle_v1_removed() override;
89+
90+
private:
91+
void enterGroup(WorkspaceGroup* group);
92+
void leaveGroup(WorkspaceGroup* group);
93+
94+
friend class WorkspaceGroup;
95+
};
96+
97+
class WorkspaceGroup: public QtWayland::ext_workspace_group_handle_v1 {
98+
public:
99+
WorkspaceGroup(::ext_workspace_group_handle_v1* handle)
100+
: QtWayland::ext_workspace_group_handle_v1(handle) {}
101+
102+
~WorkspaceGroup() override;
103+
Q_DISABLE_COPY_MOVE(WorkspaceGroup);
104+
105+
WlOutputTracker screens;
106+
bool canCreateWorkspace : 1 = false;
107+
108+
protected:
109+
void ext_workspace_group_handle_v1_capabilities(uint32_t capabilities) override;
110+
void ext_workspace_group_handle_v1_output_enter(::wl_output* output) override;
111+
void ext_workspace_group_handle_v1_output_leave(::wl_output* output) override;
112+
void ext_workspace_group_handle_v1_workspace_enter(::ext_workspace_handle_v1* handle) override;
113+
void ext_workspace_group_handle_v1_workspace_leave(::ext_workspace_handle_v1* handle) override;
114+
void ext_workspace_group_handle_v1_removed() override;
115+
};
116+
117+
} // namespace qs::wayland::workspace

src/wayland/windowmanager/init.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <qguiapplication.h>
2+
3+
#include "../../core/plugin.hpp"
4+
5+
namespace qs::wm::wayland {
6+
void installWmProvider();
7+
}
8+
9+
namespace {
10+
11+
class WaylandWmPlugin: public QsEnginePlugin {
12+
QList<QString> dependencies() override { return {"window"}; }
13+
14+
bool applies() override { return QGuiApplication::platformName() == "wayland"; }
15+
16+
void init() override { qs::wm::wayland::installWmProvider(); }
17+
};
18+
19+
QS_REGISTER_PLUGIN(WaylandWmPlugin);
20+
21+
} // namespace
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include "windowmanager.hpp"
2+
3+
namespace qs::wm::wayland {
4+
5+
WaylandWindowManager* WaylandWindowManager::instance() {
6+
static auto* instance = new WaylandWindowManager();
7+
return instance;
8+
}
9+
10+
void installWmProvider() {
11+
qs::wm::WindowManager::setProvider([]() { return WaylandWindowManager::instance(); });
12+
}
13+
14+
} // namespace qs::wm::wayland
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
3+
#include <qtmetamacros.h>
4+
5+
#include "../../windowmanager/windowmanager.hpp"
6+
#include "workspace.hpp"
7+
8+
namespace qs::wm::wayland {
9+
10+
class WaylandWindowManager: public WindowManager {
11+
Q_OBJECT;
12+
13+
public:
14+
static WaylandWindowManager* instance();
15+
16+
[[nodiscard]] UntypedObjectModel* workspaces() const override {
17+
return &WorkspaceManager::instance()->mWorkspaces;
18+
}
19+
20+
[[nodiscard]] UntypedObjectModel* workspaceGroups() const override {
21+
return &WorkspaceManager::instance()->mWorkspaceGroups;
22+
}
23+
};
24+
25+
} // namespace qs::wm::wayland

0 commit comments

Comments
 (0)