diff options
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 } @@ -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": { @@ -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; |