From 23022322331d98775c3a8ab245195cf6b2894a1f Mon Sep 17 00:00:00 2001 From: Peter Wilhelmsson <2hdddg@gmail.com> Date: Wed, 24 Jan 2024 20:26:21 +0100 Subject: [PATCH] Initial mouse wheel support Probably a bit shaky but has initial support of wheel data from Wayland to Lua widgets. Showcasing with audio widget. Actual values sent to pactl seems to be a bit badly chosen, something better is needed. --- config/config.lua | 14 ++++++++++++-- src/Configuration.h | 1 + src/Manager.cpp | 12 ++++++++++-- src/Manager.h | 1 + src/Output.cpp | 19 +++++++++++++++++++ src/Output.h | 1 + src/ScriptContext.cpp | 10 ++++++++++ src/Seat.cpp | 39 +++++++++++++++++++++++++++++++++------ src/Seat.h | 12 +++++++++--- src/ShellSurface.cpp | 34 ++++++++++++++++++++++++++++++++-- src/ShellSurface.h | 1 + 11 files changed, 129 insertions(+), 15 deletions(-) diff --git a/config/config.lua b/config/config.lua index 731d5cf..5d26016 100644 --- a/config/config.lua +++ b/config/config.lua @@ -117,7 +117,7 @@ local function render_workspaces(displayName) end local function click_workspace(tag) - os.execute("swaymsg workspace '" .. tag .. "'") + os.execute('swaymsg workspace "' .. tag .. '"') end local function render_time() @@ -151,6 +151,16 @@ local function click_audio() os.execute("pactl set-sink-mute @DEFAULT_SINK@ toggle") end +local function wheel_audio(tag, value) + local prefix = "" + if value < 0 then + prefix = "+" + else + prefix = "-" + end + os.execute("pactl set-sink-volume @DEFAULT_SINK@ " .. prefix .. "10000") +end + local function click_keyboard() local layout = "se" if zen.keyboard.layout == "Swedish" then @@ -211,7 +221,7 @@ return { anchor = "right", widgets = { { sources = {'keyboard'}, padding = { right = 10 }, on_render = render_keyboard, on_click = click_keyboard }, - { sources = {'audio'}, padding = { top = 10, right = 10 }, on_render = render_audio, on_click = click_audio }, + { sources = {'audio'}, padding = { top = 10, right = 10 }, on_render = render_audio, on_click = click_audio, on_wheel = wheel_audio }, { sources = {'power'}, padding = { top = 10, right = 10 }, on_render = render_power }, { sources = {'networks'}, padding = { top = 10, right = 10 }, on_render = render_networks }, }, diff --git a/src/Configuration.h b/src/Configuration.h index 2a282c0..ca72ca8 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -101,6 +101,7 @@ struct WidgetConfig { WidgetConfig() : padding({}) {} std::function(const std::string& outputName)> render; std::function click; + std::function wheel; std::set sources; Padding padding; }; diff --git a/src/Manager.cpp b/src/Manager.cpp index 94f5217..19fe6a7 100644 --- a/src/Manager.cpp +++ b/src/Manager.cpp @@ -10,8 +10,11 @@ std::shared_ptr Manager::Create(std::shared_ptr registry) { spdlog::error("No seat in registry"); return nullptr; } - registry->seat->RegisterClickHandler( - [manager](auto surface, int x, int y) { manager->ClickSurface(surface, x, y); }); + registry->seat->RegisterHandlers( + [manager](auto surface, int x, int y) { manager->ClickSurface(surface, x, y); }, + [manager](auto surface, int x, int y, int value) { + manager->WheelSurface(surface, x, y, value); + }); return manager; } @@ -20,6 +23,11 @@ void Manager::ClickSurface(wl_surface* surface, int x, int y) { m_registry->BorrowOutputs().ClickSurface(surface, x, y); } +void Manager::WheelSurface(wl_surface* surface, int x, int y, int value) { + spdlog::debug("Wheel in surface {} at {},{},{}", (void*)surface, x, y, value); + m_registry->BorrowOutputs().WheelSurface(surface, x, y, value); +} + void Manager::OnBatchProcessed() { // Always publish sources m_sources->PublishAll(); diff --git a/src/Manager.h b/src/Manager.h index fdb2cbb..899eb4c 100644 --- a/src/Manager.h +++ b/src/Manager.h @@ -19,6 +19,7 @@ class Manager : public IoBatchHandler { void Hide(); void ClickSurface(wl_surface* surface, int x, int y); + void WheelSurface(wl_surface* surface, int x, int y, int value); private: Manager(std::shared_ptr registry) : m_registry(registry) {} diff --git a/src/Output.cpp b/src/Output.cpp index 16582b2..cbbf491 100644 --- a/src/Output.cpp +++ b/src/Output.cpp @@ -66,6 +66,17 @@ class Output { return false; } + bool WheelSurface(wl_surface *surface, int x, int y, int value) { + for (auto &kv : m_surfaces) { + if (kv.second->WheelSurface(surface, x, y, value)) { + spdlog::debug("Wheel in surface"); + return true; + } + } + spdlog::debug("No surface found for wheel"); + return false; + } + private: Output(wl_output *wloutput, std::shared_ptr config, OnNamedCallback onNamed) : m_wloutput(wloutput), m_config(config), m_onNamed(onNamed) {} @@ -159,3 +170,11 @@ void Outputs::ClickSurface(wl_surface *surface, int x, int y) { } } } + +void Outputs::WheelSurface(wl_surface *surface, int x, int y, int value) { + for (auto &kv : m_map) { + if (kv.second->WheelSurface(surface, x, y, value)) { + return; + } + } +} diff --git a/src/Output.h b/src/Output.h index 05428a2..bc287e9 100644 --- a/src/Output.h +++ b/src/Output.h @@ -25,6 +25,7 @@ class Outputs { void Hide(const Registry& registry); void ClickSurface(wl_surface* surface, int x, int y); + void WheelSurface(wl_surface* surface, int x, int y, int value); private: Outputs(std::shared_ptr config) : m_config(config) {} diff --git a/src/ScriptContext.cpp b/src/ScriptContext.cpp index 1cb978b..ac05172 100644 --- a/src/ScriptContext.cpp +++ b/src/ScriptContext.cpp @@ -132,6 +132,7 @@ static void ParseWidgetConfig(const sol::table& table, std::vector } return FromObject(*result); }; + // Click handler sol::optional maybeClickFunction = table["on_click"]; if (maybeClickFunction) { auto clickFunction = *maybeClickFunction; @@ -140,6 +141,15 @@ static void ParseWidgetConfig(const sol::table& table, std::vector return true; }; } + // Wheel handler + sol::optional maybeWheelFunction = table["on_wheel"]; + if (maybeWheelFunction) { + auto wheelFunction = *maybeWheelFunction; + widget.wheel = [wheelFunction](std::string_view tag, int value) { + wheelFunction(tag, value); + return true; + }; + } widget.padding = PaddingFromProperty(table, "padding"); widgets.push_back(std::move(widget)); } diff --git a/src/Seat.cpp b/src/Seat.cpp index 03d5425..9081115 100644 --- a/src/Seat.cpp +++ b/src/Seat.cpp @@ -1,5 +1,6 @@ #include "Seat.h" +#include #include #include #include @@ -28,23 +29,43 @@ static void on_pointer_motion(void* data, struct wl_pointer*, uint32_t /*time*/, static void on_pointer_button(void* data, struct wl_pointer*, uint32_t /*serial*/, uint32_t /*time*/, uint32_t button, uint32_t state) { spdlog::trace("Pointer click button {} state {}", button, state); - if (state == 0 /*release*/) { + if (state == 0 /*release*/ && button == BTN_LEFT) { ((Pointer*)data)->Click(); + return; } } -void on_pointer_frame(void* /*data*/, struct wl_pointer*) {} +static void on_axis(void* data, struct wl_pointer*, uint32_t /*time*/, uint32_t axis, + wl_fixed_t value) { + spdlog::trace("on_axis, axis: {}, value: {}", axis, value); + if (axis == WL_POINTER_AXIS_SOURCE_WHEEL) { + ((Pointer*)data)->Wheel(value); + } +} + +static void on_pointer_frame(void* /*data*/, struct wl_pointer*) {} + +static void on_axis_source(void* /*data*/, struct wl_pointer*, uint32_t /*axis_source*/) {} +static void on_axis_stop(void* /*data*/, struct wl_pointer*, uint32_t /*time*/, uint32_t /*axis*/) { +} +static void on_axis_discrete(void* /*data*/, struct wl_pointer*, uint32_t /*axis*/, + int32_t /*discrete*/) {} +/* +[2024-01-24 19:34:07.087] [trace] on_axis_source: 0 +[2024-01-24 19:34:07.087] [trace] on_axis_discrete axis 0, discrete: 1 +[2024-01-24 19:34:07.087] [trace] on_axis, axis: 0, value: 3840 +*/ static const wl_pointer_listener pointer_listener = { .enter = on_pointer_enter, .leave = on_pointer_leave, .motion = on_pointer_motion, .button = on_pointer_button, - .axis = nullptr, + .axis = on_axis, .frame = on_pointer_frame, - .axis_source = nullptr, - .axis_stop = nullptr, - .axis_discrete = nullptr, + .axis_source = on_axis_source, + .axis_stop = on_axis_stop, + .axis_discrete = on_axis_discrete, // Version > supported //.axis_value120 = nullptr, //.axis_relative_direction = nullptr, @@ -63,6 +84,12 @@ void Pointer::Click() { m_clickHandler(m_current, wl_fixed_to_int(m_x), wl_fixed_to_int(m_y)); } +void Pointer::Wheel(wl_fixed_t value) { + if (!m_current) return; + if (!m_wheelHandler) return; + m_wheelHandler(m_current, wl_fixed_to_int(m_x), wl_fixed_to_int(m_y), wl_fixed_to_int(value)); +} + static void on_keymap(void* data, struct wl_keyboard*, uint32_t format, int32_t fd, uint32_t size) { if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { spdlog::error("Keyboard: Invalid keymap format"); diff --git a/src/Seat.h b/src/Seat.h index 00c0e96..cbad657 100644 --- a/src/Seat.h +++ b/src/Seat.h @@ -10,6 +10,7 @@ #include "src/Sources.h" using ClickHandler = std::function; +using WheelHandler = std::function; class Keyboard : public Source { public: @@ -37,7 +38,10 @@ class Pointer { wl_pointer_destroy(m_wlpointer); m_wlpointer = nullptr; } - void RegisterClickHandler(ClickHandler handler) { m_clickHandler = handler; } + void RegisterHandlers(ClickHandler clickHandler, WheelHandler wheelHandler) { + m_clickHandler = clickHandler; + m_wheelHandler = wheelHandler; + } void Enter(wl_surface* surface) { m_current = surface; } void Leave() { m_current = nullptr; } void Track(wl_fixed_t x, wl_fixed_t y) { @@ -45,6 +49,7 @@ class Pointer { m_y = y; } void Click(); + void Wheel(int value); private: wl_pointer* m_wlpointer; @@ -52,6 +57,7 @@ class Pointer { wl_fixed_t m_x; wl_fixed_t m_y; ClickHandler m_clickHandler; + WheelHandler m_wheelHandler; }; class Seat { @@ -63,11 +69,11 @@ class Seat { m_wlseat = nullptr; } - void RegisterClickHandler(ClickHandler handler) { + void RegisterHandlers(ClickHandler clickHandler, WheelHandler wheelHandler) { // TODO: Log error if (!m_pointer) return; - m_pointer->RegisterClickHandler(handler); + m_pointer->RegisterHandlers(clickHandler, wheelHandler); } std::shared_ptr keyboard; diff --git a/src/ShellSurface.cpp b/src/ShellSurface.cpp index 88c64c2..ec43feb 100644 --- a/src/ShellSurface.cpp +++ b/src/ShellSurface.cpp @@ -49,8 +49,7 @@ void ShellSurface::OnClosed() { } bool ShellSurface::ClickSurface(wl_surface *surface, int x, int y) { - bool isThis = surface == m_surface; - if (!isThis) { + if (surface != m_surface) { return false; } // Check what widget @@ -79,6 +78,37 @@ bool ShellSurface::ClickSurface(wl_surface *surface, int x, int y) { return true; } +// TODO: Refactor to share some code between Click and Wheel +bool ShellSurface::WheelSurface(wl_surface *surface, int x, int y, int value) { + if (surface != m_surface) { + return false; + } + // Check what widget + int i = 0; + for (const auto &w : m_drawn.widgets) { + if (w.position.Contains(x, y)) { + auto &widget = m_panelConfig.widgets.at(i); + if (widget.wheel) { + // Widget has a wheel handler. There might be inner more + // specific targets, find the tag of the correct one. + std::string tag = ""; + for (const auto &t : w.targets) { + if (t.position.Contains(x, y)) { + tag = t.tag; + break; + } + } + spdlog::debug("Wheel in widget, tag: {}", tag); + widget.wheel(tag, value); + } + break; + } + i++; + } + // Return true even if no widget was found to stop trying other surfaces + return true; +} + void ShellSurface::Draw(const Registry ®istry, BufferPool &bufferPool, const std::string &outputName) { if (m_isClosed) { diff --git a/src/ShellSurface.h b/src/ShellSurface.h index 4eae99c..be6bdae 100644 --- a/src/ShellSurface.h +++ b/src/ShellSurface.h @@ -22,6 +22,7 @@ class ShellSurface { void OnClosed(); bool ClickSurface(wl_surface *surface, int x, int y); + bool WheelSurface(wl_surface *surface, int x, int y, int value); private: ShellSurface(wl_output *output, wl_surface *surface, PanelConfig panelConfiguration)