From 8b81f41e52b55835aaaa7e4962af23a00188cbdc Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Mon, 27 Feb 2023 12:32:38 +0000 Subject: Plugin System (#1590) --------- Co-authored-by: Mihai Fufezan --- src/debug/CrashReporter.cpp | 13 +++ src/debug/HyprCtl.cpp | 50 +++++++++++ src/debug/HyprCtl.hpp | 6 +- src/debug/HyprNotificationOverlay.cpp | 155 ++++++++++++++++++++++++++++++++++ src/debug/HyprNotificationOverlay.hpp | 40 +++++++++ 5 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 src/debug/HyprNotificationOverlay.cpp create mode 100644 src/debug/HyprNotificationOverlay.hpp (limited to 'src/debug') diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index 5738f180..084e44ad 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -4,10 +4,13 @@ #include #include +#include "../plugins/PluginSystem.hpp" + #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) #include #endif + std::string getRandomMessage() { const std::vector MESSAGES = {"Sorry, didn't mean to...", @@ -43,6 +46,16 @@ void CrashReporter::createAndSaveCrash() { finalCrashReport += "Hyprland received signal 11 (SIGSEGV): Segmentation Fault\n\n"; + if (!g_pPluginSystem->getAllPlugins().empty()) { + finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n"; + + for (auto& p : g_pPluginSystem->getAllPlugins()) { + finalCrashReport += getFormat("\t%s (%s) %s\n", p->name.c_str(), p->author.c_str(), p->version.c_str()); + } + + finalCrashReport += "\n\n"; + } + finalCrashReport += "System info:\n"; struct utsname unameInfo; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 91af3938..f6ed285b 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1087,6 +1087,50 @@ std::string dispatchOutput(std::string request) { return "ok"; } +std::string dispatchPlugin(std::string request) { + CVarList vars(request, 0, ' '); + + if (vars.size() < 2) + return "not enough args"; + + const auto OPERATION = vars[1]; + const auto PATH = vars[2]; + + if (OPERATION == "load") { + if (vars.size() < 3) + return "not enough args"; + + const auto PLUGIN = g_pPluginSystem->loadPlugin(PATH); + + if (!PLUGIN) + return "error in loading plugin"; + } else if (OPERATION == "unload") { + if (vars.size() < 3) + return "not enough args"; + + const auto PLUGIN = g_pPluginSystem->getPluginByPath(PATH); + + if (!PLUGIN) + return "plugin not loaded"; + + g_pPluginSystem->unloadPlugin(PLUGIN); + } else if (OPERATION == "list") { + const auto PLUGINS = g_pPluginSystem->getAllPlugins(); + + std::string list = ""; + for (auto& p : PLUGINS) { + list += getFormat("\nPlugin %s by %s:\n\tHandle: %lx\n\tVersion: %s\n\tDescription: %s\n", p->name.c_str(), p->author.c_str(), p->m_pHandle, p->version.c_str(), + p->description.c_str()); + } + + return list; + } else { + return "unknown opt"; + } + + return "ok"; +} + std::string getReply(std::string request) { auto format = HyprCtl::FORMAT_NORMAL; @@ -1134,6 +1178,8 @@ std::string getReply(std::string request) { return bindsRequest(format); else if (request == "animations") return animationsRequest(format); + else if (request.find("plugin") == 0) + return dispatchPlugin(request); else if (request.find("setprop") == 0) return dispatchSetProp(request); else if (request.find("seterror") == 0) @@ -1156,6 +1202,10 @@ std::string getReply(std::string request) { return "unknown request"; } +std::string HyprCtl::makeDynamicCall(const std::string& input) { + return getReply(input); +} + int hyprCtlFDTick(int fd, uint32_t mask, void* data) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) return 0; diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index 26859692..00cf7c5b 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -5,7 +5,8 @@ #include "../helpers/MiscFunctions.hpp" namespace HyprCtl { - void startHyprCtlSocket(); + void startHyprCtlSocket(); + std::string makeDynamicCall(const std::string& input); // very simple thread-safe request method inline bool requestMade = false; @@ -18,8 +19,7 @@ namespace HyprCtl { inline int iSocketFD = -1; - enum eHyprCtlOutputFormat - { + enum eHyprCtlOutputFormat { FORMAT_NORMAL = 0, FORMAT_JSON }; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp new file mode 100644 index 00000000..94cb6a6c --- /dev/null +++ b/src/debug/HyprNotificationOverlay.cpp @@ -0,0 +1,155 @@ +#include "HyprNotificationOverlay.hpp" +#include "../Compositor.hpp" + +CHyprNotificationOverlay::CHyprNotificationOverlay() { + g_pHookSystem->hookDynamic("focusedMon", [&](void* self, std::any param) { + if (m_dNotifications.size() == 0) + return; + + g_pHyprRenderer->damageBox(&m_bLastDamage); + }); +} + +void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs) { + const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique()).get(); + + PNOTIF->text = text; + PNOTIF->color = color; + PNOTIF->started.reset(); + PNOTIF->timeMs = timeMs; +} + +wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { + static constexpr auto ANIM_DURATION_MS = 600.0; + static constexpr auto ANIM_LAG_MS = 100.0; + static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0; + + float offsetY = 10; + float maxWidth = 0; + + const auto SCALE = pMonitor->scale; + const auto FONTSIZE = std::clamp((int)(10.f * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); + + const auto MONSIZE = pMonitor->vecPixelSize; + + cairo_select_font_face(m_pCairo, "Noto Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(m_pCairo, FONTSIZE); + + cairo_text_extents_t cairoExtents; + + const auto PBEZIER = g_pAnimationManager->getBezier("default"); + + for (auto& notif : m_dNotifications) { + // first rect (bg, col) + const float FIRSTRECTANIMP = + (notif->started.getMillis() > (ANIM_DURATION_MS - ANIM_LAG_MS) ? + (notif->started.getMillis() > notif->timeMs - (ANIM_DURATION_MS - ANIM_LAG_MS) ? notif->timeMs - notif->started.getMillis() : (ANIM_DURATION_MS - ANIM_LAG_MS)) : + notif->started.getMillis()) / + (ANIM_DURATION_MS - ANIM_LAG_MS); + + const float FIRSTRECTPERC = FIRSTRECTANIMP >= 0.99f ? 1.f : PBEZIER->getYForPoint(FIRSTRECTANIMP); + + // second rect (fg, black) + const float SECONDRECTANIMP = (notif->started.getMillis() > ANIM_DURATION_MS ? + (notif->started.getMillis() > notif->timeMs - ANIM_DURATION_MS ? notif->timeMs - notif->started.getMillis() : ANIM_DURATION_MS) : + notif->started.getMillis()) / + ANIM_DURATION_MS; + + const float SECONDRECTPERC = SECONDRECTANIMP >= 0.99f ? 1.f : PBEZIER->getYForPoint(SECONDRECTANIMP); + + // third rect (horiz, col) + const float THIRDRECTPERC = notif->started.getMillis() / notif->timeMs; + + // get text size + cairo_text_extents(m_pCairo, notif->text.c_str(), &cairoExtents); + + cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); + + const auto NOTIFSIZE = Vector2D{cairoExtents.width + 20, cairoExtents.height + 10}; + + // draw rects + cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y); + cairo_fill(m_pCairo); + + cairo_set_source_rgb(m_pCairo, 0.f, 0.f, 0.f); + + cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y); + cairo_fill(m_pCairo); + + cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); + + cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2); + cairo_fill(m_pCairo); + + // draw text + cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f); + cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE, offsetY + FONTSIZE + (FONTSIZE / 10.0)); + cairo_show_text(m_pCairo, notif->text.c_str()); + + // adjust offset and move on + offsetY += NOTIFSIZE.y + 10; + + if (maxWidth < NOTIFSIZE.x) + maxWidth = NOTIFSIZE.x; + } + + // cleanup notifs + std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); + + return wlr_box{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10}; +} + +void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { + + if (m_pLastMonitor != pMonitor || !m_pCairo || !m_pCairoSurface) { + + if (m_pCairo && m_pCairoSurface) { + cairo_destroy(m_pCairo); + cairo_surface_destroy(m_pCairoSurface); + } + + m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + m_pCairo = cairo_create(m_pCairoSurface); + m_pLastMonitor = pMonitor; + } + + // Draw the notifications + if (m_dNotifications.size() == 0) + return; + + // Render to the monitor + + // clear the pixmap + cairo_save(m_pCairo); + cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR); + cairo_paint(m_pCairo); + cairo_restore(m_pCairo); + + cairo_surface_flush(m_pCairoSurface); + + wlr_box damage = drawNotifications(pMonitor); + + g_pHyprRenderer->damageBox(&damage); + g_pHyprRenderer->damageBox(&m_bLastDamage); + + g_pCompositor->scheduleFrameForMonitor(pMonitor); + + m_bLastDamage = damage; + + // copy the data to an OpenGL texture we have + const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); + m_tTexture.allocate(); + glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + +#ifndef GLES2 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); +#endif + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + + wlr_box pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}; + g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f); +} \ No newline at end of file diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp new file mode 100644 index 00000000..12ad8e38 --- /dev/null +++ b/src/debug/HyprNotificationOverlay.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "../defines.hpp" +#include "../helpers/Timer.hpp" +#include "../helpers/Monitor.hpp" +#include "../render/Texture.hpp" + +#include + +#include + +struct SNotification { + std::string text = ""; + CColor color; + CTimer started; + float timeMs = 0; +}; + +class CHyprNotificationOverlay { + public: + CHyprNotificationOverlay(); + + void draw(CMonitor* pMonitor); + void addNotification(const std::string& text, const CColor& color, const float timeMs); + + private: + wlr_box drawNotifications(CMonitor* pMonitor); + wlr_box m_bLastDamage; + + std::deque> m_dNotifications; + + cairo_surface_t* m_pCairoSurface = nullptr; + cairo_t* m_pCairo = nullptr; + + CMonitor* m_pLastMonitor = nullptr; + + CTexture m_tTexture; +}; + +inline std::unique_ptr g_pHyprNotificationOverlay; \ No newline at end of file -- cgit v1.2.3