Pugl

Pugl is an API for writing portable and embeddable GUIs. Pugl is not a toolkit or framework, but a minimal portability layer that sets up a drawing context and delivers events.

Compared to other libraries, Pugl is particularly suitable for use in plugins or other loadable modules. There is no implicit context or static data in the library, so it may be statically linked and used multiple times in the same process.

Pugl has a modular design that separates the core library from graphics backends. The core library is graphics agnostic, it implements platform support and depends only on standard system libraries. MacOS, Windows, and X11 are currently supported as platforms.

Graphics backends are separate so that applications only depend on the API that they use. Pugl includes graphics backends for Cairo, OpenGL, and Vulkan. It is also possible to use some other graphics API by implementing a custom backend, or simply accessing the native platform handle for a window.

Usage

Building Against Pugl

When Pugl is installed, pkg-config packages are provided that link with the core platform library and desired backend:

  • pugl-cairo-0

  • pugl-gl-0

  • pugl-vulkan-0

Depending on one of these packages should be all that is necessary to use Pugl, but details on the individual libraries that are installed are available in the README.

If you are instead including the source directly in your project, the structure is quite simple and hopefully obvious. It is only necessary to copy the platform and backend implementations that you need.

Overview

Pugl is a C library, but the bindings documented here provide a more idiomatic and type-safe API for C++. If you would rather use C, refer instead to the C API documentation.

The C++ bindings are very lightweight and do not require virtual functions, RTTI, exceptions, or linking to the C++ standard library. They are provided by the package puglxx-0 which must be used in addition to the desired platform+backend package above.

The core API (excluding backend-specific components) is declared in pugl.hpp:

#include <pugl/pugl.hpp>

The API revolves around two main objects: the world and the view. An application creates a world to manage top-level state, then creates one or more views to display.

Creating a World

The world is the top-level object which represents an instance of Pugl. It handles the connection to the window system, and manages views and the event loop.

An application typically has a single world, which is constructed once on startup and used to drive the main event loop.

Construction

A world must be created before any views, and it must outlive all of its views. The world constructor requires an argument to specify the application type:

pugl::World world{pugl::WorldType::program};

For a plugin, specify WorldType::module instead. In some cases, it is necessary to pass additional flags. For example, Vulkan requires thread support:

pugl::World world{pugl::WorldType::program, pugl::WorldFlag::threads};

It is a good idea to set a class name for your project with World::setClassName(). This allows the window system to distinguish different applications and, for example, users to set up rules to manage their windows nicely:

world.setClassName("MyAwesomeProject");

Creating a View

A view is a drawable region that receives events. You may think of it as a window, though it may be embedded and not represent a top-level system window. 1

Pugl communicates with views by dispatching events. For flexibility, the event handler can be a different object than the view. This allows using View along with a separate event handler class. Alternatively, a view class can inherit from View and set itself as its event handler, for a more object-oriented style.

This documentation will use the latter approach, so we will define a class for our view that contains everything needed:

class MyView : public pugl::View
{
public:
  explicit MyView(pugl::World& world)
      : pugl::View{world}
  {
    setEventHandler(*this);
  }

  pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept;
  pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept;

  // With other handlers here as needed...

  // Fallback handler for all other events
  template<PuglEventType t, class Base>
  pugl::Status onEvent(const pugl::Event<t, Base>&) noexcept
  {
       return pugl::Status::success;
  }

private:
  // Some data...
};

Pugl will call an onEvent method of the event handler (the view in this case) for every event.

Note that Pugl uses a static dispatching mechanism rather than virtual functions to minimize overhead. It is therefore necessary for the final class to define a handler for every event type. A terse way to do this without writing every implementation is to define a fallback handler as a template, as in the example above. Alternatively, you can define an explicit handler for each event that simply returns Status::success. This way, it will be a compile error if any event is not explicitly handled.

Configuring the Frame

Before display, the necessary frame and window attributes should be set. These allow the window system (or plugin host) to arrange the view properly.

Derived classes can configure themselves during construction, but we assume here that configuration is being done outside the view. For example:

const double defaultWidth = 1920.0;
const double defaultHeight = 1080.0;

view.setWindowTitle("My Window");
view.setDefaultSize(defaultWidth, defaultHeight);
view.setMinSize(defaultWidth / 4.0, defaultHeight / 4.0);
view.setAspectRatio(1, 1, 16, 9);

There are also several hints for basic attributes that can be set:

view.setHint(pugl::ViewHint::resizable, true);
view.setHint(pugl::ViewHint::ignoreKeyRepeat, true);

Embedding

To embed the view in another window, you will need to somehow get the native view handle for the parent, then set it with View::setParentWindow(). If the parent is a Pugl view, the native handle can be accessed with View::nativeWindow(). For example:

view.setParentWindow(view, parent.getNativeWindow());

Setting a Backend

Before being realized, the view must have a backend set with View::setBackend().

The backend manages the graphics API that will be used for drawing. Pugl includes backends and supporting API for Cairo, OpenGL, and Vulkan.

Using Cairo

Cairo-specific API is declared in the cairo.hpp header:

#include <pugl/cairo.hpp>

The Cairo backend is provided by cairoBackend():

view.setBackend(pugl::cairoBackend());

No additional configuration is required for Cairo. To draw when handling an expose event, the Cairo context can be accessed with View::context():

cairo_t* cr = static_cast<cairo_t*>(view.context());
Using OpenGL

OpenGL-specific API is declared in the gl.hpp header:

#include <pugl/gl.hpp>

The OpenGL backend is provided by glBackend():

view.setBackend(pugl::glBackend());

Some hints must also be set so that the context can be set up correctly. For example, to use OpenGL 3.3 Core Profile:

view.setHint(pugl::ViewHint::useCompatProfile, false);
view.setHint(pugl::ViewHint::contextVersionMajor, 3);
view.setHint(pugl::ViewHint::contextVersionMinor, 3);

If you need to perform some setup using the OpenGL API, there are two ways to do so.

The OpenGL context is active when CreateEvent and DestroyEvent events are dispatched, so things like creating and destroying shaders and textures can be done then.

Alternatively, if it is cumbersome to set up and tear down OpenGL in the event handler, enterContext() and leaveContext() can be used to manually activate the OpenGL context during application setup. Note, however, that unlike many other APIs, these functions must not be used for drawing. It is only valid to use the OpenGL API for configuration in a manually entered context, rendering will not work. For example:

pugl::enterContext(view);
myApp.setupOpenGL();
pugl::leaveContext(view);

while (!myApp.quit()) {
  world.update(0.0);
}

pugl::enterContext(view);
myApp.teardownOpenGL();
pugl::leaveContext(view);
Using Vulkan

Vulkan-specific API is declared in the vulkan.hpp header. This header includes Vulkan headers, so if you are dynamically loading Vulkan at runtime, you should define VK_NO_PROTOTYPES before including it.

#define VK_NO_PROTOTYPES

#include <pugl/vulkan.hpp>

The Vulkan backend is provided by vulkanBackend():

view.setBackend(pugl::vulkanBackend());

Unlike OpenGL, almost all Vulkan configuration is done using the Vulkan API directly. Pugl only provides a portable mechanism to load the Vulkan library and get the functions used to load the rest of the Vulkan API.

Loading Vulkan

For maximum compatibility, it is best to not link to Vulkan at compile-time, but instead load the Vulkan API at run-time. To do so, first create a VulkanLoader:

pugl::VulkanLoader loader{world};

The loader manages the dynamically loaded Vulkan library, so it must be kept alive for as long as the application is using Vulkan. You can get the function used to load Vulkan functions with VulkanLoader::getInstanceProcAddrFunc():

auto vkGetInstanceProcAddr = loader.getInstanceProcAddrFunc();

It is best to use this function to load everything at run time, rather than link to the Vulkan library at run time. You can, for example, pass this to get the vkCreateInstance function using this, then use that to create your Vulkan instance. In practice, you will want to use some loader or wrapper API since there are many Vulkan functions.

It is not necessary to use VulkanLoader, you can, for example, use the DynamicLoader from vulkan.hpp in the Vulkan SDK instead.

The details of using Vulkan are far beyond the scope of this documentation, but Pugl provides a portable function, createSurface(), to get the Vulkan surface for a view. Assuming you have somehow created your VkInstance, you can get the surface for a view using createSurface():

VkSurfaceKHR* surface = nullptr;
puglCreateSurface(loader.getDeviceProcAddrFunc(),
                  view,
                  vulkanInstance,
                  nullptr,
                  &surface);

Pugl does not provide API that uses vulkan.hpp to avoid the onerous dependency, but if you are using it with exceptions and unique handles, it is straightforward to wrap the surface handle yourself.

Showing the View

Once the view is configured, it can be “realized” with View::realize(). This creates a “real” system view, for example:

pugl::Status status = view.realize();
if (status != pugl::Status::success) {
  std::cerr << "Error realizing view: " << pugl::strerror(status) << "\n";
}

Note that realizing a view can fail for many reasons, so the return code should always be checked. This is generally the case for any function that interacts with the window system. Most functions also return a Status, but these checks are omitted for brevity in the rest of this documentation.

A realized view is not initially visible, but can be shown with View::show():

view.show();

To create an initially visible view, it is also possible to simply call View::show() right away. The view will be automatically realized if necessary.

Footnotes

1

MacOS has a strong distinction between views, which may be nested, and windows, which may not. On Windows and X11, everything is a nestable window, but top-level windows are configured differently.

Handling Events

Events are sent to a view when it has received user input, must be drawn, or in other situations that may need to be handled such as resizing.

Events are sent to the onEvent method that takes the matching event type. The application must handle at least ConfigureEvent and ExposeEvent to draw anything, but there are many other event types.

For example, basic event handling for our above class might look something like:

pugl::Status
MyView::onEvent(const pugl::ConfigureEvent& event) noexcept
{
  return resize(event.width, event.height);
}

pugl::Status
MyView::onEvent(const pugl::ExposeEvent& event) noexcept
{
  return drawMyAwesomeInterface(event.x, event.y, event.width, event.height);
}

Drawing

Note that Pugl uses a different drawing model than many libraries, particularly those designed for game-style main loops like SDL and GLFW.

In that style of code, drawing is performed imperatively in the main loop, but with Pugl, the application must draw only while handling an expose event. This is because Pugl supports event-driven applications that only draw the damaged region when necessary, and handles exposure internally to provide optimized and consistent behavior across platforms.

Driving the Event Loop

Pugl does not contain any threads or other event loop “magic”. For flexibility, the event loop is driven manually by repeatedly calling World::update(), which processes events from the window system and dispatches them to views when necessary.

The exact use of World::update() depends on the application. Plugins typically call it with a timeout of 0 in a callback driven by the host. This avoids blocking the main loop, since other plugins and the host itself need to run as well.

A program can use whatever timeout is appropriate: event-driven applications may wait forever by using a timeout of -1, while those that draw continuously may use a significant fraction of the frame period (with enough time left over to render).

Redrawing

Occasional redrawing can be requested by calling View::postRedisplay() or View::postRedisplayRect(). After these are called, a ExposeEvent will be dispatched on the next call to World::update(). Note, however, that this will not wake up a blocked World::update() call on MacOS (which does not handle drawing via events).

For continuous redrawing, call View::postRedisplay() while handling a UpdateEvent. This event is sent just before views are redrawn, so it can be used as a hook to expand the update region right before the view is exposed. Anything else that needs to be done every frame can be handled similarly.

Pugl C API

Pugl C API.

Events

All updates to the view happen via events, which are dispatched to the view’s event function.

Most events map directly to one from the underlying window system, but some are constructed by Pugl itself so there is not necessarily a direct correspondence.

struct PuglEventAny

Common header for all event structs.

PuglEventType type

Event type.

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

struct PuglEventConfigure

View resize or move event.

A configure event is sent whenever the view is resized or moved. When a configure event is received, the graphics context is active but not set up for drawing. For example, it is valid to adjust the OpenGL viewport or otherwise configure the context, but not to draw anything.

PuglEventType type

PuglEventType::PUGL_CONFIGURE

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double x

New parent-relative X coordinate.

double y

New parent-relative Y coordinate.

double width

New width.

double height

New height.

struct PuglEventExpose

Expose event for when a region must be redrawn.

When an expose event is received, the graphics context is active, and the view must draw the entire specified region. The contents of the region are undefined, there is no preservation of anything drawn previously.

PuglEventType type

PuglEventType::PUGL_EXPOSE

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double x

View-relative X coordinate.

double y

View-relative Y coordinate.

double width

Width of exposed region.

double height

Height of exposed region.

struct PuglEventFocus

Keyboard focus event.

This event is sent whenever the view gains or loses the keyboard focus. The view with the keyboard focus will receive any key press or release events.

PuglEventType type

PuglEventType::PUGL_FOCUS_IN or PuglEventType::PUGL_FOCUS_OUT

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

PuglCrossingMode mode

Reason for focus change.

struct PuglEventKey

Key press or release event.

This event represents low-level key presses and releases. This can be used for “direct” keyboard handing like key bindings, but must not be interpreted as text input.

Keys are represented portably as Unicode code points, using the “natural” code point for the key where possible (see PuglKey for details). The key field is the code for the pressed key, without any modifiers applied. For example, a press or release of the ‘A’ key will have key 97 (‘a’) regardless of whether shift or control are being held.

Alternatively, the raw keycode can be used to work directly with physical keys, but note that this value is not portable and differs between platforms and hardware.

PuglEventType type

PuglEventType::PUGL_KEY_PRESS or PuglEventType::PUGL_KEY_RELEASE

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double time

Time in seconds.

double x

View-relative X coordinate.

double y

View-relative Y coordinate.

double xRoot

Root-relative X coordinate.

double yRoot

Root-relative Y coordinate.

PuglMods state

Bitwise OR of PuglMod flags.

uint32_t keycode

Raw key code.

uint32_t key

Unshifted Unicode character code, or 0.

struct PuglEventText

Character input event.

This event represents text input, usually as the result of a key press. The text is given both as a Unicode character code and a UTF-8 string.

Note that this event is generated by the platform’s input system, so there is not necessarily a direct correspondence between text events and physical key presses. For example, with some input methods a sequence of several key presses will generate a single character.

PuglEventType type

PuglEventType::PUGL_TEXT

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double time

Time in seconds.

double x

View-relative X coordinate.

double y

View-relative Y coordinate.

double xRoot

Root-relative X coordinate.

double yRoot

Root-relative Y coordinate.

PuglMods state

Bitwise OR of PuglMod flags.

uint32_t keycode

Raw key code.

uint32_t character

Unicode character code.

char string

UTF-8 string.

struct PuglEventCrossing

Pointer enter or leave event.

This event is sent when the pointer enters or leaves the view. This can happen for several reasons (not just the user dragging the pointer over the window edge), as described by the mode field.

PuglEventType type

PuglEventType::PUGL_POINTER_IN or PuglEventType::PUGL_POINTER_OUT

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double time

Time in seconds.

double x

View-relative X coordinate.

double y

View-relative Y coordinate.

double xRoot

Root-relative X coordinate.

double yRoot

Root-relative Y coordinate.

PuglMods state

Bitwise OR of PuglMod flags.

PuglCrossingMode mode

Reason for crossing.

struct PuglEventButton

Button press or release event.

PuglEventType type

PuglEventType::PUGL_BUTTON_PRESS or PuglEventType::PUGL_BUTTON_RELEASE

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double time

Time in seconds.

double x

View-relative X coordinate.

double y

View-relative Y coordinate.

double xRoot

Root-relative X coordinate.

double yRoot

Root-relative Y coordinate.

PuglMods state

Bitwise OR of PuglMod flags.

uint32_t button

Button number starting from 1.

struct PuglEventMotion

Pointer motion event.

PuglEventType type

PuglEventType::PUGL_MOTION

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double time

Time in seconds.

double x

View-relative X coordinate.

double y

View-relative Y coordinate.

double xRoot

Root-relative X coordinate.

double yRoot

Root-relative Y coordinate.

PuglMods state

Bitwise OR of PuglMod flags.

struct PuglEventScroll

Scroll event.

The scroll distance is expressed in “lines”, an arbitrary unit that corresponds to a single tick of a detented mouse wheel. For example, dy = 1.0 scrolls 1 line up. Some systems and devices support finer resolution and/or higher values for fast scrolls, so programs should handle any value gracefully.

PuglEventType type

PuglEventType::PUGL_SCROLL

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

double time

Time in seconds.

double x

View-relative X coordinate.

double y

View-relative Y coordinate.

double xRoot

Root-relative X coordinate.

double yRoot

Root-relative Y coordinate.

PuglMods state

Bitwise OR of PuglMod flags.

PuglScrollDirection direction

Scroll direction.

double dx

Scroll X distance in lines.

double dy

Scroll Y distance in lines.

struct PuglEventClient

Custom client message event.

This can be used to send a custom message to a view, which is delivered via the window system and processed in the event loop as usual. Among other things, this makes it possible to wake up the event loop for any reason.

PuglEventType type

PuglEventType::PUGL_CLIENT

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

uintptr_t data1

Client-specific data.

uintptr_t data2

Client-specific data.

struct PuglEventTimer

Timer event.

This event is sent at the regular interval specified in the call to puglStartTimer() that activated it.

The id is the application-specific ID given to puglStartTimer() which distinguishes this timer from others. It should always be checked in the event handler, even in applications that register only one timer.

PuglEventType type

PuglEventType::PUGL_TIMER

PuglEventFlags flags

Bitwise OR of PuglEventFlag values.

uintptr_t id

Timer ID.

union PuglEvent

View event.

This is a union of all event types. The type must be checked to determine which fields are safe to access. A pointer to PuglEvent can either be cast to the appropriate type, or the union members used.

The graphics system may only be accessed when handling certain events. The graphics context is active for PuglEventType::PUGL_CREATE, PuglEventType::PUGL_DESTROY, PuglEventType::PUGL_CONFIGURE, and PuglEventType::PUGL_EXPOSE, but only enabled for drawing for PuglEventType::PUGL_EXPOSE.

PuglEventAny any

Valid for all event types.

PuglEventType type

Event type.

PuglEventButton button

PuglEventType::PUGL_BUTTON_PRESS, PuglEventType::PUGL_BUTTON_RELEASE

PuglEventConfigure configure

PuglEventType::PUGL_CONFIGURE

PuglEventExpose expose

PuglEventType::PUGL_EXPOSE

PuglEventKey key

PuglEventType::PUGL_KEY_PRESS, PuglEventType::PUGL_KEY_RELEASE

PuglEventText text

PuglEventType::PUGL_TEXT

PuglEventCrossing crossing

PuglEventType::PUGL_POINTER_IN, PuglEventType::PUGL_POINTER_OUT

PuglEventMotion motion

PuglEventType::PUGL_MOTION

PuglEventScroll scroll

PuglEventType::PUGL_SCROLL

PuglEventFocus focus

PuglEventType::PUGL_FOCUS_IN, PuglEventType::PUGL_FOCUS_OUT

PuglEventClient client

PuglEventType::PUGL_CLIENT

PuglEventTimer timer

PuglEventType::PUGL_TIMER

enum PuglMod

Keyboard modifier flags.

enumerator PUGL_MOD_SHIFT

Shift key.

enumerator PUGL_MOD_CTRL

Control key.

enumerator PUGL_MOD_ALT

Alt/Option key.

enumerator PUGL_MOD_SUPER

Mod4/Command/Windows key.

enum PuglKey

Keyboard key codepoints.

All keys are identified by a Unicode code point in PuglEventKey::key. This enumeration defines constants for special keys that do not have a standard code point, and some convenience constants for control characters. Note that all keys are handled in the same way, this enumeration is just for convenience when writing hard-coded key bindings.

Keys that do not have a standard code point use values in the Private Use Area in the Basic Multilingual Plane (U+E000 to U+F8FF). Applications must take care to not interpret these values beyond key detection, the mapping used here is arbitrary and specific to Pugl.

enumerator PUGL_KEY_BACKSPACE
enumerator PUGL_KEY_ESCAPE
enumerator PUGL_KEY_DELETE
enumerator PUGL_KEY_F1
enumerator PUGL_KEY_F2
enumerator PUGL_KEY_F3
enumerator PUGL_KEY_F4
enumerator PUGL_KEY_F5
enumerator PUGL_KEY_F6
enumerator PUGL_KEY_F7
enumerator PUGL_KEY_F8
enumerator PUGL_KEY_F9
enumerator PUGL_KEY_F10
enumerator PUGL_KEY_F11
enumerator PUGL_KEY_F12
enumerator PUGL_KEY_LEFT
enumerator PUGL_KEY_UP
enumerator PUGL_KEY_RIGHT
enumerator PUGL_KEY_DOWN
enumerator PUGL_KEY_PAGE_UP
enumerator PUGL_KEY_PAGE_DOWN
enumerator PUGL_KEY_HOME
enumerator PUGL_KEY_END
enumerator PUGL_KEY_INSERT
enumerator PUGL_KEY_SHIFT
enumerator PUGL_KEY_SHIFT_L
enumerator PUGL_KEY_SHIFT_R
enumerator PUGL_KEY_CTRL
enumerator PUGL_KEY_CTRL_L
enumerator PUGL_KEY_CTRL_R
enumerator PUGL_KEY_ALT
enumerator PUGL_KEY_ALT_L
enumerator PUGL_KEY_ALT_R
enumerator PUGL_KEY_SUPER
enumerator PUGL_KEY_SUPER_L
enumerator PUGL_KEY_SUPER_R
enumerator PUGL_KEY_MENU
enumerator PUGL_KEY_CAPS_LOCK
enumerator PUGL_KEY_SCROLL_LOCK
enumerator PUGL_KEY_NUM_LOCK
enumerator PUGL_KEY_PRINT_SCREEN
enumerator PUGL_KEY_PAUSE
enum PuglEventType

The type of a PuglEvent.

enumerator PUGL_NOTHING

No event.

enumerator PUGL_CREATE

View created, a PuglEventCreate.

enumerator PUGL_DESTROY

View destroyed, a PuglEventDestroy.

enumerator PUGL_CONFIGURE

View moved/resized, a PuglEventConfigure.

enumerator PUGL_MAP

View made visible, a PuglEventMap.

enumerator PUGL_UNMAP

View made invisible, a PuglEventUnmap.

enumerator PUGL_UPDATE

View ready to draw, a PuglEventUpdate.

enumerator PUGL_EXPOSE

View must be drawn, a PuglEventExpose.

enumerator PUGL_CLOSE

View will be closed, a PuglEventClose.

enumerator PUGL_FOCUS_IN

Keyboard focus entered view, a PuglEventFocus.

enumerator PUGL_FOCUS_OUT

Keyboard focus left view, a PuglEventFocus.

enumerator PUGL_KEY_PRESS

Key pressed, a PuglEventKey.

enumerator PUGL_KEY_RELEASE

Key released, a PuglEventKey.

enumerator PUGL_TEXT

Character entered, a PuglEventText.

enumerator PUGL_POINTER_IN

Pointer entered view, a PuglEventCrossing.

enumerator PUGL_POINTER_OUT

Pointer left view, a PuglEventCrossing.

enumerator PUGL_BUTTON_PRESS

Mouse button pressed, a PuglEventButton.

enumerator PUGL_BUTTON_RELEASE

Mouse button released, a PuglEventButton.

enumerator PUGL_MOTION

Pointer moved, a PuglEventMotion.

enumerator PUGL_SCROLL

Scrolled, a PuglEventScroll.

enumerator PUGL_CLIENT

Custom client message, a PuglEventClient.

enumerator PUGL_TIMER

Timer triggered, a PuglEventTimer.

enumerator PUGL_LOOP_ENTER

Recursive loop entered, a PuglEventLoopEnter.

enumerator PUGL_LOOP_LEAVE

Recursive loop left, a PuglEventLoopLeave.

enum PuglEventFlag

Common flags for all event types.

enumerator PUGL_IS_SEND_EVENT

Event is synthetic.

enumerator PUGL_IS_HINT

Event is a hint (not direct user input)

enum PuglCrossingMode

Reason for a PuglEventCrossing.

enumerator PUGL_CROSSING_NORMAL

Crossing due to pointer motion.

enumerator PUGL_CROSSING_GRAB

Crossing due to a grab.

enumerator PUGL_CROSSING_UNGRAB

Crossing due to a grab release.

enum PuglScrollDirection

Scroll direction.

Describes the direction of a PuglEventScroll along with whether the scroll is a “smooth” scroll. The discrete directions are for devices like mouse wheels with constrained axes, while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads.

enumerator PUGL_SCROLL_UP

Scroll up.

enumerator PUGL_SCROLL_DOWN

Scroll down.

enumerator PUGL_SCROLL_LEFT

Scroll left.

enumerator PUGL_SCROLL_RIGHT

Scroll right.

enumerator PUGL_SCROLL_SMOOTH

Smooth scroll in any direction.

typedef uint32_t PuglMods

Bitwise OR of PuglMod values.

typedef uint32_t PuglEventFlags

Bitwise OR of PuglEventFlag values.

typedef PuglEventAny PuglEventCreate

View create event.

This event is sent when a view is realized before it is first displayed, with the graphics context entered. This is typically used for setting up the graphics system, for example by loading OpenGL extensions.

This event type has no extra fields.

typedef PuglEventAny PuglEventDestroy

View destroy event.

This event is the counterpart to PuglEventCreate, and it is sent when the view is being destroyed. This is typically used for tearing down the graphics system, or otherwise freeing any resources allocated when the create event was handled.

This is the last event sent to any view, and immediately after it is processed, the view is destroyed and may no longer be used.

This event type has no extra fields.

typedef PuglEventAny PuglEventMap

View show event.

This event is sent when a view is mapped to the screen and made visible.

This event type has no extra fields.

typedef PuglEventAny PuglEventUnmap

View hide event.

This event is sent when a view is unmapped from the screen and made invisible.

This event type has no extra fields.

typedef PuglEventAny PuglEventUpdate

View update event.

This event is sent to every view near the end of a main loop iteration when any pending exposures are about to be redrawn. It is typically used to mark regions to expose with puglPostRedisplay() or puglPostRedisplayRect(). For example, to continuously animate, a view calls puglPostRedisplay() when an update event is received, and it will then shortly receive an expose event.

typedef PuglEventAny PuglEventClose

View close event.

This event is sent when the view is to be closed, for example when the user clicks the close button.

This event type has no extra fields.

typedef PuglEventAny PuglEventLoopEnter

Recursive loop enter event.

This event is sent when the window system enters a recursive loop. The main loop will be stalled and no expose events will be received while in the recursive loop. To give the application full control, Pugl does not do any special handling of this situation, but this event can be used to install a timer to perform continuous actions (such as drawing) on platforms that do this.

  • MacOS: A recursive loop is entered while the window is being live resized.

  • Windows: A recursive loop is entered while the window is being live resized or the menu is shown.

  • X11: A recursive loop is never entered and the event loop runs as usual while the view is being resized.

This event type has no extra fields.

typedef PuglEventAny PuglEventLoopLeave

Recursive loop leave event.

This event is sent after a loop enter event when the recursive loop is finished and normal iteration will continue.

This event type has no extra fields.

Status

Most functions return a status code which can be used to check for errors.

enum PuglStatus

Return status code.

enumerator PUGL_SUCCESS

Success.

enumerator PUGL_FAILURE

Non-fatal failure.

enumerator PUGL_UNKNOWN_ERROR

Unknown system error.

enumerator PUGL_BAD_BACKEND

Invalid or missing backend.

enumerator PUGL_BAD_CONFIGURATION

Invalid view configuration.

enumerator PUGL_BAD_PARAMETER

Invalid parameter.

enumerator PUGL_BACKEND_FAILED

Backend initialization failed.

enumerator PUGL_REGISTRATION_FAILED

Class registration failed.

enumerator PUGL_REALIZE_FAILED

System view realization failed.

enumerator PUGL_SET_FORMAT_FAILED

Failed to set pixel format.

enumerator PUGL_CREATE_CONTEXT_FAILED

Failed to create drawing context.

enumerator PUGL_UNSUPPORTED_TYPE

Unsupported data type.

const char *puglStrerror(PuglStatus status)

Return a string describing a status code.

World

The top-level context of a Pugl application or plugin.

The world contains all library-wide state. There is no static data in Pugl, so it is safe to use multiple worlds in a single process. This is to facilitate plugins or other situations where it is not possible to share a world, but a single world should be shared for all views where possible.

enum PuglWorldType

The type of a World.

enumerator PUGL_PROGRAM

Top-level application.

enumerator PUGL_MODULE

Plugin or module within a larger application.

enum PuglWorldFlag

World flags.

enumerator PUGL_WORLD_THREADS

Set up support for threads if necessary. - X11: Calls XInitThreads() which is required for some drivers.

typedef struct PuglWorldImpl PuglWorld

The “world” of application state.

The world represents everything that is not associated with a particular view. Several worlds can be created in a single process, but code using different worlds must be isolated so they are never mixed. Views are strongly associated with the world they were created in.

typedef void *PuglWorldHandle

Handle for the world’s opaque user data.

typedef uint32_t PuglWorldFlags

Bitwise OR of PuglWorldFlag values.

PuglWorld *puglNewWorld(PuglWorldType type, PuglWorldFlags flags)

Create a new world.

Parameters
  • type – The type, which dictates what this world is responsible for.

  • flags – Flags to control world features.

Returns

A new world, which must be later freed with puglFreeWorld().

void puglFreeWorld(PuglWorld *world)

Free a world allocated with puglNewWorld()

void puglSetWorldHandle(PuglWorld *world, PuglWorldHandle handle)

Set the user data for the world.

This is usually a pointer to a struct that contains all the state which must be accessed by several views.

The handle is opaque to Pugl and is not interpreted in any way.

PuglWorldHandle puglGetWorldHandle(PuglWorld *world)

Get the user data for the world.

void *puglGetNativeWorld(PuglWorld *world)

Return a pointer to the native handle of the world.

X11: Returns a pointer to the Display.

MacOS: Returns null.

Windows: Returns the HMODULE of the calling process.

PuglStatus puglSetClassName(PuglWorld *world, const char *name)

Set the class name of the application.

This is a stable identifier for the application, used as the window class/instance name on X11 and Windows. It is not displayed to the user, but can be used in scripts and by window managers, so it should be the same for every instance of the application, but different from other applications.

double puglGetTime(const PuglWorld *world)

Return the time in seconds.

This is a monotonically increasing clock with high resolution. The returned time is only useful to compare against other times returned by this function, its absolute value has no meaning.

PuglStatus puglUpdate(PuglWorld *world, double timeout)

Update by processing events from the window system.

This function is a single iteration of the main loop, and should be called repeatedly to update all views.

If timeout is zero, then this function will not block. Plugins should always use a timeout of zero to avoid blocking the host.

If a positive timeout is given, then events will be processed for that amount of time, starting from when this function was called.

If a negative timeout is given, this function will block indefinitely until an event occurs.

For continuously animating programs, a timeout that is a reasonable fraction of the ideal frame period should be used, to minimize input latency by ensuring that as many input events are consumed as possible before drawing.

Returns

PuglStatus::PUGL_SUCCESS if events are read, PuglStatus::PUGL_FAILURE if no events are read, or an error.

View

A drawable region that receives events.

A view can be thought of as a window, but does not necessarily correspond to a top-level window in a desktop environment. For example, a view can be embedded in some other window, or represent an embedded system where there is no concept of multiple windows at all.

Setup

Functions for creating and destroying a view.

PuglView *puglNewView(PuglWorld *world)

Create a new view.

A newly created view does not correspond to a real system view or window. It must first be configured, then the system view can be created with puglRealize().

void puglFreeView(PuglView *view)

Free a view created with puglNewView()

PuglWorld *puglGetWorld(PuglView *view)

Return the world that view is a part of.

void puglSetHandle(PuglView *view, PuglHandle handle)

Set the user data for a view.

This is usually a pointer to a struct that contains all the state which must be accessed by a view. Everything needed to process events should be stored here, not in static variables.

The handle is opaque to Pugl and is not interpreted in any way.

PuglHandle puglGetHandle(PuglView *view)

Get the user data for a view.

PuglStatus puglSetBackend(PuglView *view, const PuglBackend *backend)

Set the graphics backend to use for a view.

This must be called once to set the graphics backend before calling puglRealize().

Pugl includes the following backends:

Note that backends are modular and not compiled into the main Pugl library to avoid unnecessary dependencies. To use a particular backend, applications must link against the appropriate backend library, or be sure to compile in the appropriate code if using a local copy of Pugl.

PuglStatus puglSetEventFunc(PuglView *view, PuglEventFunc eventFunc)

Set the function to call when an event occurs.

PuglStatus puglSetViewHint(PuglView *view, PuglViewHint hint, int value)

Set a hint to configure view properties.

This only has an effect when called before puglRealize().

int puglGetViewHint(const PuglView *view, PuglViewHint hint)

Get the value for a view hint.

If the view has been realized, this can be used to get the actual value of a hint which was initially set to PUGL_DONT_CARE, or has been adjusted from the suggested value.

Frame

Functions for working with the position and size of a view.

PuglRect puglGetFrame(const PuglView *view)

Get the current position and size of the view.

The position is in screen coordinates with an upper left origin.

PuglStatus puglSetFrame(PuglView *view, PuglRect frame)

Set the current position and size of the view.

The position is in screen coordinates with an upper left origin.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, in which case the view frame is unchanged.

PuglStatus puglSetDefaultSize(PuglView *view, int width, int height)

Set the default size of the view.

This should be called before puglResize() to set the default size of the view, which will be the initial size of the window if this is a top level view.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

PuglStatus puglSetMinSize(PuglView *view, int width, int height)

Set the minimum size of the view.

If an initial minimum size is known, this should be called before puglRealize() to avoid stutter, though it can be called afterwards as well.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

PuglStatus puglSetMaxSize(PuglView *view, int width, int height)

Set the maximum size of the view.

If an initial maximum size is known, this should be called before puglRealize() to avoid stutter, though it can be called afterwards as well.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

PuglStatus puglSetAspectRatio(PuglView *view, int minX, int minY, int maxX, int maxY)

Set the view aspect ratio range.

The x and y values here represent a ratio of width to height. To set a fixed aspect ratio, set the minimum and maximum values to the same ratio.

Note that setting different minimum and maximum constraints does not currenty work on MacOS (the minimum is used), so only setting a fixed aspect ratio works properly across all platforms.

If an initial aspect ratio is known, this should be called before puglRealize() to avoid stutter, though it can be called afterwards as well.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

Window

Functions to control the top-level window of a view.

PuglStatus puglSetWindowTitle(PuglView *view, const char *title)

Set the title of the window.

This only makes sense for non-embedded views that will have a corresponding top-level window, and sets the title, typically displayed in the title bar or in window switchers.

PuglStatus puglSetParentWindow(PuglView *view, PuglNativeView parent)

Set the parent window for embedding a view in an existing window.

This must be called before puglRealize(), reparenting is not supported.

PuglStatus puglSetTransientFor(PuglView *view, PuglNativeView parent)

Set the transient parent of the window.

Set this for transient children like dialogs, to have them properly associated with their parent window. This should be called before puglRealize().

A view can either have a parent (for embedding) or a transient parent (for top-level windows like dialogs), but not both.

PuglStatus puglRealize(PuglView *view)

Realize a view by creating a corresponding system view or window.

After this call, the (initially invisible) underlying system view exists and can be accessed with puglGetNativeWindow(). There is currently no corresponding unrealize function, the system view will be destroyed along with the view when puglFreeView() is called.

The view should be fully configured using the above functions before this is called. This function may only be called once per view.

PuglStatus puglShow(PuglView *view)

Show the view.

If the view has not yet been realized, the first call to this function will do so automatically.

If the view is currently hidden, it will be shown and possibly raised to the top depending on the platform.

PuglStatus puglHide(PuglView *view)

Hide the current window.

bool puglGetVisible(const PuglView *view)

Return true iff the view is currently visible.

PuglNativeView puglGetNativeWindow(PuglView *view)

Return the native window handle.

Graphics

Functions for working with the graphics context and scheduling redisplays.

void *puglGetContext(PuglView *view)

Get the graphics context.

This is a backend-specific context used for drawing if the backend graphics API requires one. It is only available during an expose.

Cairo: Returns a pointer to a cairo_t.

All other backends: returns null.

PuglStatus puglPostRedisplay(PuglView *view)

Request a redisplay for the entire view.

This will cause an expose event to be dispatched later. If called from within the event handler, the expose should arrive at the end of the current event loop iteration, though this is not strictly guaranteed on all platforms. If called elsewhere, an expose will be enqueued to be processed in the next event loop iteration.

PuglStatus puglPostRedisplayRect(PuglView *view, PuglRect rect)

Request a redisplay of the given rectangle within the view.

This has the same semantics as puglPostRedisplay(), but allows giving a precise region for redrawing only a portion of the view.

Interaction

Functions for interacting with the user and window system.

enum PuglCursor

A mouse cursor type.

This is a portable subset of mouse cursors that exist on X11, MacOS, and Windows.

enumerator PUGL_CURSOR_ARROW

Default pointing arrow.

enumerator PUGL_CURSOR_CARET

Caret (I-Beam) for text entry.

enumerator PUGL_CURSOR_CROSSHAIR

Cross-hair.

enumerator PUGL_CURSOR_HAND

Hand with a pointing finger.

enumerator PUGL_CURSOR_NO

Operation not allowed.

enumerator PUGL_CURSOR_LEFT_RIGHT

Left/right arrow for horizontal resize.

enumerator PUGL_CURSOR_UP_DOWN

Up/down arrow for vertical resize.

PuglStatus puglGrabFocus(PuglView *view)

Grab the keyboard input focus.

bool puglHasFocus(const PuglView *view)

Return whether view has the keyboard input focus.

PuglStatus puglSetClipboard(PuglView *view, const char *type, const void *data, size_t len)

Set the clipboard contents.

This sets the system clipboard contents, which can be retrieved with puglGetClipboard() or pasted into other applications.

Parameters
  • view – The view.

  • type – The MIME type of the data, “text/plain” is assumed if NULL.

  • data – The data to copy to the clipboard.

  • len – The length of data in bytes (including terminator if necessary).

const void *puglGetClipboard(PuglView *view, const char **type, size_t *len)

Get the clipboard contents.

This gets the system clipboard contents, which may have been set with puglSetClipboard() or copied from another application.

Parameters
  • view – The view.

  • type – Set to the MIME type of the data.

  • len – Set to the length of the data in bytes.

Returns

The clipboard contents, or null.

PuglStatus puglSetCursor(PuglView *view, PuglCursor cursor)

Set the mouse cursor.

This changes the system cursor that is displayed when the pointer is inside the view. May fail if setting the cursor is not supported on this system, for example if compiled on X11 without Xcursor support.

Returns

PuglStatus::PUGL_BAD_PARAMETER if the given cursor is invalid, PuglStatus::PUGL_FAILURE if the cursor is known but loading it system fails.

PuglStatus puglRequestAttention(PuglView *view)

Request user attention.

This hints to the system that the window or application requires attention from the user. The exact effect depends on the platform, but is usually something like a flashing task bar entry or bouncing application icon.

PuglStatus puglStartTimer(PuglView *view, uintptr_t id, double timeout)

Activate a repeating timer event.

This starts a timer which will send a PuglEventTimer to view every timeout seconds. This can be used to perform some action in a view at a regular interval with relatively low frequency. Note that the frequency of timer events may be limited by how often puglUpdate() is called.

If the given timer already exists, it is replaced.

Parameters
  • view – The view to begin sending PuglEventType::PUGL_TIMER events to.

  • id – The identifier for this timer. This is an application-specific ID that should be a low number, typically the value of a constant or enum that starts from 0. There is a platform-specific limit to the number of supported timers, and overhead associated with each, so applications should create only a few timers and perform several tasks in one if necessary.

  • timeout – The period, in seconds, of this timer. This is not guaranteed to have a resolution better than 10ms (the maximum timer resolution on Windows) and may be rounded up if it is too short. On X11 and MacOS, a resolution of about 1ms can usually be relied on.

Returns

PuglStatus::PUGL_FAILURE if timers are not supported by the system, PuglStatus::PUGL_UNKNOWN_ERROR if setting the timer failed.

PuglStatus puglStopTimer(PuglView *view, uintptr_t id)

Stop an active timer.

Parameters
  • view – The view that the timer is set for.

  • id – The ID previously passed to puglStartTimer().

Returns

PuglStatus::PUGL_FAILURE if timers are not supported by this system, PuglStatus::PUGL_UNKNOWN_ERROR if stopping the timer failed.

PuglStatus puglSendEvent(PuglView *view, const PuglEvent *event)

Send an event to a view via the window system.

If supported, the event will be delivered to the view via the event loop like other events. Note that this function only works for certain event types.

Currently, only PuglEventType::PUGL_CLIENT events are supported on all platforms.

X11: A PuglEventType::PUGL_EXPOSE event can be sent, which is similar to calling puglPostRedisplayRect(), but will always send a message to the X server, even when called in an event handler.

Returns

PuglStatus::PUGL_UNSUPPORTED_TYPE if sending events of this type is not supported, PuglStatus::PUGL_UNKNOWN_ERROR if sending the event failed.

enum PuglViewHint

A hint for configuring a view.

enumerator PUGL_USE_COMPAT_PROFILE

Use compatible (not core) OpenGL profile.

enumerator PUGL_USE_DEBUG_CONTEXT

True to use a debug OpenGL context.

enumerator PUGL_CONTEXT_VERSION_MAJOR

OpenGL context major version.

enumerator PUGL_CONTEXT_VERSION_MINOR

OpenGL context minor version.

enumerator PUGL_RED_BITS

Number of bits for red channel.

enumerator PUGL_GREEN_BITS

Number of bits for green channel.

enumerator PUGL_BLUE_BITS

Number of bits for blue channel.

enumerator PUGL_ALPHA_BITS

Number of bits for alpha channel.

enumerator PUGL_DEPTH_BITS

Number of bits for depth buffer.

enumerator PUGL_STENCIL_BITS

Number of bits for stencil buffer.

enumerator PUGL_SAMPLES

Number of samples per pixel (AA)

enumerator PUGL_DOUBLE_BUFFER

True if double buffering should be used.

enumerator PUGL_SWAP_INTERVAL

Number of frames between buffer swaps.

enumerator PUGL_RESIZABLE

True if view should be resizable.

enumerator PUGL_IGNORE_KEY_REPEAT

True if key repeat events are ignored.

enumerator PUGL_REFRESH_RATE

Refresh rate in Hz.

enumerator PUGL_NUM_VIEW_HINTS
enum PuglViewHintValue

A special view hint value.

enumerator PUGL_DONT_CARE

Use best available value.

enumerator PUGL_FALSE

Explicitly false.

enumerator PUGL_TRUE

Explicitly true.

typedef struct PuglViewImpl PuglView

A drawable region that receives events.

typedef struct PuglBackendImpl PuglBackend

A graphics backend.

The backend dictates how graphics are set up for a view, and how drawing is performed. A backend must be set by calling puglSetBackend() before realising a view.

If you are using a local copy of Pugl, it is possible to implement a custom backend. See the definition of PuglBackendImpl in the source code for details.

typedef uintptr_t PuglNativeView

A native view handle.

X11: This is a Window.

MacOS: This is a pointer to an NSView*.

Windows: This is a HWND.

typedef void *PuglHandle

Handle for a view’s opaque user data.

typedef PuglStatus (*PuglEventFunc)(PuglView *view, const PuglEvent *event)

A function called when an event occurs.

Cairo

Cairo graphics support.

const PuglBackend *puglCairoBackend(void)

Cairo graphics backend accessor.

Pass the returned value to puglSetBackend() to draw to a view with Cairo.

OpenGL

OpenGL graphics support.

typedef void (*PuglGlFunc)(void)

OpenGL extension function.

PuglGlFunc puglGetProcAddress(const char *name)

Return the address of an OpenGL extension function.

PuglStatus puglEnterContext(PuglView *view)

Enter the OpenGL context.

This can be used to enter the graphics context in unusual situations, for doing things like loading textures. Note that this must not be used for drawing, which may only be done while processing an expose event.

PuglStatus puglLeaveContext(PuglView *view)

Leave the OpenGL context.

This must only be called after puglEnterContext().

const PuglBackend *puglGlBackend(void)

OpenGL graphics backend.

Pass the returned value to puglSetBackend() to draw to a view with OpenGL.

Stub

Native graphics support.

const PuglBackend *puglStubBackend(void)

Stub graphics backend accessor.

This backend just creates a simple native window without setting up any portable graphics API.

Vulkan

Vulkan graphics support.

Vulkan support differs from OpenGL because almost all most configuration is done using the Vulkan API itself, rather than by setting view hints to configure the context. Pugl only provides a minimal loader for loading the Vulkan library, and a portable function to create a Vulkan surface for a view, which hides the platform-specific implementation details.

typedef struct PuglVulkanLoaderImpl PuglVulkanLoader

Dynamic Vulkan loader.

This can be used to dynamically load the Vulkan library. Applications or plugins should not link against the Vulkan library, but instead use this at runtime. This ensures that things will work on as many systems as possible, and allows errors to be handled gracefully.

This is not a “loader” in the sense of loading all the required Vulkan functions (which is the application’s responsibility), but just a minimal implementation to portably load the Vulkan library and get the two functions that are used to load everything else.

Note that this owns the loaded Vulkan library, so it must outlive all use of the Vulkan API.

https://www.khronos.org/registry/vulkan/specs/1.0/html/chap4.html

PuglVulkanLoader *puglNewVulkanLoader(PuglWorld *world)

Create a new dynamic loader for Vulkan functions.

This dynamically loads the Vulkan library and gets the load functions from it.

Returns

A new Vulkan loader, or null on failure.

void puglFreeVulkanLoader(PuglVulkanLoader *loader)

Free a loader created with puglNewVulkanLoader().

Note that this closes the Vulkan library, so no Vulkan objects or API may be used after this is called.

PFN_vkGetInstanceProcAddr puglGetInstanceProcAddrFunc(const PuglVulkanLoader *loader)

Return the vkGetInstanceProcAddr function.

Returns

Null if the Vulkan library does not contain this function (which is unlikely and indicates a broken system).

PFN_vkGetDeviceProcAddr puglGetDeviceProcAddrFunc(const PuglVulkanLoader *loader)

Return the vkGetDeviceProcAddr function.

Returns

Null if the Vulkan library does not contain this function (which is unlikely and indicates a broken system).

const char *const *puglGetInstanceExtensions(uint32_t *count)

Return the Vulkan instance extensions required to draw to a PuglView.

This simply returns static strings, it does not access Vulkan or the window system. The returned array always contains at least “VK_KHR_surface”.

Parameters

count – The number of extensions in the returned array.

Returns

An array of extension name strings.

VkResult puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, PuglView *view, VkInstance instance, const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)

Create a Vulkan surface for a Pugl view.

Parameters
  • vkGetInstanceProcAddr – Accessor for Vulkan functions.

  • view – The view the surface is to be displayed on.

  • instance – The Vulkan instance.

  • allocator – Vulkan allocation callbacks, may be NULL.

  • surface – Pointed to a newly created Vulkan surface.

Returns

VK_SUCCESS on success, or a Vulkan error code.

const PuglBackend *puglVulkanBackend(void)

Vulkan graphics backend.

Pass the returned value to puglSetBackend() to draw to a view with Vulkan.

struct PuglRect

A rectangle.

This is used to describe things like view position and size. Pugl generally uses coordinates where the top left corner is 0,0.

double x
double y
double width
double height

Pugl C++ API

Pugl C++ API wrapper.

Events

template<PuglEventType t, class Base>
struct Event

A strongly-typed analogue of PuglEvent.

This is bit-for-bit identical to the corresponding PuglEvent, so events are simply cast to this type to avoid any copying overhead.

Parameters
  • t – The type field of the corresponding PuglEvent.

  • Base – The specific struct type of the corresponding PuglEvent.

using BaseEvent = Base

The type of the corresponding C event structure.

constexpr const PuglEventType type

The type field of the corresponding C event structure.

using Mod = PuglMod

Keyboard modifier flags.

using Mods = PuglMods

Bitwise OR of PuglMod values.

using Key = PuglKey

Keyboard key codepoints.

All keys are identified by a Unicode code point in PuglEventKey::key. This enumeration defines constants for special keys that do not have a standard code point, and some convenience constants for control characters. Note that all keys are handled in the same way, this enumeration is just for convenience when writing hard-coded key bindings.

Keys that do not have a standard code point use values in the Private Use Area in the Basic Multilingual Plane (U+E000 to U+F8FF). Applications must take care to not interpret these values beyond key detection, the mapping used here is arbitrary and specific to Pugl.

using EventType = PuglEventType

The type of a PuglEvent.

using EventFlag = PuglEventFlag

Common flags for all event types.

using EventFlags = PuglEventFlags

Bitwise OR of PuglEventFlag values.

using CrossingMode = PuglCrossingMode

Reason for a PuglEventCrossing.

using CreateEvent = Event<PUGL_CREATE, PuglEventCreate>

pugl::View create event.

This event is sent when a view is realized before it is first displayed, with the graphics context entered. This is typically used for setting up the graphics system, for example by loading OpenGL extensions.

This event type has no extra fields.

using DestroyEvent = Event<PUGL_DESTROY, PuglEventDestroy>

pugl::View destroy event.

This event is the counterpart to PuglEventCreate, and it is sent when the view is being destroyed. This is typically used for tearing down the graphics system, or otherwise freeing any resources allocated when the create event was handled.

This is the last event sent to any view, and immediately after it is processed, the view is destroyed and may no longer be used.

This event type has no extra fields.

using ConfigureEvent = Event<PUGL_CONFIGURE, PuglEventConfigure>

pugl::View resize or move event.

A configure event is sent whenever the view is resized or moved. When a configure event is received, the graphics context is active but not set up for drawing. For example, it is valid to adjust the OpenGL viewport or otherwise configure the context, but not to draw anything.

using MapEvent = Event<PUGL_MAP, PuglEventMap>

pugl::View show event.

This event is sent when a view is mapped to the screen and made visible.

This event type has no extra fields.

using UnmapEvent = Event<PUGL_UNMAP, PuglEventUnmap>

pugl::View hide event.

This event is sent when a view is unmapped from the screen and made invisible.

This event type has no extra fields.

using UpdateEvent = Event<PUGL_UPDATE, PuglEventUpdate>

pugl::View update event.

This event is sent to every view near the end of a main loop iteration when any pending exposures are about to be redrawn. It is typically used to mark regions to expose with puglPostRedisplay() or puglPostRedisplayRect(). For example, to continuously animate, a view calls puglPostRedisplay() when an update event is received, and it will then shortly receive an expose event.

using ExposeEvent = Event<PUGL_EXPOSE, PuglEventExpose>

Expose event for when a region must be redrawn.

When an expose event is received, the graphics context is active, and the view must draw the entire specified region. The contents of the region are undefined, there is no preservation of anything drawn previously.

using CloseEvent = Event<PUGL_CLOSE, PuglEventClose>

pugl::View close event.

This event is sent when the view is to be closed, for example when the user clicks the close button.

This event type has no extra fields.

using FocusInEvent = Event<PUGL_FOCUS_IN, PuglEventFocus>

Keyboard focus event.

This event is sent whenever the view gains or loses the keyboard focus. The view with the keyboard focus will receive any key press or release events.

using FocusOutEvent = Event<PUGL_FOCUS_OUT, PuglEventFocus>

Keyboard focus event.

This event is sent whenever the view gains or loses the keyboard focus. The view with the keyboard focus will receive any key press or release events.

using KeyPressEvent = Event<PUGL_KEY_PRESS, PuglEventKey>

Key press or release event.

This event represents low-level key presses and releases. This can be used for “direct” keyboard handing like key bindings, but must not be interpreted as text input.

Keys are represented portably as Unicode code points, using the “natural” code point for the key where possible (see PuglKey for details). The key field is the code for the pressed key, without any modifiers applied. For example, a press or release of the ‘A’ key will have key 97 (‘a’) regardless of whether shift or control are being held.

Alternatively, the raw keycode can be used to work directly with physical keys, but note that this value is not portable and differs between platforms and hardware.

using KeyReleaseEvent = Event<PUGL_KEY_RELEASE, PuglEventKey>

Key press or release event.

This event represents low-level key presses and releases. This can be used for “direct” keyboard handing like key bindings, but must not be interpreted as text input.

Keys are represented portably as Unicode code points, using the “natural” code point for the key where possible (see PuglKey for details). The key field is the code for the pressed key, without any modifiers applied. For example, a press or release of the ‘A’ key will have key 97 (‘a’) regardless of whether shift or control are being held.

Alternatively, the raw keycode can be used to work directly with physical keys, but note that this value is not portable and differs between platforms and hardware.

using TextEvent = Event<PUGL_TEXT, PuglEventText>

Character input event.

This event represents text input, usually as the result of a key press. The text is given both as a Unicode character code and a UTF-8 string.

Note that this event is generated by the platform’s input system, so there is not necessarily a direct correspondence between text events and physical key presses. For example, with some input methods a sequence of several key presses will generate a single character.

using PointerInEvent = Event<PUGL_POINTER_IN, PuglEventCrossing>

Pointer enter or leave event.

This event is sent when the pointer enters or leaves the view. This can happen for several reasons (not just the user dragging the pointer over the window edge), as described by the mode field.

using PointerOutEvent = Event<PUGL_POINTER_OUT, PuglEventCrossing>

Pointer enter or leave event.

This event is sent when the pointer enters or leaves the view. This can happen for several reasons (not just the user dragging the pointer over the window edge), as described by the mode field.

using ButtonPressEvent = Event<PUGL_BUTTON_PRESS, PuglEventButton>

Button press or release event.

using ButtonReleaseEvent = Event<PUGL_BUTTON_RELEASE, PuglEventButton>

Button press or release event.

using MotionEvent = Event<PUGL_MOTION, PuglEventMotion>

Pointer motion event.

using ScrollEvent = Event<PUGL_SCROLL, PuglEventScroll>

Scroll event.

The scroll distance is expressed in “lines”, an arbitrary unit that corresponds to a single tick of a detented mouse wheel. For example, dy = 1.0 scrolls 1 line up. Some systems and devices support finer resolution and/or higher values for fast scrolls, so programs should handle any value gracefully.

using ClientEvent = Event<PUGL_CLIENT, PuglEventClient>

Custom client message event.

This can be used to send a custom message to a view, which is delivered via the window system and processed in the event loop as usual. Among other things, this makes it possible to wake up the event loop for any reason.

using TimerEvent = Event<PUGL_TIMER, PuglEventTimer>

Timer event.

This event is sent at the regular interval specified in the call to puglStartTimer() that activated it.

The id is the application-specific ID given to puglStartTimer() which distinguishes this timer from others. It should always be checked in the event handler, even in applications that register only one timer.

using LoopEnterEvent = Event<PUGL_LOOP_ENTER, PuglEventLoopEnter>

Recursive loop enter event.

This event is sent when the window system enters a recursive loop. The main loop will be stalled and no expose events will be received while in the recursive loop. To give the application full control, Pugl does not do any special handling of this situation, but this event can be used to install a timer to perform continuous actions (such as drawing) on platforms that do this.

  • MacOS: A recursive loop is entered while the window is being live resized.

  • Windows: A recursive loop is entered while the window is being live resized or the menu is shown.

  • X11: A recursive loop is never entered and the event loop runs as usual while the view is being resized.

This event type has no extra fields.

using LoopLeaveEvent = Event<PUGL_LOOP_LEAVE, PuglEventLoopLeave>

Recursive loop leave event.

This event is sent after a loop enter event when the recursive loop is finished and normal iteration will continue.

This event type has no extra fields.

Status

enum Status

Return status code.

enumerator success

Success.

enumerator failure

Non-fatal failure.

enumerator unknownError

Unknown system error.

enumerator badBackend

Invalid or missing backend.

enumerator badConfiguration

Invalid view configuration.

enumerator badParameter

Invalid parameter.

enumerator backendFailed

Backend initialization failed.

enumerator registrationFailed

Class registration failed.

enumerator realizeFailed

System view realization failed.

enumerator setFormatFailed

Failed to set pixel format.

enumerator createContextFailed

Failed to create drawing context.

enumerator unsupportedType

Unsupported data type.

const char *strerror(const Status status) noexcept

Return a string describing a status code.

World

class World

The “world” of application state.

The world represents everything that is not associated with a particular view. Several worlds can be created in a single process, but code using different worlds must be isolated so they are never mixed. Views are strongly associated with the world they were created in.

World(const World&) = delete
World &operator=(const World&) = delete
World(World&&) = delete
World &operator=(World&&) = delete
~World() = default
World(WorldType type, WorldFlag flag)
World(WorldType type, WorldFlags flags)
World(WorldType type)
void *nativeWorld() noexcept

Return a pointer to the native handle of the world. X11: Returns a pointer to the Display.

MacOS: Returns null.

Windows: Returns the HMODULE of the calling process.

Status setClassName(const char *const name) noexcept

Set the class name of the application. This is a stable identifier for the application, used as the window class/instance name on X11 and Windows. It is not displayed to the user, but can be used in scripts and by window managers, so it should be the same for every instance of the application, but different from other applications.

double time() const noexcept

Return the time in seconds. This is a monotonically increasing clock with high resolution. The returned time is only useful to compare against other times returned by this function, its absolute value has no meaning.

Status update(const double timeout) noexcept

Update by processing events from the window system. This function is a single iteration of the main loop, and should be called repeatedly to update all views.

If timeout is zero, then this function will not block. Plugins should always use a timeout of zero to avoid blocking the host.

If a positive timeout is given, then events will be processed for that amount of time, starting from when this function was called.

If a negative timeout is given, this function will block indefinitely until an event occurs.

For continuously animating programs, a timeout that is a reasonable fraction of the ideal frame period should be used, to minimize input latency by ensuring that as many input events are consumed as possible before drawing.

Returns

PuglStatus::PUGL_SUCCESS if events are read, PuglStatus::PUGL_FAILURE if no events are read, or an error.

enum WorldType

The type of a pugl::World.

enumerator program

Top-level application.

enumerator module

Plugin or module within a larger application.

enum WorldFlag

pugl::World flags.

enumerator threads

Set up support for threads if necessary. - X11: Calls XInitThreads() which is required for some drivers.

using WorldFlags = PuglWorldFlags

Bitwise OR of PuglWorldFlag values.

PUGL_CHECK_CONSTRUCTION

Configurable macro for handling construction failure.

If PUGL_HPP_THROW_FAILED_CONSTRUCTION is defined, then this throws a pugl::FailedConstructionError if construction fails.

If PUGL_HPP_ASSERT_CONSTRUCTION is defined, then this asserts if construction fails.

Otherwise, this does nothing.

View

class View

A drawable region that receives events.

View(World &world)
const World &world() const noexcept
World &world() noexcept
template<class Handler>
Status setEventHandler(Handler &handler)

Set the object that will be called to handle events. This is a type-safe wrapper for the C functions puglSetHandle() and puglSetEventFunc() that will automatically dispatch events to the onEvent method of handler that takes the appropriate event type. The handler must have such a method defined for every event type, but if the handler is the view itself, a using declaration can be used to “inherit” the default implementation to avoid having to define every method. For example:

class MyView : public pugl::View
{
public:
  explicit MyView(pugl::World& world)
    : pugl::View{world}
  {
    setEventHandler(*this);
  }

  using pugl::View::onEvent;

  pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept;
  pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept;
};

This facility is just a convenience, applications may use the C API directly to set a handle and event function to set up a different approach for event handling.

Status setBackend(const PuglBackend *backend) noexcept

Set the graphics backend to use for a view. This must be called once to set the graphics backend before calling puglRealize().

Pugl includes the following backends:

Note that backends are modular and not compiled into the main Pugl library to avoid unnecessary dependencies. To use a particular backend, applications must link against the appropriate backend library, or be sure to compile in the appropriate code if using a local copy of Pugl.

Status setHint(ViewHint hint, int value) noexcept

Set a hint to configure view properties. This only has an effect when called before puglRealize().

int getHint(ViewHint hint) noexcept

Get the value for a view hint. If the view has been realized, this can be used to get the actual value of a hint which was initially set to PUGL_DONT_CARE, or has been adjusted from the suggested value.

Rect frame() const noexcept

Get the current position and size of the view. The position is in screen coordinates with an upper left origin.

Status setFrame(Rect frame) noexcept

Set the current position and size of the view. The position is in screen coordinates with an upper left origin.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, in which case the view frame is unchanged.

Status setDefaultSize(int width, int height) noexcept

Set the default size of the view. This should be called before puglResize() to set the default size of the view, which will be the initial size of the window if this is a top level view.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

Status setMinSize(int width, int height) noexcept

Set the minimum size of the view. If an initial minimum size is known, this should be called before puglRealize() to avoid stutter, though it can be called afterwards as well.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

Status setMaxSize(int width, int height) noexcept

Set the maximum size of the view. If an initial maximum size is known, this should be called before puglRealize() to avoid stutter, though it can be called afterwards as well.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept

Set the view aspect ratio range. The x and y values here represent a ratio of width to height. To set a fixed aspect ratio, set the minimum and maximum values to the same ratio.

Note that setting different minimum and maximum constraints does not currenty work on MacOS (the minimum is used), so only setting a fixed aspect ratio works properly across all platforms.

If an initial aspect ratio is known, this should be called before puglRealize() to avoid stutter, though it can be called afterwards as well.

Returns

PuglStatus::PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized.

Status setWindowTitle(const char *title) noexcept

Set the title of the window. This only makes sense for non-embedded views that will have a corresponding top-level window, and sets the title, typically displayed in the title bar or in window switchers.

Status setParentWindow(NativeView parent) noexcept

Set the parent window for embedding a view in an existing window. This must be called before puglRealize(), reparenting is not supported.

Status setTransientFor(NativeView parent) noexcept

Set the transient parent of the window. Set this for transient children like dialogs, to have them properly associated with their parent window. This should be called before puglRealize().

A view can either have a parent (for embedding) or a transient parent (for top-level windows like dialogs), but not both.

Status realize() noexcept

Realize a view by creating a corresponding system view or window. After this call, the (initially invisible) underlying system view exists and can be accessed with puglGetNativeWindow(). There is currently no corresponding unrealize function, the system view will be destroyed along with the view when puglFreeView() is called.

The view should be fully configured using the above functions before this is called. This function may only be called once per view.

Status show() noexcept

Show the view. If the view has not yet been realized, the first call to this function will do so automatically.

If the view is currently hidden, it will be shown and possibly raised to the top depending on the platform.

Status hide() noexcept

Hide the current window.

bool visible() const noexcept

Return true iff the view is currently visible.

NativeView nativeWindow() noexcept

Return the native window handle.

void *context() noexcept

Get the graphics context. This is a backend-specific context used for drawing if the backend graphics API requires one. It is only available during an expose.

Cairo: Returns a pointer to a cairo_t.

All other backends: returns null.

Status postRedisplay() noexcept

Request a redisplay for the entire view. This will cause an expose event to be dispatched later. If called from within the event handler, the expose should arrive at the end of the current event loop iteration, though this is not strictly guaranteed on all platforms. If called elsewhere, an expose will be enqueued to be processed in the next event loop iteration.

Status postRedisplayRect(const Rect rect) noexcept

Request a redisplay of the given rectangle within the view. This has the same semantics as puglPostRedisplay(), but allows giving a precise region for redrawing only a portion of the view.

Status grabFocus() noexcept

Grab the keyboard input focus.

bool hasFocus() const noexcept

Return whether view has the keyboard input focus.

Status setCursor(const Cursor cursor) noexcept

Set the mouse cursor. This changes the system cursor that is displayed when the pointer is inside the view. May fail if setting the cursor is not supported on this system, for example if compiled on X11 without Xcursor support.

Returns

PuglStatus::PUGL_BAD_PARAMETER if the given cursor is invalid, PuglStatus::PUGL_FAILURE if the cursor is known but loading it system fails.

Status requestAttention() noexcept

Request user attention. This hints to the system that the window or application requires attention from the user. The exact effect depends on the platform, but is usually something like a flashing task bar entry or bouncing application icon.

Status startTimer(const uintptr_t id, const double timeout) noexcept

Activate a repeating timer event. This starts a timer which will send a timer event to view every timeout seconds. This can be used to perform some action in a view at a regular interval with relatively low frequency. Note that the frequency of timer events may be limited by how often update() is called.

If the given timer already exists, it is replaced.

Parameters
  • id – The identifier for this timer. This is an application-specific ID that should be a low number, typically the value of a constant or enum that starts from 0. There is a platform-specific limit to the number of supported timers, and overhead associated with each, so applications should create only a few timers and perform several tasks in one if necessary.

  • timeout – The period, in seconds, of this timer. This is not guaranteed to have a resolution better than 10ms (the maximum timer resolution on Windows) and may be rounded up if it is too short. On X11 and MacOS, a resolution of about 1ms can usually be relied on.

Returns

PuglStatus::PUGL_FAILURE if timers are not supported by the system, PuglStatus::PUGL_UNKNOWN_ERROR if setting the timer failed.

Status stopTimer(const uintptr_t id) noexcept

Stop an active timer. :param id: The ID previously passed to startTimer().

Returns

PuglStatus::PUGL_FAILURE if timers are not supported by this system, PuglStatus::PUGL_UNKNOWN_ERROR if stopping the timer failed.

PuglView *cobj() noexcept
const PuglView *cobj() const noexcept
enum ViewHint

A hint for configuring a view.

enumerator useCompatProfile

Use compatible (not core) OpenGL profile.

enumerator useDebugContext

True to use a debug OpenGL context.

enumerator contextVersionMajor

OpenGL context major version.

enumerator contextVersionMinor

OpenGL context minor version.

enumerator redBits

Number of bits for red channel.

enumerator greenBits

Number of bits for green channel.

enumerator blueBits

Number of bits for blue channel.

enumerator alphaBits

Number of bits for alpha channel.

enumerator depthBits

Number of bits for depth buffer.

enumerator stencilBits

Number of bits for stencil buffer.

enumerator samples

Number of samples per pixel (AA)

enumerator doubleBuffer

True if double buffering should be used.

enumerator swapInterval

Number of frames between buffer swaps.

enumerator resizable

True if view should be resizable.

enumerator ignoreKeyRepeat

True if key repeat events are ignored.

enumerator refreshRate

Refresh rate in Hz.

enum Cursor

A mouse cursor type.

This is a portable subset of mouse cursors that exist on X11, MacOS, and Windows.

enumerator arrow

Default pointing arrow.

enumerator caret

Caret (I-Beam) for text entry.

enumerator crosshair

Cross-hair.

enumerator hand

Hand with a pointing finger.

enumerator no

Operation not allowed.

enumerator leftRight

Left/right arrow for horizontal resize.

enumerator upDown

Up/down arrow for vertical resize.

using Backend = PuglBackend

A graphics backend.

The backend dictates how graphics are set up for a view, and how drawing is performed. A backend must be set by calling puglSetBackend() before realising a view.

If you are using a local copy of Pugl, it is possible to implement a custom backend. See the definition of PuglBackendImpl in the source code for details.

using NativeView = PuglNativeView

A native view handle.

X11: This is a Window.

MacOS: This is a pointer to an NSView*.

Windows: This is a HWND.

using ViewHintValue = PuglViewHintValue

A special view hint value.

Cairo

Cairo graphics support.

const PuglBackend *cairoBackend() noexcept

Cairo graphics backend accessor.

Pass the returned value to puglSetBackend() to draw to a view with Cairo.

OpenGL

OpenGL graphics support.

using GlFunc = PuglGlFunc

OpenGL extension function.

GlFunc getProcAddress(const char *name) noexcept

Return the address of an OpenGL extension function.

Status enterContext(View &view) noexcept

Enter the OpenGL context.

This can be used to enter the graphics context in unusual situations, for doing things like loading textures. Note that this must not be used for drawing, which may only be done while processing an expose event.

Status leaveContext(View &view) noexcept

Leave the OpenGL context.

This must only be called after puglEnterContext().

const PuglBackend *glBackend() noexcept

OpenGL graphics backend.

Pass the returned value to puglSetBackend() to draw to a view with OpenGL.

Stub

Stub graphics support.

const PuglBackend *stubBackend() noexcept

Stub graphics backend accessor.

This backend just creates a simple native window without setting up any portable graphics API.

Vulkan

Vulkan graphics support.

Note that the Pugl C++ wrapper does not use vulkan-hpp because it is a heavyweight dependency which not everyone uses, and its design is not very friendly to dynamic loading in plugins anyway. However, if you do use vulkan-hpp smart handles, it is relatively straightforward to wrap the result of pugl::createSurface() manually.

class VulkanLoader

Dynamic Vulkan loader.

This can be used to dynamically load the Vulkan library. Applications or plugins should not link against the Vulkan library, but instead use this at runtime. This ensures that things will work on as many systems as possible, and allows errors to be handled gracefully.

This is not a “loader” in the sense of loading all the required Vulkan functions (which is the application’s responsibility), but just a minimal implementation to portably load the Vulkan library and get the two functions that are used to load everything else.

Note that this owns the loaded Vulkan library, so it must outlive all use of the Vulkan API.

https://www.khronos.org/registry/vulkan/specs/1.0/html/chap4.html

VulkanLoader(World &world) noexcept

Create a new dynamic loader for Vulkan functions. This dynamically loads the Vulkan library and gets the load functions from it.

Note that this constructor does not throw exceptions, though failure is possible. To check if the Vulkan library failed to load, test this loader, which is explicitly convertible to bool. It is safe to use a failed loader, but the accessors will always return null.

PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc() const noexcept

Return the vkGetInstanceProcAddr function. :returns: Null if the Vulkan library failed to load, or does not contain this function (which is unlikely and indicates a broken system).

PFN_vkGetDeviceProcAddr getDeviceProcAddrFunc() const noexcept

Return the vkGetDeviceProcAddr function. :returns: Null if the Vulkan library failed to load, or does not contain this function (which is unlikely and indicates a broken system).

operator bool() const noexcept

Return true if this loader is valid to use.

class StaticStringArray

A simple wrapper for an array of static C strings.

This provides a minimal API that supports iteration, like std::vector, but avoids allocation, exceptions, and a dependency on the C++ standard library.

using value_type = const char*
using const_iterator = const char*const*
using size_type = uint32_t
StaticStringArray(const char *const *strings, const uint32_t size) noexcept
const char *const *begin() const noexcept
const char *const *end() const noexcept
const char *const *data() const noexcept
uint32_t size() const noexcept
StaticStringArray getInstanceExtensions() noexcept

Return the Vulkan instance extensions required to draw to a PuglView.

If successful, the returned array always contains “VK_KHR_surface”, along with whatever other platform-specific extensions are required.

Returns

An array of extension name strings.

VkResult createSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, View &view, VkInstance instance, const VkAllocationCallbacks *const allocator, VkSurfaceKHR *const surface) noexcept

Create a Vulkan surface for a Pugl view.

Parameters
  • vkGetInstanceProcAddr – Accessor for Vulkan functions.

  • view – The view the surface is to be displayed on.

  • instance – The Vulkan instance.

  • allocator – Vulkan allocation callbacks, may be NULL.

  • surface – Pointed to a newly created Vulkan surface.

Returns

VK_SUCCESS on success, or a Vulkan error code.

const PuglBackend *vulkanBackend() noexcept

Vulkan graphics backend.

Pass the returned value to puglSetBackend() to draw to a view with Vulkan.

using Rect = PuglRect

A rectangle.

This is used to describe things like view position and size. Pugl generally uses coordinates where the top left corner is 0,0.