aboutsummaryrefslogtreecommitdiffstats
path: root/bindings/cxx
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-10-31 13:00:53 +0100
committerDavid Robillard <d@drobilla.net>2020-10-31 13:00:53 +0100
commitf7cce780cd6a83fca9413abeafb32246999f4b99 (patch)
tree5f972ff9cc4822548b031c78ca9cc540890eb9a5 /bindings/cxx
parent71312135e580b247d500070ea699462a6f3c26eb (diff)
downloadpugl-f7cce780cd6a83fca9413abeafb32246999f4b99.tar.gz
pugl-f7cce780cd6a83fca9413abeafb32246999f4b99.tar.bz2
pugl-f7cce780cd6a83fca9413abeafb32246999f4b99.zip
Use static polymorphism in C++ bindings
This removes virtual function overhead, and the weird situation of having to include pugl.ipp once (or worse, for pugl to provide a binary C++ library).
Diffstat (limited to 'bindings/cxx')
-rw-r--r--bindings/cxx/include/pugl/pugl.hpp170
-rw-r--r--bindings/cxx/include/pugl/pugl.ipp176
-rw-r--r--bindings/cxx/include/pugl/vulkan.hpp2
3 files changed, 100 insertions, 248 deletions
diff --git a/bindings/cxx/include/pugl/pugl.hpp b/bindings/cxx/include/pugl/pugl.hpp
index 54c0648..dde29c8 100644
--- a/bindings/cxx/include/pugl/pugl.hpp
+++ b/bindings/cxx/include/pugl/pugl.hpp
@@ -353,8 +353,14 @@ enum class Cursor {
static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, "");
-/// @copydoc PuglView
-class View : protected detail::Wrapper<PuglView, puglFreeView>
+/**
+ A drawable region that receives events.
+
+ This is the generic base class for all views. It can be used directly by
+ manually setting an event handling function, but typical applications should
+ use pugl::View which handles dispatching events.
+*/
+class ViewBase : protected detail::Wrapper<PuglView, puglFreeView>
{
public:
/**
@@ -363,26 +369,13 @@ public:
@{
*/
- explicit View(World& world)
+ explicit ViewBase(World& world)
: Wrapper{puglNewView(world.cobj())}
, _world(world)
{
- if (cobj()) {
- puglSetHandle(cobj(), this);
- puglSetEventFunc(cobj(), dispatchEvent);
- }
-
PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::View");
}
- virtual ~View() noexcept = default;
-
- View(const View&) = delete;
- View& operator=(const View&) = delete;
-
- View(View&&) = delete;
- View&& operator=(View&&) = delete;
-
const World& world() const noexcept { return _world; }
World& world() noexcept { return _world; }
@@ -559,6 +552,38 @@ public:
return static_cast<Status>(puglStopTimer(cobj(), id));
}
+ PuglView* cobj() noexcept { return Wrapper::cobj(); }
+ const PuglView* cobj() const noexcept { return Wrapper::cobj(); }
+
+private:
+ World& _world;
+};
+
+/**
+ A view with event handlers.
+
+ To implement a view, applications can inherit from this class, which handles
+ type-safe dispatching of events to methods. This class uses the CRTP
+ pattern, so the name of the derived class needs to be passed as a template
+ paramter, for example:
+
+ @code
+ class MyView : public pugl::View<MyView>
+ @endcode
+*/
+template<class Derived>
+class View : public ViewBase
+{
+public:
+ explicit View(World& world)
+ : ViewBase{world}
+ {
+ if (cobj()) {
+ puglSetHandle(cobj(), this);
+ puglSetEventFunc(cobj(), eventFunc);
+ }
+ }
+
/**
@}
@name Event Handlers
@@ -566,40 +591,45 @@ public:
@{
*/
- virtual Status onCreate(const CreateEvent&) PUGL_CONST_FUNC;
- virtual Status onDestroy(const DestroyEvent&) PUGL_CONST_FUNC;
- virtual Status onConfigure(const ConfigureEvent&) PUGL_CONST_FUNC;
- virtual Status onMap(const MapEvent&) PUGL_CONST_FUNC;
- virtual Status onUnmap(const UnmapEvent&) PUGL_CONST_FUNC;
- virtual Status onUpdate(const UpdateEvent&) PUGL_CONST_FUNC;
- virtual Status onExpose(const ExposeEvent&) PUGL_CONST_FUNC;
- virtual Status onClose(const CloseEvent&) PUGL_CONST_FUNC;
- virtual Status onFocusIn(const FocusInEvent&) PUGL_CONST_FUNC;
- virtual Status onFocusOut(const FocusOutEvent&) PUGL_CONST_FUNC;
- virtual Status onKeyPress(const KeyPressEvent&) PUGL_CONST_FUNC;
- virtual Status onKeyRelease(const KeyReleaseEvent&) PUGL_CONST_FUNC;
- virtual Status onText(const TextEvent&) PUGL_CONST_FUNC;
- virtual Status onPointerIn(const PointerInEvent&) PUGL_CONST_FUNC;
- virtual Status onPointerOut(const PointerOutEvent&) PUGL_CONST_FUNC;
- virtual Status onButtonPress(const ButtonPressEvent&) PUGL_CONST_FUNC;
- virtual Status onButtonRelease(const ButtonReleaseEvent&) PUGL_CONST_FUNC;
- virtual Status onMotion(const MotionEvent&) PUGL_CONST_FUNC;
- virtual Status onScroll(const ScrollEvent&) PUGL_CONST_FUNC;
- virtual Status onClient(const ClientEvent&) PUGL_CONST_FUNC;
- virtual Status onTimer(const TimerEvent&) PUGL_CONST_FUNC;
- virtual Status onLoopEnter(const LoopEnterEvent&) PUGL_CONST_FUNC;
- virtual Status onLoopLeave(const LoopLeaveEvent&) PUGL_CONST_FUNC;
+ Status onEvent(const CreateEvent&) noexcept { return Status::success; }
+ Status onEvent(const DestroyEvent&) noexcept { return Status::success; }
+ Status onEvent(const ConfigureEvent&) noexcept { return Status::success; }
+ Status onEvent(const MapEvent&) noexcept { return Status::success; }
+ Status onEvent(const UnmapEvent&) noexcept { return Status::success; }
+ Status onEvent(const UpdateEvent&) noexcept { return Status::success; }
+ Status onEvent(const ExposeEvent&) noexcept { return Status::success; }
+ Status onEvent(const CloseEvent&) noexcept { return Status::success; }
+ Status onEvent(const FocusInEvent&) noexcept { return Status::success; }
+ Status onEvent(const FocusOutEvent&) noexcept { return Status::success; }
+ Status onEvent(const KeyPressEvent&) noexcept { return Status::success; }
+ Status onEvent(const KeyReleaseEvent&) noexcept { return Status::success; }
+ Status onEvent(const TextEvent&) noexcept { return Status::success; }
+ Status onEvent(const PointerInEvent&) noexcept { return Status::success; }
+ Status onEvent(const PointerOutEvent&) noexcept { return Status::success; }
+ Status onEvent(const ButtonPressEvent&) noexcept { return Status::success; }
+ Status onEvent(const ButtonReleaseEvent&) noexcept
+ {
+ return Status::success;
+ }
+ Status onEvent(const MotionEvent&) noexcept { return Status::success; }
+ Status onEvent(const ScrollEvent&) noexcept { return Status::success; }
+ Status onEvent(const ClientEvent&) noexcept { return Status::success; }
+ Status onEvent(const TimerEvent&) noexcept { return Status::success; }
+ Status onEvent(const LoopEnterEvent&) noexcept { return Status::success; }
+ Status onEvent(const LoopLeaveEvent&) noexcept { return Status::success; }
/**
@}
*/
- PuglView* cobj() noexcept { return Wrapper::cobj(); }
- const PuglView* cobj() const noexcept { return Wrapper::cobj(); }
-
private:
- static PuglStatus
- dispatchEvent(PuglView* view, const PuglEvent* event) noexcept
+ Derived& self() noexcept { return *static_cast<Derived*>(this); }
+ const Derived& self() const noexcept
+ {
+ return *static_cast<Derived*>(this);
+ }
+
+ static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept
{
View* self = static_cast<View*>(puglGetHandle(view));
@@ -621,79 +651,77 @@ private:
return PUGL_SUCCESS;
case PUGL_CREATE:
return static_cast<PuglStatus>(
- onCreate(static_cast<const CreateEvent&>(event->any)));
+ self().onEvent(static_cast<const CreateEvent&>(event->any)));
case PUGL_DESTROY:
return static_cast<PuglStatus>(
- onDestroy(static_cast<const DestroyEvent&>(event->any)));
+ self().onEvent(static_cast<const DestroyEvent&>(event->any)));
case PUGL_CONFIGURE:
- return static_cast<PuglStatus>(onConfigure(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const ConfigureEvent&>(event->configure)));
case PUGL_MAP:
return static_cast<PuglStatus>(
- onMap(static_cast<const MapEvent&>(event->any)));
+ self().onEvent(static_cast<const MapEvent&>(event->any)));
case PUGL_UNMAP:
return static_cast<PuglStatus>(
- onUnmap(static_cast<const UnmapEvent&>(event->any)));
+ self().onEvent(static_cast<const UnmapEvent&>(event->any)));
case PUGL_UPDATE:
return static_cast<PuglStatus>(
- onUpdate(static_cast<const UpdateEvent&>(event->any)));
+ self().onEvent(static_cast<const UpdateEvent&>(event->any)));
case PUGL_EXPOSE:
return static_cast<PuglStatus>(
- onExpose(static_cast<const ExposeEvent&>(event->expose)));
+ self().onEvent(static_cast<const ExposeEvent&>(event->expose)));
case PUGL_CLOSE:
return static_cast<PuglStatus>(
- onClose(static_cast<const CloseEvent&>(event->any)));
+ self().onEvent(static_cast<const CloseEvent&>(event->any)));
case PUGL_FOCUS_IN:
return static_cast<PuglStatus>(
- onFocusIn(static_cast<const FocusInEvent&>(event->focus)));
+ self().onEvent(static_cast<const FocusInEvent&>(event->focus)));
case PUGL_FOCUS_OUT:
- return static_cast<PuglStatus>(
- onFocusOut(static_cast<const FocusOutEvent&>(event->focus)));
+ return static_cast<PuglStatus>(self().onEvent(
+ static_cast<const FocusOutEvent&>(event->focus)));
case PUGL_KEY_PRESS:
return static_cast<PuglStatus>(
- onKeyPress(static_cast<const KeyPressEvent&>(event->key)));
+ self().onEvent(static_cast<const KeyPressEvent&>(event->key)));
case PUGL_KEY_RELEASE:
- return static_cast<PuglStatus>(
- onKeyRelease(static_cast<const KeyReleaseEvent&>(event->key)));
+ return static_cast<PuglStatus>(self().onEvent(
+ static_cast<const KeyReleaseEvent&>(event->key)));
case PUGL_TEXT:
return static_cast<PuglStatus>(
- onText(static_cast<const TextEvent&>(event->text)));
+ self().onEvent(static_cast<const TextEvent&>(event->text)));
case PUGL_POINTER_IN:
- return static_cast<PuglStatus>(onPointerIn(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const PointerInEvent&>(event->crossing)));
case PUGL_POINTER_OUT:
- return static_cast<PuglStatus>(onPointerOut(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const PointerOutEvent&>(event->crossing)));
case PUGL_BUTTON_PRESS:
- return static_cast<PuglStatus>(onButtonPress(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const ButtonPressEvent&>(event->button)));
case PUGL_BUTTON_RELEASE:
- return static_cast<PuglStatus>(onButtonRelease(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const ButtonReleaseEvent&>(event->button)));
case PUGL_MOTION:
return static_cast<PuglStatus>(
- onMotion(static_cast<const MotionEvent&>(event->motion)));
+ self().onEvent(static_cast<const MotionEvent&>(event->motion)));
case PUGL_SCROLL:
return static_cast<PuglStatus>(
- onScroll(static_cast<const ScrollEvent&>(event->scroll)));
+ self().onEvent(static_cast<const ScrollEvent&>(event->scroll)));
case PUGL_CLIENT:
return static_cast<PuglStatus>(
- onClient(static_cast<const ClientEvent&>(event->client)));
+ self().onEvent(static_cast<const ClientEvent&>(event->client)));
case PUGL_TIMER:
return static_cast<PuglStatus>(
- onTimer(static_cast<const TimerEvent&>(event->timer)));
+ self().onEvent(static_cast<const TimerEvent&>(event->timer)));
case PUGL_LOOP_ENTER:
return static_cast<PuglStatus>(
- onLoopEnter(static_cast<const LoopEnterEvent&>(event->any)));
+ self().onEvent(static_cast<const LoopEnterEvent&>(event->any)));
case PUGL_LOOP_LEAVE:
return static_cast<PuglStatus>(
- onLoopLeave(static_cast<const LoopLeaveEvent&>(event->any)));
+ self().onEvent(static_cast<const LoopLeaveEvent&>(event->any)));
}
return PUGL_FAILURE;
}
-
- World& _world;
};
/**
diff --git a/bindings/cxx/include/pugl/pugl.ipp b/bindings/cxx/include/pugl/pugl.ipp
deleted file mode 100644
index c11f7d0..0000000
--- a/bindings/cxx/include/pugl/pugl.ipp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- Copyright 2012-2020 David Robillard <d@drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, 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.
-*/
-
-/**
- @file pugl.ipp
- @brief Pugl C++ API wrapper implementation.
-
- This file must be included exactly once in the application.
-*/
-
-#include "pugl/pugl.hpp"
-
-namespace pugl {
-
-#ifdef PUGL_HPP_THROW_FAILED_CONSTRUCTION
-
-const char*
-FailedConstructionError::what() const noexcept
-{
- return _msg;
-}
-
-#endif
-
-Status
-View::onCreate(const CreateEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onDestroy(const DestroyEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onConfigure(const ConfigureEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onMap(const MapEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onUnmap(const UnmapEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onUpdate(const UpdateEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onExpose(const ExposeEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onClose(const CloseEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onFocusIn(const FocusInEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onFocusOut(const FocusOutEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onKeyPress(const KeyPressEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onKeyRelease(const KeyReleaseEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onText(const TextEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onPointerIn(const PointerInEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onPointerOut(const PointerOutEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onButtonPress(const ButtonPressEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onButtonRelease(const ButtonReleaseEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onMotion(const MotionEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onScroll(const ScrollEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onClient(const ClientEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onTimer(const TimerEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onLoopEnter(const LoopEnterEvent&)
-{
- return Status::success;
-}
-
-Status
-View::onLoopLeave(const LoopLeaveEvent&)
-{
- return Status::success;
-}
-
-} // namespace pugl
diff --git a/bindings/cxx/include/pugl/vulkan.hpp b/bindings/cxx/include/pugl/vulkan.hpp
index a7b16cb..f9737e8 100644
--- a/bindings/cxx/include/pugl/vulkan.hpp
+++ b/bindings/cxx/include/pugl/vulkan.hpp
@@ -143,7 +143,7 @@ getInstanceExtensions() noexcept
/// @copydoc puglCreateSurface
inline VkResult
createSurface(const VulkanLoader& loader,
- View& view,
+ ViewBase& view,
VkInstance instance,
const VkAllocationCallbacks* const allocator,
VkSurfaceKHR* const surface) noexcept