summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxDarksome <dev@darkso.me>2022-06-26 19:20:20 +0300
committerGitHub <noreply@github.com>2022-06-26 19:20:20 +0300
commit504f76112aec3625f2d67f9289a48a01bc90cb50 (patch)
treef3a4c5176a2d8f1954a7632b542f829e994c8529 /src
parentbe460ea9547691eb136bf8b600b67b778af47e3f (diff)
parentf1a5cb4979f312f56967888c2b1b6d2aa535bb9e (diff)
Merge branch 'hyprwm:main' into main
Diffstat (limited to 'src')
-rw-r--r--src/Compositor.cpp24
-rw-r--r--src/Compositor.hpp1
-rw-r--r--src/Window.cpp6
-rw-r--r--src/Window.hpp3
-rw-r--r--src/config/ConfigManager.cpp20
-rw-r--r--src/config/defaultConfig.hpp5
-rw-r--r--src/debug/Log.cpp3
-rw-r--r--src/debug/Log.hpp3
-rw-r--r--src/events/Devices.cpp9
-rw-r--r--src/events/Monitors.cpp2
-rw-r--r--src/events/Windows.cpp15
-rw-r--r--src/helpers/MiscFunctions.cpp32
-rw-r--r--src/helpers/MiscFunctions.hpp2
-rw-r--r--src/helpers/Timer.cpp17
-rw-r--r--src/helpers/Timer.hpp15
-rw-r--r--src/helpers/WLClasses.hpp2
-rw-r--r--src/layout/DwindleLayout.cpp16
-rw-r--r--src/layout/DwindleLayout.hpp2
-rw-r--r--src/layout/IHyprLayout.hpp2
-rw-r--r--src/managers/KeybindManager.cpp16
-rw-r--r--src/managers/input/InputManager.cpp28
-rw-r--r--src/managers/input/InputManager.hpp3
-rw-r--r--src/managers/input/Tablets.cpp2
-rw-r--r--src/render/OpenGL.cpp70
-rw-r--r--src/render/OpenGL.hpp2
-rw-r--r--src/render/Renderer.cpp49
-rw-r--r--src/render/Renderer.hpp6
-rw-r--r--src/render/Shaders.hpp341
-rw-r--r--src/render/decorations/CHyprDropShadowDecoration.cpp66
-rw-r--r--src/render/decorations/CHyprDropShadowDecoration.hpp27
-rw-r--r--src/render/decorations/CHyprGroupBarDecoration.cpp3
-rw-r--r--src/render/decorations/CHyprGroupBarDecoration.hpp2
-rw-r--r--src/render/decorations/IHyprWindowDecoration.hpp5
-rw-r--r--src/render/shaders/Shadow.hpp83
-rw-r--r--src/render/shaders/Textures.hpp341
35 files changed, 833 insertions, 390 deletions
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<CHyprDropShadowDecoration>(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 <algorithm>
#include "../Compositor.hpp"
+#include <sys/utsname.h>
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<char, 128> buffer;
+ std::string result;
+ const std::unique_ptr<FILE, decltype(&pclose)> 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<std::chrono::milliseconds>(getDuration()).count();
+}
+
+float CTimer::getSeconds() {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(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 <list>
#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 <string>
-
-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 <string>
+
+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 <string>
+
+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;
+})#";