Parent directory

main.cpp

5476 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:padding_horizontal", Int, -1);
 46	CONF("tabs:padding_outer", Bool, true);
 47	CONF("tabs:from_top", Bool, false);
 48	CONF("tabs:radius", Int, 6);
 49	CONF("tabs:border_width", Int, 2);
 50	CONF("tabs:render_text", Bool, true);
 51	CONF("tabs:text_center", Bool, true);
 52	CONF("tabs:text_font", String, "Sans");
 53	CONF("tabs:text_height", Int, 8);
 54	CONF("tabs:text_padding", Int, 3);
 55	CONF("tabs:opacity", Float, 1.0);
 56	CONF("tabs:blur", Bool, true);
 57	CONF("tabs:colors:active", Color, 0x4033ccff);
 58	CONF("tabs:colors:active_border", Color, 0xee33ccff);
 59	CONF("tabs:colors:active_text", Color, 0xffffffff);
 60	CONF("tabs:colors:active_alt_monitor", Color, 0x40606060);
 61	CONF("tabs:colors:active_alt_monitor_border", Color, 0xee808080);
 62	CONF("tabs:colors:active_alt_monitor_text", Color, 0xffffffff);
 63	CONF("tabs:colors:focused", Color, 0x40606060);
 64	CONF("tabs:colors:focused_border", Color, 0xee808080);
 65	CONF("tabs:colors:focused_text", Color, 0xffffffff);
 66	CONF("tabs:colors:inactive", Color, 0x20303030);
 67	CONF("tabs:colors:inactive_border", Color, 0xaa606060);
 68	CONF("tabs:colors:inactive_text", Color, 0xffffffff);
 69	CONF("tabs:colors:urgent", Color, 0x40ff2233);
 70	CONF("tabs:colors:urgent_border", Color, 0xeeff2233);
 71	CONF("tabs:colors:urgent_text", Color, 0xffffffff);
 72	CONF("tabs:colors:locked", Color, 0x40909033);
 73	CONF("tabs:colors:locked_border", Color, 0xee909033);
 74	CONF("tabs:colors:locked_text", Color, 0xffffffff);
 75
 76	// autotiling
 77	CONF("autotile:enable", Bool, false);
 78	CONF("autotile:ephemeral_groups", Bool, true);
 79	CONF("autotile:trigger_height", Int, 0);
 80	CONF("autotile:trigger_width", Int, 0);
 81	CONF("autotile:workspaces", String, "all");
 82
 83#undef CONF
 84
 85	HyprlandAPI::addTiledAlgo(PHANDLE, "hy3", &typeid(Hy3Layout), []() -> UP<Layout::ITiledAlgorithm> {
 86		return makeUnique<Hy3Layout>();
 87	});
 88
 89	g_renderListener = Event::bus()->m_events.render.stage.listen([](const Event::SRenderStageEvent& event) {
 90		static bool rendering_normally = false;
 91		static std::vector<Hy3TabGroup*> rendered_groups;
 92
 93		switch (event.stage) {
 94		case RENDER_PRE_WINDOWS:
 95			rendering_normally = true;
 96			rendered_groups.clear();
 97			break;
 98		case RENDER_POST_WINDOW:
 99			if (!rendering_normally || !event.context) break;
100
101			for (auto& wp: g_tabGroups) {
102				auto* entry = wp.get();
103				if (!entry) continue;
104				if (!entry->hidden
105				    && entry->target_window == event.context->get().m_data.currentWindow.lock()
106				    && std::find(rendered_groups.begin(), rendered_groups.end(), entry)
107				           == rendered_groups.end())
108				{
109					g_pHyprRenderer->addPassElement(event.context->get(), makeUnique<Hy3TabPassElement>(entry));
110					rendered_groups.push_back(entry);
111				}
112			}
113			break;
114		case RENDER_POST_WINDOWS: rendering_normally = false; break;
115		default: break;
116		}
117	});
118
119	g_tickListener = Event::bus()->m_events.tick.listen([]() {
120		for (auto& wp: g_tabGroups) {
121			if (auto* tg = wp.get()) tg->tick();
122		}
123		std::erase_if(g_destroyingTabGroups, [](auto& up) { return up->bar.destroy; });
124		std::erase_if(g_tabGroups, [](auto& wp) { return !wp; });
125	});
126
127	g_windowTitleListener = Event::bus()->m_events.window.title.listen([](PHLWINDOW window) {
128		if (!window) return;
129		auto* hy3 = hy3InstanceForWorkspace(window->m_workspace);
130		if (!hy3) return;
131		auto* node = hy3->getNodeFromWindow(window.get());
132		if (!node) return;
133		node->updateTabBarRecursive();
134	});
135
136	g_urgentListener = Event::bus()->m_events.window.urgent.listen([](PHLWINDOW window) {
137		if (!window) return;
138		window->m_hints |= Desktop::View::WINDOW_HINT_URGENT;
139		auto* hy3 = hy3InstanceForWorkspace(window->m_workspace);
140		if (!hy3) return;
141		auto* node = hy3->getNodeFromWindow(window.get());
142		if (!node) return;
143		node->updateTabBarRecursive();
144	});
145
146	registerDispatchers();
147
148	HyprlandAPI::reloadConfig();
149
150	return {"hy3", "i3 like layout for hyprland", "outfoxxed", "0.1"};
151}
152
153APICALL EXPORT void PLUGIN_EXIT() {
154	g_renderListener.reset();
155	g_tickListener.reset();
156	g_windowTitleListener.reset();
157	g_urgentListener.reset();
158
159	g_tabGroups.clear();
160	g_destroyingTabGroups.clear();
161}