1 /*
2   Copyright 2012-2020 David Robillard <d@drobilla.net>
3 
4   Permission to use, copy, modify, and/or distribute this software for any
5   purpose with or without fee is hereby granted, provided that the above
6   copyright notice and this permission notice appear in all copies.
7 
8   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 
17 #ifndef PUGL_PUGL_HPP
18 #define PUGL_PUGL_HPP
19 
20 #include "pugl/pugl.h"
21 
22 #include <cstdint>
23 
24 #if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION)
25 #  include <exception>
26 #elif defined(PUGL_HPP_ASSERT_CONSTRUCTION)
27 #  include <cassert>
28 #endif
29 
30 namespace pugl {
31 
32 /**
33    @defgroup puglxx Pugl C++ API
34    Pugl C++ API wrapper.
35    @{
36 */
37 
38 namespace detail {
39 
40 /// Free function for a C object
41 template<typename T>
42 using FreeFunc = void (*)(T*);
43 
44 /// Generic C++ wrapper for a C object
45 template<class T, FreeFunc<T> Free>
46 class Wrapper
47 {
48 public:
49   Wrapper(const Wrapper&) = delete;
50   Wrapper& operator=(const Wrapper&) = delete;
51 
Wrapper(Wrapper && wrapper)52   Wrapper(Wrapper&& wrapper) noexcept
53     : _ptr{wrapper._ptr}
54   {
55     wrapper._ptr = nullptr;
56   }
57 
operator =(Wrapper && wrapper)58   Wrapper& operator=(Wrapper&& wrapper) noexcept
59   {
60     _ptr         = wrapper._ptr;
61     wrapper._ptr = nullptr;
62     return *this;
63   }
64 
~Wrapper()65   ~Wrapper() noexcept { Free(_ptr); }
66 
cobj()67   T*       cobj() noexcept { return _ptr; }
cobj() const68   const T* cobj() const noexcept { return _ptr; }
69 
70 protected:
Wrapper(T * ptr)71   explicit Wrapper(T* ptr) noexcept
72     : _ptr{ptr}
73   {}
74 
75 private:
76   T* _ptr;
77 };
78 
79 } // namespace detail
80 
81 using Rect = PuglRect; ///< @copydoc PuglRect
82 
83 /**
84    @defgroup eventsxx Events
85    @{
86 */
87 
88 /**
89    A strongly-typed analogue of PuglEvent.
90 
91    This is bit-for-bit identical to the corresponding PuglEvent, so events are
92    simply cast to this type to avoid any copying overhead.
93 
94    @tparam t The `type` field of the corresponding PuglEvent.
95 
96    @tparam Base The specific struct type of the corresponding PuglEvent.
97 */
98 template<PuglEventType t, class Base>
99 struct Event final : Base {
100   /// The type of the corresponding C event structure
101   using BaseEvent = Base;
102 
103   /// The `type` field of the corresponding C event structure
104   static constexpr const PuglEventType type = t;
105 };
106 
107 using Mod          = PuglMod;          ///< @copydoc PuglMod
108 using Mods         = PuglMods;         ///< @copydoc PuglMods
109 using Key          = PuglKey;          ///< @copydoc PuglKey
110 using EventType    = PuglEventType;    ///< @copydoc PuglEventType
111 using EventFlag    = PuglEventFlag;    ///< @copydoc PuglEventFlag
112 using EventFlags   = PuglEventFlags;   ///< @copydoc PuglEventFlags
113 using CrossingMode = PuglCrossingMode; ///< @copydoc PuglCrossingMode
114 
115 /// @copydoc PuglEventCreate
116 using CreateEvent = Event<PUGL_CREATE, PuglEventCreate>;
117 
118 /// @copydoc PuglEventDestroy
119 using DestroyEvent = Event<PUGL_DESTROY, PuglEventDestroy>;
120 
121 /// @copydoc PuglEventConfigure
122 using ConfigureEvent = Event<PUGL_CONFIGURE, PuglEventConfigure>;
123 
124 /// @copydoc PuglEventMap
125 using MapEvent = Event<PUGL_MAP, PuglEventMap>;
126 
127 /// @copydoc PuglEventUnmap
128 using UnmapEvent = Event<PUGL_UNMAP, PuglEventUnmap>;
129 
130 /// @copydoc PuglEventUpdate
131 using UpdateEvent = Event<PUGL_UPDATE, PuglEventUpdate>;
132 
133 /// @copydoc PuglEventExpose
134 using ExposeEvent = Event<PUGL_EXPOSE, PuglEventExpose>;
135 
136 /// @copydoc PuglEventClose
137 using CloseEvent = Event<PUGL_CLOSE, PuglEventClose>;
138 
139 /// @copydoc PuglEventFocus
140 using FocusInEvent = Event<PUGL_FOCUS_IN, PuglEventFocus>;
141 
142 /// @copydoc PuglEventFocus
143 using FocusOutEvent = Event<PUGL_FOCUS_OUT, PuglEventFocus>;
144 
145 /// @copydoc PuglEventKey
146 using KeyPressEvent = Event<PUGL_KEY_PRESS, PuglEventKey>;
147 
148 /// @copydoc PuglEventKey
149 using KeyReleaseEvent = Event<PUGL_KEY_RELEASE, PuglEventKey>;
150 
151 /// @copydoc PuglEventText
152 using TextEvent = Event<PUGL_TEXT, PuglEventText>;
153 
154 /// @copydoc PuglEventCrossing
155 using PointerInEvent = Event<PUGL_POINTER_IN, PuglEventCrossing>;
156 
157 /// @copydoc PuglEventCrossing
158 using PointerOutEvent = Event<PUGL_POINTER_OUT, PuglEventCrossing>;
159 
160 /// @copydoc PuglEventButton
161 using ButtonPressEvent = Event<PUGL_BUTTON_PRESS, PuglEventButton>;
162 
163 /// @copydoc PuglEventButton
164 using ButtonReleaseEvent = Event<PUGL_BUTTON_RELEASE, PuglEventButton>;
165 
166 /// @copydoc PuglEventMotion
167 using MotionEvent = Event<PUGL_MOTION, PuglEventMotion>;
168 
169 /// @copydoc PuglEventScroll
170 using ScrollEvent = Event<PUGL_SCROLL, PuglEventScroll>;
171 
172 /// @copydoc PuglEventClient
173 using ClientEvent = Event<PUGL_CLIENT, PuglEventClient>;
174 
175 /// @copydoc PuglEventTimer
176 using TimerEvent = Event<PUGL_TIMER, PuglEventTimer>;
177 
178 /// @copydoc PuglEventLoopEnter
179 using LoopEnterEvent = Event<PUGL_LOOP_ENTER, PuglEventLoopEnter>;
180 
181 /// @copydoc PuglEventLoopLeave
182 using LoopLeaveEvent = Event<PUGL_LOOP_LEAVE, PuglEventLoopLeave>;
183 
184 /**
185    @}
186    @defgroup statusxx Status
187    @{
188 */
189 
190 /// @copydoc PuglStatus
191 enum class Status {
192   success,             ///< @copydoc PUGL_SUCCESS
193   failure,             ///< @copydoc PUGL_FAILURE
194   unknownError,        ///< @copydoc PUGL_UNKNOWN_ERROR
195   badBackend,          ///< @copydoc PUGL_BAD_BACKEND
196   badConfiguration,    ///< @copydoc PUGL_BAD_CONFIGURATION
197   badParameter,        ///< @copydoc PUGL_BAD_PARAMETER
198   backendFailed,       ///< @copydoc PUGL_BACKEND_FAILED
199   registrationFailed,  ///< @copydoc PUGL_REGISTRATION_FAILED
200   realizeFailed,       ///< @copydoc PUGL_REALIZE_FAILED
201   setFormatFailed,     ///< @copydoc PUGL_SET_FORMAT_FAILED
202   createContextFailed, ///< @copydoc PUGL_CREATE_CONTEXT_FAILED
203   unsupportedType,     ///< @copydoc PUGL_UNSUPPORTED_TYPE
204 };
205 
206 static_assert(Status(PUGL_UNSUPPORTED_TYPE) == Status::unsupportedType, "");
207 
208 /// @copydoc puglStrerror
209 inline const char*
strerror(const Status status)210 strerror(const Status status) noexcept
211 {
212   return puglStrerror(static_cast<PuglStatus>(status));
213 }
214 
215 /**
216    @}
217    @defgroup worldxx World
218    @{
219 */
220 
221 /// @copydoc PuglWorldType
222 enum class WorldType {
223   program, ///< @copydoc PUGL_PROGRAM
224   module,  ///< @copydoc PUGL_MODULE
225 };
226 
227 static_assert(WorldType(PUGL_MODULE) == WorldType::module, "");
228 
229 /// @copydoc PuglWorldFlag
230 enum class WorldFlag {
231   threads = PUGL_WORLD_THREADS, ///< @copydoc PUGL_WORLD_THREADS
232 };
233 
234 static_assert(WorldFlag(PUGL_WORLD_THREADS) == WorldFlag::threads, "");
235 
236 using WorldFlags = PuglWorldFlags; ///< @copydoc PuglWorldFlags
237 
238 #if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION)
239 
240 /// An exception thrown when construction fails
241 class FailedConstructionError : public std::exception
242 {
243 public:
FailedConstructionError(const char * const msg)244   FailedConstructionError(const char* const msg) noexcept
245     : _msg{msg}
246   {}
247 
248   virtual const char* what() const noexcept override;
249 
250 private:
251   const char* _msg;
252 };
253 
254 #  define PUGL_CHECK_CONSTRUCTION(cond, msg) \
255     do {                                     \
256       if (!(cond)) {                         \
257         throw FailedConstructionError(msg);  \
258       }                                      \
259     } while (0)
260 
261 #elif defined(PUGL_HPP_ASSERT_CONSTRUCTION)
262 #  define PUGL_CHECK_CONSTRUCTION(cond, msg) assert(cond);
263 #else
264 /**
265    Configurable macro for handling construction failure.
266 
267    If `PUGL_HPP_THROW_FAILED_CONSTRUCTION` is defined, then this throws a
268    `pugl::FailedConstructionError` if construction fails.
269 
270    If `PUGL_HPP_ASSERT_CONSTRUCTION` is defined, then this asserts if
271    construction fails.
272 
273    Otherwise, this does nothing.
274 */
275 #  define PUGL_CHECK_CONSTRUCTION(cond, msg)
276 #endif
277 
278 /// @copydoc PuglWorld
279 class World : public detail::Wrapper<PuglWorld, puglFreeWorld>
280 {
281 public:
282   World(const World&) = delete;
283   World& operator=(const World&) = delete;
284 
285   World(World&&) = delete;
286   World& operator=(World&&) = delete;
287 
288   ~World() = default;
289 
World(WorldType type,WorldFlag flag)290   World(WorldType type, WorldFlag flag)
291     : Wrapper{puglNewWorld(static_cast<PuglWorldType>(type),
292                            static_cast<PuglWorldFlags>(flag))}
293   {
294     PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World");
295   }
296 
World(WorldType type,WorldFlags flags)297   World(WorldType type, WorldFlags flags)
298     : Wrapper{puglNewWorld(static_cast<PuglWorldType>(type), flags)}
299   {
300     PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World");
301   }
302 
World(WorldType type)303   explicit World(WorldType type)
304     : World{type, WorldFlags{}}
305   {}
306 
307   /// @copydoc puglGetNativeWorld
nativeWorld()308   void* nativeWorld() noexcept { return puglGetNativeWorld(cobj()); }
309 
310   /// @copydoc puglSetClassName
setClassName(const char * const name)311   Status setClassName(const char* const name) noexcept
312   {
313     return static_cast<Status>(puglSetClassName(cobj(), name));
314   }
315 
316   /// @copydoc puglGetTime
time() const317   double time() const noexcept { return puglGetTime(cobj()); }
318 
319   /// @copydoc puglUpdate
update(const double timeout)320   Status update(const double timeout) noexcept
321   {
322     return static_cast<Status>(puglUpdate(cobj(), timeout));
323   }
324 };
325 
326 /**
327    @}
328    @defgroup viewxx View
329    @{
330 */
331 
332 using Backend    = PuglBackend;    ///< @copydoc PuglBackend
333 using NativeView = PuglNativeView; ///< @copydoc PuglNativeView
334 
335 /// @copydoc PuglViewHint
336 enum class ViewHint {
337   useCompatProfile,    ///< @copydoc PUGL_USE_COMPAT_PROFILE
338   useDebugContext,     ///< @copydoc PUGL_USE_DEBUG_CONTEXT
339   contextVersionMajor, ///< @copydoc PUGL_CONTEXT_VERSION_MAJOR
340   contextVersionMinor, ///< @copydoc PUGL_CONTEXT_VERSION_MINOR
341   redBits,             ///< @copydoc PUGL_RED_BITS
342   greenBits,           ///< @copydoc PUGL_GREEN_BITS
343   blueBits,            ///< @copydoc PUGL_BLUE_BITS
344   alphaBits,           ///< @copydoc PUGL_ALPHA_BITS
345   depthBits,           ///< @copydoc PUGL_DEPTH_BITS
346   stencilBits,         ///< @copydoc PUGL_STENCIL_BITS
347   samples,             ///< @copydoc PUGL_SAMPLES
348   doubleBuffer,        ///< @copydoc PUGL_DOUBLE_BUFFER
349   swapInterval,        ///< @copydoc PUGL_SWAP_INTERVAL
350   resizable,           ///< @copydoc PUGL_RESIZABLE
351   ignoreKeyRepeat,     ///< @copydoc PUGL_IGNORE_KEY_REPEAT
352   refreshRate,         ///< @copydoc PUGL_REFRESH_RATE
353 };
354 
355 static_assert(ViewHint(PUGL_REFRESH_RATE) == ViewHint::refreshRate, "");
356 
357 using ViewHintValue = PuglViewHintValue; ///< @copydoc PuglViewHintValue
358 
359 /// @copydoc PuglCursor
360 enum class Cursor {
361   arrow,     ///< @copydoc PUGL_CURSOR_ARROW
362   caret,     ///< @copydoc PUGL_CURSOR_CARET
363   crosshair, ///< @copydoc PUGL_CURSOR_CROSSHAIR
364   hand,      ///< @copydoc PUGL_CURSOR_HAND
365   no,        ///< @copydoc PUGL_CURSOR_NO
366   leftRight, ///< @copydoc PUGL_CURSOR_LEFT_RIGHT
367   upDown,    ///< @copydoc PUGL_CURSOR_UP_DOWN
368 };
369 
370 static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, "");
371 
372 /// @copydoc PuglView
373 class View : protected detail::Wrapper<PuglView, puglFreeView>
374 {
375 public:
376   /**
377      @name Setup
378      Methods for creating and destroying a view.
379      @{
380   */
381 
View(World & world)382   explicit View(World& world)
383     : Wrapper{puglNewView(world.cobj())}
384     , _world(world)
385   {
386     PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::View");
387   }
388 
world() const389   const World& world() const noexcept { return _world; }
world()390   World&       world() noexcept { return _world; }
391 
392   /**
393      Set the object that will be called to handle events.
394 
395      This is a type-safe wrapper for the C functions puglSetHandle() and
396      puglSetEventFunc() that will automatically dispatch events to the
397      `onEvent` method of `handler` that takes the appropriate event type.
398      The handler must have such a method defined for every event type, but if
399      the handler is the view itself, a `using` declaration can be used to
400      "inherit" the default implementation to avoid having to define every
401      method.  For example:
402 
403      @code
404      class MyView : public pugl::View
405      {
406      public:
407        explicit MyView(pugl::World& world)
408          : pugl::View{world}
409        {
410          setEventHandler(*this);
411        }
412 
413        using pugl::View::onEvent;
414 
415        pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept;
416        pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept;
417      };
418      @endcode
419 
420      This facility is just a convenience, applications may use the C API
421      directly to set a handle and event function to set up a different
422      approach for event handling.
423   */
424   template<class Handler>
setEventHandler(Handler & handler)425   Status setEventHandler(Handler& handler)
426   {
427     puglSetHandle(cobj(), &handler);
428     return static_cast<Status>(puglSetEventFunc(cobj(), eventFunc<Handler>));
429   }
430 
431   /// @copydoc puglSetBackend
setBackend(const PuglBackend * backend)432   Status setBackend(const PuglBackend* backend) noexcept
433   {
434     return static_cast<Status>(puglSetBackend(cobj(), backend));
435   }
436 
437   /// @copydoc puglSetViewHint
setHint(ViewHint hint,int value)438   Status setHint(ViewHint hint, int value) noexcept
439   {
440     return static_cast<Status>(
441       puglSetViewHint(cobj(), static_cast<PuglViewHint>(hint), value));
442   }
443 
444   /// @copydoc puglGetViewHint
getHint(ViewHint hint)445   int getHint(ViewHint hint) noexcept
446   {
447     return puglGetViewHint(cobj(), static_cast<PuglViewHint>(hint));
448   }
449 
450   /**
451      @}
452      @name Frame
453      Methods for working with the position and size of a view.
454      @{
455   */
456 
457   /// @copydoc puglGetFrame
frame() const458   Rect frame() const noexcept { return puglGetFrame(cobj()); }
459 
460   /// @copydoc puglSetFrame
setFrame(Rect frame)461   Status setFrame(Rect frame) noexcept
462   {
463     return static_cast<Status>(puglSetFrame(cobj(), frame));
464   }
465 
466   /// @copydoc puglSetDefaultSize
setDefaultSize(int width,int height)467   Status setDefaultSize(int width, int height) noexcept
468   {
469     return static_cast<Status>(puglSetDefaultSize(cobj(), width, height));
470   }
471 
472   /// @copydoc puglSetMinSize
setMinSize(int width,int height)473   Status setMinSize(int width, int height) noexcept
474   {
475     return static_cast<Status>(puglSetMinSize(cobj(), width, height));
476   }
477 
478   /// @copydoc puglSetMaxSize
setMaxSize(int width,int height)479   Status setMaxSize(int width, int height) noexcept
480   {
481     return static_cast<Status>(puglSetMaxSize(cobj(), width, height));
482   }
483 
484   /// @copydoc puglSetAspectRatio
setAspectRatio(int minX,int minY,int maxX,int maxY)485   Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept
486   {
487     return static_cast<Status>(
488       puglSetAspectRatio(cobj(), minX, minY, maxX, maxY));
489   }
490 
491   /**
492      @}
493      @name Windows
494      Methods for working with top-level windows.
495      @{
496   */
497 
498   /// @copydoc puglSetWindowTitle
setWindowTitle(const char * title)499   Status setWindowTitle(const char* title) noexcept
500   {
501     return static_cast<Status>(puglSetWindowTitle(cobj(), title));
502   }
503 
504   /// @copydoc puglSetParentWindow
setParentWindow(NativeView parent)505   Status setParentWindow(NativeView parent) noexcept
506   {
507     return static_cast<Status>(puglSetParentWindow(cobj(), parent));
508   }
509 
510   /// @copydoc puglSetTransientFor
setTransientFor(NativeView parent)511   Status setTransientFor(NativeView parent) noexcept
512   {
513     return static_cast<Status>(puglSetTransientFor(cobj(), parent));
514   }
515 
516   /// @copydoc puglRealize
realize()517   Status realize() noexcept { return static_cast<Status>(puglRealize(cobj())); }
518 
519   /// @copydoc puglShow
show()520   Status show() noexcept { return static_cast<Status>(puglShow(cobj())); }
521 
522   /// @copydoc puglHide
hide()523   Status hide() noexcept { return static_cast<Status>(puglHide(cobj())); }
524 
525   /// @copydoc puglGetVisible
visible() const526   bool visible() const noexcept { return puglGetVisible(cobj()); }
527 
528   /// @copydoc puglGetNativeWindow
nativeWindow()529   NativeView nativeWindow() noexcept { return puglGetNativeWindow(cobj()); }
530 
531   /**
532      @}
533      @name Graphics
534      Methods for working with the graphics context and scheduling
535      redisplays.
536      @{
537   */
538 
539   /// @copydoc puglGetContext
context()540   void* context() noexcept { return puglGetContext(cobj()); }
541 
542   /// @copydoc puglPostRedisplay
postRedisplay()543   Status postRedisplay() noexcept
544   {
545     return static_cast<Status>(puglPostRedisplay(cobj()));
546   }
547 
548   /// @copydoc puglPostRedisplayRect
postRedisplayRect(const Rect rect)549   Status postRedisplayRect(const Rect rect) noexcept
550   {
551     return static_cast<Status>(puglPostRedisplayRect(cobj(), rect));
552   }
553 
554   /**
555      @}
556      @name Interaction
557      Methods for interacting with the user and window system.
558      @{
559   */
560 
561   /// @copydoc puglGrabFocus
grabFocus()562   Status grabFocus() noexcept
563   {
564     return static_cast<Status>(puglGrabFocus(cobj()));
565   }
566 
567   /// @copydoc puglHasFocus
hasFocus() const568   bool hasFocus() const noexcept { return puglHasFocus(cobj()); }
569 
570   /// @copydoc puglSetCursor
setCursor(const Cursor cursor)571   Status setCursor(const Cursor cursor) noexcept
572   {
573     return static_cast<Status>(
574       puglSetCursor(cobj(), static_cast<PuglCursor>(cursor)));
575   }
576 
577   /// @copydoc puglRequestAttention
requestAttention()578   Status requestAttention() noexcept
579   {
580     return static_cast<Status>(puglRequestAttention(cobj()));
581   }
582 
583   /**
584      Activate a repeating timer event.
585 
586      This starts a timer which will send a timer event to `view` every
587      `timeout` seconds.  This can be used to perform some action in a view at a
588      regular interval with relatively low frequency.  Note that the frequency
589      of timer events may be limited by how often update() is called.
590 
591      If the given timer already exists, it is replaced.
592 
593      @param id The identifier for this timer.  This is an application-specific
594      ID that should be a low number, typically the value of a constant or `enum`
595      that starts from 0.  There is a platform-specific limit to the number of
596      supported timers, and overhead associated with each, so applications should
597      create only a few timers and perform several tasks in one if necessary.
598 
599      @param timeout The period, in seconds, of this timer.  This is not
600      guaranteed to have a resolution better than 10ms (the maximum timer
601      resolution on Windows) and may be rounded up if it is too short.  On X11
602      and MacOS, a resolution of about 1ms can usually be relied on.
603 
604      @return #PUGL_FAILURE if timers are not supported by the system,
605      #PUGL_UNKNOWN_ERROR if setting the timer failed.
606   */
startTimer(const uintptr_t id,const double timeout)607   Status startTimer(const uintptr_t id, const double timeout) noexcept
608   {
609     return static_cast<Status>(puglStartTimer(cobj(), id, timeout));
610   }
611 
612   /**
613      Stop an active timer.
614 
615      @param id The ID previously passed to startTimer().
616 
617      @return #PUGL_FAILURE if timers are not supported by this system,
618      #PUGL_UNKNOWN_ERROR if stopping the timer failed.
619   */
stopTimer(const uintptr_t id)620   Status stopTimer(const uintptr_t id) noexcept
621   {
622     return static_cast<Status>(puglStopTimer(cobj(), id));
623   }
624 
625   /**
626      @}
627   */
628 
cobj()629   PuglView*       cobj() noexcept { return Wrapper::cobj(); }
cobj() const630   const PuglView* cobj() const noexcept { return Wrapper::cobj(); }
631 
632 private:
633   template<class Target>
dispatch(Target & target,const PuglEvent * event)634   static Status dispatch(Target& target, const PuglEvent* event)
635   {
636     switch (event->type) {
637     case PUGL_NOTHING:
638       return Status::success;
639     case PUGL_CREATE:
640       return target.onEvent(static_cast<const CreateEvent&>(event->any));
641     case PUGL_DESTROY:
642       return target.onEvent(static_cast<const DestroyEvent&>(event->any));
643     case PUGL_CONFIGURE:
644       return target.onEvent(
645         static_cast<const ConfigureEvent&>(event->configure));
646     case PUGL_MAP:
647       return target.onEvent(static_cast<const MapEvent&>(event->any));
648     case PUGL_UNMAP:
649       return target.onEvent(static_cast<const UnmapEvent&>(event->any));
650     case PUGL_UPDATE:
651       return target.onEvent(static_cast<const UpdateEvent&>(event->any));
652     case PUGL_EXPOSE:
653       return target.onEvent(static_cast<const ExposeEvent&>(event->expose));
654     case PUGL_CLOSE:
655       return target.onEvent(static_cast<const CloseEvent&>(event->any));
656     case PUGL_FOCUS_IN:
657       return target.onEvent(static_cast<const FocusInEvent&>(event->focus));
658     case PUGL_FOCUS_OUT:
659       return target.onEvent(static_cast<const FocusOutEvent&>(event->focus));
660     case PUGL_KEY_PRESS:
661       return target.onEvent(static_cast<const KeyPressEvent&>(event->key));
662     case PUGL_KEY_RELEASE:
663       return target.onEvent(static_cast<const KeyReleaseEvent&>(event->key));
664     case PUGL_TEXT:
665       return target.onEvent(static_cast<const TextEvent&>(event->text));
666     case PUGL_POINTER_IN:
667       return target.onEvent(
668         static_cast<const PointerInEvent&>(event->crossing));
669     case PUGL_POINTER_OUT:
670       return target.onEvent(
671         static_cast<const PointerOutEvent&>(event->crossing));
672     case PUGL_BUTTON_PRESS:
673       return target.onEvent(
674         static_cast<const ButtonPressEvent&>(event->button));
675     case PUGL_BUTTON_RELEASE:
676       return target.onEvent(
677         static_cast<const ButtonReleaseEvent&>(event->button));
678     case PUGL_MOTION:
679       return target.onEvent(static_cast<const MotionEvent&>(event->motion));
680     case PUGL_SCROLL:
681       return target.onEvent(static_cast<const ScrollEvent&>(event->scroll));
682     case PUGL_CLIENT:
683       return target.onEvent(static_cast<const ClientEvent&>(event->client));
684     case PUGL_TIMER:
685       return target.onEvent(static_cast<const TimerEvent&>(event->timer));
686     case PUGL_LOOP_ENTER:
687       return target.onEvent(static_cast<const LoopEnterEvent&>(event->any));
688     case PUGL_LOOP_LEAVE:
689       return target.onEvent(static_cast<const LoopLeaveEvent&>(event->any));
690     }
691 
692     return Status::failure;
693   }
694 
695   template<class Target>
eventFunc(PuglView * view,const PuglEvent * event)696   static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept
697   {
698     auto* target = static_cast<Target*>(puglGetHandle(view));
699 
700 #ifdef __cpp_exceptions
701     try {
702       return static_cast<PuglStatus>(dispatch(*target, event));
703     } catch (...) {
704       return PUGL_UNKNOWN_ERROR;
705     }
706 #else
707     return static_cast<PuglStatus>(pugl::dispatch(*target, event));
708 #endif
709   }
710 
711   World& _world;
712 };
713 
714 /**
715    @}
716    @}
717 */
718 
719 } // namespace pugl
720 
721 #endif // PUGL_PUGL_HPP
722