b171721e66f37d2474fd44b49d03055cd57689fa
- Author
- outfoxxed <outfoxxed@outfoxxed.me>
- Committer
- outfoxxed <outfoxxed@outfoxxed.me>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/.gitignore b/.gitignore
2new file mode 100644
3index 0000000000000000000000000000000000000000..b159eae01cad89d899b5e90e99e0bd98d6b0d51c
4--- /dev/null
5+++ b/.gitignore
6@@ -0,0 +1,2 @@
7+build/
8+compile_commands.json
9diff --git a/CMakeLists.txt b/CMakeLists.txt
10new file mode 100644
11index 0000000000000000000000000000000000000000..89ce72b1c7d8db197fdc980fa928ec034a0e11f7
12--- /dev/null
13+++ b/CMakeLists.txt
14@@ -0,0 +1,29 @@
15+cmake_minimum_required(VERSION 3.19)
16+project(Hy3 VERSION "0.1")
17+set(CMAKE_CXX_STANDARD 23)
18+add_compile_definitions(WLR_USE_UNSTABLE)
19+add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith)
20+
21+# nix workaround
22+if(CMAKE_EXPORT_COMPILE_COMMANDS)
23+ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
24+ ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
25+endif()
26+
27+IF(NOT DEFINED ENV{HYPRLAND_HEADERS})
28+ message(FATAL_ERROR "$HYPRLAND_HEADERS is unset")
29+ENDIF()
30+
31+find_package(PkgConfig REQUIRED)
32+pkg_check_modules(DEPS REQUIRED pixman-1 libdrm)
33+
34+add_library(hy3 SHARED
35+ src/main.cpp
36+ src/Hy3Layout.cpp
37+ src/Hy3SpawnLocDecoration.cpp
38+)
39+
40+target_include_directories(hy3 PRIVATE
41+ ${DEPS_INCLUDE_DIRS}
42+ $ENV{HYPRLAND_HEADERS}
43+)
44diff --git a/compile_commands_bear.sh b/compile_commands_bear.sh
45new file mode 100755
46index 0000000000000000000000000000000000000000..f4a6ace9184b5f4d33c8c0962d9cfba614483ae4
47--- /dev/null
48+++ b/compile_commands_bear.sh
49@@ -0,0 +1,8 @@
50+rm -rf build
51+mkdir -p build
52+cd build
53+cmake ..
54+bear -- make
55+mv compile_commands.json ..
56+cd ..
57+sed -i 's/-std=gnu++23/-std=gnu++2b/g' compile_commands.json
58diff --git a/compile_commands_cmake.sh b/compile_commands_cmake.sh
59new file mode 100755
60index 0000000000000000000000000000000000000000..ddf12433992b9ec75bf4476d8e7ca5c8a34adfe2
61--- /dev/null
62+++ b/compile_commands_cmake.sh
63@@ -0,0 +1,6 @@
64+mkdir -p build
65+cd build
66+cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
67+mv compile_commands.json ..
68+cd ..
69+sed -i 's/-std=gnu++23/-std=gnu++2b/g' compile_commands.json
70diff --git a/flake.lock b/flake.lock
71new file mode 100644
72index 0000000000000000000000000000000000000000..eaf318df05f911cf35b3f049bc0532c1a3896666
73--- /dev/null
74+++ b/flake.lock
75@@ -0,0 +1,132 @@
76+{
77+ "nodes": {
78+ "flake-utils": {
79+ "locked": {
80+ "lastModified": 1678901627,
81+ "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
82+ "owner": "numtide",
83+ "repo": "flake-utils",
84+ "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
85+ "type": "github"
86+ },
87+ "original": {
88+ "owner": "numtide",
89+ "repo": "flake-utils",
90+ "type": "github"
91+ }
92+ },
93+ "hyprland": {
94+ "inputs": {
95+ "hyprland-protocols": "hyprland-protocols",
96+ "nixpkgs": "nixpkgs",
97+ "wlroots": "wlroots",
98+ "xdph": "xdph"
99+ },
100+ "locked": {
101+ "lastModified": 1680645538,
102+ "narHash": "sha256-H9gAx2U3XKVoI2WjwbOXULL4TYj9y7ctxBB4up0v9tI=",
103+ "owner": "hyprwm",
104+ "repo": "Hyprland",
105+ "rev": "a80ba54bbc6a423ab0e79730442e09aea832d9d6",
106+ "type": "github"
107+ },
108+ "original": {
109+ "owner": "hyprwm",
110+ "repo": "Hyprland",
111+ "type": "github"
112+ }
113+ },
114+ "hyprland-protocols": {
115+ "inputs": {
116+ "nixpkgs": [
117+ "hyprland",
118+ "nixpkgs"
119+ ]
120+ },
121+ "locked": {
122+ "lastModified": 1671839510,
123+ "narHash": "sha256-+PY1qqJfmZzzROgcIY4I7AkCwpnC+qBIYk2eFoA9RWc=",
124+ "owner": "hyprwm",
125+ "repo": "hyprland-protocols",
126+ "rev": "b8f55e02a328c47ed373133c52483bbfa20a1b75",
127+ "type": "github"
128+ },
129+ "original": {
130+ "owner": "hyprwm",
131+ "repo": "hyprland-protocols",
132+ "type": "github"
133+ }
134+ },
135+ "nixpkgs": {
136+ "locked": {
137+ "lastModified": 1680487167,
138+ "narHash": "sha256-9FNIqrxDZgSliGGN2XJJSvcDYmQbgOANaZA4UWnTdg4=",
139+ "owner": "NixOS",
140+ "repo": "nixpkgs",
141+ "rev": "53dad94e874c9586e71decf82d972dfb640ef044",
142+ "type": "github"
143+ },
144+ "original": {
145+ "owner": "NixOS",
146+ "ref": "nixos-unstable",
147+ "repo": "nixpkgs",
148+ "type": "github"
149+ }
150+ },
151+ "root": {
152+ "inputs": {
153+ "flake-utils": "flake-utils",
154+ "hyprland": "hyprland",
155+ "nixpkgs": [
156+ "hyprland",
157+ "nixpkgs"
158+ ]
159+ }
160+ },
161+ "wlroots": {
162+ "flake": false,
163+ "locked": {
164+ "host": "gitlab.freedesktop.org",
165+ "lastModified": 1680629978,
166+ "narHash": "sha256-2iVx5zqU2CpMgmtVadsHSkhkAsoxAWKQp6RQqt2OgQY=",
167+ "owner": "wlroots",
168+ "repo": "wlroots",
169+ "rev": "835208db98a29431fa687c9506f4b43fe645ff65",
170+ "type": "gitlab"
171+ },
172+ "original": {
173+ "host": "gitlab.freedesktop.org",
174+ "owner": "wlroots",
175diff --git a/flake.nix b/flake.nix
176new file mode 100644
177index 0000000000000000000000000000000000000000..376bb8a629b9569fb084cc9a21cc75504cf3d6fe
178--- /dev/null
179+++ b/flake.nix
180@@ -0,0 +1,51 @@
181+{
182+ inputs = {
183+ hyprland.url = "github:hyprwm/Hyprland";
184+ nixpkgs.follows = "hyprland/nixpkgs";
185+ flake-utils.url = "github:numtide/flake-utils";
186+ };
187+
188+ outputs = { nixpkgs, hyprland, flake-utils, ... }:
189+ flake-utils.lib.eachDefaultSystem (system: let
190+ pkgs = import nixpkgs { inherit system; };
191+ hyprpkgs = hyprland.packages.${system};
192+ in {
193+ packages.default = pkgs.gcc12Stdenv.mkDerivation {
194+ pname = "hy3";
195+ version = "0.1";
196+
197+ src = ./.;
198+
199+ nativeBuildInputs = with pkgs; [
200+ cmake
201+ pkg-config
202+ ];
203+
204+ #HYPRLAND_HEADERS = hyprpkgs.hyprland.src; - TODO
205+ };
206+
207+ devShells.default = pkgs.mkShell.override { stdenv = pkgs.gcc12Stdenv; } {
208+ name = "hy3-shell";
209+ nativeBuildInputs = with pkgs; [
210+ cmake
211+ pkg-config
212+
213+ clang-tools_15
214+ bear
215+ ];
216+
217+ buildInputs = with pkgs; [
218+ hyprpkgs.wlroots-hyprland
219+ libdrm
220+ pixman
221+ ];
222+
223+ inputsFrom = [
224+ hyprpkgs.hyprland
225+ hyprpkgs.wlroots-hyprland
226+ ];
227+
228+ #HYPRLAND_HEADERS = hyprpkgs.hyprland.src; - TODO
229+ };
230+ });
231+}
232diff --git a/src/Hy3Layout.cpp b/src/Hy3Layout.cpp
233new file mode 100644
234index 0000000000000000000000000000000000000000..339496db1c3285e3662b42f5be6931bf75f0018e
235--- /dev/null
236+++ b/src/Hy3Layout.cpp
237@@ -0,0 +1,452 @@
238+#include "Hy3Layout.hpp"
239+#include "src/Window.hpp"
240+#include "src/debug/Log.hpp"
241+#include "src/helpers/Vector2D.hpp"
242+#include "src/helpers/Workspace.hpp"
243+#include "src/managers/XWaylandManager.hpp"
244+#include "src/managers/input/InputManager.hpp"
245+#include "src/render/Renderer.hpp"
246+#include <cairo/cairo.h>
247+#include <ctime>
248+#include <memory>
249+#include <src/Compositor.hpp>
250+
251+Hy3GroupData::Hy3GroupData(Hy3GroupLayout layout): layout(layout) {}
252+
253+Hy3NodeData::Hy3NodeData(): Hy3NodeData((CWindow*)nullptr) {}
254+
255+Hy3NodeData::Hy3NodeData(CWindow *window): type(Hy3NodeData::Window) {
256+ this->as_window = window;
257+}
258+
259+Hy3NodeData::Hy3NodeData(Hy3GroupData group): type(Hy3NodeData::Group) {
260+ new(&this->as_group) Hy3GroupData(std::move(group));
261+}
262+
263+Hy3NodeData::~Hy3NodeData() {
264+ switch (this->type) {
265+ case Hy3NodeData::Window:
266+ break;
267+ case Hy3NodeData::Group:
268+ this->as_group.~Hy3GroupData();
269+
270+ // who ever thought calling the dtor after a move was a good idea?
271+ this->type = Hy3NodeData::Window;
272+ break;
273+ }
274+}
275+
276+Hy3NodeData::Hy3NodeData(const Hy3NodeData& from): type(from.type) {
277+ Debug::log(LOG, "Copy CTor type matches? %d is group? %d", this->type == from.type, this->type == Hy3NodeData::Group);
278+ switch (from.type) {
279+ case Hy3NodeData::Window:
280+ this->as_window = from.as_window;
281+ break;
282+ case Hy3NodeData::Group:
283+ new(&this->as_group) Hy3GroupData(from.as_group);
284+ break;
285+ }
286+}
287+
288+Hy3NodeData::Hy3NodeData(Hy3NodeData&& from): type(from.type) {
289+ Debug::log(LOG, "Move CTor type matches? %d is group? %d", this->type == from.type, this->type == Hy3NodeData::Group);
290+ switch (from.type) {
291+ case Hy3NodeData::Window:
292+ this->as_window = from.as_window;
293+ break;
294+ case Hy3NodeData::Group:
295+ new(&this->as_group) Hy3GroupData(std::move(from.as_group));
296+ break;
297+ }
298+}
299+
300+Hy3NodeData& Hy3NodeData::operator=(const Hy3NodeData& from) {
301+ Debug::log(LOG, "operator= type matches? %d is group? %d", this->type == from.type, this->type == Hy3NodeData::Group);
302+ if (this->type == Hy3NodeData::Group) {
303+ this->as_group.~Hy3GroupData();
304+ }
305+
306+ this->type = from.type;
307+
308+ switch (this->type) {
309+ case Hy3NodeData::Window:
310+ this->as_window = from.as_window;
311+ break;
312+ case Hy3NodeData::Group:
313+ new(&this->as_group) Hy3GroupData(from.as_group);
314+ break;
315+ }
316+
317+ return *this;
318+}
319+
320+bool Hy3NodeData::operator==(const Hy3NodeData& rhs) const {
321+ if (this->type != rhs.type) return false;
322+ switch (this->type) {
323+ case Hy3NodeData::Window:
324+ return this->as_window == rhs.as_window;
325+ case Hy3NodeData::Group:
326+ return this->as_group.children == rhs.as_group.children;
327+ }
328+
329+ return false;
330+}
331+
332+bool Hy3Node::operator==(const Hy3Node& rhs) const {
333+ return this->data == rhs.data;
334+}
335+
336+void Hy3Node::recalcSizePosRecursive(bool force) {
337diff --git a/src/Hy3Layout.hpp b/src/Hy3Layout.hpp
338new file mode 100644
339index 0000000000000000000000000000000000000000..7d23e8054abadd2b20e316f515cb5553f7eddfb5
340--- /dev/null
341+++ b/src/Hy3Layout.hpp
342@@ -0,0 +1,85 @@
343+#pragma once
344+
345+#include <list>
346+#include <src/layout/IHyprLayout.hpp>
347+
348+class Hy3Layout;
349+struct Hy3Node;
350+
351+enum class Hy3GroupLayout {
352+ SplitH,
353+ SplitV,
354+ Tabbed,
355+};
356+
357+struct Hy3GroupData {
358+ Hy3GroupLayout layout = Hy3GroupLayout::SplitH;
359+ std::list<Hy3Node*> children;
360+
361+ Hy3GroupData(Hy3GroupLayout layout);
362+};
363+
364+struct Hy3NodeData {
365+ enum { Group, Window } type;
366+ union {
367+ Hy3GroupData as_group;
368+ CWindow* as_window;
369+ };
370+
371+ bool operator==(const Hy3NodeData&) const;
372+
373+ Hy3NodeData();
374+ Hy3NodeData(CWindow* window);
375+ Hy3NodeData(Hy3GroupData group);
376+ Hy3NodeData(const Hy3NodeData&);
377+ Hy3NodeData(Hy3NodeData&&);
378+ Hy3NodeData& operator=(const Hy3NodeData&);
379+ ~Hy3NodeData();
380+};
381+
382+struct Hy3Node {
383+ Hy3Node* parent = nullptr;
384+ Hy3NodeData data;
385+ Vector2D position;
386+ Vector2D size;
387+ float size_ratio = 1.0;
388+ int workspace_id = -1;
389+ bool valid = true;
390+ Hy3Layout* layout = nullptr;
391+
392+ void recalcSizePosRecursive(bool force = false);
393+
394+ bool operator==(const Hy3Node&) const;
395+};
396+
397+class Hy3Layout: public IHyprLayout {
398+public:
399+ virtual void onWindowCreatedTiling(CWindow*);
400+ virtual void onWindowRemovedTiling(CWindow*);
401+ virtual bool isWindowTiled(CWindow*);
402+ virtual void recalculateMonitor(const int&);
403+ virtual void recalculateWindow(CWindow*);
404+ virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
405+ virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
406+ virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
407+ virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
408+ virtual void switchWindows(CWindow*, CWindow*);
409+ virtual void alterSplitRatio(CWindow*, float, bool);
410+ virtual std::string getLayoutName();
411+ virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
412+
413+ virtual void onEnable();
414+ virtual void onDisable();
415+
416+private:
417+ // std::list is used over std::vector because it does not invalidate references
418+ // when mutated.
419+ std::list<Hy3Node> nodes;
420+
421+ int getWorkspaceNodeCount(const int&);
422+ Hy3Node* getNodeFromWindow(CWindow*);
423+ Hy3Node* getWorkspaceRootGroup(const int&);
424+ void applyNodeDataToWindow(Hy3Node*, bool force = false);
425+
426+ friend struct Hy3Node;
427+};
428diff --git a/src/main.cpp b/src/main.cpp
429new file mode 100644
430index 0000000000000000000000000000000000000000..350e61ca9c8999d0fc9d305a1b87ad2fb1ba13ab
431--- /dev/null
432+++ b/src/main.cpp
433@@ -0,0 +1,49 @@
434+#include <src/plugins/PluginAPI.hpp>
435+
436+#include "Hy3Layout.hpp"
437+#include "src/Compositor.hpp"
438+
439+inline HANDLE PHANDLE = nullptr;
440+inline std::unique_ptr<Hy3Layout> g_Hy3Layout;
441+
442+APICALL EXPORT std::string PLUGIN_API_VERSION() {
443+ return HYPRLAND_API_VERSION;
444+}
445+
446+void splith(std::string) {
447+ SLayoutMessageHeader header;
448+ header.pWindow = g_pCompositor->m_pLastWindow;
449+
450+ if (!header.pWindow) return;
451+
452+ const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
453+ if (workspace->m_bHasFullscreenWindow) return;
454+
455+ g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splith");
456+}
457+
458+void splitv(std::string) {
459+ SLayoutMessageHeader header;
460+ header.pWindow = g_pCompositor->m_pLastWindow;
461+
462+ if (!header.pWindow) return;
463+
464+ const auto workspace = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
465+ if (workspace->m_bHasFullscreenWindow) return;
466+
467+ g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "splitv");
468+}
469+
470+APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
471+ PHANDLE = handle;
472+
473+ g_Hy3Layout = std::make_unique<Hy3Layout>();
474+ HyprlandAPI::addLayout(PHANDLE, "hy3", g_Hy3Layout.get());
475+
476+ HyprlandAPI::addDispatcher(PHANDLE, "splith", splith);
477+ HyprlandAPI::addDispatcher(PHANDLE, "splitv", splitv);
478+
479+ return {"hy3", "i3 like layout for hyprland", "outfoxxed", "0.1"};
480+}
481+
482+APICALL EXPORT void PLUGIN_EXIT() {}