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