diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..bfeb1d6e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +ko_fi: vaxry diff --git a/.github/workflows/version-update.sh b/.github/workflows/nix-meson-ver-update.yaml similarity index 96% rename from .github/workflows/version-update.sh rename to .github/workflows/nix-meson-ver-update.yaml index 1bf95af9..ddeac945 100644 --- a/.github/workflows/version-update.sh +++ b/.github/workflows/nix-meson-ver-update.yaml @@ -1,6 +1,6 @@ name: "Nix & Meson: update version" -on: [push, workflow_dispatch] +on: [workflow_dispatch] jobs: update: diff --git a/README.md b/README.md index faf8acca..3f182556 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Try it out and report bugs / suggestions! - Custom bezier curve based animations - `wlr_ext` workspaces protocol support - Dual Kawase blur +- Drop shadows - Fully dynamic workspaces - Closely follows `wlroots-git` - Bundled wlroots diff --git a/example/hyprland.conf b/example/hyprland.conf index 931baf49..30c8559e 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -17,8 +17,7 @@ input { } general { - max_fps=60 # deprecated, unused - sensitivity=0.25 + sensitivity=1.0 # for mouse cursor main_mod=SUPER gaps_in=5 @@ -27,7 +26,7 @@ general { col.active_border=0x66ee1111 col.inactive_border=0x66333333 - apply_sens_to_raw=0 # do not apply the sensitivity to raw input (e.g. used by games where you aim) + apply_sens_to_raw=0 # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse) damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer } @@ -97,4 +96,4 @@ bind=ALT,6,movetoworkspace,6 bind=ALT,7,movetoworkspace,7 bind=ALT,8,movetoworkspace,8 bind=ALT,9,movetoworkspace,9 -bind=ALT,0,movetoworkspace,10 \ No newline at end of file +bind=ALT,0,movetoworkspace,10 diff --git a/flake.nix b/flake.nix index 882569a8..aff05d7f 100644 --- a/flake.nix +++ b/flake.nix @@ -32,7 +32,7 @@ src = inputs.wlroots; }); hyprland = prev.callPackage ./nix/default.nix { - version = "0.5.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")); + version = "0.6.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")); wlroots = wlroots-hyprland; }; }; diff --git a/meson.build b/meson.build index f75f64fd..7c075e4e 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('Hyprland', 'cpp', 'c', - version : '0.5.0beta', + version : '0.6.0beta', default_options : ['warning_level=3', 'cpp_std=c++20', 'default_library=static']) wlroots = subproject('wlroots', default_options: ['examples=false']) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index be94c093..a3fd3b93 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -7,6 +7,16 @@ CCompositor::CCompositor() { Debug::log(LOG, "Instance Signature: %s", m_szInstanceSignature.c_str()); + Debug::log(LOG, "===== SYSTEM INFO: ====="); + + logSystemInfo(); + + Debug::log(LOG, "========================"); + + Debug::log(NONE, "\n\n"); // pad + + Debug::log(INFO, "If you are crashing, or encounter any bugs, please consult https://github.com/hyprwm/Hyprland/wiki/Crashing-and-bugs\n\n"); + setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true); const auto INSTANCEPATH = "/tmp/hypr/" + m_szInstanceSignature; @@ -1105,4 +1115,18 @@ bool CCompositor::workspaceIDOutOfBounds(const int& id) { } return std::clamp(id, lowestID, highestID) != id; +} + +void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode mode) { + if (!windowValidMapped(pWindow)) + return; + + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, mode, on); + + g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL); + // make all windows on the same workspace under the fullscreen window + for (auto& w : g_pCompositor->m_lWindows) { + if (w.m_iWorkspaceID == pWindow->m_iWorkspaceID) + w.m_bCreatedOverFullscreen = false; + } } \ No newline at end of file diff --git a/src/Compositor.hpp b/src/Compositor.hpp index e00ea0fd..16632006 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -132,6 +132,7 @@ public: int getNextAvailableMonitorID(); void moveWorkspaceToMonitor(CWorkspace*, SMonitor*); bool workspaceIDOutOfBounds(const int&); + void setWindowFullscreen(CWindow*, bool, eFullscreenMode); private: void initAllSignals(); diff --git a/src/Window.cpp b/src/Window.cpp index 8476360a..fbd06417 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -1,11 +1,14 @@ #include "Window.hpp" #include "Compositor.hpp" +#include "render/decorations/CHyprDropShadowDecoration.hpp" CWindow::CWindow() { m_vRealPosition.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*) this, AVARDAMAGE_ENTIRE); m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, &g_pConfigManager->getConfigValuePtr("animations:borders_curve")->strValue, (void*)this, AVARDAMAGE_BORDER); m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); + + m_dWindowDecorations.emplace_back(std::make_unique(this)); // put the shadow so it's the first deco (has to be rendered first) } CWindow::~CWindow() { @@ -16,8 +19,9 @@ CWindow::~CWindow() { } wlr_box CWindow::getFullWindowBoundingBox() { + static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - SWindowDecorationExtents maxExtents; + SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 1, *PBORDERSIZE + 1}, {*PBORDERSIZE + 1, *PBORDERSIZE + 1}}; for (auto& wd : m_dWindowDecorations) { diff --git a/src/Window.hpp b/src/Window.hpp index 06140303..9f92432a 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -15,6 +15,7 @@ struct SWindowSpecialRenderData { struct SWindowAdditionalConfigData { std::string animationStyle = ""; int rounding = -1; // -1 means no + bool forceNoBlur = false; }; class CWindow { @@ -110,4 +111,4 @@ public: wlr_box getFullWindowBoundingBox(); wlr_box getWindowIdealBoundingBoxIgnoreReserved(); -}; \ No newline at end of file +}; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index c3621847..fb3aae1f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -18,14 +18,14 @@ CConfigManager::CConfigManager() { } void CConfigManager::setDefaultVars() { - configValues["general:max_fps"].intValue = 240; - configValues["general:sensitivity"].floatValue = 0.25f; + configValues["general:max_fps"].intValue = 60; + configValues["general:sensitivity"].floatValue = 1.0f; configValues["general:apply_sens_to_raw"].intValue = 0; configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated - configValues["general:damage_tracking"].strValue = "none"; - configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE; + configValues["general:damage_tracking"].strValue = "full"; + configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_FULL; configValues["general:border_size"].intValue = 1; configValues["general:no_border_on_floating"].intValue = 0; @@ -33,6 +33,7 @@ void CConfigManager::setDefaultVars() { configValues["general:gaps_out"].intValue = 20; configValues["general:col.active_border"].intValue = 0xffffffff; configValues["general:col.inactive_border"].intValue = 0xff444444; + configValues["general:cursor_inactive_timeout"].intValue = 0; configValues["debug:int"].intValue = 0; configValues["debug:log_damage"].intValue = 0; @@ -48,6 +49,11 @@ void CConfigManager::setDefaultVars() { configValues["decoration:fullscreen_opacity"].floatValue = 1; configValues["decoration:multisample_edges"].intValue = 0; configValues["decoration:no_blur_on_oversized"].intValue = 1; + configValues["decoration:drop_shadow"].intValue = 1; + configValues["decoration:shadow_range"].intValue = 4; + configValues["decoration:shadow_render_power"].intValue = 3; + configValues["decoration:shadow_ignore_window"].intValue = 1; + configValues["decoration:col.shadow"].intValue = 0xee1a1a1a; configValues["dwindle:pseudotile"].intValue = 0; configValues["dwindle:col.group_border"].intValue = 0x66777700; @@ -76,7 +82,7 @@ void CConfigManager::setDefaultVars() { configValues["animations:workspaces_speed"].floatValue = 0.f; configValues["animations:workspaces"].intValue = 1; - configValues["input:kb_layout"].strValue = "en"; + configValues["input:kb_layout"].strValue = "us"; configValues["input:kb_variant"].strValue = STRVAL_EMPTY; configValues["input:kb_options"].strValue = STRVAL_EMPTY; configValues["input:kb_rules"].strValue = STRVAL_EMPTY; @@ -481,7 +487,9 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str && RULE.find("size") != 0 && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0 - && RULE.find("nofocus") != 0 + && RULE != "nofocus" + && RULE != "noblur" + && RULE != "fullscreen" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && RULE.find("workspace") != 0) { diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index fbf3981d..0395fd30 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -24,8 +24,7 @@ input { } general { - max_fps=60 # deprecated, unused - sensitivity=0.25 + sensitivity=1.0 # for mouse cursor main_mod=SUPER gaps_in=5 @@ -34,7 +33,7 @@ general { col.active_border=0x66ee1111 col.inactive_border=0x66333333 - apply_sens_to_raw=0 # do not apply the sensitivity to raw input (e.g. used by games where you aim) + apply_sens_to_raw=0 # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse) damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer } diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 559e7b79..a864f0d2 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -31,6 +31,9 @@ void Debug::log(LogLevel level, const char* fmt, ...) { case CRIT: ofs << "[CRITICAL] "; break; + case INFO: + ofs << "[INFO] "; + break; default: break; } diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 2a7ab425..814da421 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -8,7 +8,8 @@ enum LogLevel { LOG = 0, WARN, ERR, - CRIT + CRIT, + INFO }; namespace Debug { diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index 09f7d2ab..c2e6b39a 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -55,7 +55,16 @@ void Events::listener_mouseAxis(wl_listener* listener, void* data) { void Events::listener_requestMouse(wl_listener* listener, void* data) { const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data; + + if (!g_pHyprRenderer->shouldRenderCursor()) + return; + if (!EVENT->surface) { + g_pHyprRenderer->m_bWindowRequestedCursorHide = true; + } else { + g_pHyprRenderer->m_bWindowRequestedCursorHide = false; + } + if (EVENT->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, EVENT->surface, EVENT->hotspot_x, EVENT->hotspot_y); } diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index afbc0745..9da5f779 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -193,6 +193,8 @@ void Events::listener_monitorFrame(void* owner, void* data) { if (g_pConfigManager->m_bWantsMonitorReload) g_pConfigManager->performMonitorReload(); + + g_pHyprRenderer->ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts } if (PMONITOR->framesToSkip > 0) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 48571892..76dfadda 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -78,7 +78,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) { const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); - g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL); + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL, false); g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen); } @@ -86,6 +86,7 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW); std::string requestedWorkspace = ""; bool workspaceSilent = false; + bool requestsFullscreen = false; for (auto& r : WINDOWRULES) { if (r.szRule.find("monitor") == 0) { @@ -127,6 +128,10 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bIsPseudotiled = true; } else if (r.szRule.find("nofocus") == 0) { PWINDOW->m_bNoFocus = true; + } else if (r.szRule == "noblur") { + PWINDOW->m_sAdditionalConfigData.forceNoBlur = true; + } else if (r.szRule == "fullscreen") { + requestsFullscreen = true; } else if (r.szRule.find("rounding") == 0) { try { PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); @@ -254,6 +259,10 @@ void Events::listener_mapWindow(void* owner, void* data) { } } + if (requestsFullscreen) { + g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); + } + Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y); } @@ -384,9 +393,9 @@ void Events::listener_fullscreenWindow(void* owner, void* data) { const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested; if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen) - g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL); + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, true); } else { - g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL); + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, true); } Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 55b0ec83..ce9dd788 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -2,6 +2,7 @@ #include "../defines.hpp" #include #include "../Compositor.hpp" +#include void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) { ASSERT(pSignal); @@ -232,4 +233,35 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve const float DX = std::max((double)0, std::max(p1.x - vec.x, vec.x - p2.x)); const float DY = std::max((double)0, std::max(p1.y - vec.y, vec.y - p2.y)); return DX * DX + DY * DY; +} + +// Execute a shell command and get the output +std::string execAndGet(const char* cmd) { + std::array buffer; + std::string result; + const std::unique_ptr pipe(popen(cmd, "r"), pclose); + if (!pipe) { + Debug::log(ERR, "execAndGet: failed in pipe"); + return ""; + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { + result += buffer.data(); + } + return result; +} + +void logSystemInfo() { + struct utsname unameInfo; + + uname(&unameInfo); + + Debug::log(LOG, "System name: %s", unameInfo.sysname); + Debug::log(LOG, "Node name: %s", unameInfo.nodename); + Debug::log(LOG, "Release: %s", unameInfo.release); + Debug::log(LOG, "Version: %s", unameInfo.version); + + // log etc + Debug::log(LOG, "os-release:"); + + Debug::log(NONE, "%s", execAndGet("cat /etc/os-release").c_str()); } \ No newline at end of file diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index eed3670d..8470eb81 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -11,5 +11,7 @@ bool isNumber(const std::string&); bool isDirection(const std::string&); int getWorkspaceIDFromString(const std::string&, std::string&); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); +void logSystemInfo(); +std::string execAndGet(const char*); float getPlusMinusKeywordResult(std::string in, float relative); \ No newline at end of file diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp new file mode 100644 index 00000000..33162d30 --- /dev/null +++ b/src/helpers/Timer.cpp @@ -0,0 +1,17 @@ +#include "Timer.hpp" + +void CTimer::reset() { + m_tpLastReset = std::chrono::system_clock::now(); +} + +std::chrono::system_clock::duration CTimer::getDuration() { + return std::chrono::system_clock::now() - m_tpLastReset; +} + +int CTimer::getMillis() { + return std::chrono::duration_cast(getDuration()).count(); +} + +float CTimer::getSeconds() { + return std::chrono::duration_cast(getDuration()).count() / 1000.f; +} \ No newline at end of file diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp new file mode 100644 index 00000000..2e8d6adc --- /dev/null +++ b/src/helpers/Timer.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "../defines.hpp" + +class CTimer { +public: + void reset(); + float getSeconds(); + int getMillis(); + +private: + std::chrono::system_clock::time_point m_tpLastReset; + + std::chrono::system_clock::duration getDuration(); +}; \ No newline at end of file diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 2a2d3c93..d6282224 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -71,6 +71,8 @@ struct SKeyboard { bool active = false; + xkb_rule_names currentRules; + // For the list lookup bool operator==(const SKeyboard& rhs) { return keyboard == rhs.keyboard; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index fb966153..c72dbb99 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -482,6 +482,9 @@ void CHyprDwindleLayout::onBeginDragWindow() { void CHyprDwindleLayout::onEndDragWindow() { const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; + if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) + return; + if (DRAGGINGWINDOW->m_bDraggingTiled) { DRAGGINGWINDOW->m_bIsFloating = false; changeWindowFloatingMode(DRAGGINGWINDOW); @@ -494,8 +497,10 @@ void CHyprDwindleLayout::onMouseMove(const Vector2D& mousePos) { const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; // Window invalid or drag begin size 0,0 meaning we rejected it. - if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) + if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) { + g_pInputManager->currentlyDraggedWindow = nullptr; return; + } const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); @@ -671,21 +676,24 @@ void CHyprDwindleLayout::onWindowCreatedFloating(CWindow* pWindow) { g_pCompositor->moveWindowToTop(pWindow); } -void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode) { +void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) { if (!g_pCompositor->windowValidMapped(pWindow)) return; + if (on == pWindow->m_bIsFullscreen) + return; // ignore + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); - if (PWORKSPACE->m_bHasFullscreenWindow && !pWindow->m_bIsFullscreen) { + if (PWORKSPACE->m_bHasFullscreenWindow && on) { // if the window wants to be fullscreen but there already is one, // ignore the request. return; } // otherwise, accept it. - pWindow->m_bIsFullscreen = !pWindow->m_bIsFullscreen; + pWindow->m_bIsFullscreen = on; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; if (!pWindow->m_bIsFullscreen) { diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 55c123ae..3f32ff0b 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -53,7 +53,7 @@ public: virtual void onEndDragWindow(); virtual void onMouseMove(const Vector2D&); virtual void onWindowCreatedFloating(CWindow*); - virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode); + virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool); virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); virtual void switchWindows(CWindow*, CWindow*); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index a7268301..d7102761 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -84,7 +84,7 @@ public: The layout sets all the fullscreen flags. It can either accept or ignore. */ - virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode) = 0; + virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool) = 0; /* Called when a dispatcher requests a custom message diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 85fb3919..10694e1b 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -366,14 +366,7 @@ void CKeybindManager::fullscreenActive(std::string args) { if (!g_pCompositor->windowValidMapped(PWINDOW)) return; - g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, args == "1" ? eFullscreenMode::FULLSCREEN_MAXIMIZED : eFullscreenMode::FULLSCREEN_FULL); - - g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen && (args == "0" || args == "")); - // make all windows on the same workspace under the fullscreen window - for (auto& w : g_pCompositor->m_lWindows) { - if (w.m_iWorkspaceID == PWINDOW->m_iWorkspaceID) - w.m_bCreatedOverFullscreen = false; - } + g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL); } void CKeybindManager::moveActiveToWorkspace(std::string args) { @@ -954,8 +947,8 @@ void CKeybindManager::moveActive(std::string args) { const int X = std::stoi(newX); const int Y = std::stoi(newY); - if (X < 10 || Y < 10) { - Debug::log(ERR, "moveActive: exact args cannot be < 10"); + if (X < 0 || Y < 0) { + Debug::log(ERR, "moveActive: exact args cannot be < 0"); return; } @@ -999,6 +992,9 @@ void CKeybindManager::focusWindowByClass(std::string clazz) { std::regex classCheck(clazz); for (auto& w : g_pCompositor->m_lWindows) { + if (!w.m_bIsMapped || w.m_bHidden) + continue; + const auto windowClass = g_pXWaylandManager->getAppIDClass(&w); if (!std::regex_search(windowClass, classCheck)) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 131be576..4019a188 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -14,12 +14,16 @@ void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) { wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * sensitivity, DELTA.y * sensitivity); mouseMoveUnified(e->time_msec); + + m_tmrLastCursorMovement.reset(); } void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) { wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, &e->pointer->base, e->x, e->y); mouseMoveUnified(e->time_msec); + + m_tmrLastCursorMovement.reset(); } void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { @@ -205,6 +209,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { void CInputManager::onMouseButton(wlr_pointer_button_event* e) { wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat); + m_tmrLastCursorMovement.reset(); + const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat); if (!PKEYBOARD) { // ??? @@ -289,7 +295,7 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) { m_pActiveKeyboard->active = false; m_pActiveKeyboard = PNEWKEYBOARD; - setKeyboardLayout(); + applyConfigToKeyboard(PNEWKEYBOARD); wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, keyboard->keyboard); @@ -311,6 +317,11 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { const auto VARIANT = g_pConfigManager->getString("input:kb_variant"); const auto OPTIONS = g_pConfigManager->getString("input:kb_options"); + if (RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options) { + Debug::log(LOG, "Not applying config to keyboard, it did not change."); + return; + } + xkb_rule_names rules = { .rules = RULES.c_str(), .model = MODEL.c_str(), @@ -318,6 +329,8 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { .variant = VARIANT.c_str(), .options = OPTIONS.c_str()}; + pKeyboard->currentRules = rules; + const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!CONTEXT) { @@ -325,12 +338,17 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { return; } - const auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + Debug::log(LOG, "Attempting to create a keymap for layout %s with variant %s (rules: %s, model: %s, options: %s)", rules.layout, rules.variant, rules.rules, rules.model, rules.options); + + auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!KEYMAP) { Debug::log(ERR, "Keyboard layout %s with variant %s (rules: %s, model: %s, options: %s) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options); - xkb_context_unref(CONTEXT); - return; + memset(&rules, 0, sizeof(rules)); + + pKeyboard->currentRules = rules; + + KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); } wlr_keyboard_set_keymap(pKeyboard->keyboard->keyboard, KEYMAP); @@ -401,6 +419,8 @@ void CInputManager::newMouse(wlr_input_device* mouse) { g_pCompositor->m_sSeat.mouse = PMOUSE; + m_tmrLastCursorMovement.reset(); + Debug::log(LOG, "New mouse created, pointer WLR: %x", mouse); } diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index ef3a4eb4..06e6cb07 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -4,6 +4,7 @@ #include #include "../../helpers/WLClasses.hpp" #include "../../Window.hpp" +#include "../../helpers/Timer.hpp" class CInputManager { public: @@ -53,6 +54,8 @@ public: SKeyboard* m_pActiveKeyboard = nullptr; + CTimer m_tmrLastCursorMovement; + private: uint32_t m_uiCapabilities = 0; diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index c33f021c..4285d06b 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -226,4 +226,4 @@ void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool moti if (PTOOL->pSurface) wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); } -} \ No newline at end of file +} diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 85dd29be..e44e108b 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -75,6 +75,12 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos"); m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); + prog = createProgram(QUADVERTSRC, FRAGSHADOW); + m_shSHADOW.program = prog; + m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); + m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); + m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); + Debug::log(LOG, "Shaders initialized successfully."); // End shaders @@ -566,7 +572,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; static auto* const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue; - if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1))) { + if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) { renderTexture(tex, pBox, a, round, false, border, true); return; } @@ -858,6 +864,68 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) { pixman_region32_fini(&fakeDamage); } +void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, float a) { + RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!"); + RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!"); + + static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue; + static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue; + static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; + + const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); + + const auto col = CColor(*PSHADOWCOL); + + float matrix[9]; + wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here + + float glMatrix[9]; + wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix); + + wlr_matrix_transpose(glMatrix, glMatrix); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glUseProgram(m_shSHADOW.program); + + glUniformMatrix3fv(m_shSHADOW.proj, 1, GL_FALSE, glMatrix); + glUniform4f(glGetUniformLocation(m_shSHADOW.program, "color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a); + + const auto TOPLEFT = Vector2D(range + round, range + round); + const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); + const auto FULLSIZE = Vector2D(box->width, box->height); + + // Rounded corners + glUniform2f(glGetUniformLocation(m_shSHADOW.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(glGetUniformLocation(m_shSHADOW.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(glGetUniformLocation(m_shSHADOW.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(glGetUniformLocation(m_shSHADOW.program, "radius"), range + round); + glUniform1f(glGetUniformLocation(m_shSHADOW.program, "range"), range); + glUniform1f(glGetUniformLocation(m_shSHADOW.program, "shadowPower"), SHADOWPOWER); + glUniform1i(glGetUniformLocation(m_shSHADOW.program, "ignoreWindow"), *PSHADOWIGNOREWINDOW); + + glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + + glEnableVertexAttribArray(m_shSHADOW.posAttrib); + glEnableVertexAttribArray(m_shSHADOW.texAttrib); + + if (pixman_region32_not_empty(m_RenderData.pDamage)) { + PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { + const auto RECT = RECTSARR[i]; + scissor(&RECT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + glDisableVertexAttribArray(m_shSHADOW.posAttrib); + glDisableVertexAttribArray(m_shSHADOW.texAttrib); + + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +} + void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 0648e73a..9d6e098d 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -61,6 +61,7 @@ public: void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0); void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool border = false, bool allowPrimary = false); void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool border = false); + void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0); void makeWindowSnapshot(CWindow*); void makeLayerSnapshot(SLayerSurface*); @@ -106,6 +107,7 @@ private: CShader m_shEXT; CShader m_shBLUR1; CShader m_shBLUR2; + CShader m_shSHADOW; // GLuint createProgram(const std::string&, const std::string&); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8118af48..f7328997 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -168,7 +168,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* // render window decorations first for (auto& wd : pWindow->m_dWindowDecorations) - wd->draw(pMonitor); + wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f); if (!pWindow->m_bIsX11) { @@ -194,12 +194,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); - if (pWindow->m_bIsX11) { - if (pWindow->m_uSurface.xwayland->surface) { - wlr_surface_for_each_surface(pWindow->m_uSurface.xwayland->surface, renderSurface, &renderdata); - } - } - else { + if (!pWindow->m_bIsX11) { renderdata.dontRound = false; // restore dontround renderdata.pMonitor = pMonitor; wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); @@ -574,7 +569,7 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) { // damage by size & pos // TODO TEMP: revise when added shadows/etc - wlr_box damageBox = {pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y}; + wlr_box damageBox = pWindow->getFullWindowBoundingBox(); for (auto& m : g_pCompositor->m_lMonitors) { wlr_box fixedDamageBox = damageBox; fixedDamageBox.x -= m.vecPosition.x; @@ -589,8 +584,7 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) { Debug::log(LOG, "Damage: Window floated (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); } else { // damage by real size & pos + border size * 2 (JIC) - static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - wlr_box damageBox = { pWindow->m_vRealPosition.vec().x - *PBORDERSIZE - 1, pWindow->m_vRealPosition.vec().y - *PBORDERSIZE - 1, pWindow->m_vRealSize.vec().x + 2 * *PBORDERSIZE + 2, pWindow->m_vRealSize.vec().y + 2 * *PBORDERSIZE + 2}; + wlr_box damageBox = pWindow->getFullWindowBoundingBox(); for (auto& m : g_pCompositor->m_lMonitors) { wlr_box fixedDamageBox = damageBox; fixedDamageBox.x -= m.vecPosition.x; @@ -759,3 +753,38 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR // frame skip pMonitor->framesToSkip = 1; } + +void CHyprRenderer::ensureCursorRenderingMode() { + static auto *const PCURSORTIMEOUT = &g_pConfigManager->getConfigValuePtr("general:cursor_inactive_timeout")->intValue; + + const auto PASSEDCURSORSECONDS = g_pInputManager->m_tmrLastCursorMovement.getSeconds(); + + if (*PCURSORTIMEOUT > 0) { + if (*PCURSORTIMEOUT < PASSEDCURSORSECONDS && m_bHasARenderedCursor) { + m_bHasARenderedCursor = false; + + wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, nullptr, 0, 0); // hide + + Debug::log(LOG, "Hiding the cursor (timeout)"); + + for (auto& m : g_pCompositor->m_lMonitors) + g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area? + } else if (*PCURSORTIMEOUT > PASSEDCURSORSECONDS && !m_bHasARenderedCursor) { + m_bHasARenderedCursor = true; + + if (!m_bWindowRequestedCursorHide) + wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor); + + Debug::log(LOG, "Showing the cursor (timeout)"); + + for (auto& m : g_pCompositor->m_lMonitors) + g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area? + } + } else { + m_bHasARenderedCursor = true; + } +} + +bool CHyprRenderer::shouldRenderCursor() { + return m_bHasARenderedCursor; +} \ No newline at end of file diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 24caa09d..43a241ed 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -31,6 +31,10 @@ public: void applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false); bool shouldRenderWindow(CWindow*, SMonitor*); bool shouldRenderWindow(CWindow*); + void ensureCursorRenderingMode(); + bool shouldRenderCursor(); + + bool m_bWindowRequestedCursorHide = false; DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); @@ -41,6 +45,8 @@ private: void renderLayer(SLayerSurface*, SMonitor*, timespec*); void renderDragIcon(SMonitor*, timespec*); + bool m_bHasARenderedCursor = true; + friend class CHyprOpenGLImpl; }; diff --git a/src/render/Shaders.hpp b/src/render/Shaders.hpp index d01e7775..ac7f9424 100644 --- a/src/render/Shaders.hpp +++ b/src/render/Shaders.hpp @@ -1,341 +1,4 @@ #pragma once -#include - -inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { - return R"#( - if (pixCoord[0] < topLeft[0]) { - // we're close left - if (pixCoord[1] < topLeft[1]) { - // top - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(topLeft, pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(topLeft, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(topLeft, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(topLeft, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(topLeft, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } else if (pixCoord[1] > bottomRight[1]) { - // bottom - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(vec2(topLeft[0], bottomRight[1]), pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } - } - else if (pixCoord[0] > bottomRight[0]) { - // we're close right - if (pixCoord[1] < topLeft[1]) { - // top - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(vec2(bottomRight[0], topLeft[1]), pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } else if (pixCoord[1] > bottomRight[1]) { - // bottom - - if (ignoreCorners == 1) { - discard; - return; - } - - float topLeftDistance = distance(bottomRight, pixCoord); - - if (topLeftDistance > radius - 1.0) { - if (primitiveMultisample == 0 && topLeftDistance > radius) { - discard; - return; - } else if (primitiveMultisample == 1) { - float distances = 0.0; - if (distance(bottomRight, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(bottomRight, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } - if (distance(bottomRight, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } - if (distance(bottomRight, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } - - if (distances == 0.0) { - discard; - return; - } - - distances = distances / 4.0; - - gl_FragColor = )#" + colorVarName + R"#( * distances; - return; - } - } - } - } - )#"; -}; - -inline const std::string QUADVERTSRC = R"#( -uniform mat3 proj; -uniform vec4 color; -attribute vec2 pos; -attribute vec2 texcoord; -varying vec4 v_color; -varying vec2 v_texcoord; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_color = color; - v_texcoord = texcoord; -})#"; - -inline const std::string QUADFRAGSRC = R"#( -precision mediump float; -varying vec4 v_color; -varying vec2 v_texcoord; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - if (radius == 0.0) { - gl_FragColor = v_color; - return; - } - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("v_color") + R"#( - - gl_FragColor = v_color; -})#"; - -inline const std::string TEXVERTSRC = R"#( -uniform mat3 proj; -attribute vec2 pos; -attribute vec2 texcoord; -varying vec2 v_texcoord; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_texcoord = texcoord; -})#"; - -inline const std::string TEXFRAGSRCRGBA = R"#( -precision mediump float; -varying vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int discardOpaque; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - - vec4 pixColor = texture2D(tex, v_texcoord); - - if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { - discard; - return; - } - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("pixColor") + - R"#( - - gl_FragColor = pixColor * alpha; -})#"; - -inline const std::string TEXFRAGSRCRGBX = R"#( -precision mediump float; -varying vec2 v_texcoord; -uniform sampler2D tex; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int discardOpaque; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - - if (discardOpaque == 1 && alpha == 1.0) { - discard; - return; - } - - vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0); - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( - - gl_FragColor = pixColor * alpha; -})#"; - -inline const std::string FRAGBLUR1 = R"#( -#version 100 -precision mediump float; -varying mediump vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; - -uniform float radius; -uniform vec2 halfpixel; - -void main() { - vec2 uv = v_texcoord * 2.0; - - vec4 sum = texture2D(tex, uv) * 4.0; - sum += texture2D(tex, uv - halfpixel.xy * radius); - sum += texture2D(tex, uv + halfpixel.xy * radius); - sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius); - sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius); - gl_FragColor = sum / 8.0; -} -)#"; - -inline const std::string FRAGBLUR2 = R"#( -#version 100 -precision mediump float; -varying mediump vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; - -uniform float radius; -uniform vec2 halfpixel; - -void main() { - vec2 uv = v_texcoord / 2.0; - - vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius); - - sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0; - sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius); - sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0; - sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius); - sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0; - sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius); - sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0; - - gl_FragColor = sum / 12.0; -} -)#"; - -inline const std::string TEXFRAGSRCEXT = R"#( -#extension GL_OES_EGL_image_external : require - -precision mediump float; -varying vec2 v_texcoord; -uniform samplerExternalOES texture0; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 bottomRight; -uniform vec2 fullSize; -uniform float radius; - -uniform int discardOpaque; - -uniform int primitiveMultisample; -uniform int ignoreCorners; - -void main() { - - vec4 pixColor = texture2D(texture0, v_texcoord); - - if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { - discard; - return; - } - - vec2 pixCoord = fullSize * v_texcoord; - - )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( - - gl_FragColor = pixColor * alpha; -})#"; +#include "shaders/Textures.hpp" +#include "shaders/Shadow.hpp" \ No newline at end of file diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp new file mode 100644 index 00000000..6933e687 --- /dev/null +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -0,0 +1,66 @@ +#include "CHyprDropShadowDecoration.hpp" + +#include "../../Compositor.hpp" + +CHyprDropShadowDecoration::CHyprDropShadowDecoration(CWindow* pWindow) { + m_pWindow = pWindow; +} + +CHyprDropShadowDecoration::~CHyprDropShadowDecoration() { + updateWindow(m_pWindow); +} + +SWindowDecorationExtents CHyprDropShadowDecoration::getWindowDecorationExtents() { + static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; + + if (*PSHADOWS != 1) + return {{}, {}}; + + return m_seExtents; +} + +eDecorationType CHyprDropShadowDecoration::getDecorationType() { + return DECORATION_SHADOW; +} + +void CHyprDropShadowDecoration::damageEntire() { + static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; + + if (*PSHADOWS != 1) + return; // disabled + + wlr_box dm = {m_vLastWindowPos.x - m_seExtents.topLeft.x, m_vLastWindowPos.y - m_seExtents.topLeft.y, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; + g_pHyprRenderer->damageBox(&dm); +} + +void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) { + damageEntire(); +} + +void CHyprDropShadowDecoration::draw(SMonitor* pMonitor, float a) { + + if (!g_pCompositor->windowValidMapped(m_pWindow)) + return; + + static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; + static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue; + static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; + + if (*PSHADOWS != 1) + return; // disabled + + // update the extents if needed + if (*PSHADOWSIZE != m_seExtents.topLeft.x) + m_seExtents = {{*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}, {*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}}; + + m_vLastWindowPos = m_pWindow->m_vRealPosition.vec(); + m_vLastWindowSize = m_pWindow->m_vRealSize.vec(); + + // draw the shadow + wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4}; + + fullBox.x -= pMonitor->vecPosition.x; + fullBox.y -= pMonitor->vecPosition.y; + + g_pHyprOpenGL->renderRoundedShadow(&fullBox, *PROUNDING, *PSHADOWSIZE, a); +} diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp new file mode 100644 index 00000000..f734c111 --- /dev/null +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "IHyprWindowDecoration.hpp" + +class CHyprDropShadowDecoration : public IHyprWindowDecoration { +public: + CHyprDropShadowDecoration(CWindow*); + virtual ~CHyprDropShadowDecoration(); + + virtual SWindowDecorationExtents getWindowDecorationExtents(); + + virtual void draw(SMonitor*, float a); + + virtual eDecorationType getDecorationType(); + + virtual void updateWindow(CWindow*); + + virtual void damageEntire(); + +private: + SWindowDecorationExtents m_seExtents; + + CWindow* m_pWindow = nullptr; + + Vector2D m_vLastWindowPos; + Vector2D m_vLastWindowSize; +}; \ No newline at end of file diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 25d74065..2bb486ee 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -68,7 +68,7 @@ void CHyprGroupBarDecoration::damageEntire() { g_pHyprRenderer->damageBox(&dm); } -void CHyprGroupBarDecoration::draw(SMonitor* pMonitor) { +void CHyprGroupBarDecoration::draw(SMonitor* pMonitor, float a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); @@ -88,6 +88,7 @@ void CHyprGroupBarDecoration::draw(SMonitor* pMonitor) { break; CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")) : CColor(g_pConfigManager->getInt("dwindle:col.group_border")); + color.a *= a; g_pHyprOpenGL->renderRect(&rect, color); xoff += PAD + BARW; diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 74a597a6..76baab65 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -10,7 +10,7 @@ public: virtual SWindowDecorationExtents getWindowDecorationExtents(); - virtual void draw(SMonitor*); + virtual void draw(SMonitor*, float a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 0815273d..21219b36 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -4,7 +4,8 @@ enum eDecorationType { DECORATION_NONE = -1, - DECORATION_GROUPBAR + DECORATION_GROUPBAR, + DECORATION_SHADOW }; struct SWindowDecorationExtents { @@ -21,7 +22,7 @@ public: virtual SWindowDecorationExtents getWindowDecorationExtents() = 0; - virtual void draw(SMonitor*) = 0; + virtual void draw(SMonitor*, float a) = 0; virtual eDecorationType getDecorationType() = 0; diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/Shadow.hpp new file mode 100644 index 00000000..f54124fa --- /dev/null +++ b/src/render/shaders/Shadow.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include + +inline const std::string FRAGSHADOW = R"#( +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; +uniform float range; +uniform float shadowPower; +uniform int ignoreWindow; + +float pixAlphaRoundedDistance(float distanceToCorner) { + if (distanceToCorner > radius) { + return 0.0; + } + + if (distanceToCorner > radius - range) { + return pow((range - (distanceToCorner - radius + range)) / range, shadowPower); // i think? + } + + return 1.0; +} + +void main() { + + vec4 pixColor = v_color; + float originalAlpha = pixColor[3]; + + bool done = false; + + vec2 pixCoord = fullSize * v_texcoord; + + // ok, now we check the distance to a border. + + if (pixCoord[0] < topLeft[0]) { + if (pixCoord[1] < topLeft[1]) { + // top left + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, topLeft)); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom left + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(topLeft[0], bottomRight[1]))); + done = true; + } + } else if (pixCoord[0] > bottomRight[0]) { + if (pixCoord[1] < topLeft[1]) { + // top right + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(bottomRight[0], topLeft[1]))); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom right + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, bottomRight)); + done = true; + } + } + + if (!done) { + // distance to all straight bb borders + float distanceT = pixCoord[1]; + float distanceB = fullSize[1] - pixCoord[1]; + float distanceL = pixCoord[0]; + float distanceR = fullSize[0] - pixCoord[0]; + + // get the smallest + float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR)); + + if (smallest < range) { + pixColor[3] = pixColor[3] * pow((smallest / range), shadowPower); + } + } + + if (pixColor[3] == 0.0 || (ignoreWindow == 1 && pixColor[3] == originalAlpha)) { + discard; return; + } + + gl_FragColor = pixColor; +})#"; \ No newline at end of file diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp new file mode 100644 index 00000000..d01e7775 --- /dev/null +++ b/src/render/shaders/Textures.hpp @@ -0,0 +1,341 @@ +#pragma once + +#include + +inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { + return R"#( + if (pixCoord[0] < topLeft[0]) { + // we're close left + if (pixCoord[1] < topLeft[1]) { + // top + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(topLeft, pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(topLeft, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(topLeft, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(topLeft, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(topLeft, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } else if (pixCoord[1] > bottomRight[1]) { + // bottom + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(vec2(topLeft[0], bottomRight[1]), pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } + } + else if (pixCoord[0] > bottomRight[0]) { + // we're close right + if (pixCoord[1] < topLeft[1]) { + // top + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(vec2(bottomRight[0], topLeft[1]), pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } else if (pixCoord[1] > bottomRight[1]) { + // bottom + + if (ignoreCorners == 1) { + discard; + return; + } + + float topLeftDistance = distance(bottomRight, pixCoord); + + if (topLeftDistance > radius - 1.0) { + if (primitiveMultisample == 0 && topLeftDistance > radius) { + discard; + return; + } else if (primitiveMultisample == 1) { + float distances = 0.0; + if (distance(bottomRight, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(bottomRight, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; } + if (distance(bottomRight, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; } + if (distance(bottomRight, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; } + + if (distances == 0.0) { + discard; + return; + } + + distances = distances / 4.0; + + gl_FragColor = )#" + colorVarName + R"#( * distances; + return; + } + } + } + } + )#"; +}; + +inline const std::string QUADVERTSRC = R"#( +uniform mat3 proj; +uniform vec4 color; +attribute vec2 pos; +attribute vec2 texcoord; +varying vec4 v_color; +varying vec2 v_texcoord; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_color = color; + v_texcoord = texcoord; +})#"; + +inline const std::string QUADFRAGSRC = R"#( +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + if (radius == 0.0) { + gl_FragColor = v_color; + return; + } + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("v_color") + R"#( + + gl_FragColor = v_color; +})#"; + +inline const std::string TEXVERTSRC = R"#( +uniform mat3 proj; +attribute vec2 pos; +attribute vec2 texcoord; +varying vec2 v_texcoord; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_texcoord = texcoord; +})#"; + +inline const std::string TEXFRAGSRCRGBA = R"#( +precision mediump float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; +uniform float alpha; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int discardOpaque; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + + vec4 pixColor = texture2D(tex, v_texcoord); + + if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { + discard; + return; + } + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("pixColor") + + R"#( + + gl_FragColor = pixColor * alpha; +})#"; + +inline const std::string TEXFRAGSRCRGBX = R"#( +precision mediump float; +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform float alpha; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int discardOpaque; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + + if (discardOpaque == 1 && alpha == 1.0) { + discard; + return; + } + + vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0); + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( + + gl_FragColor = pixColor * alpha; +})#"; + +inline const std::string FRAGBLUR1 = R"#( +#version 100 +precision mediump float; +varying mediump vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float radius; +uniform vec2 halfpixel; + +void main() { + vec2 uv = v_texcoord * 2.0; + + vec4 sum = texture2D(tex, uv) * 4.0; + sum += texture2D(tex, uv - halfpixel.xy * radius); + sum += texture2D(tex, uv + halfpixel.xy * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius); + sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius); + gl_FragColor = sum / 8.0; +} +)#"; + +inline const std::string FRAGBLUR2 = R"#( +#version 100 +precision mediump float; +varying mediump vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float radius; +uniform vec2 halfpixel; + +void main() { + vec2 uv = v_texcoord / 2.0; + + vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius); + + sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius); + sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0; + + gl_FragColor = sum / 12.0; +} +)#"; + +inline const std::string TEXFRAGSRCEXT = R"#( +#extension GL_OES_EGL_image_external : require + +precision mediump float; +varying vec2 v_texcoord; +uniform samplerExternalOES texture0; +uniform float alpha; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; + +uniform int discardOpaque; + +uniform int primitiveMultisample; +uniform int ignoreCorners; + +void main() { + + vec4 pixColor = texture2D(texture0, v_texcoord); + + if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { + discard; + return; + } + + vec2 pixCoord = fullSize * v_texcoord; + + )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( + + gl_FragColor = pixColor * alpha; +})#";