Wayland++  0.2.6
C++ Bindings for Wayland
egl.cpp

This is an example of how to use the Wayland C++ bindings with EGL and OpenGL.

/*
* Copyright (c) 2014-2019, Nils Christopher Brause, Philipp Kerling, Zsolt Bölöny
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdexcept>
#include <iostream>
#include <array>
#include <wayland-client-protocol-extra.hpp>
#include <wayland-egl.hpp>
#include <GL/gl.h>
#include <linux/input.h>
#include <wayland-cursor.hpp>
using namespace wayland;
// helper to create a std::function out of a member function and an object
template <typename R, typename T, typename... Args>
std::function<R(Args...)> bind_mem_fn(R(T::* func)(Args...), T *t)
{
return [func, t] (Args... args)
{
return (t->*func)(args...);
};
}
// example Wayland client
class example
{
private:
// global objects
display_t display;
registry_t registry;
compositor_t compositor;
shell_t shell;
xdg_wm_base_t xdg_wm_base;
seat_t seat;
shm_t shm;
// local objects
surface_t surface;
shell_surface_t shell_surface;
xdg_surface_t xdg_surface;
xdg_toplevel_t xdg_toplevel;
pointer_t pointer;
keyboard_t keyboard;
callback_t frame_cb;
cursor_image_t cursor_image;
buffer_t cursor_buffer;
surface_t cursor_surface;
// EGL
egl_window_t egl_window;
EGLDisplay egldisplay;
EGLSurface eglsurface;
EGLContext eglcontext;
bool running;
bool has_pointer;
bool has_keyboard;
void init_egl()
{
egldisplay = eglGetDisplay(display);
if(egldisplay == EGL_NO_DISPLAY)
throw std::runtime_error("eglGetDisplay");
EGLint major, minor;
if(eglInitialize(egldisplay, &major, &minor) == EGL_FALSE)
throw std::runtime_error("eglInitialize");
if(!((major == 1 && minor >= 4) || major >= 2))
throw std::runtime_error("EGL version too old");
if(eglBindAPI(EGL_OPENGL_API) == EGL_FALSE)
throw std::runtime_error("eglBindAPI");
std::array<EGLint, 13> config_attribs = {{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE
}};
EGLConfig config;
EGLint num;
if(eglChooseConfig(egldisplay, config_attribs.data(), &config, 1, &num) == EGL_FALSE || num == 0)
throw std::runtime_error("eglChooseConfig");
std::array<EGLint, 3> context_attribs = {{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
}};
eglcontext = eglCreateContext(egldisplay, config, EGL_NO_CONTEXT, context_attribs.data());
if(eglcontext == EGL_NO_CONTEXT)
throw std::runtime_error("eglCreateContext");
eglsurface = eglCreateWindowSurface(egldisplay, config, egl_window, nullptr);
if(eglsurface == EGL_NO_SURFACE)
throw std::runtime_error("eglCreateWindowSurface");
if(eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext) == EGL_FALSE)
throw std::runtime_error("eglMakeCurrent");
}
void draw(uint32_t serial = 0)
{
float h = ((serial >> 4) & 0xFF)/255.0;
float s = 1, v = 1;
int hi = static_cast<int>(h*6);
float f = h*6 - hi;
float p = v*(1-s);
float q = v*(1-s*f);
float t = v*(1-s*(1-f));
float r, g, b;
switch(hi)
{
case 1:
r = q; g = v; b = p;
break;
case 2:
r = p; g = v; b = t;
break;
case 3:
r = p; g = q; b = v;
break;
case 4:
r = t; g = p; b = v;
break;
case 5:
r = v; g = p; b = q;
break;
default: // 0,6
r = v; g = t; b = p;
break;
}
// draw stuff
glClearColor(r, g, b, 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
// schedule next draw
frame_cb = surface.frame();
frame_cb.on_done() = bind_mem_fn(&example::draw, this);
// swap buffers
if(eglSwapBuffers(egldisplay, eglsurface) == EGL_FALSE)
throw std::runtime_error("eglSwapBuffers");
}
public:
example()
{
// retrieve global objects
registry = display.get_registry();
registry.on_global() = [&] (uint32_t name, std::string interface, uint32_t version)
{
if(interface == compositor_t::interface_name)
registry.bind(name, compositor, version);
else if(interface == shell_t::interface_name)
registry.bind(name, shell, version);
else if(interface == xdg_wm_base_t::interface_name)
registry.bind(name, xdg_wm_base, version);
else if(interface == seat_t::interface_name)
registry.bind(name, seat, version);
else if(interface == shm_t::interface_name)
registry.bind(name, shm, version);
};
display.roundtrip();
seat.on_capabilities() = [&] (seat_capability capability)
{
has_keyboard = capability & seat_capability::keyboard;
has_pointer = capability & seat_capability::pointer;
};
// create a surface
surface = compositor.create_surface();
// create a shell surface
if(xdg_wm_base)
{
xdg_wm_base.on_ping() = [&] (uint32_t serial) { xdg_wm_base.pong(serial); };
xdg_surface = xdg_wm_base.get_xdg_surface(surface);
xdg_surface.on_configure() = [&] (uint32_t serial) { xdg_surface.ack_configure(serial); };
xdg_toplevel = xdg_surface.get_toplevel();
xdg_toplevel.set_title("Window");
xdg_toplevel.on_close() = [&] () { running = false; };
}
else
{
shell_surface = shell.get_shell_surface(surface);
shell_surface.on_ping() = [&] (uint32_t serial) { shell_surface.pong(serial); };
shell_surface.set_title("Window");
shell_surface.set_toplevel();
}
surface.commit();
display.roundtrip();
// Get input devices
if(!has_keyboard)
throw std::runtime_error("No keyboard found.");
if(!has_pointer)
throw std::runtime_error("No pointer found.");
pointer = seat.get_pointer();
keyboard = seat.get_keyboard();
// load cursor theme
cursor_theme_t cursor_theme = cursor_theme_t("default", 16, shm);
cursor_t cursor = cursor_theme.get_cursor("cross");
cursor_image = cursor.image(0);
cursor_buffer = cursor_image.get_buffer();
// create cursor surface
cursor_surface = compositor.create_surface();
// draw cursor
pointer.on_enter() = [&] (uint32_t serial, surface_t, int32_t, int32_t)
{
cursor_surface.attach(cursor_buffer, 0, 0);
cursor_surface.damage(0, 0, cursor_image.width(), cursor_image.height());
cursor_surface.commit();
pointer.set_cursor(serial, cursor_surface, 0, 0);
};
// window movement
pointer.on_button() = [&] (uint32_t serial, uint32_t time, uint32_t button, pointer_button_state state)
{
if(button == BTN_LEFT && state == pointer_button_state::pressed)
{
if(xdg_toplevel)
xdg_toplevel.move(seat, serial);
else
shell_surface.move(seat, serial);
}
};
// press 'q' to exit
keyboard.on_key() = [&] (uint32_t, uint32_t, uint32_t key, keyboard_key_state state)
{
if(key == KEY_Q && state == keyboard_key_state::pressed)
running = false;
};
// intitialize egl
egl_window = egl_window_t(surface, 320, 240);
init_egl();
// draw stuff
draw();
}
~example() noexcept(false)
{
// finialize EGL
if(eglDestroyContext(egldisplay, eglcontext) == EGL_FALSE)
throw std::runtime_error("eglDestroyContext");
if(eglTerminate(egldisplay) == EGL_FALSE)
throw std::runtime_error("eglTerminate");
}
void run()
{
// event loop
running = true;
while(running)
display.dispatch();
}
};
int main()
{
example e;
e.run();
return 0;
}
wayland::egl_window_t
Native EGL window.
Definition: wayland-egl.hpp:42
wayland::xdg_wm_base_t::pong
void pong(uint32_t serial)
respond to a ping event
Definition: wayland-client-protocol-extra.cpp:968
wayland::surface_t::frame
callback_t frame()
request a frame throttling hint
Definition: wayland-client-protocol.cpp:2633
wayland::display_t
Represents a connection to the compositor and acts as a proxy to the display singleton object.
Definition: wayland-client.hpp:463
wayland::xdg_wm_base_t::get_xdg_surface
xdg_surface_t get_xdg_surface(surface_t surface)
create a shell surface from a surface
Definition: wayland-client-protocol-extra.cpp:962
wayland::pointer_t::on_button
std::function< void(uint32_t, uint32_t, uint32_t, pointer_button_state)> & on_button()
pointer button event
Definition: wayland-client-protocol.cpp:2890
wayland::display_t::dispatch
int dispatch()
Process incoming events.
wayland::display_t::get_registry
registry_t get_registry()
get global registry object
wayland::pointer_t::on_enter
std::function< void(uint32_t, surface_t, double, double)> & on_enter()
enter event
Definition: wayland-client-protocol.cpp:2875
wayland::shell_t
create desktop-style surfaces
Definition: wayland-client-protocol.hpp:1419
wayland::shell_surface_t::pong
void pong(uint32_t serial)
respond to a ping event
Definition: wayland-client-protocol.cpp:2476
wayland::pointer_t::set_cursor
void set_cursor(uint32_t serial, surface_t surface, int32_t hotspot_x, int32_t hotspot_y)
set the pointer surface
Definition: wayland-client-protocol.cpp:2861
wayland::callback_t::on_done
std::function< void(uint32_t)> & on_done()
done event
Definition: wayland-client-protocol.cpp:1641
wayland::xdg_surface_t
desktop user interface surface base interface
Definition: wayland-client-protocol-extra.hpp:959
wayland::buffer_t
content for a wl_surface
Definition: wayland-client-protocol.hpp:602
wayland::shm_t
shared memory support
Definition: wayland-client-protocol.hpp:391
wayland::surface_t::commit
void commit()
commit pending surface state
Definition: wayland-client-protocol.cpp:2649
wayland::keyboard_t::on_key
std::function< void(uint32_t, uint32_t, uint32_t, keyboard_key_state)> & on_key()
key event
Definition: wayland-client-protocol.cpp:3033
wayland::shell_surface_t::set_title
void set_title(std::string title)
set surface title
Definition: wayland-client-protocol.cpp:2516
wayland::surface_t::attach
void attach(buffer_t buffer, int32_t x, int32_t y)
set the surface contents
Definition: wayland-client-protocol.cpp:2623
wayland::surface_t
an onscreen surface
Definition: wayland-client-protocol.hpp:1898
wayland::seat_capability::pointer
static const detail::bitfield< 3, 12 > pointer
the seat has pointer devices
Definition: wayland-client-protocol.hpp:2485
wayland::xdg_surface_t::on_configure
std::function< void(uint32_t)> & on_configure()
suggest a surface change
Definition: wayland-client-protocol-extra.cpp:1161
wayland::surface_t::damage
void damage(int32_t x, int32_t y, int32_t width, int32_t height)
mark part of the surface damaged
Definition: wayland-client-protocol.cpp:2628
wayland::seat_capability
seat capability bitmask
Definition: wayland-client-protocol.hpp:2478
wayland::xdg_toplevel_t::on_close
std::function< void()> & on_close()
surface wants to be closed
Definition: wayland-client-protocol-extra.cpp:1300
wayland::shell_surface_t
desktop-style metadata interface
Definition: wayland-client-protocol.hpp:1485
wayland::xdg_toplevel_t::set_title
void set_title(std::string title)
set surface title
Definition: wayland-client-protocol-extra.cpp:1235
wayland::xdg_surface_t::get_toplevel
xdg_toplevel_t get_toplevel()
assign the xdg_toplevel surface role
Definition: wayland-client-protocol-extra.cpp:1139
wayland::shell_surface_t::move
void move(seat_t seat, uint32_t serial)
start an interactive move
Definition: wayland-client-protocol.cpp:2481
wayland::xdg_toplevel_t::move
void move(seat_t seat, uint32_t serial)
start an interactive move
Definition: wayland-client-protocol-extra.cpp:1250
wayland::xdg_toplevel_t
toplevel surface
Definition: wayland-client-protocol-extra.hpp:1143
wayland::registry_t
global registry object
Definition: wayland-client-protocol.hpp:130
wayland::registry_t::bind
proxy_t bind(uint32_t name, proxy_t &interface, uint32_t version)
bind an object to the display
Definition: wayland-client-protocol.cpp:1560
wayland::seat_t
group of input devices
Definition: wayland-client-protocol.hpp:2334
wayland::compositor_t::create_surface
surface_t create_surface()
create new surface
Definition: wayland-client-protocol.cpp:1707
wayland::shell_t::get_shell_surface
shell_surface_t get_shell_surface(surface_t surface)
create a shell surface from a surface
Definition: wayland-client-protocol.cpp:2415
wayland::display_t::roundtrip
int roundtrip()
Block until all pending request are processed by the server.
wayland::shell_surface_t::on_ping
std::function< void(uint32_t)> & on_ping()
ping client
Definition: wayland-client-protocol.cpp:2526
wayland::seat_t::get_pointer
pointer_t get_pointer()
return pointer object
Definition: wayland-client-protocol.cpp:2756
wayland::compositor_t
the compositor singleton
Definition: wayland-client-protocol.hpp:251
wayland::xdg_surface_t::ack_configure
void ack_configure(uint32_t serial)
ack a configure event
Definition: wayland-client-protocol-extra.cpp:1156
wayland::xdg_wm_base_t
create desktop-style surfaces
Definition: wayland-client-protocol-extra.hpp:564
wayland::xdg_wm_base_t::on_ping
std::function< void(uint32_t)> & on_ping()
check if the client is alive
Definition: wayland-client-protocol-extra.cpp:973
wayland::seat_t::get_keyboard
keyboard_t get_keyboard()
return keyboard object
Definition: wayland-client-protocol.cpp:2762
wayland::callback_t
callback object
Definition: wayland-client-protocol.hpp:210
wayland::shell_surface_t::set_toplevel
void set_toplevel()
make the surface a toplevel surface
Definition: wayland-client-protocol.cpp:2491
wayland::registry_t::on_global
std::function< void(uint32_t, std::string, uint32_t)> & on_global()
announce global object
Definition: wayland-client-protocol.cpp:1567
wayland::seat_t::on_capabilities
std::function< void(seat_capability)> & on_capabilities()
seat capabilities changed
Definition: wayland-client-protocol.cpp:2783
wayland::seat_capability::keyboard
static const detail::bitfield< 3, 12 > keyboard
the seat has one or more keyboards
Definition: wayland-client-protocol.hpp:2487
wayland::keyboard_t
keyboard input device
Definition: wayland-client-protocol.hpp:2896
wayland-client.hpp
wayland::pointer_t
pointer input device
Definition: wayland-client-protocol.hpp:2505