diff --git a/CMakeLists.txt b/CMakeLists.txt index fb2209c..eb3cfa7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ target_link_libraries(hyprpaper ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_SOURCE_DIR}/wlr-layer-shell-unstable-v1-protocol.o ${CMAKE_SOURCE_DIR}/xdg-shell-protocol.o + wayland-cursor ) IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) diff --git a/src/Hyprpaper.cpp b/src/Hyprpaper.cpp index a610b35..361d30e 100644 --- a/src/Hyprpaper.cpp +++ b/src/Hyprpaper.cpp @@ -124,12 +124,23 @@ void CHyprpaper::recheckAllMonitors() { } } +void CHyprpaper::createSeat(wl_seat* pSeat) { + wl_seat_add_listener(pSeat, &Events::seatListener, pSeat); +} + void CHyprpaper::recheckMonitor(SMonitor* pMonitor) { ensureMonitorHasActiveWallpaper(pMonitor); if (pMonitor->wantsACK) { pMonitor->wantsACK = false; zwlr_layer_surface_v1_ack_configure(pMonitor->pCurrentLayerSurface->pLayerSurface, pMonitor->configureSerial); + + int XCURSOR_SIZE = 24; + if (getenv("XCURSOR_SIZE")) { + XCURSOR_SIZE = std::stoi(getenv("XCURSOR_SIZE")); + } + + pMonitor->pCurrentLayerSurface->pCursorImg = wl_cursor_theme_get_cursor(wl_cursor_theme_load(getenv("XCURSOR_THEME"), XCURSOR_SIZE * pMonitor->scale, m_sSHM), "left_ptr")->images[0]; } if (pMonitor->wantsReload) { diff --git a/src/Hyprpaper.hpp b/src/Hyprpaper.hpp index d3c4624..2b9aaf4 100644 --- a/src/Hyprpaper.hpp +++ b/src/Hyprpaper.hpp @@ -53,8 +53,11 @@ public: void ensurePoolBuffersPresent(); SPoolBuffer* getPoolBuffer(SMonitor*, CWallpaperTarget*); void unloadWallpaper(const std::string&); + void createSeat(wl_seat*); std::mutex m_mtTickMutex; + + SMonitor* m_pLastMonitor = nullptr; private: bool m_bShouldExit = false; diff --git a/src/events/Events.cpp b/src/events/Events.cpp index 3ff4439..2e1573f 100644 --- a/src/events/Events.cpp +++ b/src/events/Events.cpp @@ -33,6 +33,47 @@ void Events::description(void *data, wl_output *wl_output, const char *descripti // i do not care } +void Events::handleCapabilities(void *data, wl_seat *wl_seat, uint32_t capabilities) { + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + wl_pointer_add_listener(wl_seat_get_pointer(wl_seat), &pointerListener, wl_seat); + } +} + +void Events::handlePointerLeave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { + // ignored + wl_surface_commit(surface); + + g_pHyprpaper->m_pLastMonitor = nullptr; +} + +void Events::handlePointerAxis(void *data, wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { + // ignored +} + +void Events::handlePointerMotion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { + // ignored + if (g_pHyprpaper->m_pLastMonitor) { + wl_surface_commit(g_pHyprpaper->m_pLastMonitor->pCurrentLayerSurface->pSurface); + } +} + +void Events::handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) { + // ignored +} + +void Events::handlePointerEnter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + for (auto& mon : g_pHyprpaper->m_vMonitors) { + if (mon->pCurrentLayerSurface->pSurface == surface) { + g_pHyprpaper->m_pLastMonitor = mon.get(); + + wl_surface_set_buffer_scale(mon->pCurrentLayerSurface->pCursorSurface, mon->scale); + wl_surface_attach(mon->pCurrentLayerSurface->pCursorSurface, wl_cursor_image_get_buffer(mon->pCurrentLayerSurface->pCursorImg), 0, 0); + wl_pointer_set_cursor(wl_pointer, serial, mon->pCurrentLayerSurface->pCursorSurface, mon->pCurrentLayerSurface->pCursorImg->hotspot_x / mon->scale, mon->pCurrentLayerSurface->pCursorImg->hotspot_y / mon->scale); + wl_surface_commit(mon->pCurrentLayerSurface->pCursorSurface); + } + } +} + void Events::ls_configure(void *data, zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t width, uint32_t height) { const auto PLAYERSURFACE = (CLayerSurface*)data; @@ -60,6 +101,8 @@ void Events::handleGlobal(void *data, struct wl_registry *registry, uint32_t nam wl_output_add_listener(PMONITOR->output, &Events::outputListener, PMONITOR); g_pHyprpaper->m_mtTickMutex.unlock(); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + g_pHyprpaper->createSeat((wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1)); } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { g_pHyprpaper->m_sLayerShell = (zwlr_layer_shell_v1 *)wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1); } diff --git a/src/events/Events.hpp b/src/events/Events.hpp index c03e00d..2b01d2e 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -21,9 +21,25 @@ namespace Events { void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name); + void handleCapabilities(void *data, wl_seat *wl_seat, uint32_t capabilities); + + void handlePointerMotion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y); + + void handlePointerButton(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state); + + void handlePointerAxis(void *data, wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value); + + void handlePointerEnter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y); + + void handlePointerLeave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface); + inline const wl_output_listener outputListener = {.geometry = geometry, .mode = mode, .done = done, .scale = scale, .name = name, .description = description}; inline const zwlr_layer_surface_v1_listener layersurfaceListener = { .configure = ls_configure }; inline const struct wl_registry_listener registryListener = { .global = handleGlobal, .global_remove = handleGlobalRemove }; + + inline const wl_pointer_listener pointerListener = { .enter = handlePointerEnter, .leave = handlePointerLeave, .motion = handlePointerMotion, .button = handlePointerButton, .axis = handlePointerAxis }; + + inline const wl_seat_listener seatListener = { .capabilities = handleCapabilities }; } diff --git a/src/includes.hpp b/src/includes.hpp index f515ee4..a3895e9 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -19,6 +19,7 @@ extern "C" { #include "wlr-layer-shell-unstable-v1-protocol.h" #include "xdg-shell-protocol.h" #include +#include } #undef class diff --git a/src/render/LayerSurface.cpp b/src/render/LayerSurface.cpp index 7e5ff83..d66e8c3 100644 --- a/src/render/LayerSurface.cpp +++ b/src/render/LayerSurface.cpp @@ -6,6 +6,7 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { m_pMonitor = pMonitor; pSurface = wl_compositor_create_surface(g_pHyprpaper->m_sCompositor); + pCursorSurface = wl_compositor_create_surface(g_pHyprpaper->m_sCompositor); if (!pSurface) { Debug::log(CRIT, "The compositor did not allow hyprpaper a surface!"); diff --git a/src/render/LayerSurface.hpp b/src/render/LayerSurface.hpp index 0a75983..42dde3a 100644 --- a/src/render/LayerSurface.hpp +++ b/src/render/LayerSurface.hpp @@ -13,4 +13,7 @@ public: zwlr_layer_surface_v1* pLayerSurface = nullptr; wl_surface* pSurface = nullptr; + + wl_cursor_image* pCursorImg = nullptr; + wl_surface* pCursorSurface = nullptr; };