aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--docs/Hyprland.12
-rw-r--r--docs/ISSUE_GUIDELINES.md14
-rw-r--r--docs/hyprctl.12
-rw-r--r--example/examplePlugin/Makefile2
-rw-r--r--example/examplePlugin/main.cpp9
-rw-r--r--example/hyprland.conf2
-rw-r--r--flake.lock12
-rw-r--r--flake.nix3
-rw-r--r--hyprctl/main.cpp3
-rw-r--r--meson.build8
-rw-r--r--meson_options.txt1
-rw-r--r--nix/default.nix12
-rw-r--r--nix/hm-module.nix2
-rw-r--r--nix/module.nix2
-rw-r--r--nix/wlroots-hidpi.patch28
-rw-r--r--src/Compositor.cpp88
-rw-r--r--src/Compositor.hpp5
-rw-r--r--src/SharedDefs.hpp12
-rw-r--r--src/Window.cpp61
-rw-r--r--src/Window.hpp8
-rw-r--r--src/config/ConfigManager.cpp113
-rw-r--r--src/config/ConfigManager.hpp27
-rw-r--r--src/config/defaultConfig.hpp2
-rw-r--r--src/debug/CrashReporter.cpp28
-rw-r--r--src/debug/HyprCtl.cpp53
-rw-r--r--src/debug/HyprDebugOverlay.hpp5
-rw-r--r--src/debug/HyprNotificationOverlay.cpp88
-rw-r--r--src/debug/HyprNotificationOverlay.hpp25
-rw-r--r--src/debug/Log.cpp6
-rw-r--r--src/debug/Log.hpp5
-rw-r--r--src/events/Layers.cpp14
-rw-r--r--src/events/Misc.cpp16
-rw-r--r--src/events/Monitors.cpp245
-rw-r--r--src/events/Popups.cpp19
-rw-r--r--src/events/Windows.cpp46
-rw-r--r--src/helpers/MiscFunctions.cpp6
-rw-r--r--src/helpers/Monitor.cpp21
-rw-r--r--src/helpers/Monitor.hpp5
-rw-r--r--src/helpers/SubsurfaceTree.cpp32
-rw-r--r--src/helpers/SubsurfaceTree.hpp4
-rw-r--r--src/helpers/WLClasses.cpp15
-rw-r--r--src/helpers/WLClasses.hpp12
-rw-r--r--src/helpers/WLSurface.cpp57
-rw-r--r--src/helpers/WLSurface.hpp49
-rw-r--r--src/layout/DwindleLayout.cpp15
-rw-r--r--src/layout/IHyprLayout.cpp4
-rw-r--r--src/layout/MasterLayout.cpp28
-rw-r--r--src/main.cpp4
-rw-r--r--src/managers/KeybindManager.cpp35
-rw-r--r--src/managers/input/InputManager.cpp87
-rw-r--r--src/managers/input/InputManager.hpp19
-rw-r--r--src/meson.build5
-rw-r--r--src/plugins/PluginAPI.cpp127
-rw-r--r--src/plugins/PluginAPI.hpp35
-rw-r--r--src/protocols/Screencopy.cpp2
-rw-r--r--src/protocols/ToplevelExportWlrFuncs.hpp4
-rw-r--r--src/render/OpenGL.cpp41
-rw-r--r--src/render/OpenGL.hpp10
-rw-r--r--src/render/Renderer.cpp281
-rw-r--r--src/render/Renderer.hpp54
-rw-r--r--src/render/Shader.hpp1
-rw-r--r--src/render/shaders/Textures.hpp15
63 files changed, 1374 insertions, 564 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af5651b4..7f08cfcd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,7 +66,7 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm egl xkbcommon libinput) # we do not check for wlroots, as we provide it ourselves
+pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm egl xkbcommon libinput pango pangocairo) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
diff --git a/docs/Hyprland.1 b/docs/Hyprland.1
index 78a86b49..a2496211 100644
--- a/docs/Hyprland.1
+++ b/docs/Hyprland.1
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 2.9.2.1
.\"
-.TH "Hyprland" "1" "09 Mar 2023" "" "Hyprland User Manual"
+.TH "Hyprland" "1" "31 Mar 2023" "" "Hyprland User Manual"
.hy
.SH NAME
.PP
diff --git a/docs/ISSUE_GUIDELINES.md b/docs/ISSUE_GUIDELINES.md
index 05adbe89..b8d007c2 100644
--- a/docs/ISSUE_GUIDELINES.md
+++ b/docs/ISSUE_GUIDELINES.md
@@ -45,6 +45,13 @@ cat /tmp/hypr/$(ls -t /tmp/hypr/ | head -n 2 | tail -n 1)/hyprland.log
basically, directories in /tmp/hypr are your sessions.
+## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
+
+If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland`
+
+Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
+
+Attach that file to your issue.
## Obtaining the Hyprland coredump (v0.21.0beta and below)
If you are on systemd, you can simply use
```
@@ -58,13 +65,6 @@ coredumpctl info [PID]
```
where `[PID]` is the PID you remembered.
-## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
-Go to `~/.hyprland/` and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
-
-If you do not see it, make sure you have "show hidden files" enabled in your file manager.
-
-Attach that file to your issue.
-
## Obtaining the debug Hyprland coredump
A debug coredump provides more information for debugging and may speed up the process of fixing the bug.
diff --git a/docs/hyprctl.1 b/docs/hyprctl.1
index b76941be..e7c13078 100644
--- a/docs/hyprctl.1
+++ b/docs/hyprctl.1
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 2.9.2.1
.\"
-.TH "hyprctl" "1" "09 Mar 2023" "" "hyprctl User Manual"
+.TH "hyprctl" "1" "31 Mar 2023" "" "hyprctl User Manual"
.hy
.SH NAME
.PP
diff --git a/example/examplePlugin/Makefile b/example/examplePlugin/Makefile
index 3ccc2930..ea5f3e6d 100644
--- a/example/examplePlugin/Makefile
+++ b/example/examplePlugin/Makefile
@@ -3,6 +3,6 @@
# and that you have ran `make protocols` in the hl dir.
all:
- g++ -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I "${HYPRLAND_HEADERS}" -std=c++23
+ g++ -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I "${HYPRLAND_HEADERS}" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/include" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/include" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/build/include" -std=c++23
clean:
rm ./examplePlugin.so
diff --git a/example/examplePlugin/main.cpp b/example/examplePlugin/main.cpp
index 49364f59..ef829ae0 100644
--- a/example/examplePlugin/main.cpp
+++ b/example/examplePlugin/main.cpp
@@ -73,9 +73,12 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
// Hook a public non-member
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
- // Hook a private member (!WARNING: the signature may differ in clang. This one is for gcc ONLY.)
- g_pMouseDownHook = HyprlandAPI::createFunctionHook(
- PHANDLE, HyprlandAPI::getFunctionAddressFromSignature(PHANDLE, "_ZN13CInputManager22processMouseDownNormalEP24wlr_pointer_button_event"), (void*)&hkProcessMouseDownNormal);
+ // Hook a private member
+ static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
+ g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
+
+ // fancy notifications
+ HyprlandAPI::addNotificationV2(PHANDLE, {{"text", "Example hint"}, {"time", (uint64_t)10000}, {"color", CColor(0.2, 0.2, 0.9, 1.0)}, {"icon", ICON_HINT}});
// Enable our hooks
g_pFocusHook->hook();
diff --git a/example/hyprland.conf b/example/hyprland.conf
index 1b25f751..a896d080 100644
--- a/example/hyprland.conf
+++ b/example/hyprland.conf
@@ -99,7 +99,7 @@ gestures {
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
-device:epic mouse V1 {
+device:epic-mouse-v1 {
sensitivity = -0.5
}
diff --git a/flake.lock b/flake.lock
index 3848af28..c77ef9a5 100644
--- a/flake.lock
+++ b/flake.lock
@@ -22,11 +22,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1677676435,
- "narHash": "sha256-6FxdcmQr5JeZqsQvfinIMr0XcTyTuR7EXX0H3ANShpQ=",
+ "lastModified": 1679172431,
+ "narHash": "sha256-XEh5gIt5otaUbEAPUY5DILUTyWe1goAyeqQtmwaFPyI=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "a08d6979dd7c82c4cef0dcc6ac45ab16051c1169",
+ "rev": "1603d11595a232205f03d46e635d919d1e1ec5b9",
"type": "github"
},
"original": {
@@ -48,11 +48,11 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
- "lastModified": 1677789111,
- "narHash": "sha256-dWrk+Q3bLdtFe5rkyaAKWCQJCeE/KFNllcu1DvBC38c=",
+ "lastModified": 1679340088,
+ "narHash": "sha256-/1KiYoBivDj8HC/eVK2Tr2WYkVdKJxq2Lb0tQs0qqJo=",
"owner": "wlroots",
"repo": "wlroots",
- "rev": "5ae17de23f5fd9bb252a698f3771c840280e2c05",
+ "rev": "1d64e12391a638201c679e71d4e22bb45e5faa8e",
"type": "gitlab"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 561de707..71a6cbf6 100644
--- a/flake.nix
+++ b/flake.nix
@@ -81,8 +81,9 @@
inherit udis86;
};
hyprland-debug = hyprland.override {debug = true;};
- hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;};
+ hyprland-hidpi = hyprland.override {hidpiXWayland = true;};
hyprland-nvidia = hyprland.override {nvidiaPatches = true;};
+ hyprland-no-hidpi = builtins.trace "hyprland-no-hidpi was removed. Please use the default package." hyprland;
udis86 = prev.callPackage ./nix/udis86.nix {};
diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp
index a5bfda65..14753e71 100644
--- a/hyprctl/main.cpp
+++ b/hyprctl/main.cpp
@@ -42,6 +42,7 @@ commands:
seterror
setprop
plugin
+ notify
flags:
-j -> output in JSON
@@ -352,6 +353,8 @@ int main(int argc, char** argv) {
request(fullRequest, 3);
else if (fullRequest.contains("/plugin"))
request(fullRequest, 1);
+ else if (fullRequest.contains("/notify"))
+ request(fullRequest, 2);
else if (fullRequest.contains("/output"))
exitStatus = outputRequest(argc, argv);
else if (fullRequest.contains("/setcursor"))
diff --git a/meson.build b/meson.build
index d9d06561..ce371ec3 100644
--- a/meson.build
+++ b/meson.build
@@ -59,14 +59,18 @@ endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
systemd_dep = dependency('libsystemd', required: get_option('systemd'))
-if get_option('systemd').enabled()
+if get_option('systemd').enabled()
if systemd_dep.found()
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
- else
+ else
error('Cannot enable systemd in Hyprland: libsystemd was not found')
endif
endif
+if get_option('legacy_renderer').enabled()
+ add_project_arguments('-DLEGACY_RENDERER', language: 'cpp')
+endif
+
if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif
diff --git a/meson_options.txt b/meson_options.txt
index e8e2b062..16a34a54 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,2 +1,3 @@
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
+option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
diff --git a/nix/default.nix b/nix/default.nix
index 6fb4db98..9924dbb3 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -1,8 +1,6 @@
{
lib,
stdenv,
- fetchFromGitHub,
- fetchpatch,
pkg-config,
meson,
ninja,
@@ -15,7 +13,7 @@
libxcb,
libxkbcommon,
mesa,
- mount,
+ pango,
pciutils,
systemd,
udis86,
@@ -27,7 +25,7 @@
xwayland,
debug ? false,
enableXWayland ? true,
- hidpiXWayland ? true,
+ hidpiXWayland ? false,
legacyRenderer ? false,
nvidiaPatches ? false,
withSystemd ? true,
@@ -74,6 +72,7 @@ in
libinput
libxkbcommon
mesa
+ pango
udis86
wayland
wayland-protocols
@@ -90,8 +89,9 @@ in
else "release";
mesonFlags = builtins.concatLists [
- (lib.optional (!enableXWayland) "-Dxwayland=disabled")
- (lib.optional legacyRenderer "-DLEGACY_RENDERER:STRING=true")
+ ["-Dauto_features=disabled"]
+ (lib.optional enableXWayland "-Dxwayland=enabled")
+ (lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
(lib.optional withSystemd "-Dsystemd=enabled")
];
diff --git a/nix/hm-module.nix b/nix/hm-module.nix
index 30cd59b5..9bad3fac 100644
--- a/nix/hm-module.nix
+++ b/nix/hm-module.nix
@@ -67,7 +67,7 @@ in {
};
hidpi = lib.mkOption {
type = lib.types.bool;
- default = true;
+ default = false;
description = ''
Enable HiDPI XWayland.
'';
diff --git a/nix/module.nix b/nix/module.nix
index 21b27513..f96dd9e0 100644
--- a/nix/module.nix
+++ b/nix/module.nix
@@ -47,7 +47,7 @@ in {
};
hidpi = mkOption {
type = types.bool;
- default = true;
+ default = false;
description = ''
Enable HiDPI XWayland.
'';
diff --git a/nix/wlroots-hidpi.patch b/nix/wlroots-hidpi.patch
index a61fcb45..fd4c8955 100644
--- a/nix/wlroots-hidpi.patch
+++ b/nix/wlroots-hidpi.patch
@@ -1,25 +1,25 @@
diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h
-index c69504e8..40d8de8c 100644
+index 3d540522..1c5a2e37 100644
--- a/include/xwayland/xwm.h
+++ b/include/xwayland/xwm.h
@@ -88,6 +88,7 @@ enum atom_name {
DND_ACTION_PRIVATE,
NET_CLIENT_LIST,
NET_CLIENT_LIST_STACKING,
-+ XWAYLAND_GLOBAL_OUTPUT_SCALE,
++ XWAYLAND_GLOBAL_OUTPUT_SCALE,
ATOM_LAST // keep last
};
-@@ -98,6 +99,7 @@ struct wlr_xwm {
+@@ -96,6 +97,7 @@ struct wlr_xwm {
struct wl_event_source *event_source;
struct wlr_seat *seat;
uint32_t ping_timeout;
-+ uint32_t scale;
++ uint32_t scale;
xcb_atom_t atoms[ATOM_LAST];
xcb_connection_t *xcb_conn;
diff --git a/xwayland/xwm.c b/xwayland/xwm.c
-index 5a36dc21..83981a87 100644
+index 5f857f24..21584ebd 100644
--- a/xwayland/xwm.c
+++ b/xwayland/xwm.c
@@ -19,6 +19,14 @@
@@ -34,10 +34,10 @@ index 5a36dc21..83981a87 100644
+ return (val + xwm->scale/2) / xwm->scale;
+}
+
- const char *const atom_map[ATOM_LAST] = {
+ static const char *const atom_map[ATOM_LAST] = {
[WL_SURFACE_ID] = "WL_SURFACE_ID",
[WL_SURFACE_SERIAL] = "WL_SURFACE_SERIAL",
-@@ -90,6 +98,7 @@ const char *const atom_map[ATOM_LAST] = {
+@@ -90,6 +98,7 @@ static const char *const atom_map[ATOM_LAST] = {
[DND_ACTION_PRIVATE] = "XdndActionPrivate",
[NET_CLIENT_LIST] = "_NET_CLIENT_LIST",
[NET_CLIENT_LIST_STACKING] = "_NET_CLIENT_LIST_STACKING",
@@ -45,7 +45,7 @@ index 5a36dc21..83981a87 100644
};
#define STARTUP_INFO_REMOVE_PREFIX "remove: ID="
-@@ -968,8 +977,8 @@ static void xwm_handle_create_notify(struct wlr_xwm *xwm,
+@@ -965,8 +974,8 @@ static void xwm_handle_create_notify(struct wlr_xwm *xwm,
return;
}
@@ -56,7 +56,7 @@ index 5a36dc21..83981a87 100644
}
static void xwm_handle_destroy_notify(struct wlr_xwm *xwm,
-@@ -1000,10 +1009,10 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm,
+@@ -997,10 +1006,10 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm,
struct wlr_xwayland_surface_configure_event wlr_event = {
.surface = surface,
@@ -71,7 +71,7 @@ index 5a36dc21..83981a87 100644
.mask = mask,
};
-@@ -1018,14 +1027,14 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm,
+@@ -1015,14 +1024,14 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm,
}
bool geometry_changed =
@@ -92,7 +92,7 @@ index 5a36dc21..83981a87 100644
}
if (xsurface->override_redirect != ev->override_redirect) {
-@@ -1136,6 +1145,20 @@ static void xwm_handle_property_notify(struct wlr_xwm *xwm,
+@@ -1133,6 +1142,20 @@ static void xwm_handle_property_notify(struct wlr_xwm *xwm,
xcb_property_notify_event_t *ev) {
struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window);
if (xsurface == NULL) {
@@ -113,7 +113,7 @@ index 5a36dc21..83981a87 100644
return;
}
-@@ -1763,16 +1786,17 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
+@@ -1760,16 +1783,17 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
int old_w = xsurface->width;
int old_h = xsurface->height;
@@ -133,7 +133,7 @@ index 5a36dc21..83981a87 100644
xcb_configure_window(xwm->xcb_conn, xsurface->window_id, mask, values);
// If the window size did not change, then we cannot rely on
-@@ -1780,15 +1804,15 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
+@@ -1777,15 +1801,15 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
// we are supposed to send a synthetic event. See ICCCM part
// 4.1.5. But we ignore override-redirect windows as ICCCM does
// not apply to them.
@@ -154,7 +154,7 @@ index 5a36dc21..83981a87 100644
};
xcb_send_event(xwm->xcb_conn, 0, xsurface->window_id,
-@@ -2125,6 +2149,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
+@@ -2122,6 +2146,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
wl_list_init(&xwm->pending_startup_ids);
xwm->ping_timeout = 10000;
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 398c9f7f..5bffc785 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -85,6 +85,7 @@ void CCompositor::setRandomSplash() {
}
void CCompositor::initServer() {
+
m_sWLDisplay = wl_display_create();
m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay);
@@ -247,6 +248,9 @@ void CCompositor::initServer() {
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
initManagers(STAGE_LATE);
+
+ Debug::log(LOG, "Disabling stdout logs! Check the log for further logs.");
+ Debug::disableStdout = true;
}
void CCompositor::initAllSignals() {
@@ -314,12 +318,6 @@ void CCompositor::cleanup() {
m_pLastFocus = nullptr;
m_pLastWindow = nullptr;
- // accumulate all PIDs for killing, also request closing.
- for (auto& w : m_vWindows) {
- if (w->m_bIsMapped && !w->isHidden())
- m_dProcessPIDsOnShutdown.push_back(w->getPID());
- }
-
// end threads
g_pEventManager->m_tThread = std::thread();
@@ -345,9 +343,6 @@ void CCompositor::cleanup() {
wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr;
-
- g_pKeybindManager->spawn("sleep 5 && kill -9 " + std::to_string(m_iHyprlandPID)); // this is to prevent that random "freezing"
- // the PID should not be reused.
}
void CCompositor::initManagers(eManagersInitStage stage) {
@@ -871,7 +866,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
m_pLastWindow = PLASTWINDOW;
- const auto PWINDOWSURFACE = pSurface ? pSurface : g_pXWaylandManager->getWindowSurface(pWindow);
+ const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow->m_pWLSurface.wlr();
focusSurface(PWINDOWSURFACE, pWindow);
@@ -925,8 +920,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
- if (m_sSeat.seat->keyboard_state.focused_surface == pSurface ||
- (pWindowOwner && m_sSeat.seat->keyboard_state.focused_surface == g_pXWaylandManager->getWindowSurface(pWindowOwner)))
+ if (m_sSeat.seat->keyboard_state.focused_surface == pSurface || (pWindowOwner && m_sSeat.seat->keyboard_state.focused_surface == pWindowOwner->m_pWLSurface.wlr()))
return; // Don't focus when already focused on this.
if (g_pSessionLockManager->isSessionLocked()) {
@@ -1037,7 +1031,7 @@ CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
if (!w->m_bIsMapped || w->m_bFadingOut || !w->m_bMappedX11)
continue;
- if (g_pXWaylandManager->getWindowSurface(w.get()) == pSurface)
+ if (w->m_pWLSurface.wlr() == pSurface)
return w.get();
}
@@ -1187,7 +1181,7 @@ bool CCompositor::isWindowActive(CWindow* pWindow) {
if (!windowValidMapped(pWindow))
return false;
- const auto PSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
+ const auto PSURFACE = pWindow->m_pWLSurface.wlr();
return PSURFACE == m_pLastFocus || pWindow == m_pLastWindow;
}
@@ -1524,11 +1518,11 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
const auto PSURFACE = pMouse->currentConstraint->surface;
for (auto& w : m_vWindows) {
- if (w->isHidden() || !w->m_bMappedX11 || !w->m_bIsMapped || !g_pXWaylandManager->getWindowSurface(w.get()))
+ if (w->isHidden() || !w->m_bMappedX11 || !w->m_bIsMapped || !w->m_pWLSurface.exists())
continue;
if (w->m_bIsX11) {
- if (PSURFACE == g_pXWaylandManager->getWindowSurface(w.get()))
+ if (PSURFACE == w->m_pWLSurface.wlr())
return w.get();
} else {
std::pair<wlr_surface*, bool> check = {PSURFACE, false};
@@ -1714,6 +1708,11 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == PWORKSPACEA->m_iID) {
+ if (w->m_bPinned) {
+ w->m_iWorkspaceID = PWORKSPACEB->m_iID;
+ continue;
+ }
+
w->m_iMonitorID = pMonitorB->ID;
// additionally, move floating and fs windows manually
@@ -1734,6 +1733,11 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == PWORKSPACEB->m_iID) {
+ if (w->m_bPinned) {
+ w->m_iWorkspaceID = PWORKSPACEA->m_iID;
+ continue;
+ }
+
w->m_iMonitorID = pMonitorA->ID;
// additionally, move floating and fs windows manually
@@ -1749,17 +1753,6 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
}
}
- // fix pinned windows
- for (auto& w : g_pCompositor->m_vWindows) {
- if (w->m_iWorkspaceID == pMonitorA->activeWorkspace && w->m_bPinned) {
- w->m_iWorkspaceID = PWORKSPACEB->m_iID;
- }
-
- if (w->m_iWorkspaceID == pMonitorB->activeWorkspace && w->m_bPinned) {
- w->m_iWorkspaceID = PWORKSPACEA->m_iID;
- }
- }
-
pMonitorA->activeWorkspace = PWORKSPACEB->m_iID;
pMonitorB->activeWorkspace = PWORKSPACEA->m_iID;
@@ -1909,6 +1902,11 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
+ if (w->m_bPinned) {
+ w->m_iWorkspaceID = nextWorkspaceOnMonitorID;
+ continue;
+ }
+
w->m_iMonitorID = pMonitor->ID;
// additionally, move floating and fs windows manually
@@ -2151,11 +2149,28 @@ void CCompositor::closeWindow(CWindow* pWindow) {
}
SLayerSurface* CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) {
+ std::pair<wlr_surface*, bool> result = {pSurface, false};
+
for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLayers) {
for (auto& ls : lsl) {
if (ls->layerSurface && ls->layerSurface->surface == pSurface)
return ls.get();
+
+ static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void {
+ if (surf == ((std::pair<wlr_surface*, bool>*)data)->first) {
+ *(bool*)data = true;
+ return;
+ }
+ };
+
+ if (!ls->layerSurface || !ls->mapped)
+ continue;
+
+ wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result);
+
+ if (result.second)
+ return ls.get();
}
}
}
@@ -2288,3 +2303,22 @@ int CCompositor::getNewSpecialID() {
return highest + 1;
}
+
+void CCompositor::performUserChecks() {
+ static constexpr auto BAD_PORTALS = {"kde", "gnome"};
+
+ static auto* const PSUPPRESSPORTAL = &g_pConfigManager->getConfigValuePtr("misc:suppress_portal_warnings")->intValue;
+
+ if (!*PSUPPRESSPORTAL) {
+ if (std::ranges::any_of(BAD_PORTALS, [&](const std::string& portal) { return std::filesystem::exists("/usr/share/xdg-desktop-portal/portals/" + portal + ".portal"); })) {
+ // bad portal detected
+ g_pHyprNotificationOverlay->addNotification("You have one or more incompatible xdg-desktop-portal impls installed. Please remove incompatible ones to avoid issues.",
+ CColor(0), 15000, ICON_ERROR);
+ }
+
+ if (std::filesystem::exists("/usr/share/xdg-desktop-portal/portals/hyprland.portal") && std::filesystem::exists("/usr/share/xdg-desktop-portal/portals/wlr.portal")) {
+ g_pHyprNotificationOverlay->addNotification("You have xdg-desktop-portal-hyprland and -wlr installed simultaneously. Please uninstall one to avoid issues.", CColor(0),
+ 15000, ICON_ERROR);
+ }
+ }
+}
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index c346df0c..7bae7672 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -28,8 +28,7 @@
#include "hyprerror/HyprError.hpp"
#include "plugins/PluginSystem.hpp"
-enum eManagersInitStage
-{
+enum eManagersInitStage {
STAGE_PRIORITY = 0,
STAGE_LATE
};
@@ -116,7 +115,6 @@ class CCompositor {
bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bIsShuttingDown = false;
- std::deque<uint64_t> m_dProcessPIDsOnShutdown; // stores PIDs of apps to kill later when shutting down
// ------------------------------------------------- //
@@ -189,6 +187,7 @@ class CCompositor {
void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const int&);
int getNewSpecialID();
+ void performUserChecks();
std::string explicitConfigPath;
diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp
new file mode 100644
index 00000000..d5daf747
--- /dev/null
+++ b/src/SharedDefs.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+enum eIcons
+{
+ ICON_WARNING = 0,
+ ICON_INFO,
+ ICON_HINT,
+ ICON_ERROR,
+ ICON_CONFUSED,
+ ICON_OK,
+ ICON_NONE
+}; \ No newline at end of file
diff --git a/src/Window.cpp b/src/Window.cpp
index c1f7a56f..3942114b 100644
--- a/src/Window.cpp
+++ b/src/Window.cpp
@@ -265,23 +265,32 @@ void CWindow::updateSurfaceOutputs() {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
- wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendLeaveIter, PLASTMONITOR->output);
+ wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
- wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendEnterIter, PNEWMONITOR->output);
+ wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
}
void CWindow::moveToWorkspace(int workspaceID) {
- if (m_iWorkspaceID != workspaceID) {
- m_iWorkspaceID = workspaceID;
+ if (m_iWorkspaceID == workspaceID)
+ return;
- if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); PWORKSPACE) {
- g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", this, PWORKSPACE->m_szName.c_str())});
- EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
- }
+ m_iWorkspaceID = workspaceID;
+
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
+
+ if (PWORKSPACE) {
+ g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", this, PWORKSPACE->m_szName.c_str())});
+ EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
+ }
- if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
- g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(g_pXWaylandManager->getWindowSurface(this), PMONITOR->scale);
+ if (m_pSwallowed) {
+ m_pSwallowed->moveToWorkspace(workspaceID);
+ m_pSwallowed->m_iMonitorID = m_iMonitorID;
}
+
+ if (PMONITOR)
+ g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(m_pWLSurface.wlr(), PMONITOR->scale);
}
CWindow* CWindow::X11TransientFor() {
@@ -332,10 +341,16 @@ void CWindow::onUnmap() {
m_vRealSize.setCallbackOnBegin(nullptr);
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other == this; });
+
+ m_pWLSurface.unassign();
+
+ hyprListener_unmapWindow.removeCallback();
}
void CWindow::onMap() {
+ m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
+
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
m_vRealPosition.resetAllCallbacks();
m_vRealSize.resetAllCallbacks();
@@ -361,6 +376,8 @@ void CWindow::onMap() {
m_fBorderAngleAnimationProgress = 1.f;
g_pCompositor->m_vWindowFocusHistory.push_back(this);
+
+ hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->events.unmap : &m_uSurface.xdg->events.unmap, &Events::listener_unmapWindow, this, "CWindow");
}
void CWindow::onBorderAngleAnimEnd(void* ptr) {
@@ -398,8 +415,10 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
m_sAdditionalConfigData.forceNoBorder = true;
} else if (r.szRule == "noshadow") {
m_sAdditionalConfigData.forceNoShadow = true;
+ } else if (r.szRule == "forcergbx") {
+ m_sAdditionalConfigData.forceRGBX = true;
} else if (r.szRule == "opaque") {
- if (!m_sAdditionalConfigData.forceOpaqueOverriden)
+ if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule.find("rounding") == 0) {
try {
@@ -456,12 +475,13 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.forceNoBlur = false;
m_sAdditionalConfigData.forceNoBorder = false;
m_sAdditionalConfigData.forceNoShadow = false;
- if (!m_sAdditionalConfigData.forceOpaqueOverriden)
+ if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = std::string("");
m_sAdditionalConfigData.rounding = -1;
m_sAdditionalConfigData.dimAround = false;
+ m_sAdditionalConfigData.forceRGBX = false;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
for (auto& r : WINDOWRULES) {
@@ -615,4 +635,21 @@ void CWindow::insertWindowToGroup(CWindow* pWindow) {
pWindow->m_sGroupData.pNextWindow = PHEAD;
setGroupCurrent(pWindow);
+}
+
+void CWindow::updateGroupOutputs() {
+ if (!m_sGroupData.pNextWindow)
+ return;
+
+ CWindow* curr = m_sGroupData.pNextWindow;
+
+ while (curr != this) {
+ curr->m_iMonitorID = m_iMonitorID;
+ curr->moveToWorkspace(m_iWorkspaceID);
+
+ curr->m_vRealPosition = m_vRealPosition.goalv();
+ curr->m_vRealSize = m_vRealSize.goalv();
+
+ curr = curr->m_sGroupData.pNextWindow;
+ }
} \ No newline at end of file
diff --git a/src/Window.hpp b/src/Window.hpp
index 85144e27..0b9f9f81 100644
--- a/src/Window.hpp
+++ b/src/Window.hpp
@@ -8,6 +8,7 @@
#include <deque>
#include "config/ConfigDataValues.hpp"
#include "helpers/Vector2D.hpp"
+#include "helpers/WLSurface.hpp"
enum eIdleInhibitMode
{
@@ -110,7 +111,7 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar<int> rounding = -1; // -1 means no
CWindowOverridableVar<bool> forceNoBlur = false;
CWindowOverridableVar<bool> forceOpaque = false;
- CWindowOverridableVar<bool> forceOpaqueOverriden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
+ CWindowOverridableVar<bool> forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
CWindowOverridableVar<bool> forceAllowsInput = false;
CWindowOverridableVar<bool> forceNoAnims = false;
CWindowOverridableVar<bool> forceNoBorder = false;
@@ -118,6 +119,7 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar<bool> windowDanceCompat = false;
CWindowOverridableVar<bool> noMaxSize = false;
CWindowOverridableVar<bool> dimAround = false;
+ CWindowOverridableVar<bool> forceRGBX = false;
};
struct SWindowRule {
@@ -158,6 +160,9 @@ class CWindow {
DYNLISTENER(setOverrideRedirect);
// DYNLISTENER(newSubsurfaceWindow);
+ CWLSurface m_pWLSurface;
+ std::list<CWLSurface> m_lPopupSurfaces;
+
union {
wlr_xdg_surface* xdg;
wlr_xwayland_surface* xwayland;
@@ -317,6 +322,7 @@ class CWindow {
CWindow* getGroupCurrent();
void setGroupCurrent(CWindow* pWindow);
void insertWindowToGroup(CWindow* pWindow);
+ void updateGroupOutputs();
private:
// For hidden windows and stuff
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 4cfd89b6..4d451af5 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -40,11 +40,13 @@ CConfigManager::CConfigManager() {
void CConfigManager::populateEnvironment() {
environmentVariables.clear();
for (char** env = environ; *env; ++env) {
- const std::string ENVVAR = *env;
- const auto VARIABLE = ENVVAR.substr(0, ENVVAR.find_first_of('='));
- const auto VALUE = ENVVAR.substr(ENVVAR.find_first_of('=') + 1);
- environmentVariables[VARIABLE] = VALUE;
+ const std::string ENVVAR = *env;
+ const auto VARIABLE = ENVVAR.substr(0, ENVVAR.find_first_of('='));
+ const auto VALUE = ENVVAR.substr(ENVVAR.find_first_of('=') + 1);
+ environmentVariables.emplace_back(std::make_pair<>(VARIABLE, VALUE));
}
+
+ std::sort(environmentVariables.begin(), environmentVariables.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
}
void CConfigManager::setDefaultVars() {
@@ -74,23 +76,27 @@ void CConfigManager::setDefaultVars() {
configValues["misc:key_press_enables_dpms"].intValue = 0;
configValues["misc:always_follow_on_dnd"].intValue = 1;
configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
- configValues["misc:animate_manual_resizes"].intValue = 1;
- configValues["misc:animate_mouse_windowdragging"].intValue = 1;
+ configValues["misc:animate_manual_resizes"].intValue = 0;
+ configValues["misc:animate_mouse_windowdragging"].intValue = 0;
configValues["misc:disable_autoreload"].intValue = 0;
configValues["misc:enable_swallow"].intValue = 0;
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
configValues["misc:focus_on_activate"].intValue = 0;
- configValues["misc:no_direct_scanout"].intValue = 0;
+ configValues["misc:no_direct_scanout"].intValue = 1;
configValues["misc:hide_cursor_on_touch"].intValue = 1;
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
-
- configValues["debug:int"].intValue = 0;
- configValues["debug:log_damage"].intValue = 0;
- configValues["debug:overlay"].intValue = 0;
- configValues["debug:damage_blink"].intValue = 0;
- configValues["debug:disable_logs"].intValue = 0;
- configValues["debug:disable_time"].intValue = 1;
- configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
+ configValues["misc:suppress_portal_warnings"].intValue = 0;
+ configValues["misc:render_ahead_of_time"].intValue = 0;
+ configValues["misc:render_ahead_safezone"].intValue = 1;
+
+ configValues["debug:int"].intValue = 0;
+ configValues["debug:log_damage"].intValue = 0;
+ configValues["debug:overlay"].intValue = 0;
+ configValues["debug:damage_blink"].intValue = 0;
+ configValues["debug:disable_logs"].intValue = 0;
+ configValues["debug:disable_time"].intValue = 1;
+ configValues["debug:enable_stdout_logs"].intValue = 0;
+ configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur"].intValue = 1;
@@ -293,7 +299,9 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
if (COMMAND[0] == '$') {
// register a dynamic var
Debug::log(LOG, "Registered dynamic var \"%s\" -> %s", COMMAND.c_str(), VALUE.c_str());
- configDynamicVars[COMMAND.substr(1)] = VALUE;
+ configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE));
+
+ std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
} else {
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
}
@@ -554,6 +562,12 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
} else if (ARGS[argno] == "bitdepth") {
newrule.enable10bit = ARGS[argno + 1] == "10";
argno++;
+ } else if (ARGS[argno] == "transform") {
+ newrule.transform = (wl_output_transform)std::stoi(ARGS[argno + 1]);
+ argno++;
+ } else if (ARGS[argno] == "workspace") {
+ m_mDefaultWorkspaces[newrule.name] = ARGS[argno + 1];
+ argno++;
} else {
Debug::log(ERR, "Config error: invalid monitor syntax");
parseError = "invalid syntax at \"" + ARGS[argno] + "\"";
@@ -597,8 +611,8 @@ void CConfigManager::handleBezier(const std::string& command, const std::string&
void CConfigManager::setAnimForChildren(SAnimationPropertyConfig* const ANIM) {
for (auto& [name, anim] : animationConfig) {
- if (anim.pParentAnimation == ANIM && !anim.overriden) {
- // if a child isnt overriden, set the values of the parent
+ if (anim.pParentAnimation == ANIM && !anim.overridden) {
+ // if a child isnt overridden, set the values of the parent
anim.pValues = ANIM->pValues;
setAnimForChildren(&anim);
@@ -621,8 +635,8 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
return;
}
- PANIM->second.overriden = true;
- PANIM->second.pValues = &PANIM->second;
+ PANIM->second.overridden = true;
+ PANIM->second.pValues = &PANIM->second;
// on/off
PANIM->second.internalEnabled = ARGS[1] == "1";
@@ -744,6 +758,8 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
if (KEY != "") {
if (isNumber(KEY) && std::stoi(KEY) > 9)
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
+ else if (KEY.find("code:") == 0 && isNumber(KEY.substr(5)))
+ g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
else
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse});
}
@@ -764,11 +780,11 @@ bool windowRuleValid(const std::string& RULE) {
RULE.find("maxsize") != 0 && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0 && RULE.find("idleinhibit") != 0 && RULE != "nofocus" && RULE != "noblur" &&
RULE != "noshadow" && RULE != "noborder" && RULE != "center" && RULE != "opaque" && RULE != "forceinput" && RULE != "fullscreen" && RULE != "nofullscreenrequest" &&
RULE != "nomaxsize" && RULE != "pin" && RULE != "noanim" && RULE != "dimaround" && RULE != "windowdance" && RULE != "maximize" && RULE.find("animation") != 0 &&
- RULE.find("rounding") != 0 && RULE.find("workspace") != 0 && RULE.find("bordercolor") != 0);
+ RULE.find("rounding") != 0 && RULE.find("workspace") != 0 && RULE.find("bordercolor") != 0 && RULE != "forcergbx");
}
bool layerRuleValid(const std::string& RULE) {
- return !(RULE != "noanim");
+ return !(RULE != "noanim" && RULE != "blur" && RULE != "ignorezero");
}
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
@@ -800,9 +816,8 @@ void CConfigManager::handleLayerRule(const std::string& command, const std::stri
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
// check rule and value
- if (RULE == "" || VALUE == "") {
+ if (RULE == "" || VALUE == "")
return;
- }
if (RULE == "unset") {
std::erase_if(m_dLayerRules, [&](const SLayerRule& other) { return other.targetNamespace == VALUE; });
@@ -816,6 +831,11 @@ void CConfigManager::handleLayerRule(const std::string& command, const std::stri
}
m_dLayerRules.push_back({VALUE, RULE});
+
+ for (auto& m : g_pCompositor->m_vMonitors)
+ for (auto& lsl : m->m_aLayerSurfaceLayers)
+ for (auto& ls : lsl)
+ ls->applyRules();
}
void CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
@@ -974,12 +994,7 @@ void CConfigManager::handleBlurLS(const std::string& command, const std::string&
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
const auto ARGS = CVarList(value);
- for (auto& mr : m_dMonitorRules) {
- if (mr.name == ARGS[0]) {
- mr.defaultWorkspace = ARGS[1];
- break;
- }
- }
+ m_mDefaultWorkspaces[ARGS[0]] = ARGS[1];
}
void CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
@@ -1382,6 +1397,8 @@ void CConfigManager::loadConfigLoadVars() {
// update layout
g_pLayoutManager->switchToLayout(configValues["general:layout"].strValue);
+ Debug::disableStdout = !configValues["debug:enable_stdout_logs"].intValue;
+
for (auto& m : g_pCompositor->m_vMonitors) {
// mark blur dirty
g_pHyprOpenGL->markBlurDirtyForMonitor(m.get());
@@ -1645,16 +1662,27 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
std::vector<SLayerRule> CConfigManager::getMatchingRules(SLayerSurface* pLS) {
std::vector<SLayerRule> returns;
+ if (!pLS->layerSurface || pLS->fadingOut)
+ return returns;
+
for (auto& lr : m_dLayerRules) {
- std::regex NSCHECK(lr.targetNamespace);
+ if (lr.targetNamespace.find("address:0x") == 0) {
+ if (getFormat("address:0x%x", pLS) != lr.targetNamespace)
+ continue;
+ } else {
+ std::regex NSCHECK(lr.targetNamespace);
- if (!pLS->layerSurface->_namespace || !std::regex_search(pLS->layerSurface->_namespace, NSCHECK))
- continue;
+ if (!pLS->layerSurface->_namespace || !std::regex_search(pLS->layerSurface->_namespace, NSCHECK))
+ continue;
+ }
// hit
returns.push_back(lr);
}
+ if (pLS->layerSurface->_namespace && shouldBlurLS(pLS->layerSurface->_namespace))
+ returns.push_back({pLS->layerSurface->_namespace, "blur"});
+
return returns;
}
@@ -1663,10 +1691,11 @@ void CConfigManager::dispatchExecOnce() {
return;
// update dbus env
- handleRawExec(
- "",
- "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
- "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE");
+ if (g_pCompositor->m_sWLRSession)
+ handleRawExec(
+ "",
+ "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && hash dbus-update-activation-environment 2>/dev/null && "
+ "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE");
firstExecDispatched = true;
@@ -1686,6 +1715,9 @@ void CConfigManager::dispatchExecOnce() {
for (auto& ws : g_pCompositor->m_vWorkspaces) {
wlr_ext_workspace_handle_v1_set_name(ws->m_pWlrHandle, ws->m_szName.c_str());
}
+
+ // check for user's possible errors with their setup and notify them if needed
+ g_pCompositor->performUserChecks();
}
void CConfigManager::performMonitorReload() {
@@ -1907,3 +1939,10 @@ void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name,
void CConfigManager::removePluginConfig(HANDLE handle) {
std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; });
}
+
+std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {
+ const auto IT = std::find_if(m_mDefaultWorkspaces.begin(), m_mDefaultWorkspaces.end(), [&](const auto& other) { return other.first == name; });
+ if (IT == m_mDefaultWorkspaces.end())
+ return "";
+ return IT->second;
+} \ No newline at end of file
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index fd6b40af..c554763f 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -34,16 +34,15 @@ struct SConfigValue {
};
struct SMonitorRule {
- std::string name = "";
- Vector2D resolution = Vector2D(1280, 720);
- Vector2D offset = Vector2D(0, 0);
- float scale = 1;
- float refreshRate = 60;
- std::string defaultWorkspace = "";
- bool disabled = false;
- wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
- std::string mirrorOf = "";
- bool enable10bit = false;
+ std::string name = "";
+ Vector2D resolution = Vector2D(1280, 720);
+ Vector2D offset = Vector2D(0, 0);
+ float scale = 1;
+ float refreshRate = 60;
+ bool disabled = false;
+ wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ std::string mirrorOf = "";
+ bool enable10bit = false;
};
struct SMonitorAdditionalReservedArea {
@@ -54,7 +53,7 @@ struct SMonitorAdditionalReservedArea {
};
struct SAnimationPropertyConfig {
- bool overriden = true;
+ bool overridden = true;
std::string internalBezier = "";
std::string internalStyle = "";
@@ -150,6 +149,7 @@ class CConfigManager {
SConfigValue* getConfigValuePtrSafe(const std::string&);
SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = "");
+ std::string getDefaultWorkspaceFor(const std::string&);
CMonitor* getBoundMonitorForWS(const std::string&);
std::string getBoundMonitorStringForWS(const std::string&);
@@ -187,7 +187,7 @@ class CConfigManager {
private:
std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
- std::unordered_map<std::string, std::string> configDynamicVars; // stores dynamic vars declared by the user
+ std::vector<std::pair<std::string, std::string>> configDynamicVars; // stores dynamic vars declared by the user
std::unordered_map<std::string, SConfigValue> configValues;
std::unordered_map<std::string, std::unordered_map<std::string, SConfigValue>> deviceConfigs; // stores device configs
@@ -208,6 +208,7 @@ class CConfigManager {
bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules;
+ std::unordered_map<std::string, std::string> m_mDefaultWorkspaces;
std::deque<SWindowRule> m_dWindowRules;
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
@@ -215,7 +216,7 @@ class CConfigManager {
bool firstExecDispatched = false;
std::deque<std::string> firstExecRequests;
- std::unordered_map<std::string, std::string> environmentVariables;
+ std::vector<std::pair<std::string, std::string>> environmentVariables;
// internal methods
void setDefaultVars();
diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp
index f657d279..85d83dda 100644
--- a/src/config/defaultConfig.hpp
+++ b/src/config/defaultConfig.hpp
@@ -108,7 +108,7 @@ gestures {
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
-device:epic mouse V1 {
+device:epic-mouse-v1 {
sensitivity = -0.5
}
diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp
index 713f91df..d553b7b0 100644
--- a/src/debug/CrashReporter.cpp
+++ b/src/debug/CrashReporter.cpp
@@ -46,6 +46,8 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += getFormat("Hyprland received signal %d (%s)\n\n", sig, strsignal(sig));
+ finalCrashReport += getFormat("Version: %s\n\n", GIT_COMMIT_HASH);
+
if (!g_pPluginSystem->getAllPlugins().empty()) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
@@ -127,18 +129,32 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += execAndGet(("cat \"" + Debug::logFile + "\" | tail -n 50").c_str());
const auto HOME = getenv("HOME");
+ const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
if (!HOME)
return;
- if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
- std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
- std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
- }
+ std::ofstream ofs;
+ if (!CACHE_HOME) {
+ if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
+ std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
+ std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
+ }
- std::ofstream ofs(std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
+ ofs.open(std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
+
+ } else if (CACHE_HOME) {
+ if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
+ std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
+ std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
+ }
+
+ ofs.open(std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
+ } else {
+ return;
+ }
ofs << finalCrashReport;
ofs.close();
-} \ No newline at end of file
+}
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index 74dd7a15..4d65135e 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -486,7 +486,7 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
ret += "animations:\n";
for (auto& ac : g_pConfigManager->getAnimationConfig()) {
- ret += getFormat("\n\tname: %s\n\t\toverriden: %i\n\t\tbezier: %s\n\t\tenabled: %i\n\t\tspeed: %.2f\n\t\tstyle: %s\n", ac.first.c_str(), (int)ac.second.overriden,
+ ret += getFormat("\n\tname: %s\n\t\toverriden: %i\n\t\tbezier: %s\n\t\tenabled: %i\n\t\tspeed: %.2f\n\t\tstyle: %s\n", ac.first.c_str(), (int)ac.second.overridden,
ac.second.internalBezier.c_str(), ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle.c_str());
}
@@ -503,13 +503,13 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
ret += getFormat(R"#(
{
"name": "%s",
- "overriden": %s,
+ "overridden": %s,
"bezier": "%s",
"enabled": %s,
"speed": %.2f,
"style": "%s"
},)#",
- ac.first.c_str(), ac.second.overriden ? "true" : "false", ac.second.internalBezier.c_str(), ac.second.internalEnabled ? "true" : "false",
+ ac.first.c_str(), ac.second.overridden ? "true" : "false", ac.second.internalBezier.c_str(), ac.second.internalEnabled ? "true" : "false",
ac.second.internalSpeed, ac.second.internalStyle.c_str());
}
@@ -933,7 +933,7 @@ std::string dispatchSetProp(std::string request) {
} else if (PROP == "forceopaque") {
PWINDOW->m_sAdditionalConfigData.forceOpaque.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceopaqueoverriden") {
- PWINDOW->m_sAdditionalConfigData.forceOpaqueOverriden.forceSetIgnoreLocked(configStringToInt(VAL), lock);
+ PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceallowsinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoanims") {
@@ -960,6 +960,8 @@ std::string dispatchSetProp(std::string request) {
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "inactivebordercolor") {
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
+ } else if (PROP == "forcergbx") {
+ PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else {
return "prop not found";
}
@@ -1137,6 +1139,47 @@ std::string dispatchPlugin(std::string request) {
return "ok";
}
+std::string dispatchNotify(std::string request) {
+ CVarList vars(request, 0, ' ');
+
+ if (vars.size() < 5)
+ return "not enough args";
+
+ const auto ICON = vars[1];
+
+ if (!isNumber(ICON))
+ return "invalid arg 1";
+
+ int icon = -1;
+ try {
+ icon = std::stoi(ICON);
+ } catch (std::exception& e) { return "invalid arg 1"; }
+
+ if (icon == -1 || icon > ICON_NONE) {
+ icon = ICON_NONE;
+ }
+
+ const auto TIME = vars[2];
+ int time = 0;
+ try {
+ time = std::stoi(TIME);
+ } catch (std::exception& e) { return "invalid arg 2"; }
+
+ CColor color = configStringToInt(vars[3]);
+
+ std::string message = "";
+
+ for (size_t i = 4; i < vars.size(); ++i) {
+ message += vars[i] + " ";
+ }
+
+ message.pop_back();
+
+ g_pHyprNotificationOverlay->addNotification(message, color, time, (eIcons)icon);
+
+ return "ok";
+}
+
std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL;
@@ -1186,6 +1229,8 @@ std::string getReply(std::string request) {
return animationsRequest(format);
else if (request.find("plugin") == 0)
return dispatchPlugin(request);
+ else if (request.find("notify") == 0)
+ return dispatchNotify(request);
else if (request.find("setprop") == 0)
return dispatchSetProp(request);
else if (request.find("seterror") == 0)
diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp
index 67f188d2..03027018 100644
--- a/src/debug/HyprDebugOverlay.hpp
+++ b/src/debug/HyprDebugOverlay.hpp
@@ -7,6 +7,8 @@
#include <cairo/cairo.h>
#include <unordered_map>
+class CHyprRenderer;
+
class CHyprMonitorDebugOverlay {
public:
int draw(int offset);
@@ -23,6 +25,8 @@ class CHyprMonitorDebugOverlay {
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
CMonitor* m_pMonitor = nullptr;
wlr_box m_wbLastDrawnBox;
+
+ friend class CHyprRenderer;
};
class CHyprDebugOverlay {
@@ -41,6 +45,7 @@ class CHyprDebugOverlay {
CTexture m_tTexture;
friend class CHyprMonitorDebugOverlay;
+ friend class CHyprRenderer;
};
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay; \ No newline at end of file
diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp
index 94cb6a6c..b19f56fa 100644
--- a/src/debug/HyprNotificationOverlay.cpp
+++ b/src/debug/HyprNotificationOverlay.cpp
@@ -1,5 +1,6 @@
#include "HyprNotificationOverlay.hpp"
#include "../Compositor.hpp"
+#include <pango/pangocairo.h>
CHyprNotificationOverlay::CHyprNotificationOverlay() {
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, std::any param) {
@@ -8,38 +9,77 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
g_pHyprRenderer->damageBox(&m_bLastDamage);
});
+
+ // check for the icon backend
+ std::string fonts = execAndGet("fc-list");
+ std::string fontsLower = fonts;
+ std::transform(fontsLower.begin(), fontsLower.end(), fontsLower.begin(), [&](char& i) { return std::tolower(i); });
+
+ size_t index = 0;
+
+ if (index = fontsLower.find("nerd"); index != std::string::npos) {
+ m_eIconBackend = ICONS_BACKEND_NF;
+ } else if (index = fontsLower.find("font awesome"); index != std::string::npos) {
+ m_eIconBackend = ICONS_BACKEND_FA;
+ } else if (index = fontsLower.find("fontawesome"); index != std::string::npos) {
+ m_eIconBackend = ICONS_BACKEND_FA;
+ } else {
+ return;
+ }
+
+ const auto LASTNEWLINE = fonts.find_last_of('\n', index);
+ const auto COLON = fonts.find(':', LASTNEWLINE);
+ const auto COMMA = fonts.find(',', COLON);
+ const auto NEWLINE = fonts.find('\n', COLON);
+ const auto LASTCHAR = COMMA < NEWLINE ? COMMA : NEWLINE;
+
+ m_szIconFontName = fonts.substr(COLON + 2, LASTCHAR - (COLON + 2));
}
-void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs) {
+void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon) {
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
PNOTIF->text = text;
- PNOTIF->color = color;
+ PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
PNOTIF->started.reset();
PNOTIF->timeMs = timeMs;
+ PNOTIF->icon = icon;
}
wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
static constexpr auto ANIM_DURATION_MS = 600.0;
static constexpr auto ANIM_LAG_MS = 100.0;
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
+ static constexpr auto ICON_PAD = 3.0;
+ static constexpr auto ICON_SCALE = 0.9;
+ static constexpr auto GRADIENT_SIZE = 60.0;
float offsetY = 10;
float maxWidth = 0;
const auto SCALE = pMonitor->scale;
- const auto FONTSIZE = std::clamp((int)(10.f * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
+ const auto FONTSIZE = std::clamp((int)(13.f * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
const auto MONSIZE = pMonitor->vecPixelSize;
- cairo_select_font_face(m_pCairo, "Noto Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size(m_pCairo, FONTSIZE);
+ cairo_text_extents_t cairoExtents;
+ int iconW = 0, iconH = 0;
- cairo_text_extents_t cairoExtents;
+ PangoLayout* pangoLayout;
+ PangoFontDescription* pangoFD;
- const auto PBEZIER = g_pAnimationManager->getBezier("default");
+ pangoLayout = pango_cairo_create_layout(m_pCairo);
+ pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str());
+ pango_layout_set_font_description(pangoLayout, pangoFD);
+
+ cairo_select_font_face(m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(m_pCairo, FONTSIZE);
+
+ const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto& notif : m_dNotifications) {
+ const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
+
// first rect (bg, col)
const float FIRSTRECTANIMP =
(notif->started.getMillis() > (ANIM_DURATION_MS - ANIM_LAG_MS) ?
@@ -62,10 +102,18 @@ wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
// get text size
cairo_text_extents(m_pCairo, notif->text.c_str(), &cairoExtents);
+ const auto ICON = ICONS_ARRAY[m_eIconBackend][notif->icon];
+ const auto ICONCOLOR = ICONS_COLORS[notif->icon];
+ pango_layout_set_text(pangoLayout, ICON.c_str(), -1);
+ pango_layout_set_font_description(pangoLayout, pangoFD);
+ pango_cairo_update_layout(m_pCairo, pangoLayout);
+ pango_layout_get_size(pangoLayout, &iconW, &iconH);
+ iconW /= PANGO_SCALE;
+ iconH /= PANGO_SCALE;
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
- const auto NOTIFSIZE = Vector2D{cairoExtents.width + 20, cairoExtents.height + 10};
+ const auto NOTIFSIZE = Vector2D{cairoExtents.width + 20 + iconW + 2 * ICONPADFORNOTIF, cairoExtents.height + 10};
// draw rects
cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y);
@@ -81,9 +129,28 @@ wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2);
cairo_fill(m_pCairo);
+ // draw gradient
+ if (notif->icon != ICON_NONE) {
+ cairo_pattern_t* pattern;
+ pattern = cairo_pattern_create_linear(MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY,
+ MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC + GRADIENT_SIZE, offsetY);
+ cairo_pattern_add_color_stop_rgba(pattern, 0, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, ICONCOLOR.a / 3.0);
+ cairo_pattern_add_color_stop_rgba(pattern, 1, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, 0);
+ cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, GRADIENT_SIZE, NOTIFSIZE.y);
+ cairo_set_source(m_pCairo, pattern);
+ cairo_fill(m_pCairo);
+ cairo_pattern_destroy(pattern);
+
+ // draw icon
+ cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
+ cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY + std::round((NOTIFSIZE.y - iconH - 4) / 2.0));
+ pango_cairo_show_layout(m_pCairo, pangoLayout);
+ }
+
// draw text
+ cairo_set_font_size(m_pCairo, FONTSIZE);
cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f);
- cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE, offsetY + FONTSIZE + (FONTSIZE / 10.0));
+ cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY + FONTSIZE + (FONTSIZE / 10.0));
cairo_show_text(m_pCairo, notif->text.c_str());
// adjust offset and move on
@@ -93,6 +160,9 @@ wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
maxWidth = NOTIFSIZE.x;
}
+ pango_font_description_free(pangoFD);
+ g_object_unref(pangoLayout);
+
// cleanup notifs
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp
index 12ad8e38..462bbde1 100644
--- a/src/debug/HyprNotificationOverlay.hpp
+++ b/src/debug/HyprNotificationOverlay.hpp
@@ -4,16 +4,36 @@
#include "../helpers/Timer.hpp"
#include "../helpers/Monitor.hpp"
#include "../render/Texture.hpp"
+#include "../SharedDefs.hpp"
#include <deque>
#include <cairo/cairo.h>
+enum eIconBackend
+{
+ ICONS_BACKEND_NONE = 0,
+ ICONS_BACKEND_NF,
+ ICONS_BACKEND_FA
+};
+
+static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
+ std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "󰸞", ""},
+ std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
+static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
+ CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
+ CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
+ CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
+ CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
+ CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
+ CColor{0, 0, 0, 1.0}};
+
struct SNotification {
std::string text = "";
CColor color;
CTimer started;
float timeMs = 0;
+ eIcons icon = ICON_NONE;
};
class CHyprNotificationOverlay {
@@ -21,7 +41,7 @@ class CHyprNotificationOverlay {
CHyprNotificationOverlay();
void draw(CMonitor* pMonitor);
- void addNotification(const std::string& text, const CColor& color, const float timeMs);
+ void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
private:
wlr_box drawNotifications(CMonitor* pMonitor);
@@ -35,6 +55,9 @@ class CHyprNotificationOverlay {
CMonitor* m_pLastMonitor = nullptr;
CTexture m_tTexture;
+
+ eIconBackend m_eIconBackend = ICONS_BACKEND_NONE;
+ std::string m_szIconFontName = "Sans";
};
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay; \ No newline at end of file
diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp
index 7800b831..8c537c3f 100644
--- a/src/debug/Log.cpp
+++ b/src/debug/Log.cpp
@@ -23,6 +23,9 @@ void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
ofs << "[wlr] " << output << "\n";
ofs.close();
+
+ if (!disableStdout)
+ std::cout << output << "\n";
}
void Debug::log(LogLevel level, const char* fmt, ...) {
@@ -75,5 +78,6 @@ void Debug::log(LogLevel level, const char* fmt, ...) {
ofs.close();
// log it to the stdout too.
- std::cout << output << "\n";
+ if (!disableStdout)
+ std::cout << output << "\n";
}
diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp
index 98d176af..a159a2da 100644
--- a/src/debug/Log.hpp
+++ b/src/debug/Log.hpp
@@ -20,6 +20,7 @@ namespace Debug {
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
inline std::string logFile;
- inline int64_t* disableLogs = nullptr;
- inline int64_t* disableTime = nullptr;
+ inline int64_t* disableLogs = nullptr;
+ inline int64_t* disableTime = nullptr;
+ inline bool disableStdout = false;
}; \ No newline at end of file
diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp
index 65f679d5..a7135953 100644
--- a/src/events/Layers.cpp
+++ b/src/events/Layers.cpp
@@ -112,6 +112,8 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
layersurface->layerSurface->mapped = true;
layersurface->mapped = true;
+ layersurface->surface = layersurface->layerSurface->surface;
+
// anim
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
@@ -121,10 +123,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
if (!PMONITOR)
return;
- for (auto& rule : g_pConfigManager->getMatchingRules(layersurface)) {
- if (rule.rule == "noanim")
- layersurface->noAnimations = true;
- }
+ layersurface->applyRules();
if ((uint64_t)layersurface->monitorID != PMONITOR->ID) {
const auto POLDMON = g_pCompositor->getMonitorFromID(layersurface->monitorID);
@@ -210,12 +209,15 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
+ const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layersurface->layerSurface->surface;
+
+ layersurface->surface = nullptr;
+
if (!PMONITOR)
return;
// refocus if needed
- if (layersurface->layerSurface->surface == g_pCompositor->m_pLastFocus) {
-
+ if (WASLASTFOCUS) {
Vector2D surfaceCoords;
SLayerSurface* pFoundLayerSurface = nullptr;
wlr_surface* foundSurface = nullptr;
diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp
index 8d1b9c00..22587599 100644
--- a/src/events/Misc.cpp
+++ b/src/events/Misc.cpp
@@ -116,20 +116,11 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag,
"DragIcon");
}
-
- static auto* const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
-
- if (*PFOLLOWONDND)
- g_pInputManager->m_pFollowOnDnDBegin = g_pCompositor->m_pLastWindow;
- else
- g_pInputManager->m_pFollowOnDnDBegin = nullptr;
}
void Events::listener_destroyDrag(void* owner, void* data) {
Debug::log(LOG, "Drag destroyed.");
- static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
-
if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface)
g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4,
g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4);
@@ -137,13 +128,6 @@ void Events::listener_destroyDrag(void* owner, void* data) {
g_pInputManager->m_sDrag.drag = nullptr;
g_pInputManager->m_sDrag.dragIcon = nullptr;
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
-
- g_pInputManager->refocus();
-
- if (g_pInputManager->m_pFollowOnDnDBegin && *PFOLLOWMOUSE != 1)
- g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
-
- g_pInputManager->m_pFollowOnDnDBegin = nullptr;
}
void Events::listener_mapDragIcon(void* owner, void* data) {
diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp
index fbc163cc..ccdb3ef0 100644
--- a/src/events/Monitors.cpp
+++ b/src/events/Monitors.cpp
@@ -44,7 +44,7 @@ void Events::listener_change(wl_listener* listener, void* data) {
}
void Events::listener_newOutput(wl_listener* listener, void* data) {
- // new monitor added, let's accomodate for that.
+ // new monitor added, let's accommodate for that.
const auto OUTPUT = (wlr_output*)data;
// for warping the cursor on launch
@@ -101,6 +101,13 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
const auto POS = PNEWMONITOR->vecPosition + PNEWMONITOR->vecSize / 2.f;
if (g_pCompositor->m_sSeat.mouse)
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, POS.x, POS.y);
+ } else {
+ for (auto& w : g_pCompositor->m_vWindows) {
+ if (w->m_iMonitorID == PNEWMONITOR->ID) {
+ w->m_iLastSurfaceMonitorID = -1;
+ w->updateSurfaceOutputs();
+ }
+ }
}
}
@@ -119,235 +126,37 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (!PMONITOR->m_bEnabled)
return;
- static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
- static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
- static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
-
- static auto* const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
- static auto* const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("debug:damage_tracking")->intValue;
- static auto* const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
- static auto* const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
- static auto* const PVFR = &g_pConfigManager->getConfigValuePtr("misc:vfr")->intValue;
-
- static int damageBlinkCleanup = 0; // because double-buffered
-
- if (!*PDAMAGEBLINK)
- damageBlinkCleanup = 0;
+ static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
+ static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
- if (*PDEBUGOVERLAY == 1) {
- startRender = std::chrono::high_resolution_clock::now();
- g_pDebugOverlay->frameData(PMONITOR);
- }
-
- if (PMONITOR->framesToSkip > 0) {
- PMONITOR->framesToSkip -= 1;
+ PMONITOR->lastPresentationTimer.reset();
- if (!PMONITOR->noFrameSchedule)
- g_pCompositor->scheduleFrameForMonitor(PMONITOR);
- else {
- Debug::log(LOG, "NoFrameSchedule hit for %s.", PMONITOR->szName.c_str());
+ if (*PENABLERAT) {
+ if (!PMONITOR->RATScheduled) {
+ // render
+ g_pHyprRenderer->renderMonitor(PMONITOR);
}
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
-
- if (PMONITOR->framesToSkip > 10)
- PMONITOR->framesToSkip = 0;
- return;
- }
- // checks //
- if (PMONITOR->ID == g_pHyprRenderer->m_pMostHzMonitor->ID ||
- *PVFR == 1) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
- g_pCompositor->sanityCheckWorkspaces();
+ PMONITOR->RATScheduled = false;
- g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
+ const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
- 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->scheduledRecalc) {
- PMONITOR->scheduledRecalc = false;
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
- }
-
- // Direct scanout first
- if (!*PNODIRECTSCANOUT) {
- if (g_pHyprRenderer->attemptDirectScanout(PMONITOR)) {
+ if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate)
return;
- } else if (g_pHyprRenderer->m_pLastScanout) {
- Debug::log(LOG, "Left a direct scanout.");
- g_pHyprRenderer->m_pLastScanout = nullptr;
- }
- }
-
- EMIT_HOOK_EVENT("preRender", PMONITOR);
- timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
+ const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis();
- // check the damage
- pixman_region32_t damage;
- bool hasChanged;
- pixman_region32_init(&damage);
+ PMONITOR->RATScheduled = true;
- if (*PDAMAGETRACKINGMODE == -1) {
- Debug::log(CRIT, "Damage tracking mode -1 ????");
- return;
- }
-
- if (!wlr_output_damage_attach_render(PMONITOR->damage, &hasChanged, &damage)) {
- Debug::log(ERR, "Couldn't attach render to display %s ???", PMONITOR->szName.c_str());
- return;
- }
-
- PMONITOR->renderingActive = true;
-
- // we need to cleanup fading out when rendering the appropriate context
- g_pCompositor->cleanupFadingOut(PMONITOR->ID);
-
- if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0 && damageBlinkCleanup == 0) {
- pixman_region32_fini(&damage);
- wlr_output_rollback(PMONITOR->output);
-
- if (*PDAMAGEBLINK || *PVFR == 0)
- g_pCompositor->scheduleFrameForMonitor(PMONITOR);
-
- PMONITOR->renderingActive = false;
+ const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
+ const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
- return;
- }
-
- // if we have no tracking or full tracking, invalidate the entire monitor
- if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0 ||
- PMONITOR->isMirror() /* why??? */) {
- pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x * 10, (int)PMONITOR->vecTransformedSize.y * 10); // wot?
-
- pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
+ if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1)
+ g_pHyprRenderer->renderMonitor(PMONITOR);
+ else
+ wl_event_source_timer_update(PMONITOR->renderTimer, TIMETOSLEEP);
} else {
- static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
-
- // if we use blur we need to expand the damage for proper blurring
- if (*PBLURENABLED == 1) {
- // TODO: can this be optimized?
- static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
- static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
- const auto BLURRADIUS = *PBLURSIZE * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
-
- // now, prep the damage, get the extended damage region
- wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring
-
- pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
-
- wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring 2
- } else {
- pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
- }
- }
-
- if (PMONITOR->forceFullFrames > 0) {
- PMONITOR->forceFullFrames -= 1;
- if (PMONITOR->forceFullFrames > 10)
- PMONITOR->forceFullFrames = 0;
- }
-
- const bool UNLOCK_SC = g_pHyprRenderer->m_bSoftwareCursorsLocked;
- if (UNLOCK_SC)
- wlr_output_lock_software_cursors(PMONITOR->output, true);
-
- g_pHyprOpenGL->begin(PMONITOR, &damage);
-
- if (PMONITOR->isMirror()) {
- g_pHyprOpenGL->renderMirrored();
- } else {
- g_pHyprOpenGL->clear(CColor(17.0 / 255.0, 17.0 / 255.0, 17.0 / 255.0, 1.0));
- g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
-
- g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
-
- if (PMONITOR == g_pCompositor->m_pLastMonitor) {
- g_pHyprNotificationOverlay->draw(PMONITOR);
- g_pHyprError->draw();
- }
-
- // for drawing the debug overlay
- if (PMONITOR == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
- startRenderOverlay = std::chrono::high_resolution_clock::now();
- g_pDebugOverlay->draw();
- endRenderOverlay = std::chrono::high_resolution_clock::now();
- }
-
- if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
- wlr_box monrect = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
- g_pHyprOpenGL->renderRect(&monrect, CColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0);
- damageBlinkCleanup = 1;
- } else if (*PDAMAGEBLINK) {
- damageBlinkCleanup++;
- if (damageBlinkCleanup > 3)
- damageBlinkCleanup = 0;
- }
-
- if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y)) {
- wlr_output_render_software_cursors(PMONITOR->output, NULL);
- wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
- }
- }
-
- g_pHyprOpenGL->end();
-
- // calc frame damage
- pixman_region32_t frameDamage;
- pixman_region32_init(&frameDamage);
-
- const auto TRANSFORM = wlr_output_transform_invert(PMONITOR->output->transform);
- wlr_region_transform(&frameDamage, &g_pHyprOpenGL->m_rOriginalDamageRegion, TRANSFORM, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
-
- if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
- pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
-
- if (*PDAMAGEBLINK)
- pixman_region32_union(&frameDamage, &frameDamage, &damage);
-
- wlr_output_set_damage(PMONITOR->output, &frameDamage);
-
- if (!PMONITOR->mirrors.empty())
- g_pHyprRenderer->damageMirrorsWith(PMONITOR, &frameDamage);
-
- pixman_region32_fini(&frameDamage);
-
- PMONITOR->renderingActive = false;
-
- if (!wlr_output_commit(PMONITOR->output)) {
- pixman_region32_fini(&damage);
-
- if (UNLOCK_SC)
- wlr_output_lock_software_cursors(PMONITOR->output, false);
-
- return;
- }
-
- g_pProtocolManager->m_pScreencopyProtocolManager->onRenderEnd(PMONITOR);
- pixman_region32_fini(&damage);
-
- if (UNLOCK_SC)
- wlr_output_lock_software_cursors(PMONITOR->output, false);
-
- if (*PDAMAGEBLINK || *PVFR == 0 || PMONITOR->pendingFrame)
- g_pCompositor->scheduleFrameForMonitor(PMONITOR);
-
- PMONITOR->pendingFrame = false;
-
- if (*PDEBUGOVERLAY == 1) {
- const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
- g_pDebugOverlay->renderData(PMONITOR, µs);
- if (PMONITOR == g_pCompositor->m_vMonitors.front().get()) {
- const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
- g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µsNoOverlay);
- } else {
- g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µs);
- }
+ g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp
index 56ce41a6..b56d0792 100644
--- a/src/events/Popups.cpp
+++ b/src/events/Popups.cpp
@@ -86,10 +86,11 @@ void Events::listener_newPopup(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
- PNEWPOPUP->popup = WLRPOPUP;
- PNEWPOPUP->lx = layersurface->position.x;
- PNEWPOPUP->ly = layersurface->position.y;
- PNEWPOPUP->monitor = PMONITOR;
+ PNEWPOPUP->popup = WLRPOPUP;
+ PNEWPOPUP->lx = layersurface->position.x;
+ PNEWPOPUP->ly = layersurface->position.y;
+ PNEWPOPUP->monitor = PMONITOR;
+ PNEWPOPUP->parentLS = layersurface;
createNewPopup(WLRPOPUP, PNEWPOPUP);
}
@@ -148,6 +149,11 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
Debug::log(LOG, "New XDG Popup mapped at %d %d", (int)PPOPUP->lx, (int)PPOPUP->ly);
+ if (PPOPUP->parentWindow)
+ PPOPUP->parentWindow->m_lPopupSurfaces.emplace_back(PPOPUP->popup->base->surface);
+ else if (PPOPUP->parentLS)
+ PPOPUP->parentLS->popupSurfaces.emplace_back(PPOPUP->popup->base->surface);
+
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
int lx = 0, ly = 0;
@@ -177,6 +183,11 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
+ if (PPOPUP->parentWindow)
+ std::erase(PPOPUP->parentWindow->m_lPopupSurfaces, PPOPUP->popup->base->surface);
+ else if (PPOPUP->parentLS)
+ std::erase(PPOPUP->parentLS->popupSurfaces, PPOPUP->popup->base->surface);
+
PPOPUP->pSurfaceTree = nullptr;
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index 5b96d279..4a0d3dbe 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -67,13 +67,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
// Foreign Toplevel
PWINDOW->createToplevelHandle();
- // checks if the window wants borders and sets the appriopriate flag
+ // checks if the window wants borders and sets the appropriate flag
g_pXWaylandManager->checkBorders(PWINDOW);
// registers the animated vars and stuff
PWINDOW->onMap();
- const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(PWINDOW);
+ const auto PWINDOWSURFACE = PWINDOW->m_pWLSurface.wlr();
if (!PWINDOWSURFACE) {
g_pCompositor->removeWindowFromVectorSafe(PWINDOW);
@@ -125,11 +125,21 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (MONITORSTR == "unset") {
PWINDOW->m_iMonitorID = PMONITOR->ID;
} else {
- const long int MONITOR = std::stoi(MONITORSTR);
- if (!g_pCompositor->getMonitorFromID(MONITOR))
- PWINDOW->m_iMonitorID = 0;
- else
- PWINDOW->m_iMonitorID = MONITOR;
+ if (isNumber(MONITORSTR)) {
+ const long int MONITOR = std::stoi(MONITORSTR);
+ if (!g_pCompositor->getMonitorFromID(MONITOR))
+ PWINDOW->m_iMonitorID = 0;
+ else
+ PWINDOW->m_iMonitorID = MONITOR;
+ } else {
+ const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
+ if (PMONITOR)
+ PWINDOW->m_iMonitorID = PMONITOR->ID;
+ else {
+ Debug::log(ERR, "No monitor in monitor %s rule", MONITORSTR.c_str());
+ continue;
+ }
+ }
}
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
@@ -482,7 +492,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus();
- PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW);
+ PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(PWINDOW->m_pWLSurface.wlr(), addViewCoords, PWINDOW, PWINDOW);
PWINDOW->updateToplevel();
@@ -565,7 +575,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
- g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(g_pXWaylandManager->getWindowSurface(PWINDOW), PMONITOR->scale);
+ g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
}
void Events::listener_unmapWindow(void* owner, void* data) {
@@ -573,6 +583,12 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
+ if (!PWINDOW->m_pWLSurface.exists() || !PWINDOW->m_bIsMapped) {
+ Debug::log(WARN, "Window %x unmapped without being mapped??", PWINDOW);
+ PWINDOW->m_bFadingOut = false;
+ return;
+ }
+
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
@@ -665,8 +681,10 @@ void Events::listener_unmapWindow(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
// do the animation thing
- PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
- PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
+ if (PMONITOR) {
+ PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
+ PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
+ }
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
@@ -696,7 +714,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->updateSurfaceOutputs();
- g_pHyprRenderer->damageSurface(g_pXWaylandManager->getWindowSurface(PWINDOW), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y);
+ g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y);
// Debug::log(LOG, "Window %x committed", PWINDOW); // SPAM!
}
@@ -790,7 +808,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
}
}
- // Disable the maximize flag when we recieve a de-fullscreen request
+ // Disable the maximize flag when we receive a de-fullscreen request
PWINDOW->m_bWasMaximized &= REQUESTED->fullscreen;
requestedFullState = REQUESTED->fullscreen;
@@ -995,7 +1013,6 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
PNEWWINDOW->m_pX11Parent = g_pCompositor->getX11Parent(PNEWWINDOW);
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XWSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XWayland Window");
- PNEWWINDOW->hyprListener_unmapWindow.initCallback(&XWSURFACE->events.unmap, &Events::listener_unmapWindow, PNEWWINDOW, "XWayland Window");
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XWSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XWayland Window");
PNEWWINDOW->hyprListener_setOverrideRedirect.initCallback(&XWSURFACE->events.set_override_redirect, &Events::listener_setOverrideRedirect, PNEWWINDOW, "XWayland Window");
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window");
@@ -1014,7 +1031,6 @@ void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
- PNEWWINDOW->hyprListener_unmapWindow.initCallback(&XDGSURFACE->events.unmap, &Events::listener_unmapWindow, PNEWWINDOW, "XDG Window");
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XDG Window");
}
diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp
index de385e9b..ecbfa308 100644
--- a/src/helpers/MiscFunctions.cpp
+++ b/src/helpers/MiscFunctions.cpp
@@ -6,11 +6,11 @@
#include <iomanip>
#include <sstream>
-#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h>
#if defined(__DragonFly__)
#include <sys/kinfo.h> // struct kinfo_proc
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__FreeBSD__)
#include <sys/user.h> // struct kinfo_proc
#endif
@@ -23,7 +23,7 @@
#endif
#if defined(__DragonFly__)
#define KP_PPID(kp) kp.kp_ppid
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__FreeBSD__)
#define KP_PPID(kp) kp.ki_ppid
#else
#define KP_PPID(kp) kp.p_ppid
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 621b2889..d8bae3a8 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -2,6 +2,12 @@
#include "../Compositor.hpp"
+int ratHandler(void* data) {
+ g_pHyprRenderer->renderMonitor((CMonitor*)data);
+
+ return 1;
+}
+
void CMonitor::onConnect(bool noRule) {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
@@ -156,10 +162,17 @@ void CMonitor::onConnect(bool noRule) {
if (!found)
g_pCompositor->setActiveMonitor(this);
+
+ renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
}
void CMonitor::onDisconnect() {
+ if (renderTimer) {
+ wl_event_source_remove(renderTimer);
+ renderTimer = nullptr;
+ }
+
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
return;
@@ -214,6 +227,8 @@ void CMonitor::onDisconnect() {
g_pCompositor->m_bUnsafeState = true;
+ std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
+
return;
}
@@ -295,13 +310,15 @@ int CMonitor::findAvailableDefaultWS() {
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
// Workspace
std::string newDefaultWorkspaceName = "";
- int64_t WORKSPACEID = monitorRule.defaultWorkspace == "" ? findAvailableDefaultWS() : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
+ int64_t WORKSPACEID = g_pConfigManager->getDefaultWorkspaceFor(szName).empty() ?
+ findAvailableDefaultWS() :
+ getWorkspaceIDFromString(g_pConfigManager->getDefaultWorkspaceFor(szName), newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
- Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
+ Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", g_pConfigManager->getDefaultWorkspaceFor(szName).c_str());
}
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 9ad6d917..0707d79f 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -6,6 +6,7 @@
#include <vector>
#include <array>
#include <memory>
+#include "Timer.hpp"
struct SMonitorRule;
@@ -45,6 +46,10 @@ class CMonitor {
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
+ wl_event_source* renderTimer = nullptr; // for RAT
+ bool RATScheduled = false;
+ CTimer lastPresentationTimer;
+
// mirroring
CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors;
diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp
index aa9411f0..43ff3be7 100644
--- a/src/helpers/SubsurfaceTree.cpp
+++ b/src/helpers/SubsurfaceTree.cpp
@@ -3,8 +3,8 @@
#include "../Compositor.hpp"
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
- *lx += node->pSurface->current.dx;
- *ly += node->pSurface->current.dy;
+ *lx += node->pSurface->wlr()->current.dx;
+ *ly += node->pSurface->wlr()->current.dy;
if (node->offsetfn) {
// This is the root node
@@ -23,7 +23,13 @@ void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
SSurfaceTreeNode* createTree(wlr_surface* pSurface, CWindow* pWindow) {
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.emplace_back();
- PNODE->pSurface = pSurface;
+ if (pSurface->data)
+ PNODE->pSurface = (CWLSurface*)pSurface->data;
+ else {
+ PNODE->pInternalSurface = pSurface;
+ PNODE->pSurface = &PNODE->pInternalSurface;
+ }
+
PNODE->pWindowOwner = pWindow;
PNODE->hyprListener_newSubsurface.initCallback(&pSurface->events.new_subsurface, &Events::listener_newSubsurfaceNode, PNODE, "SurfaceTreeNode");
@@ -88,9 +94,9 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
pNode->hyprListener_newSubsurface.removeCallback();
// damage
- if (pNode->pSurface) {
+ if (pNode->pSurface && pNode->pSurface->exists()) {
wlr_box extents = {};
- wlr_surface_get_extends(pNode->pSurface, &extents);
+ wlr_surface_get_extends(pNode->pSurface->wlr(), &extents);
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
@@ -182,13 +188,14 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
std::find_if(SubsurfaceTree::surfaceTreeNodes.begin(), SubsurfaceTree::surfaceTreeNodes.end(), [&](const SSurfaceTreeNode& other) { return &other == PNODE; });
if (IT != SubsurfaceTree::surfaceTreeNodes.end()) {
- int lx = 0, ly = 0;
- addSurfaceGlobalOffset(PNODE, &lx, &ly);
+ if (PNODE->pSurface && PNODE->pSurface->exists()) {
+ int lx = 0, ly = 0;
+ addSurfaceGlobalOffset(PNODE, &lx, &ly);
+
+ wlr_box extents = {lx, ly, 0, 0};
- wlr_box extents = {lx, ly, 0, 0};
- if (PNODE->pSurface) {
- extents.width = PNODE->pSurface->current.width;
- extents.height = PNODE->pSurface->current.height;
+ extents.width = PNODE->pSurface->wlr()->current.width;
+ extents.height = PNODE->pSurface->wlr()->current.height;
g_pHyprRenderer->damageBox(&extents);
}
@@ -228,7 +235,8 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
}
}
- g_pHyprRenderer->damageSurface(pNode->pSurface, lx, ly);
+ if (pNode->pSurface && pNode->pSurface->exists())
+ g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly);
}
void Events::listener_destroySubsurface(void* owner, void* data) {
diff --git a/src/helpers/SubsurfaceTree.hpp b/src/helpers/SubsurfaceTree.hpp
index 36105d2c..7a0968fd 100644
--- a/src/helpers/SubsurfaceTree.hpp
+++ b/src/helpers/SubsurfaceTree.hpp
@@ -2,6 +2,7 @@
#include "../defines.hpp"
#include <list>
+#include "WLSurface.hpp"
struct SSubsurface;
class CWindow;
@@ -9,7 +10,8 @@ class CWindow;
typedef void (*applyGlobalOffsetFn)(void*, int*, int*);
struct SSurfaceTreeNode {
- wlr_surface* pSurface = nullptr;
+ CWLSurface* pSurface = nullptr; // actual surface
+ CWLSurface pInternalSurface; // not present for head nodes to not dupe wlr_surface ownership
DYNLISTENER(newSubsurface);
DYNLISTENER(commit);
diff --git a/src/helpers/WLClasses.cpp b/src/helpers/WLClasses.cpp
index 9b6926e2..29e10a54 100644
--- a/src/helpers/WLClasses.cpp
+++ b/src/helpers/WLClasses.cpp
@@ -5,4 +5,19 @@ SLayerSurface::SLayerSurface() {
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this;
alpha.registerVar();
+}
+
+void SLayerSurface::applyRules() {
+ noAnimations = false;
+ forceBlur = false;
+ ignoreZero = false;
+
+ for (auto& rule : g_pConfigManager->getMatchingRules(this)) {
+ if (rule.rule == "noanim")
+ noAnimations = true;
+ else if (rule.rule == "blur")
+ forceBlur = true;
+ else if (rule.rule == "ignorezero")
+ ignoreZero = true;
+ }
} \ No newline at end of file
diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp
index 8a96c6ff..0e5138b3 100644
--- a/src/helpers/WLClasses.hpp
+++ b/src/helpers/WLClasses.hpp
@@ -6,6 +6,7 @@
#include "../Window.hpp"
#include "SubsurfaceTree.hpp"
#include "AnimatedVariable.hpp"
+#include "WLSurface.hpp"
struct SLayerRule {
std::string targetNamespace = "";
@@ -15,9 +16,14 @@ struct SLayerRule {
struct SLayerSurface {
SLayerSurface();
+ void applyRules();
+
wlr_layer_surface_v1* layerSurface;
wl_list link;
+ CWLSurface surface;
+ std::list<CWLSurface> popupSurfaces;
+
DYNLISTENER(destroyLayerSurface);
DYNLISTENER(mapLayerSurface);
DYNLISTENER(unmapLayerSurface);
@@ -40,7 +46,8 @@ struct SLayerSurface {
bool noProcess = false;
bool noAnimations = false;
- bool forceBlur = false;
+ bool forceBlur = false;
+ bool ignoreZero = false;
// For the list lookup
bool operator==(const SLayerSurface& rhs) const {
@@ -169,6 +176,7 @@ class CMonitor;
struct SXDGPopup {
CWindow* parentWindow = nullptr;
+ SLayerSurface* parentLS = nullptr;
SXDGPopup* parentPopup = nullptr;
wlr_xdg_popup* popup = nullptr;
CMonitor* monitor = nullptr;
@@ -358,6 +366,8 @@ struct STouchDevice {
struct SSwitchDevice {
wlr_input_device* pWlrDevice = nullptr;
+ int status = -1; // uninitialized
+
DYNLISTENER(destroy);
DYNLISTENER(toggle);
diff --git a/src/helpers/WLSurface.cpp b/src/helpers/WLSurface.cpp
new file mode 100644
index 00000000..4bb35135
--- /dev/null
+++ b/src/helpers/WLSurface.cpp
@@ -0,0 +1,57 @@
+#include "WLSurface.hpp"
+#include "../Compositor.hpp"
+
+CWLSurface::CWLSurface(wlr_surface* pSurface) {
+ m_pWLRSurface = pSurface;
+ init();
+}
+
+void CWLSurface::assign(wlr_surface* pSurface) {
+ m_pWLRSurface = pSurface;
+ init();
+}
+
+void CWLSurface::unassign() {
+ destroy();
+}
+
+CWLSurface::~CWLSurface() {
+ destroy();
+}
+
+bool CWLSurface::exists() const {
+ return m_pWLRSurface;
+}
+
+wlr_surface* CWLSurface::wlr() const {
+ return m_pWLRSurface;
+}
+
+void CWLSurface::destroy() {
+ if (!m_pWLRSurface)
+ return;
+
+ hyprListener_destroy.removeCallback();
+ m_pWLRSurface->data = nullptr;
+
+ if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
+ g_pCompositor->m_pLastFocus = nullptr;
+
+ m_pWLRSurface = nullptr;
+
+ Debug::log(LOG, "CWLSurface %x called destroy()", this);
+}
+
+void CWLSurface::init() {
+ if (!m_pWLRSurface)
+ return;
+
+ RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
+
+ m_pWLRSurface->data = this;
+
+ hyprListener_destroy.initCallback(
+ &m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
+
+ Debug::log(LOG, "CWLSurface %x called init()", this);
+} \ No newline at end of file
diff --git a/src/helpers/WLSurface.hpp b/src/helpers/WLSurface.hpp
new file mode 100644
index 00000000..e3325f99
--- /dev/null
+++ b/src/helpers/WLSurface.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "../defines.hpp"
+
+class CWLSurface {
+ public:
+ CWLSurface() = default;
+ CWLSurface(wlr_surface* pSurface);
+ ~CWLSurface();
+
+ void assign(wlr_surface* pSurface);
+ void unassign();
+
+ CWLSurface(const CWLSurface&) = delete;
+ CWLSurface(CWLSurface&&) = delete;
+ CWLSurface& operator=(const CWLSurface&) = delete;
+ CWLSurface& operator=(CWLSurface&&) = delete;
+
+ wlr_surface* wlr() const;
+ bool exists() const;
+
+ CWLSurface& operator=(wlr_surface* pSurface) {
+ destroy();
+ m_pWLRSurface = pSurface;
+ init();
+
+ return *this;
+ }
+
+ bool operator==(const CWLSurface& other) const {
+ return other.wlr() == wlr();
+ }
+
+ bool operator==(const wlr_surface* other) const {
+ return other == wlr();
+ }
+
+ explicit operator bool() const {
+ return exists();
+ }
+
+ private:
+ wlr_surface* m_pWLRSurface = nullptr;
+
+ void destroy();
+ void init();
+
+ DYNLISTENER(destroy);
+}; \ No newline at end of file
diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp
index 37a7bf81..e05e9a7a 100644
--- a/src/layout/DwindleLayout.cpp
+++ b/src/layout/DwindleLayout.cpp
@@ -462,17 +462,14 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
}
}
- // Ignore any recalc events if we have a fullscreen window, but process if fullscreen mode 2
if (PWORKSPACE->m_bHasFullscreenWindow) {
- if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL)
- return;
-
// massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
- if (!PFULLWINDOW) { // ????
- PWORKSPACE->m_bHasFullscreenWindow = false;
- } else {
+ if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
+ PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
+ PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
+ } else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -482,9 +479,9 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
PFULLWINDOW->m_vSize = fakeNode.size;
applyNodeDataToWindow(&fakeNode);
-
- return;
}
+
+ return;
}
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace);
diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp
index 37f8a9b0..c9260f19 100644
--- a/src/layout/IHyprLayout.cpp
+++ b/src/layout/IHyprLayout.cpp
@@ -81,7 +81,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
}
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
- const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
+ const auto PWINDOWSURFACE = pWindow->m_pWLSurface.wlr();
pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height);
if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 &&
@@ -343,6 +343,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (PMONITOR && !SPECIAL) {
DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID;
DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace);
+ DRAGGINGWINDOW->updateGroupOutputs();
DRAGGINGWINDOW->updateToplevel();
}
@@ -374,6 +375,7 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
+ pWindow->updateGroupOutputs();
// save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.goalv();
diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp
index 929e8271..eebe787e 100644
--- a/src/layout/MasterLayout.cpp
+++ b/src/layout/MasterLayout.cpp
@@ -203,21 +203,23 @@ void CHyprMasterLayout::recalculateMonitor(const int& monid) {
}
if (PWORKSPACE->m_bHasFullscreenWindow) {
- if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL)
- return;
-
// massive hack from the fullscreen func
- const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
+ const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
- SMasterNodeData fakeNode;
- fakeNode.pWindow = PFULLWINDOW;
- fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
- fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
- fakeNode.workspaceID = PWORKSPACE->m_iID;
- PFULLWINDOW->m_vPosition = fakeNode.position;
- PFULLWINDOW->m_vSize = fakeNode.size;
+ if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
+ PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
+ PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
+ } else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
+ SMasterNodeData fakeNode;
+ fakeNode.pWindow = PFULLWINDOW;
+ fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
+ fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
+ fakeNode.workspaceID = PWORKSPACE->m_iID;
+ PFULLWINDOW->m_vPosition = fakeNode.position;
+ PFULLWINDOW->m_vSize = fakeNode.size;
- applyNodeDataToWindow(&fakeNode);
+ applyNodeDataToWindow(&fakeNode);
+ }
return;
}
@@ -258,7 +260,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (getNodesOnWorkspace(PWORKSPACE->m_iID) < 2 && !centerMasterWindow) {
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
PMASTERNODE->size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x,
- PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
+ PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
applyNodeDataToWindow(PMASTERNODE);
return;
} else if (orientation == ORIENTATION_LEFT || orientation == ORIENTATION_RIGHT) {
diff --git a/src/main.cpp b/src/main.cpp
index 50a69937..669ece50 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -76,10 +76,6 @@ int main(int argc, char** argv) {
if (g_pCompositor->m_sWLDisplay)
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
- // kill all clients
- for (auto& c : g_pCompositor->m_dProcessPIDsOnShutdown)
- kill(c, SIGKILL);
-
if (g_pCompositor->m_sWLDisplay)
wl_display_destroy(g_pCompositor->m_sWLDisplay);
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index 3b0a6678..8730fa45 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -385,7 +385,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
// Should never happen, as we check in the ConfigManager, but oh well
if (DISPATCHER == m_mDispatchers.end()) {
- Debug::log(ERR, "Inavlid handler in a keybind! (handler %s does not exist)", k.handler.c_str());
+ Debug::log(ERR, "Invalid handler in a keybind! (handler %s does not exist)", k.handler.c_str());
} else {
// call the dispatcher
Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %s, %d)", modmask, key.c_str(), keysym);
@@ -469,11 +469,11 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
// vtnr is bugged for some reason.
unsigned int ttynum = 0;
-#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(VT_GETSTATE)
struct vt_stat st;
if (!ioctl(0, VT_GETSTATE, &st))
ttynum = st.v_active;
-#elif defined(__DragonFly__) || defined(__FreeBSD__)
+#elif defined(VT_GETACTIVE)
int vt;
if (!ioctl(0, VT_GETACTIVE, &vt))
ttynum = vt;
@@ -838,7 +838,7 @@ void CKeybindManager::changeworkspace(std::string args) {
if (anotherMonitor)
g_pCompositor->warpCursorTo(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f);
- g_pCompositor->focusWindow(PWINDOW, g_pXWaylandManager->getWindowSurface(PWINDOW));
+ g_pCompositor->focusWindow(PWINDOW, PWINDOW->m_pWLSurface.wlr());
if (g_pCompositor->cursorOnReservedArea()) // fix focus on bars etc
g_pInputManager->refocus();
@@ -986,8 +986,9 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
PWORKSPACE = g_pCompositor->createNewWorkspace(WORKSPACEID, OLDWORKSPACE->m_iMonitorID, workspaceName);
}
- PWINDOW->moveToWorkspace(PWORKSPACE->m_iID);
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
+ PWINDOW->moveToWorkspace(PWORKSPACE->m_iID);
+ PWINDOW->updateGroupOutputs();
if (PWORKSPACE->m_bHasFullscreenWindow) {
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_FULL);
@@ -1149,7 +1150,8 @@ void CKeybindManager::moveFocusTo(std::string args) {
}
};
- const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
+ const auto PWINDOWTOCHANGETO = PLASTWINDOW->m_bIsFullscreen ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, arg == 'u' || arg == 't' || arg == 'r') :
+ g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
if (PWINDOWTOCHANGETO) {
switchToWindow(PWINDOWTOCHANGETO);
@@ -1273,6 +1275,8 @@ void CKeybindManager::moveActiveTo(std::string args) {
return;
g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO);
+
+ g_pCompositor->warpCursorTo(PLASTWINDOW->m_vRealPosition.vec() + PLASTWINDOW->m_vRealSize.vec() / 2.0);
}
void CKeybindManager::toggleGroup(std::string args) {
@@ -1394,7 +1398,18 @@ void CKeybindManager::focusMonitor(std::string arg) {
if (!PMONITOR || PMONITOR == g_pCompositor->m_pLastMonitor)
return;
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
+
changeworkspace("[internal]" + std::to_string(PMONITOR->activeWorkspace));
+
+ // remember last workspace (internal calls don't preserve it)
+
+ const auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
+ if (PNEWWORKSPACE == PWORKSPACE)
+ return;
+
+ PNEWWORKSPACE->m_sPrevWorkspace.iID = PWORKSPACE->m_iID;
+ PNEWWORKSPACE->m_sPrevWorkspace.name = PWORKSPACE->m_szName;
}
void CKeybindManager::moveCursorToCorner(std::string arg) {
@@ -1846,9 +1861,9 @@ void CKeybindManager::pass(std::string regexp) {
// pass all mf shit
if (!XWTOXW) {
if (g_pKeybindManager->m_uLastCode != 0)
- wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, g_pXWaylandManager->getWindowSurface(PWINDOW), KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers);
+ wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers);
else
- wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, g_pXWaylandManager->getWindowSurface(PWINDOW), 1, 1);
+ wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), 1, 1);
}
wlr_keyboard_modifiers kbmods = {g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0};
@@ -1894,7 +1909,7 @@ void CKeybindManager::pass(std::string regexp) {
if (g_pKeybindManager->m_uLastCode != 0)
wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, PLASTSRF, KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers);
else
- wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, g_pXWaylandManager->getWindowSurface(PWINDOW), SL.x, SL.y);
+ wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), SL.x, SL.y);
}
void CKeybindManager::layoutmsg(std::string msg) {
@@ -1909,7 +1924,7 @@ void CKeybindManager::toggleOpaque(std::string unused) {
return;
PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque;
- PWINDOW->m_sAdditionalConfigData.forceOpaqueOverriden = true;
+ PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden = true;
g_pHyprRenderer->damageWindow(PWINDOW);
}
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 55d960a1..bf9286a8 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -58,6 +58,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto* const PRESIZECURSORICON = &g_pConfigManager->getConfigValuePtr("general:hover_icon_on_border")->intValue;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
+ const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE;
+
m_pFoundSurfaceToFocus = nullptr;
m_pFoundLSToFocus = nullptr;
m_pFoundWindowToFocus = nullptr;
@@ -130,7 +132,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
}
if (CONSTRAINTWINDOW->m_bIsX11) {
- foundSurface = g_pXWaylandManager->getWindowSurface(CONSTRAINTWINDOW);
+ foundSurface = CONSTRAINTWINDOW->m_pWLSurface.wlr();
surfacePos = CONSTRAINTWINDOW->m_vRealPosition.vec();
} else {
g_pCompositor->vectorWindowToSurface(mouseCoords, CONSTRAINTWINDOW, surfaceCoords);
@@ -143,6 +145,33 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// update stuff
updateDragIcon();
+ if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus) {
+ if (m_bLastFocusOnLS) {
+ foundSurface = g_pCompositor->m_pLastFocus;
+ pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface);
+ if (pFoundLayerSurface) {
+ surfacePos = g_pCompositor->getLayerSurfaceFromSurface(foundSurface)->position;
+ m_bFocusHeldByButtons = true;
+ m_bRefocusHeldByButtons = refocus;
+ } else {
+ // ?
+ foundSurface = nullptr;
+ pFoundLayerSurface = nullptr;
+ }
+ } else if (g_pCompositor->m_pLastWindow) {
+ foundSurface = g_pCompositor->m_pLastFocus;
+ pFoundWindow = g_pCompositor->m_pLastWindow;
+
+ if (!g_pCompositor->m_pLastWindow->m_bIsX11)
+ foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, g_pCompositor->m_pLastWindow, surfaceCoords);
+ else
+ surfacePos = g_pCompositor->m_pLastWindow->m_vRealPosition.vec();
+
+ m_bFocusHeldByButtons = true;
+ m_bRefocusHeldByButtons = refocus;
+ }
+ }
+
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus)) {
@@ -198,7 +227,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
surfacePos = Vector2D(-1337, -1337);
} else {
- foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
+ foundSurface = pFoundWindow->m_pWLSurface.wlr();
surfacePos = pFoundWindow->m_vRealPosition.vec();
}
}
@@ -232,7 +261,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
} else {
- foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
+ foundSurface = pFoundWindow->m_pWLSurface.wlr();
surfacePos = pFoundWindow->m_vRealPosition.vec();
}
}
@@ -309,8 +338,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
setCursorIconOnBorder(pFoundWindow);
}
- // if we're on an input deco, reset cursor. Don't on overriden
- // if (!m_bCursorImageOverriden) {
+ // if we're on an input deco, reset cursor. Don't on overridden
+ // if (!m_bCursorImageOverridden) {
// if (!VECINRECT(m_vLastCursorPosFloored, pFoundWindow->m_vRealPosition.vec().x, pFoundWindow->m_vRealPosition.vec().y,
// pFoundWindow->m_vRealPosition.vec().x + pFoundWindow->m_vRealSize.vec().x, pFoundWindow->m_vRealPosition.vec().y + pFoundWindow->m_vRealSize.vec().y)) {
// wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
@@ -321,14 +350,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// }
// }
- if (*PFOLLOWMOUSE != 1 && !refocus) {
+ if (FOLLOWMOUSE != 1 && !refocus) {
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow &&
((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) {
// enter if change floating style
- if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
+ if (FOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
- } else if (*PFOLLOWMOUSE == 2 || *PFOLLOWMOUSE == 3) {
+ } else if (FOLLOWMOUSE == 2 || FOLLOWMOUSE == 3) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
@@ -339,17 +368,13 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
}
}
- if (*PFOLLOWONDND && m_sDrag.dragIcon) {
- wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
- }
-
- if (*PFOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
+ if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
m_bLastFocusOnLS = false;
return; // don't enter any new surfaces
} else {
- if ((*PFOLLOWMOUSE != 3 && allowKeyboardRefocus) || refocus)
+ if ((FOLLOWMOUSE != 3 && allowKeyboardRefocus) || refocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
}
@@ -360,7 +385,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
unsetCursorImage();
}
- if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3 && allowKeyboardRefocus) {
+ if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.keyboard_interactive || pFoundLayerSurface->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) &&
+ FOLLOWMOUSE != 3 && allowKeyboardRefocus) {
g_pCompositor->focusSurface(foundSurface);
}
@@ -392,6 +418,16 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
case CLICKMODE_KILL: processMouseDownKill(e); break;
default: break;
}
+
+ if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e->state == WLR_BUTTON_RELEASED) {
+ if (m_bRefocusHeldByButtons)
+ refocus();
+ else
+ simulateMouseMovement();
+
+ m_bFocusHeldByButtons = false;
+ m_bRefocusHeldByButtons = false;
+ }
}
void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) {
@@ -404,7 +440,7 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
}
- if (m_bCursorImageOverriden) {
+ if (m_bCursorImageOverridden) {
return;
}
@@ -964,7 +1000,7 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
return;
static auto* const PDPMS = &g_pConfigManager->getConfigValuePtr("misc:key_press_enables_dpms")->intValue;
- if (*PDPMS && g_pCompositor->m_bDPMSStateON) {
+ if (*PDPMS && !g_pCompositor->m_bDPMSStateON) {
// enable dpms
g_pKeybindManager->dpms("on");
}
@@ -1127,7 +1163,7 @@ void CInputManager::unconstrainMouse() {
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (CONSTRAINTWINDOW) {
- g_pXWaylandManager->activateSurface(g_pXWaylandManager->getWindowSurface(CONSTRAINTWINDOW), false);
+ g_pXWaylandManager->activateSurface(CONSTRAINTWINDOW->m_pWLSurface.wlr(), false);
}
wlr_pointer_constraint_v1_send_deactivated(g_pCompositor->m_sSeat.mouse->currentConstraint);
@@ -1307,13 +1343,16 @@ void CInputManager::newSwitch(wlr_input_device* pDevice) {
[&](void* owner, void* data) {
const auto PDEVICE = (SSwitchDevice*)owner;
const auto NAME = std::string(PDEVICE->pWlrDevice->name);
+ const auto E = (wlr_switch_toggle_event*)data;
+
+ if (PDEVICE->status != -1 && PDEVICE->status == E->switch_state)
+ return;
Debug::log(LOG, "Switch %s fired, triggering binds.", NAME.c_str());
g_pKeybindManager->onSwitchEvent(NAME);
- const auto event_data = (wlr_switch_toggle_event*)data;
- switch (event_data->switch_state) {
+ switch (E->switch_state) {
case WLR_SWITCH_STATE_ON:
Debug::log(LOG, "Switch %s turn on, triggering binds.", NAME.c_str());
g_pKeybindManager->onSwitchOnEvent(NAME);
@@ -1323,6 +1362,8 @@ void CInputManager::newSwitch(wlr_input_device* pDevice) {
g_pKeybindManager->onSwitchOffEvent(NAME);
break;
}
+
+ PDEVICE->status = E->switch_state;
},
PNEWDEV, "SwitchDevice");
}
@@ -1333,14 +1374,14 @@ void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
void CInputManager::setCursorImageUntilUnset(std::string name) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, name.c_str(), g_pCompositor->m_sWLRCursor);
- m_bCursorImageOverriden = true;
+ m_bCursorImageOverridden = true;
}
void CInputManager::unsetCursorImage() {
- if (!m_bCursorImageOverriden)
+ if (!m_bCursorImageOverridden)
return;
- m_bCursorImageOverriden = false;
+ m_bCursorImageOverridden = false;
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
}
diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp
index fd5edf12..a98ad497 100644
--- a/src/managers/input/InputManager.hpp
+++ b/src/managers/input/InputManager.hpp
@@ -7,18 +7,21 @@
#include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp"
-enum eClickBehaviorMode {
+enum eClickBehaviorMode
+{
CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL
};
-enum eMouseBindMode {
+enum eMouseBindMode
+{
MBIND_INVALID = -1,
MBIND_MOVE = 0,
MBIND_RESIZE
};
-enum eBorderIconDirection {
+enum eBorderIconDirection
+{
BORDERICON_NONE,
BORDERICON_UP,
BORDERICON_DOWN,
@@ -154,8 +157,6 @@ class CInputManager {
// for shared mods
uint32_t accumulateModsFromAllKBs();
- CWindow* m_pFollowOnDnDBegin = nullptr;
-
// for virtual keyboards: whether we should respect them as normal ones
bool shouldIgnoreVirtualKeyboard(SKeyboard*);
@@ -175,8 +176,8 @@ class CInputManager {
bool m_bLastInputTouch = false;
private:
- bool m_bCursorImageOverriden = false;
- eBorderIconDirection m_eBorderIconDirection = BORDERICON_NONE;
+ bool m_bCursorImageOverridden = false;
+ eBorderIconDirection m_eBorderIconDirection = BORDERICON_NONE;
// for click behavior override
eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT;
@@ -201,6 +202,10 @@ class CInputManager {
SLayerSurface* m_pFoundLSToFocus = nullptr;
CWindow* m_pFoundWindowToFocus = nullptr;
+ // for holding focus on buttons held
+ bool m_bFocusHeldByButtons = false;
+ bool m_bRefocusHeldByButtons = false;
+
// for releasing mouse buttons
std::list<uint32_t> m_lCurrentlyHeldButtons;
diff --git a/src/meson.build b/src/meson.build
index 7b658d31..8430f597 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -3,6 +3,7 @@ src = globber.stdout().strip().split('\n')
executable('Hyprland', src,
cpp_args: ['-DWLR_USE_UNSTABLE'],
+ link_args: '-rdynamic',
dependencies: [
server_protos,
dependency('wayland-server'),
@@ -20,7 +21,9 @@ executable('Hyprland', src,
dependency('pixman-1'),
dependency('gl', 'opengl'),
- dependency('threads')
+ dependency('threads'),
+ dependency('pango'),
+ dependency('pangocairo')
],
install : true
)
diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp
index 8c816546..f26c7b9d 100644
--- a/src/plugins/PluginAPI.cpp
+++ b/src/plugins/PluginAPI.cpp
@@ -3,6 +3,12 @@
#include "../debug/HyprCtl.hpp"
#include <dlfcn.h>
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#include <sys/sysctl.h>
+#endif
+
+#include <sstream>
+
APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
@@ -193,3 +199,124 @@ APICALL bool HyprlandAPI::removeDispatcher(HANDLE handle, const std::string& nam
return true;
}
+
+APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::string, std::any>& data) {
+ auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
+
+ if (!PLUGIN)
+ return false;
+
+ try {
+ auto iterator = data.find("text");
+ if (iterator == data.end())
+ return false;
+
+ // mandatory
+ std::string text;
+ try {
+ text = std::any_cast<std::string>(iterator->second);
+ } catch (std::exception& e) {
+ // attempt const char*
+ text = std::any_cast<const char*>(iterator->second);
+ }
+
+ iterator = data.find("time");
+ if (iterator == data.end())
+ return false;
+
+ const auto TIME = std::any_cast<uint64_t>(iterator->second);
+
+ iterator = data.find("color");
+ if (iterator == data.end())
+ return false;
+
+ const auto COLOR = std::any_cast<CColor>(iterator->second);
+
+ // optional
+ eIcons icon = ICON_NONE;
+ iterator = data.find("icon");
+ if (iterator != data.end())
+ icon = std::any_cast<eIcons>(iterator->second);
+
+ g_pHyprNotificationOverlay->addNotification(text, COLOR, TIME, icon);
+
+ } catch (std::exception& e) {
+ // bad any_cast most likely, plugin error
+ return false;
+ }
+
+ return true;
+}
+
+APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE handle, const std::string& name) {
+ auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
+
+ if (!PLUGIN)
+ return std::vector<SFunctionMatch>{};
+
+#if defined(KERN_PROC_PATHNAME)
+ int mib[] = {
+ CTL_KERN,
+#if defined(__NetBSD__)
+ KERN_PROC_ARGS,
+ -1,
+ KERN_PROC_PATHNAME,
+#else
+ KERN_PROC,
+ KERN_PROC_PATHNAME,
+ -1,
+#endif
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+ char exe[PATH_MAX] = "";
+ size_t sz = sizeof(exe);
+ sysctl(mib, miblen, &exe, &sz, NULL, 0);
+ const auto FPATH = std::filesystem::canonical(exe);
+#elif defined(__OpenBSD__)
+ // Neither KERN_PROC_PATHNAME nor /proc are supported
+ const auto FPATH = std::filesystem::canonical("/usr/local/bin/Hyprland");
+#else
+ const auto FPATH = std::filesystem::canonical("/proc/self/exe");
+#endif
+
+#ifdef __clang__
+ const auto SYMBOLS = execAndGet(("llvm-nm -D -j " + FPATH.string()).c_str());
+ const auto SYMBOLSDEMANGLED = execAndGet(("llvm-nm -D -j --demangle " + FPATH.string()).c_str());
+#else
+ const auto SYMBOLS = execAndGet(("nm -D -j " + FPATH.string()).c_str());
+ const auto SYMBOLSDEMANGLED = execAndGet(("nm -D -j --demangle=auto " + FPATH.string()).c_str());
+#endif
+
+ auto demangledFromID = [&](size_t id) -> std::string {
+ size_t pos = 0;
+ size_t count = 0;
+ while (count < id) {
+ pos++;
+ pos = SYMBOLSDEMANGLED.find('\n', pos);
+ if (pos == std::string::npos)
+ return "";
+ count++;
+ }
+
+ return SYMBOLSDEMANGLED.substr(pos, SYMBOLSDEMANGLED.find('\n', pos + 1) - pos);
+ };
+
+ std::vector<SFunctionMatch> matches;
+
+ std::istringstream inStream(SYMBOLS);
+ std::string line;
+ int lineNo = 0;
+ while (std::getline(inStream, line)) {
+ if (line.contains(name)) {
+ void* address = dlsym(nullptr, line.c_str());
+
+ if (!address)
+ continue;
+
+ matches.push_back({address, line, demangledFromID(lineNo)});
+ }
+ lineNo++;
+ }
+
+ return matches;
+} \ No newline at end of file
diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp
index 756a5631..ca8b662f 100644
--- a/src/plugins/PluginAPI.hpp
+++ b/src/plugins/PluginAPI.hpp
@@ -19,6 +19,7 @@ See examples/examplePlugin for an example plugin
#include "../helpers/Color.hpp"
#include "HookSystem.hpp"
+#include "../SharedDefs.hpp"
#include <any>
#include <functional>
@@ -32,6 +33,12 @@ typedef struct {
std::string version;
} PLUGIN_DESCRIPTION_INFO;
+struct SFunctionMatch {
+ void* address = nullptr;
+ std::string signature;
+ std::string demangled;
+};
+
#define APICALL extern "C"
#define EXPORT __attribute__((visibility("default")))
#define REQUIRED
@@ -184,8 +191,10 @@ namespace HyprlandAPI {
This is useful for hooking private functions.
returns: function address, or nullptr on fail.
+
+ Deprecated because of findFunctionsByName.
*/
- APICALL void* getFunctionAddressFromSignature(HANDLE handle, const std::string& sig);
+ APICALL [[deprecated]] void* getFunctionAddressFromSignature(HANDLE handle, const std::string& sig);
/*
Adds a window decoration to a window
@@ -214,4 +223,28 @@ namespace HyprlandAPI {
returns: true on success. False otherwise.
*/
APICALL bool removeDispatcher(HANDLE handle, const std::string& name);
+
+ /*
+ Adds a notification.
+
+ data has to contain:
+ - text: std::string or const char*
+ - time: uint64_t
+ - color: CColor -> CColor(0) will apply the default color for the notification icon
+
+ data may contain:
+ - icon: eIcons
+
+ returns: true on success. False otherwise.
+ */
+ APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::string, std::any>& data);
+
+ /*
+ Returns a vector of found functions matching the provided name.
+
+ These addresses will not change, and should be made static. Lookups are slow.
+
+ Empty means either none found or handle was invalid
+ */
+ APICALL std::vector<SFunctionMatch> findFunctionsByName(HANDLE handle, const std::string& name);
}; \ No newline at end of file
diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp
index 12053a38..f42be1c5 100644
--- a/src/protocols/Screencopy.cpp
+++ b/src/protocols/Screencopy.cpp
@@ -348,8 +348,6 @@ void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) {
zwlr_screencopy_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
}
void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
- const auto PMONITOR = frame->pMonitor;
-
if (!frame->withDamage)
return;
diff --git a/src/protocols/ToplevelExportWlrFuncs.hpp b/src/protocols/ToplevelExportWlrFuncs.hpp
index bd34be2f..97bf96f8 100644
--- a/src/protocols/ToplevelExportWlrFuncs.hpp
+++ b/src/protocols/ToplevelExportWlrFuncs.hpp
@@ -171,13 +171,13 @@ static const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fm
return NULL;
}
-static uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
+/*static uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
switch (fmt) {
case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
default: return (uint32_t)fmt;
}
-}
+}*/
static enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
switch (fmt) {
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 5d26ff8f..8b5fb2ef 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -190,6 +190,7 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shRGBA.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
+ m_RenderData.pCurrentMonData->m_shRGBA.discardAlphaZero = glGetUniformLocation(prog, "discardAlphaZero");
m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius");
@@ -212,6 +213,7 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shRGBX.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
+ m_RenderData.pCurrentMonData->m_shRGBX.discardAlphaZero = glGetUniformLocation(prog, "discardAlphaZero");
m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius");
@@ -227,6 +229,7 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shEXT.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
+ m_RenderData.pCurrentMonData->m_shEXT.discardAlphaZero = glGetUniformLocation(prog, "discardAlphaZero");
m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius");
@@ -466,15 +469,15 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha
renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV);
}
-void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool allowCustomUV) {
+void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
- renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowCustomUV, true);
+ renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardActive, false, allowCustomUV, true);
scissor((wlr_box*)nullptr);
}
-void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool noAA,
+void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardActive, bool noAA,
bool allowCustomUV, bool allowDim) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
@@ -518,6 +521,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
}
}
+ if (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceRGBX)
+ shader = &m_RenderData.pCurrentMonData->m_shRGBX;
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_iTarget, tex.m_iTexID);
@@ -542,7 +548,14 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
if (!usingFinalShader) {
glUniform1f(shader->alpha, alpha);
- glUniform1i(shader->discardOpaque, (int)discardOpaque);
+
+ if (discardActive) {
+ glUniform1i(shader->discardOpaque, !!(m_RenderData.discardMode & DISCARD_OPAQUE));
+ glUniform1i(shader->discardAlphaZero, !!(m_RenderData.discardMode & DISCARD_ALPHAZERO));
+ } else {
+ glUniform1i(shader->discardOpaque, 0);
+ glUniform1i(shader->discardAlphaZero, 0);
+ }
}
wlr_box transformedBox;
@@ -560,7 +573,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glUniform1f(shader->radius, round);
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
- if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
+ if (allowDim && m_pCurrentWindow && *PDIMINACTIVE) {
glUniform1i(shader->applyTint, 1);
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
@@ -643,7 +656,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
pixman_region32_copy(&damage, originalDamage);
wlr_region_transform(&damage, &damage, wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x,
m_RenderData.pMonitor->vecTransformedSize.y);
- wlr_region_expand(&damage, &damage, pow(2, *PBLURPASSES) * *PBLURSIZE);
+ wlr_region_expand(&damage, &damage, *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES));
// helper
const auto PMIRRORFB = &m_RenderData.pCurrentMonData->mirrorFB;
@@ -764,7 +777,7 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
if (pWindow->m_sAdditionalConfigData.forceNoBlur)
return false;
- const auto PSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
+ const auto PSURFACE = pWindow->m_pWLSurface.wlr();
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const float A = pWindow->m_fAlpha.fl() * pWindow->m_fActiveInactiveAlpha.fl() * PWORKSPACE->m_fAlpha.fl();
@@ -865,7 +878,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
return;
if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) ||
- (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) {
+ (m_pCurrentWindow && (m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur || m_pCurrentWindow->m_sAdditionalConfigData.forceRGBX))) {
renderTexture(tex, pBox, a, round, false, true);
return;
}
@@ -1066,6 +1079,10 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CGradientValueData& grad,
void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFramebuffer) {
// we trust the window is valid.
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
+
+ if (!PMONITOR || !PMONITOR->output)
+ return;
+
wlr_output_attach_render(PMONITOR->output, nullptr);
// we need to "damage" the entire monitor
@@ -1121,6 +1138,10 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFra
void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
// we trust the window is valid.
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
+
+ if (!PMONITOR || !PMONITOR->output)
+ return;
+
wlr_output_attach_render(PMONITOR->output, nullptr);
// we need to "damage" the entire monitor
@@ -1181,6 +1202,10 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
// we trust the window is valid.
const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID);
+
+ if (!PMONITOR || !PMONITOR->output)
+ return;
+
wlr_output_attach_render(PMONITOR->output, nullptr);
// we need to "damage" the entire monitor
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 171efb35..028be4df 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -23,6 +23,12 @@ inline const float fullVerts[] = {
};
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
+enum eDiscardMode
+{
+ DISCARD_OPAQUE = 1,
+ DISCARD_ALPHAZERO = 1 << 1
+};
+
struct SMonitorRenderData {
CFramebuffer primaryFB;
CFramebuffer mirrorFB; // these are used for some effects,
@@ -64,6 +70,8 @@ struct SCurrentRenderData {
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
wlr_box clipBox = {};
+
+ uint32_t discardMode = DISCARD_OPAQUE;
};
class CGradientValueData;
@@ -78,7 +86,7 @@ class CHyprOpenGLImpl {
void renderRect(wlr_box*, const CColor&, int round = 0);
void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0);
void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0, bool allowCustomUV = false);
- void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowCustomUV = false);
+ void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false);
void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0);
void renderBorder(wlr_box*, const CGradientValueData&, int round, float a = 1.0);
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 528e2f2e..a8ba8b22 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -250,7 +250,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
if (ignoreAllGeometry)
decorate = false;
- renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
+ renderdata.surface = pWindow->m_pWLSurface.wlr();
renderdata.w = std::max(pWindow->m_vRealSize.vec().x, 5.0); // clamp the size to min 5,
renderdata.h = std::max(pWindow->m_vRealSize.vec().y, 5.0); // otherwise we'll have issues later with invalid boxes
renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding);
@@ -313,7 +313,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
for (auto& wd : pWindow->m_dWindowDecorations)
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha, offset);
- wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
+ wlr_surface_for_each_surface(pWindow->m_pWLSurface.wlr(), renderSurface, &renderdata);
if (renderdata.decorate && pWindow->m_sSpecialRenderData.border) {
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
@@ -376,7 +376,11 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
renderdata.w = pLayer->geometry.width;
renderdata.h = pLayer->geometry.height;
renderdata.blockBlurOptimization = pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM || pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
+
+ if (pLayer->ignoreZero)
+ g_pHyprOpenGL->m_RenderData.discardMode |= DISCARD_ALPHAZERO;
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
+ g_pHyprOpenGL->m_RenderData.discardMode &= ~DISCARD_ALPHAZERO;
renderdata.squishOversized = false; // don't squish popups
renderdata.dontRound = true;
@@ -566,9 +570,8 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
renderIMEPopup(&imep, PMONITOR, time);
}
- for (auto ls = PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].rbegin(); ls != PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].rend();
- ls++) {
- renderLayer(ls->get(), PMONITOR, time);
+ for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
+ renderLayer(ls.get(), PMONITOR, time);
}
renderDragIcon(PMONITOR, time);
@@ -706,7 +709,7 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
if (surfaceCount != 1)
return false;
- const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
+ const auto PSURFACE = PCANDIDATE->m_pWLSurface.wlr();
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
return false;
@@ -736,12 +739,251 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
return true;
}
+void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
+ static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
+ static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
+ static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
+
+ static auto* const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
+ static auto* const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("debug:damage_tracking")->intValue;
+ static auto* const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
+ static auto* const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
+ static auto* const PVFR = &g_pConfigManager->getConfigValuePtr("misc:vfr")->intValue;
+
+ static int damageBlinkCleanup = 0; // because double-buffered
+
+ if (!*PDAMAGEBLINK)
+ damageBlinkCleanup = 0;
+
+ startRender = std::chrono::high_resolution_clock::now();
+
+ if (*PDEBUGOVERLAY == 1) {
+ g_pDebugOverlay->frameData(pMonitor);
+ }
+
+ if (pMonitor->framesToSkip > 0) {
+ pMonitor->framesToSkip -= 1;
+
+ if (!pMonitor->noFrameSchedule)
+ g_pCompositor->scheduleFrameForMonitor(pMonitor);
+ else {
+ Debug::log(LOG, "NoFrameSchedule hit for %s.", pMonitor->szName.c_str());
+ }
+ g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
+
+ if (pMonitor->framesToSkip > 10)
+ pMonitor->framesToSkip = 0;
+ return;
+ }
+
+ // checks //
+ if (pMonitor->ID == m_pMostHzMonitor->ID ||
+ *PVFR == 1) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
+ g_pCompositor->sanityCheckWorkspaces();
+
+ g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
+
+ if (g_pConfigManager->m_bWantsMonitorReload)
+ g_pConfigManager->performMonitorReload();
+
+ ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts
+ }
+ // //
+
+ if (pMonitor->scheduledRecalc) {
+ pMonitor->scheduledRecalc = false;
+ g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
+ }
+
+ // Direct scanout first
+ if (!*PNODIRECTSCANOUT) {
+ if (attemptDirectScanout(pMonitor)) {
+ return;
+ } else if (m_pLastScanout) {
+ Debug::log(LOG, "Left a direct scanout.");
+ m_pLastScanout = nullptr;
+ }
+ }
+
+ EMIT_HOOK_EVENT("preRender", pMonitor);
+
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ // check the damage
+ pixman_region32_t damage;
+ bool hasChanged;
+ pixman_region32_init(&damage);
+
+ if (*PDAMAGETRACKINGMODE == -1) {
+ Debug::log(CRIT, "Damage tracking mode -1 ????");
+ return;
+ }
+
+ const bool UNLOCK_SC = g_pHyprRenderer->m_bSoftwareCursorsLocked;
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, true);
+
+ if (!wlr_output_damage_attach_render(pMonitor->damage, &hasChanged, &damage)) {
+ Debug::log(ERR, "Couldn't attach render to display %s ???", pMonitor->szName.c_str());
+ return;
+ }
+
+ pMonitor->renderingActive = true;
+
+ // we need to cleanup fading out when rendering the appropriate context
+ g_pCompositor->cleanupFadingOut(pMonitor->ID);
+
+ if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) {
+ pixman_region32_fini(&damage);
+ wlr_output_rollback(pMonitor->output);
+
+ if (*PDAMAGEBLINK || *PVFR == 0)
+ g_pCompositor->scheduleFrameForMonitor(pMonitor);
+
+ pMonitor->renderingActive = false;
+
+ return;
+ }
+
+ // if we have no tracking or full tracking, invalidate the entire monitor
+ if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || pMonitor->forceFullFrames > 0 || damageBlinkCleanup > 0 ||
+ pMonitor->isMirror() /* why??? */) {
+ pixman_region32_union_rect(&damage, &damage, 0, 0, (int)pMonitor->vecTransformedSize.x * 10, (int)pMonitor->vecTransformedSize.y * 10); // wot?
+
+ pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
+ } else {
+ static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
+
+ // if we use blur we need to expand the damage for proper blurring
+ if (*PBLURENABLED == 1) {
+ // TODO: can this be optimized?
+ static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
+ static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
+ const auto BLURRADIUS =
+ *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
+
+ // now, prep the damage, get the extended damage region
+ wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring
+
+ pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
+
+ wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring 2
+ } else {
+ pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
+ }
+ }
+
+ if (pMonitor->forceFullFrames > 0) {
+ pMonitor->forceFullFrames -= 1;
+ if (pMonitor->forceFullFrames > 10)
+ pMonitor->forceFullFrames = 0;
+ }
+
+ // TODO: this is getting called with extents being 0,0,0,0 should it be?
+ // potentially can save on resources.
+
+ g_pHyprOpenGL->begin(pMonitor, &damage);
+
+ if (pMonitor->isMirror()) {
+ g_pHyprOpenGL->renderMirrored();
+ } else {
+ g_pHyprOpenGL->clear(CColor(17.0 / 255.0, 17.0 / 255.0, 17.0 / 255.0, 1.0));
+ g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
+
+ renderAllClientsForMonitor(pMonitor->ID, &now);
+
+ if (pMonitor == g_pCompositor->m_pLastMonitor) {
+ g_pHyprNotificationOverlay->draw(pMonitor);
+ g_pHyprError->draw();
+ }
+
+ // for drawing the debug overlay
+ if (pMonitor == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
+ startRenderOverlay = std::chrono::high_resolution_clock::now();
+ g_pDebugOverlay->draw();
+ endRenderOverlay = std::chrono::high_resolution_clock::now();
+ }
+
+ if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
+ wlr_box monrect = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y};
+ g_pHyprOpenGL->renderRect(&monrect, CColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0);
+ damageBlinkCleanup = 1;
+ } else if (*PDAMAGEBLINK) {
+ damageBlinkCleanup++;
+ if (damageBlinkCleanup > 3)
+ damageBlinkCleanup = 0;
+ }
+
+ if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y)) {
+ wlr_output_render_software_cursors(pMonitor->output, NULL);
+ wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
+ }
+ }
+
+ g_pHyprOpenGL->end();
+
+ // calc frame damage
+ pixman_region32_t frameDamage;
+ pixman_region32_init(&frameDamage);
+
+ const auto TRANSFORM = wlr_output_transform_invert(pMonitor->output->transform);
+ wlr_region_transform(&frameDamage, &g_pHyprOpenGL->m_rOriginalDamageRegion, TRANSFORM, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
+
+ if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
+ pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
+
+ if (*PDAMAGEBLINK)
+ pixman_region32_union(&frameDamage, &frameDamage, &damage);
+
+ wlr_output_set_damage(pMonitor->output, &frameDamage);
+
+ if (!pMonitor->mirrors.empty())
+ g_pHyprRenderer->damageMirrorsWith(pMonitor, &frameDamage);
+
+ pixman_region32_fini(&frameDamage);
+
+ pMonitor->renderingActive = false;
+
+ if (!wlr_output_commit(pMonitor->output)) {
+ pixman_region32_fini(&damage);
+
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, false);
+
+ return;
+ }
+
+ g_pProtocolManager->m_pScreencopyProtocolManager->onRenderEnd(pMonitor);
+ pixman_region32_fini(&damage);
+
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, false);
+
+ if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame)
+ g_pCompositor->scheduleFrameForMonitor(pMonitor);
+
+ pMonitor->pendingFrame = false;
+
+ const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
+ g_pDebugOverlay->renderData(pMonitor, µs);
+
+ if (*PDEBUGOVERLAY == 1) {
+ if (pMonitor == g_pCompositor->m_vMonitors.front().get()) {
+ const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
+ g_pDebugOverlay->renderDataNoOverlay(pMonitor, µsNoOverlay);
+ } else {
+ g_pDebugOverlay->renderDataNoOverlay(pMonitor, µs);
+ }
+ }
+}
+
void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) {
if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked())
return;
if (!pWindow->m_bIsFullscreen) {
- wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), nullptr);
+ wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), nullptr);
Debug::log(LOG, "Scanout mode OFF set for %x", pWindow);
return;
}
@@ -758,7 +1000,7 @@ void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) {
if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS))
return;
- wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), &feedback);
+ wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), &feedback);
wlr_linux_dmabuf_feedback_v1_finish(&feedback);
Debug::log(LOG, "Scanout mode ON set for %x", pWindow);
@@ -1031,6 +1273,9 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
pixman_region32_init(&damageBoxForEach);
for (auto& m : g_pCompositor->m_vMonitors) {
+ if (!m->output)
+ continue;
+
double lx = 0, ly = 0;
wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m->output, &lx, &ly);
@@ -1481,8 +1726,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
(int)pMonitor->vecPixelSize.y, pMonitor->refreshRate, pMonitor->scale, (int)pMonitor->transform, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y,
(int)pMonitor->enabled10bit);
- g_pInputManager->refocus();
-
return true;
}
@@ -1523,3 +1766,21 @@ void CHyprRenderer::ensureCursorRenderingMode() {
bool CHyprRenderer::shouldRenderCursor() {
return m_bHasARenderedCursor;
}
+
+std::tuple<float, float, float> CHyprRenderer::getRenderTimes(CMonitor* pMonitor) {
+ const auto POVERLAY = &g_pDebugOverlay->m_mMonitorOverlays[pMonitor];
+
+ float avgRenderTime = 0;
+ float maxRenderTime = 0;
+ float minRenderTime = 9999;
+ for (auto& rt : POVERLAY->m_dLastRenderTimes) {
+ if (rt > maxRenderTime)
+ maxRenderTime = rt;
+ if (rt < minRenderTime)
+ minRenderTime = rt;
+ avgRenderTime += rt;
+ }
+ avgRenderTime /= POVERLAY->m_dLastRenderTimes.size() == 0 ? 1 : POVERLAY->m_dLastRenderTimes.size();
+
+ return std::make_tuple<>(avgRenderTime, maxRenderTime, minRenderTime);
+}
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index 18929738..82da4b69 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -31,35 +31,37 @@ struct SSessionLockSurface;
class CHyprRenderer {
public:
- void renderAllClientsForMonitor(const int&, timespec*);
- void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
- void arrangeLayersForMonitor(const int&);
- void damageSurface(wlr_surface*, double, double);
- void damageWindow(CWindow*);
- void damageBox(wlr_box*);
- void damageBox(const int& x, const int& y, const int& w, const int& h);
- void damageRegion(pixman_region32_t*);
- void damageMonitor(CMonitor*);
- void damageMirrorsWith(CMonitor*, pixman_region32_t*);
- bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
- bool shouldRenderWindow(CWindow*, CMonitor*);
- bool shouldRenderWindow(CWindow*);
- void ensureCursorRenderingMode();
- bool shouldRenderCursor();
- void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false);
+ void renderMonitor(CMonitor* pMonitor);
+ void renderAllClientsForMonitor(const int&, timespec*);
+ void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
+ void arrangeLayersForMonitor(const int&);
+ void damageSurface(wlr_surface*, double, double);
+ void damageWindow(CWindow*);
+ void damageBox(wlr_box*);
+ void damageBox(const int& x, const int& y, const int& w, const int& h);
+ void damageRegion(pixman_region32_t*);
+ void damageMonitor(CMonitor*);
+ void damageMirrorsWith(CMonitor*, pixman_region32_t*);
+ bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
+ bool shouldRenderWindow(CWindow*, CMonitor*);
+ bool shouldRenderWindow(CWindow*);
+ void ensureCursorRenderingMode();
+ bool shouldRenderCursor();
+ void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false);
+ std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
- bool m_bWindowRequestedCursorHide = false;
- bool m_bBlockSurfaceFeedback = false;
- bool m_bRenderingSnapshot = false;
- CWindow* m_pLastScanout = nullptr;
- CMonitor* m_pMostHzMonitor = nullptr;
- bool m_bDirectScanoutBlocked = false;
- bool m_bSoftwareCursorsLocked = false;
+ bool m_bWindowRequestedCursorHide = false;
+ bool m_bBlockSurfaceFeedback = false;
+ bool m_bRenderingSnapshot = false;
+ CWindow* m_pLastScanout = nullptr;
+ CMonitor* m_pMostHzMonitor = nullptr;
+ bool m_bDirectScanoutBlocked = false;
+ bool m_bSoftwareCursorsLocked = false;
- DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
+ DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
- bool attemptDirectScanout(CMonitor*);
- void setWindowScanoutMode(CWindow*);
+ bool attemptDirectScanout(CMonitor*);
+ void setWindowScanoutMode(CWindow*);
private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp
index 6d3ca09b..33bcdca3 100644
--- a/src/render/Shader.hpp
+++ b/src/render/Shader.hpp
@@ -15,6 +15,7 @@ class CShader {
GLint posAttrib;
GLint texAttrib;
GLint discardOpaque;
+ GLint discardAlphaZero;
GLint topLeft;
GLint bottomRight;
diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp
index 0bf168a4..52e77fae 100644
--- a/src/render/shaders/Textures.hpp
+++ b/src/render/shaders/Textures.hpp
@@ -96,6 +96,7 @@ uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
+uniform int discardAlphaZero;
uniform int applyTint;
uniform vec3 tint;
@@ -107,13 +108,15 @@ void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
- discard;
-
+ discard;
+
+ if (discardAlphaZero == 1 && pixColor[3] == 0.0)
+ discard;
if (applyTint == 1) {
- pixColor[0] = pixColor[0] * tint[0];
- pixColor[1] = pixColor[1] * tint[1];
- pixColor[2] = pixColor[2] * tint[2];
+ pixColor[0] = pixColor[0] * tint[0];
+ pixColor[1] = pixColor[1] * tint[1];
+ pixColor[2] = pixColor[2] * tint[2];
}
)#" +
@@ -142,6 +145,7 @@ uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
+uniform int discardAlphaZero;
uniform int applyTint;
uniform vec3 tint;
@@ -228,6 +232,7 @@ uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
+uniform int discardAlphaZero;
uniform int applyTint;
uniform vec3 tint;