diff options
147 files changed, 5415 insertions, 2253 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e42a530a..43cbb50c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprlang>=0.3.2 hyprcursor>=0.1.7 ) -find_package(hyprwayland-scanner 0.3.8 REQUIRED) +find_package(hyprwayland-scanner 0.3.10 REQUIRED) file(GLOB_RECURSE SRCFILES "src/*.cpp") @@ -277,7 +277,6 @@ target_link_libraries(Hyprland protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) -protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) @@ -291,6 +290,7 @@ protocolNew("protocols" "kde-server-decoration" true) protocolNew("protocols" "wlr-data-control-unstable-v1" true) protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolNew("protocols" "wayland-drm" true) protocolNew("staging/tearing-control" "tearing-control-v1" false) protocolNew("staging/fractional-scale" "fractional-scale-v1" false) protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) @@ -312,6 +312,8 @@ protocolNew("stable/presentation-time" "presentation-time" false) protocolNew("stable/xdg-shell" "xdg-shell" false) protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false) +protocolNew("stable/viewporter" "viewporter" false) +protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false) protocolWayland() @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1716576411, - "narHash": "sha256-FIN1wMoyePBTtibCbaeJaoKNLuAYIGwLCWAYC1DJanw=", + "lastModified": 1717181720, + "narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "57298fc4f13c807e50ada2c986a3114b7fc2e621", + "rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c", "type": "github" }, "original": { @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1716058375, - "narHash": "sha256-CwjWoVnBZE5SBpRx9dgSQGCr4Goxyfcyv3zZbOhVqzk=", + "lastModified": 1717784906, + "narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "3afed4364790aebe0426077631af1e164a9650cc", + "rev": "0f30f9eca6e404130988554accbb64d1c9ec877d", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1716330097, - "narHash": "sha256-8BO3B7e3BiyIDsaKA0tY8O88rClYRTjvAp66y+VBUeU=", + "lastModified": 1717602782, + "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5710852ba686cc1fd0d3b8e22b3117d43ba374c2", + "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", "type": "github" }, "original": { diff --git a/protocols/meson.build b/protocols/meson.build index f491bb09..f4978c23 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -24,7 +24,6 @@ hyprwayland_scanner = find_program( ) protocols = [ - [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], @@ -41,6 +40,7 @@ new_protocols = [ ['wlr-output-management-unstable-v1.xml'], ['kde-server-decoration.xml'], ['wlr-layer-shell-unstable-v1.xml'], + ['wayland-drm.xml'], ['wlr-data-control-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], @@ -64,6 +64,8 @@ new_protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'], [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], + [wl_protocol_dir, 'stable/viewporter/viewporter.xml'], + [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], ] wl_protos_src = [] diff --git a/protocols/wayland-drm.xml b/protocols/wayland-drm.xml new file mode 100644 index 00000000..eaf2654a --- /dev/null +++ b/protocols/wayland-drm.xml @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="drm"> + + <copyright> + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2011 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that\n the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + </copyright> + + <!-- drm support. This object is created by the server and published + using the display's global event. --> + <interface name="wl_drm" version="2"> + <enum name="error"> + <entry name="authenticate_fail" value="0"/> + <entry name="invalid_format" value="1"/> + <entry name="invalid_name" value="2"/> + </enum> + + <enum name="format"> + <!-- The drm format codes match the #defines in drm_fourcc.h. + The formats actually supported by the compositor will be + reported by the format event. New codes must not be added, + unless directly taken from drm_fourcc.h. --> + <entry name="c8" value="0x20203843"/> + <entry name="rgb332" value="0x38424752"/> + <entry name="bgr233" value="0x38524742"/> + <entry name="xrgb4444" value="0x32315258"/> + <entry name="xbgr4444" value="0x32314258"/> + <entry name="rgbx4444" value="0x32315852"/> + <entry name="bgrx4444" value="0x32315842"/> + <entry name="argb4444" value="0x32315241"/> + <entry name="abgr4444" value="0x32314241"/> + <entry name="rgba4444" value="0x32314152"/> + <entry name="bgra4444" value="0x32314142"/> + <entry name="xrgb1555" value="0x35315258"/> + <entry name="xbgr1555" value="0x35314258"/> + <entry name="rgbx5551" value="0x35315852"/> + <entry name="bgrx5551" value="0x35315842"/> + <entry name="argb1555" value="0x35315241"/> + <entry name="abgr1555" value="0x35314241"/> + <entry name="rgba5551" value="0x35314152"/> + <entry name="bgra5551" value="0x35314142"/> + <entry name="rgb565" value="0x36314752"/> + <entry name="bgr565" value="0x36314742"/> + <entry name="rgb888" value="0x34324752"/> + <entry name="bgr888" value="0x34324742"/> + <entry name="xrgb8888" value="0x34325258"/> + <entry name="xbgr8888" value="0x34324258"/> + <entry name="rgbx8888" value="0x34325852"/> + <entry name="bgrx8888" value="0x34325842"/> + <entry name="argb8888" value="0x34325241"/> + <entry name="abgr8888" value="0x34324241"/> + <entry name="rgba8888" value="0x34324152"/> + <entry name="bgra8888" value="0x34324142"/> + <entry name="xrgb2101010" value="0x30335258"/> + <entry name="xbgr2101010" value="0x30334258"/> + <entry name="rgbx1010102" value="0x30335852"/> + <entry name="bgrx1010102" value="0x30335842"/> + <entry name="argb2101010" value="0x30335241"/> + <entry name="abgr2101010" value="0x30334241"/> + <entry name="rgba1010102" value="0x30334152"/> + <entry name="bgra1010102" value="0x30334142"/> + <entry name="yuyv" value="0x56595559"/> + <entry name="yvyu" value="0x55595659"/> + <entry name="uyvy" value="0x59565955"/> + <entry name="vyuy" value="0x59555956"/> + <entry name="ayuv" value="0x56555941"/> + <entry name="xyuv8888" value="0x56555958"/> + <entry name="nv12" value="0x3231564e"/> + <entry name="nv21" value="0x3132564e"/> + <entry name="nv16" value="0x3631564e"/> + <entry name="nv61" value="0x3136564e"/> + <entry name="yuv410" value="0x39565559"/> + <entry name="yvu410" value="0x39555659"/> + <entry name="yuv411" value="0x31315559"/> + <entry name="yvu411" value="0x31315659"/> + <entry name="yuv420" value="0x32315559"/> + <entry name="yvu420" value="0x32315659"/> + <entry name="yuv422" value="0x36315559"/> + <entry name="yvu422" value="0x36315659"/> + <entry name="yuv444" value="0x34325559"/> + <entry name="yvu444" value="0x34325659"/> + <entry name="abgr16f" value="0x48344241"/> + <entry name="xbgr16f" value="0x48344258"/> + </enum> + + <!-- Call this request with the magic received from drmGetMagic(). + It will be passed on to the drmAuthMagic() or + DRIAuthConnection() call. This authentication must be + completed before create_buffer could be used. --> + <request name="authenticate"> + <arg name="id" type="uint"/> + </request> + + <!-- Create a wayland buffer for the named DRM buffer. The DRM + surface must have a name using the flink ioctl --> + <request name="create_buffer"> + <arg name="id" type="new_id" interface="wl_buffer"/> + <arg name="name" type="uint"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + <arg name="stride" type="uint"/> + <arg name="format" type="uint"/> + </request> + + <!-- Create a wayland buffer for the named DRM buffer. The DRM + surface must have a name using the flink ioctl --> + <request name="create_planar_buffer"> + <arg name="id" type="new_id" interface="wl_buffer"/> + <arg name="name" type="uint"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + <arg name="format" type="uint"/> + <arg name="offset0" type="int"/> + <arg name="stride0" type="int"/> + <arg name="offset1" type="int"/> + <arg name="stride1" type="int"/> + <arg name="offset2" type="int"/> + <arg name="stride2" type="int"/> + </request> + + <!-- Notification of the path of the drm device which is used by + the server. The client should use this device for creating + local buffers. Only buffers created from this device should + be be passed to the server using this drm object's + create_buffer request. --> + <event name="device"> + <arg name="name" type="string"/> + </event> + + <event name="format"> + <arg name="format" type="uint"/> + </event> + + <!-- Raised if the authenticate request succeeded --> + <event name="authenticated"/> + + <enum name="capability" since="2"> + <description summary="wl_drm capability bitmask"> + Bitmask of capabilities. + </description> + <entry name="prime" value="1" summary="wl_drm prime available"/> + </enum> + + <event name="capabilities"> + <arg name="value" type="uint"/> + </event> + + <!-- Version 2 additions --> + + <!-- Create a wayland buffer for the prime fd. Use for regular and planar + buffers. Pass 0 for offset and stride for unused planes. --> + <request name="create_prime_buffer" since="2"> + <arg name="id" type="new_id" interface="wl_buffer"/> + <arg name="name" type="fd"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + <arg name="format" type="uint"/> + <arg name="offset0" type="int"/> + <arg name="stride0" type="int"/> + <arg name="offset1" type="int"/> + <arg name="stride1" type="int"/> + <arg name="offset2" type="int"/> + <arg name="stride2" type="int"/> + </request> + + </interface> + +</protocol> diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 73708b1b..b0456358 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -19,6 +19,8 @@ #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" #include "protocols/XDGShell.hpp" +#include "protocols/core/Compositor.hpp" +#include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" #include "xwayland/XWayland.hpp" @@ -184,7 +186,7 @@ void CCompositor::initServer() { &isHeadlessOnly); if (isHeadlessOnly) { - m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); + m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now. } else { m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend); if (m_iDRMFD < 0) { @@ -200,15 +202,6 @@ void CCompositor::initServer() { throwError("wlr_gles2_renderer_create_with_drm_fd() failed!"); } - wlr_renderer_init_wl_shm(m_sWLRRenderer, m_sWLDisplay); - - if (wlr_renderer_get_dmabuf_texture_formats(m_sWLRRenderer)) { - if (wlr_renderer_get_drm_fd(m_sWLRRenderer) >= 0) - wlr_drm_create(m_sWLDisplay, m_sWLRRenderer); - - m_sWLRLinuxDMABuf = wlr_linux_dmabuf_v1_create_with_renderer(m_sWLDisplay, 4, m_sWLRRenderer); - } - m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer); if (!m_sWLRAllocator) { @@ -223,13 +216,7 @@ void CCompositor::initServer() { throwError("wlr_gles2_renderer_get_egl() failed!"); } - m_sWLRCompositor = wlr_compositor_create(m_sWLDisplay, 6, m_sWLRRenderer); - m_sWLRSubCompositor = wlr_subcompositor_create(m_sWLDisplay); - // m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay); - - // wlr_data_control_manager_v1_create(m_sWLDisplay); - // wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); - wlr_viewporter_create(m_sWLDisplay); + initManagers(STAGE_BASICINIT); m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend); if (!m_sWRLDRMLeaseMgr) { @@ -244,8 +231,6 @@ void CCompositor::initServer() { throwError("wlr_headless_backend_create() failed!"); } - wlr_single_pixel_buffer_manager_v1_create(m_sWLDisplay); - wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend); initManagers(STAGE_LATE); @@ -320,7 +305,7 @@ void CCompositor::cleanup() { // still in a normal working state. g_pPluginSystem->unloadAllPlugins(); - m_pLastFocus = nullptr; + m_pLastFocus.reset(); m_pLastWindow.reset(); m_vWorkspaces.clear(); @@ -393,12 +378,6 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the HookSystem!"); g_pHookSystem = std::make_unique<CHookSystemManager>(); - Debug::log(LOG, "Creating the ProtocolManager!"); - g_pProtocolManager = std::make_unique<CProtocolManager>(); - - Debug::log(LOG, "Creating the SeatManager!"); - g_pSeatManager = std::make_unique<CSeatManager>(); - Debug::log(LOG, "Creating the KeybindManager!"); g_pKeybindManager = std::make_unique<CKeybindManager>(); @@ -423,6 +402,13 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the PointerManager!"); g_pPointerManager = std::make_unique<CPointerManager>(); } break; + case STAGE_BASICINIT: { + Debug::log(LOG, "Creating the ProtocolManager!"); + g_pProtocolManager = std::make_unique<CProtocolManager>(); + + Debug::log(LOG, "Creating the SeatManager!"); + g_pSeatManager = std::make_unique<CSeatManager>(); + } break; case STAGE_LATE: { Debug::log(LOG, "Creating the ThreadManager!"); g_pThreadManager = std::make_unique<CThreadManager>(); @@ -574,6 +560,8 @@ void CCompositor::startCompositor() { createLockFile(); + EMIT_HOOK_EVENT("ready", nullptr); + // This blocks until we are done. Debug::log(LOG, "Hyprland is ready, running the event loop!"); g_pEventLoopManager->enterLoop(m_sWLDisplay, m_sWLEventLoop); @@ -789,47 +777,32 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper return windowForWorkspace(false); } -wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW pWindow, Vector2D& sl) { +SP<CWLSurfaceResource> CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW pWindow, Vector2D& sl) { if (!validMapped(pWindow)) return nullptr; RASSERT(!pWindow->m_bIsX11, "Cannot call vectorWindowToSurface on an X11 window!"); - double subx, suby; - - CBox geom = pWindow->m_pXDGSurface->current.geometry; - // try popups first - const auto PPOPUP = pWindow->m_pPopupHead->at(pos); + const auto PPOPUP = pWindow->m_pPopupHead->at(pos); - wlr_surface* found = PPOPUP ? PPOPUP->m_sWLSurface.wlr() : nullptr; - - if (!PPOPUP) - found = wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx, - &suby); - else { + if (PPOPUP) { const auto OFF = PPOPUP->coordsRelativeToParent(); - subx = pos.x - OFF.x + geom.x - pWindow->m_vRealPosition.goal().x; - suby = pos.y - OFF.y + geom.y - pWindow->m_vRealPosition.goal().y; + sl = pos - pWindow->m_vRealPosition.goal() - OFF; + return PPOPUP->m_pWLSurface->resource(); } - if (found) { - sl.x = subx; - sl.y = suby; - return found; + auto [surf, local] = pWindow->m_pWLSurface->resource()->at(pos - pWindow->m_vRealPosition.goal(), true); + if (surf) { + sl = local; + return surf; } - sl.x = pos.x - pWindow->m_vRealPosition.value().x; - sl.y = pos.y - pWindow->m_vRealPosition.value().y; - - sl.x += geom.x; - sl.y += geom.y; - - return pWindow->m_pWLSurface.wlr(); + return nullptr; } -Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, wlr_surface* pSurface) { +Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface) { if (!validMapped(pWindow)) return {}; @@ -840,25 +813,22 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo if (PPOPUP) return vec - PPOPUP->coordsGlobal(); - std::tuple<wlr_surface*, int, int> iterData = {pSurface, -1337, -1337}; + std::tuple<SP<CWLSurfaceResource>, Vector2D> iterData = {pSurface, {-1337, -1337}}; - wlr_surface_for_each_surface( - pWindow->m_pWLSurface.wlr(), - [](wlr_surface* surf, int x, int y, void* data) { - const auto PDATA = (std::tuple<wlr_surface*, int, int>*)data; - if (surf == std::get<0>(*PDATA)) { - std::get<1>(*PDATA) = x; - std::get<2>(*PDATA) = y; - } + pWindow->m_pWLSurface->resource()->breadthfirst( + [](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { + const auto PDATA = (std::tuple<SP<CWLSurfaceResource>, Vector2D>*)data; + if (surf == std::get<0>(*PDATA)) + std::get<1>(*PDATA) = offset; }, &iterData); CBox geom = pWindow->m_pXDGSurface->current.geometry; - if (std::get<1>(iterData) == -1337 && std::get<2>(iterData) == -1337) + if (std::get<1>(iterData) == Vector2D{-1337, -1337}) return vec - pWindow->m_vRealPosition.goal(); - return vec - pWindow->m_vRealPosition.goal() - Vector2D{std::get<1>(iterData), std::get<2>(iterData)} + Vector2D{geom.x, geom.y}; + return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; } CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { @@ -881,7 +851,7 @@ CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) { return nullptr; } -void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { +void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface) { static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough"); @@ -924,7 +894,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr); - m_pLastFocus = nullptr; + m_pLastFocus.reset(); g_pInputManager->recheckIdleInhibitorStatus(); return; @@ -976,7 +946,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { m_pLastWindow = PLASTWINDOW; - const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow->m_pWLSurface.wlr(); + const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow->m_pWLSurface->resource(); focusSurface(PWINDOWSURFACE, pWindow); @@ -1011,9 +981,9 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { g_pInputManager->sendMotionEventsToFocused(); } -void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { +void CCompositor::focusSurface(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindowOwner) { - if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface.wlr())) + if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface->resource())) return; // Don't focus when already focused on this. if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) @@ -1024,18 +994,18 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { return; } - const auto PLASTSURF = m_pLastFocus; + const auto PLASTSURF = m_pLastFocus.lock(); // Unfocus last surface if should if (m_pLastFocus && !pWindowOwner) - g_pXWaylandManager->activateSurface(m_pLastFocus, false); + g_pXWaylandManager->activateSurface(m_pLastFocus.lock(), false); if (!pSurface) { g_pSeatManager->setKeyboardFocus(nullptr); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""}); - EMIT_HOOK_EVENT("keyboardFocus", (wlr_surface*)nullptr); - m_pLastFocus = nullptr; + EMIT_HOOK_EVENT("keyboardFocus", (SP<CWLSurfaceResource>)nullptr); + m_pLastFocus.reset(); return; } @@ -1052,8 +1022,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { EMIT_HOOK_EVENT("keyboardFocus", pSurface); - const auto SURF = CWLSurface::surfaceFromWlr(pSurface); - const auto OLDSURF = CWLSurface::surfaceFromWlr(PLASTSURF); + const auto SURF = CWLSurface::fromResource(pSurface); + const auto OLDSURF = CWLSurface::fromResource(PLASTSURF); if (OLDSURF && OLDSURF->constraint()) OLDSURF->constraint()->deactivate(); @@ -1062,7 +1032,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { SURF->constraint()->activate(); } -wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { +SP<CWLSurfaceResource> CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto& ls : lsl | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) @@ -1073,7 +1043,7 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito if (SURFACEAT) { *ppLayerSurfaceFound = ls.lock(); *sCoords = pos - SURFACEAT->coordsGlobal(); - return SURFACEAT->m_sWLSurface.wlr(); + return SURFACEAT->m_pWLSurface->resource(); } } } @@ -1081,31 +1051,34 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito return nullptr; } -wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<PHLLSREF>* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { +SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<PHLLSREF>* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& ls : *layerSurfaces | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; - auto SURFACEAT = wlr_surface_surface_at(ls->layerSurface->surface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y); + auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos()); - if (SURFACEAT) { - if (!pixman_region32_not_empty(&SURFACEAT->input_region)) + if (surf) { + if (surf->current.input.empty()) continue; *ppLayerSurfaceFound = ls.lock(); - return SURFACEAT; + + *sCoords = local; + + return surf; } } return nullptr; } -PHLWINDOW CCompositor::getWindowFromSurface(wlr_surface* pSurface) { +PHLWINDOW CCompositor::getWindowFromSurface(SP<CWLSurfaceResource> pSurface) { for (auto& w : m_vWindows) { if (!w->m_bIsMapped || w->m_bFadingOut) continue; - if (w->m_pWLSurface.wlr() == pSurface) + if (w->m_pWLSurface->resource() == pSurface) return w; } @@ -1244,7 +1217,7 @@ bool CCompositor::isWindowActive(PHLWINDOW pWindow) { if (!pWindow->m_bIsMapped) return false; - const auto PSURFACE = pWindow->m_pWLSurface.wlr(); + const auto PSURFACE = pWindow->m_pWLSurface->resource(); return PSURFACE == m_pLastFocus || pWindow == m_pLastWindow.lock(); } @@ -1646,11 +1619,6 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* p return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); } -void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) { - auto pair = (std::pair<wlr_surface*, bool>*)data; - pair->second = pair->second || pSurface == pair->first; -} - CMonitor* CCompositor::getMonitorInDirection(const char& dir) { return this->getMonitorInDirection(m_pLastMonitor.get(), dir); } @@ -2389,24 +2357,24 @@ void CCompositor::closeWindow(PHLWINDOW pWindow) { } } -PHLLS CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) { - std::pair<wlr_surface*, bool> result = {pSurface, false}; +PHLLS CCompositor::getLayerSurfaceFromSurface(SP<CWLSurfaceResource> pSurface) { + std::pair<SP<CWLSurfaceResource>, bool> result = {pSurface, false}; for (auto& ls : m_vLayers) { if (ls->layerSurface && ls->layerSurface->surface == pSurface) return ls; - 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); + ls->layerSurface->surface->breadthfirst( + [](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { + if (surf == ((std::pair<SP<CWLSurfaceResource>, bool>*)data)->first) { + *(bool*)data = true; + return; + } + }, + &result); if (result.second) return ls; @@ -2738,13 +2706,13 @@ void CCompositor::leaveUnsafeState() { } } -void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) { +void CCompositor::setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale) { PROTO::fractional->sendScale(pSurface, scale); - wlr_surface_set_preferred_buffer_scale(pSurface, static_cast<int32_t>(std::ceil(scale))); + pSurface->sendPreferredScale(std::ceil(scale)); - const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface); + const auto PSURFACE = CWLSurface::fromResource(pSurface); if (!PSURFACE) { - Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface); + Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface); return; } @@ -2752,12 +2720,12 @@ void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scal PSURFACE->m_iLastScale = static_cast<int32_t>(std::ceil(scale)); } -void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) { - wlr_surface_set_preferred_buffer_transform(pSurface, transform); +void CCompositor::setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform) { + pSurface->sendPreferredTransform(transform); - const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface); + const auto PSURFACE = CWLSurface::fromResource(pSurface); if (!PSURFACE) { - Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface); + Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface); return; } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a297518d..793899ee 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -29,8 +29,11 @@ #include "plugins/PluginSystem.hpp" #include "helpers/Watchdog.hpp" +class CWLSurfaceResource; + enum eManagersInitStage { STAGE_PRIORITY = 0, + STAGE_BASICINIT, STAGE_LATE }; @@ -79,7 +82,7 @@ class CCompositor { void createLockFile(); void removeLockFile(); - wlr_surface* m_pLastFocus = nullptr; + WP<CWLSurfaceResource> m_pLastFocus; PHLWINDOWREF m_pLastWindow; WP<CMonitor> m_pLastMonitor; @@ -96,86 +99,86 @@ class CCompositor { // ------------------------------------------------- // - CMonitor* getMonitorFromID(const int&); - CMonitor* getMonitorFromName(const std::string&); - CMonitor* getMonitorFromDesc(const std::string&); - CMonitor* getMonitorFromCursor(); - CMonitor* getMonitorFromVector(const Vector2D&); - void removeWindowFromVectorSafe(PHLWINDOW); - void focusWindow(PHLWINDOW, wlr_surface* pSurface = nullptr); - void focusSurface(wlr_surface*, PHLWINDOW pWindowOwner = nullptr); - bool monitorExists(CMonitor*); - PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); - wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*); - wlr_surface* vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); - wlr_surface* vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); - Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, wlr_surface*); - CMonitor* getMonitorFromOutput(wlr_output*); - CMonitor* getRealMonitorFromOutput(wlr_output*); - PHLWINDOW getWindowFromSurface(wlr_surface*); - PHLWINDOW getWindowFromHandle(uint32_t); - bool isWorkspaceVisible(PHLWORKSPACE); - PHLWORKSPACE getWorkspaceByID(const int&); - PHLWORKSPACE getWorkspaceByName(const std::string&); - PHLWORKSPACE getWorkspaceByString(const std::string&); - void sanityCheckWorkspaces(); - void updateWorkspaceWindowDecos(const int&); - void updateWorkspaceSpecialRenderData(const int&); - int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); - int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); - PHLWINDOW getUrgentWindow(); - bool hasUrgentWindowOnWorkspace(const int&); - PHLWINDOW getFirstWindowOnWorkspace(const int&); - PHLWINDOW getTopLeftWindowOnWorkspace(const int&); - PHLWINDOW getFullscreenWindowOnWorkspace(const int&); - bool isWindowActive(PHLWINDOW); - void changeWindowZOrder(PHLWINDOW, bool); - void cleanupFadingOut(const int& monid); - PHLWINDOW getWindowInDirection(PHLWINDOW, char); - PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); - PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); - int getNextAvailableNamedWorkspace(); - bool isPointOnAnyMonitor(const Vector2D&); - bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); - CMonitor* getMonitorInDirection(const char&); - CMonitor* getMonitorInDirection(CMonitor*, const char&); - void updateAllWindowsAnimatedDecorationValues(); - void updateWorkspaceWindows(const int64_t& id); - void updateWindowAnimatedDecorationValues(PHLWINDOW); - int getNextAvailableMonitorID(std::string const& name); - void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); - void swapActiveWorkspaces(CMonitor*, CMonitor*); - CMonitor* getMonitorFromString(const std::string&); - bool workspaceIDOutOfBounds(const int64_t&); - void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); - void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); - PHLWINDOW getX11Parent(PHLWINDOW); - void scheduleFrameForMonitor(CMonitor*); - void addToFadingOutSafe(PHLLS); - void addToFadingOutSafe(PHLWINDOW); - PHLWINDOW getWindowByRegex(const std::string&); - void warpCursorTo(const Vector2D&, bool force = false); - PHLLS getLayerSurfaceFromSurface(wlr_surface*); - void closeWindow(PHLWINDOW); - Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); - void forceReportSizesToWindowsOnWorkspace(const int&); - PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! - void renameWorkspace(const int&, const std::string& name = ""); - void setActiveMonitor(CMonitor*); - bool isWorkspaceSpecial(const int&); - int getNewSpecialID(); - void performUserChecks(); - void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); - PHLWINDOW getForceFocus(); - void arrangeMonitors(); - void enterUnsafeState(); - void leaveUnsafeState(); - void setPreferredScaleForSurface(wlr_surface* pSurface, double scale); - void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform); - void updateSuspendedStates(); - PHLWINDOW windowForCPointer(CWindow*); - - std::string explicitConfigPath; + CMonitor* getMonitorFromID(const int&); + CMonitor* getMonitorFromName(const std::string&); + CMonitor* getMonitorFromDesc(const std::string&); + CMonitor* getMonitorFromCursor(); + CMonitor* getMonitorFromVector(const Vector2D&); + void removeWindowFromVectorSafe(PHLWINDOW); + void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr); + void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr); + bool monitorExists(CMonitor*); + PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); + SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*); + SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); + SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); + Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>); + CMonitor* getMonitorFromOutput(wlr_output*); + CMonitor* getRealMonitorFromOutput(wlr_output*); + PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>); + PHLWINDOW getWindowFromHandle(uint32_t); + bool isWorkspaceVisible(PHLWORKSPACE); + PHLWORKSPACE getWorkspaceByID(const int&); + PHLWORKSPACE getWorkspaceByName(const std::string&); + PHLWORKSPACE getWorkspaceByString(const std::string&); + void sanityCheckWorkspaces(); + void updateWorkspaceWindowDecos(const int&); + void updateWorkspaceSpecialRenderData(const int&); + int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); + int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); + PHLWINDOW getUrgentWindow(); + bool hasUrgentWindowOnWorkspace(const int&); + PHLWINDOW getFirstWindowOnWorkspace(const int&); + PHLWINDOW getTopLeftWindowOnWorkspace(const int&); + PHLWINDOW getFullscreenWindowOnWorkspace(const int&); + bool isWindowActive(PHLWINDOW); + void changeWindowZOrder(PHLWINDOW, bool); + void cleanupFadingOut(const int& monid); + PHLWINDOW getWindowInDirection(PHLWINDOW, char); + PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); + PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}); + int getNextAvailableNamedWorkspace(); + bool isPointOnAnyMonitor(const Vector2D&); + bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); + CMonitor* getMonitorInDirection(const char&); + CMonitor* getMonitorInDirection(CMonitor*, const char&); + void updateAllWindowsAnimatedDecorationValues(); + void updateWorkspaceWindows(const int64_t& id); + void updateWindowAnimatedDecorationValues(PHLWINDOW); + int getNextAvailableMonitorID(std::string const& name); + void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); + void swapActiveWorkspaces(CMonitor*, CMonitor*); + CMonitor* getMonitorFromString(const std::string&); + bool workspaceIDOutOfBounds(const int64_t&); + void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); + void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); + PHLWINDOW getX11Parent(PHLWINDOW); + void scheduleFrameForMonitor(CMonitor*); + void addToFadingOutSafe(PHLLS); + void addToFadingOutSafe(PHLWINDOW); + PHLWINDOW getWindowByRegex(const std::string&); + void warpCursorTo(const Vector2D&, bool force = false); + PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>); + void closeWindow(PHLWINDOW); + Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); + void forceReportSizesToWindowsOnWorkspace(const int&); + PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! + void renameWorkspace(const int&, const std::string& name = ""); + void setActiveMonitor(CMonitor*); + bool isWorkspaceSpecial(const int&); + int getNewSpecialID(); + void performUserChecks(); + void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); + PHLWINDOW getForceFocus(); + void arrangeMonitors(); + void enterUnsafeState(); + void leaveUnsafeState(); + void setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale); + void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform); + void updateSuspendedStates(); + PHLWINDOW windowForCPointer(CWindow*); + + std::string explicitConfigPath; private: void initAllSignals(); diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 6d3ec907..889be8ea 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -3,6 +3,10 @@ #include "config/ConfigValue.hpp" #include "../Compositor.hpp" +CHyprDebugOverlay::CHyprDebugOverlay() { + m_pTexture = makeShared<CTexture>(); +} + void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { m_dLastRenderTimes.push_back(µs / 1000.f); @@ -222,8 +226,8 @@ void CHyprDebugOverlay::draw() { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); - m_tTexture.allocate(); - glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); + m_pTexture->allocate(); + glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -235,5 +239,5 @@ void CHyprDebugOverlay::draw() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; - g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f); + g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f); } diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index f3beab45..a6063ee9 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -31,6 +31,7 @@ class CHyprMonitorDebugOverlay { class CHyprDebugOverlay { public: + CHyprDebugOverlay(); void draw(); void renderData(CMonitor*, float µs); void renderDataNoOverlay(CMonitor*, float µs); @@ -42,7 +43,7 @@ class CHyprDebugOverlay { cairo_surface_t* m_pCairoSurface = nullptr; cairo_t* m_pCairo = nullptr; - CTexture m_tTexture; + SP<CTexture> m_pTexture; friend class CHyprMonitorDebugOverlay; friend class CHyprRenderer; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index e1fc810b..aec3853e 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -23,6 +23,8 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() { g_pHyprRenderer->damageBox(&m_bLastDamage); }); + + m_pTexture = makeShared<CTexture>(); } CHyprNotificationOverlay::~CHyprNotificationOverlay() { @@ -227,8 +229,8 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); - m_tTexture.allocate(); - glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); + m_pTexture->allocate(); + glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -240,7 +242,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); CBox pMonBox = {0, 0, MONSIZE.x, MONSIZE.y}; - g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f); + g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f); } bool CHyprNotificationOverlay::hasAny() { diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index 5c978089..352c44c9 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -58,7 +58,7 @@ class CHyprNotificationOverlay { CMonitor* m_pLastMonitor = nullptr; Vector2D m_vecLastSize = Vector2D(-1, -1); - CTexture m_tTexture; + SP<CTexture> m_pTexture; }; inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 759eb09f..62cae8f6 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../events/Events.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { @@ -9,6 +10,8 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor); + pLS->surface->assign(resource->surface.lock(), pLS); + if (!pMonitor) { Debug::log(ERR, "New LS has no monitor??"); return pLS; @@ -39,8 +42,6 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { pLS->alpha.setValueAndWarp(0.f); - pLS->surface.assign(resource->surface, pLS); - Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); return pLS; @@ -58,13 +59,16 @@ CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : layerSurface(r listeners.map = layerSurface->events.map.registerListener([this](std::any d) { onMap(); }); listeners.unmap = layerSurface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); listeners.destroy = layerSurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); + + surface = CWLSurface::create(); } CLayerSurface::~CLayerSurface() { if (!g_pHyprOpenGL) return; - surface.unassign(); + if (surface) + surface->unassign(); g_pHyprRenderer->makeEGLCurrent(); std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); }); } @@ -105,7 +109,8 @@ void CLayerSurface::onDestroy() { readyToDelete = true; layerSurface.reset(); - surface.unassign(); + if (surface) + surface->unassign(); } void CLayerSurface::onMap() { @@ -126,7 +131,7 @@ void CLayerSurface::onMap() { g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); - wlr_surface_send_enter(surface.wlr(), PMONITOR->output); + surface->resource()->enter(PMONITOR->self.lock()); if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) g_pInputManager->m_dExclusiveLSes.push_back(self); @@ -139,10 +144,10 @@ void CLayerSurface::onMap() { // TODO: use the new superb really very cool grab g_pSeatManager->setGrab(nullptr); g_pInputManager->releaseAllMouseButtons(); - g_pCompositor->focusSurface(surface.wlr()); + g_pCompositor->focusSurface(surface->resource()); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - g_pSeatManager->setPointerFocus(surface.wlr(), LOCAL); + g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); g_pInputManager->m_bEmptyFocusCursorSet = false; } @@ -160,8 +165,8 @@ void CLayerSurface::onMap() { g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", szNamespace}); EMIT_HOOK_EVENT("openLayer", self.lock()); - g_pCompositor->setPreferredScaleForSurface(surface.wlr(), PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(surface.wlr(), PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform); } void CLayerSurface::onUnmap() { @@ -173,7 +178,7 @@ void CLayerSurface::onUnmap() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); if (!g_pInputManager->m_dExclusiveLSes.empty()) - g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface); + g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource()); if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); @@ -197,9 +202,9 @@ void CLayerSurface::onUnmap() { const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); - const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layerSurface->surface; + const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); - surface = nullptr; + surface.reset(); if (!PMONITOR) return; @@ -208,11 +213,11 @@ void CLayerSurface::onUnmap() { if (WASLASTFOCUS) { g_pInputManager->releaseAllMouseButtons(); - Vector2D surfaceCoords; - PHLLS pFoundLayerSurface; - wlr_surface* foundSurface = nullptr; + Vector2D surfaceCoords; + PHLLS pFoundLayerSurface; + SP<CWLSurfaceResource> foundSurface = nullptr; - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); // find LS-es to focus foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], @@ -236,8 +241,8 @@ void CLayerSurface::onUnmap() { CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); - geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.width, - (int)layerSurface->surface->current.height}; + geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x, + (int)layerSurface->surface->current.size.y}; g_pHyprRenderer->damageBox(&geomFixed); g_pInputManager->sendMotionEventsToFocused(); @@ -284,12 +289,12 @@ void CLayerSurface::onCommit() { position = Vector2D(geometry.x, geometry.y); // update geom if it changed - if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.has_dst) { + if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.hasDestination) { // fractional scaling. Dirty hack. - geometry = {geometry.x, geometry.y, (int)(layerSurface->surface->current.viewport.dst_width), (int)(layerSurface->surface->current.viewport.dst_height)}; + geometry = {geometry.pos(), layerSurface->surface->current.viewport.destination}; } else { // this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly. - geometry = {geometry.x, geometry.y, (int)layerSurface->surface->current.width, (int)layerSurface->surface->current.height}; + geometry = {geometry.pos(), layerSurface->surface->current.size}; } } @@ -308,10 +313,10 @@ void CLayerSurface::onCommit() { if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained && !keyboardExclusive && mapped) { - g_pCompositor->focusSurface(layerSurface->surface); + g_pCompositor->focusSurface(surface->resource()); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - g_pSeatManager->setPointerFocus(layerSurface->surface, LOCAL); + g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); g_pInputManager->m_bEmptyFocusCursorSet = false; } else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { g_pInputManager->refocus(); @@ -319,10 +324,10 @@ void CLayerSurface::onCommit() { keyboardExclusive = layerSurface->current.interactivity; - g_pHyprRenderer->damageSurface(layerSurface->surface, position.x, position.y); + g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y); - g_pCompositor->setPreferredScaleForSurface(layerSurface->surface, PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(layerSurface->surface, PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform); } void CLayerSurface::applyRules() { diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index d60a6dd0..9fa96d2d 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -36,7 +36,7 @@ class CLayerSurface { bool keyboardExclusive = false; - CWLSurface surface; + SP<CWLSurface> surface; bool mapped = false; uint32_t layer = 0; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 6bc76fc7..f0fd556c 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include <ranges> CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { @@ -14,7 +15,8 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) { } CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) { - m_sWLSurface.assign(popup->surface->surface, this); + m_pWLSurface = CWLSurface::create(); + m_pWLSurface->assign(popup->surface->surface.lock(), this); m_pLayerOwner = pOwner->m_pLayerOwner; m_pWindowOwner = pOwner->m_pWindowOwner; @@ -26,7 +28,8 @@ CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), } CPopup::~CPopup() { - m_sWLSurface.unassign(); + if (m_pWLSurface) + m_pWLSurface->unassign(); } void CPopup::initAllSignals() { @@ -69,14 +72,14 @@ void CPopup::onMap() { if (m_bMapped) return; - m_bMapped = true; - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_bMapped = true; + m_vLastSize = m_pResource->surface->surface->current.size; + const auto COORDS = coordsGlobal(); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); - CBox box; - wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr()); - box.applyFromWlr().translate(COORDS).expand(4); + CBox box = m_pWLSurface->resource()->extends(); + box.translate(COORDS).expand(4); g_pHyprRenderer->damageBox(&box); m_vLastPos = coordsRelativeToParent(); @@ -87,7 +90,7 @@ void CPopup::onMap() { //unconstrain(); sendScale(); - wlr_surface_send_enter(m_pResource->surface->surface, PMONITOR->output); + m_pResource->surface->surface->enter(PMONITOR->self.lock()); if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); @@ -103,12 +106,12 @@ void CPopup::onUnmap() { return; } - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_vLastSize = m_pResource->surface->surface->current.size; + const auto COORDS = coordsGlobal(); - CBox box; - wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr()); - box.applyFromWlr().translate(COORDS).expand(4); + CBox box = m_pWLSurface->resource()->extends(); + box.translate(COORDS).expand(4); g_pHyprRenderer->damageBox(&box); m_pSubsurfaceHead.reset(); @@ -143,7 +146,7 @@ void CPopup::onCommit(bool ignoreSiblings) { } if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) { - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_vLastSize = m_pResource->surface->surface->current.size; static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage"); if (*PLOGDAMAGE) @@ -157,11 +160,10 @@ void CPopup::onCommit(bool ignoreSiblings) { const auto COORDS = coordsGlobal(); const auto COORDSLOCAL = coordsRelativeToParent(); - if (m_vLastSize != Vector2D{m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height} || m_bRequestedReposition || - m_vLastPos != COORDSLOCAL) { + if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) { CBox box = {localToGlobal(m_vLastPos), m_vLastSize}; g_pHyprRenderer->damageBox(&box); - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_vLastSize = m_pResource->surface->surface->current.size; box = {COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box); @@ -171,7 +173,7 @@ void CPopup::onCommit(bool ignoreSiblings) { if (!ignoreSiblings && m_pSubsurfaceHead) m_pSubsurfaceHead->recheckDamageForSubsurfaces(); - g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y); + g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); m_bRequestedReposition = false; @@ -211,7 +213,7 @@ Vector2D CPopup::coordsRelativeToParent() { while (current->m_pParent && current->m_pResource) { - offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy}; + offset += current->m_pWLSurface->resource()->current.offset; offset += current->m_pResource->geometry.pos(); current = current->m_pParent; @@ -260,9 +262,9 @@ Vector2D CPopup::size() { void CPopup::sendScale() { if (!m_pWindowOwner.expired()) - g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner->m_pWLSurface.m_fLastScale); + g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pWindowOwner->m_pWLSurface->m_fLastScale); else if (!m_pLayerOwner.expired()) - g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner->surface.m_fLastScale); + g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pLayerOwner->surface->m_fLastScale); else UNREACHABLE(); } @@ -318,9 +320,8 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { return p; } else { const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; - const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input} - .intersect(CBox{{}, {p->m_sWLSurface.wlr()->current.width, p->m_sWLSurface.wlr()->current.height}}) - .translate(p->coordsGlobal() + offset); + const auto REGION = + CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset); if (REGION.containsPoint(globalCoords)) return p; } diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 7fdabee6..91e569e7 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -39,7 +39,7 @@ class CPopup { CPopup* at(const Vector2D& globalCoords, bool allowsInput = false); // - CWLSurface m_sWLSurface; + SP<CWLSurface> m_pWLSurface; private: // T1 owners, each popup has to have one of these diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 21482ff7..71ee16f0 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -2,29 +2,31 @@ #include "../events/Events.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" - -static void onNewSubsurface(void* owner, void* data); +#include "../protocols/core/Compositor.hpp" +#include "../protocols/core/Subcompositor.hpp" CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) { initSignals(); - initExistingSubsurfaces(pOwner->m_pWLSurface.wlr()); + initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); } CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) { initSignals(); - initExistingSubsurfaces(pOwner->m_sWLSurface.wlr()); + initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); } -CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { - m_sWLSurface.assign(pSubsurface->surface, this); +CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { + m_pWLSurface = CWLSurface::create(); + m_pWLSurface->assign(pSubsurface->surface.lock(), this); initSignals(); - initExistingSubsurfaces(pSubsurface->surface); + initExistingSubsurfaces(pSubsurface->surface.lock()); } -CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { - m_sWLSurface.assign(pSubsurface->surface, this); +CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { + m_pWLSurface = CWLSurface::create(); + m_pWLSurface->assign(pSubsurface->surface.lock(), this); initSignals(); - initExistingSubsurfaces(pSubsurface->surface); + initExistingSubsurfaces(pSubsurface->surface.lock()); } CSubsurface::~CSubsurface() { @@ -33,52 +35,27 @@ CSubsurface::~CSubsurface() { if (!m_pSubsurface) return; - m_pSubsurface->data = nullptr; - hyprListener_commitSubsurface.removeCallback(); hyprListener_destroySubsurface.removeCallback(); } -static void onNewSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onNewSubsurface((wlr_subsurface*)data); -} - -static void onDestroySubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onDestroy(); -} - -static void onCommitSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onCommit(); -} - -static void onMapSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onMap(); -} - -static void onUnmapSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onUnmap(); -} - void CSubsurface::initSignals() { if (m_pSubsurface) { - m_pSubsurface->data = this; - hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface"); - hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface"); - hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface"); - hyprListener_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface"); - hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface"); + listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); }); + listeners.destroySubsurface = m_pSubsurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); + listeners.mapSubsurface = m_pSubsurface->surface->events.map.registerListener([this](std::any d) { onMap(); }); + listeners.unmapSubsurface = m_pSubsurface->surface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); + listeners.newSubsurface = + m_pSubsurface->surface->events.newSubsurface.registerListener([this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); } else { - if (!m_pWindowParent.expired()) - hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head"); + if (m_pWindowParent) + listeners.newSubsurface = m_pWindowParent->m_pWLSurface->resource()->events.newSubsurface.registerListener( + [this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); else if (m_pPopupParent) - hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head"); + listeners.newSubsurface = m_pPopupParent->m_pWLSurface->resource()->events.newSubsurface.registerListener( + [this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); else - RASSERT(false, "CSubsurface::initSignals empty subsurface"); + ASSERT(false); } } @@ -93,21 +70,21 @@ void CSubsurface::checkSiblingDamage() { continue; const auto COORDS = n->coordsGlobal(); - g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE); + g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y, SCALE); } } void CSubsurface::recheckDamageForSubsurfaces() { for (auto& n : m_vChildren) { const auto COORDS = n->coordsGlobal(); - g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y); + g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y); } } void CSubsurface::onCommit() { // no damaging if it's not visible if (!m_pWindowParent.expired() && (!m_pWindowParent->m_bIsMapped || !m_pWindowParent->m_pWorkspace->m_bVisible)) { - m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + m_vLastSize = m_pWLSurface->resource()->current.size; static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage"); if (*PLOGDAMAGE) @@ -117,7 +94,7 @@ void CSubsurface::onCommit() { const auto COORDS = coordsGlobal(); - g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y); + g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); if (m_pPopupParent) m_pPopupParent->recheckTree(); @@ -127,10 +104,10 @@ void CSubsurface::onCommit() { // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) checkSiblingDamage(); - if (m_vLastSize != Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}) { + if (m_vLastSize != m_pWLSurface->resource()->current.size) { CBox box{COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box); - m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + m_vLastSize = m_pWLSurface->resource()->current.size; box = {COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box); } @@ -149,20 +126,21 @@ void CSubsurface::onDestroy() { std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; }); } -void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) { +void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) { CSubsurface* PSUBSURFACE = nullptr; if (!m_pWindowParent.expired()) PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent.lock())).get(); else if (m_pPopupParent) PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get(); - PSUBSURFACE->m_pParent = this; ASSERT(PSUBSURFACE); + + PSUBSURFACE->m_pParent = this; } void CSubsurface::onMap() { - m_vLastSize = {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + m_vLastSize = m_pWLSurface->resource()->current.size; const auto COORDS = coordsGlobal(); CBox box{COORDS, m_vLastSize}; @@ -179,7 +157,7 @@ void CSubsurface::onUnmap() { box.expand(4); g_pHyprRenderer->damageBox(&box); - if (m_sWLSurface.wlr() == g_pCompositor->m_pLastFocus) + if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus) g_pInputManager->releaseAllMouseButtons(); g_pInputManager->simulateMouseMovement(); @@ -188,19 +166,9 @@ void CSubsurface::onUnmap() { } Vector2D CSubsurface::coordsRelativeToParent() { - Vector2D offset; - - CSubsurface* current = this; - - while (current->m_pParent) { - - offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy}; - offset += {current->m_pSubsurface->current.x, current->m_pSubsurface->current.y}; - - current = current->m_pParent; - } - - return offset; + if (!m_pSubsurface) + return {}; + return m_pSubsurface->posRelativeToParent(); } Vector2D CSubsurface::coordsGlobal() { @@ -214,18 +182,16 @@ Vector2D CSubsurface::coordsGlobal() { return coords; } -void CSubsurface::initExistingSubsurfaces(wlr_surface* pSurface) { - wlr_subsurface* wlrSubsurface; - wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) { - ::onNewSubsurface(this, wlrSubsurface); - } - wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) { - ::onNewSubsurface(this, wlrSubsurface); +void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) { + for (auto& s : pSurface->subsurfaces) { + if (!s || s->surface->hlSurface /* already assigned */) + continue; + onNewSubsurface(s.lock()); } } Vector2D CSubsurface::size() { - return {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + return m_pWLSurface->resource()->current.size; } bool CSubsurface::visible() { diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index f3a5ea4b..101f4f19 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -5,6 +5,7 @@ #include "WLSurface.hpp" class CPopup; +class CWLSubsurfaceResource; class CSubsurface { public: @@ -13,8 +14,8 @@ class CSubsurface { CSubsurface(CPopup* pOwner); // real nodes - CSubsurface(wlr_subsurface* pSubsurface, PHLWINDOW pOwner); - CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner); + CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner); + CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner); ~CSubsurface(); @@ -25,7 +26,7 @@ class CSubsurface { void onCommit(); void onDestroy(); - void onNewSubsurface(wlr_subsurface* pSubsurface); + void onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface); void onMap(); void onUnmap(); @@ -37,12 +38,18 @@ class CSubsurface { DYNLISTENER(destroySubsurface); DYNLISTENER(commitSubsurface); DYNLISTENER(newSubsurface); - DYNLISTENER(mapSubsurface); - DYNLISTENER(unmapSubsurface); - wlr_subsurface* m_pSubsurface = nullptr; - CWLSurface m_sWLSurface; - Vector2D m_vLastSize = {}; + struct { + CHyprSignalListener destroySubsurface; + CHyprSignalListener commitSubsurface; + CHyprSignalListener mapSubsurface; + CHyprSignalListener unmapSubsurface; + CHyprSignalListener newSubsurface; + } listeners; + + WP<CWLSubsurfaceResource> m_pSubsurface; + SP<CWLSurface> m_pWLSurface; + Vector2D m_vLastSize = {}; // if nullptr, means it's a dummy node CSubsurface* m_pParent = nullptr; @@ -55,6 +62,6 @@ class CSubsurface { bool m_bInert = false; void initSignals(); - void initExistingSubsurfaces(wlr_surface* pSurface); + void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface); void checkSiblingDamage(); };
\ No newline at end of file diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 78b50d45..c7a09b40 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -1,36 +1,37 @@ #include "WLSurface.hpp" #include "../Compositor.hpp" +#include "../protocols/core/Compositor.hpp" -void CWLSurface::assign(wlr_surface* pSurface) { - m_pWLRSurface = pSurface; +void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) { + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, PHLWINDOW pOwner) { +void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner) { m_pWindowOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, PHLLS pOwner) { +void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner) { m_pLayerOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, CSubsurface* pOwner) { +void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner) { m_pSubsurfaceOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, CPopup* pOwner) { +void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner) { m_pPopupOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } @@ -44,20 +45,23 @@ CWLSurface::~CWLSurface() { } bool CWLSurface::exists() const { - return m_pWLRSurface; + return m_pResource; } -wlr_surface* CWLSurface::wlr() const { - return m_pWLRSurface; +SP<CWLSurfaceResource> CWLSurface::resource() const { + return m_pResource.lock(); } bool CWLSurface::small() const { if (!validMapped(m_pWindowOwner) || !exists()) return false; + if (!m_pResource->current.buffer) + return false; + const auto O = m_pWindowOwner.lock(); - return O->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || O->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1; + return O->m_vReportedSize.x > m_pResource->current.buffer->size.x + 1 || O->m_vReportedSize.y > m_pResource->current.buffer->size.y + 1; } Vector2D CWLSurface::correctSmallVec() const { @@ -71,29 +75,28 @@ Vector2D CWLSurface::correctSmallVec() const { } Vector2D CWLSurface::getViewporterCorrectedSize() const { - if (!exists()) + if (!exists() || !m_pResource->current.buffer) return {}; - return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} : - Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height}; + return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size; } CRegion CWLSurface::logicalDamage() const { - CRegion damage{&m_pWLRSurface->buffer_damage}; - damage.transform(m_pWLRSurface->current.transform, m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height); - damage.scale(1.0 / m_pWLRSurface->current.scale); + if (!m_pResource->current.buffer) + return {}; + + CRegion damage = m_pResource->accumulateCurrentBufferDamage(); + damage.transform(m_pResource->current.transform, m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); + damage.scale(1.0 / m_pResource->current.scale); const auto VPSIZE = getViewporterCorrectedSize(); const auto CORRECTVEC = correctSmallVec(); - if (m_pWLRSurface->current.viewport.has_src) { - damage.intersect(CBox{std::floor(m_pWLRSurface->current.viewport.src.x), std::floor(m_pWLRSurface->current.viewport.src.y), - std::ceil(m_pWLRSurface->current.viewport.src.width), std::ceil(m_pWLRSurface->current.viewport.src.height)}); - } + if (m_pResource->current.viewport.hasSource) + damage.intersect(m_pResource->current.viewport.source); - const auto SCALEDSRCSIZE = m_pWLRSurface->current.viewport.has_src ? - Vector2D{m_pWLRSurface->current.viewport.src.width, m_pWLRSurface->current.viewport.src.height} * m_pWLRSurface->current.scale : - Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height}; + const auto SCALEDSRCSIZE = + m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size; damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y}); damage.translate(CORRECTVEC); @@ -102,48 +105,38 @@ CRegion CWLSurface::logicalDamage() const { } void CWLSurface::destroy() { - if (!m_pWLRSurface) + if (!m_pResource) return; events.destroy.emit(); m_pConstraint.reset(); - hyprListener_destroy.removeCallback(); - hyprListener_commit.removeCallback(); - m_pWLRSurface->data = nullptr; + listeners.destroy.reset(); + m_pResource->hlSurface.reset(); m_pWindowOwner.reset(); m_pLayerOwner.reset(); m_pPopupOwner = nullptr; m_pSubsurfaceOwner = nullptr; m_bInert = true; - if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface) - g_pCompositor->m_pLastFocus = nullptr; - if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == this) + if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf && g_pHyprRenderer->m_sLastCursorData.surf->get() == this) g_pHyprRenderer->m_sLastCursorData.surf.reset(); - m_pWLRSurface = nullptr; + m_pResource.reset(); Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this); } -static void onCommit(void* owner, void* data) { - const auto SURF = (CWLSurface*)owner; - SURF->onCommit(); -} - void CWLSurface::init() { - if (!m_pWLRSurface) + if (!m_pResource) return; - RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!"); + RASSERT(!m_pResource->hlSurface, "Attempted to duplicate CWLSurface ownership!"); - m_pWLRSurface->data = this; + m_pResource->hlSurface = self.lock(); - hyprListener_destroy.initCallback( - &m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface"); - hyprListener_commit.initCallback(&m_pWLRSurface->events.commit, ::onCommit, this, "CWLSurface"); + listeners.destroy = m_pResource->events.destroy.registerListener([this](std::any d) { destroy(); }); Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); } @@ -188,10 +181,6 @@ void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) { m_pConstraint = constraint; } -void CWLSurface::onCommit() { - ; -} - SP<CPointerConstraint> CWLSurface::constraint() { return m_pConstraint.lock(); } @@ -207,3 +196,9 @@ bool CWLSurface::visible() { return m_pSubsurfaceOwner->visible(); return true; // non-desktop, we don't know much. } + +SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) { + if (!pSurface) + return nullptr; + return pSurface->hlSurface.lock(); +} diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 03e81b45..4ba381a9 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -7,33 +7,37 @@ class CSubsurface; class CPopup; class CPointerConstraint; +class CWLSurfaceResource; class CWLSurface { public: - CWLSurface() = default; + static SP<CWLSurface> create() { + auto p = SP<CWLSurface>(new CWLSurface); + p->self = p; + return p; + } ~CWLSurface(); // anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD - void assign(wlr_surface* pSurface); - void assign(wlr_surface* pSurface, PHLWINDOW pOwner); - void assign(wlr_surface* pSurface, PHLLS pOwner); - void assign(wlr_surface* pSurface, CSubsurface* pOwner); - void assign(wlr_surface* pSurface, CPopup* pOwner); + void assign(SP<CWLSurfaceResource> pSurface); + void assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner); + void assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner); + void assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner); + void assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner); void unassign(); - CWLSurface(const CWLSurface&) = delete; - CWLSurface(CWLSurface&&) = delete; - CWLSurface& operator=(const CWLSurface&) = delete; - CWLSurface& operator=(CWLSurface&&) = delete; + CWLSurface(const CWLSurface&) = delete; + CWLSurface(CWLSurface&&) = delete; + CWLSurface& operator=(const CWLSurface&) = delete; + CWLSurface& operator=(CWLSurface&&) = delete; - wlr_surface* wlr() const; - bool exists() const; - bool small() const; // means surface is smaller than the requested size - Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces - Vector2D getViewporterCorrectedSize() const; - CRegion logicalDamage() const; - void onCommit(); - bool visible(); + SP<CWLSurfaceResource> resource() const; + bool exists() const; + bool small() const; // means surface is smaller than the requested size + Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces + Vector2D getViewporterCorrectedSize() const; + CRegion logicalDamage() const; + bool visible(); // getters for owners. PHLWINDOW getWindow(); @@ -55,31 +59,27 @@ class CWLSurface { wl_output_transform m_eLastTransform = (wl_output_transform)-1; // - CWLSurface& operator=(wlr_surface* pSurface) { + CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) { destroy(); - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); return *this; } bool operator==(const CWLSurface& other) const { - return other.wlr() == wlr(); + return other.resource() == resource(); } - bool operator==(const wlr_surface* other) const { - return other == wlr(); + bool operator==(const SP<CWLSurfaceResource> other) const { + return other == resource(); } explicit operator bool() const { return exists(); } - static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) { - if (!pSurface) - return nullptr; - return (CWLSurface*)pSurface->data; - } + static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface); // used by the alpha-modifier protocol float m_pAlphaModifier = 1.F; @@ -88,15 +88,19 @@ class CWLSurface { CSignal destroy; } events; + WP<CWLSurface> self; + private: - bool m_bInert = true; + CWLSurface() = default; + + bool m_bInert = true; - wlr_surface* m_pWLRSurface = nullptr; + WP<CWLSurfaceResource> m_pResource; - PHLWINDOWREF m_pWindowOwner; - PHLLSREF m_pLayerOwner; - CPopup* m_pPopupOwner = nullptr; - CSubsurface* m_pSubsurfaceOwner = nullptr; + PHLWINDOWREF m_pWindowOwner; + PHLLSREF m_pLayerOwner; + CPopup* m_pPopupOwner = nullptr; + CSubsurface* m_pSubsurfaceOwner = nullptr; // WP<CPointerConstraint> m_pConstraint; @@ -105,8 +109,9 @@ class CWLSurface { void init(); bool desktopComponent(); - DYNLISTENER(destroy); - DYNLISTENER(commit); + struct { + CHyprSignalListener destroy; + } listeners; friend class CPointerConstraint; };
\ No newline at end of file diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index c478b766..5d6e32e9 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -9,6 +9,7 @@ #include "../config/ConfigValue.hpp" #include "../managers/TokenManager.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) { @@ -51,12 +52,14 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) { pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow)); pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow)); - pWindow->m_pWLSurface.assign(pWindow->m_pXDGSurface->surface, pWindow); + pWindow->m_pWLSurface->assign(pWindow->m_pXDGSurface->surface.lock(), pWindow); return pWindow; } CWindow::CWindow(SP<CXDGSurfaceResource> resource) : m_pXDGSurface(resource) { + m_pWLSurface = CWLSurface::create(); + listeners.map = m_pXDGSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); listeners.ack = m_pXDGSurface->events.ack.registerListener([this](std::any d) { onAck(std::any_cast<uint32_t>(d)); }); listeners.unmap = m_pXDGSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); @@ -67,6 +70,8 @@ CWindow::CWindow(SP<CXDGSurfaceResource> resource) : m_pXDGSurface(resource) { } CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) { + m_pWLSurface = CWLSurface::create(); + listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); @@ -83,7 +88,7 @@ CWindow::CWindow(SP<CXWaylandSurface> surface) : m_pXWaylandSurface(surface) { CWindow::~CWindow() { if (g_pCompositor->m_pLastWindow.lock().get() == this) { - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pCompositor->m_pLastWindow.reset(); } @@ -124,12 +129,12 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) maxExtents.bottomRight.y = EXTENTS.bottomRight.y; - if (m_pWLSurface.exists() && !m_bIsX11 && m_pPopupHead) { + if (m_pWLSurface->exists() && !m_bIsX11 && m_pPopupHead) { CBox surfaceExtents = {0, 0, 0, 0}; // TODO: this could be better, perhaps make a getFullWindowRegion? m_pPopupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; CBox* pSurfaceExtents = (CBox*)data; @@ -151,11 +156,11 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { if (-surfaceExtents.y > maxExtents.topLeft.y) maxExtents.topLeft.y = -surfaceExtents.y; - if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface.wlr()->current.width + maxExtents.bottomRight.x) - maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface.wlr()->current.width; + if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface->resource()->current.size.x + maxExtents.bottomRight.x) + maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface->resource()->current.size.x; - if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface.wlr()->current.height + maxExtents.bottomRight.y) - maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface.wlr()->current.height; + if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface->resource()->current.size.y + maxExtents.bottomRight.y) + maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface->resource()->current.size.y; } return maxExtents; @@ -340,17 +345,7 @@ void CWindow::updateToplevel() { updateSurfaceScaleTransformDetails(); } -void sendEnterIter(wlr_surface* pSurface, int x, int y, void* data) { - const auto OUTPUT = (wlr_output*)data; - wlr_surface_send_enter(pSurface, OUTPUT); -} - -void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) { - const auto OUTPUT = (wlr_output*)data; - wlr_surface_send_leave(pSurface, OUTPUT); -} - -void CWindow::updateSurfaceScaleTransformDetails() { +void CWindow::updateSurfaceScaleTransformDetails(bool force) { if (!m_bIsMapped || m_bHidden || g_pCompositor->m_bUnsafeState) return; @@ -363,26 +358,25 @@ void CWindow::updateSurfaceScaleTransformDetails() { if (!PNEWMONITOR) return; - if (PNEWMONITOR != PLASTMONITOR) { - if (PLASTMONITOR && PLASTMONITOR->m_bEnabled) - wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output); + if (PNEWMONITOR != PLASTMONITOR || force) { + if (PLASTMONITOR && PLASTMONITOR->m_bEnabled && PNEWMONITOR != PLASTMONITOR) + m_pWLSurface->resource()->breadthfirst([PLASTMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->leave(PLASTMONITOR->self.lock()); }, nullptr); - wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output); + m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr); } - wlr_surface_for_each_surface( - m_pWLSurface.wlr(), - [](wlr_surface* surf, int x, int y, void* data) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID); + m_pWLSurface->resource()->breadthfirst( + [this](SP<CWLSurfaceResource> s, const Vector2D& offset, void* d) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - const auto PSURFACE = CWLSurface::surfaceFromWlr(surf); + const auto PSURFACE = CWLSurface::fromResource(s); if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale) return; - g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(s, PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(s, PMONITOR->transform); }, - this); + nullptr); } void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { @@ -568,6 +562,8 @@ void CWindow::onMap() { m_vReportedSize = m_vPendingReportedSize; m_bAnimatingIn = true; + updateSurfaceScaleTransformDetails(true); + if (m_bIsX11) return; @@ -860,7 +856,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) { CPopup* popup = m_pPopupHead->at(pos); - return popup && popup->m_sWLSurface.wlr(); + return popup && popup->m_pWLSurface->resource(); } void CWindow::applyGroupRules() { @@ -1135,23 +1131,24 @@ bool CWindow::opaque() { const auto PWORKSPACE = m_pWorkspace; - if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall) + if (m_pWLSurface->small() && !m_pWLSurface->m_bFillIgnoreSmall) return false; if (PWORKSPACE->m_fAlpha.value() != 1.f) return false; - if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface) - return m_pXWaylandSurface->surface->opaque; + if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer) + return m_pXWaylandSurface->surface->current.buffer->opaque; - if (m_pXDGSurface && m_pXDGSurface->surface->opaque) - return true; + if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.buffer) + return false; - const auto EXTENTS = pixman_region32_extents(&m_pXDGSurface->surface->opaque_region); - if (EXTENTS->x2 - EXTENTS->x1 >= m_pXDGSurface->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_pXDGSurface->surface->current.buffer_height) + // TODO: this is wrong + const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents(); + if (EXTENTS.w >= m_pXDGSurface->surface->current.buffer->size.x && EXTENTS.h >= m_pXDGSurface->surface->current.buffer->size.y) return true; - return false; + return m_pWLSurface->resource()->current.buffer->opaque; } float CWindow::rounding() { @@ -1282,8 +1279,7 @@ int CWindow::surfacesCount() { return 1; int no = 0; - wlr_surface_for_each_surface( - m_pWLSurface.wlr(), [](wlr_surface* surf, int x, int y, void* data) { *((int*)data) += 1; }, &no); + m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { *((int*)d) += 1; }, &no); return no; } @@ -1456,16 +1452,16 @@ void CWindow::onAck(uint32_t serial) { } void CWindow::onResourceChangeX11() { - if (m_pXWaylandSurface->surface && !m_pWLSurface.wlr()) - m_pWLSurface.assign(m_pXWaylandSurface->surface, m_pSelf.lock()); - else if (!m_pXWaylandSurface->surface && m_pWLSurface.wlr()) - m_pWLSurface.unassign(); + if (m_pXWaylandSurface->surface && !m_pWLSurface->resource()) + m_pWLSurface->assign(m_pXWaylandSurface->surface.lock(), m_pSelf.lock()); + else if (!m_pXWaylandSurface->surface && m_pWLSurface->resource()) + m_pWLSurface->unassign(); // update metadata as well, // could be first assoc and we need to catch the class onUpdateMeta(); - Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface.wlr()); + Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get()); } void CWindow::onX11Configure(CBox box) { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 151d9809..85c74622 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -213,7 +213,7 @@ class CWindow { public: ~CWindow(); - CWLSurface m_pWLSurface; + SP<CWLSurface> m_pWLSurface; struct { CSignal destroy; @@ -396,7 +396,7 @@ class CWindow { IHyprWindowDecoration* getDecorationByType(eDecorationType); void removeDecorationByType(eDecorationType); void updateToplevel(); - void updateSurfaceScaleTransformDetails(); + void updateSurfaceScaleTransformDetails(bool force = false); void moveToWorkspace(PHLWORKSPACE); PHLWINDOW X11TransientFor(); void onUnmap(); diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp index f5b610a9..b5ab16c1 100644 --- a/src/devices/Tablet.cpp +++ b/src/devices/Tablet.cpp @@ -1,6 +1,7 @@ #include "Tablet.hpp" #include "../defines.hpp" #include "../protocols/Tablet.hpp" +#include "../protocols/core/Compositor.hpp" SP<CTablet> CTablet::create(wlr_tablet* tablet) { SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet)); @@ -295,32 +296,29 @@ CTabletTool::~CTabletTool() { void CTabletTool::disconnectCallbacks() { hyprListener_destroy.removeCallback(); - hyprListener_destroySurface.removeCallback(); + listeners.destroySurface.reset(); } -wlr_surface* CTabletTool::getSurface() { - return pSurface; +SP<CWLSurfaceResource> CTabletTool::getSurface() { + return pSurface.lock(); } -void CTabletTool::setSurface(wlr_surface* surf) { +void CTabletTool::setSurface(SP<CWLSurfaceResource> surf) { if (surf == pSurface) return; if (pSurface) { - hyprListener_destroySurface.removeCallback(); - pSurface = nullptr; + listeners.destroySurface.reset(); + pSurface.reset(); } pSurface = surf; if (surf) { - hyprListener_destroySurface.initCallback( - &surf->events.destroy, - [this](void* owner, void* data) { - PROTO::tablet->proximityOut(self.lock()); - pSurface = nullptr; - hyprListener_destroySurface.removeCallback(); - }, - this, "CTabletTool"); + listeners.destroySurface = surf->events.destroy.registerListener([this](std::any d) { + PROTO::tablet->proximityOut(self.lock()); + pSurface.reset(); + listeners.destroySurface.reset(); + }); } } diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index f2444972..1805f3ba 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -12,6 +12,7 @@ struct wlr_tablet_pad; class CTabletTool; class CTabletPad; +class CWLSurfaceResource; /* A tablet device @@ -197,32 +198,35 @@ class CTabletTool : public IHID { HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5), }; - virtual uint32_t getCapabilities(); - wlr_tablet_tool* wlr(); - virtual eHIDType getType(); - wlr_surface* getSurface(); - void setSurface(wlr_surface*); + virtual uint32_t getCapabilities(); + wlr_tablet_tool* wlr(); + virtual eHIDType getType(); + SP<CWLSurfaceResource> getSurface(); + void setSurface(SP<CWLSurfaceResource>); - WP<CTabletTool> self; - Vector2D tilt; - bool active = false; // true if in proximity - uint32_t toolCapabilities = 0; + WP<CTabletTool> self; + Vector2D tilt; + bool active = false; // true if in proximity + uint32_t toolCapabilities = 0; - bool isDown = false; - std::vector<uint32_t> buttonsDown; - Vector2D absolutePos; // last known absolute position. + bool isDown = false; + std::vector<uint32_t> buttonsDown; + Vector2D absolutePos; // last known absolute position. - std::string hlName; + std::string hlName; private: CTabletTool(wlr_tablet_tool* tool); - void disconnectCallbacks(); + void disconnectCallbacks(); - wlr_surface* pSurface = nullptr; + WP<CWLSurfaceResource> pSurface; - wlr_tablet_tool* tool = nullptr; + wlr_tablet_tool* tool = nullptr; DYNLISTENER(destroy); - DYNLISTENER(destroySurface); + + struct { + CHyprSignalListener destroySurface; + } listeners; };
\ No newline at end of file diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 5372a105..88b28c87 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -9,6 +9,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" // ------------------------------------------------------------ // @@ -104,7 +105,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // registers the animated vars and stuff PWINDOW->onMap(); - const auto PWINDOWSURFACE = PWINDOW->m_pWLSurface.wlr(); + const auto PWINDOWSURFACE = PWINDOW->m_pWLSurface->resource(); if (!PWINDOWSURFACE) { g_pCompositor->removeWindowFromVectorSafe(PWINDOW); @@ -463,7 +464,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // check LS focus grab const auto PFORCEFOCUS = g_pCompositor->getForceFocus(); - const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); + const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) PWINDOW->m_bNoInitialFocus = true; if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) { @@ -618,8 +619,8 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating) PWINDOW->m_fAlpha.setValueAndWarp(0.f); - g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform); if (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) g_pInputManager->sendMotionEventsToFocused(); @@ -638,7 +639,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { Debug::log(LOG, "{:c} unmapped", PWINDOW); - if (!PWINDOW->m_pWLSurface.exists() || !PWINDOW->m_bIsMapped) { + if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) { Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); PWINDOW->m_bFadingOut = false; return; @@ -674,7 +675,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { wasLastWindow = true; g_pCompositor->m_pLastWindow.reset(); - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pInputManager->releaseAllMouseButtons(); } @@ -788,7 +789,7 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_pWorkspace->m_bVisible) return; - g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, + g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); if (!PWINDOW->m_bIsX11) { @@ -798,9 +799,8 @@ void Events::listener_commitWindow(void* owner, void* data) { // tearing: if solitary, redraw it. This still might be a single surface window const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); - if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && - PWINDOW->m_pWLSurface.wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) { - CRegion damageBox{&PWINDOW->m_pWLSurface.wlr()->buffer_damage}; + if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) { + CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.bufferDamage}; if (!damageBox.empty()) { if (PMONITOR->tearingState.busy) { @@ -820,10 +820,10 @@ void Events::listener_destroyWindow(void* owner, void* data) { if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { g_pCompositor->m_pLastWindow.reset(); - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); } - PWINDOW->m_pWLSurface.unassign(); + PWINDOW->m_pWLSurface->unassign(); PWINDOW->listeners = {}; diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp new file mode 100644 index 00000000..3d6b7cc3 --- /dev/null +++ b/src/helpers/Format.cpp @@ -0,0 +1,271 @@ +#include "Format.hpp" +#include <vector> +#include "../includes.hpp" + +/* + DRM formats are LE, while OGL is BE. The two primary formats + will be flipped, so we will set flipRB which will later use swizzle + to flip the red and blue channels. + This will not work on GLES2, but I want to drop support for it one day anyways. +*/ +inline const std::vector<SPixelFormat> GLES3_FORMATS = { + { + .drmFormat = DRM_FORMAT_ARGB8888, + .flipRB = true, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XRGB8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XRGB8888, + .flipRB = true, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XRGB8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XBGR8888, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_ABGR8888, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_BGR888, + .glFormat = GL_RGB, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_BGR888, + .bytesPerBlock = 3, + }, + { + .drmFormat = DRM_FORMAT_RGBX4444, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_4_4_4_4, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_RGBX4444, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGBA4444, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_4_4_4_4, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_RGBX4444, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGBX5551, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_5_5_5_1, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_RGBX5551, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGBA5551, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_5_5_5_1, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_RGBX5551, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGB565, + .glFormat = GL_RGB, + .glType = GL_UNSIGNED_SHORT_5_6_5, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_RGB565, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_XBGR2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_ABGR2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XRGB2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XRGB2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_ARGB2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XRGB2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XBGR16161616F, + .glFormat = GL_RGBA, + .glType = GL_HALF_FLOAT, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR16161616F, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_ABGR16161616F, + .glFormat = GL_RGBA, + .glType = GL_HALF_FLOAT, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR16161616F, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_XBGR16161616, + .glInternalFormat = GL_RGBA16UI, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_ABGR16161616, + .glInternalFormat = GL_RGBA16UI, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_YVYU, + .bytesPerBlock = 4, + .blockSize = {2, 1}, + }, + { + .drmFormat = DRM_FORMAT_VYUY, + .bytesPerBlock = 4, + .blockSize = {2, 1}, + }, + { + .drmFormat = DRM_FORMAT_R8, + .bytesPerBlock = 1, + }, + { + .drmFormat = DRM_FORMAT_GR88, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGB888, + .bytesPerBlock = 3, + }, + { + .drmFormat = DRM_FORMAT_BGR888, + .bytesPerBlock = 3, + }, + { + .drmFormat = DRM_FORMAT_RGBX4444, + .bytesPerBlock = 2, + }, +}; + +SHMFormat FormatUtils::drmToShm(DRMFormat drm) { + switch (drm) { + case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888; + case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888; + default: return drm; + } + + return drm; +} + +DRMFormat FormatUtils::shmToDRM(SHMFormat shm) { + switch (shm) { + case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888; + case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888; + default: return shm; + } + + return shm; +} + +const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) { + for (auto& fmt : GLES3_FORMATS) { + if (fmt.drmFormat == drm) + return &fmt; + } + + return nullptr; +} + +const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) { + for (auto& fmt : GLES3_FORMATS) { + if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha) + return &fmt; + } + + return nullptr; +} + +bool FormatUtils::isFormatOpaque(DRMFormat drm) { + const auto FMT = FormatUtils::getPixelFormatFromDRM(drm); + if (!FMT) + return false; + + return !FMT->withAlpha; +} + +int FormatUtils::pixelsPerBlock(const SPixelFormat* const fmt) { + return fmt->blockSize.x * fmt->blockSize.y > 0 ? fmt->blockSize.x * fmt->blockSize.y : 1; +} + +int FormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) { + return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt)); +} + +uint32_t FormatUtils::drmFormatToGL(DRMFormat drm) { + switch (drm) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case. + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: +#ifdef GLES2 + return GL_RGB10_A2_EXT; +#else + return GL_RGB10_A2; +#endif + default: return GL_RGBA; + } + UNREACHABLE(); + return GL_RGBA; +} + +uint32_t FormatUtils::glFormatToType(uint32_t gl) { + return gl != GL_RGBA ? +#ifdef GLES2 + GL_UNSIGNED_INT_2_10_10_10_REV_EXT : +#else + GL_UNSIGNED_INT_2_10_10_10_REV : +#endif + GL_UNSIGNED_BYTE; +} diff --git a/src/helpers/Format.hpp b/src/helpers/Format.hpp new file mode 100644 index 00000000..b86f44dd --- /dev/null +++ b/src/helpers/Format.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include <cstdint> +#include "Vector2D.hpp" + +typedef uint32_t DRMFormat; +typedef uint32_t SHMFormat; + +struct SPixelFormat { + DRMFormat drmFormat = 0; /* DRM_FORMAT_INVALID */ + bool flipRB = false; + int glInternalFormat = 0; + int glFormat = 0; + int glType = 0; + bool withAlpha = true; + DRMFormat alphaStripped = 0; /* DRM_FORMAT_INVALID */ + uint32_t bytesPerBlock = 0; + Vector2D blockSize; +}; + +struct SDRMFormat { + uint32_t format = 0; + std::vector<uint64_t> mods; +}; + +namespace FormatUtils { + SHMFormat drmToShm(DRMFormat drm); + DRMFormat shmToDRM(SHMFormat shm); + + const SPixelFormat* getPixelFormatFromDRM(DRMFormat drm); + const SPixelFormat* getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha); + bool isFormatOpaque(DRMFormat drm); + int pixelsPerBlock(const SPixelFormat* const fmt); + int minStride(const SPixelFormat* const fmt, int32_t width); + uint32_t drmFormatToGL(DRMFormat drm); + uint32_t glFormatToType(uint32_t gl); +}; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index a520c9d4..32cd9868 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -857,33 +857,6 @@ void throwError(const std::string& err) { throw std::runtime_error(err); } -uint32_t drmFormatToGL(uint32_t drm) { - switch (drm) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case. - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: -#ifdef GLES2 - return GL_RGB10_A2_EXT; -#else - return GL_RGB10_A2; -#endif - default: return GL_RGBA; - } - UNREACHABLE(); - return GL_RGBA; -} - -uint32_t glFormatToType(uint32_t gl) { - return gl != GL_RGBA ? -#ifdef GLES2 - GL_UNSIGNED_INT_2_10_10_10_REV_EXT : -#else - GL_UNSIGNED_INT_2_10_10_10_REV : -#endif - GL_UNSIGNED_BYTE; -} - bool envEnabled(const std::string& env) { const auto ENV = getenv(env.c_str()); if (!ENV) @@ -922,3 +895,42 @@ int allocateSHMFile(size_t len) { return fd; } + +bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { + auto [fd, name] = openExclusiveShm(); + if (fd < 0) { + return false; + } + + // CLOEXEC is guaranteed to be set by shm_open + int ro_fd = shm_open(name.c_str(), O_RDONLY, 0); + if (ro_fd < 0) { + shm_unlink(name.c_str()); + close(fd); + return false; + } + + shm_unlink(name.c_str()); + + // Make sure the file cannot be re-opened in read-write mode (e.g. via + // "/proc/self/fd/" on Linux) + if (fchmod(fd, 0) != 0) { + close(fd); + close(ro_fd); + return false; + } + + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(fd); + close(ro_fd); + return false; + } + + *rw_fd_ptr = fd; + *ro_fd_ptr = ro_fd; + return true; +} diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 80103eac..9d34174c 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -35,10 +35,9 @@ double normalizeAngleRad(double ang); std::string replaceInString(std::string subject, const std::string& search, const std::string& replace); std::vector<SCallstackFrameInfo> getBacktrace(); void throwError(const std::string& err); -uint32_t drmFormatToGL(uint32_t drm); -uint32_t glFormatToType(uint32_t gl); bool envEnabled(const std::string& env); int allocateSHMFile(size_t len); +bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); template <typename... Args> [[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) { diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index d13acf0c..5962b73d 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -216,7 +216,6 @@ void CMonitor::onConnect(bool noRule) { PROTO::gamma->applyGammaToState(this); events.connect.emit(); - updateGlobal(); } void CMonitor::onDisconnect(bool destroy) { @@ -284,8 +283,6 @@ void CMonitor::onDisconnect(bool destroy) { m_bEnabled = false; m_bRenderingInitPassed = false; - updateGlobal(); - if (BACKUPMON) { // snap cursor g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true); @@ -304,7 +301,7 @@ void CMonitor::onDisconnect(bool destroy) { w->startAnim(true, true, true); } } else { - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pCompositor->m_pLastWindow.reset(); g_pCompositor->m_pLastMonitor.reset(); } @@ -750,13 +747,6 @@ CBox CMonitor::logicalBox() { return {vecPosition, vecSize}; } -void CMonitor::updateGlobal() { - if (output->width > 0 && output->height > 0 && m_bEnabled) - wlr_output_create_global(output, g_pCompositor->m_sWLDisplay); - else - wlr_output_destroy_global(output); -} - CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; wlr_output_state_init(&m_state); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index e4456084..4bfbf53c 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -172,7 +172,6 @@ class CMonitor { int64_t activeWorkspaceID(); int64_t activeSpecialWorkspaceID(); CBox logicalBox(); - void updateGlobal(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/helpers/Region.cpp b/src/helpers/Region.cpp index 20eaf452..9e572b34 100644 --- a/src/helpers/Region.cpp +++ b/src/helpers/Region.cpp @@ -4,6 +4,8 @@ extern "C" { #include <wlr/util/region.h> } +constexpr const int64_t MAX_REGION_SIDE = 10000000; + CRegion::CRegion() { pixman_region32_init(&m_rRegion); } @@ -103,6 +105,11 @@ CRegion& CRegion::transform(const wl_output_transform t, double w, double h) { return *this; } +CRegion& CRegion::rationalize() { + intersect(CBox{-MAX_REGION_SIDE, -MAX_REGION_SIDE, MAX_REGION_SIDE * 2, MAX_REGION_SIDE * 2}); + return *this; +} + CRegion CRegion::copy() const { return CRegion(*this); } diff --git a/src/helpers/Region.hpp b/src/helpers/Region.hpp index 27f460f4..42693c21 100644 --- a/src/helpers/Region.hpp +++ b/src/helpers/Region.hpp @@ -50,6 +50,7 @@ class CRegion { CRegion& invert(const CBox& box); CRegion& scale(float scale); CRegion& scale(const Vector2D& scale); + CRegion& rationalize(); CBox getExtents(); bool containsPoint(const Vector2D& vec) const; bool empty() const; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 30f5aebf..d5be9f40 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -13,6 +13,7 @@ class CMonitor; class IPointer; class IKeyboard; +class CWLSurfaceResource; struct SRenderData { CMonitor* pMonitor; @@ -20,9 +21,9 @@ struct SRenderData { double x, y; // for iters - void* data = nullptr; - wlr_surface* surface = nullptr; - double w, h; + void* data = nullptr; + SP<CWLSurfaceResource> surface = nullptr; + double w, h; // for rounding bool dontRound = true; @@ -52,12 +53,6 @@ struct SRenderData { bool popup = false; }; -struct SExtensionFindingData { - Vector2D origin; - Vector2D vec; - wlr_surface** found; -}; - struct SSwipeGesture { PHLWORKSPACE pWorkspaceBegin = nullptr; diff --git a/src/helpers/memory/SharedPtr.hpp b/src/helpers/memory/SharedPtr.hpp index 77f5164a..02900911 100644 --- a/src/helpers/memory/SharedPtr.hpp +++ b/src/helpers/memory/SharedPtr.hpp @@ -60,7 +60,7 @@ namespace CSharedPointer_ { bool _destroying = false; void _destroy() { - if (!_data) + if (!_data || _destroying) return; // first, we destroy the data, but keep the pointer. @@ -297,6 +297,6 @@ static CSharedPointer<U> makeShared(Args&&... args) { template <typename T> struct std::hash<CSharedPointer<T>> { std::size_t operator()(const CSharedPointer<T>& p) const noexcept { - return std::hash<void*>{}(p->impl_); + return std::hash<void*>{}(p.impl_); } }; diff --git a/src/helpers/memory/WeakPtr.hpp b/src/helpers/memory/WeakPtr.hpp index f0e72146..872f8e55 100644 --- a/src/helpers/memory/WeakPtr.hpp +++ b/src/helpers/memory/WeakPtr.hpp @@ -185,6 +185,6 @@ class CWeakPointer { template <typename T> struct std::hash<CWeakPointer<T>> { std::size_t operator()(const CWeakPointer<T>& p) const noexcept { - return std::hash<void*>{}(p->impl_); + return std::hash<void*>{}(p.impl_); } }; diff --git a/src/helpers/signal/Signal.cpp b/src/helpers/signal/Signal.cpp index fdd2cc23..fd2d11c8 100644 --- a/src/helpers/signal/Signal.cpp +++ b/src/helpers/signal/Signal.cpp @@ -2,19 +2,40 @@ #include <algorithm> void CSignal::emit(std::any data) { - bool dirty = false; + bool dirty = false; + std::vector<SP<CSignalListener>> listeners; for (auto& l : m_vListeners) { - if (const CHyprSignalListener L = l.lock()) - L->emit(data); - else + if (l.expired()) { dirty = true; + continue; + } + + listeners.emplace_back(l.lock()); } + std::vector<CStaticSignalListener*> statics; for (auto& l : m_vStaticListeners) { + statics.emplace_back(l.get()); + } + + for (auto& l : listeners) { + // if there is only one lock, it means the event is only held by the listeners + // vector and was removed during our iteration + if (l.strongRef() == 1) { + dirty = true; + continue; + } l->emit(data); } + for (auto& l : statics) { + l->emit(data); + } + + // release SPs + listeners.clear(); + if (dirty) std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); }); } diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index d147a6bb..a325d858 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -22,6 +22,8 @@ CHyprError::CHyprError() { if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged) g_pHyprRenderer->damageBox(&m_bDamageBox); }); + + m_pTexture = makeShared<CTexture>(); } CHyprError::~CHyprError() { @@ -34,9 +36,8 @@ void CHyprError::queueCreate(std::string message, const CColor& color) { } void CHyprError::createQueued() { - if (m_bIsCreated) { - m_tTexture.destroyTexture(); - } + if (m_bIsCreated) + m_pTexture->destroyTexture(); m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); @@ -136,8 +137,8 @@ void CHyprError::createQueued() { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - m_tTexture.allocate(); - glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); + m_pTexture->allocate(); + glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -170,7 +171,7 @@ void CHyprError::draw() { if (!m_fFadeOpacity.isBeingAnimated()) { if (m_fFadeOpacity.value() == 0.f) { m_bQueuedDestroy = false; - m_tTexture.destroyTexture(); + m_pTexture->destroyTexture(); m_bIsCreated = false; m_szQueued = ""; return; @@ -193,7 +194,7 @@ void CHyprError::draw() { m_bMonitorChanged = false; - g_pHyprOpenGL->renderTexture(m_tTexture, &monbox, m_fFadeOpacity.value(), 0); + g_pHyprOpenGL->renderTexture(m_pTexture, &monbox, m_fFadeOpacity.value(), 0); } void CHyprError::destroy() { diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index aaa8bd12..8dbb4521 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -21,7 +21,7 @@ class CHyprError { CColor m_cQueued; bool m_bQueuedDestroy = false; bool m_bIsCreated = false; - CTexture m_tTexture; + SP<CTexture> m_pTexture; CAnimatedVariable<float> m_fFadeOpacity; CBox m_bDamageBox = {0, 0, 0, 0}; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 7fadf188..b4270bb8 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -5,6 +5,7 @@ #include "../config/ConfigValue.hpp" #include "../desktop/Window.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { @@ -99,8 +100,8 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { - const auto PWINDOWSURFACE = pWindow->m_pWLSurface.wlr(); - pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height); + const auto PWINDOWSURFACE = pWindow->m_pWLSurface->resource(); + pWindow->m_vRealSize = PWINDOWSURFACE->current.size; if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms? diff --git a/src/macros.hpp b/src/macros.hpp index 66dfe783..4c6d621c 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -89,4 +89,14 @@ } #else #define UNREACHABLE() std::unreachable(); -#endif
\ No newline at end of file +#endif + +#define GLCALL(__CALL__) \ + { \ + __CALL__; \ + auto err = glGetError(); \ + if (err != GL_NO_ERROR) { \ + Debug::log(ERR, "[GLES] Error in call at {}@{}: 0x{:x}", __LINE__, \ + ([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })(), err); \ + } \ + } diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index e3ebce80..4430d0f4 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -117,8 +117,8 @@ wlr_buffer* CCursorManager::getCursorBuffer() { return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr; } -void CCursorManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { - if (!surf || !surf->wlr()) +void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) { + if (!surf || !surf->resource()) g_pPointerManager->resetCursorImage(); else g_pPointerManager->setCursorSurface(surf, hotspot); diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index e76b6829..6fbff636 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -18,7 +18,7 @@ class CCursorManager { wlr_buffer* getCursorBuffer(); void setCursorFromName(const std::string& name); - void setCursorSurface(CWLSurface* surf, const Vector2D& hotspot); + void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot); void setXCursor(const std::string& name); bool changeTheme(const std::string& name, const int size); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index f7009afb..5811f4a1 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2003,14 +2003,14 @@ void CKeybindManager::pass(std::string regexp) { } const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; - const auto LASTSRF = g_pCompositor->m_pLastFocus; + const auto LASTSRF = g_pCompositor->m_pLastFocus.lock(); // pass all mf shit if (!XWTOXW) { if (g_pKeybindManager->m_uLastCode != 0) - g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr()); + g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface->resource()); else - g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1}); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), {1, 1}); } g_pSeatManager->sendKeyboardMods(g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0); @@ -2044,10 +2044,10 @@ void CKeybindManager::pass(std::string regexp) { // please kill me if (PWINDOW->m_bIsX11) { if (g_pKeybindManager->m_uLastCode != 0) { - g_pSeatManager->state.keyboardFocus = nullptr; + g_pSeatManager->state.keyboardFocus.reset(); g_pSeatManager->state.keyboardFocusResource.reset(); } else { - g_pSeatManager->state.pointerFocus = nullptr; + g_pSeatManager->state.pointerFocus.reset(); g_pSeatManager->state.pointerFocusResource.reset(); } } @@ -2057,7 +2057,7 @@ void CKeybindManager::pass(std::string regexp) { if (g_pKeybindManager->m_uLastCode != 0) g_pSeatManager->setKeyboardFocus(LASTSRF); else - g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), SL); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), SL); } void CKeybindManager::sendshortcut(std::string args) { @@ -2136,7 +2136,7 @@ void CKeybindManager::sendshortcut(std::string args) { const std::string regexp = ARGS[2]; PHLWINDOW PWINDOW = nullptr; - const auto LASTSURFACE = g_pCompositor->m_pLastFocus; + const auto LASTSURFACE = g_pCompositor->m_pLastFocus.lock(); //if regexp is not empty, send shortcut to current window //else, dont change focus @@ -2154,15 +2154,15 @@ void CKeybindManager::sendshortcut(std::string args) { } if (!isMouse) - g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr()); + g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface->resource()); else - g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1}); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), {1, 1}); } //copied the rest from pass and modified it // if wl -> xwl, activate destination if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsX11) - g_pXWaylandManager->activateSurface(PWINDOW->m_pWLSurface.wlr(), true); + g_pXWaylandManager->activateSurface(PWINDOW->m_pWLSurface->resource(), true); // if xwl -> xwl, send to current. Timing issues make this not work. if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) PWINDOW = nullptr; @@ -2195,10 +2195,10 @@ void CKeybindManager::sendshortcut(std::string args) { if (PWINDOW->m_bIsX11) { //xwayland hack, see pass if (!isMouse) { - g_pSeatManager->state.keyboardFocus = nullptr; + g_pSeatManager->state.keyboardFocus.reset(); g_pSeatManager->state.keyboardFocusResource.reset(); } else { - g_pSeatManager->state.pointerFocus = nullptr; + g_pSeatManager->state.pointerFocus.reset(); g_pSeatManager->state.pointerFocusResource.reset(); } } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 66d12076..80a7ee76 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/PointerGestures.hpp" #include "../protocols/FractionalScale.hpp" +#include "../protocols/core/Compositor.hpp" #include "SeatManager.hpp" #include <wlr/interfaces/wlr_output.h> #include <wlr/render/interface.h> @@ -212,13 +213,13 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, damageIfSoftware(); } -void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { +void CPointerManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) { damageIfSoftware(); if (surf == currentCursorImage.surface) { - if (hotspot != currentCursorImage.hotspot || (surf && surf->wlr() ? surf->wlr()->current.scale : 1.F) != currentCursorImage.scale) { + if (hotspot != currentCursorImage.hotspot || (surf && surf->resource() ? surf->resource()->current.scale : 1.F) != currentCursorImage.scale) { currentCursorImage.hotspot = hotspot; - currentCursorImage.scale = surf && surf->wlr() ? surf->wlr()->current.scale : 1.F; + currentCursorImage.scale = surf && surf->resource() ? surf->resource()->current.scale : 1.F; updateCursorBackend(); damageIfSoftware(); } @@ -229,27 +230,24 @@ void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot resetCursorImage(false); if (surf) { - currentCursorImage.size = {surf->wlr()->current.buffer_width, surf->wlr()->current.buffer_height}; currentCursorImage.surface = surf; - currentCursorImage.scale = surf->wlr()->current.scale; + currentCursorImage.scale = surf->resource()->current.scale; currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); }); - currentCursorImage.hyprListener_commitSurface.initCallback( - &surf->wlr()->events.commit, - [this](void* owner, void* data) { - damageIfSoftware(); - currentCursorImage.size = {currentCursorImage.surface->wlr()->current.buffer_width, currentCursorImage.surface->wlr()->current.buffer_height}; - currentCursorImage.scale = currentCursorImage.surface && currentCursorImage.surface->wlr() ? currentCursorImage.surface->wlr()->current.scale : 1.F; - recheckEnteredOutputs(); - updateCursorBackend(); - damageIfSoftware(); - }, - nullptr, "CPointerManager"); + currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) { + damageIfSoftware(); + currentCursorImage.size = currentCursorImage.surface->resource()->current.buffer ? currentCursorImage.surface->resource()->current.buffer->size : Vector2D{}; + currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F; + recheckEnteredOutputs(); + updateCursorBackend(); + damageIfSoftware(); + }); - if (wlr_surface_has_buffer(surf->wlr())) { + if (surf->resource()->current.buffer) { + currentCursorImage.size = surf->resource()->current.buffer->size; timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(surf->wlr(), &now); + surf->resource()->frame(&now); } } @@ -278,9 +276,9 @@ void CPointerManager::recheckEnteredOutputs() { if (!currentCursorImage.surface) continue; - wlr_surface_send_enter(currentCursorImage.surface->wlr(), s->monitor->output); - PROTO::fractional->sendScale(currentCursorImage.surface->wlr(), s->monitor->scale); - g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->wlr(), s->monitor->scale); + currentCursorImage.surface->resource()->enter(s->monitor.lock()); + PROTO::fractional->sendScale(currentCursorImage.surface->resource(), s->monitor->scale); + g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->resource(), s->monitor->scale); } else if (s->entered && !overlaps) { s->entered = false; @@ -293,7 +291,7 @@ void CPointerManager::recheckEnteredOutputs() { if (!currentCursorImage.surface) continue; - wlr_surface_send_leave(currentCursorImage.surface->wlr(), s->monitor->output); + currentCursorImage.surface->resource()->leave(s->monitor.lock()); } } } @@ -303,12 +301,12 @@ void CPointerManager::resetCursorImage(bool apply) { if (currentCursorImage.surface) { for (auto& m : g_pCompositor->m_vMonitors) { - wlr_surface_send_leave(currentCursorImage.surface->wlr(), m->output); + currentCursorImage.surface->resource()->leave(m); } currentCursorImage.destroySurface.reset(); - currentCursorImage.hyprListener_commitSurface.removeCallback(); - currentCursorImage.surface = nullptr; + currentCursorImage.commitSurface.reset(); + currentCursorImage.surface.reset(); } else if (currentCursorImage.pBuffer) { wlr_buffer_unlock(currentCursorImage.pBuffer); currentCursorImage.hyprListener_destroyBuffer.removeCallback(); @@ -451,7 +449,7 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buff return true; } -wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, wlr_texture* texture) { +wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) { auto output = state->monitor->output; int w = currentCursorImage.size.x, h = currentCursorImage.size.y; @@ -528,7 +526,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* if ((!state->hardwareFailed && state->softwareLocks == 0)) { if (currentCursorImage.surface) - wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); + currentCursorImage.surface->resource()->frame(now); return; } @@ -550,7 +548,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); if (currentCursorImage.surface) - wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); + currentCursorImage.surface->resource()->frame(now); } Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) { @@ -762,17 +760,19 @@ void CPointerManager::onMonitorLayoutChange() { damageIfSoftware(); } -wlr_texture* CPointerManager::getCurrentCursorTexture() { - if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !wlr_surface_get_texture(currentCursorImage.surface->wlr()))) +SP<CTexture> CPointerManager::getCurrentCursorTexture() { + if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.buffer)) return nullptr; if (currentCursorImage.pBuffer) { - if (!currentCursorImage.pBufferTexture) + if (!currentCursorImage.pBufferTexture) { currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer); - return currentCursorImage.pBufferTexture; + currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBufferTexture); + } + return currentCursorImage.bufferTex; } - return wlr_surface_get_texture(currentCursorImage.surface->wlr()); + return currentCursorImage.surface->resource()->current.buffer->texture; } void CPointerManager::attachPointer(SP<IPointer> pointer) { diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index db9f27e7..b71a79c3 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -11,6 +11,7 @@ class CMonitor; struct wlr_input_device; class IHID; +class CTexture; /* The naming here is a bit confusing. @@ -37,7 +38,7 @@ class CPointerManager { void warpAbsolute(Vector2D abs, SP<IHID> dev); void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); - void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot); + void setCursorSurface(SP<CWLSurface> buf, const Vector2D& hotspot); void resetCursorImage(bool apply = true); void lockSoftwareForMonitor(SP<CMonitor> pMonitor); @@ -76,7 +77,7 @@ class CPointerManager { Vector2D transformedHotspot(SP<CMonitor> pMonitor); - wlr_texture* getCurrentCursorTexture(); + SP<CTexture> getCurrentCursorTexture(); struct SPointerListener { CHyprSignalListener destroy; @@ -129,8 +130,9 @@ class CPointerManager { } currentMonitorLayout; struct { - wlr_buffer* pBuffer = nullptr; - CWLSurface* surface = nullptr; + wlr_buffer* pBuffer = nullptr; + SP<CTexture> bufferTex; + WP<CWLSurface> surface; wlr_texture* pBufferTexture = nullptr; Vector2D hotspot; @@ -138,7 +140,7 @@ class CPointerManager { float scale = 1.F; CHyprSignalListener destroySurface; - DYNLISTENER(commitSurface); + CHyprSignalListener commitSurface; DYNLISTENER(destroyBuffer); } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors @@ -165,7 +167,7 @@ class CPointerManager { std::vector<SP<SMonitorPointerState>> monitorStates; SP<SMonitorPointerState> stateFor(SP<CMonitor> mon); bool attemptHardwareCursor(SP<SMonitorPointerState> state); - wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, wlr_texture* texture); + wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture); bool setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf); struct { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index feff69e0..bd435b27 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -32,17 +32,45 @@ #include "../protocols/DataDeviceWlr.hpp" #include "../protocols/PrimarySelection.hpp" #include "../protocols/XWaylandShell.hpp" +#include "../protocols/Viewporter.hpp" +#include "../protocols/MesaDRM.hpp" +#include "../protocols/LinuxDMABUF.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" +#include "../protocols/core/Compositor.hpp" +#include "../protocols/core/Subcompositor.hpp" +#include "../protocols/core/Output.hpp" +#include "../protocols/core/Shm.hpp" + +#include "../helpers/Monitor.hpp" CProtocolManager::CProtocolManager() { + // Outputs are a bit dumb, we have to agree. + static auto P = g_pHookSystem->hookDynamic("monitorAdded", [](void* self, SCallbackInfo& info, std::any param) { + auto M = std::any_cast<CMonitor*>(param); + if (PROTO::outputs.contains(M->szName)) + PROTO::outputs.erase(M->szName); + PROTO::outputs.emplace(M->szName, std::make_unique<CWLOutputProtocol>(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock())); + }); + + static auto P2 = g_pHookSystem->hookDynamic("monitorRemoved", [](void* self, SCallbackInfo& info, std::any param) { + auto M = std::any_cast<CMonitor*>(param); + if (!PROTO::outputs.contains(M->szName)) + return; + PROTO::outputs.at(M->szName)->remove(); + }); + // Core - PROTO::seat = std::make_unique<CWLSeatProtocol>(&wl_seat_interface, 9, "WLSeat"); - PROTO::data = std::make_unique<CWLDataDeviceProtocol>(&wl_data_device_manager_interface, 3, "WLDataDevice"); + PROTO::seat = std::make_unique<CWLSeatProtocol>(&wl_seat_interface, 9, "WLSeat"); + PROTO::data = std::make_unique<CWLDataDeviceProtocol>(&wl_data_device_manager_interface, 3, "WLDataDevice"); + PROTO::compositor = std::make_unique<CWLCompositorProtocol>(&wl_compositor_interface, 6, "WLCompositor"); + PROTO::subcompositor = std::make_unique<CWLSubcompositorProtocol>(&wl_subcompositor_interface, 1, "WLSubcompositor"); + PROTO::shm = std::make_unique<CWLSHMProtocol>(&wl_shm_interface, 1, "WLSHM"); // Extensions + PROTO::viewport = std::make_unique<CViewporterProtocol>(&wp_viewporter_interface, 1, "Viewporter"); PROTO::tearing = std::make_unique<CTearingControlProtocol>(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); PROTO::fractional = std::make_unique<CFractionalScaleProtocol>(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale"); PROTO::xdgOutput = std::make_unique<CXDGOutputProtocol>(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); @@ -75,6 +103,8 @@ CProtocolManager::CProtocolManager() { PROTO::dataWlr = std::make_unique<CDataDeviceWLRProtocol>(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); PROTO::primarySelection = std::make_unique<CPrimarySelectionProtocol>(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); PROTO::xwaylandShell = std::make_unique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell"); + PROTO::mesaDRM = std::make_unique<CMesaDRMProtocol>(&wl_drm_interface, 2, "MesaDRM"); + PROTO::linuxDma = std::make_unique<CLinuxDMABufV1Protocol>(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 7899386b..399ef419 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -3,6 +3,7 @@ #include "../protocols/core/DataDevice.hpp" #include "../protocols/DataDeviceWlr.hpp" #include "../protocols/PrimarySelection.hpp" +#include "../protocols/core/Compositor.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" #include <algorithm> @@ -98,7 +99,7 @@ void CSeatManager::updateActiveKeyboardData() { PROTO::seat->updateKeymap(); } -void CSeatManager::setKeyboardFocus(wlr_surface* surf) { +void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) { if (state.keyboardFocus == surf) return; @@ -107,7 +108,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { return; } - hyprListener_keyboardSurfaceDestroy.removeCallback(); + listeners.keyboardSurfaceDestroy.reset(); if (state.keyboardFocusResource) { auto client = state.keyboardFocusResource->client(); @@ -132,7 +133,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { return; } - auto client = wl_resource_get_client(surf->resource); + auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; @@ -147,8 +148,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { } } - hyprListener_keyboardSurfaceDestroy.initCallback( - &surf->events.destroy, [this](void* owner, void* data) { setKeyboardFocus(nullptr); }, nullptr, "CSeatManager"); + listeners.keyboardSurfaceDestroy = surf->events.destroy.registerListener([this](std::any d) { setKeyboardFocus(nullptr); }); events.keyboardFocusChange.emit(); } @@ -187,7 +187,7 @@ void CSeatManager::sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32 } } -void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { +void CSeatManager::setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D& local) { if (state.pointerFocus == surf) return; @@ -196,7 +196,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { return; } - hyprListener_pointerSurfaceDestroy.removeCallback(); + listeners.pointerSurfaceDestroy.reset(); if (state.pointerFocusResource) { auto client = state.pointerFocusResource->client(); @@ -224,7 +224,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { return; } - auto client = wl_resource_get_client(surf->resource); + auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; @@ -243,8 +243,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { sendPointerFrame(); - hyprListener_pointerSurfaceDestroy.initCallback( - &surf->events.destroy, [this](void* owner, void* data) { setPointerFocus(nullptr, {}); }, nullptr, "CSeatManager"); + listeners.pointerSurfaceDestroy = surf->events.destroy.registerListener([this](std::any d) { setPointerFocus(nullptr, {}); }); events.pointerFocusChange.emit(); } @@ -340,11 +339,11 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double } } -void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local) { +void CSeatManager::sendTouchDown(SP<CWLSurfaceResource> surf, uint32_t timeMs, int32_t id, const Vector2D& local) { if (state.touchFocus == surf) return; - hyprListener_touchSurfaceDestroy.removeCallback(); + listeners.touchSurfaceDestroy.reset(); if (state.touchFocusResource) { auto client = state.touchFocusResource->client(); @@ -369,7 +368,7 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, return; } - auto client = wl_resource_get_client(surf->resource); + auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; @@ -383,8 +382,7 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, } } - hyprListener_touchSurfaceDestroy.initCallback( - &surf->events.destroy, [this, timeMs, id](void* owner, void* data) { sendTouchUp(timeMs + 10, id); }, nullptr, "CSeatManager"); + listeners.touchSurfaceDestroy = surf->events.destroy.registerListener([this, timeMs, id](std::any d) { sendTouchUp(timeMs + 10, id); }); events.touchFocusChange.emit(); } @@ -486,7 +484,7 @@ void CSeatManager::refocusGrab() { // try to find a surf in focus first const auto MOUSE = g_pInputManager->getMouseCoordsInternal(); for (auto& s : seatGrab->surfs) { - auto hlSurf = CWLSurface::surfaceFromWlr(s); + auto hlSurf = CWLSurface::fromResource(s.lock()); if (!hlSurf) continue; @@ -498,13 +496,13 @@ void CSeatManager::refocusGrab() { continue; if (seatGrab->keyboard) - setKeyboardFocus(s); + setKeyboardFocus(s.lock()); if (seatGrab->pointer) - setPointerFocus(s, MOUSE - b->pos()); + setPointerFocus(s.lock(), MOUSE - b->pos()); return; } - wlr_surface* surf = seatGrab->surfs.at(0); + SP<CWLSurfaceResource> surf = seatGrab->surfs.at(0).lock(); if (seatGrab->keyboard) setKeyboardFocus(surf); if (seatGrab->pointer) @@ -512,7 +510,7 @@ void CSeatManager::refocusGrab() { } } -void CSeatManager::onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot) { +void CSeatManager::onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& hotspot) { if (!state.pointerFocusResource || !seatResource || seatResource->client() != state.pointerFocusResource->client()) { Debug::log(LOG, "[seatmgr] Rejecting a setCursor because the client ain't in focus"); return; @@ -599,10 +597,10 @@ void CSeatManager::setGrab(SP<CSeatGrab> grab) { } void CSeatManager::resendEnterEvents() { - wlr_surface* kb = state.keyboardFocus; - wlr_surface* pt = state.pointerFocus; + SP<CWLSurfaceResource> kb = state.keyboardFocus.lock(); + SP<CWLSurfaceResource> pt = state.pointerFocus.lock(); - auto last = lastLocalCoords; + auto last = lastLocalCoords; setKeyboardFocus(nullptr); setPointerFocus(nullptr, {}); @@ -611,15 +609,15 @@ void CSeatManager::resendEnterEvents() { setPointerFocus(pt, last); } -bool CSeatGrab::accepts(wlr_surface* surf) { +bool CSeatGrab::accepts(SP<CWLSurfaceResource> surf) { return std::find(surfs.begin(), surfs.end(), surf) != surfs.end(); } -void CSeatGrab::add(wlr_surface* surf) { +void CSeatGrab::add(SP<CWLSurfaceResource> surf) { surfs.push_back(surf); } -void CSeatGrab::remove(wlr_surface* surf) { +void CSeatGrab::remove(SP<CWLSurfaceResource> surf) { std::erase(surfs, surf); if ((keyboard && g_pSeatManager->state.keyboardFocus == surf) || (pointer && g_pSeatManager->state.pointerFocus == surf)) g_pSeatManager->refocusGrab(); diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 35456cb3..e74d9ace 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -11,7 +11,7 @@ constexpr size_t MAX_SERIAL_STORE_LEN = 100; -struct wlr_surface; +class CWLSurfaceResource; class CWLSeatResource; class IPointer; class IKeyboard; @@ -29,9 +29,9 @@ class IKeyboard; */ class CSeatGrab { public: - bool accepts(wlr_surface* surf); - void add(wlr_surface* surf); - void remove(wlr_surface* surf); + bool accepts(SP<CWLSurfaceResource> surf); + void add(SP<CWLSurfaceResource> surf); + void remove(SP<CWLSurfaceResource> surf); void setCallback(std::function<void()> onEnd_); void clear(); @@ -42,8 +42,8 @@ class CSeatGrab { bool removeOnInput = true; // on hard input e.g. click outside, remove private: - std::vector<wlr_surface*> surfs; // read-only - std::function<void()> onEnd; + std::vector<WP<CWLSurfaceResource>> surfs; + std::function<void()> onEnd; friend class CSeatManager; }; @@ -57,11 +57,11 @@ class CSeatManager { void setKeyboard(SP<IKeyboard> keeb); void updateActiveKeyboardData(); // updates the clients with the keymap and repeat info - void setKeyboardFocus(wlr_surface* surf); + void setKeyboardFocus(SP<CWLSurfaceResource> surf); void sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state); void sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void setPointerFocus(wlr_surface* surf, const Vector2D& local); + void setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D& local); void sendPointerMotion(uint32_t timeMs, const Vector2D& local); void sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state); void sendPointerFrame(); @@ -69,7 +69,7 @@ class CSeatManager { void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, int32_t value120, wl_pointer_axis_source source, wl_pointer_axis_relative_direction relative); - void sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local); + void sendTouchDown(SP<CWLSurfaceResource> surf, uint32_t timeMs, int32_t id, const Vector2D& local); void sendTouchUp(uint32_t timeMs, int32_t id); void sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local); void sendTouchFrame(); @@ -83,24 +83,24 @@ class CSeatManager { // pops the serial if it was valid, meaning it is consumed. bool serialValid(SP<CWLSeatResource> seatResource, uint32_t serial); - void onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot); + void onSetCursor(SP<CWLSeatResource> seatResource, uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& hotspot); SP<CWLSeatResource> seatResourceForClient(wl_client* client); struct { - wlr_surface* keyboardFocus = nullptr; - WP<CWLSeatResource> keyboardFocusResource; + WP<CWLSurfaceResource> keyboardFocus; + WP<CWLSeatResource> keyboardFocusResource; - wlr_surface* pointerFocus = nullptr; - WP<CWLSeatResource> pointerFocusResource; + WP<CWLSurfaceResource> pointerFocus; + WP<CWLSeatResource> pointerFocusResource; - wlr_surface* touchFocus = nullptr; - WP<CWLSeatResource> touchFocusResource; + WP<CWLSurfaceResource> touchFocus; + WP<CWLSeatResource> touchFocusResource; } state; struct SSetCursorEvent { - wlr_surface* surf = nullptr; - Vector2D hotspot; + SP<CWLSurfaceResource> surf = nullptr; + Vector2D hotspot; }; struct { @@ -149,14 +149,13 @@ class CSeatManager { struct { CHyprSignalListener newSeatResource; + CHyprSignalListener keyboardSurfaceDestroy; + CHyprSignalListener pointerSurfaceDestroy; + CHyprSignalListener touchSurfaceDestroy; } listeners; Vector2D lastLocalCoords; - DYNLISTENER(keyboardSurfaceDestroy); - DYNLISTENER(pointerSurfaceDestroy); - DYNLISTENER(touchSurfaceDestroy); - friend struct SSeatResourceContainer; friend class CSeatGrab; }; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index fd4841f4..3bec1c4b 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -20,7 +20,7 @@ SSessionLockSurface::SSessionLockSurface(SP<CSessionLockSurface> surface_) : sur listeners.destroy = surface_->events.destroy.registerListener([this](std::any data) { if (pWlrSurface == g_pCompositor->m_pLastFocus) - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pSessionLockManager->removeSessionLockSurface(this); }); @@ -70,7 +70,7 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) { g_pHyprRenderer->damageMonitor(m.get()); }); - m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([this](std::any data) { + m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([](std::any data) { g_pCompositor->focusSurface(nullptr); for (auto& m : g_pCompositor->m_vMonitors) @@ -117,7 +117,7 @@ float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f); } -bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) { +bool CSessionLockManager::isSurfaceSessionLock(SP<CWLSurfaceResource> pSurface) { // TODO: this has some edge cases when it's wrong (e.g. destroyed lock but not yet surfaces) // but can be easily fixed when I rewrite wlr_surface diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index d655a2bc..ea1b2029 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -8,13 +8,14 @@ class CSessionLockSurface; class CSessionLock; +class CWLSurfaceResource; struct SSessionLockSurface { SSessionLockSurface(SP<CSessionLockSurface> surface_); WP<CSessionLockSurface> surface; - wlr_surface* pWlrSurface = nullptr; - uint64_t iMonitorID = -1; + WP<CWLSurfaceResource> pWlrSurface; + uint64_t iMonitorID = -1; bool mapped = false; @@ -49,7 +50,7 @@ class CSessionLockManager { bool isSessionLocked(); bool isSessionLockPresent(); - bool isSurfaceSessionLock(wlr_surface*); + bool isSurfaceSessionLock(SP<CWLSurfaceResource>); void removeSessionLockSurface(SSessionLockSurface*); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 4aebefcb..12387900 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -3,6 +3,7 @@ #include "../events/Events.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" #define OUTPUT_MANAGER_VERSION 3 @@ -19,11 +20,11 @@ CHyprXWaylandManager::~CHyprXWaylandManager() { #endif } -wlr_surface* CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { - return pWindow->m_pWLSurface.wlr(); +SP<CWLSurfaceResource> CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { + return pWindow->m_pWLSurface->resource(); } -void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) { +void CHyprXWaylandManager::activateSurface(SP<CWLSurfaceResource> pSurface, bool activate) { if (!pSurface) return; @@ -33,7 +34,7 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) if (!w->m_bIsMapped) continue; - if (w->m_pWLSurface.wlr() != pSurface) + if (w->m_pWLSurface->resource() != pSurface) continue; if (w->m_bIsX11) { @@ -131,10 +132,6 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor())); } -wlr_surface* CHyprXWaylandManager::surfaceAt(PHLWINDOW pWindow, const Vector2D& client, Vector2D& surface) { - return wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), client.x, client.y, &surface.x, &surface.y); -} - bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { for (auto& a : pWindow->m_pXWaylandSurface->atoms) diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index 5bbab802..a9f95974 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -5,25 +5,25 @@ class CWindow; // because clangd typedef SP<CWindow> PHLWINDOW; +class CWLSurfaceResource; class CHyprXWaylandManager { public: CHyprXWaylandManager(); ~CHyprXWaylandManager(); - wlr_surface* getWindowSurface(PHLWINDOW); - void activateSurface(wlr_surface*, bool); - void activateWindow(PHLWINDOW, bool); - void getGeometryForWindow(PHLWINDOW, CBox*); - void sendCloseWindow(PHLWINDOW); - void setWindowSize(PHLWINDOW, Vector2D, bool force = false); - void setWindowFullscreen(PHLWINDOW, bool); - wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&); - bool shouldBeFloated(PHLWINDOW, bool pending = false); - void checkBorders(PHLWINDOW); - Vector2D getMaxSizeForWindow(PHLWINDOW); - Vector2D getMinSizeForWindow(PHLWINDOW); - Vector2D xwaylandToWaylandCoords(const Vector2D&); + SP<CWLSurfaceResource> getWindowSurface(PHLWINDOW); + void activateSurface(SP<CWLSurfaceResource>, bool); + void activateWindow(PHLWINDOW, bool); + void getGeometryForWindow(PHLWINDOW, CBox*); + void sendCloseWindow(PHLWINDOW); + void setWindowSize(PHLWINDOW, Vector2D, bool force = false); + void setWindowFullscreen(PHLWINDOW, bool); + bool shouldBeFloated(PHLWINDOW, bool pending = false); + void checkBorders(PHLWINDOW); + Vector2D getMaxSizeForWindow(PHLWINDOW); + Vector2D getMinSizeForWindow(PHLWINDOW); + Vector2D xwaylandToWaylandCoords(const Vector2D&); }; inline std::unique_ptr<CHyprXWaylandManager> g_pXWaylandManager;
\ No newline at end of file diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index a71059e4..a38acdbf 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -14,7 +14,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { recheckIdleInhibitorStatus(); }); - auto WLSurface = CWLSurface::surfaceFromWlr(PINHIBIT->inhibitor->surface); + auto WLSurface = CWLSurface::fromResource(PINHIBIT->inhibitor->surface.lock()); if (!WLSurface) { Debug::log(LOG, "Inhibitor has no HL Surface attached to it, likely meaning it's a non-desktop element. Assuming it's visible."); @@ -37,7 +37,7 @@ void CInputManager::recheckIdleInhibitorStatus() { return; } - auto WLSurface = CWLSurface::surfaceFromWlr(ii->inhibitor->surface); + auto WLSurface = CWLSurface::fromResource(ii->inhibitor->surface.lock()); if (!WLSurface) continue; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 27d04699..c12ac389 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -43,7 +43,7 @@ CInputManager::CInputManager() { Debug::log(LOG, "cursorImage request: shape {} -> {}", (uint32_t)event.shape, event.shapeName); - m_sCursorSurfaceInfo.wlSurface.unassign(); + m_sCursorSurfaceInfo.wlSurface->unassign(); m_sCursorSurfaceInfo.vHotspot = {}; m_sCursorSurfaceInfo.name = event.shapeName; m_sCursorSurfaceInfo.hidden = false; @@ -58,6 +58,8 @@ CInputManager::CInputManager() { m_sListeners.newVirtualMouse = PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) { this->newVirtualMouse(std::any_cast<SP<CVirtualPointerV1Resource>>(data)); }); m_sListeners.setCursor = g_pSeatManager->events.setCursor.registerListener([this](std::any d) { this->processMouseRequest(d); }); + + m_sCursorSurfaceInfo.wlSurface = CWLSurface::create(); } CInputManager::~CInputManager() { @@ -115,8 +117,8 @@ void CInputManager::sendMotionEventsToFocused() { return; // todo: this sucks ass - const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus); - const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); + const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock()); + const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -125,7 +127,7 @@ void CInputManager::sendMotionEventsToFocused() { m_bEmptyFocusCursorSet = false; - g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus, LOCAL); + g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus.lock(), LOCAL); } void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { @@ -141,14 +143,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE; - m_pFoundSurfaceToFocus = nullptr; + m_pFoundSurfaceToFocus.reset(); m_pFoundLSToFocus.reset(); m_pFoundWindowToFocus.reset(); - wlr_surface* foundSurface = nullptr; - Vector2D surfaceCoords; - Vector2D surfacePos = Vector2D(-1337, -1337); - PHLWINDOW pFoundWindow; - PHLLS pFoundLayerSurface; + SP<CWLSurfaceResource> foundSurface; + Vector2D surfaceCoords; + Vector2D surfacePos = Vector2D(-1337, -1337); + PHLWINDOW pFoundWindow; + PHLLS pFoundLayerSurface; if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; @@ -191,12 +193,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (forcedFocus) { pFoundWindow = forcedFocus; surfacePos = pFoundWindow->m_vRealPosition.value(); - foundSurface = pFoundWindow->m_pWLSurface.wlr(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); } // constraints if (!g_pSeatManager->mouse.expired() && isConstrained()) { - const auto SURF = CWLSurface::surfaceFromWlr(g_pCompositor->m_pLastFocus); + const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); const auto CONSTRAINT = SURF->constraint(); if (SURF && CONSTRAINT) { @@ -223,7 +225,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // if we are holding a pointer button, // and we're not dnd-ing, don't refocus. Keep focus on last surface. if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) { - foundSurface = g_pSeatManager->state.pointerFocus; + foundSurface = g_pSeatManager->state.pointerFocus.lock(); // IME popups aren't desktop-like elements // TODO: make them. @@ -233,7 +235,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_bFocusHeldByButtons = true; m_bRefocusHeldByButtons = refocus; } else { - auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface); + auto HLSurface = CWLSurface::fromResource(foundSurface); if (HLSurface) { const auto BOX = HLSurface->getSurfaceBoxGlobal(); @@ -275,7 +277,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!foundSurface) { auto popup = g_pInputManager->m_sIMERelay.popupFromCoords(mouseCoords); if (popup) { - foundSurface = popup->getWlrSurface(); + foundSurface = popup->getSurface(); surfacePos = popup->globalBox().pos(); } } @@ -306,7 +308,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); surfacePos = Vector2D(-1337, -1337); } else { - foundSurface = pFoundWindow->m_pWLSurface.wlr(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); surfacePos = pFoundWindow->m_vRealPosition.value(); } } @@ -345,7 +347,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!pFoundWindow->m_bIsX11) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); } else { - foundSurface = pFoundWindow->m_pWLSurface.wlr(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); surfacePos = pFoundWindow->m_vRealPosition.value(); } } @@ -369,9 +371,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { return; // setGrab will refocus } else { // we need to grab the last surface. - foundSurface = g_pSeatManager->state.pointerFocus; + foundSurface = g_pSeatManager->state.pointerFocus.lock(); - auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface); + auto HLSurface = CWLSurface::fromResource(foundSurface); if (HLSurface) { const auto BOX = HLSurface->getSurfaceBoxGlobal(); @@ -423,7 +425,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { bool allowKeyboardRefocus = true; if (!refocus && g_pCompositor->m_pLastFocus) { - const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); + const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); if (PLS && PLS->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) allowKeyboardRefocus = false; @@ -441,7 +443,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { return; } - if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface.wlr() && !m_bCursorImageOverridden) { + if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface->resource() && !m_bCursorImageOverridden) { const auto BOX = pFoundWindow->getWindowMainSurfaceBox(); if (!VECINRECT(mouseCoords, BOX.x, BOX.y, BOX.x + BOX.width, BOX.y + BOX.height)) setCursorImageOverride("left_ptr"); @@ -555,11 +557,11 @@ void CInputManager::processMouseRequest(std::any E) { Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf); - if (e.surf != m_sCursorSurfaceInfo.wlSurface.wlr()) { - m_sCursorSurfaceInfo.wlSurface.unassign(); + if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) { + m_sCursorSurfaceInfo.wlSurface->unassign(); if (e.surf) - m_sCursorSurfaceInfo.wlSurface.assign(e.surf); + m_sCursorSurfaceInfo.wlSurface->assign(e.surf); } if (e.surf) { @@ -573,7 +575,7 @@ void CInputManager::processMouseRequest(std::any E) { m_sCursorSurfaceInfo.name = ""; m_sCursorSurfaceInfo.inUse = true; - g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e.hotspot.x, e.hotspot.y); + g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface, e.hotspot.x, e.hotspot.y); } void CInputManager::restoreCursorIconToApp() { @@ -586,8 +588,8 @@ void CInputManager::restoreCursorIconToApp() { } if (m_sCursorSurfaceInfo.name.empty()) { - if (m_sCursorSurfaceInfo.wlSurface.exists()) - g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); + if (m_sCursorSurfaceInfo.wlSurface->exists()) + g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); } else { g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name); } @@ -696,7 +698,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { if (!g_pSeatManager->state.pointerFocus) break; - auto HLSurf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus); + auto HLSurf = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); if (HLSurf && HLSurf->getWindow()) g_pCompositor->changeWindowZOrder(HLSurf->getWindow(), true); @@ -1399,7 +1401,7 @@ bool CInputManager::isConstrained() { if (!C) continue; - if (!C->isActive() || C->owner()->wlr() != g_pCompositor->m_pLastFocus) + if (!C->isActive() || C->owner()->resource() != g_pCompositor->m_pLastFocus) continue; return true; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index f7d9ae57..9fdf061c 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -44,10 +44,10 @@ enum eBorderIconDirection { }; struct STouchData { - PHLWINDOWREF touchFocusWindow; - PHLLSREF touchFocusLS; - wlr_surface* touchFocusSurface = nullptr; - Vector2D touchSurfaceOrigin; + PHLWINDOWREF touchFocusWindow; + PHLLSREF touchFocusLS; + WP<CWLSurfaceResource> touchFocusSurface; + Vector2D touchSurfaceOrigin; }; // The third row is always 0 0 1 and is not expected by `libinput_device_config_calibration_set_matrix` @@ -236,9 +236,9 @@ class CInputManager { void applyConfigToKeyboard(SP<IKeyboard>); // this will be set after a refocus() - wlr_surface* m_pFoundSurfaceToFocus = nullptr; - PHLLSREF m_pFoundLSToFocus; - PHLWINDOWREF m_pFoundWindowToFocus; + WP<CWLSurfaceResource> m_pFoundSurfaceToFocus; + PHLLSREF m_pFoundLSToFocus; + PHLWINDOWREF m_pFoundWindowToFocus; // for holding focus on buttons held bool m_bFocusHeldByButtons = false; @@ -268,11 +268,11 @@ class CInputManager { // cursor surface struct cursorSI { - bool hidden = false; // null surface = hidden - CWLSurface wlSurface; - Vector2D vHotspot; - std::string name; // if not empty, means set by name. - bool inUse = false; + bool hidden = false; // null surface = hidden + SP<CWLSurface> wlSurface; + Vector2D vHotspot; + std::string name; // if not empty, means set by name. + bool inUse = false; } m_sCursorSurfaceInfo; void restoreCursorIconToApp(); // no-op if restored diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index 9ff584e6..a8757030 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -3,22 +3,24 @@ #include "../../Compositor.hpp" #include "../../protocols/FractionalScale.hpp" #include "../../protocols/InputMethodV2.hpp" +#include "../../protocols/core/Compositor.hpp" CInputPopup::CInputPopup(SP<CInputMethodPopupV2> popup_) : popup(popup_) { listeners.commit = popup_->events.commit.registerListener([this](std::any d) { onCommit(); }); listeners.map = popup_->events.map.registerListener([this](std::any d) { onMap(); }); listeners.unmap = popup_->events.unmap.registerListener([this](std::any d) { onUnmap(); }); listeners.destroy = popup_->events.destroy.registerListener([this](std::any d) { onDestroy(); }); - surface.assign(popup_->surface()); + surface = CWLSurface::create(); + surface->assign(popup_->surface()); } -CWLSurface* CInputPopup::queryOwner() { +SP<CWLSurface> CInputPopup::queryOwner() { const auto FOCUSED = g_pInputManager->m_sIMERelay.getFocusedTextInput(); if (!FOCUSED) return nullptr; - return CWLSurface::surfaceFromWlr(FOCUSED->focusedSurface()); + return CWLSurface::fromResource(FOCUSED->focusedSurface()); } void CInputPopup::onDestroy() { @@ -36,7 +38,7 @@ void CInputPopup::onMap() { if (!PMONITOR) return; - PROTO::fractional->sendScale(surface.wlr(), PMONITOR->scale); + PROTO::fractional->sendScale(surface->resource(), PMONITOR->scale); } void CInputPopup::onUnmap() { @@ -69,7 +71,7 @@ void CInputPopup::damageSurface() { } Vector2D pos = globalBox().pos(); - g_pHyprRenderer->damageSurface(surface.wlr(), pos.x, pos.y); + g_pHyprRenderer->damageSurface(surface->resource(), pos.x, pos.y); } void CInputPopup::updateBox() { @@ -98,7 +100,7 @@ void CInputPopup::updateBox() { cursorBoxParent = {0, 0, (int)parentBox.w, (int)parentBox.h}; } - Vector2D currentPopupSize = surface.getViewporterCorrectedSize(); + Vector2D currentPopupSize = surface->getViewporterCorrectedSize(); CMonitor* pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle()); @@ -127,9 +129,9 @@ void CInputPopup::updateBox() { const auto PML = g_pCompositor->getMonitorFromID(lastMonitor); if (PML) - wlr_surface_send_leave(surface.wlr(), PML->output); + surface->resource()->leave(PML->self.lock()); - wlr_surface_send_enter(surface.wlr(), PM->output); + surface->resource()->enter(PM->self.lock()); lastMonitor = PM->ID; } @@ -151,6 +153,6 @@ bool CInputPopup::isVecInPopup(const Vector2D& point) { return globalBox().containsPoint(point); } -wlr_surface* CInputPopup::getWlrSurface() { - return surface.wlr(); +SP<CWLSurfaceResource> CInputPopup::getSurface() { + return surface->resource(); } diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index 61b45d74..9c5491bf 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -12,18 +12,18 @@ class CInputPopup { public: CInputPopup(SP<CInputMethodPopupV2> popup); - void damageEntire(); - void damageSurface(); + void damageEntire(); + void damageSurface(); - bool isVecInPopup(const Vector2D& point); + bool isVecInPopup(const Vector2D& point); - CBox globalBox(); - wlr_surface* getWlrSurface(); + CBox globalBox(); + SP<CWLSurfaceResource> getSurface(); - void onCommit(); + void onCommit(); private: - CWLSurface* queryOwner(); + SP<CWLSurface> queryOwner(); void updateBox(); void onDestroy(); @@ -31,7 +31,7 @@ class CInputPopup { void onUnmap(); WP<CInputMethodPopupV2> popup; - CWLSurface surface; + SP<CWLSurface> surface; CBox lastBoxLocal; uint64_t lastMonitor = -1; diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index abf18fba..92ab14d8 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -3,9 +3,11 @@ #include "../../Compositor.hpp" #include "../../protocols/TextInputV3.hpp" #include "../../protocols/InputMethodV2.hpp" +#include "../../protocols/core/Compositor.hpp" CInputMethodRelay::CInputMethodRelay() { - static auto P = g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<wlr_surface*>(param)); }); + static auto P = + g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<SP<CWLSurfaceResource>>(param)); }); listeners.newTIV3 = PROTO::textInputV3->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(ti); }); listeners.newIME = PROTO::ime->events.newIME.registerListener([this](std::any ime) { onNewIME(std::any_cast<SP<CInputMethodV2>>(ime)); }); @@ -54,17 +56,17 @@ void CInputMethodRelay::onNewIME(SP<CInputMethodV2> pIME) { return; for (auto& ti : m_vTextInputs) { - if (ti->client() != wl_resource_get_client(g_pCompositor->m_pLastFocus->resource)) + if (ti->client() != g_pCompositor->m_pLastFocus->client()) continue; if (ti->isV3()) - ti->enter(g_pCompositor->m_pLastFocus); + ti->enter(g_pCompositor->m_pLastFocus.lock()); else - ti->onEnabled(g_pCompositor->m_pLastFocus); + ti->onEnabled(g_pCompositor->m_pLastFocus.lock()); } } -void CInputMethodRelay::setIMEPopupFocus(CInputPopup* pPopup, wlr_surface* pSurface) { +void CInputMethodRelay::setIMEPopupFocus(CInputPopup* pPopup, SP<CWLSurfaceResource> pSurface) { pPopup->onCommit(); } @@ -125,7 +127,7 @@ void CInputMethodRelay::commitIMEState(CTextInput* pInput) { pInput->commitStateToIME(m_pIME.lock()); } -void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) { +void CInputMethodRelay::onKeyboardFocus(SP<CWLSurfaceResource> pSurface) { if (m_pIME.expired()) return; @@ -145,7 +147,7 @@ void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) { if (!ti->isV3()) continue; - if (ti->client() != wl_resource_get_client(pSurface->resource)) + if (ti->client() != pSurface->client()) continue; ti->enter(pSurface); @@ -161,9 +163,9 @@ CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) { return nullptr; } -CInputPopup* CInputMethodRelay::popupFromSurface(const wlr_surface* surface) { +CInputPopup* CInputMethodRelay::popupFromSurface(const SP<CWLSurfaceResource> surface) { for (auto& p : m_vIMEPopups) { - if (p->getWlrSurface() == surface) + if (p->getSurface() == surface) return p.get(); } diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index 2896e8e8..e942add8 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -26,15 +26,15 @@ class CInputMethodRelay { void commitIMEState(CTextInput* pInput); void removeTextInput(CTextInput* pInput); - void onKeyboardFocus(wlr_surface*); + void onKeyboardFocus(SP<CWLSurfaceResource>); CTextInput* getFocusedTextInput(); - void setIMEPopupFocus(CInputPopup*, wlr_surface*); + void setIMEPopupFocus(CInputPopup*, SP<CWLSurfaceResource>); void removePopup(CInputPopup*); CInputPopup* popupFromCoords(const Vector2D& point); - CInputPopup* popupFromSurface(const wlr_surface* surface); + CInputPopup* popupFromSurface(const SP<CWLSurfaceResource> surface); void updateAllPopups(); @@ -44,7 +44,7 @@ class CInputMethodRelay { std::vector<std::unique_ptr<CTextInput>> m_vTextInputs; std::vector<std::unique_ptr<CInputPopup>> m_vIMEPopups; - wlr_surface* m_pLastKbFocus = nullptr; + WP<CWLSurfaceResource> m_pLastKbFocus; struct { CHyprSignalListener newTIV3; @@ -57,6 +57,6 @@ class CInputMethodRelay { friend class CHyprRenderer; friend class CInputManager; friend class CTextInputV1ProtocolManager; - friend struct CTextInput; + friend class CTextInput; friend class CHyprRenderer; }; diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 56e817ec..f1157e4b 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -20,7 +20,7 @@ static void unfocusTool(SP<CTabletTool> tool) { PROTO::tablet->proximityOut(tool); } -static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf) { +static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, SP<CWLSurfaceResource> surf) { if (tool->getSurface() == surf || !surf) return; @@ -37,7 +37,7 @@ static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* sur } static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = false) { - const auto LASTHLSURFACE = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus); + const auto LASTHLSURFACE = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); if (!LASTHLSURFACE || !tool->active) { if (tool->getSurface()) @@ -57,7 +57,7 @@ static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = f const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); - focusTool(tool, tab, g_pSeatManager->state.pointerFocus); + focusTool(tool, tab, g_pSeatManager->state.pointerFocus.lock()); if (!motion) return; diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index b3f0b0cb..4c7ffe6e 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -5,6 +5,7 @@ #include "../../Compositor.hpp" #include "../../protocols/TextInputV3.hpp" #include "../../protocols/InputMethodV2.hpp" +#include "../../protocols/core/Compositor.hpp" CTextInput::CTextInput(STextInputV1* ti) : pV1Input(ti) { ti->pTextInput = this; @@ -56,8 +57,8 @@ void CTextInput::initCallbacks() { hyprListener_textInputDestroy.removeCallback(); hyprListener_textInputDisable.removeCallback(); hyprListener_textInputEnable.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); - hyprListener_surfaceUnmapped.removeCallback(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); g_pInputManager->m_sIMERelay.removeTextInput(this); }, @@ -65,7 +66,7 @@ void CTextInput::initCallbacks() { } } -void CTextInput::onEnabled(wlr_surface* surfV1) { +void CTextInput::onEnabled(SP<CWLSurfaceResource> surfV1) { Debug::log(LOG, "TI ENABLE"); if (g_pInputManager->m_sIMERelay.m_pIME.expired()) { @@ -75,7 +76,7 @@ void CTextInput::onEnabled(wlr_surface* surfV1) { // v1 only, map surface to PTI if (!isV3()) { - wlr_surface* pSurface = surfV1; + SP<CWLSurfaceResource> pSurface = surfV1; if (g_pCompositor->m_pLastFocus != pSurface || !pV1Input->active) return; @@ -97,8 +98,8 @@ void CTextInput::onDisabled() { if (!isV3()) leave(); - hyprListener_surfaceDestroyed.removeCallback(); - hyprListener_surfaceUnmapped.removeCallback(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); g_pInputManager->m_sIMERelay.deactivateIME(this); } @@ -117,50 +118,44 @@ void CTextInput::onCommit() { g_pInputManager->m_sIMERelay.commitIMEState(this); } -void CTextInput::setFocusedSurface(wlr_surface* pSurface) { +void CTextInput::setFocusedSurface(SP<CWLSurfaceResource> pSurface) { if (pSurface == pFocusedSurface) return; pFocusedSurface = pSurface; - hyprListener_surfaceUnmapped.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); if (!pSurface) return; - hyprListener_surfaceUnmapped.initCallback( - &pSurface->events.unmap, - [this](void* owner, void* data) { - Debug::log(LOG, "Unmap TI owner1"); - - if (enterLocks) - enterLocks--; - pFocusedSurface = nullptr; - hyprListener_surfaceUnmapped.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); - }, - this, "CTextInput"); - - hyprListener_surfaceDestroyed.initCallback( - &pSurface->events.destroy, - [this](void* owner, void* data) { - Debug::log(LOG, "destroy TI owner1"); - - if (enterLocks) - enterLocks--; - pFocusedSurface = nullptr; - hyprListener_surfaceUnmapped.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); - }, - this, "CTextInput"); + listeners.surfaceUnmap = pSurface->events.unmap.registerListener([this](std::any d) { + Debug::log(LOG, "Unmap TI owner1"); + + if (enterLocks) + enterLocks--; + pFocusedSurface.reset(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); + }); + + listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) { + Debug::log(LOG, "Destroy TI owner1"); + + if (enterLocks) + enterLocks--; + pFocusedSurface.reset(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); + }); } bool CTextInput::isV3() { return !pV1Input; } -void CTextInput::enter(wlr_surface* pSurface) { +void CTextInput::enter(SP<CWLSurfaceResource> pSurface) { if (!pSurface || !pSurface->mapped) return; @@ -182,7 +177,7 @@ void CTextInput::enter(wlr_surface* pSurface) { if (isV3()) pV3Input->enter(pSurface); else { - zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->resource); + zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->getResource()->resource()); pV1Input->active = true; } @@ -211,8 +206,8 @@ void CTextInput::leave() { g_pInputManager->m_sIMERelay.deactivateIME(this); } -wlr_surface* CTextInput::focusedSurface() { - return pFocusedSurface; +SP<CWLSurfaceResource> CTextInput::focusedSurface() { + return pFocusedSurface.lock(); } wl_client* CTextInput::client() { diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index ff21da95..30fbb4cc 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -6,12 +6,12 @@ #include "../../helpers/signal/Listener.hpp" #include <memory> -struct wlr_surface; struct wl_client; struct STextInputV1; class CTextInputV3; class CInputMethodV2; +class CWLSurfaceResource; class CTextInput { public: @@ -19,43 +19,43 @@ class CTextInput { CTextInput(STextInputV1* ti); ~CTextInput(); - bool isV3(); - void enter(wlr_surface* pSurface); - void leave(); - void tiV1Destroyed(); - wl_client* client(); - void commitStateToIME(SP<CInputMethodV2> ime); - void updateIMEState(SP<CInputMethodV2> ime); + bool isV3(); + void enter(SP<CWLSurfaceResource> pSurface); + void leave(); + void tiV1Destroyed(); + wl_client* client(); + void commitStateToIME(SP<CInputMethodV2> ime); + void updateIMEState(SP<CInputMethodV2> ime); - void onEnabled(wlr_surface* surfV1 = nullptr); - void onDisabled(); - void onCommit(); + void onEnabled(SP<CWLSurfaceResource> surfV1 = nullptr); + void onDisabled(); + void onCommit(); - bool hasCursorRectangle(); - CBox cursorBox(); + bool hasCursorRectangle(); + CBox cursorBox(); - wlr_surface* focusedSurface(); + SP<CWLSurfaceResource> focusedSurface(); private: - void setFocusedSurface(wlr_surface* pSurface); - void initCallbacks(); + void setFocusedSurface(SP<CWLSurfaceResource> pSurface); + void initCallbacks(); - wlr_surface* pFocusedSurface = nullptr; - int enterLocks = 0; - WP<CTextInputV3> pV3Input; - STextInputV1* pV1Input = nullptr; + WP<CWLSurfaceResource> pFocusedSurface; + int enterLocks = 0; + WP<CTextInputV3> pV3Input; + STextInputV1* pV1Input = nullptr; DYNLISTENER(textInputEnable); DYNLISTENER(textInputDisable); DYNLISTENER(textInputCommit); DYNLISTENER(textInputDestroy); - DYNLISTENER(surfaceUnmapped); - DYNLISTENER(surfaceDestroyed); struct { CHyprSignalListener enable; CHyprSignalListener disable; CHyprSignalListener commit; CHyprSignalListener destroy; + CHyprSignalListener surfaceUnmap; + CHyprSignalListener surfaceDestroy; } listeners; };
\ No newline at end of file diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 7748813b..a1f949c2 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -77,7 +77,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { } else return; // oops, nothing found. - g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local); + g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface.lock(), e.timeMs, e.touchID, local); PROTO::idle->onActivity(); } diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index b9b99f69..04dcd0a8 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -2,10 +2,11 @@ #include <algorithm> #include "../desktop/WLSurface.hpp" #include "../render/Renderer.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::alphaModifier->protoLog -CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface_) : resource(resource_), pSurface(surface_) { +CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, SP<CWLSurfaceResource> surface_) : resource(resource_), pSurface(surface_) { if (!resource->resource()) return; @@ -18,8 +19,7 @@ CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surf setSurfaceAlpha(1.F); }); - hyprListener_surfaceDestroy.initCallback( - &surface_->events.destroy, [this](void* owner, void* data) { onSurfaceDestroy(); }, this, "CAlphaModifier"); + listeners.destroySurface = pSurface->events.destroy.registerListener([this](std::any d) { onSurfaceDestroy(); }); resource->setSetMultiplier([this](CWpAlphaModifierSurfaceV1* mod, uint32_t alpha) { if (!pSurface) { @@ -35,19 +35,19 @@ CAlphaModifier::CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surf } CAlphaModifier::~CAlphaModifier() { - hyprListener_surfaceDestroy.removeCallback(); + ; } bool CAlphaModifier::good() { return resource->resource(); } -wlr_surface* CAlphaModifier::getSurface() { - return pSurface; +SP<CWLSurfaceResource> CAlphaModifier::getSurface() { + return pSurface.lock(); } void CAlphaModifier::setSurfaceAlpha(float a) { - CWLSurface* surf = CWLSurface::surfaceFromWlr(pSurface); + auto surf = CWLSurface::fromResource(pSurface.lock()); if (!surf) { LOGM(ERR, "CAlphaModifier::setSurfaceAlpha: No CWLSurface for given surface??"); @@ -62,8 +62,7 @@ void CAlphaModifier::setSurfaceAlpha(float a) { } void CAlphaModifier::onSurfaceDestroy() { - hyprListener_surfaceDestroy.removeCallback(); - pSurface = nullptr; + pSurface.reset(); } CAlphaModifierProtocol::CAlphaModifierProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { @@ -75,7 +74,7 @@ void CAlphaModifierProtocol::bindManager(wl_client* client, void* data, uint32_t RESOURCE->setOnDestroy([this](CWpAlphaModifierV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpAlphaModifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); - RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, wlr_surface_from_resource(surface)); }); + RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, CWLSurfaceResource::fromResource(surface)); }); } void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) { @@ -83,29 +82,11 @@ void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) { } void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) { - if (modifier->getSurface()) - m_mAlphaModifiers.erase(modifier->getSurface()); - else { - // find it first - wlr_surface* deadptr = nullptr; - for (auto& [k, v] : m_mAlphaModifiers) { - if (v.get() == modifier) { - deadptr = k; - break; - } - } - - if (!deadptr) { - LOGM(ERR, "CAlphaModifierProtocol::destroyModifier: dead resource but no deadptr???"); - return; - } - - m_mAlphaModifiers.erase(deadptr); - } + std::erase_if(m_mAlphaModifiers, [](const auto& e) { return e.first.expired(); }); } -void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface) { - if (m_mAlphaModifiers.contains(surface)) { +void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) { + if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) { LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface); pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present"); return; diff --git a/src/protocols/AlphaModifier.hpp b/src/protocols/AlphaModifier.hpp index 457d1b4c..d49d1e4e 100644 --- a/src/protocols/AlphaModifier.hpp +++ b/src/protocols/AlphaModifier.hpp @@ -5,23 +5,28 @@ #include <unordered_map> #include "WaylandProtocol.hpp" #include "alpha-modifier-v1.hpp" +#include "../helpers/signal/Listener.hpp" + +class CWLSurfaceResource; class CAlphaModifier { public: - CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, wlr_surface* surface); + CAlphaModifier(SP<CWpAlphaModifierSurfaceV1> resource_, SP<CWLSurfaceResource> surface); ~CAlphaModifier(); - bool good(); - wlr_surface* getSurface(); - void onSurfaceDestroy(); + bool good(); + SP<CWLSurfaceResource> getSurface(); + void onSurfaceDestroy(); private: SP<CWpAlphaModifierSurfaceV1> resource; - wlr_surface* pSurface = nullptr; + WP<CWLSurfaceResource> pSurface; void setSurfaceAlpha(float a); - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CAlphaModifierProtocol : public IWaylandProtocol { @@ -33,15 +38,15 @@ class CAlphaModifierProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void destroyModifier(CAlphaModifier* decoration); - void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface); + void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface); // - std::vector<UP<CWpAlphaModifierV1>> m_vManagers; - std::unordered_map<wlr_surface*, UP<CAlphaModifier>> m_mAlphaModifiers; // xdg_toplevel -> deco + std::vector<UP<CWpAlphaModifierV1>> m_vManagers; + std::unordered_map<WP<CWLSurfaceResource>, UP<CAlphaModifier>> m_mAlphaModifiers; // xdg_toplevel -> deco friend class CAlphaModifier; }; namespace PROTO { inline UP<CAlphaModifierProtocol> alphaModifier; -};
\ No newline at end of file +}; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 5f0771e0..40f9af44 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -1,21 +1,21 @@ #include "FocusGrab.hpp" -#include "Compositor.hpp" +#include "../Compositor.hpp" #include <hyprland-focus-grab-v1.hpp> #include "../managers/input/InputManager.hpp" #include "../managers/SeatManager.hpp" +#include "core/Compositor.hpp" #include <cstdint> #include <memory> #include <wayland-server.h> #define LOGM PROTO::focusGrab->protoLog -CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) { - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [=](void*, void*) { grab->eraseSurface(surface); }, this, "CFocusGrab"); +CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP<CWLSurfaceResource> surface) { + listeners.destroy = surface->events.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); }); } CFocusGrabSurfaceState::~CFocusGrabSurfaceState() { - hyprListener_surfaceDestroy.removeCallback(); + ; } CFocusGrab::CFocusGrab(SP<CHyprlandFocusGrabV1> resource_) : resource(resource_) { @@ -29,8 +29,8 @@ CFocusGrab::CFocusGrab(SP<CHyprlandFocusGrabV1> resource_) : resource(resource_) resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); - resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(wlr_surface_from_resource(surface)); }); - resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(wlr_surface_from_resource(surface)); }); + resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(CWLSurfaceResource::fromResource(surface)); }); + resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(CWLSurfaceResource::fromResource(surface)); }); resource->setCommit([this](CHyprlandFocusGrabV1* pMgr) { commit(); }); } @@ -42,8 +42,8 @@ bool CFocusGrab::good() { return resource->resource(); } -bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) { - auto iter = m_mSurfaces.find(surface); +bool CFocusGrab::isSurfaceComitted(SP<CWLSurfaceResource> surface) { + auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& o) { return o.first == surface; }); if (iter == m_mSurfaces.end()) return false; @@ -77,14 +77,14 @@ void CFocusGrab::finish(bool sendCleared) { } } -void CFocusGrab::addSurface(wlr_surface* surface) { - auto iter = m_mSurfaces.find(surface); +void CFocusGrab::addSurface(SP<CWLSurfaceResource> surface) { + auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& e) { return e.first == surface; }); if (iter == m_mSurfaces.end()) { m_mSurfaces.emplace(surface, std::make_unique<CFocusGrabSurfaceState>(this, surface)); } } -void CFocusGrab::removeSurface(wlr_surface* surface) { +void CFocusGrab::removeSurface(SP<CWLSurfaceResource> surface) { auto iter = m_mSurfaces.find(surface); if (iter != m_mSurfaces.end()) { if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) { @@ -94,20 +94,20 @@ void CFocusGrab::removeSurface(wlr_surface* surface) { } } -void CFocusGrab::eraseSurface(wlr_surface* surface) { +void CFocusGrab::eraseSurface(SP<CWLSurfaceResource> surface) { removeSurface(surface); commit(true); } void CFocusGrab::refocusKeyboard() { auto keyboardSurface = g_pSeatManager->state.keyboardFocus; - if (keyboardSurface != nullptr && isSurfaceComitted(keyboardSurface)) + if (keyboardSurface && isSurfaceComitted(keyboardSurface.lock())) return; - wlr_surface* surface = nullptr; + SP<CWLSurfaceResource> surface = nullptr; for (auto& [surf, state] : m_mSurfaces) { if (state->state == CFocusGrabSurfaceState::Comitted) { - surface = surf; + surface = surf.lock(); break; } } @@ -124,14 +124,14 @@ void CFocusGrab::commit(bool removeOnly) { for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) { switch (iter->second->state) { case CFocusGrabSurfaceState::PendingRemoval: - grab->remove(iter->first); + grab->remove(iter->first.lock()); iter = m_mSurfaces.erase(iter); surfacesChanged = true; continue; case CFocusGrabSurfaceState::PendingAddition: if (!removeOnly) { iter->second->state = CFocusGrabSurfaceState::Comitted; - grab->add(iter->first); + grab->add(iter->first.lock()); surfacesChanged = true; anyComitted = true; } diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 40922c22..80166f9f 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -6,13 +6,15 @@ #include <cstdint> #include <unordered_map> #include <vector> +#include "../helpers/signal/Listener.hpp" class CFocusGrab; class CSeatGrab; +class CWLSurfaceResource; class CFocusGrabSurfaceState { public: - CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface); + CFocusGrabSurfaceState(CFocusGrab* grab, SP<CWLSurfaceResource> surface); ~CFocusGrabSurfaceState(); enum State { @@ -22,7 +24,9 @@ class CFocusGrabSurfaceState { } state = PendingAddition; private: - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroy; + } listeners; }; class CFocusGrab { @@ -31,23 +35,23 @@ class CFocusGrab { ~CFocusGrab(); bool good(); - bool isSurfaceComitted(wlr_surface* surface); + bool isSurfaceComitted(SP<CWLSurfaceResource> surface); void start(); void finish(bool sendCleared); private: - void addSurface(wlr_surface* surface); - void removeSurface(wlr_surface* surface); - void eraseSurface(wlr_surface* surface); - void refocusKeyboard(); - void commit(bool removeOnly = false); + void addSurface(SP<CWLSurfaceResource> surface); + void removeSurface(SP<CWLSurfaceResource> surface); + void eraseSurface(SP<CWLSurfaceResource> surface); + void refocusKeyboard(); + void commit(bool removeOnly = false); - SP<CHyprlandFocusGrabV1> resource; - std::unordered_map<wlr_surface*, UP<CFocusGrabSurfaceState>> m_mSurfaces; - SP<CSeatGrab> grab; + SP<CHyprlandFocusGrabV1> resource; + std::unordered_map<WP<CWLSurfaceResource>, UP<CFocusGrabSurfaceState>> m_mSurfaces; + SP<CSeatGrab> grab; - bool m_bGrabActive = false; + bool m_bGrabActive = false; DYNLISTENER(pointerGrabStarted); DYNLISTENER(keyboardGrabStarted); diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index 691ab697..6d225e99 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -1,13 +1,9 @@ #include "FractionalScale.hpp" +#include <algorithm> +#include "core/Compositor.hpp" #define LOGM PROTO::fractional->protoLog -static void onWlrSurfaceDestroy(void* owner, void* data) { - const auto SURF = (wlr_surface*)owner; - - PROTO::fractional->onSurfaceDestroy(SURF); -} - CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -18,7 +14,7 @@ void CFractionalScaleProtocol::bindManager(wl_client* client, void* data, uint32 RESOURCE->setDestroy([this](CWpFractionalScaleManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); RESOURCE->setGetFractionalScale( - [this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, wlr_surface_from_resource(surface)); }); + [this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, CWLSurfaceResource::fromResource(surface)); }); } void CFractionalScaleProtocol::removeAddon(CFractionalScaleAddon* addon) { @@ -29,11 +25,13 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) { std::erase_if(m_vManagers, [res](const auto& other) { return other->resource() == res; }); } -void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface) { - if (m_mAddons.contains(surface)) { - LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface); - pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists"); - return; +void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) { + for (auto& [k, v] : m_mAddons) { + if (k == surface) { + LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface); + pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists"); + return; + } } const auto PADDON = @@ -48,35 +46,22 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* PADDON->resource->setOnDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); PADDON->resource->setDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); - if (!m_mSurfaceScales.contains(surface)) - m_mSurfaceScales[surface] = 1.F; + if (std::find_if(m_mSurfaceScales.begin(), m_mSurfaceScales.end(), [surface](const auto& e) { return e.first == surface; }) == m_mSurfaceScales.end()) + m_mSurfaceScales.emplace(surface, 1.F); + + PADDON->setScale(m_mSurfaceScales.at(surface)); - PADDON->setScale(m_mSurfaceScales[surface]); - registerSurface(surface); + // clean old + std::erase_if(m_mSurfaceScales, [](const auto& e) { return e.first.expired(); }); } -void CFractionalScaleProtocol::sendScale(wlr_surface* surf, const float& scale) { +void CFractionalScaleProtocol::sendScale(SP<CWLSurfaceResource> surf, const float& scale) { m_mSurfaceScales[surf] = scale; if (m_mAddons.contains(surf)) m_mAddons[surf]->setScale(scale); - registerSurface(surf); -} - -void CFractionalScaleProtocol::registerSurface(wlr_surface* surf) { - if (m_mSurfaceDestroyListeners.contains(surf)) - return; - - m_mSurfaceDestroyListeners[surf].hyprListener_surfaceDestroy.initCallback(&surf->events.destroy, ::onWlrSurfaceDestroy, surf, "FractionalScale"); -} - -void CFractionalScaleProtocol::onSurfaceDestroy(wlr_surface* surf) { - m_mSurfaceDestroyListeners.erase(surf); - m_mSurfaceScales.erase(surf); - if (m_mAddons.contains(surf)) - m_mAddons[surf]->onSurfaceDestroy(); } -CFractionalScaleAddon::CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) { +CFractionalScaleAddon::CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, SP<CWLSurfaceResource> surf_) : resource(resource_), surface(surf_) { resource->setDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); resource->setOnDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); } @@ -93,6 +78,6 @@ bool CFractionalScaleAddon::good() { return resource->resource(); } -wlr_surface* CFractionalScaleAddon::surf() { - return surface; +SP<CWLSurfaceResource> CFractionalScaleAddon::surf() { + return surface.lock(); }
\ No newline at end of file diff --git a/src/protocols/FractionalScale.hpp b/src/protocols/FractionalScale.hpp index 10ebf49a..f6d1f96f 100644 --- a/src/protocols/FractionalScale.hpp +++ b/src/protocols/FractionalScale.hpp @@ -6,19 +6,20 @@ #include "fractional-scale-v1.hpp" class CFractionalScaleProtocol; +class CWLSurfaceResource; class CFractionalScaleAddon { public: - CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, wlr_surface* surf_); + CFractionalScaleAddon(SP<CWpFractionalScaleV1> resource_, SP<CWLSurfaceResource> surf_); - void setScale(const float& scale); - void onSurfaceDestroy(); + void setScale(const float& scale); + void onSurfaceDestroy(); - bool good(); + bool good(); - wlr_surface* surf(); + SP<CWLSurfaceResource> surf(); - bool operator==(const wl_resource* other) const { + bool operator==(const wl_resource* other) const { return other == resource->resource(); } @@ -28,42 +29,36 @@ class CFractionalScaleAddon { private: SP<CWpFractionalScaleV1> resource; - float scale = 1.F; - wlr_surface* surface = nullptr; + float scale = 1.F; + WP<CWLSurfaceResource> surface; bool surfaceGone = false; friend class CFractionalScaleProtocol; }; -struct SSurfaceListener { - DYNLISTENER(surfaceDestroy); -}; - class CFractionalScaleProtocol : public IWaylandProtocol { public: CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); - void onSurfaceDestroy(wlr_surface* surf); - void sendScale(wlr_surface* surf, const float& scale); + void onSurfaceDestroy(SP<CWLSurfaceResource> surf); + void sendScale(SP<CWLSurfaceResource> surf, const float& scale); private: void removeAddon(CFractionalScaleAddon*); - void registerSurface(wlr_surface*); void onManagerResourceDestroy(wl_resource* res); - void onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface); + void onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface); // - std::unordered_map<wlr_surface*, SSurfaceListener> m_mSurfaceDestroyListeners; - std::unordered_map<wlr_surface*, float> m_mSurfaceScales; - std::unordered_map<wlr_surface*, UP<CFractionalScaleAddon>> m_mAddons; - std::vector<UP<CWpFractionalScaleManagerV1>> m_vManagers; + std::unordered_map<WP<CWLSurfaceResource>, float> m_mSurfaceScales; + std::unordered_map<WP<CWLSurfaceResource>, UP<CFractionalScaleAddon>> m_mAddons; + std::vector<UP<CWpFractionalScaleManagerV1>> m_vManagers; friend class CFractionalScaleAddon; }; namespace PROTO { inline UP<CFractionalScaleProtocol> fractional; -};
\ No newline at end of file +}; diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index c8db7100..7c3b39ce 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -3,6 +3,7 @@ #include <unistd.h> #include "../helpers/Monitor.hpp" #include "../Compositor.hpp" +#include "../protocols/core/Output.hpp" #define LOGM PROTO::gamma->protoLog @@ -10,15 +11,15 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out if (!resource_->resource()) return; - wlr_output* wlrOutput = wlr_output_from_resource(output); + auto OUTPUTRES = CWLOutputResource::fromResource(output); - if (!wlrOutput) { - LOGM(ERR, "No wlr_output in CGammaControl"); + if (!OUTPUTRES) { + LOGM(ERR, "No output in CGammaControl"); resource->sendFailed(); return; } - pMonitor = g_pCompositor->getRealMonitorFromOutput(wlrOutput); + pMonitor = OUTPUTRES->monitor.get(); if (!pMonitor) { LOGM(ERR, "No CMonitor"); @@ -33,7 +34,7 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out } } - gammaSize = wlr_output_get_gamma_size(wlrOutput); + gammaSize = wlr_output_get_gamma_size(pMonitor->output); if (gammaSize <= 0) { LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName); diff --git a/src/protocols/IdleInhibit.cpp b/src/protocols/IdleInhibit.cpp index 0ff11a56..89eb3108 100644 --- a/src/protocols/IdleInhibit.cpp +++ b/src/protocols/IdleInhibit.cpp @@ -1,26 +1,23 @@ #include "IdleInhibit.hpp" +#include "core/Compositor.hpp" -CIdleInhibitor::CIdleInhibitor(SP<CIdleInhibitorResource> resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) { +CIdleInhibitor::CIdleInhibitor(SP<CIdleInhibitorResource> resource_, SP<CWLSurfaceResource> surf_) : resource(resource_), surface(surf_) { ; } -CIdleInhibitorResource::CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, wlr_surface* surface_) : resource(resource_), surface(surface_) { - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, - [this](void* owner, void* data) { - surface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); - destroySent = true; - events.destroy.emit(); - }, - this, "CIdleInhibitorResource"); +CIdleInhibitorResource::CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, SP<CWLSurfaceResource> surface_) : resource(resource_), surface(surface_) { + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { + surface.reset(); + listeners.destroySurface.reset(); + destroySent = true; + events.destroy.emit(); + }); resource->setOnDestroy([this](CZwpIdleInhibitorV1* p) { PROTO::idleInhibit->removeInhibitor(this); }); resource->setDestroy([this](CZwpIdleInhibitorV1* p) { PROTO::idleInhibit->removeInhibitor(this); }); } CIdleInhibitorResource::~CIdleInhibitorResource() { - hyprListener_surfaceDestroy.removeCallback(); if (!destroySent) events.destroy.emit(); } @@ -39,14 +36,14 @@ void CIdleInhibitProtocol::bindManager(wl_client* client, void* data, uint32_t v RESOURCE->setDestroy([this](CZwpIdleInhibitManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); RESOURCE->setCreateInhibitor( - [this](CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onCreateInhibitor(pMgr, id, wlr_surface_from_resource(surface)); }); + [this](CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onCreateInhibitor(pMgr, id, CWLSurfaceResource::fromResource(surface)); }); } void CIdleInhibitProtocol::removeInhibitor(CIdleInhibitorResource* resource) { std::erase_if(m_vInhibitors, [resource](const auto& el) { return el.get() == resource; }); } -void CIdleInhibitProtocol::onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wlr_surface* surface) { +void CIdleInhibitProtocol::onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vInhibitors.emplace_back(makeShared<CIdleInhibitorResource>(makeShared<CZwpIdleInhibitorV1>(CLIENT, pMgr->version(), id), surface)); diff --git a/src/protocols/IdleInhibit.hpp b/src/protocols/IdleInhibit.hpp index b59e8789..3cbfd78d 100644 --- a/src/protocols/IdleInhibit.hpp +++ b/src/protocols/IdleInhibit.hpp @@ -7,22 +7,23 @@ #include "../helpers/signal/Signal.hpp" class CIdleInhibitorResource; +class CWLSurfaceResource; class CIdleInhibitor { public: - CIdleInhibitor(SP<CIdleInhibitorResource> resource_, wlr_surface* surf_); + CIdleInhibitor(SP<CIdleInhibitorResource> resource_, SP<CWLSurfaceResource> surf_); struct { CHyprSignalListener destroy; } listeners; WP<CIdleInhibitorResource> resource; - wlr_surface* surface = nullptr; + WP<CWLSurfaceResource> surface; }; class CIdleInhibitorResource { public: - CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, wlr_surface* surface_); + CIdleInhibitorResource(SP<CZwpIdleInhibitorV1> resource_, SP<CWLSurfaceResource> surface_); ~CIdleInhibitorResource(); SP<CIdleInhibitor> inhibitor; @@ -33,10 +34,12 @@ class CIdleInhibitorResource { private: SP<CZwpIdleInhibitorV1> resource; - wlr_surface* surface = nullptr; + WP<CWLSurfaceResource> surface; bool destroySent = false; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CIdleInhibitProtocol : public IWaylandProtocol { @@ -51,7 +54,7 @@ class CIdleInhibitProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); - void onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wlr_surface* surface); + void onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surface); void removeInhibitor(CIdleInhibitorResource*); @@ -64,4 +67,4 @@ class CIdleInhibitProtocol : public IWaylandProtocol { namespace PROTO { inline UP<CIdleInhibitProtocol> idleInhibit; -}
\ No newline at end of file +} diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 93ca38c0..5d0bd417 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "../devices/IKeyboard.hpp" #include <sys/mman.h> +#include "core/Compositor.hpp" #define LOGM PROTO::ime->protoLog @@ -83,51 +84,45 @@ wl_client* CInputMethodKeyboardGrabV2::client() { return resource->client(); } -CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, wlr_surface* wlrSurface) : resource(resource_), owner(owner_) { +CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, SP<CWLSurfaceResource> surface) : resource(resource_), owner(owner_) { if (!resource->resource()) return; resource->setDestroy([this](CZwpInputPopupSurfaceV2* r) { PROTO::ime->destroyResource(this); }); resource->setOnDestroy([this](CZwpInputPopupSurfaceV2* r) { PROTO::ime->destroyResource(this); }); - pSurface = wlrSurface; + pSurface = surface; - hyprListener_destroySurface.initCallback( - &wlrSurface->events.destroy, - [this](void* owner, void* data) { - if (mapped) - events.unmap.emit(); + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { + if (mapped) + events.unmap.emit(); - hyprListener_commitSurface.removeCallback(); - hyprListener_destroySurface.removeCallback(); + listeners.destroySurface.reset(); + listeners.commitSurface.reset(); - if (g_pCompositor->m_pLastFocus == pSurface) - g_pCompositor->m_pLastFocus = nullptr; + if (g_pCompositor->m_pLastFocus == pSurface) + g_pCompositor->m_pLastFocus.reset(); - pSurface = nullptr; - }, - this, "IMEPopup"); + pSurface.reset(); + }); - hyprListener_commitSurface.initCallback( - &wlrSurface->events.commit, - [this](void* owner, void* data) { - if (pSurface->pending.buffer_width > 0 && pSurface->pending.buffer_height > 0 && !mapped) { - mapped = true; - wlr_surface_map(pSurface); - events.map.emit(); - return; - } + listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { + if (pSurface->current.buffer && !mapped) { + mapped = true; + pSurface->map(); + events.map.emit(); + return; + } - if (pSurface->pending.buffer_width <= 0 && pSurface->pending.buffer_height <= 0 && mapped) { - mapped = false; - wlr_surface_unmap(pSurface); - events.unmap.emit(); - return; - } + if (!pSurface->current.buffer && mapped) { + mapped = false; + pSurface->unmap(); + events.unmap.emit(); + return; + } - events.commit.emit(); - }, - this, "IMEPopup"); + events.commit.emit(); + }); } CInputMethodPopupV2::~CInputMethodPopupV2() { @@ -145,8 +140,8 @@ void CInputMethodPopupV2::sendInputRectangle(const CBox& box) { resource->sendTextInputRectangle(box.x, box.y, box.w, box.h); } -wlr_surface* CInputMethodPopupV2::surface() { - return pSurface; +SP<CWLSurfaceResource> CInputMethodPopupV2::surface() { + return pSurface.lock(); } void CInputMethodV2::SState::reset() { @@ -194,7 +189,7 @@ CInputMethodV2::CInputMethodV2(SP<CZwpInputMethodV2> resource_) : resource(resou resource->setGetInputPopupSurface([this](CZwpInputMethodV2* r, uint32_t id, wl_resource* surface) { const auto RESOURCE = PROTO::ime->m_vPopups.emplace_back( - makeShared<CInputMethodPopupV2>(makeShared<CZwpInputPopupSurfaceV2>(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surface))); + makeShared<CInputMethodPopupV2>(makeShared<CZwpInputPopupSurfaceV2>(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surface))); if (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/InputMethodV2.hpp b/src/protocols/InputMethodV2.hpp index 1f5d2598..bc21270c 100644 --- a/src/protocols/InputMethodV2.hpp +++ b/src/protocols/InputMethodV2.hpp @@ -101,12 +101,12 @@ class CInputMethodKeyboardGrabV2 { class CInputMethodPopupV2 { public: - CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, wlr_surface* surface); + CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, SP<CWLSurfaceResource> surface); ~CInputMethodPopupV2(); - bool good(); - void sendInputRectangle(const CBox& box); - wlr_surface* surface(); + bool good(); + void sendInputRectangle(const CBox& box); + SP<CWLSurfaceResource> surface(); struct { CSignal map; @@ -120,10 +120,12 @@ class CInputMethodPopupV2 { private: SP<CZwpInputPopupSurfaceV2> resource; WP<CInputMethodV2> owner; - wlr_surface* pSurface = nullptr; + WP<CWLSurfaceResource> pSurface; - DYNLISTENER(commitSurface); - DYNLISTENER(destroySurface); + struct { + CHyprSignalListener destroySurface; + CHyprSignalListener commitSurface; + } listeners; }; class CInputMethodV2Protocol : public IWaylandProtocol { diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 962b89a3..8fa6dd27 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -1,6 +1,8 @@ #include "LayerShell.hpp" #include "../Compositor.hpp" #include "XDGShell.hpp" +#include "core/Compositor.hpp" +#include "core/Output.hpp" #define LOGM PROTO::layerShell->protoLog @@ -14,7 +16,7 @@ void CLayerShellResource::SState::reset() { margin = {0, 0, 0, 0}; } -CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) : +CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<CWLSurfaceResource> surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) : layerNamespace(namespace_), surface(surf_), resource(resource_) { if (!good()) return; @@ -31,57 +33,52 @@ CLayerShellResource::CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, wlr_ PROTO::layerShell->destroyResource(this); }); - hyprListener_destroySurface.initCallback( - &surf_->events.destroy, - [this](void* owner, void* data) { - events.destroy.emit(); - PROTO::layerShell->destroyResource(this); - }, - this, "CLayerShellResource"); - - hyprListener_commitSurface.initCallback( - &surf_->events.commit, - [this](void* owner, void* data) { - current = pending; - pending.committed = 0; - - bool attachedBuffer = surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0; - - if (attachedBuffer && !configured) { - wlr_surface_reject_pending(surface, resource->resource(), -1, "layerSurface was not configured, but a buffer was attached"); - return; - } - - constexpr uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - constexpr uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - - if (current.desiredSize.x <= 0 && (current.anchor & horiz) != horiz) { - wlr_surface_reject_pending(surface, resource->resource(), -1, "x == 0 but anchor doesn't have left and right"); - return; - } - - if (current.desiredSize.y <= 0 && (current.anchor & vert) != vert) { - wlr_surface_reject_pending(surface, resource->resource(), -1, "y == 0 but anchor doesn't have top and bottom"); - return; - } - - if (attachedBuffer && !mapped) { - mapped = true; - wlr_surface_map(surface); - events.map.emit(); - return; - } - - if (!attachedBuffer && mapped) { - mapped = false; - wlr_surface_unmap(surface); - events.unmap.emit(); - return; - } - - events.commit.emit(); - }, - this, "CLayerShellResource"); + listeners.destroySurface = surf_->events.destroy.registerListener([this](std::any d) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }); + + listeners.commitSurface = surf_->events.commit.registerListener([this](std::any d) { + current = pending; + pending.committed = 0; + + bool attachedBuffer = surface->current.buffer; + + if (attachedBuffer && !configured) { + surface->error(-1, "layerSurface was not configured, but a buffer was attached"); + return; + } + + constexpr uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + constexpr uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + + if (current.desiredSize.x <= 0 && (current.anchor & horiz) != horiz) { + surface->error(-1, "x == 0 but anchor doesn't have left and right"); + return; + } + + if (current.desiredSize.y <= 0 && (current.anchor & vert) != vert) { + surface->error(-1, "y == 0 but anchor doesn't have top and bottom"); + return; + } + + if (attachedBuffer && !mapped) { + mapped = true; + surface->map(); + events.map.emit(); + return; + } + + if (!attachedBuffer && mapped) { + mapped = false; + surface->unmap(); + events.unmap.emit(); + configured = false; + return; + } + + events.commit.emit(); + }); resource->setSetSize([this](CZwlrLayerSurfaceV1* r, uint32_t x, uint32_t y) { pending.committed |= STATE_SIZE; @@ -209,9 +206,9 @@ void CLayerShellProtocol::destroyResource(CLayerShellResource* surf) { void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { const auto CLIENT = pMgr->client(); - const auto PMONITOR = output ? g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)) : nullptr; + const auto PMONITOR = output ? CWLOutputResource::fromResource(output)->monitor.get() : nullptr; const auto RESOURCE = m_vLayers.emplace_back( - makeShared<CLayerShellResource>(makeShared<CZwlrLayerSurfaceV1>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), namespace_, PMONITOR, layer)); + makeShared<CLayerShellResource>(makeShared<CZwlrLayerSurfaceV1>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), namespace_, PMONITOR, layer)); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index 9ed6bc66..f348e86b 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -10,10 +10,11 @@ #include "../helpers/signal/Signal.hpp" class CMonitor; +class CWLSurfaceResource; class CLayerShellResource { public: - CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); + CLayerShellResource(SP<CZwlrLayerSurfaceV1> resource_, SP<CWLSurfaceResource> surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); ~CLayerShellResource(); bool good(); @@ -54,18 +55,20 @@ class CLayerShellResource { void reset(); } current, pending; - Vector2D size; - std::string layerNamespace; - std::string monitor = ""; - wlr_surface* surface = nullptr; - bool mapped = false; - bool configured = false; + Vector2D size; + std::string layerNamespace; + std::string monitor = ""; + WP<CWLSurfaceResource> surface; + bool mapped = false; + bool configured = false; private: SP<CZwlrLayerSurfaceV1> resource; - DYNLISTENER(destroySurface); - DYNLISTENER(commitSurface); + struct { + CHyprSignalListener commitSurface; + CHyprSignalListener destroySurface; + } listeners; bool closed = false; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp new file mode 100644 index 00000000..f7911f6e --- /dev/null +++ b/src/protocols/LinuxDMABUF.cpp @@ -0,0 +1,454 @@ +#include "LinuxDMABUF.hpp" +#include <algorithm> +#include <set> +#include <tuple> +#include "../helpers/MiscFunctions.hpp" +#include <sys/mman.h> +#include <xf86drm.h> +#include <fcntl.h> +#include "core/Compositor.hpp" +#include "types/DMABuffer.hpp" +#include "types/WLBuffer.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../render/OpenGL.hpp" +#include "../Compositor.hpp" + +#define LOGM PROTO::linuxDma->protoLog + +static std::optional<dev_t> devIDFromFD(int fd) { + struct stat stat; + if (fstat(fd, &stat) != 0) + return {}; + return stat.st_rdev; +} + +CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches_) { + std::set<std::pair<uint32_t, uint64_t>> formats; + for (auto& t : tranches_) { + for (auto& fmt : t.formats) { + for (auto& mod : fmt.mods) { + formats.insert(std::make_pair<>(fmt.format, mod)); + } + } + } + + tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry); + int fds[2] = {0}; + allocateSHMFilePair(tableLen, &fds[0], &fds[1]); + + auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + + if (!arr) { + LOGM(ERR, "mmap failed"); + close(fds[0]); + close(fds[1]); + return; + } + + close(fds[0]); + + std::vector<std::pair<uint32_t, uint64_t>> formatsVec; + for (auto& f : formats) { + formatsVec.push_back(f); + } + + size_t i = 0; + for (auto& [fmt, mod] : formatsVec) { + arr[i++] = SDMABUFFeedbackTableEntry{ + .fmt = fmt, + .modifier = mod, + }; + } + + munmap(arr, tableLen); + + mainDevice = device; + tableFD = fds[1]; + tranches = formatsVec; + + // TODO: maybe calculate indices? currently we send all as available which could be wrong? I ain't no kernel dev tho. +} + +CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() { + close(tableFD); +} + +CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) { + buffer = makeShared<CDMABuffer>(id, client, attrs); + + buffer->resource->buffer = buffer; + + listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::linuxDma->destroyResource(this); + }); + + if (!buffer->success) + LOGM(ERR, "Possibly compositor bug: buffer failed to create"); +} + +CLinuxDMABuffer::~CLinuxDMABuffer() { + buffer.reset(); + listeners.bufferResourceDestroy.reset(); +} + +bool CLinuxDMABuffer::good() { + return buffer && buffer->good(); +} + +CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParamsV1> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); + resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); + + attrs = makeShared<SDMABUFAttrs>(); + + attrs->success = true; + + resource->setAdd([this](CZwpLinuxBufferParamsV1* r, int32_t fd, uint32_t plane, uint32_t offset, uint32_t stride, uint32_t modHi, uint32_t modLo) { + if (used) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used"); + return; + } + + if (plane > 3) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, "plane > 3"); + return; + } + + if (attrs->fds.at(plane) != -1) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, "plane used"); + return; + } + + attrs->fds[plane] = fd; + attrs->strides[plane] = stride; + attrs->offsets[plane] = offset; + attrs->modifier = ((uint64_t)modHi << 32) | modLo; + }); + + resource->setCreate([this](CZwpLinuxBufferParamsV1* r, int32_t w, int32_t h, uint32_t fmt, zwpLinuxBufferParamsV1Flags flags) { + if (used) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used"); + return; + } + + if (flags > 0) { + r->sendFailed(); + LOGM(ERR, "DMABUF flags are not supported"); + return; + } + + attrs->size = {w, h}; + attrs->format = fmt; + attrs->planes = 4 - std::count(attrs->fds.begin(), attrs->fds.end(), -1); + + create(0); + }); + + resource->setCreateImmed([this](CZwpLinuxBufferParamsV1* r, uint32_t id, int32_t w, int32_t h, uint32_t fmt, zwpLinuxBufferParamsV1Flags flags) { + if (used) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used"); + return; + } + + if (flags > 0) { + r->sendFailed(); + LOGM(ERR, "DMABUF flags are not supported"); + return; + } + + attrs->size = {w, h}; + attrs->format = fmt; + attrs->planes = 4 - std::count(attrs->fds.begin(), attrs->fds.end(), -1); + + create(id); + }); +} + +CLinuxDMABBUFParamsResource::~CLinuxDMABBUFParamsResource() { + ; +} + +bool CLinuxDMABBUFParamsResource::good() { + return resource->resource(); +} + +void CLinuxDMABBUFParamsResource::create(uint32_t id) { + used = true; + + if (!verify()) { + LOGM(ERR, "Failed creating a dmabuf: verify() said no"); + return; // if verify failed, we errored the resource. + } + + if (!commence()) { + LOGM(ERR, "Failed creating a dmabuf: commence() said no"); + resource->sendFailed(); + return; + } + + LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, attrs->format, attrs->planes); + for (int i = 0; i < attrs->planes; ++i) { + LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs->modifier, attrs->fds[i], attrs->strides[i], attrs->offsets[i]); + } + + auto buf = PROTO::linuxDma->m_vBuffers.emplace_back(makeShared<CLinuxDMABuffer>(id, resource->client(), *attrs)); + + if (!buf->good() || !buf->buffer->success) { + resource->sendFailed(); + return; + } + + if (!id) + resource->sendCreated(PROTO::linuxDma->m_vBuffers.back()->buffer->resource->getResource()); + + createdBuffer = buf; +} + +bool CLinuxDMABBUFParamsResource::commence() { + if (PROTO::linuxDma->mainDeviceFD < 0) + return true; + + for (int i = 0; i < attrs->planes; i++) { + uint32_t handle = 0; + + if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD, attrs->fds.at(i), &handle)) { + LOGM(ERR, "Failed to import dmabuf fd"); + return false; + } + + if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD, handle)) { + LOGM(ERR, "Failed to close dmabuf handle"); + return false; + } + } + + return true; +} + +bool CLinuxDMABBUFParamsResource::verify() { + if (attrs->planes <= 0) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No planes added"); + return false; + } + + if (attrs->fds.at(0) < 0) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No plane 0"); + return false; + } + + bool empty = false; + for (auto& plane : attrs->fds) { + if (empty && plane != -1) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "Gap in planes"); + return false; + } + + if (plane == -1) { + empty = true; + continue; + } + } + + if (attrs->size.x < 1 || attrs->size.y < 1) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS, "x/y < 1"); + return false; + } + + for (size_t i = 0; i < (size_t)attrs->planes; ++i) { + if ((uint64_t)attrs->offsets.at(i) + (uint64_t)attrs->strides.at(i) * attrs->size.y > UINT32_MAX) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + std::format("size overflow on plane {}: offset {} + stride {} * height {} = {}, overflows UINT32_MAX", i, (uint64_t)attrs->offsets.at(i), + (uint64_t)attrs->strides.at(i), attrs->size.y, (uint64_t)attrs->offsets.at(i) + (uint64_t)attrs->strides.at(i))); + return false; + } + } + + return true; +} + +CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SP<CZwpLinuxDmabufFeedbackV1> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); + resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); + + if (surface) + LOGM(ERR, "FIXME: surface feedback stub"); + + auto* feedback = PROTO::linuxDma->defaultFeedback.get(); + + resource->sendFormatTable(feedback->tableFD, feedback->tableLen); + + // send default feedback + struct wl_array deviceArr = { + .size = sizeof(feedback->mainDevice), + .data = (void*)&feedback->mainDevice, + }; + resource->sendMainDevice(&deviceArr); + resource->sendTrancheTargetDevice(&deviceArr); + resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)0); + + wl_array indices; + wl_array_init(&indices); + for (size_t i = 0; i < feedback->tranches.size(); ++i) { + *((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i; + } + resource->sendTrancheFormats(&indices); + wl_array_release(&indices); + resource->sendTrancheDone(); + + resource->sendDone(); +} + +CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() { + ; +} + +bool CLinuxDMABUFFeedbackResource::good() { + return resource->resource(); +} + +CLinuxDMABUFResource::CLinuxDMABUFResource(SP<CZwpLinuxDmabufV1> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CZwpLinuxDmabufV1* r) { PROTO::linuxDma->destroyResource(this); }); + resource->setDestroy([this](CZwpLinuxDmabufV1* r) { PROTO::linuxDma->destroyResource(this); }); + + resource->setGetDefaultFeedback([](CZwpLinuxDmabufV1* r, uint32_t id) { + const auto RESOURCE = + PROTO::linuxDma->m_vFeedbacks.emplace_back(makeShared<CLinuxDMABUFFeedbackResource>(makeShared<CZwpLinuxDmabufFeedbackV1>(r->client(), r->version(), id), nullptr)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::linuxDma->m_vFeedbacks.pop_back(); + return; + } + }); + + resource->setGetSurfaceFeedback([](CZwpLinuxDmabufV1* r, uint32_t id, wl_resource* surf) { + const auto RESOURCE = PROTO::linuxDma->m_vFeedbacks.emplace_back( + makeShared<CLinuxDMABUFFeedbackResource>(makeShared<CZwpLinuxDmabufFeedbackV1>(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::linuxDma->m_vFeedbacks.pop_back(); + return; + } + }); + + resource->setCreateParams([](CZwpLinuxDmabufV1* r, uint32_t id) { + const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared<CLinuxDMABBUFParamsResource>(makeShared<CZwpLinuxBufferParamsV1>(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::linuxDma->m_vParams.pop_back(); + return; + } + }); + + if (resource->version() < 4) + sendMods(); +} + +bool CLinuxDMABUFResource::good() { + return resource->resource(); +} + +void CLinuxDMABUFResource::sendMods() { + for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->tranches) { + if (resource->version() < 3) { + if (mod == DRM_FORMAT_MOD_INVALID) + resource->sendFormat(fmt); + continue; + } + + // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + + resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF); + } +} + +CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) { + int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + auto dev = devIDFromFD(rendererFD); + + if (!dev.has_value()) { + LOGM(ERR, "failed to get drm dev"); + PROTO::linuxDma.reset(); + return; + } + + mainDevice = *dev; + + auto fmts = g_pHyprOpenGL->getDRMFormats(); + + SDMABufTranche tranche = { + .device = *dev, + .formats = fmts, + }; + + std::vector<SDMABufTranche> tches; + tches.push_back(tranche); + + defaultFeedback = std::make_unique<CCompiledDMABUFFeedback>(*dev, tches); + + drmDevice* device = nullptr; + if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { + LOGM(ERR, "failed to get drm dev"); + PROTO::linuxDma.reset(); + return; + } + + if (device->available_nodes & (1 << DRM_NODE_RENDER)) { + const char* name = device->nodes[DRM_NODE_RENDER]; + mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); + drmFreeDevice(&device); + if (mainDeviceFD < 0) { + LOGM(ERR, "failed to open drm dev"); + PROTO::linuxDma.reset(); + return; + } + } else { + LOGM(ERR, "DRM device {} has no render node!!", device->nodes[DRM_NODE_PRIMARY]); + drmFreeDevice(&device); + } + }); +} + +CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { + if (mainDeviceFD >= 0) + close(mainDeviceFD); +} + +void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared<CLinuxDMABUFResource>(makeShared<CZwpLinuxDmabufV1>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFFeedbackResource* resource) { + std::erase_if(m_vFeedbacks, [&](const auto& other) { return other.get() == resource; }); +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resource) { + std::erase_if(m_vParams, [&](const auto& other) { return other.get() == resource; }); +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp new file mode 100644 index 00000000..2b8ce736 --- /dev/null +++ b/src/protocols/LinuxDMABUF.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include <memory> +#include <vector> +#include <cstdint> +#include "WaylandProtocol.hpp" +#include "wayland.hpp" +#include "linux-dmabuf-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CDMABuffer; +struct SDRMFormat; +struct SDMABUFAttrs; +class CWLSurfaceResource; + +class CLinuxDMABuffer { + public: + CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + ~CLinuxDMABuffer(); + + bool good(); + + private: + SP<CDMABuffer> buffer; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; + + friend class CLinuxDMABBUFParamsResource; +}; + +#pragma pack(push, 1) +struct SDMABUFFeedbackTableEntry { + uint32_t fmt = 0; + char pad[4]; + uint64_t modifier = 0; +}; +#pragma pack(pop) + +class SCompiledDMABUFTranche { + dev_t device = 0; + uint32_t flags = 0; + std::vector<uint16_t> indices; +}; + +struct SDMABufTranche { + dev_t device = 0; + uint32_t flags = 0; + std::vector<SDRMFormat> formats; +}; + +class CCompiledDMABUFFeedback { + public: + CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches); + ~CCompiledDMABUFFeedback(); + + dev_t mainDevice = 0; + int tableFD = -1; + size_t tableLen = 0; + std::vector<std::pair<uint32_t, uint64_t>> tranches; +}; + +class CLinuxDMABBUFParamsResource { + public: + CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParamsV1> resource_); + ~CLinuxDMABBUFParamsResource(); + + bool good(); + void create(uint32_t id); // 0 means not immed + + SP<SDMABUFAttrs> attrs; + WP<CLinuxDMABuffer> createdBuffer; + bool used = false; + + private: + SP<CZwpLinuxBufferParamsV1> resource; + + bool verify(); + bool commence(); +}; + +class CLinuxDMABUFFeedbackResource { + public: + CLinuxDMABUFFeedbackResource(SP<CZwpLinuxDmabufFeedbackV1> resource_, SP<CWLSurfaceResource> surface_); + ~CLinuxDMABUFFeedbackResource(); + + bool good(); + + SP<CWLSurfaceResource> surface; // optional, for surface feedbacks + + private: + SP<CZwpLinuxDmabufFeedbackV1> resource; +}; + +class CLinuxDMABUFResource { + public: + CLinuxDMABUFResource(SP<CZwpLinuxDmabufV1> resource_); + + bool good(); + void sendMods(); + + private: + SP<CZwpLinuxDmabufV1> resource; +}; + +class CLinuxDMABufV1Protocol : public IWaylandProtocol { + public: + CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); + ~CLinuxDMABufV1Protocol(); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CLinuxDMABUFResource* resource); + void destroyResource(CLinuxDMABUFFeedbackResource* resource); + void destroyResource(CLinuxDMABBUFParamsResource* resource); + void destroyResource(CLinuxDMABuffer* resource); + + // + std::vector<SP<CLinuxDMABUFResource>> m_vManagers; + std::vector<SP<CLinuxDMABUFFeedbackResource>> m_vFeedbacks; + std::vector<SP<CLinuxDMABBUFParamsResource>> m_vParams; + std::vector<SP<CLinuxDMABuffer>> m_vBuffers; + + UP<CCompiledDMABUFFeedback> defaultFeedback; + dev_t mainDevice; + int mainDeviceFD = -1; + + friend class CLinuxDMABUFResource; + friend class CLinuxDMABUFFeedbackResource; + friend class CLinuxDMABBUFParamsResource; + friend class CLinuxDMABuffer; +}; + +namespace PROTO { + inline UP<CLinuxDMABufV1Protocol> linuxDma; +}; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp new file mode 100644 index 00000000..0bcf4a9c --- /dev/null +++ b/src/protocols/MesaDRM.cpp @@ -0,0 +1,133 @@ +#include "MesaDRM.hpp" +#include <algorithm> +#include <xf86drm.h> +#include "../Compositor.hpp" +#include <wlr/render/drm_format_set.h> +#include "types/WLBuffer.hpp" + +#define LOGM PROTO::mesaDRM->protoLog + +CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) { + LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); + for (int i = 0; i < attrs_.planes; ++i) { + LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]); + } + + buffer = makeShared<CDMABuffer>(id, client, attrs_); + buffer->resource->buffer = buffer; + + listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::mesaDRM->destroyResource(this); + }); + + if (!buffer->success) + LOGM(ERR, "Possibly compositor bug: buffer failed to create"); +} + +CMesaDRMBufferResource::~CMesaDRMBufferResource() { + if (buffer && buffer->resource) + buffer->resource->sendRelease(); + buffer.reset(); + listeners.bufferResourceDestroy.reset(); +} + +bool CMesaDRMBufferResource::good() { + return buffer && buffer->good(); +} + +CMesaDRMResource::CMesaDRMResource(SP<CWlDrm> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlDrm* r) { PROTO::mesaDRM->destroyResource(this); }); + + resource->setAuthenticate([this](CWlDrm* r, uint32_t token) { + // we don't need this + resource->sendAuthenticated(); + }); + + resource->setCreateBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, uint32_t) { r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead"); }); + + resource->setCreatePlanarBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) { + r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead"); + }); + + resource->setCreatePrimeBuffer( + [this](CWlDrm* r, uint32_t id, int32_t nameFd, int32_t w, int32_t h, uint32_t fmt, int32_t off0, int32_t str0, int32_t off1, int32_t str1, int32_t off2, int32_t str2) { + if (off0 < 0 || w <= 0 || h <= 0) { + r->error(WL_DRM_ERROR_INVALID_FORMAT, "Invalid w, h, or offset"); + return; + } + + SDMABUFAttrs attrs; + attrs.success = true; + attrs.size = {w, h}; + attrs.modifier = DRM_FORMAT_MOD_INVALID; + attrs.planes = 1; + attrs.offsets[0] = off0; + attrs.strides[0] = str0; + attrs.fds[0] = nameFd; + attrs.format = fmt; + + const auto RESOURCE = PROTO::mesaDRM->m_vBuffers.emplace_back(makeShared<CMesaDRMBufferResource>(id, resource->client(), attrs)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::mesaDRM->m_vBuffers.pop_back(); + return; + } + + // append instance so that buffer knows its owner + RESOURCE->buffer->resource->buffer = RESOURCE->buffer; + }); + + resource->sendDevice(PROTO::mesaDRM->nodeName.c_str()); + resource->sendCapabilities(WL_DRM_CAPABILITY_PRIME); + + auto fmts = g_pHyprOpenGL->getDRMFormats(); + for (auto& fmt : fmts) { + resource->sendFormat(fmt.format); + } +} + +bool CMesaDRMResource::good() { + return resource->resource(); +} + +CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + drmDevice* dev = nullptr; + int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + if (drmGetDevice2(drmFD, 0, &dev) != 0) { + LOGM(ERR, "Failed to get device"); + PROTO::mesaDRM.reset(); + return; + } + + if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + nodeName = dev->nodes[DRM_NODE_RENDER]; + } else { + ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); + LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); + nodeName = dev->nodes[DRM_NODE_PRIMARY]; + } + drmFreeDevice(&dev); +} + +void CMesaDRMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared<CMesaDRMResource>(makeShared<CWlDrm>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CMesaDRMProtocol::destroyResource(CMesaDRMResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CMesaDRMProtocol::destroyResource(CMesaDRMBufferResource* resource) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/MesaDRM.hpp b/src/protocols/MesaDRM.hpp new file mode 100644 index 00000000..ad31a182 --- /dev/null +++ b/src/protocols/MesaDRM.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include <memory> +#include <vector> +#include <cstdint> +#include "WaylandProtocol.hpp" +#include "wayland-drm.hpp" +#include "types/Buffer.hpp" +#include "types/DMABuffer.hpp" + +class CMesaDRMBufferResource { + public: + CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + ~CMesaDRMBufferResource(); + + bool good(); + + private: + SP<CDMABuffer> buffer; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; + + friend class CMesaDRMResource; +}; + +class CMesaDRMResource { + public: + CMesaDRMResource(SP<CWlDrm> resource_); + + bool good(); + + private: + SP<CWlDrm> resource; +}; + +class CMesaDRMProtocol : public IWaylandProtocol { + public: + CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CMesaDRMResource* resource); + void destroyResource(CMesaDRMBufferResource* resource); + + // + std::vector<SP<CMesaDRMResource>> m_vManagers; + std::vector<SP<CMesaDRMBufferResource>> m_vBuffers; + + std::string nodeName = ""; + + friend class CMesaDRMResource; + friend class CMesaDRMBufferResource; +}; + +namespace PROTO { + inline UP<CMesaDRMProtocol> mesaDRM; +}; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index db241048..ef287cfa 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -1,5 +1,6 @@ #include "OutputPower.hpp" #include "../Compositor.hpp" +#include "core/Output.hpp" #define LOGM PROTO::outputPower->protoLog @@ -61,15 +62,15 @@ void COutputPowerProtocol::destroyOutputPower(COutputPower* power) { void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uint32_t id, wl_resource* output) { - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)); + const auto OUTPUT = CWLOutputResource::fromResource(output); - if (!PMONITOR) { + if (!OUTPUT) { pMgr->error(0, "Invalid output resource"); return; } const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique<COutputPower>(makeShared<CZwlrOutputPowerV1>(CLIENT, pMgr->version(), id), PMONITOR)).get(); + const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique<COutputPower>(makeShared<CZwlrOutputPowerV1>(CLIENT, pMgr->version(), id), OUTPUT->monitor.get())).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index 87abdcdd..c7b78a5b 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -3,10 +3,11 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../managers/SeatManager.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::constraints->protoLog -CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : +CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : resourceL(resource_), locked(true) { if (!resource_->resource()) return; @@ -14,13 +15,13 @@ CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_su resource_->setOnDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); resource_->setDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); - pHLSurface = CWLSurface::surfaceFromWlr(surf); + pHLSurface = CWLSurface::fromResource(surf); if (!pHLSurface) return; if (region_) - region.set(wlr_region_from_resource(region_)); + region.set(CWLRegionResource::fromResource(region_)->region); resource_->setSetRegion([this](CZwpLockedPointerV1* p, wl_resource* region) { onSetRegion(region); }); resource_->setSetCursorPositionHint([this](CZwpLockedPointerV1* p, wl_fixed_t x, wl_fixed_t y) { @@ -45,7 +46,7 @@ CPointerConstraint::CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_su sharedConstructions(); } -CPointerConstraint::CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : +CPointerConstraint::CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : resourceC(resource_), locked(false) { if (!resource_->resource()) return; @@ -53,13 +54,13 @@ CPointerConstraint::CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, wlr_ resource_->setOnDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); resource_->setDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); - pHLSurface = CWLSurface::surfaceFromWlr(surf); + pHLSurface = CWLSurface::fromResource(surf); if (!pHLSurface) return; if (region_) - region.set(wlr_region_from_resource(region_)); + region.set(CWLRegionResource::fromResource(region_)->region); resource_->setSetRegion([this](CZwpConfinedPointerV1* p, wl_resource* region) { onSetRegion(region); }); @@ -79,7 +80,7 @@ CPointerConstraint::~CPointerConstraint() { void CPointerConstraint::sharedConstructions() { if (pHLSurface) { listeners.destroySurface = pHLSurface->events.destroy.registerListener([this](std::any d) { - pHLSurface = nullptr; + pHLSurface.reset(); if (active) deactivate(); @@ -92,7 +93,7 @@ void CPointerConstraint::sharedConstructions() { cursorPosOnActivate = g_pInputManager->getMouseCoordsInternal(); - if (g_pCompositor->m_pLastFocus == pHLSurface->wlr()) + if (g_pCompositor->m_pLastFocus == pHLSurface->resource()) activate(); } @@ -126,10 +127,10 @@ void CPointerConstraint::activate() { return; // TODO: hack, probably not a super duper great idea - if (g_pSeatManager->state.pointerFocus != pHLSurface->wlr()) { + if (g_pSeatManager->state.pointerFocus != pHLSurface->resource()) { const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal(); const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{}; - g_pSeatManager->setPointerFocus(pHLSurface->wlr(), LOCAL); + g_pSeatManager->setPointerFocus(pHLSurface->resource(), LOCAL); } if (locked) @@ -152,15 +153,15 @@ void CPointerConstraint::onSetRegion(wl_resource* wlRegion) { return; } - const auto REGION = wlr_region_from_resource(wlRegion); + const auto REGION = region.set(CWLRegionResource::fromResource(wlRegion)->region); region.set(REGION); positionHint = region.closestPoint(positionHint); g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss } -CWLSurface* CPointerConstraint::owner() { - return pHLSurface; +SP<CWLSurface> CPointerConstraint::owner() { + return pHLSurface.lock(); } CRegion CPointerConstraint::logicConstraintRegion() { @@ -241,7 +242,7 @@ void CPointerConstraintsProtocol::onLockPointer(CZwpPointerConstraintsV1* pMgr, zwpPointerConstraintsV1Lifetime lifetime) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vConstraints.emplace_back( - makeShared<CPointerConstraint>(makeShared<CZwpLockedPointerV1>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); + makeShared<CPointerConstraint>(makeShared<CZwpLockedPointerV1>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), region, lifetime)); onNewConstraint(RESOURCE, pMgr); } @@ -250,7 +251,7 @@ void CPointerConstraintsProtocol::onConfinePointer(CZwpPointerConstraintsV1* pMg zwpPointerConstraintsV1Lifetime lifetime) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vConstraints.emplace_back( - makeShared<CPointerConstraint>(makeShared<CZwpConfinedPointerV1>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); + makeShared<CPointerConstraint>(makeShared<CZwpConfinedPointerV1>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), region, lifetime)); onNewConstraint(RESOURCE, pMgr); } diff --git a/src/protocols/PointerConstraints.hpp b/src/protocols/PointerConstraints.hpp index 93e57c46..06bebb02 100644 --- a/src/protocols/PointerConstraints.hpp +++ b/src/protocols/PointerConstraints.hpp @@ -12,31 +12,32 @@ #include "../helpers/signal/Listener.hpp" class CWLSurface; +class CWLSurfaceResource; class CPointerConstraint { public: - CPointerConstraint(SP<CZwpLockedPointerV1> resource_, wlr_surface* surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); - CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, wlr_surface* surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); + CPointerConstraint(SP<CZwpLockedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); + CPointerConstraint(SP<CZwpConfinedPointerV1> resource_, SP<CWLSurfaceResource> surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); ~CPointerConstraint(); - bool good(); + bool good(); - void deactivate(); - void activate(); - bool isActive(); + void deactivate(); + void activate(); + bool isActive(); - CWLSurface* owner(); + SP<CWLSurface> owner(); - CRegion logicConstraintRegion(); - bool isLocked(); - Vector2D logicPositionHint(); + CRegion logicConstraintRegion(); + bool isLocked(); + Vector2D logicPositionHint(); private: SP<CZwpLockedPointerV1> resourceL; SP<CZwpConfinedPointerV1> resourceC; wl_client* pClient = nullptr; - CWLSurface* pHLSurface = nullptr; + WP<CWLSurface> pHLSurface; CRegion region; bool hintSet = false; diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 2bfd74da..86510779 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::pointerGestures->protoLog @@ -116,7 +117,7 @@ void CPointerGesturesProtocol::swipeBegin(uint32_t timeMs, uint32_t fingers) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers); } } @@ -162,7 +163,7 @@ void CPointerGesturesProtocol::pinchBegin(uint32_t timeMs, uint32_t fingers) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers); } } @@ -208,7 +209,7 @@ void CPointerGesturesProtocol::holdBegin(uint32_t timeMs, uint32_t fingers) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers); } } diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index e21c8403..0275b53f 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -2,10 +2,11 @@ #include <algorithm> #include "../helpers/Monitor.hpp" #include "../managers/HookSystemManager.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::presentation->protoLog -CQueuedPresentationData::CQueuedPresentationData(wlr_surface* surf) : surface(surf) { +CQueuedPresentationData::CQueuedPresentationData(SP<CWLSurfaceResource> surf) : surface(surf) { ; } @@ -25,7 +26,7 @@ void CQueuedPresentationData::discarded() { wasPresented = false; } -CPresentationFeedback::CPresentationFeedback(SP<CWpPresentationFeedback> resource_, wlr_surface* surf) : resource(resource_), surface(surf) { +CPresentationFeedback::CPresentationFeedback(SP<CWpPresentationFeedback> resource_, SP<CWLSurfaceResource> surf) : resource(resource_), surface(surf) { if (!good()) return; @@ -69,7 +70,7 @@ void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespe CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { const auto PMONITOR = std::any_cast<CMonitor*>(param); - std::erase_if(m_vQueue, [PMONITOR, this](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); + std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); }); } @@ -92,7 +93,8 @@ void CPresentationProtocol::destroyResource(CPresentationFeedback* feedback) { void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* surf, uint32_t id) { const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_vFeedbacks.emplace_back(makeShared<CPresentationFeedback>(makeShared<CWpPresentationFeedback>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get(); + m_vFeedbacks.emplace_back(makeShared<CPresentationFeedback>(makeShared<CWpPresentationFeedback>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))) + .get(); if (!RESOURCE->good()) { pMgr->noMemory(); @@ -116,8 +118,8 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint } } - std::erase_if(m_vFeedbacks, [pMonitor, this](const auto& other) { return !other->surface || other->done; }); - std::erase_if(m_vQueue, [pMonitor, this](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; }); + std::erase_if(m_vFeedbacks, [](const auto& other) { return !other->surface || other->done; }); + std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; }); } void CPresentationProtocol::queueData(SP<CQueuedPresentationData> data) { diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index 2df1c781..2c6ce3e9 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -7,10 +7,11 @@ #include "presentation-time.hpp" class CMonitor; +class CWLSurfaceResource; class CQueuedPresentationData { public: - CQueuedPresentationData(wlr_surface* surf); + CQueuedPresentationData(SP<CWLSurfaceResource> surf); void setPresentationType(bool zeroCopy); void attachMonitor(CMonitor* pMonitor); @@ -19,10 +20,10 @@ class CQueuedPresentationData { void discarded(); private: - bool wasPresented = false; - bool zeroCopy = false; - CMonitor* pMonitor = nullptr; - wlr_surface* surface = nullptr; // READ-ONLY + bool wasPresented = false; + bool zeroCopy = false; + CMonitor* pMonitor = nullptr; + WP<CWLSurfaceResource> surface; DYNLISTENER(destroySurface); @@ -32,7 +33,7 @@ class CQueuedPresentationData { class CPresentationFeedback { public: - CPresentationFeedback(SP<CWpPresentationFeedback> resource_, wlr_surface* surf); + CPresentationFeedback(SP<CWpPresentationFeedback> resource_, SP<CWLSurfaceResource> surf); bool good(); @@ -40,8 +41,8 @@ class CPresentationFeedback { private: SP<CWpPresentationFeedback> resource; - wlr_surface* surface = nullptr; // READ-ONLY - bool done = false; + WP<CWLSurfaceResource> surface; + bool done = false; friend class CPresentationProtocol; }; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 622d9d68..0c4eac86 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -2,11 +2,13 @@ #include "../Compositor.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/PointerManager.hpp" +#include "core/Output.hpp" +#include "types/WLBuffer.hpp" +#include "types/Buffer.hpp" +#include "../helpers/Format.hpp" #include <algorithm> -#include "ToplevelExportWlrFuncs.hpp" - #define SCREENCOPY_VERSION 3 static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { @@ -202,8 +204,8 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); wl_resource_set_user_data(frame->resource, nullptr); - if (frame->buffer && frame->buffer->n_locks > 0) - wlr_buffer_unlock(frame->buffer); + if (frame->buffer && frame->buffer->locked()) + frame->buffer->unlock(); removeClient(frame->client, force); m_lFrames.remove(*frame); } @@ -214,7 +216,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r const auto PFRAME = &m_lFrames.emplace_back(); PFRAME->overlayCursor = !!overlay_cursor; PFRAME->resource = wl_resource_create(client, &zwlr_screencopy_frame_v1_interface, wl_resource_get_version(resource), frame); - PFRAME->pMonitor = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)); + PFRAME->pMonitor = CWLOutputResource::fromResource(output)->monitor.get(); if (!PFRAME->pMonitor) { Debug::log(ERR, "client requested sharing of a monitor that doesnt exist"); @@ -256,7 +258,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r return; } - const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat); + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat); if (!PSHMINFO) { Debug::log(ERR, "No pixel format supported by renderer in capture output"); zwlr_screencopy_frame_v1_send_failed(PFRAME->resource); @@ -279,9 +281,9 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round(); - PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w); + PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); - zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); + zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); if (wl_resource_get_version(resource) >= 3) { if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) { @@ -307,7 +309,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - const auto PBUFFER = wlr_buffer_try_from_resource(buffer); + const auto PBUFFER = CWLBufferResource::fromResource(buffer); if (!PBUFFER) { Debug::log(ERR, "[sc] invalid buffer in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); @@ -315,7 +317,9 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) { + PBUFFER->buffer->lock(); + + if (PBUFFER->buffer->size != PFRAME->box.size()) { Debug::log(ERR, "[sc] invalid dimensions in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); removeFrame(PFRAME); @@ -329,28 +333,22 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - wlr_dmabuf_attributes dmabufAttrs; - void* wlrBufferAccessData; - uint32_t wlrBufferAccessFormat; - size_t wlrBufferAccessStride; - if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) { - PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF; + if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) { + PFRAME->bufferDMA = true; - if (dmabufAttrs.format != PFRAME->dmabufFormat) { + if (attrs.format != PFRAME->dmabufFormat) { Debug::log(ERR, "[sc] invalid buffer dma format in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; } - } else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) { - wlr_buffer_end_data_ptr_access(PBUFFER); - - if (wlrBufferAccessFormat != PFRAME->shmFormat) { + } else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) { + if (attrs.format != PFRAME->shmFormat) { Debug::log(ERR, "[sc] invalid buffer shm format in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; - } else if ((int)wlrBufferAccessStride != PFRAME->shmStride) { + } else if ((int)attrs.stride != PFRAME->shmStride) { Debug::log(ERR, "[sc] invalid buffer shm stride in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); removeFrame(PFRAME); @@ -363,7 +361,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - PFRAME->buffer = PBUFFER; + PFRAME->buffer = PBUFFER->buffer; m_vFramesAwaitingWrite.emplace_back(PFRAME); @@ -432,7 +430,7 @@ void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) { clock_gettime(CLOCK_MONOTONIC, &now); uint32_t flags = 0; - if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) { + if (frame->bufferDMA) { if (!copyFrameDmabuf(frame)) { Debug::log(ERR, "[sc] dmabuf copy failed in {:x}", (uintptr_t)frame); zwlr_screencopy_frame_v1_send_failed(frame->resource); @@ -471,7 +469,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) { // std::clamp(RECT.x2 - RECT.x1, 0, frame->buffer->width - RECT.x1), std::clamp(RECT.y2 - RECT.y1, 0, frame->buffer->height - RECT.y1)); // } - zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->width, frame->buffer->height); + zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->size.x, frame->buffer->size.y); } bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { @@ -479,13 +477,10 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* if (!sourceTex) return false; - void* data; - uint32_t format; - size_t stride; - if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) { - wlr_texture_destroy(sourceTex); - return false; - } + auto TEXTURE = makeShared<CTexture>(sourceTex); + + auto shm = frame->buffer->shm(); + auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; @@ -496,14 +491,13 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { wlr_texture_destroy(sourceTex); - wlr_buffer_end_data_ptr_access(frame->buffer); return false; } CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y}); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1); + g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); @@ -513,14 +507,15 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* glBindFramebuffer(GL_FRAMEBUFFER, fb.m_iFb); #endif - const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format); + const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { g_pHyprRenderer->endRender(); wlr_texture_destroy(sourceTex); - wlr_buffer_end_data_ptr_access(frame->buffer); return false; } + auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA; + g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); @@ -530,21 +525,20 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* glPixelStorei(GL_PACK_ALIGNMENT, 1); - const wlr_pixel_format_info* drmFmtWlr = drm_get_pixel_format_info(format); - uint32_t packStride = pixel_format_info_min_stride(drmFmtWlr, frame->box.w); + const auto drmFmt = FormatUtils::getPixelFormatFromDRM(shm.format); + uint32_t packStride = FormatUtils::minStride(drmFmt, frame->box.w); - if (packStride == stride) { - glReadPixels(0, 0, frame->box.w, frame->box.h, PFORMAT->glFormat, PFORMAT->glType, data); + if (packStride == (uint32_t)shm.stride) { + glReadPixels(0, 0, frame->box.w, frame->box.h, glFormat, PFORMAT->glType, pixelData); } else { for (size_t i = 0; i < frame->box.h; ++i) { uint32_t y = i; - glReadPixels(0, y, frame->box.w, 1, PFORMAT->glFormat, PFORMAT->glType, ((unsigned char*)data) + i * stride); + glReadPixels(0, y, frame->box.w, 1, glFormat, PFORMAT->glType, ((unsigned char*)pixelData) + i * shm.stride); } } g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; - wlr_buffer_end_data_ptr_access(frame->buffer); wlr_texture_destroy(sourceTex); return true; @@ -555,9 +549,11 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { if (!sourceTex) return false; + auto TEXTURE = makeShared<CTexture>(sourceTex); + CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer, nullptr, true)) + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) return false; CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} @@ -565,7 +561,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { .transform(wlr_output_transform_invert(frame->pMonitor->output->transform), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1); + g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index 1bdf6963..be434285 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -10,6 +10,7 @@ #include "../managers/eventLoop/EventLoopTimer.hpp" class CMonitor; +class IWLBuffer; enum eClientOwners { CLIENT_SCREENCOPY = 0, @@ -53,9 +54,9 @@ struct SScreencopyFrame { bool withDamage = false; bool lockedSWCursors = false; - wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM; + bool bufferDMA = false; - wlr_buffer* buffer = nullptr; + WP<IWLBuffer> buffer; CMonitor* pMonitor = nullptr; PHLWINDOWREF pWindow; diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp index d47467b3..42da52a9 100644 --- a/src/protocols/ServerDecorationKDE.cpp +++ b/src/protocols/ServerDecorationKDE.cpp @@ -1,8 +1,9 @@ #include "ServerDecorationKDE.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::serverDecorationKDE->protoLog -CServerDecorationKDE::CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, wlr_surface* surf) : resource(resource_) { +CServerDecorationKDE::CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, SP<CWLSurfaceResource> surf) : resource(resource_) { if (!good()) return; @@ -42,7 +43,8 @@ void CServerDecorationKDEProtocol::destroyResource(CServerDecorationKDE* hayperl void CServerDecorationKDEProtocol::createDecoration(COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* surf) { const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_vDecos.emplace_back(std::make_unique<CServerDecorationKDE>(makeShared<COrgKdeKwinServerDecoration>(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get(); + m_vDecos.emplace_back(std::make_unique<CServerDecorationKDE>(makeShared<COrgKdeKwinServerDecoration>(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))) + .get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/ServerDecorationKDE.hpp b/src/protocols/ServerDecorationKDE.hpp index ec7a852f..ab082b17 100644 --- a/src/protocols/ServerDecorationKDE.hpp +++ b/src/protocols/ServerDecorationKDE.hpp @@ -6,9 +6,11 @@ #include "WaylandProtocol.hpp" #include "kde-server-decoration.hpp" +class CWLSurfaceResource; + class CServerDecorationKDE { public: - CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, wlr_surface* surf); + CServerDecorationKDE(SP<COrgKdeKwinServerDecoration> resource_, SP<CWLSurfaceResource> surf); bool good(); diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index fd803eda..ae45b0f1 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -2,10 +2,12 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "FractionalScale.hpp" +#include "core/Compositor.hpp" +#include "core/Output.hpp" #define LOGM PROTO::sessionLock->protoLog -CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_) : +CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, SP<CWLSurfaceResource> surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_) : resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { if (!resource->resource()) return; @@ -21,45 +23,38 @@ CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; }); - hyprListener_surfaceCommit.initCallback( - &pSurface->events.commit, - [this](void* owner, void* data) { - if (pSurface->pending.buffer_width <= 0 || pSurface->pending.buffer_height <= 0) { - LOGM(ERR, "SessionLock attached a null buffer"); - resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached"); - return; - } - - if (!ackdConfigure) { - LOGM(ERR, "SessionLock committed without an ack"); - resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, "Committed surface before first ack"); - return; - } - - if (committed) - events.commit.emit(); - else { - wlr_surface_map(pSurface); - events.map.emit(); - } - committed = true; - }, - this, "SessionLockSurface"); - - hyprListener_surfaceDestroy.initCallback( - &pSurface->events.destroy, - [this](void* owner, void* data) { - LOGM(WARN, "SessionLockSurface object remains but surface is being destroyed???"); - wlr_surface_unmap(pSurface); - hyprListener_surfaceCommit.removeCallback(); - hyprListener_surfaceDestroy.removeCallback(); - - if (g_pCompositor->m_pLastFocus == pSurface) - g_pCompositor->m_pLastFocus = nullptr; - - pSurface = nullptr; - }, - this, "SessionLockSurface"); + listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) { + if (!pSurface->current.buffer) { + LOGM(ERR, "SessionLock attached a null buffer"); + resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached"); + return; + } + + if (!ackdConfigure) { + LOGM(ERR, "SessionLock committed without an ack"); + resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, "Committed surface before first ack"); + return; + } + + if (committed) + events.commit.emit(); + else { + pSurface->map(); + events.map.emit(); + } + committed = true; + }); + + listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) { + LOGM(WARN, "SessionLockSurface object remains but surface is being destroyed???"); + pSurface->unmap(); + listeners.surfaceCommit.reset(); + listeners.surfaceDestroy.reset(); + if (g_pCompositor->m_pLastFocus == pSurface) + g_pCompositor->m_pLastFocus.reset(); + + pSurface.reset(); + }); PROTO::fractional->sendScale(surface_, pMonitor_->scale); @@ -70,9 +65,9 @@ CSessionLockSurface::CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, CSessionLockSurface::~CSessionLockSurface() { if (pSurface && pSurface->mapped) - wlr_surface_unmap(pSurface); - hyprListener_surfaceCommit.removeCallback(); - hyprListener_surfaceDestroy.removeCallback(); + pSurface->unmap(); + listeners.surfaceCommit.reset(); + listeners.surfaceDestroy.reset(); events.destroy.emit(); // just in case. } @@ -93,8 +88,8 @@ CMonitor* CSessionLockSurface::monitor() { return pMonitor; } -wlr_surface* CSessionLockSurface::surface() { - return pSurface; +SP<CWLSurfaceResource> CSessionLockSurface::surface() { + return pSurface.lock(); } CSessionLock::CSessionLock(SP<CExtSessionLockV1> resource_) : resource(resource_) { @@ -195,8 +190,8 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id, wl_resource* surface, wl_resource* output) { LOGM(LOG, "New sessionLockSurface with id {}", id); - auto PSURFACE = wlr_surface_from_resource(surface); - auto PMONITOR = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)); + auto PSURFACE = CWLSurfaceResource::fromResource(surface); + auto PMONITOR = CWLOutputResource::fromResource(output)->monitor.get(); SP<CSessionLock> sessionLock; for (auto& l : m_vLocks) { diff --git a/src/protocols/SessionLock.hpp b/src/protocols/SessionLock.hpp index 6b0c4e08..a0c67e88 100644 --- a/src/protocols/SessionLock.hpp +++ b/src/protocols/SessionLock.hpp @@ -9,16 +9,17 @@ class CMonitor; class CSessionLock; +class CWLSurfaceResource; class CSessionLockSurface { public: - CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_); + CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, SP<CWLSurfaceResource> surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_); ~CSessionLockSurface(); - bool good(); - bool inert(); - CMonitor* monitor(); - wlr_surface* surface(); + bool good(); + bool inert(); + CMonitor* monitor(); + SP<CWLSurfaceResource> surface(); struct { CSignal map; @@ -29,7 +30,7 @@ class CSessionLockSurface { private: SP<CExtSessionLockSurfaceV1> resource; WP<CSessionLock> sessionLock; - wlr_surface* pSurface = nullptr; + WP<CWLSurfaceResource> pSurface; CMonitor* pMonitor = nullptr; bool ackdConfigure = false; @@ -37,11 +38,10 @@ class CSessionLockSurface { void sendConfigure(); - DYNLISTENER(surfaceCommit); - DYNLISTENER(surfaceDestroy); - struct { CHyprSignalListener monitorMode; + CHyprSignalListener surfaceCommit; + CHyprSignalListener surfaceDestroy; } listeners; }; diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index af9724b5..211a7a01 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -1,10 +1,11 @@ #include "ShortcutsInhibit.hpp" #include <algorithm> #include "../Compositor.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::shortcutsInhibit->protoLog -CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, wlr_surface* surf) : resource(resource_), pSurface(surf) { +CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, SP<CWLSurfaceResource> surf) : resource(resource_), pSurface(surf) { if (!resource->resource()) return; @@ -16,8 +17,8 @@ CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcut resource->sendActive(); } -wlr_surface* CKeyboardShortcutsInhibitor::surface() { - return pSurface; +SP<CWLSurfaceResource> CKeyboardShortcutsInhibitor::surface() { + return pSurface.lock(); } bool CKeyboardShortcutsInhibitor::good() { @@ -46,8 +47,8 @@ void CKeyboardShortcutsInhibitProtocol::destroyInhibitor(CKeyboardShortcutsInhib } void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* seat) { - wlr_surface* surf = wlr_surface_from_resource(surface); - const auto CLIENT = pMgr->client(); + SP<CWLSurfaceResource> surf = CWLSurfaceResource::fromResource(surface); + const auto CLIENT = pMgr->client(); for (auto& in : m_vInhibitors) { if (in->surface() != surf) diff --git a/src/protocols/ShortcutsInhibit.hpp b/src/protocols/ShortcutsInhibit.hpp index 4e06938f..ba1c134c 100644 --- a/src/protocols/ShortcutsInhibit.hpp +++ b/src/protocols/ShortcutsInhibit.hpp @@ -6,17 +6,19 @@ #include "WaylandProtocol.hpp" #include "keyboard-shortcuts-inhibit-unstable-v1.hpp" +class CWLSurfaceResource; + class CKeyboardShortcutsInhibitor { public: - CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, wlr_surface* surf); + CKeyboardShortcutsInhibitor(SP<CZwpKeyboardShortcutsInhibitorV1> resource_, SP<CWLSurfaceResource> surf); // read-only pointer, may be invalid - wlr_surface* surface(); - bool good(); + SP<CWLSurfaceResource> surface(); + bool good(); private: SP<CZwpKeyboardShortcutsInhibitorV1> resource; - wlr_surface* pSurface = nullptr; + WP<CWLSurfaceResource> pSurface; }; class CKeyboardShortcutsInhibitProtocol : public IWaylandProtocol { diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 54c55176..393dfd38 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +#include "core/Compositor.hpp" #include <algorithm> #define LOGM PROTO::tablet->protoLog @@ -160,11 +161,11 @@ CTabletToolV2Resource::CTabletToolV2Resource(SP<CZwpTabletToolV2> resource_, SP< resource->setDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); resource->setOnDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); - resource->setSetCursor([this](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) { + resource->setSetCursor([](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) { if (!g_pSeatManager->state.pointerFocusResource || g_pSeatManager->state.pointerFocusResource->client() != r->client()) return; - g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{surf ? wlr_surface_from_resource(surf) : nullptr, {hot_x, hot_y}}); + g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hot_x, hot_y}}); }); } @@ -448,7 +449,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { if (t->current) { t->resource->sendProximityOut(); t->sendFrame(); - t->lastSurf = nullptr; + t->lastSurf.reset(); } t->resource->sendRemoved(); @@ -545,9 +546,9 @@ void CTabletV2Protocol::down(SP<CTabletTool> tool) { } } -void CTabletV2Protocol::proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf) { +void CTabletV2Protocol::proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, SP<CWLSurfaceResource> surf) { proximityOut(tool); - const auto CLIENT = wl_resource_get_client(surf->resource); + const auto CLIENT = surf->client(); SP<CTabletToolV2Resource> toolResource; SP<CTabletV2Resource> tabletResource; @@ -587,7 +588,7 @@ void CTabletV2Protocol::proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wl toolResource->lastSurf = surf; auto serial = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(toolResource->resource->client())); - toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->resource); + toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->getResource()->resource()); toolResource->queueFrame(); LOGM(ERR, "proximityIn: found no resource to send enter"); @@ -598,8 +599,8 @@ void CTabletV2Protocol::proximityOut(SP<CTabletTool> tool) { if (t->tool != tool || !t->current) continue; - t->current = false; - t->lastSurf = nullptr; + t->current = false; + t->lastSurf.reset(); t->resource->sendProximityOut(); t->sendFrame(); } diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 74a45c63..c61395c9 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -12,6 +12,7 @@ class CTabletTool; class CTabletPad; class CEventLoopTimer; class CTabletSeat; +class CWLSurfaceResource; class CTabletPadStripV2Resource { public: @@ -112,19 +113,19 @@ class CTabletToolV2Resource { CTabletToolV2Resource(SP<CZwpTabletToolV2> resource_, SP<CTabletTool> tool_, SP<CTabletSeat> seat_); ~CTabletToolV2Resource(); - bool good(); - void sendData(); - void queueFrame(); - void sendFrame(bool removeSource = true); + bool good(); + void sendData(); + void queueFrame(); + void sendFrame(bool removeSource = true); - bool current = false; - wlr_surface* lastSurf = nullptr; // READ-ONLY + bool current = false; + WP<CWLSurfaceResource> lastSurf; - WP<CTabletTool> tool; - WP<CTabletSeat> seat; - wl_event_source* frameSource = nullptr; + WP<CTabletTool> tool; + WP<CTabletSeat> seat; + wl_event_source* frameSource = nullptr; - bool inert = false; // removed was sent + bool inert = false; // removed was sent private: SP<CZwpTabletToolV2> resource; @@ -180,7 +181,7 @@ class CTabletV2Protocol : public IWaylandProtocol { void tilt(SP<CTabletTool> tool, const Vector2D& value); void up(SP<CTabletTool> tool); void down(SP<CTabletTool> tool); - void proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf); + void proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, SP<CWLSurfaceResource> surf); void proximityOut(SP<CTabletTool> tool); void buttonTool(SP<CTabletTool> tool, uint32_t button, uint32_t state); void motion(SP<CTabletTool> tool, const Vector2D& value); diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index df3126fe..7f3c0a18 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -2,6 +2,7 @@ #include "../managers/ProtocolManager.hpp" #include "../desktop/Window.hpp" #include "../Compositor.hpp" +#include "core/Compositor.hpp" CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = @@ -13,15 +14,16 @@ void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_ RESOURCE->setOnDestroy([this](CWpTearingControlManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpTearingControlManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); - RESOURCE->setGetTearingControl( - [this](CWpTearingControlManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetController(pMgr->client(), pMgr, id, wlr_surface_from_resource(surface)); }); + RESOURCE->setGetTearingControl([this](CWpTearingControlManagerV1* pMgr, uint32_t id, wl_resource* surface) { + this->onGetController(pMgr->client(), pMgr, id, CWLSurfaceResource::fromResource(surface)); + }); } void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) { std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); } -void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, wlr_surface* surf) { +void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surf) { const auto CONTROLLER = m_vTearingControllers.emplace_back(std::make_unique<CTearingControl>(makeShared<CWpTearingControlV1>(client, pMgr->version(), id), surf)).get(); if (!CONTROLLER->good()) { @@ -44,14 +46,14 @@ void CTearingControlProtocol::onWindowDestroy(PHLWINDOW pWindow) { // -CTearingControl::CTearingControl(SP<CWpTearingControlV1> resource_, wlr_surface* surf_) : resource(resource_) { +CTearingControl::CTearingControl(SP<CWpTearingControlV1> resource_, SP<CWLSurfaceResource> surf_) : resource(resource_) { resource->setData(this); resource->setOnDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); }); resource->setDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); }); resource->setSetPresentationHint([this](CWpTearingControlV1* res, wpTearingControlV1PresentationHint hint) { this->onHint(hint); }); for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_pWLSurface.wlr() == surf_) { + if (w->m_pWLSurface->resource() == surf_) { pWindow = w; break; } diff --git a/src/protocols/TearingControl.hpp b/src/protocols/TearingControl.hpp index 199397a3..d81a27cd 100644 --- a/src/protocols/TearingControl.hpp +++ b/src/protocols/TearingControl.hpp @@ -6,10 +6,11 @@ class CWindow; class CTearingControlProtocol; +class CWLSurfaceResource; class CTearingControl { public: - CTearingControl(SP<CWpTearingControlV1> resource_, wlr_surface* surf_); + CTearingControl(SP<CWpTearingControlV1> resource_, SP<CWLSurfaceResource> surf_); void onHint(wpTearingControlV1PresentationHint hint_); @@ -42,7 +43,7 @@ class CTearingControlProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void onControllerDestroy(CTearingControl* control); - void onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, wlr_surface* surf); + void onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP<CWLSurfaceResource> surf); void onWindowDestroy(PHLWINDOW pWindow); // diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index 8fff4db5..7c16ef8c 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -1,6 +1,7 @@ #include "TextInputV1.hpp" #include "../Compositor.hpp" +#include "core/Compositor.hpp" #define TEXT_INPUT_VERSION 1 @@ -168,7 +169,7 @@ void CTextInputV1ProtocolManager::handleActivate(wl_client* client, wl_resource* return; } PTI->active = true; - PTI->pTextInput->onEnabled(wlr_surface_from_resource(surface)); + PTI->pTextInput->onEnabled(CWLSurfaceResource::fromResource(surface)); } void CTextInputV1ProtocolManager::handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat) { diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index b463c6d6..1302a57f 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -1,5 +1,6 @@ #include "TextInputV3.hpp" #include <algorithm> +#include "core/Compositor.hpp" #define LOGM PROTO::textInputV3->protoLog @@ -66,12 +67,12 @@ CTextInputV3::~CTextInputV3() { events.destroy.emit(); } -void CTextInputV3::enter(wlr_surface* surf) { - resource->sendEnter(surf->resource); +void CTextInputV3::enter(SP<CWLSurfaceResource> surf) { + resource->sendEnter(surf->getResource()->resource()); } -void CTextInputV3::leave(wlr_surface* surf) { - resource->sendLeave(surf->resource); +void CTextInputV3::leave(SP<CWLSurfaceResource> surf) { + resource->sendLeave(surf->getResource()->resource()); } void CTextInputV3::preeditString(const std::string& text, int32_t cursorBegin, int32_t cursorEnd) { diff --git a/src/protocols/TextInputV3.hpp b/src/protocols/TextInputV3.hpp index 6d4f3d54..3959e72b 100644 --- a/src/protocols/TextInputV3.hpp +++ b/src/protocols/TextInputV3.hpp @@ -9,13 +9,15 @@ #include "../helpers/signal/Signal.hpp" #include "../helpers/Box.hpp" +class CWLSurfaceResource; + class CTextInputV3 { public: CTextInputV3(SP<CZwpTextInputV3> resource_); ~CTextInputV3(); - void enter(wlr_surface* surf); - void leave(wlr_surface* surf); + void enter(SP<CWLSurfaceResource> surf); + void leave(SP<CWLSurfaceResource> surf); void preeditString(const std::string& text, int32_t cursorBegin, int32_t cursorEnd); void commitString(const std::string& text); void deleteSurroundingText(uint32_t beforeLength, uint32_t afterLength); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 14629214..80f9defa 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -2,11 +2,12 @@ #include "../Compositor.hpp" #include "ForeignToplevelWlr.hpp" #include "../managers/PointerManager.hpp" +#include "types/WLBuffer.hpp" +#include "types/Buffer.hpp" +#include "../helpers/Format.hpp" #include <algorithm> -#include "ToplevelExportWlrFuncs.hpp" - #define TOPLEVEL_EXPORT_VERSION 2 static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { @@ -131,8 +132,8 @@ void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool f std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); wl_resource_set_user_data(frame->resource, nullptr); - if (frame->buffer && frame->buffer->n_locks > 0) - wlr_buffer_unlock(frame->buffer); + if (frame->buffer && frame->buffer->locked() > 0) + frame->buffer->unlock(); removeClient(frame->client, force); m_lFrames.remove(*frame); } @@ -184,7 +185,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou return; } - const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat); + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat); if (!PSHMINFO) { Debug::log(ERR, "No pixel format supported by renderer in capture toplevel"); hyprland_toplevel_export_frame_v1_send_failed(resource); @@ -203,9 +204,9 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); PFRAME->box.transform(PMONITOR->transform, ow, oh).round(); - PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w); + PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); - hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); + hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) { hyprland_toplevel_export_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height); @@ -238,14 +239,16 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r return; } - const auto PBUFFER = wlr_buffer_try_from_resource(buffer); + const auto PBUFFER = CWLBufferResource::fromResource(buffer); if (!PBUFFER) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); removeFrame(PFRAME); return; } - if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) { + PBUFFER->buffer->lock(); + + if (PBUFFER->buffer->size != PFRAME->box.size()) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); removeFrame(PFRAME); return; @@ -257,26 +260,20 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r return; } - wlr_dmabuf_attributes dmabufAttrs; - void* wlrBufferAccessData; - uint32_t wlrBufferAccessFormat; - size_t wlrBufferAccessStride; - if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) { - PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF; + if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) { + PFRAME->bufferDMA = true; - if (dmabufAttrs.format != PFRAME->dmabufFormat) { + if (attrs.format != PFRAME->dmabufFormat) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; } - } else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) { - wlr_buffer_end_data_ptr_access(PBUFFER); - - if (wlrBufferAccessFormat != PFRAME->shmFormat) { + } else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) { + if (attrs.format != PFRAME->shmFormat) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; - } else if ((int)wlrBufferAccessStride != PFRAME->shmStride) { + } else if ((int)attrs.stride != PFRAME->shmStride) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); removeFrame(PFRAME); return; @@ -287,7 +284,7 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r return; } - PFRAME->buffer = PBUFFER; + PFRAME->buffer = PBUFFER->buffer; m_vFramesAwaitingWrite.emplace_back(PFRAME); } @@ -338,7 +335,7 @@ void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) { clock_gettime(CLOCK_MONOTONIC, &now); uint32_t flags = 0; - if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) { + if (frame->bufferDMA) { if (!copyFrameDmabuf(frame, &now)) { hyprland_toplevel_export_frame_v1_send_failed(frame->resource); return; @@ -363,11 +360,8 @@ void CToplevelExportProtocolManager::sendDamage(SScreencopyFrame* frame) { } bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { - void* data; - uint32_t format; - size_t stride; - if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) - return false; + auto shm = frame->buffer->shm(); + auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm // render the client const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); @@ -383,10 +377,8 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pPointerManager->damageCursor(PMONITOR->self.lock()); } - if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) { - wlr_buffer_end_data_ptr_access(frame->buffer); + if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) return false; - } g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); @@ -398,10 +390,9 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times if (frame->overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); - const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format); + const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { g_pHyprRenderer->endRender(); - wlr_buffer_end_data_ptr_access(frame->buffer); return false; } @@ -418,9 +409,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, data); - - wlr_buffer_end_data_ptr_access(frame->buffer); + glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, pixelData); if (frame->overlayCursor) { g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); @@ -435,7 +424,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer)) + if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock())) return false; g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); diff --git a/src/protocols/ToplevelExportWlrFuncs.hpp b/src/protocols/ToplevelExportWlrFuncs.hpp deleted file mode 100644 index b6f387e8..00000000 --- a/src/protocols/ToplevelExportWlrFuncs.hpp +++ /dev/null @@ -1,243 +0,0 @@ -#include <GLES2/gl2ext.h> - -#ifndef DRM_WLR_FUNCS -#define DRM_WLR_FUNCS - -struct wlr_pixel_format_info { - uint32_t drm_format; - - /* Equivalent of the format if it has an alpha channel, - * DRM_FORMAT_INVALID (0) if NA - */ - uint32_t opaque_substitute; - - /* Bytes per block (including padding) */ - uint32_t bytes_per_block; - /* Size of a block in pixels (zero for 1×1) */ - uint32_t block_width, block_height; - - /* True if the format has an alpha channel */ - bool has_alpha; -}; - -static const struct wlr_pixel_format_info pixel_format_info[] = { - { - .drm_format = DRM_FORMAT_XRGB8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ARGB8888, - .opaque_substitute = DRM_FORMAT_XRGB8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ABGR8888, - .opaque_substitute = DRM_FORMAT_XBGR8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_RGBX8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_RGBA8888, - .opaque_substitute = DRM_FORMAT_RGBX8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_BGRX8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_BGRA8888, - .opaque_substitute = DRM_FORMAT_BGRX8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_R8, - .bytes_per_block = 1, - }, - { - .drm_format = DRM_FORMAT_GR88, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_RGB888, - .bytes_per_block = 3, - }, - { - .drm_format = DRM_FORMAT_BGR888, - .bytes_per_block = 3, - }, - { - .drm_format = DRM_FORMAT_RGBX4444, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_RGBA4444, - .opaque_substitute = DRM_FORMAT_RGBX4444, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_BGRX4444, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_BGRA4444, - .opaque_substitute = DRM_FORMAT_BGRX4444, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_RGBX5551, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_RGBA5551, - .opaque_substitute = DRM_FORMAT_RGBX5551, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_BGRX5551, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_BGRA5551, - .opaque_substitute = DRM_FORMAT_BGRX5551, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XRGB1555, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_ARGB1555, - .opaque_substitute = DRM_FORMAT_XRGB1555, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_RGB565, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_BGR565, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_XRGB2101010, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ARGB2101010, - .opaque_substitute = DRM_FORMAT_XRGB2101010, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR2101010, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ABGR2101010, - .opaque_substitute = DRM_FORMAT_XBGR2101010, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR16161616F, - .bytes_per_block = 8, - }, - { - .drm_format = DRM_FORMAT_ABGR16161616F, - .opaque_substitute = DRM_FORMAT_XBGR16161616F, - .bytes_per_block = 8, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR16161616, - .bytes_per_block = 8, - }, - { - .drm_format = DRM_FORMAT_ABGR16161616, - .opaque_substitute = DRM_FORMAT_XBGR16161616, - .bytes_per_block = 8, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_YVYU, - .bytes_per_block = 4, - .block_width = 2, - .block_height = 1, - }, - { - .drm_format = DRM_FORMAT_VYUY, - .bytes_per_block = 4, - .block_width = 2, - .block_height = 1, - }, -}; - -static const size_t pixel_format_info_size = sizeof(pixel_format_info) / sizeof(pixel_format_info[0]); - -static const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) { - for (size_t i = 0; i < pixel_format_info_size; ++i) { - if (pixel_format_info[i].drm_format == fmt) { - return &pixel_format_info[i]; - } - } - - return NULL; -} - -/*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) { - case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888; - case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888; - default: return (enum wl_shm_format)fmt; - } -} - -static uint32_t pixel_format_info_pixels_per_block(const struct wlr_pixel_format_info* info) { - uint32_t pixels = info->block_width * info->block_height; - return pixels > 0 ? pixels : 1; -} - -static int32_t div_round_up(int32_t dividend, int32_t divisor) { - int32_t quotient = dividend / divisor; - if (dividend % divisor != 0) { - quotient++; - } - return quotient; -} - -static int32_t pixel_format_info_min_stride(const wlr_pixel_format_info* fmt, int32_t width) { - int32_t pixels_per_block = (int32_t)pixel_format_info_pixels_per_block(fmt); - int32_t bytes_per_block = (int32_t)fmt->bytes_per_block; - if (width > INT32_MAX / bytes_per_block) { - wlr_log(WLR_DEBUG, "Invalid width %d (overflow)", width); - return 0; - } - return div_round_up(width * bytes_per_block, pixels_per_block); -} - -#endif
\ No newline at end of file diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp new file mode 100644 index 00000000..8cb69dbe --- /dev/null +++ b/src/protocols/Viewporter.cpp @@ -0,0 +1,126 @@ +#include "Viewporter.hpp" +#include "core/Compositor.hpp" +#include <algorithm> + +#define LOGM PROTO::viewport->protoLog + +CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); }); + resource->setOnDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); }); + + resource->setSetDestination([this](CWpViewport* r, int32_t x, int32_t y) { + if (!surface) { + r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + if (x == -1 && y == -1) { + surface->pending.viewport.hasDestination = false; + return; + } + + if (x <= 0 || y <= 0) { + r->error(WP_VIEWPORT_ERROR_BAD_SIZE, "Size was <= 0"); + return; + } + + surface->pending.viewport.hasDestination = true; + surface->pending.viewport.destination = {x, y}; + }); + + resource->setSetSource([this](CWpViewport* r, wl_fixed_t fx, wl_fixed_t fy, wl_fixed_t fw, wl_fixed_t fh) { + if (!surface) { + r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + double x = wl_fixed_to_double(fx), y = wl_fixed_to_double(fy), w = wl_fixed_to_double(fw), h = wl_fixed_to_double(fh); + + if (x == -1 && y == -1 && w == -1 && h == -1) { + surface->pending.viewport.hasSource = false; + return; + } + + if (x < 0 || y < 0) { + r->error(WP_VIEWPORT_ERROR_BAD_SIZE, "Pos was < 0"); + return; + } + + surface->pending.viewport.hasSource = true; + surface->pending.viewport.source = {x, y, w, h}; + }); +} + +CViewportResource::~CViewportResource() { + if (!surface) + return; + + surface->pending.viewport.hasDestination = false; + surface->pending.viewport.hasSource = false; +} + +bool CViewportResource::good() { + return resource->resource(); +} + +void CViewportResource::verify() { + if (!surface) + return; + + if (surface->pending.viewport.hasSource) { + auto& src = surface->pending.viewport.source; + + if (src.w + src.x > surface->pending.size.x || src.h + src.y > surface->pending.size.y) { + resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); + return; + } + } +} + +CViewporterResource::CViewporterResource(SP<CWpViewporter> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpViewporter* r) { PROTO::viewport->destroyResource(this); }); + resource->setOnDestroy([this](CWpViewporter* r) { PROTO::viewport->destroyResource(this); }); + + resource->setGetViewport([](CWpViewporter* r, uint32_t id, wl_resource* surf) { + const auto RESOURCE = PROTO::viewport->m_vViewports.emplace_back( + makeShared<CViewportResource>(makeShared<CWpViewport>(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::viewport->m_vViewports.pop_back(); + return; + } + }); +} + +bool CViewporterResource::good() { + return resource->resource(); +} + +CViewporterProtocol::CViewporterProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CViewporterProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared<CViewporterResource>(makeShared<CWpViewporter>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CViewporterProtocol::destroyResource(CViewporterResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CViewporterProtocol::destroyResource(CViewportResource* resource) { + std::erase_if(m_vViewports, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/Viewporter.hpp b/src/protocols/Viewporter.hpp new file mode 100644 index 00000000..01278203 --- /dev/null +++ b/src/protocols/Viewporter.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include <memory> +#include <vector> +#include <cstdint> +#include "WaylandProtocol.hpp" +#include "viewporter.hpp" +#include "../helpers/signal/Signal.hpp" + +class CWLSurfaceResource; + +class CViewportResource { + public: + CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceResource> surface_); + ~CViewportResource(); + + bool good(); + void verify(); + WP<CWLSurfaceResource> surface; + + private: + SP<CWpViewport> resource; +}; + +class CViewporterResource { + public: + CViewporterResource(SP<CWpViewporter> resource_); + + bool good(); + + private: + SP<CWpViewporter> resource; +}; + +class CViewporterProtocol : public IWaylandProtocol { + public: + CViewporterProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CViewporterResource* resource); + void destroyResource(CViewportResource* resource); + + // + std::vector<SP<CViewporterResource>> m_vManagers; + std::vector<SP<CViewportResource>> m_vViewports; + + friend class CViewporterResource; + friend class CViewportResource; +}; + +namespace PROTO { + inline UP<CViewporterProtocol> viewport; +}; diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 30120235..23a6721c 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -10,6 +10,8 @@ static void displayDestroyInternal(struct wl_listener* listener, void* data) { } void IWaylandProtocol::onDisplayDestroy() { + wl_list_remove(&m_liDisplayDestroy.link); + wl_list_init(&m_liDisplayDestroy.link); wl_global_destroy(m_pGlobal); } @@ -30,3 +32,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co IWaylandProtocol::~IWaylandProtocol() { onDisplayDestroy(); } + +void IWaylandProtocol::removeGlobal() { + wl_global_remove(m_pGlobal); +} diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index a7487c15..b443e253 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -14,9 +14,10 @@ class IWaylandProtocol { public: IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name); - ~IWaylandProtocol(); + virtual ~IWaylandProtocol(); virtual void onDisplayDestroy(); + virtual void removeGlobal(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index 1d9814ac..40f33f02 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -1,6 +1,7 @@ #include "XDGActivation.hpp" #include "../managers/TokenManager.hpp" #include "../Compositor.hpp" +#include "core/Compositor.hpp" #include <algorithm> #define LOGM PROTO::activation->protoLog @@ -79,8 +80,8 @@ void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t // remove token. It's been now spent. m_vSentTokens.erase(TOKEN); - wlr_surface* surf = wlr_surface_from_resource(surface); - const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf); + SP<CWLSurfaceResource> surf = CWLSurfaceResource::fromResource(surface); + const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf); if (!PWINDOW) { LOGM(WARN, "activate event for non-window or gone surface with token {}, ignoring", token); diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 771f5f78..03e58956 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../xwayland/XWayland.hpp" +#include "core/Output.hpp" #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 @@ -48,9 +49,9 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver } void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) { - const auto OUTPUT = wlr_output_from_resource(outputResource); + const auto OUTPUT = CWLOutputResource::fromResource(outputResource); - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT); + const auto PMONITOR = OUTPUT->monitor.get(); const auto CLIENT = mgr->client(); diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 80e3487d..97de49f6 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::xdgShell->protoLog @@ -288,7 +289,8 @@ void CXDGToplevelResource::close() { resource->sendClose(); } -CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, wlr_surface* surface_) : owner(owner_), surface(surface_), resource(resource_) { +CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, SP<CWLSurfaceResource> surface_) : + owner(owner_), surface(surface_), resource(resource_) { if (!good()) return; @@ -307,56 +309,50 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas PROTO::xdgShell->destroyResource(this); }); - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, - [this](void* owner, void* data) { - LOGM(WARN, "wl_surface destroyed before its xdg_surface role object"); - hyprListener_surfaceDestroy.removeCallback(); - hyprListener_surfaceCommit.removeCallback(); - - if (mapped) - events.unmap.emit(); - - mapped = false; - surface = nullptr; - events.destroy.emit(); - }, - nullptr, "CXDGSurfaceResource"); - - hyprListener_surfaceCommit.initCallback( - &surface->events.commit, - [this](void* owner, void* data) { - current = pending; + listeners.surfaceDestroy = surface->events.destroy.registerListener([this](std::any d) { + LOGM(WARN, "wl_surface destroyed before its xdg_surface role object"); + listeners.surfaceDestroy.reset(); + listeners.surfaceCommit.reset(); + + if (mapped) + events.unmap.emit(); + + mapped = false; + surface.reset(); + events.destroy.emit(); + }); + + listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) { + current = pending; + if (toplevel) + toplevel->current = toplevel->pending; + + if (initialCommit && surface->pending.buffer) { + resource->error(-1, "Buffer attached before initial commit"); + return; + } + + if (surface->current.buffer && !mapped) { + // this forces apps to not draw CSD. if (toplevel) - toplevel->current = toplevel->pending; - - if (initialCommit && surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) { - resource->error(-1, "Buffer attached before initial commit"); - return; - } - - if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) { - // this forces apps to not draw CSD. - if (toplevel) - toplevel->setMaximized(true); - - mapped = true; - wlr_surface_map(surface); - events.map.emit(); - return; - } - - if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) { - mapped = false; - wlr_surface_unmap(surface); - events.unmap.emit(); - return; - } - - events.commit.emit(); - initialCommit = false; - }, - nullptr, "CXDGSurfaceResource"); + toplevel->setMaximized(true); + + mapped = true; + surface->map(); + events.map.emit(); + return; + } + + if (!surface->current.buffer && mapped) { + mapped = false; + surface->unmap(); + events.unmap.emit(); + return; + } + + events.commit.emit(); + initialCommit = false; + }); resource->setGetToplevel([this](CXdgSurface* r, uint32_t id) { const auto RESOURCE = PROTO::xdgShell->m_vToplevels.emplace_back(makeShared<CXDGToplevelResource>(makeShared<CXdgToplevel>(r->client(), r->version(), id), self.lock())); @@ -649,7 +645,7 @@ CXDGWMBase::CXDGWMBase(SP<CXdgWmBase> resource_) : resource(resource_) { resource->setGetXdgSurface([this](CXdgWmBase* r, uint32_t id, wl_resource* surf) { const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back( - makeShared<CXDGSurfaceResource>(makeShared<CXdgSurface>(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surf))); + makeShared<CXDGSurfaceResource>(makeShared<CXdgSurface>(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surf))); if (!RESOURCE->good()) { r->noMemory(); @@ -724,9 +720,9 @@ void CXDGShellProtocol::addOrStartGrab(SP<CXDGPopupResource> popup) { grabOwner = popup; grabbed.clear(); grab->clear(); - grab->add(popup->surface->surface); + grab->add(popup->surface->surface.lock()); if (popup->parent) - grab->add(popup->parent->surface); + grab->add(popup->parent->surface.lock()); g_pSeatManager->setGrab(grab); grabbed.emplace_back(popup); return; @@ -734,10 +730,10 @@ void CXDGShellProtocol::addOrStartGrab(SP<CXDGPopupResource> popup) { grabbed.emplace_back(popup); - grab->add(popup->surface->surface); + grab->add(popup->surface->surface.lock()); if (popup->parent) - grab->add(popup->parent->surface); + grab->add(popup->parent->surface.lock()); } void CXDGShellProtocol::onPopupDestroy(WP<CXDGPopupResource> popup) { @@ -752,5 +748,5 @@ void CXDGShellProtocol::onPopupDestroy(WP<CXDGPopupResource> popup) { std::erase(grabbed, popup); if (popup->surface) - grab->remove(popup->surface->surface); + grab->remove(popup->surface->surface.lock()); } diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 1dbeb209..fe2517a2 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -16,6 +16,7 @@ class CXDGSurfaceResource; class CXDGToplevelResource; class CXDGPopupResource; class CSeatGrab; +class CWLSurfaceResource; struct SXDGPositionerState { Vector2D requestedSize; @@ -138,7 +139,7 @@ class CXDGToplevelResource { class CXDGSurfaceResource { public: - CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, wlr_surface* surface_); + CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBase> owner_, SP<CWLSurfaceResource> surface_); ~CXDGSurfaceResource(); static SP<CXDGSurfaceResource> fromResource(wl_resource*); @@ -146,7 +147,7 @@ class CXDGSurfaceResource { bool good(); WP<CXDGWMBase> owner; - wlr_surface* surface = nullptr; + WP<CWLSurfaceResource> surface; WP<CXDGToplevelResource> toplevel; WP<CXDGPopupResource> popup; @@ -184,8 +185,10 @@ class CXDGSurfaceResource { // std::vector<WP<CXDGPopupResource>> popups; - DYNLISTENER(surfaceDestroy); - DYNLISTENER(surfaceCommit); + struct { + CHyprSignalListener surfaceDestroy; + CHyprSignalListener surfaceCommit; + } listeners; friend class CXDGPopupResource; friend class CXDGToplevelResource; diff --git a/src/protocols/XWaylandShell.cpp b/src/protocols/XWaylandShell.cpp index 8b9905f8..6cc5256f 100644 --- a/src/protocols/XWaylandShell.cpp +++ b/src/protocols/XWaylandShell.cpp @@ -1,9 +1,10 @@ #include "XWaylandShell.hpp" +#include "core/Compositor.hpp" #include <algorithm> #define LOGM PROTO::xwaylandShell->protoLog -CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, wlr_surface* surface_) : surface(surface_), resource(resource_) { +CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, SP<CWLSurfaceResource> surface_) : surface(surface_), resource(resource_) { if (!good()) return; @@ -45,7 +46,7 @@ CXWaylandShellResource::CXWaylandShellResource(SP<CXwaylandShellV1> resource_) : resource->setGetXwaylandSurface([this](CXwaylandShellV1* r, uint32_t id, wl_resource* surface) { const auto RESOURCE = PROTO::xwaylandShell->m_vSurfaces.emplace_back( - makeShared<CXWaylandSurfaceResource>(makeShared<CXwaylandSurfaceV1>(r->client(), r->version(), id), wlr_surface_from_resource(surface))); + makeShared<CXWaylandSurfaceResource>(makeShared<CXwaylandSurfaceV1>(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surface))); if (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/XWaylandShell.hpp b/src/protocols/XWaylandShell.hpp index 2c03d172..c8c0c04a 100644 --- a/src/protocols/XWaylandShell.hpp +++ b/src/protocols/XWaylandShell.hpp @@ -7,9 +7,11 @@ #include "xwayland-shell-v1.hpp" #include "../helpers/signal/Signal.hpp" +class CWLSurfaceResource; + class CXWaylandSurfaceResource { public: - CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, wlr_surface* surface_); + CXWaylandSurfaceResource(SP<CXwaylandSurfaceV1> resource_, SP<CWLSurfaceResource> surface_); ~CXWaylandSurfaceResource(); bool good(); @@ -19,8 +21,8 @@ class CXWaylandSurfaceResource { CSignal destroy; } events; - uint64_t serial = 0; - wlr_surface* surface = nullptr; + uint64_t serial = 0; + WP<CWLSurfaceResource> surface; WP<CXWaylandSurfaceResource> self; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp new file mode 100644 index 00000000..e8503ae8 --- /dev/null +++ b/src/protocols/core/Compositor.cpp @@ -0,0 +1,467 @@ +#include "Compositor.hpp" +#include "Output.hpp" +#include "../types/WLBuffer.hpp" +#include <algorithm> +#include <ranges> +#include "Subcompositor.hpp" +#include "../Viewporter.hpp" +#include "../../helpers/Monitor.hpp" + +#define LOGM PROTO::compositor->protoLog + +class CDefaultSurfaceRole : public ISurfaceRole { + public: + virtual eSurfaceRole role() { + return SURFACE_ROLE_UNASSIGNED; + } +}; + +SP<CDefaultSurfaceRole> defaultRole = makeShared<CDefaultSurfaceRole>(); + +CWLCallbackResource::CWLCallbackResource(SP<CWlCallback> resource_) : resource(resource_) { + ; +} + +bool CWLCallbackResource::good() { + return resource->resource(); +} + +void CWLCallbackResource::send(timespec* now) { + resource->sendDone(now->tv_sec * 1000 + now->tv_nsec / 1000000); +} + +CWLRegionResource::CWLRegionResource(SP<CWlRegion> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CWlRegion* r) { PROTO::compositor->destroyResource(this); }); + resource->setOnDestroy([this](CWlRegion* r) { PROTO::compositor->destroyResource(this); }); + + resource->setAdd([this](CWlRegion* r, int32_t x, int32_t y, int32_t w, int32_t h) { region.add(CBox{x, y, w, h}); }); + resource->setSubtract([this](CWlRegion* r, int32_t x, int32_t y, int32_t w, int32_t h) { region.subtract(CBox{x, y, w, h}); }); +} + +bool CWLRegionResource::good() { + return resource->resource(); +} + +SP<CWLRegionResource> CWLRegionResource::fromResource(wl_resource* res) { + auto data = (CWLRegionResource*)(((CWlRegion*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setData(this); + + role = defaultRole; + + resource->setDestroy([this](CWlSurface* r) { destroy(); }); + resource->setOnDestroy([this](CWlSurface* r) { destroy(); }); + + resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) { + pending.offset = {x, y}; + + if (!buffer) { + pending.buffer.reset(); + pending.texture.reset(); + } else { + auto res = CWLBufferResource::fromResource(buffer); + pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr; + pending.size = res && res->buffer ? res->buffer->size : Vector2D{}; + pending.texture = res && res->buffer ? res->buffer->texture : nullptr; + } + + Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{}; + Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{}; + + if (oldBufSize != newBufSize) + pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; + + bufferReleased = false; + }); + + resource->setCommit([this](CWlSurface* r) { + if (pending.buffer) + pending.bufferDamage.intersect(CBox{{}, pending.buffer->size}); + + if (!pending.buffer) + pending.size = {}; + else if (pending.viewport.hasDestination) + pending.size = pending.viewport.destination; + else if (pending.viewport.hasSource) + pending.size = pending.viewport.source.size(); + else { + Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.buffer->size.y, pending.buffer->size.x} : pending.buffer->size; + pending.size = tfs / pending.scale; + } + + if (viewportResource) + viewportResource->verify(); + + pending.damage.intersect(CBox{{}, pending.size}); + + CRegion previousBufferDamage = accumulateCurrentBufferDamage(); + + current = pending; + pending.damage.clear(); + pending.bufferDamage.clear(); + + if (current.buffer && !bufferReleased) { + // without previous dolphin et al are weird vvv + //CRegion surfaceDamage = + // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); + current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. + + // release the buffer, glTexImage2D is synchronous (as in, data is consumed after the call returns) + // so we can let the app know we're done. + // for dma buffers, this doesn't matter. + current.buffer->sendRelease(); + bufferReleased = true; + } + + // TODO: we should _accumulate_ and not replace above if sync + if (role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)role.get(); + if (subsurface->sync) + return; + + events.commit.emit(); + } else { + // send commit to all synced surfaces in this tree. + breadthfirst( + [](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { + if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); + if (!subsurface->sync) + return; + } + surf->events.commit.emit(); + }, + nullptr); + } + }); + + resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); }); + resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.bufferDamage.add(CBox{x, y, w, h}); }); + + resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) { pending.scale = scale; }); + resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) { pending.transform = (wl_output_transform)tr; }); + + resource->setSetInputRegion([this](CWlSurface* r, wl_resource* region) { + if (!region) { + pending.input = CBox{{}, {INT32_MAX, INT32_MAX}}; + return; + } + + auto RG = CWLRegionResource::fromResource(region); + pending.input = RG->region; + }); + + resource->setSetOpaqueRegion([this](CWlSurface* r, wl_resource* region) { + if (!region) { + pending.opaque = CBox{{}, {}}; + return; + } + + auto RG = CWLRegionResource::fromResource(region); + pending.opaque = RG->region; + }); + + resource->setFrame([this](CWlSurface* r, uint32_t id) { callbacks.emplace_back(makeShared<CWLCallbackResource>(makeShared<CWlCallback>(pClient, 1, id))); }); + + resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) { pending.offset = {x, y}; }); +} + +CWLSurfaceResource::~CWLSurfaceResource() { + events.destroy.emit(); +} + +void CWLSurfaceResource::destroy() { + if (mapped) + unmap(); + events.destroy.emit(); + PROTO::compositor->destroyResource(this); +} + +SP<CWLSurfaceResource> CWLSurfaceResource::fromResource(wl_resource* res) { + auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CWLSurfaceResource::good() { + return resource->resource(); +} + +wl_client* CWLSurfaceResource::client() { + return pClient; +} + +void CWLSurfaceResource::enter(SP<CMonitor> monitor) { + if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) != enteredOutputs.end()) + return; + + if (!PROTO::outputs.contains(monitor->szName)) { + // can happen on unplug/replug + LOGM(ERR, "enter() called on a non-existent output global"); + return; + } + + auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient); + + if (!output || !output->getResource() || !output->getResource()->resource()) { + LOGM(ERR, "Cannot enter surface {:x} to {}, client hasn't bound the output", (uintptr_t)this, monitor->szName); + return; + } + + enteredOutputs.emplace_back(monitor); + + resource->sendEnter(output->getResource().get()); +} + +void CWLSurfaceResource::leave(SP<CMonitor> monitor) { + if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) == enteredOutputs.end()) + return; + + auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient); + + if (!output) { + LOGM(ERR, "Cannot leave surface {:x} from {}, client hasn't bound the output", (uintptr_t)this, monitor->szName); + return; + } + + std::erase(enteredOutputs, monitor); + + resource->sendLeave(output->getResource().get()); +} + +void CWLSurfaceResource::sendPreferredTransform(wl_output_transform t) { + if (resource->version() < 6) + return; + resource->sendPreferredBufferTransform(t); +} + +void CWLSurfaceResource::sendPreferredScale(int32_t scale) { + if (resource->version() < 6) + return; + resource->sendPreferredBufferScale(scale); +} + +void CWLSurfaceResource::frame(timespec* now) { + if (callbacks.empty()) + return; + + for (auto& c : callbacks) { + c->send(now); + } + + callbacks.clear(); +} + +void CWLSurfaceResource::resetRole() { + role = defaultRole; +} + +void CWLSurfaceResource::bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) { + for (auto& n : nodes) { + + Vector2D offset = {}; + if (n->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)n->role.get(); + offset = subsurface->posRelativeToParent(); + } + + fn(n, offset, data); + } + + std::vector<SP<CWLSurfaceResource>> nodes2; + + for (auto& n : nodes) { + std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); + for (auto& c : n->subsurfaces) { + nodes2.push_back(c->surface.lock()); + } + } + + if (!nodes2.empty()) + bfHelper(nodes2, fn, data); +} + +void CWLSurfaceResource::breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data) { + std::vector<SP<CWLSurfaceResource>> surfs; + surfs.push_back(self.lock()); + bfHelper(surfs, fn, data); +} + +std::pair<SP<CWLSurfaceResource>, Vector2D> CWLSurfaceResource::at(const Vector2D& localCoords, bool allowsInput) { + std::vector<std::pair<SP<CWLSurfaceResource>, Vector2D>> surfs; + breadthfirst([](SP<CWLSurfaceResource> surf, const Vector2D& offset, + void* data) { ((std::vector<std::pair<SP<CWLSurfaceResource>, Vector2D>>*)data)->emplace_back(std::make_pair<>(surf, offset)); }, + &surfs); + + for (auto& [surf, pos] : surfs | std::views::reverse) { + if (!allowsInput) { + const auto BOX = CBox{pos, surf->current.size}; + if (BOX.containsPoint(localCoords)) + return {surf, localCoords - pos}; + } else { + const auto REGION = surf->current.input.copy().intersect(CBox{{}, surf->current.size}).translate(pos); + if (REGION.containsPoint(localCoords)) + return {surf, localCoords - pos}; + } + } + + return {nullptr, {}}; +} + +uint32_t CWLSurfaceResource::id() { + return wl_resource_get_id(resource->resource()); +} + +void CWLSurfaceResource::map() { + if (mapped) + return; + + mapped = true; + + events.map.emit(); + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + frame(&now); + + current.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; + pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; +} + +void CWLSurfaceResource::unmap() { + if (!mapped) + return; + + mapped = false; + + events.unmap.emit(); +} + +void CWLSurfaceResource::error(int code, const std::string& str) { + resource->error(code, str); +} + +SP<CWlSurface> CWLSurfaceResource::getResource() { + return resource; +} + +CBox CWLSurfaceResource::extends() { + CRegion full = CBox{{}, current.size}; + breadthfirst( + [](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* d) { + if (surf->role->role() != SURFACE_ROLE_SUBSURFACE) + return; + + ((CRegion*)d)->add(CBox{offset, surf->current.size}); + }, + &full); + return full.getExtents(); +} + +Vector2D CWLSurfaceResource::sourceSize() { + if (!current.buffer) + return {}; + + if (current.viewport.hasSource) + return current.viewport.source.size(); + + Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + return trc / current.scale; +} + +CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { + if (!current.buffer) + return {}; + + CRegion surfaceDamage = current.damage; + if (current.viewport.hasDestination) { + Vector2D scale = sourceSize() / current.viewport.destination; + surfaceDamage.scale(scale); + } + + if (current.viewport.hasSource) + surfaceDamage.translate(current.viewport.source.pos()); + + Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + + return surfaceDamage.scale(current.scale).transform(wlr_output_transform_invert(current.transform), trc.x, trc.y).add(current.bufferDamage); +} + +CWLCompositorResource::CWLCompositorResource(SP<CWlCompositor> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlCompositor* r) { PROTO::compositor->destroyResource(this); }); + + resource->setCreateSurface([](CWlCompositor* r, uint32_t id) { + const auto RESOURCE = PROTO::compositor->m_vSurfaces.emplace_back(makeShared<CWLSurfaceResource>(makeShared<CWlSurface>(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::compositor->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New wl_surface with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); + + PROTO::compositor->events.newSurface.emit(RESOURCE); + }); + + resource->setCreateRegion([](CWlCompositor* r, uint32_t id) { + const auto RESOURCE = PROTO::compositor->m_vRegions.emplace_back(makeShared<CWLRegionResource>(makeShared<CWlRegion>(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::compositor->m_vRegions.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New wl_region with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); + }); +} + +bool CWLCompositorResource::good() { + return resource->resource(); +} + +CWLCompositorProtocol::CWLCompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLCompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared<CWLCompositorResource>(makeShared<CWlCompositor>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CWLCompositorProtocol::destroyResource(CWLCompositorResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLCompositorProtocol::destroyResource(CWLSurfaceResource* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLCompositorProtocol::destroyResource(CWLRegionResource* resource) { + std::erase_if(m_vRegions, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp new file mode 100644 index 00000000..f50144bf --- /dev/null +++ b/src/protocols/core/Compositor.hpp @@ -0,0 +1,175 @@ +#pragma once + +/* + Implementations for: + - wl_compositor + - wl_surface + - wl_region + - wl_callback +*/ + +#include <memory> +#include <vector> +#include <cstdint> +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../../helpers/Region.hpp" +#include "../types/Buffer.hpp" +#include "../types/SurfaceRole.hpp" + +class CWLOutputResource; +class CMonitor; +class CWLSurface; +class CWLSurfaceResource; +class CWLSubsurfaceResource; +class CViewportResource; + +class CWLCallbackResource { + public: + CWLCallbackResource(SP<CWlCallback> resource_); + + bool good(); + void send(timespec* now); + + private: + SP<CWlCallback> resource; +}; + +class CWLRegionResource { + public: + CWLRegionResource(SP<CWlRegion> resource_); + static SP<CWLRegionResource> fromResource(wl_resource* res); + + bool good(); + + CRegion region; + WP<CWLRegionResource> self; + + private: + SP<CWlRegion> resource; +}; + +class CWLSurfaceResource { + public: + CWLSurfaceResource(SP<CWlSurface> resource_); + ~CWLSurfaceResource(); + + static SP<CWLSurfaceResource> fromResource(wl_resource* res); + + bool good(); + wl_client* client(); + void enter(SP<CMonitor> monitor); + void leave(SP<CMonitor> monitor); + void sendPreferredTransform(wl_output_transform t); + void sendPreferredScale(int32_t scale); + void frame(timespec* now); + uint32_t id(); + void map(); + void unmap(); + void error(int code, const std::string& str); + SP<CWlSurface> getResource(); + CBox extends(); + void resetRole(); + Vector2D sourceSize(); + + struct { + CSignal commit; + CSignal map; + CSignal unmap; + CSignal newSubsurface; + CSignal destroy; + } events; + + struct { + CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + int scale = 1; + SP<IWLBuffer> buffer; + SP<CTexture> texture; + Vector2D offset; + Vector2D size; + struct { + bool hasDestination = false; + bool hasSource = false; + Vector2D destination; + CBox source; + } viewport; + + // + void reset() { + damage.clear(); + bufferDamage.clear(); + transform = WL_OUTPUT_TRANSFORM_NORMAL; + scale = 1; + offset = {}; + size = {}; + } + } current, pending; + + std::vector<SP<CWLCallbackResource>> callbacks; + WP<CWLSurfaceResource> self; + WP<CWLSurface> hlSurface; + std::vector<WP<CMonitor>> enteredOutputs; + bool mapped = false; + std::vector<WP<CWLSubsurfaceResource>> subsurfaces; + WP<ISurfaceRole> role; + WP<CViewportResource> viewportResource; + + void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data); + CRegion accumulateCurrentBufferDamage(); + + // returns a pair: found surface (null if not found) and surface local coords. + // localCoords param is relative to 0,0 of this surface + std::pair<SP<CWLSurfaceResource>, Vector2D> at(const Vector2D& localCoords, bool allowsInput = false); + + private: + SP<CWlSurface> resource; + wl_client* pClient = nullptr; + + // tracks whether we should release the buffer + bool bufferReleased = false; + + void destroy(); + void bfHelper(std::vector<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data); +}; + +class CWLCompositorResource { + public: + CWLCompositorResource(SP<CWlCompositor> resource_); + + bool good(); + + private: + SP<CWlCompositor> resource; +}; + +class CWLCompositorProtocol : public IWaylandProtocol { + public: + CWLCompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + struct { + CSignal newSurface; // SP<CWLSurfaceResource> + } events; + + private: + void destroyResource(CWLCompositorResource* resource); + void destroyResource(CWLSurfaceResource* resource); + void destroyResource(CWLRegionResource* resource); + + // + std::vector<SP<CWLCompositorResource>> m_vManagers; + std::vector<SP<CWLSurfaceResource>> m_vSurfaces; + std::vector<SP<CWLRegionResource>> m_vRegions; + + friend class CWLSurfaceResource; + friend class CWLCompositorResource; + friend class CWLRegionResource; + friend class CWLCallbackResource; +}; + +namespace PROTO { + inline UP<CWLCompositorProtocol> compositor; +}; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 354259fe..ca044e93 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -4,6 +4,7 @@ #include "../../managers/PointerManager.hpp" #include "../../Compositor.hpp" #include "Seat.hpp" +#include "Compositor.hpp" #define LOGM PROTO::data->protoLog @@ -233,7 +234,7 @@ CWLDataDeviceResource::CWLDataDeviceResource(SP<CWlDataDevice> resource_) : reso source->dnd = true; - PROTO::data->initiateDrag(source, icon ? wlr_surface_from_resource(icon) : nullptr, wlr_surface_from_resource(origin)); + PROTO::data->initiateDrag(source, icon ? CWLSurfaceResource::fromResource(icon) : nullptr, CWLSurfaceResource::fromResource(origin)); }); } @@ -252,8 +253,8 @@ void CWLDataDeviceResource::sendDataOffer(SP<CWLDataOfferResource> offer) { resource->sendDataOfferRaw(nullptr); } -void CWLDataDeviceResource::sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP<CWLDataOfferResource> offer) { - resource->sendEnterRaw(serial, surf->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource()); +void CWLDataDeviceResource::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<CWLDataOfferResource> offer) { + resource->sendEnterRaw(serial, surf->getResource()->resource(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource()); } void CWLDataDeviceResource::sendLeave() { @@ -454,7 +455,7 @@ void CWLDataDeviceProtocol::onKeyboardFocus() { updateDrag(); } -void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource, wlr_surface* dragSurface, wlr_surface* origin) { +void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource, SP<CWLSurfaceResource> dragSurface, SP<CWLSurfaceResource> origin) { if (dnd.currentSource) { LOGM(WARN, "New drag started while old drag still active??"); @@ -472,22 +473,18 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource dnd.originSurface = origin; dnd.dndSurface = dragSurface; if (dragSurface) { - dnd.hyprListener_dndSurfaceDestroy.initCallback( - &dragSurface->events.destroy, [this](void* owner, void* data) { abortDrag(); }, nullptr, "CWLDataDeviceProtocol::drag"); - dnd.hyprListener_dndSurfaceCommit.initCallback( - &dragSurface->events.commit, - [this](void* owner, void* data) { - if (dnd.dndSurface->pending.buffer_width > 0 && dnd.dndSurface->pending.buffer_height > 0 && !dnd.dndSurface->mapped) { - wlr_surface_map(dnd.dndSurface); - return; - } - - if (dnd.dndSurface->pending.buffer_width <= 0 && dnd.dndSurface->pending.buffer_height <= 0 && dnd.dndSurface->mapped) { - wlr_surface_unmap(dnd.dndSurface); - return; - } - }, - nullptr, "CWLDataDeviceProtocol::drag"); + dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); }); + dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) { + if (dnd.dndSurface->current.buffer && !dnd.dndSurface->mapped) { + dnd.dndSurface->map(); + return; + } + + if (dnd.dndSurface->current.buffer <= 0 && dnd.dndSurface->mapped) { + dnd.dndSurface->unmap(); + return; + } + }); } dnd.mouseButton = g_pHookSystem->hookDynamic("mouseButton", [this](void* self, SCallbackInfo& info, std::any e) { @@ -506,7 +503,7 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource dnd.mouseMove = g_pHookSystem->hookDynamic("mouseMove", [this](void* self, SCallbackInfo& info, std::any e) { auto V = std::any_cast<const Vector2D>(e); if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { - auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus); + auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock()); if (!surf) return; @@ -524,7 +521,7 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource dnd.touchMove = g_pHookSystem->hookDynamic("touchMove", [this](void* self, SCallbackInfo& info, std::any e) { auto E = std::any_cast<ITouch::SMotionEvent>(e); if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { - auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus); + auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock()); if (!surf) return; @@ -572,14 +569,14 @@ void CWLDataDeviceProtocol::updateDrag() { dnd.focusedDevice->sendDataOffer(OFFER); OFFER->sendData(); - dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus, - Vector2D{g_pSeatManager->state.keyboardFocus->current.width, g_pSeatManager->state.keyboardFocus->current.height} / 2.F, OFFER); + dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus.lock(), + g_pSeatManager->state.keyboardFocus->current.size / 2.F, OFFER); } void CWLDataDeviceProtocol::resetDndState() { - dnd.dndSurface = nullptr; - dnd.hyprListener_dndSurfaceDestroy.removeCallback(); - dnd.hyprListener_dndSurfaceCommit.removeCallback(); + dnd.dndSurface.reset(); + dnd.dndSurfaceCommit.reset(); + dnd.dndSurfaceDestroy.reset(); dnd.mouseButton.reset(); dnd.mouseMove.reset(); dnd.touchUp.reset(); @@ -638,20 +635,18 @@ void CWLDataDeviceProtocol::abortDrag() { } void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { - if (!dnd.dndSurface || !wlr_surface_get_texture(dnd.dndSurface)) + if (!dnd.dndSurface || !dnd.dndSurface->current.buffer || !dnd.dndSurface->current.buffer->texture) return; const auto POS = g_pInputManager->getMouseCoordsInternal(); - CBox box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}} - .translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F) - .scale(pMonitor->scale); - g_pHyprOpenGL->renderTexture(wlr_surface_get_texture(dnd.dndSurface), &box, 1.F); + CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale); + g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.buffer->texture, &box, 1.F); - box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}}.translate(g_pPointerManager->cursorSizeLogical() / 2.F); + box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F); g_pHyprRenderer->damageBox(&box); - wlr_surface_send_frame_done(dnd.dndSurface, when); + dnd.dndSurface->frame(when); } bool CWLDataDeviceProtocol::dndActive() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 3112b720..f31725ee 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -23,6 +23,7 @@ class CWLDataDeviceManagerResource; class CWLDataSourceResource; class CWLDataOfferResource; +class CWLSurfaceResource; class CMonitor; class CWLDataOfferResource { @@ -92,7 +93,7 @@ class CWLDataDeviceResource { wl_client* client(); void sendDataOffer(SP<CWLDataOfferResource> offer); - void sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP<CWLDataOfferResource> offer); + void sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, const Vector2D& local, SP<CWLDataOfferResource> offer); void sendLeave(); void sendMotion(uint32_t timeMs, const Vector2D& local); void sendDrop(); @@ -155,11 +156,11 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { struct { WP<CWLDataDeviceResource> focusedDevice; WP<CWLDataSourceResource> currentSource; - wlr_surface* dndSurface = nullptr; - wlr_surface* originSurface = nullptr; // READ-ONLY + WP<CWLSurfaceResource> dndSurface; + WP<CWLSurfaceResource> originSurface; bool overriddenCursor = false; - DYNLISTENER(dndSurfaceDestroy); - DYNLISTENER(dndSurfaceCommit); + CHyprSignalListener dndSurfaceDestroy; + CHyprSignalListener dndSurfaceCommit; // for ending a dnd SP<HOOK_CALLBACK_FN> mouseMove; @@ -169,7 +170,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { } dnd; void abortDrag(); - void initiateDrag(WP<CWLDataSourceResource> currentSource, wlr_surface* dragSurface, wlr_surface* origin); + void initiateDrag(WP<CWLDataSourceResource> currentSource, SP<CWLSurfaceResource> dragSurface, SP<CWLSurfaceResource> origin); void updateDrag(); void dropDrag(); void completeDrag(); diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp new file mode 100644 index 00000000..3778e453 --- /dev/null +++ b/src/protocols/core/Output.cpp @@ -0,0 +1,107 @@ +#include "Output.hpp" +#include "../../helpers/Monitor.hpp" + +CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMonitor) : monitor(pMonitor), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + pClient = resource->client(); + + resource->setOnDestroy([this](CWlOutput* r) { + if (monitor && PROTO::outputs.contains(monitor->szName)) + PROTO::outputs.at(monitor->szName)->destroyResource(this); + }); + resource->setRelease([this](CWlOutput* r) { + if (monitor && PROTO::outputs.contains(monitor->szName)) + PROTO::outputs.at(monitor->szName)->destroyResource(this); + }); + + resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null", + monitor->output->model ? monitor->output->model : "null", monitor->transform); + if (resource->version() >= 4) { + resource->sendName(monitor->szName.c_str()); + resource->sendDescription(monitor->szDescription.c_str()); + } + + updateState(); +} + +SP<CWLOutputResource> CWLOutputResource::fromResource(wl_resource* res) { + auto data = (CWLOutputResource*)(((CWlOutput*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CWLOutputResource::good() { + return resource->resource(); +} + +wl_client* CWLOutputResource::client() { + return pClient; +} + +SP<CWlOutput> CWLOutputResource::getResource() { + return resource; +} + +void CWLOutputResource::updateState() { + if (!monitor) + return; + + if (resource->version() >= 2) + resource->sendScale(std::ceil(monitor->scale)); + + resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED), monitor->vecSize.x, monitor->vecSize.y, monitor->refreshRate * 1000.0); + + if (resource->version() >= 2) + resource->sendDone(); +} + +CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP<CMonitor> pMonitor) : + IWaylandProtocol(iface, ver, name), monitor(pMonitor), szName(pMonitor->szName) { + + listeners.modeChanged = monitor->events.modeChanged.registerListener([this](std::any d) { + for (auto& o : m_vOutputs) { + o->updateState(); + } + }); +} + +void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vOutputs.emplace_back(makeShared<CWLOutputResource>(makeShared<CWlOutput>(client, ver, id), monitor.lock())); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vOutputs.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; +} + +void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) { + std::erase_if(m_vOutputs, [&](const auto& other) { return other.get() == resource; }); + + if (m_vOutputs.empty() && defunct) + PROTO::outputs.erase(szName); +} + +SP<CWLOutputResource> CWLOutputProtocol::outputResourceFrom(wl_client* client) { + for (auto& r : m_vOutputs) { + if (r->client() != client) + continue; + + return r; + } + + return nullptr; +} + +void CWLOutputProtocol::remove() { + if (defunct) + return; + + defunct = true; + removeGlobal(); +} diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp new file mode 100644 index 00000000..5c274612 --- /dev/null +++ b/src/protocols/core/Output.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include <memory> +#include <vector> +#include <cstdint> +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Listener.hpp" + +class CMonitor; + +class CWLOutputResource { + public: + CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMonitor); + static SP<CWLOutputResource> fromResource(wl_resource*); + + bool good(); + wl_client* client(); + SP<CWlOutput> getResource(); + void updateState(); + + WP<CMonitor> monitor; + + WP<CWLOutputResource> self; + + private: + SP<CWlOutput> resource; + wl_client* pClient = nullptr; +}; + +class CWLOutputProtocol : public IWaylandProtocol { + public: + CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP<CMonitor> pMonitor); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + SP<CWLOutputResource> outputResourceFrom(wl_client* client); + + WP<CMonitor> monitor; + + // will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global) + void remove(); + + private: + void destroyResource(CWLOutputResource* resource); + + // + std::vector<SP<CWLOutputResource>> m_vOutputs; + bool defunct = false; + std::string szName = ""; + + struct { + CHyprSignalListener modeChanged; + } listeners; + + friend class CWLOutputResource; +}; + +namespace PROTO { + inline std::unordered_map<std::string, UP<CWLOutputProtocol>> outputs; +}; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 9d5cf496..8bf03909 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -1,4 +1,5 @@ #include "Seat.hpp" +#include "Compositor.hpp" #include "../../devices/IKeyboard.hpp" #include "../../managers/SeatManager.hpp" #include "../../config/ConfigValue.hpp" @@ -20,7 +21,7 @@ bool CWLTouchResource::good() { return resource->resource(); } -void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local) { +void CWLTouchResource::sendDown(SP<CWLSurfaceResource> surface, uint32_t timeMs, int32_t id, const Vector2D& local) { if (!owner) return; @@ -29,15 +30,12 @@ void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t i sendUp(timeMs, id); } - ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + ASSERT(surface->client() == owner->client()); - currentSurface = surface; - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [this, id, timeMs](void* owner, void* data) { sendUp(timeMs + 10 /* hack */, id); }, this, "CWLTouchResource"); + currentSurface = surface; + listeners.destroySurface = surface->events.destroy.registerListener([this, timeMs, id](std::any d) { sendUp(timeMs + 10 /* hack */, id); }); - // FIXME: - // fix this once we get our own wlr_surface, this is horrible - resource->sendDownRaw(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->resource, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); + resource->sendDown(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->getResource().get(), id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { @@ -45,8 +43,8 @@ void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { return; resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id); - currentSurface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); + currentSurface.reset(); + listeners.destroySurface.reset(); } void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { @@ -97,7 +95,7 @@ CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResou return; } - g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? wlr_surface_from_resource(surf) : nullptr, {hotX, hotY}); + g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY}); }); } @@ -105,7 +103,7 @@ bool CWLPointerResource::good() { return resource->resource(); } -void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local) { +void CWLPointerResource::sendEnter(SP<CWLSurfaceResource> surface, const Vector2D& local) { if (!owner || currentSurface == surface) return; @@ -114,22 +112,21 @@ void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local) sendLeave(); } - ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + ASSERT(surface->client() == owner->client()); - currentSurface = surface; - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLPointerResource"); + currentSurface = surface; + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); }); - resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); + resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } void CWLPointerResource::sendLeave() { if (!owner || !currentSurface) return; - resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); - currentSurface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); + resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get()); + currentSurface.reset(); + listeners.destroySurface.reset(); } void CWLPointerResource::sendMotion(uint32_t timeMs, const Vector2D& local) { @@ -237,7 +234,7 @@ void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) { close(fd); } -void CWLKeyboardResource::sendEnter(wlr_surface* surface) { +void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface) { if (!owner || currentSurface == surface) return; @@ -246,16 +243,15 @@ void CWLKeyboardResource::sendEnter(wlr_surface* surface) { sendLeave(); } - ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + ASSERT(surface->client() == owner->client()); - currentSurface = surface; - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLKeyboardResource"); + currentSurface = surface; + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); }); wl_array arr; wl_array_init(&arr); - resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, &arr); + resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), &arr); wl_array_release(&arr); } @@ -264,9 +260,9 @@ void CWLKeyboardResource::sendLeave() { if (!owner || !currentSurface) return; - resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); - currentSurface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); + resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get()); + currentSurface.reset(); + listeners.destroySurface.reset(); } void CWLKeyboardResource::sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) { diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 4cd0d124..524783f9 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -20,6 +20,7 @@ constexpr const char* HL_SEAT_NAME = "Hyprland"; class IKeyboard; +class CWLSurfaceResource; class CWLPointerResource; class CWLKeyboardResource; @@ -31,7 +32,7 @@ class CWLTouchResource { CWLTouchResource(SP<CWlTouch> resource_, SP<CWLSeatResource> owner_); bool good(); - void sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local); + void sendDown(SP<CWLSurfaceResource> surface, uint32_t timeMs, int32_t id, const Vector2D& local); void sendUp(uint32_t timeMs, int32_t id); void sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local); void sendFrame(); @@ -42,10 +43,12 @@ class CWLTouchResource { WP<CWLSeatResource> owner; private: - SP<CWlTouch> resource; - wlr_surface* currentSurface = nullptr; + SP<CWlTouch> resource; + WP<CWLSurfaceResource> currentSurface; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CWLPointerResource { @@ -53,7 +56,7 @@ class CWLPointerResource { CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResource> owner_); bool good(); - void sendEnter(wlr_surface* surface, const Vector2D& local); + void sendEnter(SP<CWLSurfaceResource> surface, const Vector2D& local); void sendLeave(); void sendMotion(uint32_t timeMs, const Vector2D& local); void sendButton(uint32_t timeMs, uint32_t button, wl_pointer_button_state state); @@ -68,10 +71,12 @@ class CWLPointerResource { WP<CWLSeatResource> owner; private: - SP<CWlPointer> resource; - wlr_surface* currentSurface = nullptr; + SP<CWlPointer> resource; + WP<CWLSurfaceResource> currentSurface; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CWLKeyboardResource { @@ -80,7 +85,7 @@ class CWLKeyboardResource { bool good(); void sendKeymap(SP<IKeyboard> keeb); - void sendEnter(wlr_surface* surface); + void sendEnter(SP<CWLSurfaceResource> surface); void sendLeave(); void sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); @@ -89,10 +94,12 @@ class CWLKeyboardResource { WP<CWLSeatResource> owner; private: - SP<CWlKeyboard> resource; - wlr_surface* currentSurface = nullptr; + SP<CWlKeyboard> resource; + WP<CWLSurfaceResource> currentSurface; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CWLSeatResource { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp new file mode 100644 index 00000000..0c01cf80 --- /dev/null +++ b/src/protocols/core/Shm.cpp @@ -0,0 +1,214 @@ +#include "Shm.hpp" +#include <algorithm> +#include <sys/mman.h> +#include <drm_fourcc.h> +#include "../../render/Texture.hpp" +#include "../types/WLBuffer.hpp" +#include "../../Compositor.hpp" +#include "../../helpers/Format.hpp" + +#define LOGM PROTO::shm->protoLog + +CWLSHMBuffer::CWLSHMBuffer(SP<CWLSHMPoolResource> pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { + if (!pool_->pool->data) + return; + + g_pHyprRenderer->makeEGLCurrent(); + + size = size_; + pool = pool_->pool; + stride = stride_; + fmt = fmt_; + offset = offset_; + opaque = FormatUtils::isFormatOpaque(FormatUtils::shmToDRM(fmt_)); + + texture = makeShared<CTexture>(FormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, size_); + + resource = CWLBufferResource::create(makeShared<CWlBuffer>(pool_->resource->client(), 1, id)); + + listeners.bufferResourceDestroy = events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::shm->destroyResource(this); + }); + + success = texture->m_iTexID; + + if (!success) + Debug::log(ERR, "Failed creating a shm texture: null texture id"); +} + +CWLSHMBuffer::~CWLSHMBuffer() { + ; +} + +eBufferCapability CWLSHMBuffer::caps() { + return BUFFER_CAPABILITY_DATAPTR; +} + +eBufferType CWLSHMBuffer::type() { + return BUFFER_TYPE_SHM; +} + +SSHMAttrs CWLSHMBuffer::shm() { + SSHMAttrs attrs; + attrs.success = true; + attrs.fd = pool->fd; + attrs.format = FormatUtils::shmToDRM(fmt); + attrs.size = size; + attrs.stride = stride; + attrs.offset = offset; + return attrs; +} + +std::tuple<uint8_t*, uint32_t, size_t> CWLSHMBuffer::beginDataPtr(uint32_t flags) { + return {(uint8_t*)pool->data + offset, fmt, size.x * size.y * 4}; +} + +void CWLSHMBuffer::endDataPtr() { + ; +} + +bool CWLSHMBuffer::good() { + return success; +} + +void CWLSHMBuffer::update(const CRegion& damage) { + texture->update(FormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage); +} + +CSHMPool::CSHMPool(int fd_, size_t size_) : fd(fd_), size(size_) { + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); +} + +CSHMPool::~CSHMPool() { + munmap(data, size); + close(fd); +} + +void CSHMPool::resize(size_t size_) { + LOGM(LOG, "Resizing a SHM pool from {} to {}", size, size_); + + if (data) + munmap(data, size); + size = size_; + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (!data) + LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); +} + +CWLSHMPoolResource::CWLSHMPoolResource(SP<CWlShmPool> resource_, int fd_, size_t size_) : resource(resource_) { + if (!good()) + return; + + pool = makeShared<CSHMPool>(fd_, size_); + + resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); + resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); + + resource->setResize([this](CWlShmPool* r, int32_t size_) { + if (size_ < (int32_t)pool->size) { + r->error(-1, "Shrinking a shm pool is illegal"); + return; + } + pool->resize(size_); + }); + + resource->setCreateBuffer([this](CWlShmPool* r, uint32_t id, int32_t offset, int32_t w, int32_t h, int32_t stride, uint32_t fmt) { + if (!pool || !pool->data) { + r->error(-1, "The provided shm pool failed to allocate properly"); + return; + } + + if (std::find(PROTO::shm->shmFormats.begin(), PROTO::shm->shmFormats.end(), fmt) == PROTO::shm->shmFormats.end()) { + r->error(WL_SHM_ERROR_INVALID_FORMAT, "Format invalid"); + return; + } + + if (offset < 0 || w <= 0 || h <= 0 || stride <= 0) { + r->error(WL_SHM_ERROR_INVALID_STRIDE, "Invalid stride, w, h, or offset"); + return; + } + + const auto RESOURCE = PROTO::shm->m_vBuffers.emplace_back(makeShared<CWLSHMBuffer>(self.lock(), id, offset, Vector2D{w, h}, stride, fmt)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::shm->m_vBuffers.pop_back(); + return; + } + + // append instance so that buffer knows its owner + RESOURCE->resource->buffer = RESOURCE; + }); + + if (!pool->data) + resource->error(WL_SHM_ERROR_INVALID_FD, "Couldn't mmap from fd"); +} + +bool CWLSHMPoolResource::good() { + return resource->resource(); +} + +CWLSHMResource::CWLSHMResource(SP<CWlShm> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); }); + + resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) { + const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared<CWLSHMPoolResource>(makeShared<CWlShmPool>(r->client(), r->version(), id), fd, size)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::shm->m_vPools.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + + // send a few supported formats. No need for any other I think? + for (auto& s : PROTO::shm->shmFormats) { + resource->sendFormat((wl_shm_format)s); + } +} + +bool CWLSHMResource::good() { + return resource->resource(); +} + +CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + if (shmFormats.empty()) { + size_t len = 0; + const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len); + + for (size_t i = 0; i < len; ++i) { + shmFormats.push_back(FormatUtils::drmToShm(formats[i])); + } + } + + const auto RESOURCE = m_vManagers.emplace_back(makeShared<CWLSHMResource>(makeShared<CWlShm>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CWLSHMProtocol::destroyResource(CWLSHMResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSHMProtocol::destroyResource(CWLSHMPoolResource* resource) { + std::erase_if(m_vPools, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSHMProtocol::destroyResource(CWLSHMBuffer* resource) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp new file mode 100644 index 00000000..862ea112 --- /dev/null +++ b/src/protocols/core/Shm.hpp @@ -0,0 +1,111 @@ +#pragma once + +/* + Implementations for: + - wl_shm + - wl_shm_pool + - wl_buffer with shm +*/ + +#include <memory> +#include <vector> +#include <cstdint> +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../types/Buffer.hpp" +#include "../../helpers/Vector2D.hpp" + +class CWLSHMPoolResource; + +class CSHMPool { + public: + CSHMPool(int fd, size_t size); + ~CSHMPool(); + + int fd = 0; + size_t size = 0; + void* data = nullptr; + + void resize(size_t size); +}; + +class CWLSHMBuffer : public IWLBuffer { + public: + CWLSHMBuffer(SP<CWLSHMPoolResource> pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); + virtual ~CWLSHMBuffer(); + + virtual eBufferCapability caps(); + virtual eBufferType type(); + virtual void update(const CRegion& damage); + virtual SSHMAttrs shm(); + virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + + bool good(); + void updateTexture(); + + int32_t offset = 0, stride = 0; + uint32_t fmt = 0; + SP<CSHMPool> pool; + + private: + bool success = false; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; +}; + +class CWLSHMPoolResource { + public: + CWLSHMPoolResource(SP<CWlShmPool> resource_, int fd, size_t size); + + bool good(); + + SP<CSHMPool> pool; + + WP<CWLSHMPoolResource> self; + + private: + SP<CWlShmPool> resource; + + friend class CWLSHMBuffer; +}; + +class CWLSHMResource { + public: + CWLSHMResource(SP<CWlShm> resource_); + + bool good(); + + private: + SP<CWlShm> resource; +}; + +class CWLSHMProtocol : public IWaylandProtocol { + public: + CWLSHMProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CWLSHMResource* resource); + void destroyResource(CWLSHMPoolResource* resource); + void destroyResource(CWLSHMBuffer* resource); + + // + std::vector<SP<CWLSHMResource>> m_vManagers; + std::vector<SP<CWLSHMPoolResource>> m_vPools; + std::vector<SP<CWLSHMBuffer>> m_vBuffers; + + // + std::vector<uint32_t> shmFormats; + + friend class CWLSHMResource; + friend class CWLSHMPoolResource; + friend class CWLSHMBuffer; +}; + +namespace PROTO { + inline UP<CWLSHMProtocol> shm; +}; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp new file mode 100644 index 00000000..213fdc42 --- /dev/null +++ b/src/protocols/core/Subcompositor.cpp @@ -0,0 +1,192 @@ +#include "Subcompositor.hpp" +#include "Compositor.hpp" +#include <algorithm> + +#define LOGM PROTO::subcompositor->protoLog + +CWLSubsurfaceResource::CWLSubsurfaceResource(SP<CWlSubsurface> resource_, SP<CWLSurfaceResource> surface_, SP<CWLSurfaceResource> parent_) : + surface(surface_), parent(parent_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSubsurface* r) { destroy(); }); + resource->setDestroy([this](CWlSubsurface* r) { destroy(); }); + + resource->setSetPosition([this](CWlSubsurface* r, int32_t x, int32_t y) { position = {x, y}; }); + + resource->setSetDesync([this](CWlSubsurface* r) { sync = false; }); + resource->setSetSync([this](CWlSubsurface* r) { sync = true; }); + + resource->setPlaceAbove([this](CWlSubsurface* r, wl_resource* surf) { + auto SURF = CWLSurfaceResource::fromResource(surf); + + if (!parent) + return; + + std::erase(parent->subsurfaces, self.lock()); + + auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); + + if (it == parent->subsurfaces.end()) { + LOGM(ERR, "Invalid surface reference in placeAbove"); + parent->subsurfaces.emplace_back(self.lock()); + } else + parent->subsurfaces.insert(it, self.lock()); + }); + + resource->setPlaceBelow([this](CWlSubsurface* r, wl_resource* surf) { + auto SURF = CWLSurfaceResource::fromResource(surf); + + if (!parent) + return; + + std::erase(parent->subsurfaces, self.lock()); + + auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); + + if (it == parent->subsurfaces.end()) { + LOGM(ERR, "Invalid surface reference in placeBelow"); + parent->subsurfaces.emplace_back(self.lock()); + } else + parent->subsurfaces.insert(it--, self.lock()); + }); + + listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { + if (surface->current.buffer && !surface->mapped) { + surface->map(); + return; + } + + if (!surface->current.buffer && surface->mapped) { + surface->unmap(); + return; + } + }); +} + +CWLSubsurfaceResource::~CWLSubsurfaceResource() { + events.destroy.emit(); + if (surface) + surface->resetRole(); +} + +void CWLSubsurfaceResource::destroy() { + if (surface && surface->mapped) + surface->unmap(); + events.destroy.emit(); + PROTO::subcompositor->destroyResource(this); +} + +Vector2D CWLSubsurfaceResource::posRelativeToParent() { + Vector2D pos = position; + SP<CWLSurfaceResource> surf = parent.lock(); + + // some apps might create cycles, which I believe _technically_ are not a protocol error + // in some cases, notably firefox likes to do that, so we keep track of what + // surfaces we've visited and if we hit a surface we've visited we bail out. + std::vector<SP<CWLSurfaceResource>> surfacesVisited; + + while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && + std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + surfacesVisited.emplace_back(surf); + auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + pos += subsurface->position; + surf = subsurface->parent.lock(); + } + return pos; +} + +bool CWLSubsurfaceResource::good() { + return resource->resource(); +} + +eSurfaceRole CWLSubsurfaceResource::role() { + return SURFACE_ROLE_SUBSURFACE; +} + +SP<CWLSurfaceResource> CWLSubsurfaceResource::t1Parent() { + SP<CWLSurfaceResource> surf = parent.lock(); + std::vector<SP<CWLSurfaceResource>> surfacesVisited; + + while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && + std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + surfacesVisited.emplace_back(surf); + auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + surf = subsurface->parent.lock(); + } + return surf; +} + +CWLSubcompositorResource::CWLSubcompositorResource(SP<CWlSubcompositor> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSubcompositor* r) { PROTO::subcompositor->destroyResource(this); }); + resource->setDestroy([this](CWlSubcompositor* r) { PROTO::subcompositor->destroyResource(this); }); + + resource->setGetSubsurface([](CWlSubcompositor* r, uint32_t id, wl_resource* surface, wl_resource* parent) { + auto SURF = CWLSurfaceResource::fromResource(surface); + auto PARENT = CWLSurfaceResource::fromResource(parent); + + if (!SURF || !PARENT || SURF == PARENT) { + r->error(WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Invalid surface/parent"); + return; + } + + SP<CWLSurfaceResource> t1Parent = nullptr; + + if (PARENT->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)PARENT->role.get(); + t1Parent = subsurface->t1Parent(); + } else + t1Parent = PARENT; + + if (t1Parent == SURF) { + r->error(WL_SUBCOMPOSITOR_ERROR_BAD_PARENT, "Bad parent, t1 parent == surf"); + return; + } + + const auto RESOURCE = + PROTO::subcompositor->m_vSurfaces.emplace_back(makeShared<CWLSubsurfaceResource>(makeShared<CWlSubsurface>(r->client(), r->version(), id), SURF, PARENT)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::subcompositor->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + SURF->role = RESOURCE; + PARENT->subsurfaces.emplace_back(RESOURCE); + + LOGM(LOG, "New wl_subsurface with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); + + PARENT->events.newSubsurface.emit(RESOURCE); + }); +} + +bool CWLSubcompositorResource::good() { + return resource->resource(); +} + +CWLSubcompositorProtocol::CWLSubcompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLSubcompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared<CWLSubcompositorResource>(makeShared<CWlSubcompositor>(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CWLSubcompositorProtocol::destroyResource(CWLSubcompositorResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSubcompositorProtocol::destroyResource(CWLSubsurfaceResource* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/core/Subcompositor.hpp b/src/protocols/core/Subcompositor.hpp new file mode 100644 index 00000000..abcfbf6d --- /dev/null +++ b/src/protocols/core/Subcompositor.hpp @@ -0,0 +1,82 @@ + +#pragma once + +/* + Implementations for: + - wl_subsurface + - wl_subcompositor +*/ + +#include <memory> +#include <vector> +#include <cstdint> +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../types/SurfaceRole.hpp" + +class CWLSurfaceResource; + +class CWLSubsurfaceResource : public ISurfaceRole { + public: + CWLSubsurfaceResource(SP<CWlSubsurface> resource_, SP<CWLSurfaceResource> surface_, SP<CWLSurfaceResource> parent_); + ~CWLSubsurfaceResource(); + + Vector2D posRelativeToParent(); + bool good(); + virtual eSurfaceRole role(); + SP<CWLSurfaceResource> t1Parent(); + + bool sync = false; + Vector2D position; + + WP<CWLSurfaceResource> surface; + WP<CWLSurfaceResource> parent; + + WP<CWLSubsurfaceResource> self; + + struct { + CSignal destroy; + } events; + + private: + SP<CWlSubsurface> resource; + + void destroy(); + + struct { + CHyprSignalListener commitSurface; + } listeners; +}; + +class CWLSubcompositorResource { + public: + CWLSubcompositorResource(SP<CWlSubcompositor> resource_); + + bool good(); + + private: + SP<CWlSubcompositor> resource; +}; + +class CWLSubcompositorProtocol : public IWaylandProtocol { + public: + CWLSubcompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CWLSubcompositorResource* resource); + void destroyResource(CWLSubsurfaceResource* resource); + + // + std::vector<SP<CWLSubcompositorResource>> m_vManagers; + std::vector<SP<CWLSubsurfaceResource>> m_vSurfaces; + + friend class CWLSubcompositorResource; + friend class CWLSubsurfaceResource; +}; + +namespace PROTO { + inline UP<CWLSubcompositorProtocol> subcompositor; +}; diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp new file mode 100644 index 00000000..5ed942e1 --- /dev/null +++ b/src/protocols/types/Buffer.cpp @@ -0,0 +1,41 @@ +#include "Buffer.hpp" +#include "WLBuffer.hpp" + +SDMABUFAttrs IWLBuffer::dmabuf() { + return SDMABUFAttrs{}; +} + +SSHMAttrs IWLBuffer::shm() { + return SSHMAttrs{}; +} + +std::tuple<uint8_t*, uint32_t, size_t> IWLBuffer::beginDataPtr(uint32_t flags) { + return {nullptr, 0, 0}; +} + +void IWLBuffer::endDataPtr() { + ; // empty +} + +void IWLBuffer::sendRelease() { + if (!resource || !resource->resource) + return; + resource->resource->sendRelease(); +} + +void IWLBuffer::lock() { + locks++; +} + +void IWLBuffer::unlock() { + locks--; + + ASSERT(locks >= 0); + + if (locks <= 0) + sendRelease(); +} + +bool IWLBuffer::locked() { + return locks; +} diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp new file mode 100644 index 00000000..c9902f8d --- /dev/null +++ b/src/protocols/types/Buffer.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "../../defines.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../../render/Texture.hpp" + +#include <array> +#include <tuple> + +enum eBufferCapability { + BUFFER_CAPABILITY_DATAPTR = (1 << 0), +}; + +enum eBufferType { + BUFFER_TYPE_DMABUF = 0, + BUFFER_TYPE_SHM, + BUFFER_TYPE_MISC, +}; + +class CWLBufferResource; + +struct SDMABUFAttrs { + bool success = false; + Vector2D size; + uint32_t format = 0; // fourcc + uint64_t modifier = 0; + + int planes = 1; + std::array<uint32_t, 4> offsets = {0}; + std::array<uint32_t, 4> strides = {0}; + std::array<int, 4> fds = {-1, -1, -1, -1}; +}; + +struct SSHMAttrs { + bool success = false; + int fd = 0; + uint32_t format = 0; + Vector2D size; + int stride = 0; + int64_t offset = 0; +}; + +class IWLBuffer { + public: + virtual ~IWLBuffer() { + ; + }; + + virtual eBufferCapability caps() = 0; + virtual eBufferType type() = 0; + virtual void update(const CRegion& damage) = 0; + virtual SDMABUFAttrs dmabuf(); + virtual SSHMAttrs shm(); + virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + virtual void sendRelease(); + virtual void lock(); + virtual void unlock(); + virtual bool locked(); + + Vector2D size; + bool opaque = false; + + SP<CWLBufferResource> resource; + + SP<CTexture> texture; + + struct { + CSignal destroy; + } events; + + private: + int locks = 0; +}; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp new file mode 100644 index 00000000..930e71e6 --- /dev/null +++ b/src/protocols/types/DMABuffer.cpp @@ -0,0 +1,75 @@ +#include "DMABuffer.hpp" +#include "WLBuffer.hpp" +#include "../../render/Renderer.hpp" +#include "../../helpers/Format.hpp" + +CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) : attrs(attrs_) { + g_pHyprRenderer->makeEGLCurrent(); + + listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) { + closeFDs(); + listeners.resourceDestroy.reset(); + }); + + size = attrs.size; + resource = CWLBufferResource::create(makeShared<CWlBuffer>(client, 1, id)); + + auto eglImage = g_pHyprOpenGL->createEGLImage(attrs); + + if (!eglImage) + return; + + texture = makeShared<CTexture>(attrs, eglImage); // texture takes ownership of the eglImage + opaque = FormatUtils::isFormatOpaque(attrs.format); + success = texture->m_iTexID; + + if (!success) + Debug::log(ERR, "Failed to create a dmabuf: texture is null"); +} + +CDMABuffer::~CDMABuffer() { + closeFDs(); +} + +eBufferCapability CDMABuffer::caps() { + return BUFFER_CAPABILITY_DATAPTR; +} + +eBufferType CDMABuffer::type() { + return BUFFER_TYPE_DMABUF; +} + +void CDMABuffer::update(const CRegion& damage) { + ; +} + +SDMABUFAttrs CDMABuffer::dmabuf() { + return attrs; +} + +std::tuple<uint8_t*, uint32_t, size_t> CDMABuffer::beginDataPtr(uint32_t flags) { + // FIXME: + return {nullptr, 0, 0}; +} + +void CDMABuffer::endDataPtr() { + // FIXME: +} + +bool CDMABuffer::good() { + return success; +} + +void CDMABuffer::updateTexture() { + ; +} + +void CDMABuffer::closeFDs() { + for (int i = 0; i < attrs.planes; ++i) { + if (attrs.fds[i] == -1) + continue; + close(attrs.fds[i]); + attrs.fds[i] = -1; + } + attrs.planes = 0; +}
\ No newline at end of file diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp new file mode 100644 index 00000000..e06b5791 --- /dev/null +++ b/src/protocols/types/DMABuffer.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Buffer.hpp" + +class CDMABuffer : public IWLBuffer { + public: + CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_); + virtual ~CDMABuffer(); + + virtual eBufferCapability caps(); + virtual eBufferType type(); + virtual void update(const CRegion& damage); + virtual SDMABUFAttrs dmabuf(); + virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + bool good(); + void updateTexture(); + void closeFDs(); + + bool success = false; + + private: + SDMABUFAttrs attrs; + + struct { + CHyprSignalListener resourceDestroy; + } listeners; +};
\ No newline at end of file diff --git a/src/protocols/types/SurfaceRole.hpp b/src/protocols/types/SurfaceRole.hpp new file mode 100644 index 00000000..05c0ea66 --- /dev/null +++ b/src/protocols/types/SurfaceRole.hpp @@ -0,0 +1,14 @@ +#pragma once + +enum eSurfaceRole { + SURFACE_ROLE_UNASSIGNED = 0, + SURFACE_ROLE_XDG_SHELL, + SURFACE_ROLE_LAYER_SHELL, + SURFACE_ROLE_EASTER_EGG, + SURFACE_ROLE_SUBSURFACE, +}; + +class ISurfaceRole { + public: + virtual eSurfaceRole role() = 0; +}; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp new file mode 100644 index 00000000..e53538cb --- /dev/null +++ b/src/protocols/types/WLBuffer.cpp @@ -0,0 +1,43 @@ +#include "WLBuffer.hpp" +#include "Buffer.hpp" + +CWLBufferResource::CWLBufferResource(SP<CWlBuffer> resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlBuffer* r) { + if (buffer.expired()) + return; + buffer->events.destroy.emit(); + }); + resource->setDestroy([this](CWlBuffer* r) { + if (buffer.expired()) + return; + buffer->events.destroy.emit(); + }); + + resource->setData(this); +} + +bool CWLBufferResource::good() { + return resource->resource(); +} + +void CWLBufferResource::sendRelease() { + resource->sendRelease(); +} + +wl_resource* CWLBufferResource::getResource() { + return resource->resource(); +} + +SP<CWLBufferResource> CWLBufferResource::fromResource(wl_resource* res) { + auto data = (CWLBufferResource*)(((CWlBuffer*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +SP<CWLBufferResource> CWLBufferResource::create(SP<CWlBuffer> resource) { + auto p = SP<CWLBufferResource>(new CWLBufferResource(resource)); + p->self = p; + return p; +} diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp new file mode 100644 index 00000000..ac177965 --- /dev/null +++ b/src/protocols/types/WLBuffer.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <memory> +#include <vector> +#include <cstdint> +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" + +class IWLBuffer; + +class CWLBufferResource { + public: + static SP<CWLBufferResource> create(SP<CWlBuffer> resource); + static SP<CWLBufferResource> fromResource(wl_resource* res); + + bool good(); + void sendRelease(); + wl_resource* getResource(); + + WP<IWLBuffer> buffer; + + WP<CWLBufferResource> self; + + private: + CWLBufferResource(SP<CWlBuffer> resource_); + + SP<CWlBuffer> resource; + + friend class IWLBuffer; +}; diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 83325dd7..67629e23 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -1,22 +1,26 @@ #include "Framebuffer.hpp" #include "OpenGL.hpp" +CFramebuffer::CFramebuffer() { + m_cTex = makeShared<CTexture>(); +} + bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { bool firstAlloc = false; RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h); - uint32_t glFormat = drmFormatToGL(drmFormat); - uint32_t glType = glFormatToType(glFormat); + uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat); + uint32_t glType = FormatUtils::glFormatToType(glFormat); if (m_iFb == (uint32_t)-1) { firstAlloc = true; glGenFramebuffers(1, &m_iFb); } - if (m_cTex.m_iTexID == 0) { + if (m_cTex->m_iTexID == 0) { firstAlloc = true; - glGenTextures(1, &m_cTex.m_iTexID); - glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); + m_cTex->allocate(); + glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -24,11 +28,11 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { } if (firstAlloc || m_vSize != Vector2D(w, h)) { - glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); + glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, GL_RGBA, glType, 0); glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex->m_iTexID, 0); // TODO: Allow this with gles2 #ifndef GLES2 @@ -87,12 +91,9 @@ void CFramebuffer::release() { if (m_iFb != (uint32_t)-1 && m_iFb) glDeleteFramebuffers(1, &m_iFb); - if (m_cTex.m_iTexID) - glDeleteTextures(1, &m_cTex.m_iTexID); - - m_cTex.m_iTexID = 0; - m_iFb = -1; - m_vSize = Vector2D(); + m_cTex->destroyTexture(); + m_iFb = -1; + m_vSize = Vector2D(); } CFramebuffer::~CFramebuffer() { diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index 22809158..a46a4859 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -5,19 +5,20 @@ class CFramebuffer { public: + CFramebuffer(); ~CFramebuffer(); - bool alloc(int w, int h, uint32_t format = GL_RGBA); - void addStencil(); - void bind(); - void release(); - void reset(); - bool isAllocated(); + bool alloc(int w, int h, uint32_t format = GL_RGBA); + void addStencil(); + void bind(); + void release(); + void reset(); + bool isAllocated(); - Vector2D m_vSize; + Vector2D m_vSize; - CTexture m_cTex; - GLuint m_iFb = -1; + SP<CTexture> m_cTex; + GLuint m_iFb = -1; - CTexture* m_pStencilTex = nullptr; + SP<CTexture> m_pStencilTex; };
\ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a1e6f73e..d4e8faa6 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -7,6 +7,8 @@ #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/core/Compositor.hpp" +#include <xf86drm.h> inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); @@ -21,7 +23,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)), "Couldn't unset current EGL!"); - auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS); RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); @@ -33,12 +36,25 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(LOG, "Using: {}", (char*)glGetString(GL_VERSION)); Debug::log(LOG, "Vendor: {}", (char*)glGetString(GL_VENDOR)); Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER)); - Debug::log(LOG, "Supported extensions size: {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' ')); + Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions); loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); + loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR"); loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR"); + loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT"); + loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT"); + loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); - m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); + m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); + m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import"); + m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers"); + + RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required"); + + if (!m_sExts.EXT_read_format_bgra) + Debug::log(WARN, "Your GPU does not support GL_EXT_read_format_bgra, this may cause issues with texture importing"); + if (!m_sExts.EXT_image_dma_buf_import || !m_sExts.EXT_image_dma_buf_import_modifiers) + Debug::log(WARN, "Your GPU does not support DMABUFs, this will possibly cause issues and will take a hit on the performance."); #ifdef USE_TRACY_GPU @@ -54,6 +70,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!"); #endif + initDRMFormats(); + static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); }); RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); @@ -61,6 +79,171 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_tGlobalTimer.reset(); } +std::vector<uint64_t> CHyprOpenGLImpl::getModsForFormat(EGLint format) { + // TODO: return std::expected when clang supports it + + if (!m_sExts.EXT_image_dma_buf_import_modifiers) + return {}; + + EGLint len = 0; + if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) { + Debug::log(ERR, "EGL: Failed to query mods"); + return {}; + } + + if (len <= 0) + return {}; + + std::vector<uint64_t> mods; + std::vector<EGLBoolean> external; + + mods.resize(len); + external.resize(len); + + m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len); + + std::vector<uint64_t> result; + for (size_t i = 0; i < mods.size(); ++i) { + if (external.at(i)) + continue; + + result.push_back(mods.at(i)); + } + + return result; +} + +void CHyprOpenGLImpl::initDRMFormats() { + const auto DISABLE_MODS = envEnabled("HYPRLAND_EGL_NO_MODIFIERS"); + if (DISABLE_MODS) + Debug::log(WARN, "HYPRLAND_EGL_NO_MODIFIERS set, disabling modifiers"); + + if (!m_sExts.EXT_image_dma_buf_import) { + Debug::log(ERR, "EGL: No dmabuf import, DMABufs will not work."); + return; + } + + std::vector<EGLint> formats; + + if (!m_sExts.EXT_image_dma_buf_import_modifiers || !m_sProc.eglQueryDmaBufFormatsEXT) { + formats.push_back(DRM_FORMAT_ARGB8888); + formats.push_back(DRM_FORMAT_XRGB8888); + Debug::log(WARN, "EGL: No mod support"); + } else { + EGLint len = 0; + m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len); + formats.resize(len); + m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len); + } + + if (formats.size() == 0) { + Debug::log(ERR, "EGL: Failed to get formats, DMABufs will not work."); + return; + } + + wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:"); + + std::vector<SDRMFormat> dmaFormats; + + for (auto& fmt : formats) { + std::vector<uint64_t> mods; + if (!DISABLE_MODS) + mods = getModsForFormat(fmt); + else + mods = {DRM_FORMAT_MOD_LINEAR}; + + m_bHasModifiers = m_bHasModifiers || mods.size() > 0; + + if (mods.size() == 0) + continue; + + dmaFormats.push_back(SDRMFormat{ + .format = fmt, + .mods = mods, + }); + + std::vector<std::pair<uint64_t, std::string>> modifierData; + + auto fmtName = drmGetFormatName(fmt); + Debug::log(LOG, "EGL: GPU Supports Format {} (0x{:x})", fmtName ? fmtName : "?unknown?", fmt); + for (auto& mod : mods) { + auto modName = drmGetFormatModifierName(mod); + modifierData.emplace_back(std::make_pair<>(mod, modName ? modName : "?unknown?")); + free(modName); + } + free(fmtName); + + mods.clear(); + std::sort(modifierData.begin(), modifierData.end(), [](const auto& a, const auto& b) { + if (a.first == 0) + return false; + if (a.second.contains("DCC")) + return false; + return true; + }); + + for (auto& [m, name] : modifierData) { + Debug::log(LOG, "EGL: | with modifier {} (0x{:x})", name, m); + mods.emplace_back(m); + } + } + + Debug::log(LOG, "EGL: {} formats found in total. Some modifiers may be omitted as they are external-only.", dmaFormats.size()); + + drmFormats = dmaFormats; +} + +EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) { + std::vector<uint32_t> attribs; + + attribs.push_back(EGL_WIDTH); + attribs.push_back(attrs.size.x); + attribs.push_back(EGL_HEIGHT); + attribs.push_back(attrs.size.y); + attribs.push_back(EGL_LINUX_DRM_FOURCC_EXT); + attribs.push_back(attrs.format); + + struct { + EGLint fd; + EGLint offset; + EGLint pitch; + EGLint modlo; + EGLint modhi; + } attrNames[4] = { + {EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE1_FD_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE3_FD_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT}}; + + for (int i = 0; i < attrs.planes; i++) { + attribs.push_back(attrNames[i].fd); + attribs.push_back(attrs.fds[i]); + attribs.push_back(attrNames[i].offset); + attribs.push_back(attrs.offsets[i]); + attribs.push_back(attrNames[i].pitch); + attribs.push_back(attrs.strides[i]); + if (m_bHasModifiers && attrs.modifier != DRM_FORMAT_MOD_INVALID) { + attribs.push_back(attrNames[i].modlo); + attribs.push_back(attrs.modifier & 0xFFFFFFFF); + attribs.push_back(attrNames[i].modhi); + attribs.push_back(attrs.modifier >> 32); + } + } + + attribs.push_back(EGL_IMAGE_PRESERVED_KHR); + attribs.push_back(EGL_TRUE); + + attribs.push_back(EGL_NONE); + + EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data()); + if (image == EGL_NO_IMAGE_KHR) { + Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError()); + return EGL_NO_IMAGE_KHR; + } + + return image; +} + void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) { GLint maxLength = 0; if (program) @@ -339,12 +522,12 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu // ensure a framebuffer for the monitor exists if (m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) { - m_RenderData.pCurrentMonData->stencilTex.allocate(); + m_RenderData.pCurrentMonData->stencilTex->allocate(); - m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); @@ -381,8 +564,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu // we can render to the rbo / fbo (fake) directly const auto PFBO = fb ? fb : PRBO->getFB(); m_RenderData.currentFB = PFBO; - if (PFBO->m_pStencilTex != &m_RenderData.pCurrentMonData->stencilTex) { - PFBO->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + if (PFBO->m_pStencilTex != m_RenderData.pCurrentMonData->stencilTex) { + PFBO->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; PFBO->addStencil(); } PFBO->bind(); @@ -863,19 +1046,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, int round, bool allowCustomUV) { - RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - - renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV); -} - -void CHyprOpenGLImpl::renderTextureWithDamage(wlr_texture* tex, CBox* pBox, CRegion* damage, float alpha, int round, bool allowCustomUV) { - RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - - renderTextureWithDamage(CTexture(tex), pBox, damage, alpha, round, false, allowCustomUV); -} - -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(SP<CTexture> tex, CBox* 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.damage, round, discardActive, false, allowCustomUV, true); @@ -883,7 +1054,7 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP<CTexture> tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); @@ -891,10 +1062,10 @@ void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, C scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, +void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, CBox* pBox, float alpha, CRegion* 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!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTextureInternalWithDamage"); @@ -934,11 +1105,11 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; usingFinalShader = true; } else { - switch (tex.m_iType) { + switch (tex->m_iType) { case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break; case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break; case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break; - default: RASSERT(false, "tex.m_iTarget unsupported!"); + default: RASSERT(false, "tex->m_iTarget unsupported!"); } } } @@ -947,14 +1118,14 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* shader = &m_RenderData.pCurrentMonData->m_shRGBX; glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); if (m_RenderData.useNearestNeighbor) { - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else { - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } glUseProgram(shader->program); @@ -1057,12 +1228,12 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { +void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, CBox* pBox) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTexturePrimitive"); @@ -1083,7 +1254,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); glUseProgram(shader->program); @@ -1111,12 +1282,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte) { +void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuffer& matte) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTextureMatte"); @@ -1148,10 +1319,10 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame glUniform1i(shader->alphaMatte, 1); glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(matte.m_cTex.m_iTarget, matte.m_cTex.m_iTexID); + glBindTexture(matte.m_cTex->m_iTarget, matte.m_cTex->m_iTexID); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1169,7 +1340,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } // This probably isn't the fastest @@ -1221,9 +1392,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(m_RenderData.currentFB->m_cTex.m_iTarget, m_RenderData.currentFB->m_cTex.m_iTexID); + glBindTexture(m_RenderData.currentFB->m_cTex->m_iTarget, m_RenderData.currentFB->m_cTex->m_iTexID); - glTexParameteri(m_RenderData.currentFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(m_RenderData.currentFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); @@ -1265,9 +1436,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID); + glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); - glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(pShader->program); @@ -1315,7 +1486,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // draw the things. // first draw is swap -> mirr PMIRRORFB->bind(); - glBindTexture(PMIRRORSWAPFB->m_cTex.m_iTarget, PMIRRORSWAPFB->m_cTex.m_iTexID); + glBindTexture(PMIRRORSWAPFB->m_cTex->m_iTarget, PMIRRORSWAPFB->m_cTex->m_iTexID); // damage region will be scaled, make a temp CRegion tempDamage{damage}; @@ -1343,9 +1514,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID); + glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); - glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); @@ -1383,7 +1554,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o } // finish - glBindTexture(PMIRRORFB->m_cTex.m_iTarget, 0); + glBindTexture(PMIRRORFB->m_cTex->m_iTarget, 0); blend(BLENDBEFORE); @@ -1417,23 +1588,23 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { if (pWindow->m_sAdditionalConfigData.forceNoBlur) return false; - if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall) + if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) return true; - const auto PSURFACE = pWindow->m_pWLSurface.wlr(); + const auto PSURFACE = pWindow->m_pWLSurface->resource(); const auto PWORKSPACE = pWindow->m_pWorkspace; const float A = pWindow->m_fAlpha.value() * pWindow->m_fActiveInactiveAlpha.value() * PWORKSPACE->m_fAlpha.value(); if (A >= 1.f) { - if (PSURFACE->opaque) - return false; + // if (PSURFACE->opaque) + // return false; CRegion inverseOpaque; - pixman_box32_t surfbox = {0, 0, PSURFACE->current.width, PSURFACE->current.height}; - CRegion opaqueRegion{&PSURFACE->current.opaque}; - inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.width, PSURFACE->current.height); + pixman_box32_t surfbox = {0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y}; + CRegion opaqueRegion{PSURFACE->current.opaque}; + inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y); if (inverseOpaque.empty()) return false; @@ -1461,8 +1632,8 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { if (!ls->layerSurface || ls->xray != 1) continue; - if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) - continue; + // if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) + // continue; hasWindows = true; break; @@ -1527,7 +1698,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin static auto PBLURNEWOPTIMIZE = CConfigValue<Hyprlang::INT>("decoration:blur:new_optimizations"); static auto PBLURXRAY = CConfigValue<Hyprlang::INT>("decoration:blur:xray"); - if (!m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID) + if (!m_RenderData.pCurrentMonData->blurFB.m_cTex->m_iTexID) return false; if (pWindow && pWindow->m_sAdditionalConfigData.xray.toUnderlying() == 0) @@ -1545,7 +1716,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin return false; } -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization, float blurA) { +void CHyprOpenGLImpl::renderTextureWithBlur(SP<CTexture> tex, CBox* pBox, float a, SP<CWLSurfaceResource> pSurface, int round, bool blockBlurOptimization, float blurA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto PBLURENABLED = CConfigValue<Hyprlang::INT>("decoration:blur:enabled"); @@ -1570,11 +1741,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo // amazing hack: the surface has an opaque region! CRegion inverseOpaque; - if (a >= 1.f && std::round(pSurface->current.width * m_RenderData.pMonitor->scale) == pBox->w && - std::round(pSurface->current.height * m_RenderData.pMonitor->scale) == pBox->h) { - pixman_box32_t surfbox = {0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale}; - inverseOpaque = &pSurface->current.opaque; - inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale); + if (a >= 1.f && std::round(pSurface->current.size.x * m_RenderData.pMonitor->scale) == pBox->w && + std::round(pSurface->current.size.y * m_RenderData.pMonitor->scale) == pBox->h) { + pixman_box32_t surfbox = {0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale}; + inverseOpaque = pSurface->current.opaque; + inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale); if (inverseOpaque.empty()) { renderTexture(tex, pBox, a, round, false, true); @@ -1765,7 +1936,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr g_pHyprRenderer->makeEGLCurrent(); - pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); @@ -1903,7 +2074,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { const auto FBDATA = &m_mWindowFramebuffers.at(ref); - if (!FBDATA->m_cTex.m_iTexID) + if (!FBDATA->m_cTex->m_iTexID) return; const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); @@ -1942,7 +2113,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) { const auto FBDATA = &m_mLayerFramebuffers.at(pLayer); - if (!FBDATA->m_cTex.m_iTexID) + if (!FBDATA->m_cTex->m_iTexID) return; const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID); @@ -2077,7 +2248,7 @@ void CHyprOpenGLImpl::renderMirrored() { monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; const auto PFB = &m_mMonitorRenderResources[mirrored].monitorMirrorFB; - if (!PFB->isAllocated() || PFB->m_cTex.m_iTexID <= 0) + if (!PFB->isAllocated() || PFB->m_cTex->m_iTexID <= 0) return; // replace monitor projection to undo the mirrored monitor's projection @@ -2179,12 +2350,12 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { } // create a new one with cairo - CTexture tex; + SP<CTexture> tex = makeShared<CTexture>(); - const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str()); - const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE); + const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str()); + const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE); - tex.allocate(); + tex->allocate(); const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)}; // calc the target box @@ -2220,8 +2391,8 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { cairo_surface_flush(CAIROSURFACE); - CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale}; - tex.m_vSize = IMAGESIZE * scale; + CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale}; + tex->m_vSize = IMAGESIZE * scale; // copy the data to an OpenGL texture we have const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? @@ -2235,7 +2406,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifndef GLES2 @@ -2244,7 +2415,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); } #endif - glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex.m_vSize.x, tex.m_vSize.y, 0, glFormat, glType, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); cairo_surface_destroy(CAIROSURFACE); cairo_surface_destroy(CAIROISURFACE); @@ -2293,7 +2464,7 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { RESIT->second.monitorMirrorFB.release(); RESIT->second.blurFB.release(); RESIT->second.offMainFB.release(); - RESIT->second.stencilTex.destroyTexture(); + RESIT->second.stencilTex->destroyTexture(); g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT); } @@ -2343,109 +2514,6 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) { m_RenderData.renderModif.enabled = enabled; } -inline const SGLPixelFormat GLES2_FORMATS[] = { - { - .drmFormat = DRM_FORMAT_ARGB8888, - .glFormat = GL_BGRA_EXT, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XRGB8888, - .glFormat = GL_BGRA_EXT, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_XBGR8888, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR8888, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_BGR888, - .glFormat = GL_RGB, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - { - .drmFormat = DRM_FORMAT_RGBX4444, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_4_4_4_4, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_RGBA4444, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_4_4_4_4, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_RGBX5551, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_5_5_5_1, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_RGBA5551, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_5_5_5_1, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_RGB565, - .glFormat = GL_RGB, - .glType = GL_UNSIGNED_SHORT_5_6_5, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_XBGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XBGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT_OES, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT_OES, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XBGR16161616, - .glInternalFormat = GL_RGBA16_EXT, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR16161616, - .glInternalFormat = GL_RGBA16_EXT, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = true, - }, -#endif -}; - uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { GLint glf = -1, glt = -1, as = 0; /*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf); @@ -2453,14 +2521,12 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { glGetIntegerv(GL_ALPHA_BITS, &as);*/ if (glf == 0 || glt == 0) { - glf = drmFormatToGL(pMonitor->drmFormat); - glt = glFormatToType(glf); + glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat); + glt = FormatUtils::glFormatToType(glf); } - for (auto& fmt : GLES2_FORMATS) { - if (fmt.glFormat == glf && fmt.glType == glt && fmt.withAlpha == (as > 0)) - return fmt.drmFormat; - } + if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT) + return FMT->drmFormat; if (m_sExts.EXT_read_format_bgra) return DRM_FORMAT_XRGB8888; @@ -2468,13 +2534,8 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { return DRM_FORMAT_XBGR8888; } -const SGLPixelFormat* CHyprOpenGLImpl::getPixelFormatFromDRM(uint32_t drmFormat) { - for (auto& fmt : GLES2_FORMATS) { - if (fmt.drmFormat == drmFormat) - return &fmt; - } - - return nullptr; +std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() { + return drmFormats; } void SRenderModifData::applyToBox(CBox& box) { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index ca9eecc6..db0f8ea1 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -5,6 +5,7 @@ #include "../helpers/Color.hpp" #include "../helpers/Timer.hpp" #include "../helpers/Region.hpp" +#include "../helpers/Format.hpp" #include <list> #include <unordered_map> #include <map> @@ -54,14 +55,6 @@ struct SRenderModifData { bool enabled = true; }; -struct SGLPixelFormat { - uint32_t drmFormat = DRM_FORMAT_INVALID; - GLint glInternalFormat = 0; - GLint glFormat = 0; - GLint glType = 0; - bool withAlpha = false; -}; - struct SMonitorRenderData { CFramebuffer offloadFB; CFramebuffer mirrorFB; // these are used for some effects, @@ -70,7 +63,7 @@ struct SMonitorRenderData { CFramebuffer monitorMirrorFB; // used for mirroring outputs, does not contain artifacts like offloadFB - CTexture stencilTex; + SP<CTexture> stencilTex = makeShared<CTexture>(); CFramebuffer blurFB; bool blurFBDirty = true; @@ -132,74 +125,73 @@ class CHyprOpenGLImpl { public: CHyprOpenGLImpl(); - void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {}); - void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); - void end(); + void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {}); + void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); + void end(); - void renderRect(CBox*, const CColor&, int round = 0); - void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); - void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); - void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false); - void renderTextureWithDamage(wlr_texture*, CBox*, CRegion* damage, float a, int round = 0, bool allowCustomUV = false); - void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(const CTexture&, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); - void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); - void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); - void renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte); + void renderRect(CBox*, const CColor&, int round = 0); + void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); + void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); + void renderTexture(SP<CTexture>, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP<CTexture>, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithBlur(SP<CTexture>, CBox*, float a, SP<CWLSurfaceResource> pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); + void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); + void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); + void renderTextureMatte(SP<CTexture> tex, CBox* pBox, CFramebuffer& matte); - void setMonitorTransformEnabled(bool enabled); - void setRenderModifEnabled(bool enabled); + void setMonitorTransformEnabled(bool enabled); + void setRenderModifEnabled(bool enabled); - void saveMatrix(); - void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); - void restoreMatrix(); + void saveMatrix(); + void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); + void restoreMatrix(); - void blend(bool enabled); + void blend(bool enabled); - void makeWindowSnapshot(PHLWINDOW); - void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); - void makeLayerSnapshot(PHLLS); - void renderSnapshot(PHLWINDOW); - void renderSnapshot(PHLLS); - bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); + void makeWindowSnapshot(PHLWINDOW); + void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); + void makeLayerSnapshot(PHLLS); + void renderSnapshot(PHLWINDOW); + void renderSnapshot(PHLLS); + bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); - void clear(const CColor&); - void clearWithTex(); - void scissor(const CBox*, bool transform = true); - void scissor(const pixman_box32*, bool transform = true); - void scissor(const int x, const int y, const int w, const int h, bool transform = true); + void clear(const CColor&); + void clearWithTex(); + void scissor(const CBox*, bool transform = true); + void scissor(const pixman_box32*, bool transform = true); + void scissor(const int x, const int y, const int w, const int h, bool transform = true); - void destroyMonitorResources(CMonitor*); + void destroyMonitorResources(CMonitor*); - void markBlurDirtyForMonitor(CMonitor*); + void markBlurDirtyForMonitor(CMonitor*); - void preWindowPass(); - bool preBlurQueued(); - void preRender(CMonitor*); + void preWindowPass(); + bool preBlurQueued(); + void preRender(CMonitor*); - void saveBufferForMirror(CBox*); - void renderMirrored(); + void saveBufferForMirror(CBox*); + void renderMirrored(); - void applyScreenShader(const std::string& path); + void applyScreenShader(const std::string& path); - void bindOffMain(); - void renderOffToMain(CFramebuffer* off); - void bindBackOnMain(); + void bindOffMain(); + void renderOffToMain(CFramebuffer* off); + void bindBackOnMain(); - void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {}); + void setDamage(const CRegion& damage, std::optional<CRegion> finalDamage = {}); - uint32_t getPreferredReadFormat(CMonitor* pMonitor); - const SGLPixelFormat* getPixelFormatFromDRM(uint32_t drmFormat); + uint32_t getPreferredReadFormat(CMonitor* pMonitor); + std::vector<SDRMFormat> getDRMFormats(); + EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window - PHLLS m_pCurrentLayer; // hack to get the current rendered layer + PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window + PHLLS m_pCurrentLayer; // hack to get the current rendered layer std::map<PHLWINDOWREF, CFramebuffer> m_mWindowFramebuffers; std::map<PHLLSREF, CFramebuffer> m_mLayerFramebuffers; @@ -208,41 +200,52 @@ class CHyprOpenGLImpl { struct { PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr; + PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr; + PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr; + PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr; } m_sProc; struct { - bool EXT_read_format_bgra = false; + bool EXT_read_format_bgra = false; + bool EXT_image_dma_buf_import = false; + bool EXT_image_dma_buf_import_modifiers = false; } m_sExts; private: - std::list<GLuint> m_lBuffers; - std::list<GLuint> m_lTextures; + std::list<GLuint> m_lBuffers; + std::list<GLuint> m_lTextures; + + std::vector<SDRMFormat> drmFormats; + bool m_bHasModifiers = false; - int m_iDRMFD; - std::string m_szExtensions; + int m_iDRMFD; + std::string m_szExtensions; - bool m_bFakeFrame = false; - bool m_bEndFrame = false; - bool m_bApplyFinalShader = false; - bool m_bBlend = false; - bool m_bOffloadedFramebuffer = false; + bool m_bFakeFrame = false; + bool m_bEndFrame = false; + bool m_bApplyFinalShader = false; + bool m_bBlend = false; + bool m_bOffloadedFramebuffer = false; - CShader m_sFinalScreenShader; - CTimer m_tGlobalTimer; + CShader m_sFinalScreenShader; + CTimer m_tGlobalTimer; - void logShaderError(const GLuint&, bool program = false); - GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); - GLuint compileShader(const GLuint&, std::string, bool dynamic = false); - void createBGTextureForMonitor(CMonitor*); - void initShaders(); + void logShaderError(const GLuint&, bool program = false); + GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); + GLuint compileShader(const GLuint&, std::string, bool dynamic = false); + void createBGTextureForMonitor(CMonitor*); + void initShaders(); + void initDRMFormats(); + std::vector<uint64_t> getModsForFormat(EGLint format); // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); - void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, + void renderTextureInternalWithDamage(SP<CTexture>, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false, bool allowDim = false); - void renderTexturePrimitive(const CTexture& tex, CBox* pBox); + void renderTexturePrimitive(SP<CTexture> tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); void preBlurForCurrentMonitor(); diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 5003f600..694485c2 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -1,6 +1,7 @@ #include "Renderbuffer.hpp" #include "OpenGL.hpp" #include "../Compositor.hpp" +#include "../protocols/types/Buffer.hpp" #include <dlfcn.h> @@ -61,6 +62,29 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer &buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); } +CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { + auto dma = buffer->dmabuf(); + + m_iImage = g_pHyprOpenGL->createEGLImage(dma); + if (m_iImage == EGL_NO_IMAGE_KHR) + throw std::runtime_error("createEGLImage failed"); + + glGenRenderbuffers(1, &m_iRBO); + glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); + g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glGenFramebuffers(1, &m_sFramebuffer.m_iFb); + m_sFramebuffer.m_vSize = buffer->size; + m_sFramebuffer.bind(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + throw std::runtime_error("rbo: glCheckFramebufferStatus failed"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + void CRenderbuffer::bind() { glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); bindFB(); diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index 2a8bf250..ed7050c5 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -3,10 +3,12 @@ #include "Framebuffer.hpp" class CMonitor; +class IWLBuffer; class CRenderbuffer { public: CRenderbuffer(wlr_buffer* buffer, uint32_t format); + CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format); ~CRenderbuffer(); void bind(); @@ -16,6 +18,7 @@ class CRenderbuffer { uint32_t getFormat(); wlr_buffer* m_pWlrBuffer = nullptr; + WP<IWLBuffer> m_pHLBuffer = {}; DYNLISTENER(destroyBuffer); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 40ae953e..2a6cbb3b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,6 +1,5 @@ #include "Renderer.hpp" #include "../Compositor.hpp" -#include "linux-dmabuf-unstable-v1-protocol.h" #include "../helpers/Region.hpp" #include <algorithm> #include "../config/ConfigValue.hpp" @@ -13,6 +12,7 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/core/DataDevice.hpp" +#include "../protocols/core/Compositor.hpp" extern "C" { #include <xf86drm.h> @@ -90,19 +90,24 @@ CHyprRenderer::CHyprRenderer() { wl_event_source_timer_update(m_pCursorTicker, 500); } -static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { - const auto TEXTURE = wlr_surface_get_texture(surface); - const auto RDATA = (SRenderData*)data; - const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; +static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* data) { + if (!surface->current.buffer || !surface->current.buffer->texture) + return; + + const auto& TEXTURE = surface->current.buffer->texture; + const auto RDATA = (SRenderData*)data; + const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; - if (!TEXTURE) + // this is bad, probably has been logged elsewhere. Means the texture failed + // uploading to the GPU. + if (!TEXTURE->m_iTexID) return; TRACY_GPU_ZONE("RenderSurface"); double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; - auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface); + auto PSURFACE = CWLSurface::fromResource(surface); const float ALPHA = RDATA->alpha * RDATA->fadeAlpha * (PSURFACE ? PSURFACE->m_pAlphaModifier : 1.F); @@ -140,7 +145,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) } } else { // here we clamp to 2, these might be some tiny specks - windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max(surface->current.width, 2), std::max(surface->current.height, 2)}; + windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)}; if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { // adjust subsurfaces to the window windowBox.width = (windowBox.width / RDATA->pWindow->m_vReportedSize.x) * RDATA->pWindow->m_vRealSize.value().x; @@ -155,15 +160,23 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) windowBox.height = RDATA->h - y; } - if (windowBox.width <= 1 || windowBox.height <= 1) + if (windowBox.width <= 1 || windowBox.height <= 1) { + if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { + surface->frame(RDATA->when); + auto FEEDBACK = makeShared<CQueuedPresentationData>(surface); + FEEDBACK->attachMonitor(RDATA->pMonitor); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + } return; // invisible + } windowBox.scale(RDATA->pMonitor->scale); windowBox.round(); const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ && - windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ && - DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ && + windowBox.size() != surface->current.buffer->size /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.buffer->size.x, 3) && + DELTALESSTHAN(windowBox.height, surface->current.buffer->size.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); @@ -183,8 +196,8 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (RDATA->dontRound) rounding = 0; - const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface.wlr() == surface ? RDATA->pWindow->opaque() : false; - const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && (WINDOWOPAQUE || surface->opaque); + const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface->resource() == surface ? RDATA->pWindow->opaque() : false; + const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && WINDOWOPAQUE; if (CANDISABLEBLEND) g_pHyprOpenGL->blend(false); @@ -195,16 +208,16 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (RDATA->blur) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); } else { if (RDATA->blur && RDATA->popup) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - wlr_surface_send_frame_done(surface, RDATA->when); + surface->frame(RDATA->when); auto FEEDBACK = makeShared<CQueuedPresentationData>(surface); FEEDBACK->attachMonitor(RDATA->pMonitor); FEEDBACK->presented(); @@ -506,7 +519,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (ignoreAllGeometry) decorate = false; - renderdata.surface = pWindow->m_pWLSurface.wlr(); + renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding); renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value()); renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); @@ -576,7 +589,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if ((pWindow->m_bIsX11 && *PXWLUSENN) || pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying()) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { + if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h}; wb.scale(pMonitor->scale).round(); g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha, @@ -584,7 +597,8 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec renderdata.blur = false; } - wlr_surface_for_each_surface(pWindow->m_pWLSurface.wlr(), renderSurface, &renderdata); + pWindow->m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, + &renderdata); g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; @@ -641,14 +655,15 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec pWindow->m_pPopupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; auto pos = popup->coordsRelativeToParent(); auto rd = (SRenderData*)data; Vector2D oldPos = {rd->x, rd->y}; rd->x += pos.x; rd->y += pos.y; - wlr_surface_for_each_surface(popup->m_sWLSurface.wlr(), renderSurface, rd); + popup->m_pWLSurface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, + data); rd->x = oldPos.x; rd->y = oldPos.y; }, @@ -698,7 +713,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time SRenderData renderdata = {pMonitor, time, REALPOS.x, REALPOS.y}; renderdata.fadeAlpha = pLayer->alpha.value(); renderdata.blur = pLayer->forceBlur; - renderdata.surface = pLayer->layerSurface->surface; + renderdata.surface = pLayer->surface->resource(); renderdata.decorate = false; renderdata.w = REALSIZ.x; renderdata.h = REALSIZ.y; @@ -717,7 +732,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time } if (!popups) - wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); + pLayer->surface->resource()->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); renderdata.squishOversized = false; // don't squish popups renderdata.dontRound = true; @@ -726,11 +741,11 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time if (popups) { pLayer->popupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; Vector2D pos = popup->coordsRelativeToParent(); - renderSurface(popup->m_sWLSurface.wlr(), pos.x, pos.y, data); + renderSurface(popup->m_pWLSurface->resource(), pos.x, pos.y, data); }, &renderdata); } @@ -746,15 +761,15 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, CMonitor* pMonitor, time SRenderData renderdata = {pMonitor, time, POS.x, POS.y}; - const auto SURF = pPopup->getWlrSurface(); + const auto SURF = pPopup->getSurface(); renderdata.blur = false; renderdata.surface = SURF; renderdata.decorate = false; - renderdata.w = SURF->current.width; - renderdata.h = SURF->current.height; + renderdata.w = SURF->current.size.x; + renderdata.h = SURF->current.size.y; - wlr_surface_for_each_surface(SURF, renderSurface, &renderdata); + SURF->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMonitor* pMonitor, timespec* time) { @@ -766,7 +781,7 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon renderdata.w = pMonitor->vecSize.x; renderdata.h = pMonitor->vecSize.y; - wlr_surface_for_each_surface(pSurface->surface->surface(), renderSurface, &renderdata); + renderdata.surface->breadthfirst([](SP<CWLSurfaceResource> s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { @@ -966,17 +981,15 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB } } -void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { +void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; Vector2D uvBR = Vector2D(1, 1); - if (pSurface->current.viewport.has_src) { + if (pSurface->current.viewport.hasSource) { // we stretch it to dest. if no dest, to 1,1 - wlr_fbox bufferSource; - wlr_surface_get_buffer_source_box(pSurface, &bufferSource); - - Vector2D bufferSize = Vector2D(pSurface->buffer->texture->width, pSurface->buffer->texture->height); + Vector2D bufferSize = pSurface->current.buffer->size; + auto bufferSource = pSurface->current.viewport.source; // calculate UV for the basic src_box. Assume dest == size. Scale to dest later uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y); @@ -991,8 +1004,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa if (projSize != Vector2D{} && fixMisalignedFSV1) { // instead of nearest_neighbor (we will repeat / skip) // just cut off / expand surface - const Vector2D PIXELASUV = Vector2D{1, 1} / Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height}; - const Vector2D MISALIGNMENT = Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height} - projSize; + const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->current.buffer->size; + const Vector2D MISALIGNMENT = pSurface->current.buffer->size - projSize; if (MISALIGNMENT != Vector2D{}) uvBR -= MISALIGNMENT * PIXELASUV; } @@ -1013,10 +1026,10 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa // ignore X and Y, adjust uv if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { - const auto XPERC = (double)geom.x / (double)pSurface->current.width; - const auto YPERC = (double)geom.y / (double)pSurface->current.height; - const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.width; - const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.height; + const auto XPERC = (double)geom.x / (double)pSurface->current.size.x; + const auto YPERC = (double)geom.y / (double)pSurface->current.size.y; + const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x; + const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.size.y; const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y)); @@ -1025,8 +1038,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa // TODO: make this passed to the func. Might break in the future. auto maxSize = pWindow->m_vRealSize.value(); - if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall) - maxSize = pWindow->m_pWLSurface.getViewporterCorrectedSize(); + if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) + maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize(); if (geom.width > maxSize.x) uvBR.x = uvBR.x * (maxSize.x / geom.width); @@ -1048,53 +1061,51 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa } } -void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) { - *(int*)data += 1; -} - bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) { - if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) - return false; // do not DS if this monitor is being mirrored. Will break the functionality. + return false; // FIXME: fix when we move to new lib for backend. - if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) - return false; + // if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) + // return false; // do not DS if this monitor is being mirrored. Will break the functionality. - const auto PCANDIDATE = pMonitor->solitaryClient.lock(); + // if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) + // return false; - if (!PCANDIDATE) - return false; + // const auto PCANDIDATE = pMonitor->solitaryClient.lock(); - const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); + // if (!PCANDIDATE) + // return false; - if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) - return false; + // const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - // finally, we should be GTG. - wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); + // if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) + // return false; - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) - return false; + // // finally, we should be GTG. + // wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(PSURFACE, &now); - auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE); - FEEDBACK->attachMonitor(pMonitor); - FEEDBACK->presented(); - FEEDBACK->setPresentationType(true); - PROTO::presentation->queueData(FEEDBACK); - - if (pMonitor->state.commit()) { - if (m_pLastScanout.expired()) { - m_pLastScanout = PCANDIDATE; - Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); - } - } else { - m_pLastScanout.reset(); - return false; - } + // if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) + // return false; - return true; + // timespec now; + // clock_gettime(CLOCK_MONOTONIC, &now); + // PSURFACE->frame(&now); + // auto FEEDBACK = makeShared<CQueuedPresentationData>(PSURFACE); + // FEEDBACK->attachMonitor(pMonitor); + // FEEDBACK->presented(); + // FEEDBACK->setPresentationType(true); + // PROTO::presentation->queueData(FEEDBACK); + + // if (pMonitor->state.commit()) { + // if (m_pLastScanout.expired()) { + // m_pLastScanout = PCANDIDATE; + // Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); + // } + // } else { + // m_pLastScanout.reset(); + // return false; + // } + + // return true; } void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { @@ -1430,53 +1441,52 @@ void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now) { for (auto& w : g_pCompositor->m_vWindows) { - if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface.wlr()) + if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface->resource()) continue; if (!shouldRenderWindow(w, pMonitor)) continue; - wlr_surface_for_each_surface( - w->m_pWLSurface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now); + w->m_pWLSurface->resource()->breadthfirst([now](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { for (auto& ls : lsl) { - if (ls->fadingOut || !ls->surface.wlr()) + if (ls->fadingOut || !ls->surface->resource()) continue; - wlr_surface_for_each_surface( - ls->surface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now); + ls->surface->resource()->breadthfirst([now](SP<CWLSurfaceResource> r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } } } void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) { - if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) - return; + // FIXME: fix when moved to new impl + // if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) + // return; - if (!pWindow->m_bIsFullscreen) { - wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), nullptr); - Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); - return; - } + // if (!pWindow->m_bIsFullscreen) { + // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr); + // Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); + // return; + // } - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + // const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { - .main_renderer = g_pCompositor->m_sWLRRenderer, - .scanout_primary_output = PMONITOR->output, - }; + // const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { + // .main_renderer = g_pCompositor->m_sWLRRenderer, + // .scanout_primary_output = PMONITOR->output, + // }; - wlr_linux_dmabuf_feedback_v1 feedback = {0}; + // wlr_linux_dmabuf_feedback_v1 feedback = {0}; - if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) - return; + // if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) + // return; - wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), &feedback); - wlr_linux_dmabuf_feedback_v1_finish(&feedback); + // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback); + // wlr_linux_dmabuf_feedback_v1_finish(&feedback); - Debug::log(LOG, "Scanout mode ON set for {}", pWindow); + // Debug::log(LOG, "Scanout mode ON set for {}", pWindow); } // taken from Sway. @@ -1662,26 +1672,25 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor); } -void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, double scale) { +void CHyprRenderer::damageSurface(SP<CWLSurfaceResource> pSurface, double x, double y, double scale) { if (!pSurface) return; // wut? if (g_pCompositor->m_bUnsafeState) return; - const auto WLSURF = CWLSurface::surfaceFromWlr(pSurface); + const auto WLSURF = CWLSurface::fromResource(pSurface); CRegion damageBox = WLSURF ? WLSURF->logicalDamage() : CRegion{}; if (!WLSURF) { Debug::log(ERR, "BUG THIS: No CWLSurface for surface in damageSurface!!!"); - wlr_surface_get_effective_damage(pSurface, damageBox.pixman()); + return; } if (scale != 1.0) damageBox.scale(scale); // schedule frame events - if (!wl_list_empty(&pSurface->current.frame_callback_list)) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); if (damageBox.empty()) return; @@ -1836,7 +1845,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->onDisconnect(); pMonitor->events.modeChanged.emit(); - pMonitor->updateGlobal(); return true; } @@ -2242,12 +2250,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); pMonitor->events.modeChanged.emit(); - pMonitor->updateGlobal(); return true; } -void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) { +void CHyprRenderer::setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force) { m_bCursorHasSurface = surf; m_sLastCursorData.name = ""; @@ -2464,8 +2471,8 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { continue; // TODO: cache maybe? - CRegion opaque = &ls->layerSurface->surface->opaque_region; - CBox lsbox = {0, 0, ls->layerSurface->surface->current.buffer_width, ls->layerSurface->surface->current.buffer_height}; + CRegion opaque = ls->layerSurface->surface->current.opaque; + CBox lsbox = {{}, ls->layerSurface->surface->current.size}; opaque.invert(lsbox); if (!opaque.empty()) @@ -2544,6 +2551,15 @@ CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32 return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get(); } +CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt) { + auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; }); + + if (it != m_vRenderbuffers.end()) + return it->get(); + + return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get(); +} + void CHyprRenderer::makeEGLCurrent() { if (!g_pCompositor) return; @@ -2556,7 +2572,7 @@ void CHyprRenderer::unsetEGL() { eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IWLBuffer> buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2586,10 +2602,13 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return false; } } else - m_pCurrentWlrBuffer = wlr_buffer_lock(buffer); + m_pCurrentHLBuffer = buffer; try { - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); + if (m_pCurrentWlrBuffer) + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); + else + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat); } catch (std::exception& e) { Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName); wlr_buffer_unlock(m_pCurrentWlrBuffer); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index da38fed2..f88bfebf 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -12,6 +12,7 @@ struct SMonitorRule; class CWorkspace; class CWindow; class CInputPopup; +class IWLBuffer; // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { @@ -44,7 +45,7 @@ class CHyprRenderer { void renderMonitor(CMonitor* pMonitor); void arrangeLayersForMonitor(const int&); - void damageSurface(wlr_surface*, double, double, double scale = 1.0); + void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); void damageBox(CBox*); void damageBox(const int& x, const int& y, const int& w, const int& h); @@ -57,14 +58,14 @@ class CHyprRenderer { void ensureCursorRenderingMode(); bool shouldRenderCursor(); void setCursorHidden(bool hide); - void calculateUVForSurface(PHLWINDOW, wlr_surface*, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); + void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods bool canSkipBackBufferClear(CMonitor* pMonitor); void recheckSolitaryForMonitor(CMonitor* pMonitor); - void setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force = false); + void setCursorSurface(SP<CWLSurface> surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); void onRenderbufferDestroy(CRenderbuffer* rb); CRenderbuffer* getCurrentRBO(); @@ -74,7 +75,7 @@ class CHyprRenderer { // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr, bool simple = false); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IWLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); void endRender(); bool m_bBlockSurfaceFeedback = false; @@ -98,10 +99,10 @@ class CHyprRenderer { CTimer m_tRenderTimer; struct { - int hotspotX; - int hotspotY; - std::optional<CWLSurface*> surf = nullptr; - std::string name; + int hotspotX; + int hotspotY; + std::optional<SP<CWLSurface>> surf; + std::string name; } m_sLastCursorData; private: @@ -121,6 +122,7 @@ class CHyprRenderer { bool m_bCursorHasSurface = false; CRenderbuffer* m_pCurrentRenderbuffer = nullptr; wlr_buffer* m_pCurrentWlrBuffer = nullptr; + WP<IWLBuffer> m_pCurrentHLBuffer = {}; eRenderMode m_eRenderMode = RENDER_MODE_NORMAL; bool m_bNvidia = false; @@ -132,6 +134,7 @@ class CHyprRenderer { } m_sCursorHiddenConditions; CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt); + CRenderbuffer* getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt); std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers; friend class CHyprOpenGLImpl; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 1820d0fb..aef8e4ac 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -1,16 +1,54 @@ #include "Texture.hpp" +#include "Renderer.hpp" +#include "../Compositor.hpp" +#include "../protocols/types/Buffer.hpp" +#include "../helpers/Format.hpp" CTexture::CTexture() { // naffin' } +CTexture::~CTexture() { + if (m_bNonOwning) + return; + + g_pHyprRenderer->makeEGLCurrent(); + destroyTexture(); +} + +CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + m_iType = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX; + m_vSize = size_; + allocate(); + + GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); +#ifndef GLES2 + if (format->flipRB) { + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED)); + } +#endif + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, size_.x, size_.y, 0, format->glFormat, format->glType, pixels)); + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); +} + CTexture::CTexture(wlr_texture* tex) { RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!"); wlr_gles2_texture_attribs attrs; wlr_gles2_texture_get_attribs(tex, &attrs); - m_iTarget = attrs.target; - m_iTexID = attrs.tex; + m_iTarget = attrs.target; + m_iTexID = attrs.tex; + m_bNonOwning = true; if (m_iTarget == GL_TEXTURE_2D) m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX; @@ -20,14 +58,72 @@ CTexture::CTexture(wlr_texture* tex) { m_vSize = Vector2D(tex->width, tex->height); } +CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) { + if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) { + Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); + return; + } + + m_iTarget = GL_TEXTURE_2D; + m_iType = TEXTURE_RGBA; + m_vSize = attrs.size; + m_iType = FormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA; + allocate(); + m_pEglImage = image; + + GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLCALL(g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES(m_iTarget, image)); + GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); +} + +void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) { + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + glBindTexture(GL_TEXTURE_2D, m_iTexID); + + auto rects = damage.copy().intersect(CBox{{}, m_vSize}).getRects(); + +#ifndef GLES2 + if (format->flipRB) { + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED)); + } +#endif + + for (auto& rect : rects) { + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1)); + + int width = rect.x2 - rect.x1; + int height = rect.y2 - rect.y1; + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height, format->glFormat, format->glType, pixels)); + } + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + + glBindTexture(GL_TEXTURE_2D, 0); +} + void CTexture::destroyTexture() { if (m_iTexID) { - glDeleteTextures(1, &m_iTexID); + GLCALL(glDeleteTextures(1, &m_iTexID)); m_iTexID = 0; } + + if (m_pEglImage) + g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage); + m_pEglImage = nullptr; } void CTexture::allocate() { if (!m_iTexID) - glGenTextures(1, &m_iTexID); -}
\ No newline at end of file + GLCALL(glGenTextures(1, &m_iTexID)); +} diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index 93a6aa5f..fa1ca4fe 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -2,6 +2,10 @@ #include "../defines.hpp" +class IWLBuffer; +struct SDMABUFAttrs; +class CRegion; + enum TEXTURETYPE { TEXTURE_INVALID, // Invalid TEXTURE_RGBA, // 4 channels @@ -12,13 +16,27 @@ enum TEXTURETYPE { class CTexture { public: CTexture(); + + CTexture(CTexture&) = delete; + CTexture(CTexture&&) = delete; + CTexture(const CTexture&&) = delete; + CTexture(const CTexture&) = delete; + + CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); CTexture(wlr_texture*); + // this ctor takes ownership of the eglImage. + CTexture(const SDMABUFAttrs&, void* image); + ~CTexture(); + void destroyTexture(); void allocate(); + void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); TEXTURETYPE m_iType = TEXTURE_RGBA; GLenum m_iTarget = GL_TEXTURE_2D; GLuint m_iTexID = 0; Vector2D m_vSize; + void* m_pEglImage = nullptr; + bool m_bNonOwning = false; // wlr };
\ No newline at end of file diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 04f69aaa..d96f2c3c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -6,23 +6,23 @@ #include <pango/pangocairo.h> // shared things to conserve VRAM -static CTexture m_tGradientActive; -static CTexture m_tGradientInactive; -static CTexture m_tGradientLockedActive; -static CTexture m_tGradientLockedInactive; +static SP<CTexture> m_tGradientActive = makeShared<CTexture>(); +static SP<CTexture> m_tGradientInactive = makeShared<CTexture>(); +static SP<CTexture> m_tGradientLockedActive = makeShared<CTexture>(); +static SP<CTexture> m_tGradientLockedInactive = makeShared<CTexture>(); -constexpr int BAR_INDICATOR_HEIGHT = 3; -constexpr int BAR_PADDING_OUTER_VERT = 2; -constexpr int BAR_PADDING_OUTER_HORZ = 2; -constexpr int BAR_TEXT_PAD = 2; -constexpr int BAR_HORIZONTAL_PADDING = 2; +constexpr int BAR_INDICATOR_HEIGHT = 3; +constexpr int BAR_PADDING_OUTER_VERT = 2; +constexpr int BAR_PADDING_OUTER_HORZ = 2; +constexpr int BAR_TEXT_PAD = 2; +constexpr int BAR_HORIZONTAL_PADDING = 2; CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) { static auto PGRADIENTS = CConfigValue<Hyprlang::INT>("group:groupbar:enabled"); static auto PENABLED = CConfigValue<Hyprlang::INT>("group:groupbar:gradients"); m_pWindow = pWindow; - if (m_tGradientActive.m_iTexID == 0 && *PENABLED && *PGRADIENTS) + if (m_tGradientActive->m_iTexID == 0 && *PENABLED && *PGRADIENTS) refreshGroupBarGradients(); } @@ -157,10 +157,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { rect.scale(pMonitor->scale); if (*PGRADIENTS) { - const auto& GRADIENTTEX = - (m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : - (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); - if (GRADIENTTEX.m_iTexID != 0) + const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : + (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); + if (GRADIENTTEX->m_iTexID != 0) g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0); } @@ -204,6 +203,7 @@ void CHyprGroupBarDecoration::invalidateTextures() { } CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) { + tex = makeShared<CTexture>(); szContent = pWindow->m_szTitle; pWindowOwner = pWindow; const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); @@ -254,8 +254,8 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - tex.allocate(); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + tex->allocate(); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -272,10 +272,10 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float } CTitleTex::~CTitleTex() { - tex.destroyTexture(); + tex->destroyTexture(); } -void renderGradientTo(CTexture& tex, CGradientValueData* grad) { +void renderGradientTo(SP<CTexture> tex, CGradientValueData* grad) { if (!g_pCompositor->m_pLastMonitor) return; @@ -308,8 +308,8 @@ void renderGradientTo(CTexture& tex, CGradientValueData* grad) { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - tex.allocate(); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + tex->allocate(); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -340,11 +340,11 @@ void refreshGroupBarGradients() { g_pHyprRenderer->makeEGLCurrent(); - if (m_tGradientActive.m_iTexID != 0) { - m_tGradientActive.destroyTexture(); - m_tGradientInactive.destroyTexture(); - m_tGradientLockedActive.destroyTexture(); - m_tGradientLockedInactive.destroyTexture(); + if (m_tGradientActive->m_iTexID != 0) { + m_tGradientActive->destroyTexture(); + m_tGradientInactive->destroyTexture(); + m_tGradientLockedActive->destroyTexture(); + m_tGradientLockedInactive->destroyTexture(); } if (!*PENABLED || !*PGRADIENTS) diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index e3f553c5..64870d45 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -12,7 +12,7 @@ class CTitleTex { CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale); ~CTitleTex(); - CTexture tex; + SP<CTexture> tex; std::string szContent; PHLWINDOWREF pWindowOwner; }; diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 8994e975..07cac832 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -1,6 +1,7 @@ #include "XSurface.hpp" #include "XWayland.hpp" #include "../protocols/XWaylandShell.hpp" +#include "../protocols/core/Compositor.hpp" #ifndef NO_XWAYLAND @@ -44,46 +45,41 @@ CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID } void CXWaylandSurface::ensureListeners() { - bool connected = hyprListener_surfaceDestroy.isConnected(); + bool connected = listeners.destroySurface; if (connected && !surface) { - hyprListener_surfaceDestroy.removeCallback(); - hyprListener_surfaceCommit.removeCallback(); + listeners.destroySurface.reset(); + listeners.commitSurface.reset(); } else if (!connected && surface) { - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, - [this](void* owner, void* data) { - if (mapped) - unmap(); - - surface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); - hyprListener_surfaceCommit.removeCallback(); - events.resourceChange.emit(); - }, - nullptr, "CXWaylandSurface"); - hyprListener_surfaceCommit.initCallback( - &surface->events.commit, - [this](void* owner, void* data) { - if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) { - map(); - return; - } - - if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) { - unmap(); - return; - } - - events.commit.emit(); - }, - nullptr, "CXWaylandSurface"); + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { + if (mapped) + unmap(); + + surface.reset(); + listeners.destroySurface.reset(); + listeners.commitSurface.reset(); + events.resourceChange.emit(); + }); + + listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { + if (surface->pending.buffer && !mapped) { + map(); + return; + } + + if (!surface->pending.buffer && mapped) { + unmap(); + return; + } + + events.commit.emit(); + }); } if (resource) { listeners.destroyResource = resource->events.destroy.registerListener([this](std::any d) { unmap(); - surface = nullptr; + surface.reset(); events.resourceChange.emit(); }); } @@ -99,7 +95,7 @@ void CXWaylandSurface::map() { g_pXWayland->pWM->mappedSurfacesStacking.emplace_back(self); mapped = true; - wlr_surface_map(surface); + surface->map(); Debug::log(LOG, "XWayland surface {:x} mapping", (uintptr_t)this); @@ -118,7 +114,7 @@ void CXWaylandSurface::unmap() { std::erase(g_pXWayland->pWM->mappedSurfacesStacking, self); mapped = false; - wlr_surface_unmap(surface); + surface->unmap(); Debug::log(LOG, "XWayland surface {:x} unmapping", (uintptr_t)this); @@ -136,7 +132,7 @@ void CXWaylandSurface::considerMap() { return; } - if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) { + if (surface->pending.buffer) { Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer"); map(); return; diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 73cb89a5..0cdac1d5 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -5,7 +5,7 @@ #include "../helpers/Box.hpp" #include <vector> -struct wlr_surface; +class CWLSurfaceResource; class CXWaylandSurfaceResource; #ifdef NO_XWAYLAND @@ -39,7 +39,7 @@ typedef struct { class CXWaylandSurface { public: - wlr_surface* surface = nullptr; + WP<CWLSurfaceResource> surface; WP<CXWaylandSurfaceResource> resource; struct { @@ -109,11 +109,10 @@ class CXWaylandSurface { void considerMap(); void setWithdrawn(bool withdrawn); - DYNLISTENER(surfaceDestroy); - DYNLISTENER(surfaceCommit); - struct { CHyprSignalListener destroyResource; + CHyprSignalListener destroySurface; + CHyprSignalListener commitSurface; } listeners; friend class CXWM; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 5dfd4839..7af1d506 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -6,6 +6,7 @@ #include <unordered_map> #include "../Compositor.hpp" #include "../protocols/XWaylandShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" #include "../protocols/core/Seat.hpp" #include <ranges> @@ -296,7 +297,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { auto id = e->data.data32[0]; auto resource = wl_client_get_object(g_pXWayland->pServer->xwaylandClient, id); if (resource) { - auto wlrSurface = wlr_surface_from_resource(resource); + auto wlrSurface = CWLSurfaceResource::fromResource(resource); associate(XSURF, wlrSurface); } } else if (e->type == HYPRATOMS["WL_SURFACE_SERIAL"]) { @@ -318,7 +319,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { if (res->serial != XSURF->wlSerial || !XSURF->wlSerial) continue; - associate(XSURF, res->surface); + associate(XSURF, res->surface.lock()); break; } @@ -827,9 +828,7 @@ CXWM::CXWM() { initSelection(); - hyprListener_newSurface.initCallback( - &g_pCompositor->m_sWLRCompositor->events.new_surface, [this](void* owner, void* data) { onNewSurface((wlr_surface*)data); }, nullptr, "XWM"); - + listeners.newWLSurface = PROTO::compositor->events.newSurface.registerListener([this](std::any d) { onNewSurface(std::any_cast<SP<CWLSurfaceResource>>(d)); }); listeners.newXShellSurface = PROTO::xwaylandShell->events.newSurface.registerListener([this](std::any d) { onNewResource(std::any_cast<SP<CXWaylandSurfaceResource>>(d)); }); createWMWindow(); @@ -903,13 +902,13 @@ void CXWM::sendState(SP<CXWaylandSurface> surf) { xcb_change_property(connection, XCB_PROP_MODE_REPLACE, surf->xID, HYPRATOMS["_NET_WM_STATE"], XCB_ATOM_ATOM, 32, props.size(), props.data()); } -void CXWM::onNewSurface(wlr_surface* surf) { - if (wl_resource_get_client(surf->resource) != g_pXWayland->pServer->xwaylandClient) +void CXWM::onNewSurface(SP<CWLSurfaceResource> surf) { + if (surf->client() != g_pXWayland->pServer->xwaylandClient) return; Debug::log(LOG, "[xwm] New XWayland surface at {:x}", (uintptr_t)surf); - const auto WLID = wl_resource_get_id(surf->resource); + const auto WLID = surf->id(); for (auto& sr : surfaces) { if (sr->surface || sr->wlID != WLID) @@ -932,7 +931,7 @@ void CXWM::onNewResource(SP<CXWaylandSurfaceResource> resource) { if (surf->resource || surf->wlSerial != resource->serial) continue; - associate(surf, resource->surface); + associate(surf, resource->surface.lock()); break; } } @@ -955,7 +954,7 @@ void CXWM::readWindowData(SP<CXWaylandSurface> surf) { } } -void CXWM::associate(SP<CXWaylandSurface> surf, wlr_surface* wlSurf) { +void CXWM::associate(SP<CXWaylandSurface> surf, SP<CWLSurfaceResource> wlSurf) { if (surf->surface) return; @@ -981,7 +980,7 @@ void CXWM::dissociate(SP<CXWaylandSurface> surf) { if (surf->mapped) surf->unmap(); - surf->surface = nullptr; + surf->surface.reset(); surf->events.resourceChange.emit(); Debug::log(LOG, "Dissociate for {:x}", (uintptr_t)surf.get()); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 1d695a15..bdf4fac2 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -73,7 +73,7 @@ class CXWM { void createWMWindow(); void initSelection(); - void onNewSurface(wlr_surface* surf); + void onNewSurface(SP<CWLSurfaceResource> surf); void onNewResource(SP<CXWaylandSurfaceResource> resource); void setActiveWindow(xcb_window_t window); @@ -87,7 +87,7 @@ class CXWM { SP<CXWaylandSurface> windowForXID(xcb_window_t wid); void readWindowData(SP<CXWaylandSurface> surf); - void associate(SP<CXWaylandSurface> surf, wlr_surface* wlSurf); + void associate(SP<CXWaylandSurface> surf, SP<CWLSurfaceResource> wlSurf); void dissociate(SP<CXWaylandSurface> surf); void updateClientList(); @@ -147,9 +147,8 @@ class CXWM { SXSelection clipboard; - DYNLISTENER(newSurface); - struct { + CHyprSignalListener newWLSurface; CHyprSignalListener newXShellSurface; } listeners; |