main.cpp
5331 bytes
1#include <hyprland/src/Compositor.hpp>
2#include <hyprland/src/config/values/ConfigValues.hpp>
3#include <hyprland/src/plugins/PluginAPI.hpp>
4#include <hyprland/src/render/Renderer.hpp>
5#include <hyprland/src/render/OpenGL.hpp>
6#include <hyprland/src/version.h>
7
8#include "dispatchers.hpp"
9#include "globals.hpp"
10#include "TabGroup.hpp"
11
12APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; }
13
14APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
15 PHANDLE = handle;
16
17#ifndef HY3_NO_VERSION_CHECK
18 const std::string COMPOSITOR_HASH = __hyprland_api_get_hash();
19 const std::string CLIENT_HASH = __hyprland_api_get_client_hash();
20
21 if (COMPOSITOR_HASH != CLIENT_HASH) {
22 HyprlandAPI::addNotification(
23 PHANDLE,
24 "[hy3] hy3 was compiled for a different version of hyprland; refusing to load.",
25 CHyprColor {1.0, 0.2, 0.2, 1.0},
26 10000
27 );
28
29 throw std::runtime_error("[hy3] target hyprland version mismatch");
30 }
31#endif
32
33#define CONF(NAME, TYPE, VALUE) \
34 HyprlandAPI::addConfigValueV2(PHANDLE, makeShared<Config::Values::TYPE>("plugin:hy3:" NAME, "", VALUE))
35
36 // general
37 CONF("no_gaps_when_only", Int, 0);
38 CONF("node_collapse_policy", Int, 2);
39 CONF("group_inset", Int, 10);
40 CONF("tab_first_window", Bool, false);
41
42 // tabs
43 CONF("tabs:height", Int, 22);
44 CONF("tabs:padding", Int, 5);
45 CONF("tabs:from_top", Bool, false);
46 CONF("tabs:radius", Int, 6);
47 CONF("tabs:border_width", Int, 2);
48 CONF("tabs:render_text", Bool, true);
49 CONF("tabs:text_center", Bool, true);
50 CONF("tabs:text_font", String, "Sans");
51 CONF("tabs:text_height", Int, 8);
52 CONF("tabs:text_padding", Int, 3);
53 CONF("tabs:opacity", Float, 1.0);
54 CONF("tabs:blur", Bool, true);
55 CONF("tabs:colors:active", Color, 0x4033ccff);
56 CONF("tabs:colors:active_border", Color, 0xee33ccff);
57 CONF("tabs:colors:active_text", Color, 0xffffffff);
58 CONF("tabs:colors:active_alt_monitor", Color, 0x40606060);
59 CONF("tabs:colors:active_alt_monitor_border", Color, 0xee808080);
60 CONF("tabs:colors:active_alt_monitor_text", Color, 0xffffffff);
61 CONF("tabs:colors:focused", Color, 0x40606060);
62 CONF("tabs:colors:focused_border", Color, 0xee808080);
63 CONF("tabs:colors:focused_text", Color, 0xffffffff);
64 CONF("tabs:colors:inactive", Color, 0x20303030);
65 CONF("tabs:colors:inactive_border", Color, 0xaa606060);
66 CONF("tabs:colors:inactive_text", Color, 0xffffffff);
67 CONF("tabs:colors:urgent", Color, 0x40ff2233);
68 CONF("tabs:colors:urgent_border", Color, 0xeeff2233);
69 CONF("tabs:colors:urgent_text", Color, 0xffffffff);
70 CONF("tabs:colors:locked", Color, 0x40909033);
71 CONF("tabs:colors:locked_border", Color, 0xee909033);
72 CONF("tabs:colors:locked_text", Color, 0xffffffff);
73
74 // autotiling
75 CONF("autotile:enable", Bool, false);
76 CONF("autotile:ephemeral_groups", Bool, true);
77 CONF("autotile:trigger_height", Int, 0);
78 CONF("autotile:trigger_width", Int, 0);
79 CONF("autotile:workspaces", String, "all");
80
81#undef CONF
82
83 HyprlandAPI::addTiledAlgo(PHANDLE, "hy3", &typeid(Hy3Layout), []() -> UP<Layout::ITiledAlgorithm> {
84 return makeUnique<Hy3Layout>();
85 });
86
87 g_renderListener = Event::bus()->m_events.render.stage.listen([](eRenderStage stage) {
88 static bool rendering_normally = false;
89 static std::vector<Hy3TabGroup*> rendered_groups;
90
91 switch (stage) {
92 case RENDER_PRE_WINDOWS:
93 rendering_normally = true;
94 rendered_groups.clear();
95 break;
96 case RENDER_POST_WINDOW:
97 if (!rendering_normally) break;
98
99 for (auto& wp: g_tabGroups) {
100 auto* entry = wp.get();
101 if (!entry) continue;
102 if (!entry->hidden
103 && entry->target_window == g_pHyprRenderer->m_renderData.currentWindow.lock()
104 && std::find(rendered_groups.begin(), rendered_groups.end(), entry)
105 == rendered_groups.end())
106 {
107 g_pHyprRenderer->m_renderPass.add(makeUnique<Hy3TabPassElement>(entry));
108 rendered_groups.push_back(entry);
109 }
110 }
111 break;
112 case RENDER_POST_WINDOWS: rendering_normally = false; break;
113 default: break;
114 }
115 });
116
117 g_tickListener = Event::bus()->m_events.tick.listen([]() {
118 for (auto& wp: g_tabGroups) {
119 if (auto* tg = wp.get()) tg->tick();
120 }
121 std::erase_if(g_destroyingTabGroups, [](auto& up) { return up->bar.destroy; });
122 std::erase_if(g_tabGroups, [](auto& wp) { return !wp; });
123 });
124
125 g_windowTitleListener = Event::bus()->m_events.window.title.listen([](PHLWINDOW window) {
126 if (!window) return;
127 auto* hy3 = hy3InstanceForWorkspace(window->m_workspace);
128 if (!hy3) return;
129 auto* node = hy3->getNodeFromWindow(window.get());
130 if (!node) return;
131 node->updateTabBarRecursive();
132 });
133
134 g_urgentListener = Event::bus()->m_events.window.urgent.listen([](PHLWINDOW window) {
135 if (!window) return;
136 window->m_hints |= Desktop::View::WINDOW_HINT_URGENT;
137 auto* hy3 = hy3InstanceForWorkspace(window->m_workspace);
138 if (!hy3) return;
139 auto* node = hy3->getNodeFromWindow(window.get());
140 if (!node) return;
141 node->updateTabBarRecursive();
142 });
143
144 registerDispatchers();
145
146 HyprlandAPI::reloadConfig();
147
148 return {"hy3", "i3 like layout for hyprland", "outfoxxed", "0.1"};
149}
150
151APICALL EXPORT void PLUGIN_EXIT() {
152 g_renderListener.reset();
153 g_tickListener.reset();
154 g_windowTitleListener.reset();
155 g_urgentListener.reset();
156
157 g_tabGroups.clear();
158 g_destroyingTabGroups.clear();
159}