Skip to content

Commit

Permalink
Move decoration input resolution code to a shared class InputResolver
Browse files Browse the repository at this point in the history
Added `InputResolverAdapter` to expose a more stable(?) interface. It
allows users to point to their implementation of
`process_{enter,leave,up,down,motion, drag}`.

Remove ununsed `DeviceEvent&` parameter from `process_{leave,up,down}`.
  • Loading branch information
tarek-y-ismail committed Nov 11, 2024
1 parent 4c33535 commit 977ef38
Show file tree
Hide file tree
Showing 15 changed files with 627 additions and 480 deletions.
298 changes: 99 additions & 199 deletions examples/miral-custom-decorations/input.cpp

Large diffs are not rendered by default.

73 changes: 25 additions & 48 deletions examples/miral-custom-decorations/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef MIRAL_CUSTOM_DECORATIONS_INPUT_H
#define MIRAL_CUSTOM_DECORATIONS_INPUT_H

#include "mir/shell/input_resolver.h"
#include "mircore/mir/geometry/rectangle.h"
#include "mircore/mir_toolkit/common.h"
#include "threadsafe_access.h"
Expand All @@ -28,6 +29,8 @@
#include <map>
#include <optional>

namespace msd = mir::shell::decoration;

struct MirEvent;
class UserDecorationExample;

Expand All @@ -47,13 +50,6 @@ class Shell;
}
}

enum class ButtonState
{
Up, ///< The user is not interacting with this button
Hovered, ///< The user is hovering over this button
Down, ///< The user is currently pressing this button
};

enum class ButtonFunction
{
Close,
Expand All @@ -64,7 +60,7 @@ enum class ButtonFunction
struct ButtonInfo
{
ButtonFunction function;
ButtonState state;
msd::ButtonState state;
mir::geometry::Rectangle rect;

auto operator==(ButtonInfo const& other) const -> bool
Expand Down Expand Up @@ -101,17 +97,19 @@ class InputState
/// Manages user input
class InputManager
{

public:
InputManager(
std::shared_ptr<StaticGeometry const> const& static_geometry,
WindowState const& window_state,
std::shared_ptr<ThreadsafeAccess<UserDecorationExample>> const& decoration);
~InputManager();

void handle_input_event(std::shared_ptr<MirEvent const> const& event);

void update_window_state(WindowState const& window_state);
auto state() -> std::unique_ptr<InputState>;

void handle_input_event(std::shared_ptr<MirEvent const> const& event);
private:
static std::chrono::nanoseconds const double_click_threshold;

Expand All @@ -123,22 +121,6 @@ class InputManager
StaticGeometry const& static_geometry,
MirResizeEdge resize_edge) -> mir::geometry::Rectangle;

void pointer_event(std::shared_ptr<MirEvent const> const& event, mir::geometry::Point location, bool pressed);
void pointer_leave(std::shared_ptr<MirEvent const> const& event);
void touch_event(std::shared_ptr<MirEvent const> const& event, int32_t id, mir::geometry::Point location);

void touch_up(std::shared_ptr<MirEvent const> const& event, int32_t id);

std::mutex mutex;
std::shared_ptr<StaticGeometry const> const static_geometry;
std::shared_ptr<ThreadsafeAccess<UserDecorationExample>> decoration;
std::vector<mir::geometry::Rectangle> input_shape;
/// The most recent event, or the event currently being processed
std::shared_ptr<MirEvent const> latest_event;
/// Timestamp of the previous up event (not the one currently being processed)
std::chrono::nanoseconds previous_up_timestamp{0};
std::string current_cursor_name{""};

struct Widget
{
Widget(ButtonFunction button)
Expand All @@ -152,41 +134,28 @@ class InputManager
}

mir::geometry::Rectangle rect;
ButtonState state{ButtonState::Up};
msd::ButtonState state{msd::ButtonState::Up};
std::optional<ButtonFunction> const button;
// mir_resize_edge_none is used to mean the widget moves the window
std::optional<MirResizeEdge> const resize_edge;
};

using DeviceEvent = msd::InputResolver::DeviceEvent;
/// Pointer or touchpoint
struct Device
{
Device(mir::geometry::Point location, bool pressed)
: location{location},
pressed{pressed}

{
}

mir::geometry::Point location;
bool pressed;
std::optional<std::shared_ptr<Widget>> active_widget;
};

/// The input device has entered the surface
void process_enter(Device& device);
void process_enter(DeviceEvent& device);
/// The input device has left the surface
void process_leave(Device& device);
void process_leave();
/// The input device has clicked down
/// A touch triggers a process_enter() followed by a process_down()
void process_down(Device& device);
void process_down();
/// The input device has released
/// A touch release triggers a process_up() followed by a process_leave()
void process_up(Device& device);
void process_up();
/// The device has moved while up
void process_move(Device& device);
void process_move(DeviceEvent& device);
/// The device has moved while down
void process_drag(Device& device);
void process_drag(DeviceEvent& device);

auto widget_at(mir::geometry::Point location) -> std::optional<std::shared_ptr<Widget>>;

Expand All @@ -205,9 +174,17 @@ class InputManager

void set_cursor(MirResizeEdge resize_edge);

std::optional<Device> pointer;
std::map<int32_t, Device> touches;
std::shared_ptr<StaticGeometry const> const static_geometry;
std::shared_ptr<ThreadsafeAccess<UserDecorationExample>> decoration;
std::vector<std::shared_ptr<Widget>> widgets;
std::unique_ptr<mir::shell::decoration::InputResolver> input_resolver;
std::mutex mutex;
std::vector<mir::geometry::Rectangle> input_shape;
std::optional<std::shared_ptr<Widget>> active_widget;
/// Timestamp of the previous up event (not the one currently being processed)
std::chrono::nanoseconds previous_up_timestamp{0};
/// The most recent event, or the event currently being processed
std::string current_cursor_name{""};
};

#endif
2 changes: 1 addition & 1 deletion examples/miral-custom-decorations/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ auto Renderer::render_titlebar() -> std::optional<std::shared_ptr<mg::Buffer>>
auto const [icon_theme, icon_drawer] = icon->second;

Pixel button_color = icon_theme.normal_color;
if (button.state == ButtonState::Hovered)
if (button.state == msd::ButtonState::Hovered)
button_color = icon_theme.active_color;
for (geom::Y y{scaled_button_rect.top()}; y < scaled_button_rect.bottom(); y += geom::DeltaY{1})
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef MIRAL_CUSTOM_DECORATIONS_USER_DECORATION_EXAMPLE_H
#define MIRAL_CUSTOM_DECORATIONS_USER_DECORATION_EXAMPLE_H

#include "mir/shell/input_resolver.h"
#include "renderer.h"
#include "theme.h"
#include "window.h"
Expand Down
70 changes: 70 additions & 0 deletions include/miral/miral/decoration/decoration_input_resolver_adapter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MIRAL_DECORATION_DECORATION_INPUT_MANAGER_ADAPTER_H
#define MIRAL_DECORATION_DECORATION_INPUT_MANAGER_ADAPTER_H

#include "mir/shell/input_resolver.h"

#include <functional>
#include <memory>

namespace miral::decoration
{
class InputResolverBuilder;
class InputResolverAdapter : public mir::shell::decoration::InputResolver
{
protected:
void process_enter(DeviceEvent& device) override;
void process_leave() override;
void process_down() override;
void process_up() override;
void process_move(DeviceEvent& device) override;
void process_drag(DeviceEvent& device) override;

private:
friend InputResolverBuilder;
InputResolverAdapter();

std::function<void(DeviceEvent& device)> on_process_enter;
std::function<void()> on_process_leave;
std::function<void()> on_process_down;
std::function<void()> on_process_up;
std::function<void(DeviceEvent& device)> on_process_move;
std::function<void(DeviceEvent& device)> on_process_drag;
};

class InputResolverBuilder
{
public:
using DeviceEvent = mir::shell::decoration::InputResolver::DeviceEvent;
static auto build(
std::function<void(DeviceEvent& device)> on_process_enter,
std::function<void()> on_process_leave,
std::function<void()> on_process_down,
std::function<void()> on_process_up,
std::function<void(DeviceEvent& device)> on_process_move,
std::function<void(DeviceEvent& device)> on_process_drag) -> InputResolverBuilder;

auto done() -> std::unique_ptr<InputResolverAdapter>;

private:
InputResolverBuilder();

std::unique_ptr<InputResolverAdapter> adapter;
};
}
#endif
117 changes: 117 additions & 0 deletions src/include/server/mir/shell/input_resolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MIR_SHELL_DECORATION_INPUT_MANAGER_H_
#define MIR_SHELL_DECORATION_INPUT_MANAGER_H_

#include "mir/geometry/rectangle.h"
#include "mir_toolkit/common.h"

#include <memory>
#include <mutex>
#include <map>
#include <optional>

struct MirEvent;

namespace mir
{
namespace scene
{
class Surface;
}
namespace input
{
class CursorImages;
}
namespace shell
{
class Shell;
namespace decoration
{
class Decoration;
class WindowState;
class BasicDecoration;
class StaticGeometry;
template<typename T> class ThreadsafeAccess;

enum class ButtonState
{
Up, ///< The user is not interacting with this button
Hovered, ///< The user is hovering over this button
Down, ///< The user is currently pressing this button
};

// Given an input event, figures out which decoration callback should be
// invoked to respond.
class InputResolver
{
public:

/// Pointer or touchpoint
struct DeviceEvent
{
DeviceEvent(geometry::Point location, bool pressed)
: location{location},
pressed{pressed}

{
}

geometry::Point location;
bool pressed;
};

virtual ~InputResolver() = default;
void handle_input_event(std::shared_ptr<MirEvent const> const& event);
auto latest_event() -> std::shared_ptr<MirEvent const> const;

protected:
// To be overriden by child classes.
// Called into from {pointer,touch}_{event,leave}

/// The input device has entered the surface
virtual void process_enter(DeviceEvent& device) = 0;
/// The input device has left the surface
virtual void process_leave() = 0;
/// The input device has clicked down
/// A touch triggers a process_enter() followed by a process_down()
virtual void process_down() = 0;
/// The input device has released
/// A touch release triggers a process_up() followed by a process_leave()
virtual void process_up() = 0;
/// The device has moved while up
virtual void process_move(DeviceEvent& device) = 0;
/// The device has moved while down
virtual void process_drag(DeviceEvent& device) = 0;

std::mutex mutex;
private:
void pointer_event(std::shared_ptr<MirEvent const> const& event, geometry::Point location, bool pressed);
void pointer_leave(std::shared_ptr<MirEvent const> const& event);
void touch_event(std::shared_ptr<MirEvent const> const& event, int32_t id, geometry::Point location);
void touch_up(std::shared_ptr<MirEvent const> const& event, int32_t id);

/// The most recent event, or the event currently being processed
std::shared_ptr<MirEvent const> latest_event_;
std::optional<DeviceEvent> pointer;
std::map<int32_t, DeviceEvent> touches;
};
}
}
}

#endif
1 change: 1 addition & 0 deletions src/miral/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ add_library(miral-internal STATIC
window_specification_internal.cpp window_specification_internal.h
decoration/decoration_manager_adapter.cpp
decoration/decoration_adapter.cpp
decoration/decoration_input_resolver_adapter.cpp
)

# Already implied by the linker's symbol version script, but can avoid accidents
Expand Down
Loading

0 comments on commit 977ef38

Please sign in to comment.