diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 70abde59..153410da 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -17,8 +17,8 @@ jobs: environment_script: "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat" - name: "Ubuntu Latest GCC" os: ubuntu-latest - cc: "gcc-9" - cxx: "g++-9" + cc: "gcc" + cxx: "g++" - name: "macOS Latest Clang" os: macos-latest cc: "clang" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1fc8b415..2ab24818 100755 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,7 +8,50 @@ project(examples) if (UNIX AND NOT APPLE) find_package(OpenGL REQUIRED COMPONENTS OpenGL) find_package(PkgConfig REQUIRED) - pkg_check_modules(gtk3 REQUIRED IMPORTED_TARGET gtk+-3.0) + + option(X_Win "Use x11 window" ON) + + set(SRC host/linux/skia_app.cpp + host/linux/skia_context.cpp) + + if (X_Win) + pkg_check_modules(depend REQUIRED IMPORTED_TARGET + x11 glx + ) + set(SRC ${SRC} + host/linux/x11/application.cpp + ) + + else() + pkg_check_modules(depend REQUIRED IMPORTED_TARGET + wayland-client wayland-cursor wayland-egl xkbcommon egl + ) + + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake") + find_package(WaylandScanner REQUIRED) + + set(WORK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/host/linux/wayland") + + wayland_add_protocol_client(SRC_GEN ${WORK_DIR} + "${WaylandScanner_DATADIR}/stable/xdg-shell/xdg-shell.xml") + wayland_add_protocol_client(SRC_GEN ${WORK_DIR} + "${WaylandScanner_DATADIR}/unstable/tablet/tablet-unstable-v2.xml") + wayland_add_protocol_client(SRC_GEN ${WORK_DIR} + "${WaylandScanner_DATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml") + wayland_add_protocol_client(SRC_GEN ${WORK_DIR} + "${WaylandScanner_DATADIR}/staging/fractional-scale/fractional-scale-v1.xml") + wayland_add_protocol_client(SRC_GEN ${WORK_DIR} + "${WaylandScanner_DATADIR}/stable/viewporter/viewporter.xml") + + set(SRC ${SRC} ${SRC_GEN} + host/linux/wayland/core.cpp + host/linux/wayland/display.cpp + host/linux/wayland/xdgshell.cpp + host/linux/wayland/contextegl.cpp + host/linux/wayland/application.cpp + ) + endif() + endif() file( @@ -78,17 +121,17 @@ function(add_example name) ) elseif (UNIX) - + add_executable( ${name} ${name}.cpp - host/linux/skia_app.cpp + ${SRC} print_elapsed.cpp ) target_link_libraries( ${name} - PkgConfig::gtk3 + PkgConfig::depend OpenGL::GL ) diff --git a/examples/cmake/FindWaylandScanner.cmake b/examples/cmake/FindWaylandScanner.cmake new file mode 100644 index 00000000..62af1562 --- /dev/null +++ b/examples/cmake/FindWaylandScanner.cmake @@ -0,0 +1,60 @@ +# Finds the Wayland client libraries +# Also supports components "protocols" and "scanner" + +find_package(PkgConfig QUIET) + +pkg_check_modules(PKG_Wayland QUIET wayland-protocols wayland-scanner) + +set(WaylandScanner_VERSION ${PKG_Wayland_VERSION}) +set(WaylandScanner_DEFINITIONS ${PKG_Wayland_CFLAGS}) +mark_as_advanced(WaylandScanner_DEFINITIONS) + +pkg_get_variable(Wayland_PROTOCOLS_DATADIR wayland-protocols pkgdatadir) +mark_as_advanced(Wayland_PROTOCOLS_DATADIR) + +if (NOT Wayland_PROTOCOLS_DATADIR) + message(FATAL "The wayland-protocols data directory has not been found on your system.") +endif() + +pkg_get_variable(WaylandScanner_EXECUTABLE_DIR wayland-scanner bindir) +find_program(WaylandScanner_EXECUTABLE NAMES wayland-scanner HINTS ${WaylandScanner_EXECUTABLE_DIR}) +mark_as_advanced(WaylandScanner_EXECUTABLE WaylandScanner_EXECUTABLE_DIR) + +set(WaylandScanner_DATADIR ${Wayland_PROTOCOLS_DATADIR}) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(WaylandScanner + FOUND_VAR WaylandScanner_FOUND + VERSION_VAR WaylandScanner_VERSION + REQUIRED_VARS WaylandScanner_EXECUTABLE ) #Wayland_LIBRARIES) + +if (NOT TARGET Wayland::Scanner AND WaylandScanner_FOUND) + add_executable(Wayland::Scanner IMPORTED) + set_target_properties(Wayland::Scanner PROPERTIES + IMPORTED_LOCATION "${WaylandScanner_EXECUTABLE}") +endif() + +function(wayland_add_protocol_client _sources _workdir _protocol) + if (NOT TARGET Wayland::Scanner) + message(FATAL "The wayland-scanner executable has not been found on your system.") + endif() + + get_filename_component(_basename ${_protocol} NAME_WLE) + + set(_source_file "${_protocol}") + set(_client_header "${_workdir}/${_basename}-client-protocol.h") + set(_private_code "${_workdir}/${_basename}-protocol.c") + + add_custom_command(OUTPUT ${_client_header} + COMMAND Wayland::Scanner client-header ${_source_file} ${_client_header} + DEPENDS ${_source_file} VERBATIM) + + add_custom_command(OUTPUT ${_private_code} + COMMAND Wayland::Scanner private-code ${_source_file} ${_private_code} + DEPENDS ${_source_file} ${_client_header} VERBATIM) + + list(APPEND ${_sources} ${_client_header} ${_private_code}) + set(${_sources} ${${_sources}} PARENT_SCOPE) + +endfunction() diff --git a/examples/host/linux/application.h b/examples/host/linux/application.h new file mode 100644 index 00000000..495992ad --- /dev/null +++ b/examples/host/linux/application.h @@ -0,0 +1,51 @@ +#ifndef APP_H +#define APP_H + +#include "SkSurface.h" + +class Application +{ +public: + void run(); + void stop(){isRuning = false;} + + class DisplayImpl; + +private: + bool isRuning{false}; +}; + +enum SurfaceState +{ + resizing = 1 << 0, + maximized = 1 << 1, + activated = 1 << 2, + fullscreen = 1 << 3 +}; + +class Surface +{ +public: + Surface(int width, int height); + ~Surface(); + + void setTitle(const char* txt); + +protected: + /* + * Draw frame. Returns true if the next frame needs to be drawn + */ + virtual bool draw(float /*scale*/) = 0; + virtual void configure(unsigned /*w*/, unsigned /*h*/, unsigned /*state*/) = 0; + virtual void closed() = 0; + + sk_sp skia_surf; + +private: + struct Impl; + std::unique_ptr impl; + + friend class Application; +}; + +#endif // APP_H diff --git a/examples/host/linux/logger.h b/examples/host/linux/logger.h new file mode 100644 index 00000000..b42d50fa --- /dev/null +++ b/examples/host/linux/logger.h @@ -0,0 +1,43 @@ +#ifndef LOG_H +#define LOG_H + +#include + +class Logger final +{ +public: + explicit Logger(const char* app_id) + { + openlog(app_id, LOG_PERROR | LOG_PID, LOG_USER); + } + + ~Logger() + { + closelog(); + } + + template + static void message(const char *msg, Arg&& ...args) noexcept + { + syslog(LOG_INFO, msg, args...); + } + + template + static void error(const char *msg, Arg&& ...args) noexcept + { + syslog(LOG_ERR, msg, args...); + } + + template + static void debug(const char *msg, Arg&& ...args) noexcept + { +#ifndef NDEBUG + syslog(LOG_DEBUG, msg, args...); +#endif + } + +private: + Logger() = default; +}; + +#endif // LOG_H diff --git a/examples/host/linux/skia_app.cpp b/examples/host/linux/skia_app.cpp index d70f530f..5cbf2243 100644 --- a/examples/host/linux/skia_app.cpp +++ b/examples/host/linux/skia_app.cpp @@ -4,163 +4,30 @@ Distributed under the MIT License [ https://opensource.org/licenses/MIT ] =============================================================================*/ #include "../../app.hpp" -#include + #include -#include -#include "GrDirectContext.h" -#include "gl/GrGLInterface.h" -#include "gl/GrGLAssembleInterface.h" -#include "SkImage.h" -#include "SkColorSpace.h" #include "SkCanvas.h" -#include "SkSurface.h" #include +#include "logger.h" +#include "application.h" + using namespace cycfi::artist; float elapsed_ = 0; // rendering elapsed time -namespace +void render(SkCanvas* gpu_canvas, float scale) { - struct view_state - { - extent _size = {}; - float _scale = 1.0; - bool _animate = false; - color _bkd = colors::white; - guint _timer_id = 0; - - sk_sp _xface; - sk_sp _ctx; - sk_sp _surface; - }; - - void close_window(GtkWidget*, gpointer user_data) - { - view_state& state = *reinterpret_cast(user_data); - if (state._timer_id) - g_source_remove(state._timer_id); - } - - void realize(GtkGLArea* area, gpointer user_data) - { - auto error = [](char const* msg) { throw std::runtime_error(msg); }; - - gtk_gl_area_make_current(area); - if (gtk_gl_area_get_error(area) != nullptr) - error("Error. gtk_gl_area_get_error failed"); - - view_state& state = *reinterpret_cast(user_data); - glClearColor(state._bkd.red, state._bkd.green, state._bkd.blue, state._bkd.alpha); - glClear(GL_COLOR_BUFFER_BIT); - if (state._xface = GrGLMakeNativeInterface(); state._xface == nullptr) - { - //backup plan. see https://gist.github.com/ad8e/dd150b775ae6aa4d5cf1a092e4713add?permalink_comment_id=4680136#gistcomment-4680136 - state._xface = GrGLMakeAssembledInterface( - nullptr, (GrGLGetProc) * - [](void*, const char* p) -> void* - { - return (void*)glXGetProcAddress((const GLubyte*)p); - } - ); - if (state._xface == nullptr) - error("Error. GLMakeNativeInterface failed"); - } - if (state._ctx = GrDirectContext::MakeGL(state._xface); state._ctx == nullptr) - error("Error. GrDirectContext::MakeGL failed"); - } - - gboolean render(GtkGLArea* area, GdkGLContext* context, gpointer user_data) - { - view_state& state = *reinterpret_cast(user_data); - auto error = [](char const* msg) { throw std::runtime_error(msg); }; - - auto draw_f = - [&]() - { - if (!state._surface) - { - GrGLint buffer; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buffer); - GrGLFramebufferInfo info; - info.fFBOID = (GrGLuint) buffer; - SkColorType colorType = kRGBA_8888_SkColorType; - - info.fFormat = GL_RGBA8; - GrBackendRenderTarget target( - state._size.x*state._scale - , state._size.y*state._scale - , 0, 8, info - ); - - state._surface = - SkSurface::MakeFromBackendRenderTarget( - state._ctx.get(), target, - kBottomLeft_GrSurfaceOrigin, colorType, nullptr, nullptr - ); - - if (!state._surface) - error("Error: SkSurface::MakeRenderTarget returned null"); - } - - SkCanvas* gpu_canvas = state._surface->getCanvas(); - gpu_canvas->save(); - gpu_canvas->scale(state._scale, state._scale); - auto cnv = canvas{gpu_canvas}; - - draw(cnv); - - gpu_canvas->restore(); - state._surface->flush(); - }; - - auto start = std::chrono::steady_clock::now(); - draw_f(); - auto stop = std::chrono::steady_clock::now(); - elapsed_ = std::chrono::duration{stop - start}.count(); - - return true; - } - - gboolean animate(gpointer user_data) - { - GtkWidget* da = GTK_WIDGET(user_data); - gtk_widget_queue_draw(da); - return true; - } - - static auto proc = &glXGetProcAddress; - - void activate(GtkApplication* app, gpointer user_data) - { - auto error = [](char const* msg) { throw std::runtime_error(msg); }; - if (!proc) - error("Error: glXGetProcAddress is null"); - - view_state& state = *reinterpret_cast(user_data); - auto* window = gtk_application_window_new(app); - gtk_window_set_title(GTK_WINDOW(window), "Drawing Area"); - - g_signal_connect(window, "destroy", G_CALLBACK(close_window), user_data); + auto start = std::chrono::steady_clock::now(); - GtkWidget* widget = nullptr; - // create a GtkGLArea instance - GtkWidget* gl_area = gtk_gl_area_new(); - widget = gl_area; - gtk_container_add(GTK_CONTAINER(window), gl_area); + gpu_canvas->save(); + gpu_canvas->scale(scale, scale); + auto cnv = canvas{gpu_canvas}; + draw(cnv); + gpu_canvas->restore(); - g_signal_connect(gl_area, "render", G_CALLBACK(render), user_data); - g_signal_connect(gl_area, "realize", G_CALLBACK(realize), user_data); - - gtk_window_resize(GTK_WINDOW(window), state._size.x, state._size.y); - gtk_widget_show_all(window); - - auto w = gtk_widget_get_window(GTK_WIDGET(window)); - state._scale = gdk_window_get_scale_factor(w); - - if (widget && state._animate) - state._timer_id = g_timeout_add(1000 / 60, animate, widget); - } + auto stop = std::chrono::steady_clock::now(); + elapsed_ = std::chrono::duration{stop - start}.count(); } namespace cycfi::artist @@ -179,6 +46,35 @@ namespace cycfi::artist } } +class Window: public Surface +{ +public: + using Surface::Surface; + + std::function onClosed; + //std::function onDraw; + std::function onReshape; + + bool animate; + +private: + //bool m_opaque; + + bool draw(float scale) override + { + render(skia_surf->getCanvas(), scale); + return animate; + } + + void closed() override + {if (onClosed) onClosed();} + + void configure(uint32_t width, uint32_t height, unsigned state) override + { + onReshape(width, height); + } +}; + int run_app( int argc , char const* argv[] @@ -187,28 +83,31 @@ int run_app( , bool animate ) { - view_state state; - state._size = window_size; - state._animate = animate; - state._bkd = background_color; + try { - auto* app = gtk_application_new("org.gtk-skia.example", G_APPLICATION_FLAGS_NONE); - int status = 0; + Application app; - try - { - g_signal_connect(app, "activate", G_CALLBACK(activate), &state); - int status = g_application_run(G_APPLICATION(app), argc, const_cast(argv)); - } - catch (std::runtime_error const& e) - { - // GPU rendering not available - g_printerr(e.what()); - int status = 1; - } - g_object_unref(app); + Window window(window_size.x, window_size.y); + + window.setTitle("Example application"); + window.animate = animate; + window.onClosed = [&app](){app.stop();}; + window.onReshape = [&background_color](int, int) { + glClearColor(background_color.red + 0.1, + background_color.green, + background_color.blue, + background_color.alpha); + glClear(GL_COLOR_BUFFER_BIT); + }; + + app.run(); + + } catch (const std::runtime_error& e) { + Logger::error("Error application : %s", e.what()); + exit(1); + } - return status; + return 0; } diff --git a/examples/host/linux/skia_context.cpp b/examples/host/linux/skia_context.cpp new file mode 100644 index 00000000..d1e4201c --- /dev/null +++ b/examples/host/linux/skia_context.cpp @@ -0,0 +1,47 @@ +#include "skia_context.h" +#include "SkColorSpace.h" + +#include + +void GlSkiaContext::init(GrGLGetProc gl_get_proc) +{ + auto _xface = GrGLMakeNativeInterface(); + if (_xface == nullptr) { + //backup plan. see https://gist.github.com/ad8e/dd150b775ae6aa4d5cf1a092e4713add?permalink_comment_id=4680136#gistcomment-4680136 + _xface = GrGLMakeAssembledInterface( + nullptr, gl_get_proc); + } + + _ctx = GrDirectContext::MakeGL(_xface); + if (!_ctx) + throw std::runtime_error("failed to make Skia context"); +} + +sk_sp GlSkiaContext::makeSurface(int width, int height) noexcept +{ + GrGLFramebufferInfo framebufferInfo; + framebufferInfo.fFBOID = 0; // assume default framebuffer + framebufferInfo.fFormat = GL_RGBA8; + + SkColorType colorType = kRGBA_8888_SkColorType; + target = std::make_unique( + width, + height, + 1, // sample count + 8, // stencil bits + framebufferInfo); + + auto result = target->isValid() ? SkSurface::MakeFromBackendRenderTarget(_ctx.get(), + *target.get(), + kBottomLeft_GrSurfaceOrigin, + colorType, + nullptr, + nullptr) + : nullptr; + + if (!result) + throw std::runtime_error("failed to make Skia surface"); + + return std::move(result); +} + diff --git a/examples/host/linux/skia_context.h b/examples/host/linux/skia_context.h new file mode 100644 index 00000000..b68667d7 --- /dev/null +++ b/examples/host/linux/skia_context.h @@ -0,0 +1,28 @@ +#ifndef SKIA_CONTEXT_H +#define SKIA_CONTEXT_H + +#include "GrDirectContext.h" +#include "gl/GrGLAssembleInterface.h" + +#include "SkSurface.h" + +class GlSkiaContext +{ +public: + GlSkiaContext(GlSkiaContext const&) = delete; + GlSkiaContext& operator=(GlSkiaContext const&) = delete; + GlSkiaContext(GlSkiaContext&& other) = delete; + GlSkiaContext& operator=(GlSkiaContext&&) = delete; + + GlSkiaContext() = default; + + void init(GrGLGetProc gl_get_proc); + + sk_sp makeSurface(int width, int height) noexcept; + +private: + sk_sp _ctx; + std::unique_ptr target; +}; + +#endif // SKIA_CONTEXT_H diff --git a/examples/host/linux/wayland/application.cpp b/examples/host/linux/wayland/application.cpp new file mode 100644 index 00000000..92379f30 --- /dev/null +++ b/examples/host/linux/wayland/application.cpp @@ -0,0 +1,152 @@ +#include "../application.h" +#include "../logger.h" + +#include "contextegl.h" +#include "xdgshell.h" + + +struct Surface::Impl: public WL::Toplevel +{ + Impl(const WL::Display &display, ::Surface* holder, int width, int height): + WL::Toplevel(display, width, height), + m_context(display.c_ptr()), + m_holder(holder), + m_need_redraw(false), + m_is_corrupt(false) + {} + + bool event_process() + { + if (m_need_redraw) draw(m_scale); + return m_is_corrupt; + } + + void buffer_scale(float scale) override + { + Logger::debug("buffer_scale %f", scale); + } + + void draw(float scale) override + { + m_need_redraw = m_holder->draw(scale); + + m_holder->skia_surf->flush(); + m_context.flush(m_buffer); + } + + void configure(unsigned w, unsigned h, unsigned s) override + { + unsigned state = 0; + + try { + if (m_buffer.empty()) + { + m_width *= m_scale; + m_height *= m_scale; + + m_buffer.init(*this, m_width, m_height); + m_context.makeCurrent(m_buffer); + + m_holder->skia_surf = m_context.makeSurface(m_width, m_height); + m_holder->configure(w, h, SurfaceState::resizing); + draw(m_scale); + return; + } + else { + if (s & WL::resizing) + state |= SurfaceState::resizing; + if (s & WL::maximized) + state |= SurfaceState::maximized; + if (s & WL::activated) + state |= SurfaceState::activated; + if (s & WL::fullscreen) + state |= SurfaceState::fullscreen; + + if (s & WL::resizing) + m_buffer.resize(w, h); + } + + m_holder->configure(w, h, state); + m_need_redraw = true; + + } catch(const std::runtime_error& e){ + Logger::error("Error configure, the window must be closed : %s", e.what()); + m_need_redraw = false; + m_is_corrupt = true; + } + } + + void closed() override + { + m_holder->closed(); + } + + WL::ContextEGL::Buffer m_buffer; + WL::ContextEGL m_context; + + ::Surface* m_holder; + + bool m_need_redraw; + bool m_is_corrupt; +}; + +class Application::DisplayImpl +{ +public: + static DisplayImpl& inst() + { + static DisplayImpl dpy(WL::Display::create_default()); + return dpy; + } + + void start_event(bool &isrun); + + const WL::Display& display(){return m_display;} + +private: + DisplayImpl(WL::Display &&dpy): + syslogger("artist_lib_wayland"), + m_display(std::move(dpy)){} + + Logger syslogger; + WL::Display m_display; + + Surface::Impl* m_win{nullptr}; + friend class Surface; +}; + +void Application::DisplayImpl::start_event(bool &isrun) +{ + assert(m_win); + + while (isrun) { + m_display.event_wait(); + if (m_win->event_process()) + throw std::runtime_error("Window is corrupt"); + } +} + +void Application::run() +{ + if (isRuning) return; + isRuning = true; + + DisplayImpl::inst().start_event(isRuning); +} + +Surface::Surface(int width, int height): + impl{std::make_unique(Application::DisplayImpl::inst().display(), this, width, height)} +{ + Application::DisplayImpl::inst().m_win = impl.get(); +} + +Surface::~Surface() +{ + Application::DisplayImpl::inst().m_win = nullptr; +} + +void Surface::setTitle(const char* txt) +{ + impl->setTitle(txt); +} diff --git a/examples/host/linux/wayland/contextegl.cpp b/examples/host/linux/wayland/contextegl.cpp new file mode 100644 index 00000000..73356c3e --- /dev/null +++ b/examples/host/linux/wayland/contextegl.cpp @@ -0,0 +1,208 @@ +#include "contextegl.h" +#include "core.h" + +#include + +#include "../logger.h" + +using namespace WL; + +ContextEGL::ContextEGL(EGLNativeDisplayType dpy): + m_display(eglGetDisplay(dpy)), + m_context(EGL_NO_CONTEXT), + m_surface(EGL_NO_SURFACE) +{ + EGLint majorVersion; + EGLint minorVersion; + + if (m_display == EGL_NO_DISPLAY || + eglInitialize(m_display, &majorVersion, &minorVersion) != EGL_TRUE) { + + throw std::runtime_error("Can't connect to egl display"); + } + + if (eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE) + throw std::runtime_error("Can't bind EGL_OPENGL_ES_API"); + + Logger::debug("EGL: %i.%i", majorVersion, minorVersion); + + EGLint config_attribs[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_DEPTH_SIZE, 1, + EGL_STENCIL_SIZE, 1, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, + EGL_ALPHA_SIZE, 8, + //EGL_NONE, EGL_NONE, + EGL_NONE + }; + + EGLint num_config; + if (!eglChooseConfig (m_display, config_attribs, &m_config, 1, &num_config) + || num_config != 1) + throw std::runtime_error("Can't choose config"); +} + +ContextEGL::~ContextEGL() +{ + if (m_display != EGL_NO_DISPLAY){ + if (m_context != EGL_NO_CONTEXT){ + if (m_surface != EGL_NO_SURFACE){ + eglMakeCurrent (m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_context); + eglDestroySurface(m_display, m_surface); + } + eglDestroyContext(m_display, m_context); + } + eglTerminate(m_display); + } +} + +// bool ContextEGL::opaque() const +// { +// EGLint alpha_size; +// if (!eglGetConfigAttrib(m_egl_display, m_egl_config, EGL_ALPHA_SIZE, &alpha_size)) +// throw std::runtime_error("failed to get alpha size"); + +// return !alpha_size; +// } + +void ContextEGL::makeCurrent(Buffer &buf) +{ + if (buf.empty()) return; + + if (buf.m_egl_surface == EGL_NO_SURFACE) { + + m_surface = eglCreateWindowSurface(m_display, m_config, + buf.m_egl_window, nullptr); + if (m_surface == EGL_NO_SURFACE) + std::runtime_error("Can't create egl surface"); + + if (m_context == EGL_NO_CONTEXT) { + + const EGLint context_attribs[] = { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_MINOR_VERSION, 0, + //EGL_CONTEXT_OPENGL_DEBUG, EGL_TRUE, + EGL_NONE + }; + + m_context = eglCreateContext(m_display, m_config, + EGL_NO_CONTEXT, context_attribs); + if (!m_context) + throw std::runtime_error("Can't create egl context"); + + if (!eglMakeCurrent(m_display, + m_surface, + m_surface, + m_context)) + throw std::runtime_error("failed to make EGL context current"); + + GlSkiaContext::init((GrGLGetProc)* [](void *, const char *p) -> void * { + return (void *) eglGetProcAddress(p);}); + + Logger::debug("context GL_VENDOR: %s, GL_RENDERER: %s, GL_VERSION: %s", + glGetString(GL_VENDOR), + glGetString(GL_RENDERER), + glGetString(GL_VERSION)); + } + else + if (!eglMakeCurrent(m_display, + m_surface, + m_surface, + m_context)) + throw std::runtime_error("failed to make EGL context current"); + + buf.m_egl_surface = m_surface; + } + else if (m_surface != buf.m_egl_surface){ + + if (!eglMakeCurrent(m_display, + buf.m_egl_surface, + buf.m_egl_surface, + m_context)) + throw std::runtime_error("failed to make EGL context current"); + + m_surface = buf.m_egl_surface; + } + +} + +void ContextEGL::destroy(Buffer &buf) +{ + if (buf.m_egl_surface != EGL_NO_SURFACE){ + if (buf.m_egl_surface == m_surface){ + eglMakeCurrent(m_display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + m_context); + + m_surface = EGL_NO_SURFACE; + } + + eglDestroySurface(m_display, buf.m_egl_surface); + + buf.m_egl_surface = EGL_NO_SURFACE; + } +} + +void ContextEGL::flush(Buffer &buf) const +{ + eglSwapBuffers(m_display, buf.m_egl_surface); +} + +void WL::ContextEGL::Buffer::init(const Surface &wl, uint32_t width, uint32_t height) +{ + assert(m_egl_window == nullptr);//duble initialized + + m_egl_window = wl_egl_window_create(wl.c_ptr(), width, height); + if(!m_egl_window) + std::runtime_error("Can't create egl window"); +} + +void WL::ContextEGL::Buffer::resize(uint32_t width, uint32_t height) +{ + assert(m_egl_window);// window not initialized + + wl_egl_window_resize(m_egl_window, width, height, 0, 0); +} + +const char* getEGLErrorString() +{ + switch (eglGetError()) + { + case EGL_SUCCESS: + return "Success"; + case EGL_NOT_INITIALIZED: + return "EGL is not or could not be initialized"; + case EGL_BAD_ACCESS: + return "EGL cannot access a requested resource"; + case EGL_BAD_ALLOC: + return "EGL failed to allocate resources for the requested operation"; + case EGL_BAD_ATTRIBUTE: + return "An unrecognized attribute or attribute value was passed in the attribute list"; + case EGL_BAD_CONTEXT: + return "An EGLContext argument does not name a valid EGL rendering context"; + case EGL_BAD_CONFIG: + return "An EGLConfig argument does not name a valid EGL frame buffer configuration"; + case EGL_BAD_CURRENT_SURFACE: + return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid"; + case EGL_BAD_DISPLAY: + return "An EGLDisplay argument does not name a valid EGL display connection"; + case EGL_BAD_SURFACE: + return "An EGLSurface argument does not name a valid surface configured for GL rendering"; + case EGL_BAD_MATCH: + return "Arguments are inconsistent"; + case EGL_BAD_PARAMETER: + return "One or more argument values are invalid"; + case EGL_BAD_NATIVE_PIXMAP: + return "A NativePixmapType argument does not refer to a valid native pixmap"; + case EGL_BAD_NATIVE_WINDOW: + return "A NativeWindowType argument does not refer to a valid native window"; + case EGL_CONTEXT_LOST: + return "The application must destroy all contexts and reinitialise"; + default: + return "ERROR: UNKNOWN EGL ERROR"; + } +} diff --git a/examples/host/linux/wayland/contextegl.h b/examples/host/linux/wayland/contextegl.h new file mode 100644 index 00000000..0ecb11ea --- /dev/null +++ b/examples/host/linux/wayland/contextegl.h @@ -0,0 +1,55 @@ +#ifndef CONTEXTEGL_H +#define CONTEXTEGL_H + +#include "../skia_context.h" + +#include +#include + +namespace WL { + +class Surface; + +class ContextEGL: public GlSkiaContext +{ +public: + explicit ContextEGL(EGLNativeDisplayType dpy); + + class Buffer + { + public: + ~Buffer() + {if (!empty()) wl_egl_window_destroy(m_egl_window);} + + void init(const Surface &wl, uint32_t width, uint32_t height); + void resize(uint32_t width, uint32_t height); + + bool empty() const {return m_egl_window == nullptr;} + + private: + wl_egl_window *m_egl_window{nullptr}; + EGLSurface m_egl_surface{EGL_NO_SURFACE}; + + friend class ContextEGL; + }; + + void makeCurrent(Buffer &buf); + void flush(Buffer &buf) const; + void destroy(Buffer &buf); + + ~ContextEGL(); + + operator bool() const { return m_display != nullptr; } + + //bool opaque() const; + +private: + EGLDisplay m_display; + EGLContext m_context; + EGLSurface m_surface; + EGLConfig m_config; +}; + +} + +#endif // CONTEXTEGL_H diff --git a/examples/host/linux/wayland/core.cpp b/examples/host/linux/wayland/core.cpp new file mode 100644 index 00000000..ab3be2dd --- /dev/null +++ b/examples/host/linux/wayland/core.cpp @@ -0,0 +1,473 @@ +#include "core.h" + +#include +#include +#include +#include +#include + +#include "../logger.h" + +namespace WL { + +////////---- Surface Impl ----/////////////////////////////////////// + +Surface::Surface(wl_compositor *compositor, + const FractionalScaleManager *manager): +Base(wl_compositor_create_surface(compositor), "Can't create surface"), +m_scale(1), +m_fscale(manager ? wp_fractional_scale_manager_v1_get_fractional_scale(manager->c_ptr(), c_ptr()) + : nullptr), +m_input_hundler(nullptr) +{ + static const wl_surface_listener lsr { + .enter = [](void *data, + struct wl_surface *wl_surface, + struct wl_output *output){ + + }, + + .leave = [](void *data, + struct wl_surface *wl_surface, + struct wl_output *output){ + }, + + .preferred_buffer_scale = [](void *data, + struct wl_surface *wl_surface, + int32_t factor){ + auto surface = static_cast(data); + if (!surface->m_fscale) + surface->buffer_scale(factor); + }, + + .preferred_buffer_transform = [](void *data, + struct wl_surface *wl_surface, + uint32_t transform){ + + } + }; + + wl_surface_add_listener(c_ptr(), &lsr, this); + + if (m_fscale) { + static const wp_fractional_scale_v1_listener lsr{ + .preferred_scale = [](void *data, wp_fractional_scale_v1 *, uint32_t scale) { + auto surface = static_cast(data); + auto val = (float)scale / 120; + + surface->m_scale = val; + surface->buffer_scale(val); + } + }; + + wp_fractional_scale_v1_add_listener(m_fscale.c_ptr(), &lsr, this); + } +} + +void Surface::setAreaOpaque(wl_compositor *compositor, int32_t w, int32_t h) const +{ + auto region = wl_compositor_create_region(compositor); + if (!region) + return; + + wl_region_add(region, 0, 0, w, h); + wl_surface_set_opaque_region(c_ptr(), region); + wl_region_destroy(region); +} + + +////////---- Seat Impl ----////////////////////////////////////////// + +struct Keyboard::KeyMapper +{ + xkb_context *kcontext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + xkb_keymap *keymap = nullptr; + xkb_state *kstate = nullptr; + uint32_t keycode = 0; + uint32_t keysymbol = 0; + + ~KeyMapper() + { + if (kstate) + xkb_state_unref(kstate); + if (keymap) + xkb_keymap_unref(keymap); + if (kcontext) + xkb_context_unref(kcontext); + } + + bool map(int32_t fd, uint32_t size) noexcept; + bool keySymbol(uint32_t key) noexcept; +}; + +bool Keyboard::KeyMapper::map(int32_t fd, uint32_t size) noexcept +{ + if(!kcontext){ + Logger::error("xkb context failed"); + return false; + } + + void *addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) { + Logger::error("Error: XKBKeyboard mmap code %i", errno); + return false; + } + + if (keymap) + xkb_keymap_unref(keymap); + if (!(keymap = xkb_keymap_new_from_string(kcontext, + (const char*)addr, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS))){ + Logger::error("Error: create xkb keymap"); + return false; + } + + if (kstate) + xkb_state_unref(kstate); + if (!(kstate = xkb_state_new(keymap))){ + Logger::error("Error: create xkb kstate"); + return false; + } + + if (munmap(addr, size) < 0){ + Logger::error("Error: XKBKeyboard munmap code %i", errno); + return false; + } + + return true; +} + +bool Keyboard::KeyMapper::keySymbol(uint32_t key) noexcept +{ + auto raw_key = key + 8; + auto sym = xkb_state_key_get_one_sym(kstate, raw_key); + + if ((sym >= XKB_KEY_Shift_L && sym <= XKB_KEY_Hyper_R) || + (sym >= XKB_KEY_ISO_Lock && sym <= XKB_KEY_ISO_Last_Group_Lock) || + sym == XKB_KEY_Mode_switch || + sym == XKB_KEY_Num_Lock) + return false; + + keycode = raw_key; + keysymbol = sym; + return true; +} + +Keyboard::~Keyboard() +{ + delete m_mapper; +} + +unsigned Keyboard::modifiers(ModSet group) const +{ + if (m_mapper) + switch (group) { + case ModSet::effective: + return xkb_state_serialize_mods( + m_mapper->kstate, XKB_STATE_MODS_EFFECTIVE); + case ModSet::consumed: + return xkb_state_key_get_consumed_mods2( + m_mapper->kstate, m_mapper->keycode, XKB_CONSUMED_MODE_XKB); + case ModSet::locked: + return xkb_state_serialize_mods( + m_mapper->kstate, XKB_STATE_MODS_LOCKED); + default: + break; + } + + return 0; +} + +const char* Keyboard::utf8() const +{ + return ""; +} + +uint32_t Keyboard::symbol() const +{ + return m_mapper->keysymbol; +} + +void Seat::emitKeypress() const +{ + assert(m_focused_surf); + + m_focused_surf->key(m_keyboard); +} + +const wl_keyboard_listener Seat::keyboard_listener = { + .keymap = [](void *data, wl_keyboard*, + uint32_t format, int32_t fd, + uint32_t size){ + + auto& kb = static_cast(data)->m_keyboard; + + if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 && !kb.m_mapper) + kb.m_mapper = new(std::nothrow) Keyboard::KeyMapper; + //else + //To Do WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP + + if(kb.m_mapper){ + if(!kb.m_mapper->map(fd, size)){ + delete kb.m_mapper; + kb.m_mapper = nullptr; + + Logger::error("KEYMAP_FORMAT failed"); + } + } + else + Logger::error("KEYMAP_FORMAT not supported, format code: %d", format); + + close(fd); + }, + .enter = [](void *data, wl_keyboard*, uint32_t serial, + wl_surface *surface, wl_array *keys){ + + auto seat = static_cast(data); + auto surf = static_cast( + wl_surface_get_user_data(surface)); + + if (surf){ + seat->m_focused_surf = surf->m_input_hundler; + + if (seat->m_focused_surf) + seat->m_focused_surf->keyFocused(true); + } + }, + .leave = [](void *data, wl_keyboard *wl_kd, uint32_t, + wl_surface*){ + + auto seat = static_cast(data); + + if (seat->m_focused_surf){ + + seat->m_focused_surf->keyFocused(false); + seat->m_focused_surf = nullptr; + + struct itimerspec timer = {0}; + timerfd_settime(seat->key_repeat_fd, 0, &timer, NULL); + } + }, + .key = [](void *data, wl_keyboard *wl_kd, uint32_t /*serial*/, + uint32_t time, + uint32_t key, + uint32_t state){ + + auto seat = static_cast(data); + auto mapper = seat->m_keyboard.m_mapper; + + if (seat->m_focused_surf && mapper){ + + bool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); + + itimerspec timer = {0}; + + if (seat->rate != 0 && + xkb_keymap_key_repeats(mapper->keymap, key+8) && + pressed) { + + timer = { + .it_interval = {.tv_sec = 0, .tv_nsec = seat->rate}, + .it_value = {.tv_sec = 0, .tv_nsec = seat->delay}, + }; + + if (timer.it_value.tv_nsec >= 1000000000) { + timer.it_value.tv_sec += timer.it_value.tv_nsec / 1000000000; + timer.it_value.tv_nsec %= 1000000000; + } + if (timer.it_interval.tv_nsec >= 1000000000) { + timer.it_interval.tv_sec += timer.it_interval.tv_nsec / 1000000000; + timer.it_interval.tv_nsec %= 1000000000; + } + } + + Logger::debug("repeat_info %d", timer.it_interval.tv_nsec); + + timerfd_settime(seat->key_repeat_fd, 0, &timer, NULL); + + if (pressed && mapper->keySymbol(key)) + seat->emitKeypress(); + } + }, + .modifiers = [](void *data, wl_keyboard *, uint32_t /*serial*/, + uint32_t mods_depressed, //which key + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group){ + + auto mapper = static_cast(data)->m_keyboard.m_mapper; + + if (mapper) + xkb_state_update_mask(mapper->kstate, + mods_depressed, mods_latched, mods_locked, + 0, 0, group); + + }, + .repeat_info = [](void *data, wl_keyboard *wl_kd, + int32_t rate, int32_t delay){ + + auto seat = static_cast(data); + + if (seat){ + + //The protocol guarantees non-zero values, but it doesn't hurt to check. + //Just in case, in Russian + if (rate != 0 && delay != 0){ + + /** + * rate - generation speed (number of characters in sec) + * delay - number of ms during which you need to hold the key before the repeat starts + */ + seat->delay = delay * 1000000; + seat->rate = 1000000000 / rate; + } + else + Logger::error("Incorrect keyboard parameters rate = %i, delay = %i", + rate, delay); + } + } +}; + +const wl_pointer_listener Seat::pointer_listener = { + .enter = [](void *data, wl_pointer *pointer, + uint32_t serial, wl_surface *surface, + wl_fixed_t sx, wl_fixed_t sy) + { + // Happens in the case we just destroyed the surface. + if (!surface) return; + + auto seat = static_cast(data); + auto surf = static_cast( + wl_surface_get_user_data(surface)); + + assert(seat && seat->m_pointer.c_ptr() == pointer); + + if (surf){ + seat->m_hovered_surf = surf->m_input_hundler; + + if (seat->m_hovered_surf) + seat->m_hovered_surf->point(SeatListener::enter, 0, seat->m_pointer.set(sx, sy)); + } + }, + .leave = [](void *data, wl_pointer *pointer, + uint32_t serial, wl_surface *surface) + { + auto seat = static_cast(data); + + assert(seat && seat->m_pointer.c_ptr() == pointer); + + if (seat->m_hovered_surf) { + + seat->m_hovered_surf->point(SeatListener::leave, 0, seat->m_pointer); + seat->m_hovered_surf = nullptr; + } + }, + .motion = [](void *data, wl_pointer *pointer, + uint32_t time, wl_fixed_t sx, wl_fixed_t sy) + { + auto seat = static_cast(data); + + assert(seat && seat->m_pointer.c_ptr() == pointer); + + if (seat->m_hovered_surf) + seat->m_hovered_surf->point(SeatListener::motion, time, seat->m_pointer.set(sx, sy)); + }, + .button = [](void *data, wl_pointer *pointer, + uint32_t serial, uint32_t time, uint32_t button, + uint32_t state) + { + auto seat = static_cast(data); + + assert(seat && seat->m_pointer.c_ptr() == pointer); + + if (seat->m_hovered_surf) { + + /* count click */ + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + if (state == WL_POINTER_BUTTON_STATE_PRESSED){ + + if (seat->m_last_released_button == button && + now.tv_sec == seat->m_stamp && + time - seat->m_last_time <= 300) + seat->m_count_click++; + else + seat->m_count_click = 1; + + auto& key = seat->m_keyboard; + + seat->m_hovered_surf->click((Pointer::BTN)button, true, + seat->m_count_click, + key ? key.modifiers(Keyboard::ModSet::effective) : 0, + seat->m_pointer ); + } + else { + seat->m_last_released_button = button; + seat->m_last_time = time; + seat->m_stamp = now.tv_sec; + seat->m_hovered_surf->click((Pointer::BTN)button, false, 0, 0, seat->m_pointer); + } + } + }, + .axis = [](void *data, wl_pointer *pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) + { + auto seat = static_cast(data); + + assert(seat && seat->m_pointer.c_ptr() == pointer); + + if (seat->m_hovered_surf) + seat->m_hovered_surf->scroll(time, axis, wl_fixed_to_double(value)); + } +}; + +Seat::~Seat() +{ + if (key_repeat_fd >= 0) + close(key_repeat_fd); +} + +void Seat::bind(wl_registry *reg, uint32_t name, uint32_t version) noexcept +{ + registry(reg, name, 4); + + static const wl_seat_listener seat_listener = { + .capabilities = [](void *data, wl_seat *wl_seat, uint32_t flags){ + + auto seat = static_cast(data); + + if (flags & WL_SEAT_CAPABILITY_POINTER) { + auto pointer = wl_seat_get_pointer(wl_seat); + seat->m_pointer.reset(pointer); + if (wl_pointer_add_listener(pointer, &pointer_listener, seat) < 0) + Logger::error("failed to add pointer listener"); + } + else + seat->m_pointer.reset(nullptr); + + if (flags & WL_SEAT_CAPABILITY_KEYBOARD){ + auto kb = wl_seat_get_keyboard(wl_seat); + seat->m_keyboard.reset(kb); + if (wl_keyboard_add_listener(kb, &keyboard_listener, seat) < 0) + Logger::error("failed to add keyboard listener"); + } + else + seat->m_keyboard.reset(nullptr); + }, + .name = [](void*, wl_seat*, const char *name){ + Logger::debug("Seat connected, name: %s", name); + } + }; + + if (wl_seat_add_listener(c_ptr(), &seat_listener, this) < 0) + Logger::error("failed to add seat listener"); +} + +Viewport::Viewport(Viewporter const *vpr, NativeSurface const &surface) + :Base(vpr ? wp_viewporter_get_viewport(vpr->c_ptr(), surface.c_ptr()) : nullptr) +{} + +} + diff --git a/examples/host/linux/wayland/core.h b/examples/host/linux/wayland/core.h new file mode 100644 index 00000000..8eafbe8d --- /dev/null +++ b/examples/host/linux/wayland/core.h @@ -0,0 +1,266 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "fractional-scale-v1-client-protocol.h" +#include "viewporter-client-protocol.h" + +namespace WL +{ + +template +class ProxyBase +{ +public: + ~ProxyBase() + { + if (m_ptr) + wl_proxy_marshal_flags(m_ptr, DCode, NULL, + version(), WL_MARSHAL_FLAG_DESTROY); + } + + inline operator bool() const noexcept + {return m_ptr != nullptr;} + + inline uint32_t version() const noexcept + {return wl_proxy_get_version((wl_proxy*)m_ptr);} + +protected: + ProxyBase():m_ptr(nullptr){} + + template + ProxyBase(T* ptr):m_ptr((wl_proxy*)ptr){} + + ProxyBase(ProxyBase const&) = delete; + ProxyBase& operator=(ProxyBase const&) = delete; + + ProxyBase(ProxyBase&& other): + m_ptr(other.m_ptr) + { + other.m_ptr = nullptr; + } + + wl_proxy* m_ptr; +}; + +class ProtocolBase +{ +public: + virtual void bind(wl_registry *reg, uint32_t name, uint32_t version) noexcept = 0; +}; + +template +class Protocol: public ProtocolBase, public ProxyBase +{ +public: + constexpr static const wl_interface* iface(){return I;} + + Protocol() = default; + + Protocol(Protocol&& other) = default; + Protocol& operator=(Protocol&&) = delete; + + void bind(wl_registry *reg, uint32_t name, uint32_t version) noexcept override + { registry(reg, name, version);} + + inline T* c_ptr() const noexcept + { return (T*) this->m_ptr; } + +protected: + void registry(wl_registry *reg, uint32_t name, uint32_t version) noexcept + { this->m_ptr = static_cast(wl_registry_bind(reg, name, I, version)); } +}; + +template +class Proxy: public ProxyBase +{ +public: + Proxy() = default; + explicit Proxy(T* p):ProxyBase(p){} + + Proxy(T* p, const char* msg): ProxyBase(p) + { if (!p) throw std::runtime_error(msg); } + + Proxy(Proxy&& other) = default; + Proxy& operator=(Proxy&& other) + { + ~Proxy(); + this->m_ptr = other.m_ptr; + other.m_ptr = nullptr; + + return *this; + } + + inline void reset(T* ptr) noexcept + { + ~Proxy(); + this->m_ptr = (wl_proxy*)ptr; + } + + inline T* c_ptr() const noexcept + {return (T*) this->m_ptr;} + +protected: + using Base = Proxy; +}; + +class Keyboard: public Proxy +{ +public: + ~Keyboard(); + + enum ModSet {locked, effective, consumed}; + + unsigned modifiers(ModSet group) const; + const char *utf8() const; + uint32_t symbol() const; + +private: + struct KeyMapper; + KeyMapper* m_mapper{nullptr}; + + friend class Seat; +}; + +class Pointer: public Proxy +{ +public: + std::pair toInt() const + { + return {wl_fixed_to_int(m_x), + wl_fixed_to_int(m_y)}; + } + + std::pair toDouble() const + { + return {wl_fixed_to_double(m_x), + wl_fixed_to_double(m_y)}; + } + + bool inBound(int sx, int sy, int sw, int sh) const + { + auto [x, y] = toInt(); + return sx > x && sw < x && sy > y && sh < y; + } + + //from input-event-codes.h + //зависит от платформы, хотя на Linux и FreeBSD одинаковые + enum BTN { + LEFT = 0x110, + RIGHT = 0x111, + MIDDLE = 0x112, + SIDE = 0x113, + EXTRA = 0x114, + FORWARD = 0x115, + BACK = 0x116, + ASK = 0x117 + }; + +private: + wl_fixed_t m_x{0}, m_y{0}; + + const Pointer& set(wl_fixed_t x, wl_fixed_t y) + {m_x = x; m_y = y; return *this;} + + friend class Seat; +}; + +class SeatListener +{ +public: + virtual void keyFocused(bool) = 0; + virtual void key(Keyboard const&) = 0; + + enum PointerState { enter, leave, motion }; + virtual void point(PointerState, uint32_t /*serial*/, Pointer const&) = 0; + + virtual void click(Pointer::BTN /*button*/ , + bool /*pressed*/, + int /*count*/, + unsigned /*key_mod*/, + Pointer const&) = 0; + virtual void scroll(int time, int axis, double value) = 0; +}; + +class Seat final: public Protocol +{ +public: + ~Seat(); + void bind(wl_registry *reg, uint32_t name, uint32_t version) noexcept override; + +private: + Keyboard m_keyboard; + SeatListener *m_focused_surf = nullptr; + static const wl_keyboard_listener keyboard_listener; + int key_repeat_fd{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)}; + uint32_t delay {0}; + uint32_t rate {0}; + void emitKeypress() const; + + friend class Display; + + Pointer m_pointer; + SeatListener *m_hovered_surf = nullptr; + static const wl_pointer_listener pointer_listener; + + //double click handling + uint32_t m_last_time = 0; + std::time_t m_stamp; + uint32_t m_last_released_button = 0; + int m_count_click = 0; +}; + +using FractionalScaleManager = Protocol; + +class Surface: public Proxy +{ +public: + Surface(wl_compositor *compositor, + const FractionalScaleManager *manager); + + inline void listenerInput(SeatListener &input) + { m_input_hundler = &input;} + + inline void commit() + { wl_surface_commit(c_ptr()); } + +protected: + void setAreaOpaque(wl_compositor *compositor, int32_t w, int32_t h) const; + + float m_scale; + + virtual void draw(float /*scale*/) = 0; + virtual void buffer_scale(float /*scale*/) = 0; + +private: + Proxy m_fscale; + + SeatListener *m_input_hundler; + friend class Seat; +}; + +using Viewporter = Protocol; + +class Viewport final: public Proxy +{ +public: + Viewport(const WL::Viewporter *vpr, Surface const &surface); + Viewport() = default; + + void setDestination(int32_t width, int32_t height) + {wp_viewport_set_destination(c_ptr(), width, height);} +}; + +} + + diff --git a/examples/host/linux/wayland/display.cpp b/examples/host/linux/wayland/display.cpp new file mode 100644 index 00000000..aa0f6587 --- /dev/null +++ b/examples/host/linux/wayland/display.cpp @@ -0,0 +1,120 @@ +#include "display.h" + +#include + +using namespace WL; + +Display::Display(const char *dpy_name, std::unique_ptr &&protocols) + : m_display(wl_display_connect(dpy_name)) + , m_compositor(nullptr) + , m_protocols(std::move(protocols)) +{ + if (!m_display) + throw std::runtime_error("display does not exist"); + + static const wl_registry_listener lsr = { + .global = [](void *data, + wl_registry *registry, + uint32_t name, + const char *interface, + uint32_t version) + { + auto dpy = static_cast(data); + + if (strcmp(interface, wl_compositor_interface.name) == 0) + dpy->m_compositor.reset( + (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, version)); + else + if (auto item = dpy->m_protocols->find(interface)) + item->bind(registry, name, version); + + }, + .global_remove = [](void*, wl_registry*, uint32_t){ + //To do global remove + } + }; + + auto registry = wl_display_get_registry(m_display.get()); + + if (!registry || wl_registry_add_listener(registry, &lsr, this) < 0) + throw std::runtime_error("add registry listener failed"); + + + wl_display_roundtrip(m_display.get()); + wl_registry_destroy(registry); + + if (!m_compositor) + throw std::runtime_error("wayland compositor not found"); + + m_fds[EventT::wayland].fd = wl_display_get_fd(m_display.get()); + m_fds[EventT::wayland].events = POLLIN; + m_fds[EventT::system].fd = -1; //To do add system interrupts + + m_seat = protocol(); + m_fds[EventT::key].fd = m_seat ? m_seat->key_repeat_fd : -1; + m_fds[EventT::key].events = POLLIN; +} + +void Display::event_wait() +{ + auto display = c_ptr(); + + while (wl_display_prepare_read(display) != 0) { + if (wl_display_dispatch_pending(display) < 0) + throw std::runtime_error("failed to dispatch pending Wayland events"); + } + + int ret; + + while ((ret = wl_display_flush(display)) < 0) { + if (errno == EINTR) { + continue; + } + + if (errno == EAGAIN) { + struct pollfd fds[1]; + fds[0].fd = m_fds[EventT::wayland].fd; + fds[0].events = POLLOUT; + + do { + ret = poll(fds, 1, -1); + } while (ret < 0 && errno == EINTR); + } + } + + if (ret < 0) { + wl_display_cancel_read(display); + throw std::runtime_error("failed to display flush"); + } + + do { + ret = poll(m_fds, EventT::count - 1, -1); //To do add system interrupts + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + if (m_fds[0].revents & POLLHUP) + throw std::runtime_error("disconnected from wayland"); + + wl_display_cancel_read(display); + throw std::runtime_error("failed to poll():"); + } + + if ((m_fds[0].revents & POLLIN)) { + + if (wl_display_read_events(display) < 0) + throw std::runtime_error("failed to read Wayland events"); + } + else + wl_display_cancel_read(display); + + if (wl_display_dispatch_pending(display) < 0) + throw std::runtime_error("failed to dispatch pending Wayland events"); + + if (m_fds[1].revents & POLLIN) { + uint64_t repeats; + if (read(m_fds[1].fd, &repeats, sizeof(repeats)) == 8) { + for (uint64_t i = 0; i < repeats; i++) + m_seat->emitKeypress(); + } + } +} diff --git a/examples/host/linux/wayland/display.h b/examples/host/linux/wayland/display.h new file mode 100644 index 00000000..8f016e65 --- /dev/null +++ b/examples/host/linux/wayland/display.h @@ -0,0 +1,140 @@ +#ifndef DISPLAY_H +#define DISPLAY_H + +#include +#include +#include +#include +#include + +#include + +#include "core.h" + +namespace WL { + +class ProtocolContainer +{ +public: + virtual ~ProtocolContainer() = default; + virtual ProtocolBase* find(const char*) noexcept = 0; + virtual const ProtocolBase* find(const wl_interface*) noexcept = 0; +}; + +template +class ProtocolTuple final: public ProtocolContainer +{ + std::tuple m_gb; + + template + void tuple_find(F &&f) noexcept + { + std::apply([&f](auto &...e) { + (std::forward(f)(e, e.iface()) || ...); + }, m_gb); + } + +public: + ProtocolBase* find(const char* str) noexcept override + { + ProtocolBase* result = nullptr; + tuple_find([str, &result](ProtocolBase& gb, + const wl_interface* ifc){ + if (strcmp(str, ifc->name) == 0){ + result = &gb; return true; + } + return false; + }); + + return result; + } + + const ProtocolBase* find(const wl_interface* iface) noexcept override + { + ProtocolBase* result = nullptr; + tuple_find([iface, &result](ProtocolBase& gb, + const wl_interface* ifc){ + if (iface == ifc){ + result = &gb; return true; + } + return false; + }); + + return result; + } + + virtual ~ProtocolTuple() + { + std::cerr<<"~GlobalTuple"< + static Display create_default() + { + return Display(nullptr, std::make_unique>()); + } + + Display(Display const&) = delete; + Display& operator=(Display const&) = delete; + Display(Display&& other) = default; + Display& operator=(Display&&) = delete; + + Display(const char *name, std::unique_ptr &&protocols); + + void event_wait(); + + wl_display* c_ptr() const {return m_display.get();} + wl_compositor* compositor() const {return m_compositor.get();} + + template + const G* protocol() const + { + if (auto search = m_protocols->find(G::iface())) + return static_cast(search); + + return nullptr; + } + + template + const G& ensureProtocol() const + { + if (auto search = m_protocols->find(G::iface())) + return *static_cast(search); + + std::string err("protocol not found: "); + throw std::runtime_error(err + G::iface()->name); + } + +private: + + struct Deleter + { + void operator()(wl_display* data) const + {wl_display_disconnect(data);} + + void operator()(wl_compositor* data) const + {wl_proxy_destroy((wl_proxy*) data);} + }; + + std::unique_ptr m_display; + std::unique_ptr m_compositor; + + const Seat *m_seat; + + std::unique_ptr m_protocols; + + enum EventT + {wayland, key, system, count}; + + pollfd m_fds[EventT::count]; +}; + +} + +#endif // DISPLAY_H diff --git a/examples/host/linux/wayland/fractional-scale-v1-client-protocol.h b/examples/host/linux/wayland/fractional-scale-v1-client-protocol.h new file mode 100644 index 00000000..8df7558a --- /dev/null +++ b/examples/host/linux/wayland/fractional-scale-v1-client-protocol.h @@ -0,0 +1,264 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H +#define FRACTIONAL_SCALE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_fractional_scale_v1 The fractional_scale_v1 protocol + * Protocol for requesting fractional surface scales + * + * @section page_desc_fractional_scale_v1 Description + * + * This protocol allows a compositor to suggest for surfaces to render at + * fractional scales. + * + * A client can submit scaled content by utilizing wp_viewport. This is done by + * creating a wp_viewport object for the surface and setting the destination + * rectangle to the surface size before the scale factor is applied. + * + * The buffer size is calculated by multiplying the surface size by the + * intended scale. + * + * The wl_surface buffer scale should remain set to 1. + * + * If a surface has a surface-local size of 100 px by 50 px and wishes to + * submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should + * be used and the wp_viewport destination rectangle should be 100 px by 50 px. + * + * For toplevel surfaces, the size is rounded halfway away from zero. The + * rounding algorithm for subsurface position and size is not defined. + * + * @section page_ifaces_fractional_scale_v1 Interfaces + * - @subpage page_iface_wp_fractional_scale_manager_v1 - fractional surface scale information + * - @subpage page_iface_wp_fractional_scale_v1 - fractional scale interface to a wl_surface + * @section page_copyright_fractional_scale_v1 Copyright + *
+ *
+ * Copyright © 2022 Kenny Levinsen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_fractional_scale_manager_v1; +struct wp_fractional_scale_v1; + +#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE +#define WP_FRACTIONAL_SCALE_MANAGER_V1_INTERFACE +/** + * @page page_iface_wp_fractional_scale_manager_v1 wp_fractional_scale_manager_v1 + * @section page_iface_wp_fractional_scale_manager_v1_desc Description + * + * A global interface for requesting surfaces to use fractional scales. + * @section page_iface_wp_fractional_scale_manager_v1_api API + * See @ref iface_wp_fractional_scale_manager_v1. + */ +/** + * @defgroup iface_wp_fractional_scale_manager_v1 The wp_fractional_scale_manager_v1 interface + * + * A global interface for requesting surfaces to use fractional scales. + */ +extern const struct wl_interface wp_fractional_scale_manager_v1_interface; +#endif +#ifndef WP_FRACTIONAL_SCALE_V1_INTERFACE +#define WP_FRACTIONAL_SCALE_V1_INTERFACE +/** + * @page page_iface_wp_fractional_scale_v1 wp_fractional_scale_v1 + * @section page_iface_wp_fractional_scale_v1_desc Description + * + * An additional interface to a wl_surface object which allows the compositor + * to inform the client of the preferred scale. + * @section page_iface_wp_fractional_scale_v1_api API + * See @ref iface_wp_fractional_scale_v1. + */ +/** + * @defgroup iface_wp_fractional_scale_v1 The wp_fractional_scale_v1 interface + * + * An additional interface to a wl_surface object which allows the compositor + * to inform the client of the preferred scale. + */ +extern const struct wl_interface wp_fractional_scale_v1_interface; +#endif + +#ifndef WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM +#define WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM +enum wp_fractional_scale_manager_v1_error { + /** + * the surface already has a fractional_scale object associated + */ + WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS = 0, +}; +#endif /* WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_ENUM */ + +#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY 0 +#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE 1 + + +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + */ +#define WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + */ +#define WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE_SINCE_VERSION 1 + +/** @ingroup iface_wp_fractional_scale_manager_v1 */ +static inline void +wp_fractional_scale_manager_v1_set_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1, user_data); +} + +/** @ingroup iface_wp_fractional_scale_manager_v1 */ +static inline void * +wp_fractional_scale_manager_v1_get_user_data(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_manager_v1); +} + +static inline uint32_t +wp_fractional_scale_manager_v1_get_version(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1); +} + +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + * + * Informs the server that the client will not be using this protocol + * object anymore. This does not affect any other objects, + * wp_fractional_scale_v1 objects included. + */ +static inline void +wp_fractional_scale_manager_v1_destroy(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, + WP_FRACTIONAL_SCALE_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_fractional_scale_manager_v1 + * + * Create an add-on object for the the wl_surface to let the compositor + * request fractional scales. If the given wl_surface already has a + * wp_fractional_scale_v1 object associated, the fractional_scale_exists + * protocol error is raised. + */ +static inline struct wp_fractional_scale_v1 * +wp_fractional_scale_manager_v1_get_fractional_scale(struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_manager_v1, + WP_FRACTIONAL_SCALE_MANAGER_V1_GET_FRACTIONAL_SCALE, &wp_fractional_scale_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_manager_v1), 0, NULL, surface); + + return (struct wp_fractional_scale_v1 *) id; +} + +/** + * @ingroup iface_wp_fractional_scale_v1 + * @struct wp_fractional_scale_v1_listener + */ +struct wp_fractional_scale_v1_listener { + /** + * notify of new preferred scale + * + * Notification of a new preferred scale for this surface that + * the compositor suggests that the client should use. + * + * The sent scale is the numerator of a fraction with a denominator + * of 120. + * @param scale the new preferred scale + */ + void (*preferred_scale)(void *data, + struct wp_fractional_scale_v1 *wp_fractional_scale_v1, + uint32_t scale); +}; + +/** + * @ingroup iface_wp_fractional_scale_v1 + */ +static inline int +wp_fractional_scale_v1_add_listener(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, + const struct wp_fractional_scale_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_fractional_scale_v1, + (void (**)(void)) listener, data); +} + +#define WP_FRACTIONAL_SCALE_V1_DESTROY 0 + +/** + * @ingroup iface_wp_fractional_scale_v1 + */ +#define WP_FRACTIONAL_SCALE_V1_PREFERRED_SCALE_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_fractional_scale_v1 + */ +#define WP_FRACTIONAL_SCALE_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_fractional_scale_v1 */ +static inline void +wp_fractional_scale_v1_set_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_fractional_scale_v1, user_data); +} + +/** @ingroup iface_wp_fractional_scale_v1 */ +static inline void * +wp_fractional_scale_v1_get_user_data(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_fractional_scale_v1); +} + +static inline uint32_t +wp_fractional_scale_v1_get_version(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1); +} + +/** + * @ingroup iface_wp_fractional_scale_v1 + * + * Destroy the fractional scale object. When this object is destroyed, + * preferred_scale events will no longer be sent. + */ +static inline void +wp_fractional_scale_v1_destroy(struct wp_fractional_scale_v1 *wp_fractional_scale_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_fractional_scale_v1, + WP_FRACTIONAL_SCALE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_fractional_scale_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/host/linux/wayland/fractional-scale-v1-protocol.c b/examples/host/linux/wayland/fractional-scale-v1-protocol.c new file mode 100644 index 00000000..f847c1ea --- /dev/null +++ b/examples/host/linux/wayland/fractional-scale-v1-protocol.c @@ -0,0 +1,74 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2022 Kenny Levinsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_fractional_scale_v1_interface; + +static const struct wl_interface *fractional_scale_v1_types[] = { + NULL, + &wp_fractional_scale_v1_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_fractional_scale_manager_v1_requests[] = { + { "destroy", "", fractional_scale_v1_types + 0 }, + { "get_fractional_scale", "no", fractional_scale_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface wp_fractional_scale_manager_v1_interface = { + "wp_fractional_scale_manager_v1", 1, + 2, wp_fractional_scale_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_fractional_scale_v1_requests[] = { + { "destroy", "", fractional_scale_v1_types + 0 }, +}; + +static const struct wl_message wp_fractional_scale_v1_events[] = { + { "preferred_scale", "u", fractional_scale_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_fractional_scale_v1_interface = { + "wp_fractional_scale_v1", 1, + 1, wp_fractional_scale_v1_requests, + 1, wp_fractional_scale_v1_events, +}; + diff --git a/examples/host/linux/wayland/tablet-unstable-v2-client-protocol.h b/examples/host/linux/wayland/tablet-unstable-v2-client-protocol.h new file mode 100644 index 00000000..38629f22 --- /dev/null +++ b/examples/host/linux/wayland/tablet-unstable-v2-client-protocol.h @@ -0,0 +1,2252 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef TABLET_UNSTABLE_V2_CLIENT_PROTOCOL_H +#define TABLET_UNSTABLE_V2_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_tablet_unstable_v2 The tablet_unstable_v2 protocol + * Wayland protocol for graphics tablets + * + * @section page_desc_tablet_unstable_v2 Description + * + * This description provides a high-level overview of the interplay between + * the interfaces defined this protocol. For details, see the protocol + * specification. + * + * More than one tablet may exist, and device-specifics matter. Tablets are + * not represented by a single virtual device like wl_pointer. A client + * binds to the tablet manager object which is just a proxy object. From + * that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat) + * and that returns the actual interface that has all the tablets. With + * this indirection, we can avoid merging wp_tablet into the actual Wayland + * protocol, a long-term benefit. + * + * The wp_tablet_seat sends a "tablet added" event for each tablet + * connected. That event is followed by descriptive events about the + * hardware; currently that includes events for name, vid/pid and + * a wp_tablet.path event that describes a local path. This path can be + * used to uniquely identify a tablet or get more information through + * libwacom. Emulated or nested tablets can skip any of those, e.g. a + * virtual tablet may not have a vid/pid. The sequence of descriptive + * events is terminated by a wp_tablet.done event to signal that a client + * may now finalize any initialization for that tablet. + * + * Events from tablets require a tool in proximity. Tools are also managed + * by the tablet seat; a "tool added" event is sent whenever a tool is new + * to the compositor. That event is followed by a number of descriptive + * events about the hardware; currently that includes capabilities, + * hardware id and serial number, and tool type. Similar to the tablet + * interface, a wp_tablet_tool.done event is sent to terminate that initial + * sequence. + * + * Any event from a tool happens on the wp_tablet_tool interface. When the + * tool gets into proximity of the tablet, a proximity_in event is sent on + * the wp_tablet_tool interface, listing the tablet and the surface. That + * event is followed by a motion event with the coordinates. After that, + * it's the usual motion, axis, button, etc. events. The protocol's + * serialisation means events are grouped by wp_tablet_tool.frame events. + * + * Two special events (that don't exist in X) are down and up. They signal + * "tip touching the surface". For tablets without real proximity + * detection, the sequence is: proximity_in, motion, down, frame. + * + * When the tool leaves proximity, a proximity_out event is sent. If any + * button is still down, a button release event is sent before this + * proximity event. These button events are sent in the same frame as the + * proximity event to signal to the client that the buttons were held when + * the tool left proximity. + * + * If the tool moves out of the surface but stays in proximity (i.e. + * between windows), compositor-specific grab policies apply. This usually + * means that the proximity-out is delayed until all buttons are released. + * + * Moving a tool physically from one tablet to the other has no real effect + * on the protocol, since we already have the tool object from the "tool + * added" event. All the information is already there and the proximity + * events on both tablets are all a client needs to reconstruct what + * happened. + * + * Some extra axes are normalized, i.e. the client knows the range as + * specified in the protocol (e.g. [0, 65535]), the granularity however is + * unknown. The current normalized axes are pressure, distance, and slider. + * + * Other extra axes are in physical units as specified in the protocol. + * The current extra axes with physical units are tilt, rotation and + * wheel rotation. + * + * Since tablets work independently of the pointer controlled by the mouse, + * the focus handling is independent too and controlled by proximity. + * The wp_tablet_tool.set_cursor request sets a tool-specific cursor. + * This cursor surface may be the same as the mouse cursor, and it may be + * the same across tools but it is possible to be more fine-grained. For + * example, a client may set different cursors for the pen and eraser. + * + * Tools are generally independent of tablets and it is + * compositor-specific policy when a tool can be removed. Common approaches + * will likely include some form of removing a tool when all tablets the + * tool was used on are removed. + * + * Disclaimer: This protocol extension has been marked stable. This copy is + * no longer used and only retained for backwards compatibility. The + * canonical version can be found in the stable/ directory. + * + * @section page_ifaces_tablet_unstable_v2 Interfaces + * - @subpage page_iface_zwp_tablet_manager_v2 - controller object for graphic tablet devices + * - @subpage page_iface_zwp_tablet_seat_v2 - controller object for graphic tablet devices of a seat + * - @subpage page_iface_zwp_tablet_tool_v2 - a physical tablet tool + * - @subpage page_iface_zwp_tablet_v2 - graphics tablet device + * - @subpage page_iface_zwp_tablet_pad_ring_v2 - pad ring + * - @subpage page_iface_zwp_tablet_pad_strip_v2 - pad strip + * - @subpage page_iface_zwp_tablet_pad_group_v2 - a set of buttons, rings and strips + * - @subpage page_iface_zwp_tablet_pad_v2 - a set of buttons, rings and strips + * @section page_copyright_tablet_unstable_v2 Copyright + *
+ *
+ * Copyright 2014 © Stephen "Lyude" Chandler Paul
+ * Copyright 2015-2016 © Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ */ +struct wl_seat; +struct wl_surface; +struct zwp_tablet_manager_v2; +struct zwp_tablet_pad_group_v2; +struct zwp_tablet_pad_ring_v2; +struct zwp_tablet_pad_strip_v2; +struct zwp_tablet_pad_v2; +struct zwp_tablet_seat_v2; +struct zwp_tablet_tool_v2; +struct zwp_tablet_v2; + +#ifndef ZWP_TABLET_MANAGER_V2_INTERFACE +#define ZWP_TABLET_MANAGER_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_manager_v2 zwp_tablet_manager_v2 + * @section page_iface_zwp_tablet_manager_v2_desc Description + * + * An object that provides access to the graphics tablets available on this + * system. All tablets are associated with a seat, to get access to the + * actual tablets, use wp_tablet_manager.get_tablet_seat. + * @section page_iface_zwp_tablet_manager_v2_api API + * See @ref iface_zwp_tablet_manager_v2. + */ +/** + * @defgroup iface_zwp_tablet_manager_v2 The zwp_tablet_manager_v2 interface + * + * An object that provides access to the graphics tablets available on this + * system. All tablets are associated with a seat, to get access to the + * actual tablets, use wp_tablet_manager.get_tablet_seat. + */ +extern const struct wl_interface zwp_tablet_manager_v2_interface; +#endif +#ifndef ZWP_TABLET_SEAT_V2_INTERFACE +#define ZWP_TABLET_SEAT_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_seat_v2 zwp_tablet_seat_v2 + * @section page_iface_zwp_tablet_seat_v2_desc Description + * + * An object that provides access to the graphics tablets available on this + * seat. After binding to this interface, the compositor sends a set of + * wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events. + * @section page_iface_zwp_tablet_seat_v2_api API + * See @ref iface_zwp_tablet_seat_v2. + */ +/** + * @defgroup iface_zwp_tablet_seat_v2 The zwp_tablet_seat_v2 interface + * + * An object that provides access to the graphics tablets available on this + * seat. After binding to this interface, the compositor sends a set of + * wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events. + */ +extern const struct wl_interface zwp_tablet_seat_v2_interface; +#endif +#ifndef ZWP_TABLET_TOOL_V2_INTERFACE +#define ZWP_TABLET_TOOL_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_tool_v2 zwp_tablet_tool_v2 + * @section page_iface_zwp_tablet_tool_v2_desc Description + * + * An object that represents a physical tool that has been, or is + * currently in use with a tablet in this seat. Each wp_tablet_tool + * object stays valid until the client destroys it; the compositor + * reuses the wp_tablet_tool object to indicate that the object's + * respective physical tool has come into proximity of a tablet again. + * + * A wp_tablet_tool object's relation to a physical tool depends on the + * tablet's ability to report serial numbers. If the tablet supports + * this capability, then the object represents a specific physical tool + * and can be identified even when used on multiple tablets. + * + * A tablet tool has a number of static characteristics, e.g. tool type, + * hardware_serial and capabilities. These capabilities are sent in an + * event sequence after the wp_tablet_seat.tool_added event before any + * actual events from this tool. This initial event sequence is + * terminated by a wp_tablet_tool.done event. + * + * Tablet tool events are grouped by wp_tablet_tool.frame events. + * Any events received before a wp_tablet_tool.frame event should be + * considered part of the same hardware state change. + * @section page_iface_zwp_tablet_tool_v2_api API + * See @ref iface_zwp_tablet_tool_v2. + */ +/** + * @defgroup iface_zwp_tablet_tool_v2 The zwp_tablet_tool_v2 interface + * + * An object that represents a physical tool that has been, or is + * currently in use with a tablet in this seat. Each wp_tablet_tool + * object stays valid until the client destroys it; the compositor + * reuses the wp_tablet_tool object to indicate that the object's + * respective physical tool has come into proximity of a tablet again. + * + * A wp_tablet_tool object's relation to a physical tool depends on the + * tablet's ability to report serial numbers. If the tablet supports + * this capability, then the object represents a specific physical tool + * and can be identified even when used on multiple tablets. + * + * A tablet tool has a number of static characteristics, e.g. tool type, + * hardware_serial and capabilities. These capabilities are sent in an + * event sequence after the wp_tablet_seat.tool_added event before any + * actual events from this tool. This initial event sequence is + * terminated by a wp_tablet_tool.done event. + * + * Tablet tool events are grouped by wp_tablet_tool.frame events. + * Any events received before a wp_tablet_tool.frame event should be + * considered part of the same hardware state change. + */ +extern const struct wl_interface zwp_tablet_tool_v2_interface; +#endif +#ifndef ZWP_TABLET_V2_INTERFACE +#define ZWP_TABLET_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_v2 zwp_tablet_v2 + * @section page_iface_zwp_tablet_v2_desc Description + * + * The wp_tablet interface represents one graphics tablet device. The + * tablet interface itself does not generate events; all events are + * generated by wp_tablet_tool objects when in proximity above a tablet. + * + * A tablet has a number of static characteristics, e.g. device name and + * pid/vid. These capabilities are sent in an event sequence after the + * wp_tablet_seat.tablet_added event. This initial event sequence is + * terminated by a wp_tablet.done event. + * @section page_iface_zwp_tablet_v2_api API + * See @ref iface_zwp_tablet_v2. + */ +/** + * @defgroup iface_zwp_tablet_v2 The zwp_tablet_v2 interface + * + * The wp_tablet interface represents one graphics tablet device. The + * tablet interface itself does not generate events; all events are + * generated by wp_tablet_tool objects when in proximity above a tablet. + * + * A tablet has a number of static characteristics, e.g. device name and + * pid/vid. These capabilities are sent in an event sequence after the + * wp_tablet_seat.tablet_added event. This initial event sequence is + * terminated by a wp_tablet.done event. + */ +extern const struct wl_interface zwp_tablet_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_RING_V2_INTERFACE +#define ZWP_TABLET_PAD_RING_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_ring_v2 zwp_tablet_pad_ring_v2 + * @section page_iface_zwp_tablet_pad_ring_v2_desc Description + * + * A circular interaction area, such as the touch ring on the Wacom Intuos + * Pro series tablets. + * + * Events on a ring are logically grouped by the wl_tablet_pad_ring.frame + * event. + * @section page_iface_zwp_tablet_pad_ring_v2_api API + * See @ref iface_zwp_tablet_pad_ring_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_ring_v2 The zwp_tablet_pad_ring_v2 interface + * + * A circular interaction area, such as the touch ring on the Wacom Intuos + * Pro series tablets. + * + * Events on a ring are logically grouped by the wl_tablet_pad_ring.frame + * event. + */ +extern const struct wl_interface zwp_tablet_pad_ring_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_STRIP_V2_INTERFACE +#define ZWP_TABLET_PAD_STRIP_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_strip_v2 zwp_tablet_pad_strip_v2 + * @section page_iface_zwp_tablet_pad_strip_v2_desc Description + * + * A linear interaction area, such as the strips found in Wacom Cintiq + * models. + * + * Events on a strip are logically grouped by the wl_tablet_pad_strip.frame + * event. + * @section page_iface_zwp_tablet_pad_strip_v2_api API + * See @ref iface_zwp_tablet_pad_strip_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_strip_v2 The zwp_tablet_pad_strip_v2 interface + * + * A linear interaction area, such as the strips found in Wacom Cintiq + * models. + * + * Events on a strip are logically grouped by the wl_tablet_pad_strip.frame + * event. + */ +extern const struct wl_interface zwp_tablet_pad_strip_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_GROUP_V2_INTERFACE +#define ZWP_TABLET_PAD_GROUP_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_group_v2 zwp_tablet_pad_group_v2 + * @section page_iface_zwp_tablet_pad_group_v2_desc Description + * + * A pad group describes a distinct (sub)set of buttons, rings and strips + * present in the tablet. The criteria of this grouping is usually positional, + * eg. if a tablet has buttons on the left and right side, 2 groups will be + * presented. The physical arrangement of groups is undisclosed and may + * change on the fly. + * + * Pad groups will announce their features during pad initialization. Between + * the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the + * pad group will announce the buttons, rings and strips contained in it, + * plus the number of supported modes. + * + * Modes are a mechanism to allow multiple groups of actions for every element + * in the pad group. The number of groups and available modes in each is + * persistent across device plugs. The current mode is user-switchable, it + * will be announced through the wp_tablet_pad_group.mode_switch event both + * whenever it is switched, and after wp_tablet_pad.enter. + * + * The current mode logically applies to all elements in the pad group, + * although it is at clients' discretion whether to actually perform different + * actions, and/or issue the respective .set_feedback requests to notify the + * compositor. See the wp_tablet_pad_group.mode_switch event for more details. + * @section page_iface_zwp_tablet_pad_group_v2_api API + * See @ref iface_zwp_tablet_pad_group_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_group_v2 The zwp_tablet_pad_group_v2 interface + * + * A pad group describes a distinct (sub)set of buttons, rings and strips + * present in the tablet. The criteria of this grouping is usually positional, + * eg. if a tablet has buttons on the left and right side, 2 groups will be + * presented. The physical arrangement of groups is undisclosed and may + * change on the fly. + * + * Pad groups will announce their features during pad initialization. Between + * the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the + * pad group will announce the buttons, rings and strips contained in it, + * plus the number of supported modes. + * + * Modes are a mechanism to allow multiple groups of actions for every element + * in the pad group. The number of groups and available modes in each is + * persistent across device plugs. The current mode is user-switchable, it + * will be announced through the wp_tablet_pad_group.mode_switch event both + * whenever it is switched, and after wp_tablet_pad.enter. + * + * The current mode logically applies to all elements in the pad group, + * although it is at clients' discretion whether to actually perform different + * actions, and/or issue the respective .set_feedback requests to notify the + * compositor. See the wp_tablet_pad_group.mode_switch event for more details. + */ +extern const struct wl_interface zwp_tablet_pad_group_v2_interface; +#endif +#ifndef ZWP_TABLET_PAD_V2_INTERFACE +#define ZWP_TABLET_PAD_V2_INTERFACE +/** + * @page page_iface_zwp_tablet_pad_v2 zwp_tablet_pad_v2 + * @section page_iface_zwp_tablet_pad_v2_desc Description + * + * A pad device is a set of buttons, rings and strips + * usually physically present on the tablet device itself. Some + * exceptions exist where the pad device is physically detached, e.g. the + * Wacom ExpressKey Remote. + * + * Pad devices have no axes that control the cursor and are generally + * auxiliary devices to the tool devices used on the tablet surface. + * + * A pad device has a number of static characteristics, e.g. the number + * of rings. These capabilities are sent in an event sequence after the + * wp_tablet_seat.pad_added event before any actual events from this pad. + * This initial event sequence is terminated by a wp_tablet_pad.done + * event. + * + * All pad features (buttons, rings and strips) are logically divided into + * groups and all pads have at least one group. The available groups are + * notified through the wp_tablet_pad.group event; the compositor will + * emit one event per group before emitting wp_tablet_pad.done. + * + * Groups may have multiple modes. Modes allow clients to map multiple + * actions to a single pad feature. Only one mode can be active per group, + * although different groups may have different active modes. + * @section page_iface_zwp_tablet_pad_v2_api API + * See @ref iface_zwp_tablet_pad_v2. + */ +/** + * @defgroup iface_zwp_tablet_pad_v2 The zwp_tablet_pad_v2 interface + * + * A pad device is a set of buttons, rings and strips + * usually physically present on the tablet device itself. Some + * exceptions exist where the pad device is physically detached, e.g. the + * Wacom ExpressKey Remote. + * + * Pad devices have no axes that control the cursor and are generally + * auxiliary devices to the tool devices used on the tablet surface. + * + * A pad device has a number of static characteristics, e.g. the number + * of rings. These capabilities are sent in an event sequence after the + * wp_tablet_seat.pad_added event before any actual events from this pad. + * This initial event sequence is terminated by a wp_tablet_pad.done + * event. + * + * All pad features (buttons, rings and strips) are logically divided into + * groups and all pads have at least one group. The available groups are + * notified through the wp_tablet_pad.group event; the compositor will + * emit one event per group before emitting wp_tablet_pad.done. + * + * Groups may have multiple modes. Modes allow clients to map multiple + * actions to a single pad feature. Only one mode can be active per group, + * although different groups may have different active modes. + */ +extern const struct wl_interface zwp_tablet_pad_v2_interface; +#endif + +#define ZWP_TABLET_MANAGER_V2_GET_TABLET_SEAT 0 +#define ZWP_TABLET_MANAGER_V2_DESTROY 1 + + +/** + * @ingroup iface_zwp_tablet_manager_v2 + */ +#define ZWP_TABLET_MANAGER_V2_GET_TABLET_SEAT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_manager_v2 + */ +#define ZWP_TABLET_MANAGER_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_manager_v2 */ +static inline void +zwp_tablet_manager_v2_set_user_data(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_manager_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_manager_v2 */ +static inline void * +zwp_tablet_manager_v2_get_user_data(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_manager_v2); +} + +static inline uint32_t +zwp_tablet_manager_v2_get_version(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_manager_v2); +} + +/** + * @ingroup iface_zwp_tablet_manager_v2 + * + * Get the wp_tablet_seat object for the given seat. This object + * provides access to all graphics tablets in this seat. + */ +static inline struct zwp_tablet_seat_v2 * +zwp_tablet_manager_v2_get_tablet_seat(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2, struct wl_seat *seat) +{ + struct wl_proxy *tablet_seat; + + tablet_seat = wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_manager_v2, + ZWP_TABLET_MANAGER_V2_GET_TABLET_SEAT, &zwp_tablet_seat_v2_interface, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_manager_v2), 0, NULL, seat); + + return (struct zwp_tablet_seat_v2 *) tablet_seat; +} + +/** + * @ingroup iface_zwp_tablet_manager_v2 + * + * Destroy the wp_tablet_manager object. Objects created from this + * object are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_manager_v2_destroy(struct zwp_tablet_manager_v2 *zwp_tablet_manager_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_manager_v2, + ZWP_TABLET_MANAGER_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_manager_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_tablet_seat_v2 + * @struct zwp_tablet_seat_v2_listener + */ +struct zwp_tablet_seat_v2_listener { + /** + * new device notification + * + * This event is sent whenever a new tablet becomes available on + * this seat. This event only provides the object id of the tablet, + * any static information about the tablet (device name, vid/pid, + * etc.) is sent through the wp_tablet interface. + * @param id the newly added graphics tablet + */ + void (*tablet_added)(void *data, + struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + struct zwp_tablet_v2 *id); + /** + * a new tool has been used with a tablet + * + * This event is sent whenever a tool that has not previously + * been used with a tablet comes into use. This event only provides + * the object id of the tool; any static information about the tool + * (capabilities, type, etc.) is sent through the wp_tablet_tool + * interface. + * @param id the newly added tablet tool + */ + void (*tool_added)(void *data, + struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + struct zwp_tablet_tool_v2 *id); + /** + * new pad notification + * + * This event is sent whenever a new pad is known to the system. + * Typically, pads are physically attached to tablets and a + * pad_added event is sent immediately after the + * wp_tablet_seat.tablet_added. However, some standalone pad + * devices logically attach to tablets at runtime, and the client + * must wait for wp_tablet_pad.enter to know the tablet a pad is + * attached to. + * + * This event only provides the object id of the pad. All further + * features (buttons, strips, rings) are sent through the + * wp_tablet_pad interface. + * @param id the newly added pad + */ + void (*pad_added)(void *data, + struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + struct zwp_tablet_pad_v2 *id); +}; + +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +static inline int +zwp_tablet_seat_v2_add_listener(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, + const struct zwp_tablet_seat_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_seat_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_SEAT_V2_DESTROY 0 + +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_TABLET_ADDED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_TOOL_ADDED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_PAD_ADDED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_seat_v2 + */ +#define ZWP_TABLET_SEAT_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_seat_v2 */ +static inline void +zwp_tablet_seat_v2_set_user_data(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_seat_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_seat_v2 */ +static inline void * +zwp_tablet_seat_v2_get_user_data(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_seat_v2); +} + +static inline uint32_t +zwp_tablet_seat_v2_get_version(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_seat_v2); +} + +/** + * @ingroup iface_zwp_tablet_seat_v2 + * + * Destroy the wp_tablet_seat object. Objects created from this + * object are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_seat_v2_destroy(struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_seat_v2, + ZWP_TABLET_SEAT_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_seat_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_TOOL_V2_TYPE_ENUM +#define ZWP_TABLET_TOOL_V2_TYPE_ENUM +/** + * @ingroup iface_zwp_tablet_tool_v2 + * a physical tool type + * + * Describes the physical type of a tool. The physical type of a tool + * generally defines its base usage. + * + * The mouse tool represents a mouse-shaped tool that is not a relative + * device but bound to the tablet's surface, providing absolute + * coordinates. + * + * The lens tool is a mouse-shaped tool with an attached lens to + * provide precision focus. + */ +enum zwp_tablet_tool_v2_type { + /** + * Pen + */ + ZWP_TABLET_TOOL_V2_TYPE_PEN = 0x140, + /** + * Eraser + */ + ZWP_TABLET_TOOL_V2_TYPE_ERASER = 0x141, + /** + * Brush + */ + ZWP_TABLET_TOOL_V2_TYPE_BRUSH = 0x142, + /** + * Pencil + */ + ZWP_TABLET_TOOL_V2_TYPE_PENCIL = 0x143, + /** + * Airbrush + */ + ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH = 0x144, + /** + * Finger + */ + ZWP_TABLET_TOOL_V2_TYPE_FINGER = 0x145, + /** + * Mouse + */ + ZWP_TABLET_TOOL_V2_TYPE_MOUSE = 0x146, + /** + * Lens + */ + ZWP_TABLET_TOOL_V2_TYPE_LENS = 0x147, +}; +#endif /* ZWP_TABLET_TOOL_V2_TYPE_ENUM */ + +#ifndef ZWP_TABLET_TOOL_V2_CAPABILITY_ENUM +#define ZWP_TABLET_TOOL_V2_CAPABILITY_ENUM +/** + * @ingroup iface_zwp_tablet_tool_v2 + * capability flags for a tool + * + * Describes extra capabilities on a tablet. + * + * Any tool must provide x and y values, extra axes are + * device-specific. + */ +enum zwp_tablet_tool_v2_capability { + /** + * Tilt axes + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_TILT = 1, + /** + * Pressure axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE = 2, + /** + * Distance axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE = 3, + /** + * Z-rotation axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION = 4, + /** + * Slider axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER = 5, + /** + * Wheel axis + */ + ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL = 6, +}; +#endif /* ZWP_TABLET_TOOL_V2_CAPABILITY_ENUM */ + +#ifndef ZWP_TABLET_TOOL_V2_BUTTON_STATE_ENUM +#define ZWP_TABLET_TOOL_V2_BUTTON_STATE_ENUM +/** + * @ingroup iface_zwp_tablet_tool_v2 + * physical button state + * + * Describes the physical state of a button that produced the button event. + */ +enum zwp_tablet_tool_v2_button_state { + /** + * button is not pressed + */ + ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED = 0, + /** + * button is pressed + */ + ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED = 1, +}; +#endif /* ZWP_TABLET_TOOL_V2_BUTTON_STATE_ENUM */ + +#ifndef ZWP_TABLET_TOOL_V2_ERROR_ENUM +#define ZWP_TABLET_TOOL_V2_ERROR_ENUM +enum zwp_tablet_tool_v2_error { + /** + * given wl_surface has another role + */ + ZWP_TABLET_TOOL_V2_ERROR_ROLE = 0, +}; +#endif /* ZWP_TABLET_TOOL_V2_ERROR_ENUM */ + +/** + * @ingroup iface_zwp_tablet_tool_v2 + * @struct zwp_tablet_tool_v2_listener + */ +struct zwp_tablet_tool_v2_listener { + /** + * tool type + * + * The tool type is the high-level type of the tool and usually + * decides the interaction expected from this tool. + * + * This event is sent in the initial burst of events before the + * wp_tablet_tool.done event. + * @param tool_type the physical tool type + */ + void (*type)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t tool_type); + /** + * unique hardware serial number of the tool + * + * If the physical tool can be identified by a unique 64-bit + * serial number, this event notifies the client of this serial + * number. + * + * If multiple tablets are available in the same seat and the tool + * is uniquely identifiable by the serial number, that tool may + * move between tablets. + * + * Otherwise, if the tool has no serial number and this event is + * missing, the tool is tied to the tablet it first comes into + * proximity with. Even if the physical tool is used on multiple + * tablets, separate wp_tablet_tool objects will be created, one + * per tablet. + * + * This event is sent in the initial burst of events before the + * wp_tablet_tool.done event. + * @param hardware_serial_hi the unique serial number of the tool, most significant bits + * @param hardware_serial_lo the unique serial number of the tool, least significant bits + */ + void (*hardware_serial)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t hardware_serial_hi, + uint32_t hardware_serial_lo); + /** + * hardware id notification in Wacom's format + * + * This event notifies the client of a hardware id available on + * this tool. + * + * The hardware id is a device-specific 64-bit id that provides + * extra information about the tool in use, beyond the wl_tool.type + * enumeration. The format of the id is specific to tablets made by + * Wacom Inc. For example, the hardware id of a Wacom Grip Pen (a + * stylus) is 0x802. + * + * This event is sent in the initial burst of events before the + * wp_tablet_tool.done event. + * @param hardware_id_hi the hardware id, most significant bits + * @param hardware_id_lo the hardware id, least significant bits + */ + void (*hardware_id_wacom)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t hardware_id_hi, + uint32_t hardware_id_lo); + /** + * tool capability notification + * + * This event notifies the client of any capabilities of this + * tool, beyond the main set of x/y axes and tip up/down detection. + * + * One event is sent for each extra capability available on this + * tool. + * + * This event is sent in the initial burst of events before the + * wp_tablet_tool.done event. + * @param capability the capability + */ + void (*capability)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t capability); + /** + * tool description events sequence complete + * + * This event signals the end of the initial burst of descriptive + * events. A client may consider the static description of the tool + * to be complete and finalize initialization of the tool. + */ + void (*done)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * tool removed + * + * This event is sent when the tool is removed from the system + * and will send no further events. Should the physical tool come + * back into proximity later, a new wp_tablet_tool object will be + * created. + * + * It is compositor-dependent when a tool is removed. A compositor + * may remove a tool on proximity out, tablet removal or any other + * reason. A compositor may also keep a tool alive until shutdown. + * + * If the tool is currently in proximity, a proximity_out event + * will be sent before the removed event. See + * wp_tablet_tool.proximity_out for the handling of any buttons + * logically down. + * + * When this event is received, the client must + * wp_tablet_tool.destroy the object. + */ + void (*removed)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * proximity in event + * + * Notification that this tool is focused on a certain surface. + * + * This event can be received when the tool has moved from one + * surface to another, or when the tool has come back into + * proximity above the surface. + * + * If any button is logically down when the tool comes into + * proximity, the respective button event is sent after the + * proximity_in event but within the same frame as the proximity_in + * event. + * @param tablet The tablet the tool is in proximity of + * @param surface The current surface the tablet tool is over + */ + void (*proximity_in)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t serial, + struct zwp_tablet_v2 *tablet, + struct wl_surface *surface); + /** + * proximity out event + * + * Notification that this tool has either left proximity, or is + * no longer focused on a certain surface. + * + * When the tablet tool leaves proximity of the tablet, button + * release events are sent for each button that was held down at + * the time of leaving proximity. These events are sent before the + * proximity_out event but within the same wp_tablet.frame. + * + * If the tool stays within proximity of the tablet, but the focus + * changes from one surface to another, a button release event may + * not be sent until the button is actually released or the tool + * leaves the proximity of the tablet. + */ + void (*proximity_out)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * tablet tool is making contact + * + * Sent whenever the tablet tool comes in contact with the + * surface of the tablet. + * + * If the tool is already in contact with the tablet when entering + * the input region, the client owning said region will receive a + * wp_tablet.proximity_in event, followed by a wp_tablet.down event + * and a wp_tablet.frame event. + * + * Note that this event describes logical contact, not physical + * contact. On some devices, a compositor may not consider a tool + * in logical contact until a minimum physical pressure threshold + * is exceeded. + */ + void (*down)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t serial); + /** + * tablet tool is no longer making contact + * + * Sent whenever the tablet tool stops making contact with the + * surface of the tablet, or when the tablet tool moves out of the + * input region and the compositor grab (if any) is dismissed. + * + * If the tablet tool moves out of the input region while in + * contact with the surface of the tablet and the compositor does + * not have an ongoing grab on the surface, the client owning said + * region will receive a wp_tablet.up event, followed by a + * wp_tablet.proximity_out event and a wp_tablet.frame event. If + * the compositor has an ongoing grab on this device, this event + * sequence is sent whenever the grab is dismissed in the future. + * + * Note that this event describes logical contact, not physical + * contact. On some devices, a compositor may not consider a tool + * out of logical contact until physical pressure falls below a + * specific threshold. + */ + void (*up)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2); + /** + * motion event + * + * Sent whenever a tablet tool moves. + * @param x surface-local x coordinate + * @param y surface-local y coordinate + */ + void (*motion)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t x, + wl_fixed_t y); + /** + * pressure change event + * + * Sent whenever the pressure axis on a tool changes. The value + * of this event is normalized to a value between 0 and 65535. + * + * Note that pressure may be nonzero even when a tool is not in + * logical contact. See the down and up events for more details. + * @param pressure The current pressure value + */ + void (*pressure)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t pressure); + /** + * distance change event + * + * Sent whenever the distance axis on a tool changes. The value + * of this event is normalized to a value between 0 and 65535. + * + * Note that distance may be nonzero even when a tool is not in + * logical contact. See the down and up events for more details. + * @param distance The current distance value + */ + void (*distance)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t distance); + /** + * tilt change event + * + * Sent whenever one or both of the tilt axes on a tool change. + * Each tilt value is in degrees, relative to the z-axis of the + * tablet. The angle is positive when the top of a tool tilts along + * the positive x or y axis. + * @param tilt_x The current value of the X tilt axis + * @param tilt_y The current value of the Y tilt axis + */ + void (*tilt)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t tilt_x, + wl_fixed_t tilt_y); + /** + * z-rotation change event + * + * Sent whenever the z-rotation axis on the tool changes. The + * rotation value is in degrees clockwise from the tool's logical + * neutral position. + * @param degrees The current rotation of the Z axis + */ + void (*rotation)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t degrees); + /** + * Slider position change event + * + * Sent whenever the slider position on the tool changes. The + * value is normalized between -65535 and 65535, with 0 as the + * logical neutral position of the slider. + * + * The slider is available on e.g. the Wacom Airbrush tool. + * @param position The current position of slider + */ + void (*slider)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + int32_t position); + /** + * Wheel delta event + * + * Sent whenever the wheel on the tool emits an event. This event + * contains two values for the same axis change. The degrees value + * is in the same orientation as the wl_pointer.vertical_scroll + * axis. The clicks value is in discrete logical clicks of the + * mouse wheel. This value may be zero if the movement of the wheel + * was less than one logical click. + * + * Clients should choose either value and avoid mixing degrees and + * clicks. The compositor may accumulate values smaller than a + * logical click and emulate click events when a certain threshold + * is met. Thus, wl_tablet_tool.wheel events with non-zero clicks + * values may have different degrees values. + * @param degrees The wheel delta in degrees + * @param clicks The wheel delta in discrete clicks + */ + void (*wheel)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + wl_fixed_t degrees, + int32_t clicks); + /** + * button event + * + * Sent whenever a button on the tool is pressed or released. + * + * If a button is held down when the tool moves in or out of + * proximity, button events are generated by the compositor. See + * wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for + * details. + * @param button The button whose state has changed + * @param state Whether the button was pressed or released + */ + void (*button)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t serial, + uint32_t button, + uint32_t state); + /** + * frame event + * + * Marks the end of a series of axis and/or button updates from + * the tablet. The Wayland protocol requires axis updates to be + * sent sequentially, however all events within a frame should be + * considered one hardware event. + * @param time The time of the event with millisecond granularity + */ + void (*frame)(void *data, + struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + uint32_t time); +}; + +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +static inline int +zwp_tablet_tool_v2_add_listener(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, + const struct zwp_tablet_tool_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_tool_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_TOOL_V2_SET_CURSOR 0 +#define ZWP_TABLET_TOOL_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_TYPE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_HARDWARE_SERIAL_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_HARDWARE_ID_WACOM_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_CAPABILITY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_REMOVED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_PROXIMITY_IN_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_PROXIMITY_OUT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DOWN_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_UP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_MOTION_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_PRESSURE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DISTANCE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_TILT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_ROTATION_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_SLIDER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_WHEEL_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_BUTTON_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_FRAME_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_SET_CURSOR_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_tool_v2 + */ +#define ZWP_TABLET_TOOL_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_tool_v2 */ +static inline void +zwp_tablet_tool_v2_set_user_data(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_tool_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_tool_v2 */ +static inline void * +zwp_tablet_tool_v2_get_user_data(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_tool_v2); +} + +static inline uint32_t +zwp_tablet_tool_v2_get_version(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_tool_v2); +} + +/** + * @ingroup iface_zwp_tablet_tool_v2 + * + * Sets the surface of the cursor used for this tool on the given + * tablet. This request only takes effect if the tool is in proximity + * of one of the requesting client's surfaces or the surface parameter + * is the current pointer surface. If there was a previous surface set + * with this request it is replaced. If surface is NULL, the cursor + * image is hidden. + * + * The parameters hotspot_x and hotspot_y define the position of the + * pointer surface relative to the pointer location. Its top-left corner + * is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the + * coordinates of the pointer location, in surface-local coordinates. + * + * On surface.attach requests to the pointer surface, hotspot_x and + * hotspot_y are decremented by the x and y parameters passed to the + * request. Attach must be confirmed by wl_surface.commit as usual. + * + * The hotspot can also be updated by passing the currently set pointer + * surface to this request with new values for hotspot_x and hotspot_y. + * + * The current and pending input regions of the wl_surface are cleared, + * and wl_surface.set_input_region is ignored until the wl_surface is no + * longer used as the cursor. When the use as a cursor ends, the current + * and pending input regions become undefined, and the wl_surface is + * unmapped. + * + * This request gives the surface the role of a wp_tablet_tool cursor. A + * surface may only ever be used as the cursor surface for one + * wp_tablet_tool. If the surface already has another role or has + * previously been used as cursor surface for a different tool, a + * protocol error is raised. + */ +static inline void +zwp_tablet_tool_v2_set_cursor(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_tool_v2, + ZWP_TABLET_TOOL_V2_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_tool_v2), 0, serial, surface, hotspot_x, hotspot_y); +} + +/** + * @ingroup iface_zwp_tablet_tool_v2 + * + * This destroys the client's resource for this tool object. + */ +static inline void +zwp_tablet_tool_v2_destroy(struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_tool_v2, + ZWP_TABLET_TOOL_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_tool_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_tablet_v2 + * @struct zwp_tablet_v2_listener + */ +struct zwp_tablet_v2_listener { + /** + * tablet device name + * + * A descriptive name for the tablet device. + * + * If the device has no descriptive name, this event is not sent. + * + * This event is sent in the initial burst of events before the + * wp_tablet.done event. + * @param name the device name + */ + void (*name)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2, + const char *name); + /** + * tablet device USB vendor/product id + * + * The USB vendor and product IDs for the tablet device. + * + * If the device has no USB vendor/product ID, this event is not + * sent. This can happen for virtual devices or non-USB devices, + * for instance. + * + * This event is sent in the initial burst of events before the + * wp_tablet.done event. + * @param vid USB vendor id + * @param pid USB product id + */ + void (*id)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2, + uint32_t vid, + uint32_t pid); + /** + * path to the device + * + * A system-specific device path that indicates which device is + * behind this wp_tablet. This information may be used to gather + * additional information about the device, e.g. through libwacom. + * + * A device may have more than one device path. If so, multiple + * wp_tablet.path events are sent. A device may be emulated and not + * have a device path, and in that case this event will not be + * sent. + * + * The format of the path is unspecified, it may be a device node, + * a sysfs path, or some other identifier. It is up to the client + * to identify the string provided. + * + * This event is sent in the initial burst of events before the + * wp_tablet.done event. + * @param path path to local device + */ + void (*path)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2, + const char *path); + /** + * tablet description events sequence complete + * + * This event is sent immediately to signal the end of the + * initial burst of descriptive events. A client may consider the + * static description of the tablet to be complete and finalize + * initialization of the tablet. + */ + void (*done)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2); + /** + * tablet removed event + * + * Sent when the tablet has been removed from the system. When a + * tablet is removed, some tools may be removed. + * + * When this event is received, the client must wp_tablet.destroy + * the object. + */ + void (*removed)(void *data, + struct zwp_tablet_v2 *zwp_tablet_v2); +}; + +/** + * @ingroup iface_zwp_tablet_v2 + */ +static inline int +zwp_tablet_v2_add_listener(struct zwp_tablet_v2 *zwp_tablet_v2, + const struct zwp_tablet_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_V2_DESTROY 0 + +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_NAME_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_ID_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_PATH_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_REMOVED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_v2 + */ +#define ZWP_TABLET_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_v2 */ +static inline void +zwp_tablet_v2_set_user_data(struct zwp_tablet_v2 *zwp_tablet_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_v2 */ +static inline void * +zwp_tablet_v2_get_user_data(struct zwp_tablet_v2 *zwp_tablet_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_v2); +} + +static inline uint32_t +zwp_tablet_v2_get_version(struct zwp_tablet_v2 *zwp_tablet_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_v2); +} + +/** + * @ingroup iface_zwp_tablet_v2 + * + * This destroys the client's resource for this tablet object. + */ +static inline void +zwp_tablet_v2_destroy(struct zwp_tablet_v2 *zwp_tablet_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_v2, + ZWP_TABLET_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_PAD_RING_V2_SOURCE_ENUM +#define ZWP_TABLET_PAD_RING_V2_SOURCE_ENUM +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * ring axis source + * + * Describes the source types for ring events. This indicates to the + * client how a ring event was physically generated; a client may + * adjust the user interface accordingly. For example, events + * from a "finger" source may trigger kinetic scrolling. + */ +enum zwp_tablet_pad_ring_v2_source { + /** + * finger + */ + ZWP_TABLET_PAD_RING_V2_SOURCE_FINGER = 1, +}; +#endif /* ZWP_TABLET_PAD_RING_V2_SOURCE_ENUM */ + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * @struct zwp_tablet_pad_ring_v2_listener + */ +struct zwp_tablet_pad_ring_v2_listener { + /** + * ring event source + * + * Source information for ring events. + * + * This event does not occur on its own. It is sent before a + * wp_tablet_pad_ring.frame event and carries the source + * information for all events within that frame. + * + * The source specifies how this event was generated. If the source + * is wp_tablet_pad_ring.source.finger, a wp_tablet_pad_ring.stop + * event will be sent when the user lifts the finger off the + * device. + * + * This event is optional. If the source is unknown for an + * interaction, no event is sent. + * @param source the event source + */ + void (*source)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + uint32_t source); + /** + * angle changed + * + * Sent whenever the angle on a ring changes. + * + * The angle is provided in degrees clockwise from the logical + * north of the ring in the pad's current rotation. + * @param degrees the current angle in degrees + */ + void (*angle)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + wl_fixed_t degrees); + /** + * interaction stopped + * + * Stop notification for ring events. + * + * For some wp_tablet_pad_ring.source types, a + * wp_tablet_pad_ring.stop event is sent to notify a client that + * the interaction with the ring has terminated. This enables the + * client to implement kinetic scrolling. See the + * wp_tablet_pad_ring.source documentation for information on when + * this event may be generated. + * + * Any wp_tablet_pad_ring.angle events with the same source after + * this event should be considered as the start of a new + * interaction. + */ + void (*stop)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2); + /** + * end of a ring event sequence + * + * Indicates the end of a set of ring events that logically + * belong together. A client is expected to accumulate the data in + * all events within the frame before proceeding. + * + * All wp_tablet_pad_ring events before a wp_tablet_pad_ring.frame + * event belong logically together. For example, on termination of + * a finger interaction on a ring the compositor will send a + * wp_tablet_pad_ring.source event, a wp_tablet_pad_ring.stop event + * and a wp_tablet_pad_ring.frame event. + * + * A wp_tablet_pad_ring.frame event is sent for every logical event + * group, even if the group only contains a single + * wp_tablet_pad_ring event. Specifically, a client may get a + * sequence: angle, frame, angle, frame, etc. + * @param time timestamp with millisecond granularity + */ + void (*frame)(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + uint32_t time); +}; + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +static inline int +zwp_tablet_pad_ring_v2_add_listener(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + const struct zwp_tablet_pad_ring_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_ring_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_RING_V2_SET_FEEDBACK 0 +#define ZWP_TABLET_PAD_RING_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_ANGLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_STOP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_FRAME_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_SET_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + */ +#define ZWP_TABLET_PAD_RING_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_ring_v2 */ +static inline void +zwp_tablet_pad_ring_v2_set_user_data(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_ring_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_ring_v2 */ +static inline void * +zwp_tablet_pad_ring_v2_get_user_data(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_ring_v2); +} + +static inline uint32_t +zwp_tablet_pad_ring_v2_get_version(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_ring_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * + * Request that the compositor use the provided feedback string + * associated with this ring. This request should be issued immediately + * after a wp_tablet_pad_group.mode_switch event from the corresponding + * group is received, or whenever the ring is mapped to a different + * action. See wp_tablet_pad_group.mode_switch for more details. + * + * Clients are encouraged to provide context-aware descriptions for + * the actions associated with the ring; compositors may use this + * information to offer visual feedback about the button layout + * (eg. on-screen displays). + * + * The provided string 'description' is a UTF-8 encoded string to be + * associated with this ring, and is considered user-visible; general + * internationalization rules apply. + * + * The serial argument will be that of the last + * wp_tablet_pad_group.mode_switch event received for the group of this + * ring. Requests providing other serials than the most recent one will be + * ignored. + */ +static inline void +zwp_tablet_pad_ring_v2_set_feedback(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, const char *description, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_ring_v2, + ZWP_TABLET_PAD_RING_V2_SET_FEEDBACK, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_ring_v2), 0, description, serial); +} + +/** + * @ingroup iface_zwp_tablet_pad_ring_v2 + * + * This destroys the client's resource for this ring object. + */ +static inline void +zwp_tablet_pad_ring_v2_destroy(struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_ring_v2, + ZWP_TABLET_PAD_RING_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_ring_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_PAD_STRIP_V2_SOURCE_ENUM +#define ZWP_TABLET_PAD_STRIP_V2_SOURCE_ENUM +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * strip axis source + * + * Describes the source types for strip events. This indicates to the + * client how a strip event was physically generated; a client may + * adjust the user interface accordingly. For example, events + * from a "finger" source may trigger kinetic scrolling. + */ +enum zwp_tablet_pad_strip_v2_source { + /** + * finger + */ + ZWP_TABLET_PAD_STRIP_V2_SOURCE_FINGER = 1, +}; +#endif /* ZWP_TABLET_PAD_STRIP_V2_SOURCE_ENUM */ + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * @struct zwp_tablet_pad_strip_v2_listener + */ +struct zwp_tablet_pad_strip_v2_listener { + /** + * strip event source + * + * Source information for strip events. + * + * This event does not occur on its own. It is sent before a + * wp_tablet_pad_strip.frame event and carries the source + * information for all events within that frame. + * + * The source specifies how this event was generated. If the source + * is wp_tablet_pad_strip.source.finger, a wp_tablet_pad_strip.stop + * event will be sent when the user lifts their finger off the + * device. + * + * This event is optional. If the source is unknown for an + * interaction, no event is sent. + * @param source the event source + */ + void (*source)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t source); + /** + * position changed + * + * Sent whenever the position on a strip changes. + * + * The position is normalized to a range of [0, 65535], the 0-value + * represents the top-most and/or left-most position of the strip + * in the pad's current rotation. + * @param position the current position + */ + void (*position)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t position); + /** + * interaction stopped + * + * Stop notification for strip events. + * + * For some wp_tablet_pad_strip.source types, a + * wp_tablet_pad_strip.stop event is sent to notify a client that + * the interaction with the strip has terminated. This enables the + * client to implement kinetic scrolling. See the + * wp_tablet_pad_strip.source documentation for information on when + * this event may be generated. + * + * Any wp_tablet_pad_strip.position events with the same source + * after this event should be considered as the start of a new + * interaction. + */ + void (*stop)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2); + /** + * end of a strip event sequence + * + * Indicates the end of a set of events that represent one + * logical hardware strip event. A client is expected to accumulate + * the data in all events within the frame before proceeding. + * + * All wp_tablet_pad_strip events before a + * wp_tablet_pad_strip.frame event belong logically together. For + * example, on termination of a finger interaction on a strip the + * compositor will send a wp_tablet_pad_strip.source event, a + * wp_tablet_pad_strip.stop event and a wp_tablet_pad_strip.frame + * event. + * + * A wp_tablet_pad_strip.frame event is sent for every logical + * event group, even if the group only contains a single + * wp_tablet_pad_strip event. Specifically, a client may get a + * sequence: position, frame, position, frame, etc. + * @param time timestamp with millisecond granularity + */ + void (*frame)(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t time); +}; + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +static inline int +zwp_tablet_pad_strip_v2_add_listener(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + const struct zwp_tablet_pad_strip_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_strip_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_STRIP_V2_SET_FEEDBACK 0 +#define ZWP_TABLET_PAD_STRIP_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_STOP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_FRAME_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_SET_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + */ +#define ZWP_TABLET_PAD_STRIP_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_strip_v2 */ +static inline void +zwp_tablet_pad_strip_v2_set_user_data(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_strip_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_strip_v2 */ +static inline void * +zwp_tablet_pad_strip_v2_get_user_data(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_strip_v2); +} + +static inline uint32_t +zwp_tablet_pad_strip_v2_get_version(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_strip_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * + * Requests the compositor to use the provided feedback string + * associated with this strip. This request should be issued immediately + * after a wp_tablet_pad_group.mode_switch event from the corresponding + * group is received, or whenever the strip is mapped to a different + * action. See wp_tablet_pad_group.mode_switch for more details. + * + * Clients are encouraged to provide context-aware descriptions for + * the actions associated with the strip, and compositors may use this + * information to offer visual feedback about the button layout + * (eg. on-screen displays). + * + * The provided string 'description' is a UTF-8 encoded string to be + * associated with this ring, and is considered user-visible; general + * internationalization rules apply. + * + * The serial argument will be that of the last + * wp_tablet_pad_group.mode_switch event received for the group of this + * strip. Requests providing other serials than the most recent one will be + * ignored. + */ +static inline void +zwp_tablet_pad_strip_v2_set_feedback(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, const char *description, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_strip_v2, + ZWP_TABLET_PAD_STRIP_V2_SET_FEEDBACK, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_strip_v2), 0, description, serial); +} + +/** + * @ingroup iface_zwp_tablet_pad_strip_v2 + * + * This destroys the client's resource for this strip object. + */ +static inline void +zwp_tablet_pad_strip_v2_destroy(struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_strip_v2, + ZWP_TABLET_PAD_STRIP_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_strip_v2), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + * @struct zwp_tablet_pad_group_v2_listener + */ +struct zwp_tablet_pad_group_v2_listener { + /** + * buttons announced + * + * Sent on wp_tablet_pad_group initialization to announce the + * available buttons in the group. Button indices start at 0, a + * button may only be in one group at a time. + * + * This event is first sent in the initial burst of events before + * the wp_tablet_pad_group.done event. + * + * Some buttons are reserved by the compositor. These buttons may + * not be assigned to any wp_tablet_pad_group. Compositors may + * broadcast this event in the case of changes to the mapping of + * these reserved buttons. If the compositor happens to reserve all + * buttons in a group, this event will be sent with an empty array. + * @param buttons buttons in this group + */ + void (*buttons)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct wl_array *buttons); + /** + * ring announced + * + * Sent on wp_tablet_pad_group initialization to announce + * available rings. One event is sent for each ring available on + * this pad group. + * + * This event is sent in the initial burst of events before the + * wp_tablet_pad_group.done event. + */ + void (*ring)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct zwp_tablet_pad_ring_v2 *ring); + /** + * strip announced + * + * Sent on wp_tablet_pad initialization to announce available + * strips. One event is sent for each strip available on this pad + * group. + * + * This event is sent in the initial burst of events before the + * wp_tablet_pad_group.done event. + */ + void (*strip)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct zwp_tablet_pad_strip_v2 *strip); + /** + * mode-switch ability announced + * + * Sent on wp_tablet_pad_group initialization to announce that + * the pad group may switch between modes. A client may use a mode + * to store a specific configuration for buttons, rings and strips + * and use the wl_tablet_pad_group.mode_switch event to toggle + * between these configurations. Mode indices start at 0. + * + * Switching modes is compositor-dependent. See the + * wp_tablet_pad_group.mode_switch event for more details. + * + * This event is sent in the initial burst of events before the + * wp_tablet_pad_group.done event. This event is only sent when + * more than more than one mode is available. + * @param modes the number of modes + */ + void (*modes)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + uint32_t modes); + /** + * tablet group description events sequence complete + * + * This event is sent immediately to signal the end of the + * initial burst of descriptive events. A client may consider the + * static description of the tablet to be complete and finalize + * initialization of the tablet group. + */ + void (*done)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2); + /** + * mode switch event + * + * Notification that the mode was switched. + * + * A mode applies to all buttons, rings and strips in a group + * simultaneously, but a client is not required to assign different + * actions for each mode. For example, a client may have + * mode-specific button mappings but map the ring to vertical + * scrolling in all modes. Mode indices start at 0. + * + * Switching modes is compositor-dependent. The compositor may + * provide visual cues to the client about the mode, e.g. by + * toggling LEDs on the tablet device. Mode-switching may be + * software-controlled or controlled by one or more physical + * buttons. For example, on a Wacom Intuos Pro, the button inside + * the ring may be assigned to switch between modes. + * + * The compositor will also send this event after + * wp_tablet_pad.enter on each group in order to notify of the + * current mode. Groups that only feature one mode will use mode=0 + * when emitting this event. + * + * If a button action in the new mode differs from the action in + * the previous mode, the client should immediately issue a + * wp_tablet_pad.set_feedback request for each changed button. + * + * If a ring or strip action in the new mode differs from the + * action in the previous mode, the client should immediately issue + * a wp_tablet_ring.set_feedback or wp_tablet_strip.set_feedback + * request for each changed ring or strip. + * @param time the time of the event with millisecond granularity + * @param mode the new mode of the pad + */ + void (*mode_switch)(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + uint32_t time, + uint32_t serial, + uint32_t mode); +}; + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +static inline int +zwp_tablet_pad_group_v2_add_listener(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + const struct zwp_tablet_pad_group_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_group_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_GROUP_V2_DESTROY 0 + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_BUTTONS_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_RING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_STRIP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_MODES_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_MODE_SWITCH_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + */ +#define ZWP_TABLET_PAD_GROUP_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_group_v2 */ +static inline void +zwp_tablet_pad_group_v2_set_user_data(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_group_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_group_v2 */ +static inline void * +zwp_tablet_pad_group_v2_get_user_data(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_group_v2); +} + +static inline uint32_t +zwp_tablet_pad_group_v2_get_version(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_group_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_group_v2 + * + * Destroy the wp_tablet_pad_group object. Objects created from this object + * are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_pad_group_v2_destroy(struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_group_v2, + ZWP_TABLET_PAD_GROUP_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_group_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef ZWP_TABLET_PAD_V2_BUTTON_STATE_ENUM +#define ZWP_TABLET_PAD_V2_BUTTON_STATE_ENUM +/** + * @ingroup iface_zwp_tablet_pad_v2 + * physical button state + * + * Describes the physical state of a button that caused the button + * event. + */ +enum zwp_tablet_pad_v2_button_state { + /** + * the button is not pressed + */ + ZWP_TABLET_PAD_V2_BUTTON_STATE_RELEASED = 0, + /** + * the button is pressed + */ + ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED = 1, +}; +#endif /* ZWP_TABLET_PAD_V2_BUTTON_STATE_ENUM */ + +/** + * @ingroup iface_zwp_tablet_pad_v2 + * @struct zwp_tablet_pad_v2_listener + */ +struct zwp_tablet_pad_v2_listener { + /** + * group announced + * + * Sent on wp_tablet_pad initialization to announce available + * groups. One event is sent for each pad group available. + * + * This event is sent in the initial burst of events before the + * wp_tablet_pad.done event. At least one group will be announced. + */ + void (*group)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + struct zwp_tablet_pad_group_v2 *pad_group); + /** + * path to the device + * + * A system-specific device path that indicates which device is + * behind this wp_tablet_pad. This information may be used to + * gather additional information about the device, e.g. through + * libwacom. + * + * The format of the path is unspecified, it may be a device node, + * a sysfs path, or some other identifier. It is up to the client + * to identify the string provided. + * + * This event is sent in the initial burst of events before the + * wp_tablet_pad.done event. + * @param path path to local device + */ + void (*path)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + const char *path); + /** + * buttons announced + * + * Sent on wp_tablet_pad initialization to announce the available + * buttons. + * + * This event is sent in the initial burst of events before the + * wp_tablet_pad.done event. This event is only sent when at least + * one button is available. + * @param buttons the number of buttons + */ + void (*buttons)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t buttons); + /** + * pad description event sequence complete + * + * This event signals the end of the initial burst of descriptive + * events. A client may consider the static description of the pad + * to be complete and finalize initialization of the pad. + */ + void (*done)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2); + /** + * physical button state + * + * Sent whenever the physical state of a button changes. + * @param time the time of the event with millisecond granularity + * @param button the index of the button that changed state + */ + void (*button)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t time, + uint32_t button, + uint32_t state); + /** + * enter event + * + * Notification that this pad is focused on the specified + * surface. + * @param serial serial number of the enter event + * @param tablet the tablet the pad is attached to + * @param surface surface the pad is focused on + */ + void (*enter)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t serial, + struct zwp_tablet_v2 *tablet, + struct wl_surface *surface); + /** + * leave event + * + * Notification that this pad is no longer focused on the + * specified surface. + * @param serial serial number of the leave event + * @param surface surface the pad is no longer focused on + */ + void (*leave)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t serial, + struct wl_surface *surface); + /** + * pad removed event + * + * Sent when the pad has been removed from the system. When a + * tablet is removed its pad(s) will be removed too. + * + * When this event is received, the client must destroy all rings, + * strips and groups that were offered by this pad, and issue + * wp_tablet_pad.destroy the pad itself. + */ + void (*removed)(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2); +}; + +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +static inline int +zwp_tablet_pad_v2_add_listener(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + const struct zwp_tablet_pad_v2_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_tablet_pad_v2, + (void (**)(void)) listener, data); +} + +#define ZWP_TABLET_PAD_V2_SET_FEEDBACK 0 +#define ZWP_TABLET_PAD_V2_DESTROY 1 + +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_GROUP_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_PATH_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_BUTTONS_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_BUTTON_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_REMOVED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_SET_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_tablet_pad_v2 + */ +#define ZWP_TABLET_PAD_V2_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_tablet_pad_v2 */ +static inline void +zwp_tablet_pad_v2_set_user_data(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_tablet_pad_v2, user_data); +} + +/** @ingroup iface_zwp_tablet_pad_v2 */ +static inline void * +zwp_tablet_pad_v2_get_user_data(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_tablet_pad_v2); +} + +static inline uint32_t +zwp_tablet_pad_v2_get_version(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_v2); +} + +/** + * @ingroup iface_zwp_tablet_pad_v2 + * + * Requests the compositor to use the provided feedback string + * associated with this button. This request should be issued immediately + * after a wp_tablet_pad_group.mode_switch event from the corresponding + * group is received, or whenever a button is mapped to a different + * action. See wp_tablet_pad_group.mode_switch for more details. + * + * Clients are encouraged to provide context-aware descriptions for + * the actions associated with each button, and compositors may use + * this information to offer visual feedback on the button layout + * (e.g. on-screen displays). + * + * Button indices start at 0. Setting the feedback string on a button + * that is reserved by the compositor (i.e. not belonging to any + * wp_tablet_pad_group) does not generate an error but the compositor + * is free to ignore the request. + * + * The provided string 'description' is a UTF-8 encoded string to be + * associated with this ring, and is considered user-visible; general + * internationalization rules apply. + * + * The serial argument will be that of the last + * wp_tablet_pad_group.mode_switch event received for the group of this + * button. Requests providing other serials than the most recent one will + * be ignored. + */ +static inline void +zwp_tablet_pad_v2_set_feedback(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, uint32_t button, const char *description, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_v2, + ZWP_TABLET_PAD_V2_SET_FEEDBACK, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_v2), 0, button, description, serial); +} + +/** + * @ingroup iface_zwp_tablet_pad_v2 + * + * Destroy the wp_tablet_pad object. Objects created from this object + * are unaffected and should be destroyed separately. + */ +static inline void +zwp_tablet_pad_v2_destroy(struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_tablet_pad_v2, + ZWP_TABLET_PAD_V2_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_tablet_pad_v2), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/host/linux/wayland/tablet-unstable-v2-protocol.c b/examples/host/linux/wayland/tablet-unstable-v2-protocol.c new file mode 100644 index 00000000..60881d9b --- /dev/null +++ b/examples/host/linux/wayland/tablet-unstable-v2-protocol.c @@ -0,0 +1,234 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright 2014 © Stephen "Lyude" Chandler Paul + * Copyright 2015-2016 © Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface zwp_tablet_pad_group_v2_interface; +extern const struct wl_interface zwp_tablet_pad_ring_v2_interface; +extern const struct wl_interface zwp_tablet_pad_strip_v2_interface; +extern const struct wl_interface zwp_tablet_pad_v2_interface; +extern const struct wl_interface zwp_tablet_seat_v2_interface; +extern const struct wl_interface zwp_tablet_tool_v2_interface; +extern const struct wl_interface zwp_tablet_v2_interface; + +static const struct wl_interface *tablet_unstable_v2_types[] = { + NULL, + NULL, + NULL, + &zwp_tablet_seat_v2_interface, + &wl_seat_interface, + &zwp_tablet_v2_interface, + &zwp_tablet_tool_v2_interface, + &zwp_tablet_pad_v2_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &zwp_tablet_v2_interface, + &wl_surface_interface, + &zwp_tablet_pad_ring_v2_interface, + &zwp_tablet_pad_strip_v2_interface, + &zwp_tablet_pad_group_v2_interface, + NULL, + &zwp_tablet_v2_interface, + &wl_surface_interface, + NULL, + &wl_surface_interface, +}; + +static const struct wl_message zwp_tablet_manager_v2_requests[] = { + { "get_tablet_seat", "no", tablet_unstable_v2_types + 3 }, + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_manager_v2_interface = { + "zwp_tablet_manager_v2", 1, + 2, zwp_tablet_manager_v2_requests, + 0, NULL, +}; + +static const struct wl_message zwp_tablet_seat_v2_requests[] = { + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_seat_v2_events[] = { + { "tablet_added", "n", tablet_unstable_v2_types + 5 }, + { "tool_added", "n", tablet_unstable_v2_types + 6 }, + { "pad_added", "n", tablet_unstable_v2_types + 7 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_seat_v2_interface = { + "zwp_tablet_seat_v2", 1, + 1, zwp_tablet_seat_v2_requests, + 3, zwp_tablet_seat_v2_events, +}; + +static const struct wl_message zwp_tablet_tool_v2_requests[] = { + { "set_cursor", "u?oii", tablet_unstable_v2_types + 8 }, + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_tool_v2_events[] = { + { "type", "u", tablet_unstable_v2_types + 0 }, + { "hardware_serial", "uu", tablet_unstable_v2_types + 0 }, + { "hardware_id_wacom", "uu", tablet_unstable_v2_types + 0 }, + { "capability", "u", tablet_unstable_v2_types + 0 }, + { "done", "", tablet_unstable_v2_types + 0 }, + { "removed", "", tablet_unstable_v2_types + 0 }, + { "proximity_in", "uoo", tablet_unstable_v2_types + 12 }, + { "proximity_out", "", tablet_unstable_v2_types + 0 }, + { "down", "u", tablet_unstable_v2_types + 0 }, + { "up", "", tablet_unstable_v2_types + 0 }, + { "motion", "ff", tablet_unstable_v2_types + 0 }, + { "pressure", "u", tablet_unstable_v2_types + 0 }, + { "distance", "u", tablet_unstable_v2_types + 0 }, + { "tilt", "ff", tablet_unstable_v2_types + 0 }, + { "rotation", "f", tablet_unstable_v2_types + 0 }, + { "slider", "i", tablet_unstable_v2_types + 0 }, + { "wheel", "fi", tablet_unstable_v2_types + 0 }, + { "button", "uuu", tablet_unstable_v2_types + 0 }, + { "frame", "u", tablet_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_tool_v2_interface = { + "zwp_tablet_tool_v2", 1, + 2, zwp_tablet_tool_v2_requests, + 19, zwp_tablet_tool_v2_events, +}; + +static const struct wl_message zwp_tablet_v2_requests[] = { + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_v2_events[] = { + { "name", "s", tablet_unstable_v2_types + 0 }, + { "id", "uu", tablet_unstable_v2_types + 0 }, + { "path", "s", tablet_unstable_v2_types + 0 }, + { "done", "", tablet_unstable_v2_types + 0 }, + { "removed", "", tablet_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_v2_interface = { + "zwp_tablet_v2", 1, + 1, zwp_tablet_v2_requests, + 5, zwp_tablet_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_ring_v2_requests[] = { + { "set_feedback", "su", tablet_unstable_v2_types + 0 }, + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_ring_v2_events[] = { + { "source", "u", tablet_unstable_v2_types + 0 }, + { "angle", "f", tablet_unstable_v2_types + 0 }, + { "stop", "", tablet_unstable_v2_types + 0 }, + { "frame", "u", tablet_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_ring_v2_interface = { + "zwp_tablet_pad_ring_v2", 1, + 2, zwp_tablet_pad_ring_v2_requests, + 4, zwp_tablet_pad_ring_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_strip_v2_requests[] = { + { "set_feedback", "su", tablet_unstable_v2_types + 0 }, + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_strip_v2_events[] = { + { "source", "u", tablet_unstable_v2_types + 0 }, + { "position", "u", tablet_unstable_v2_types + 0 }, + { "stop", "", tablet_unstable_v2_types + 0 }, + { "frame", "u", tablet_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_strip_v2_interface = { + "zwp_tablet_pad_strip_v2", 1, + 2, zwp_tablet_pad_strip_v2_requests, + 4, zwp_tablet_pad_strip_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_group_v2_requests[] = { + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_group_v2_events[] = { + { "buttons", "a", tablet_unstable_v2_types + 0 }, + { "ring", "n", tablet_unstable_v2_types + 15 }, + { "strip", "n", tablet_unstable_v2_types + 16 }, + { "modes", "u", tablet_unstable_v2_types + 0 }, + { "done", "", tablet_unstable_v2_types + 0 }, + { "mode_switch", "uuu", tablet_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_group_v2_interface = { + "zwp_tablet_pad_group_v2", 1, + 1, zwp_tablet_pad_group_v2_requests, + 6, zwp_tablet_pad_group_v2_events, +}; + +static const struct wl_message zwp_tablet_pad_v2_requests[] = { + { "set_feedback", "usu", tablet_unstable_v2_types + 0 }, + { "destroy", "", tablet_unstable_v2_types + 0 }, +}; + +static const struct wl_message zwp_tablet_pad_v2_events[] = { + { "group", "n", tablet_unstable_v2_types + 17 }, + { "path", "s", tablet_unstable_v2_types + 0 }, + { "buttons", "u", tablet_unstable_v2_types + 0 }, + { "done", "", tablet_unstable_v2_types + 0 }, + { "button", "uuu", tablet_unstable_v2_types + 0 }, + { "enter", "uoo", tablet_unstable_v2_types + 18 }, + { "leave", "uo", tablet_unstable_v2_types + 21 }, + { "removed", "", tablet_unstable_v2_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_tablet_pad_v2_interface = { + "zwp_tablet_pad_v2", 1, + 2, zwp_tablet_pad_v2_requests, + 8, zwp_tablet_pad_v2_events, +}; + diff --git a/examples/host/linux/wayland/viewporter-client-protocol.h b/examples/host/linux/wayland/viewporter-client-protocol.h new file mode 100644 index 00000000..f2860952 --- /dev/null +++ b/examples/host/linux/wayland/viewporter-client-protocol.h @@ -0,0 +1,394 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef VIEWPORTER_CLIENT_PROTOCOL_H +#define VIEWPORTER_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_viewporter The viewporter protocol + * @section page_ifaces_viewporter Interfaces + * - @subpage page_iface_wp_viewporter - surface cropping and scaling + * - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface + * @section page_copyright_viewporter Copyright + *
+ *
+ * Copyright © 2013-2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_viewport; +struct wp_viewporter; + +#ifndef WP_VIEWPORTER_INTERFACE +#define WP_VIEWPORTER_INTERFACE +/** + * @page page_iface_wp_viewporter wp_viewporter + * @section page_iface_wp_viewporter_desc Description + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * surface size. + * @section page_iface_wp_viewporter_api API + * See @ref iface_wp_viewporter. + */ +/** + * @defgroup iface_wp_viewporter The wp_viewporter interface + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * surface size. + */ +extern const struct wl_interface wp_viewporter_interface; +#endif +#ifndef WP_VIEWPORT_INTERFACE +#define WP_VIEWPORT_INTERFACE +/** + * @page page_iface_wp_viewport wp_viewport + * @section page_iface_wp_viewport_desc Description + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * src_y, src_width, src_height), and the destination size (dst_width, + * dst_height). The contents of the source rectangle are scaled to the + * destination size, and content outside the source rectangle is ignored. + * This state is double-buffered, see wl_surface.commit. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * on the next wl_surface.commit. + * @section page_iface_wp_viewport_api API + * See @ref iface_wp_viewport. + */ +/** + * @defgroup iface_wp_viewport The wp_viewport interface + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * src_y, src_width, src_height), and the destination size (dst_width, + * dst_height). The contents of the source rectangle are scaled to the + * destination size, and content outside the source rectangle is ignored. + * This state is double-buffered, see wl_surface.commit. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * on the next wl_surface.commit. + */ +extern const struct wl_interface wp_viewport_interface; +#endif + +#ifndef WP_VIEWPORTER_ERROR_ENUM +#define WP_VIEWPORTER_ERROR_ENUM +enum wp_viewporter_error { + /** + * the surface already has a viewport object associated + */ + WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0, +}; +#endif /* WP_VIEWPORTER_ERROR_ENUM */ + +#define WP_VIEWPORTER_DESTROY 0 +#define WP_VIEWPORTER_GET_VIEWPORT 1 + + +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewporter */ +static inline void +wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data); +} + +/** @ingroup iface_wp_viewporter */ +static inline void * +wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter); +} + +static inline uint32_t +wp_viewporter_get_version(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewporter); +} + +/** + * @ingroup iface_wp_viewporter + * + * Informs the server that the client will not be using this + * protocol object anymore. This does not affect any other objects, + * wp_viewport objects included. + */ +static inline void +wp_viewporter_destroy(struct wp_viewporter *wp_viewporter) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_viewporter + * + * Instantiate an interface extension for the given wl_surface to + * crop and scale its content. If the given wl_surface already has + * a wp_viewport object associated, the viewport_exists + * protocol error is raised. + */ +static inline struct wp_viewport * +wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, wl_proxy_get_version((struct wl_proxy *) wp_viewporter), 0, NULL, surface); + + return (struct wp_viewport *) id; +} + +#ifndef WP_VIEWPORT_ERROR_ENUM +#define WP_VIEWPORT_ERROR_ENUM +enum wp_viewport_error { + /** + * negative or zero values in width or height + */ + WP_VIEWPORT_ERROR_BAD_VALUE = 0, + /** + * destination size is not integer + */ + WP_VIEWPORT_ERROR_BAD_SIZE = 1, + /** + * source rectangle extends outside of the content area + */ + WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2, + /** + * the wl_surface was destroyed + */ + WP_VIEWPORT_ERROR_NO_SURFACE = 3, +}; +#endif /* WP_VIEWPORT_ERROR_ENUM */ + +#define WP_VIEWPORT_DESTROY 0 +#define WP_VIEWPORT_SET_SOURCE 1 +#define WP_VIEWPORT_SET_DESTINATION 2 + + +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewport */ +static inline void +wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data); +} + +/** @ingroup iface_wp_viewport */ +static inline void * +wp_viewport_get_user_data(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport); +} + +static inline uint32_t +wp_viewport_get_version(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewport); +} + +/** + * @ingroup iface_wp_viewport + * + * The associated wl_surface's crop and scale state is removed. + * The change is applied on the next wl_surface.commit. + */ +static inline void +wp_viewport_destroy(struct wp_viewport *wp_viewport) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the source rectangle of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If all of x, y, width and height are -1.0, the source rectangle is + * unset instead. Any other set of values where width or height are zero + * or negative, or x or y are negative, raise the bad_value protocol + * error. + * + * The crop and scale state is double-buffered, see wl_surface.commit. + */ +static inline void +wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_SOURCE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, x, y, width, height); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the destination size of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If width is -1 and height is -1, the destination size is unset + * instead. Any other pair of values for width and height that + * contains zero or negative values raises the bad_value protocol + * error. + * + * The crop and scale state is double-buffered, see wl_surface.commit. + */ +static inline void +wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_DESTINATION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_viewport), 0, width, height); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/host/linux/wayland/viewporter-protocol.c b/examples/host/linux/wayland/viewporter-protocol.c new file mode 100644 index 00000000..d6858580 --- /dev/null +++ b/examples/host/linux/wayland/viewporter-protocol.c @@ -0,0 +1,75 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2013-2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_viewport_interface; + +static const struct wl_interface *viewporter_types[] = { + NULL, + NULL, + NULL, + NULL, + &wp_viewport_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_viewporter_requests[] = { + { "destroy", "", viewporter_types + 0 }, + { "get_viewport", "no", viewporter_types + 4 }, +}; + +WL_PRIVATE const struct wl_interface wp_viewporter_interface = { + "wp_viewporter", 1, + 2, wp_viewporter_requests, + 0, NULL, +}; + +static const struct wl_message wp_viewport_requests[] = { + { "destroy", "", viewporter_types + 0 }, + { "set_source", "ffff", viewporter_types + 0 }, + { "set_destination", "ii", viewporter_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_viewport_interface = { + "wp_viewport", 1, + 3, wp_viewport_requests, + 0, NULL, +}; + diff --git a/examples/host/linux/wayland/xdg-decoration-unstable-v1-client-protocol.h b/examples/host/linux/wayland/xdg-decoration-unstable-v1-client-protocol.h new file mode 100644 index 00000000..217af207 --- /dev/null +++ b/examples/host/linux/wayland/xdg-decoration-unstable-v1-client-protocol.h @@ -0,0 +1,384 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol + * @section page_ifaces_xdg_decoration_unstable_v1 Interfaces + * - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager + * - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface + * @section page_copyright_xdg_decoration_unstable_v1 Copyright + *
+ *
+ * Copyright © 2018 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct xdg_toplevel; +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +#ifndef ZXDG_DECORATION_MANAGER_V1_INTERFACE +#define ZXDG_DECORATION_MANAGER_V1_INTERFACE +/** + * @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1 + * @section page_iface_zxdg_decoration_manager_v1_desc Description + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * @section page_iface_zxdg_decoration_manager_v1_api API + * See @ref iface_zxdg_decoration_manager_v1. + */ +/** + * @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + */ +extern const struct wl_interface zxdg_decoration_manager_v1_interface; +#endif +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE +#define ZXDG_TOPLEVEL_DECORATION_V1_INTERFACE +/** + * @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1 + * @section page_iface_zxdg_toplevel_decoration_v1_desc Description + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + * @section page_iface_zxdg_toplevel_decoration_v1_api API + * See @ref iface_zxdg_toplevel_decoration_v1. + */ +/** + * @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + */ +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; +#endif + +#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0 +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1 + + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void +zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data); +} + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void * +zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +static inline uint32_t +zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Destroy the decoration manager. This doesn't destroy objects created + * with the manager. + */ +static inline void +zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Create a new decoration object associated with the given toplevel. + * + * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a + * buffer attached or committed is a client error, and any attempts by a + * client to attach or manipulate a buffer prior to the first + * xdg_toplevel_decoration.configure event must also be treated as + * errors. + */ +static inline struct zxdg_toplevel_decoration_v1 * +zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1), 0, NULL, toplevel); + + return (struct zxdg_toplevel_decoration_v1 *) id; +} + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +enum zxdg_toplevel_decoration_v1_error { + /** + * xdg_toplevel has a buffer attached before configure + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0, + /** + * xdg_toplevel already has a decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1, + /** + * xdg_toplevel destroyed before the decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2, + /** + * invalid mode + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_INVALID_MODE = 3, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */ + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * window decoration modes + * + * These values describe window decoration modes. + */ +enum zxdg_toplevel_decoration_v1_mode { + /** + * no server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1, + /** + * server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */ + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * @struct zxdg_toplevel_decoration_v1_listener + */ +struct zxdg_toplevel_decoration_v1_listener { + /** + * notify a decoration mode change + * + * The configure event configures the effective decoration mode. + * The configured state should not be applied immediately. Clients + * must send an ack_configure in response to this event. See + * xdg_surface.configure and xdg_surface.ack_configure for details. + * + * A configure event can be sent at any time. The specified mode + * must be obeyed by the client. + * @param mode the decoration mode + */ + void (*configure)(void *data, + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + uint32_t mode); +}; + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +static inline int +zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + const struct zxdg_toplevel_decoration_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1, + (void (**)(void)) listener, data); +} + +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0 +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1 +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void +zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data); +} + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void * +zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +static inline uint32_t +zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Switch back to a mode without any server-side decorations at the next + * commit. + */ +static inline void +zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Set the toplevel surface decoration mode. This informs the compositor + * that the client prefers the provided decoration mode. + * + * After requesting a decoration mode, the compositor will respond by + * emitting an xdg_surface.configure event. The client should then update + * its content, drawing it without decorations if the received mode is + * server-side decorations. The client must also acknowledge the configure + * when committing the new content (see xdg_surface.ack_configure). + * + * The compositor can decide not to use the client's mode and enforce a + * different mode instead. + * + * Clients whose decoration mode depend on the xdg_toplevel state may send + * a set_mode request in response to an xdg_surface.configure event and wait + * for the next xdg_surface.configure event to prevent unwanted state. + * Such clients are responsible for preventing configure loops and must + * make sure not to send multiple successive set_mode requests with the + * same decoration mode. + * + * If an invalid mode is supplied by the client, the invalid_mode protocol + * error is raised by the compositor. + */ +static inline void +zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0, mode); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Unset the toplevel surface decoration mode. This informs the compositor + * that the client doesn't prefer a particular decoration mode. + * + * This request has the same semantics as set_mode. + */ +static inline void +zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1), 0); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/host/linux/wayland/xdg-decoration-unstable-v1-protocol.c b/examples/host/linux/wayland/xdg-decoration-unstable-v1-protocol.c new file mode 100644 index 00000000..85496afa --- /dev/null +++ b/examples/host/linux/wayland/xdg-decoration-unstable-v1-protocol.c @@ -0,0 +1,76 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2018 Simon Ser + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface xdg_toplevel_interface; +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +static const struct wl_interface *xdg_decoration_unstable_v1_types[] = { + NULL, + &zxdg_toplevel_decoration_v1_interface, + &xdg_toplevel_interface, +}; + +static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", 1, + 2, zxdg_decoration_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 }, + { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 }, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { + { "configure", "u", xdg_decoration_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = { + "zxdg_toplevel_decoration_v1", 1, + 3, zxdg_toplevel_decoration_v1_requests, + 1, zxdg_toplevel_decoration_v1_events, +}; + diff --git a/examples/host/linux/wayland/xdg-shell-client-protocol.h b/examples/host/linux/wayland/xdg-shell-client-protocol.h new file mode 100644 index 00000000..1f077b49 --- /dev/null +++ b/examples/host/linux/wayland/xdg-shell-client-protocol.h @@ -0,0 +1,2325 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef XDG_SHELL_CLIENT_PROTOCOL_H +#define XDG_SHELL_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +#ifndef XDG_WM_BASE_INTERFACE +#define XDG_WM_BASE_INTERFACE +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +#endif +#ifndef XDG_POSITIONER_INTERFACE +#define XDG_POSITIONER_INTERFACE +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an invalid_positioner error. + */ +extern const struct wl_interface xdg_positioner_interface; +#endif +#ifndef XDG_SURFACE_INTERFACE +#define XDG_SURFACE_INTERFACE +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up (e.g. by sending + * the title, app ID, size constraints, parent, etc), the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed, i.e. the client must perform the initial commit + * again before attaching a buffer. + */ +extern const struct wl_interface xdg_surface_interface; +#endif +#ifndef XDG_TOPLEVEL_INTERFACE +#define XDG_TOPLEVEL_INTERFACE +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * A xdg_toplevel by default is responsible for providing the full intended + * visual representation of the toplevel, which depending on the window + * state, may mean things like a title bar, window controls and drop shadow. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by performing a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +#endif +#ifndef XDG_POPUP_INTERFACE +#define XDG_POPUP_INTERFACE +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; +#endif + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, + /** + * the client didn’t respond to a ping event in time + */ + XDG_WM_BASE_ERROR_UNRESPONSIVE = 6, +}; +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_listener + */ +struct xdg_wm_base_listener { + /** + * check if the client is alive + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. See + * xdg_wm_base.pong. + * + * Compositors can use this to determine if the client is still + * alive. It's unspecified what will happen if the client doesn't + * respond to the ping request, or in what timeframe. Clients + * should try to respond in a reasonable amount of time. The + * “unresponsive” error is provided for compositors that wish + * to disconnect unresponsive clients. + * + * A compositor is free to ping in any way it wants, but a client + * must always respond to any xdg_wm_base object it created. + * @param serial pass this to the pong request + */ + void (*ping)(void *data, + struct xdg_wm_base *xdg_wm_base, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_wm_base + */ +static inline int +xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base, + const struct xdg_wm_base_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base, + (void (**)(void)) listener, data); +} + +#define XDG_WM_BASE_DESTROY 0 +#define XDG_WM_BASE_CREATE_POSITIONER 1 +#define XDG_WM_BASE_GET_XDG_SURFACE 2 +#define XDG_WM_BASE_PONG 3 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** @ingroup iface_xdg_wm_base */ +static inline void +xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data); +} + +/** @ingroup iface_xdg_wm_base */ +static inline void * +xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base); +} + +static inline uint32_t +xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is illegal + * and will result in a defunct_surfaces error. + */ +static inline void +xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Create a positioner object. A positioner object is used to position + * surfaces relative to some parent surface. See the interface description + * and xdg_surface.get_popup for details. + */ +static inline struct xdg_positioner * +xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL); + + return (struct xdg_positioner *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * This creates an xdg_surface for the given surface. While xdg_surface + * itself is not a role, the corresponding surface may only be assigned + * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is + * illegal to create an xdg_surface for a wl_surface which already has an + * assigned role and this will result in a role error. + * + * This creates an xdg_surface for the given surface. An xdg_surface is + * used as basis to define a role to a given surface, such as xdg_toplevel + * or xdg_popup. It also manages functionality shared between xdg_surface + * based surface roles. + * + * See the documentation of xdg_surface for more details about what an + * xdg_surface is and how it is used. + */ +static inline struct xdg_surface * +xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface); + + return (struct xdg_surface *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping + * and xdg_wm_base.error.unresponsive. + */ +static inline void +xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * constraint adjustments + * + * The constraint adjustment value define ways the compositor will adjust + * the position of the surface, if the unadjusted position would result + * in the surface being partly constrained. + * + * Whether a surface is considered 'constrained' is left to the compositor + * to determine. For example, the surface may be partly outside the + * compositor's defined 'work area', thus necessitating the child surface's + * position be adjusted until it is entirely inside the work area. + * + * The adjustments can be combined, according to a defined precedence: 1) + * Flip, 2) Slide, 3) Resize. + */ +enum xdg_positioner_constraint_adjustment { + /** + * don't move the child surface when constrained + * + * Don't alter the surface position even if it is constrained on + * some axis, for example partially outside the edge of an output. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + /** + * move along the x axis until unconstrained + * + * Slide the surface along the x axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the x + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the x axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + /** + * move along the y axis until unconstrained + * + * Slide the surface along the y axis until it is no longer + * constrained. + * + * First try to slide towards the direction of the gravity on the y + * axis until either the edge in the opposite direction of the + * gravity is unconstrained or the edge in the direction of the + * gravity is constrained. + * + * Then try to slide towards the opposite direction of the gravity + * on the y axis until either the edge in the direction of the + * gravity is unconstrained or the edge in the opposite direction + * of the gravity is constrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + /** + * invert the anchor and gravity on the x axis + * + * Invert the anchor and gravity on the x axis if the surface is + * constrained on the x axis. For example, if the left edge of the + * surface is constrained, the gravity is 'left' and the anchor is + * 'left', change the gravity to 'right' and the anchor to 'right'. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_x adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + /** + * invert the anchor and gravity on the y axis + * + * Invert the anchor and gravity on the y axis if the surface is + * constrained on the y axis. For example, if the bottom edge of + * the surface is constrained, the gravity is 'bottom' and the + * anchor is 'bottom', change the gravity to 'top' and the anchor + * to 'top'. + * + * The adjusted position is calculated given the original anchor + * rectangle and offset, but with the new flipped anchor and + * gravity values. + * + * If the adjusted position also ends up being constrained, the + * resulting position of the flip_y adjustment will be the one + * before the adjustment. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + /** + * horizontally resize the surface + * + * Resize the surface horizontally so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + /** + * vertically resize the surface + * + * Resize the surface vertically so that it is completely + * unconstrained. + */ + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +#define XDG_POSITIONER_DESTROY 0 +#define XDG_POSITIONER_SET_SIZE 1 +#define XDG_POSITIONER_SET_ANCHOR_RECT 2 +#define XDG_POSITIONER_SET_ANCHOR 3 +#define XDG_POSITIONER_SET_GRAVITY 4 +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 +#define XDG_POSITIONER_SET_OFFSET 6 +#define XDG_POSITIONER_SET_REACTIVE 7 +#define XDG_POSITIONER_SET_PARENT_SIZE 8 +#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9 + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +/** @ingroup iface_xdg_positioner */ +static inline void +xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data); +} + +/** @ingroup iface_xdg_positioner */ +static inline void * +xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner); +} + +static inline uint32_t +xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Notify the compositor that the xdg_positioner will no longer be used. + */ +static inline void +xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the size of the surface that is to be positioned with the positioner + * object. The size is in surface-local coordinates and corresponds to the + * window geometry. See xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the anchor rectangle within the parent surface that the child + * surface will be placed relative to. The rectangle is relative to the + * window geometry as defined by xdg_surface.set_window_geometry of the + * parent surface. + * + * When the xdg_positioner object is used to position a child surface, the + * anchor rectangle may not extend outside the window geometry of the + * positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines the anchor point for the anchor rectangle. The specified anchor + * is used derive an anchor point that the child surface will be + * positioned relative to. If a corner anchor is set (e.g. 'top_left' or + * 'bottom_right'), the anchor point will be at the specified corner; + * otherwise, the derived anchor point will be centered on the specified + * edge, or in the center of the anchor rectangle if no edge is specified. + */ +static inline void +xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines in what direction a surface should be positioned, relative to + * the anchor point of the parent surface. If a corner gravity is + * specified (e.g. 'bottom_right' or 'top_left'), then the child surface + * will be placed towards the specified gravity; otherwise, the child + * surface will be centered over the anchor point on any axis that had no + * gravity specified. If the gravity is not in the ‘gravity’ enum, an + * invalid_input error is raised. + */ +static inline void +xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify how the window should be positioned if the originally intended + * position caused the surface to be constrained, meaning at least + * partially outside positioning boundaries set by the compositor. The + * adjustment is set by constructing a bitmask describing the adjustment to + * be made when the surface is constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that the child + * surface should not change its position on that axis when constrained. + * + * If more than one bit for one axis is set, the order of how adjustments + * are applied is specified in the corresponding adjustment descriptions. + * + * The default adjustment is none. + */ +static inline void +xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the surface position offset relative to the position of the + * anchor on the anchor rectangle and the anchor on the surface. For + * example if the anchor of the anchor rectangle is at (x, y), the surface + * has the gravity bottom|right, and the offset is (ox, oy), the calculated + * surface position will be (x + ox, y + oy). The offset position of the + * surface is the one used for constraint testing. See + * set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user interface + * element, while aligning the user interface element of the parent surface + * with some user interface element placed somewhere in the popup surface. + */ +static inline void +xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y); +} + +/** + * @ingroup iface_xdg_positioner + * + * When set reactive, the surface is reconstrained if the conditions used + * for constraining changed, e.g. the parent window moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, followed by an + * xdg_surface.configure event. + */ +static inline void +xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information to + * determine the future state the popup should be constrained using. If + * this doesn't match the dimension of the parent the popup is eventually + * positioned against, the behavior is undefined. + * + * The arguments are given in the surface-local coordinate space. + */ +static inline void +xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the serial of an xdg_surface.configure event this positioner will be + * used in response to. The compositor may use this information together + * with set_parent_size to determine what future state the popup should be + * constrained using. + */ +static inline void +xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial); +} + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + /** + * Surface was not fully constructed + */ + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + /** + * Surface was already constructed + */ + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + /** + * Attaching a buffer to an unconfigured surface + */ + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, + /** + * Invalid serial number when acking a configure event + */ + XDG_SURFACE_ERROR_INVALID_SERIAL = 4, + /** + * Width or height was zero or negative + */ + XDG_SURFACE_ERROR_INVALID_SIZE = 5, + /** + * Surface was destroyed before its role object + */ + XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6, +}; +#endif /* XDG_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_listener + */ +struct xdg_surface_listener { + /** + * suggest a surface change + * + * The configure event marks the end of a configure sequence. A + * configure sequence is a set of one or more events configuring + * the state of the xdg_surface, including the final + * xdg_surface.configure event. + * + * Where applicable, xdg_surface surface roles will during a + * configure sequence extend this event as a latched state sent as + * events before the xdg_surface.configure event. Such events + * should be considered to make up a set of atomically applied + * configuration states, where the xdg_surface.configure commits + * the accumulated state. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + * @param serial serial of the configure event + */ + void (*configure)(void *data, + struct xdg_surface *xdg_surface, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_surface + */ +static inline int +xdg_surface_add_listener(struct xdg_surface *xdg_surface, + const struct xdg_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, + (void (**)(void)) listener, data); +} + +#define XDG_SURFACE_DESTROY 0 +#define XDG_SURFACE_GET_TOPLEVEL 1 +#define XDG_SURFACE_GET_POPUP 2 +#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3 +#define XDG_SURFACE_ACK_CONFIGURE 4 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** @ingroup iface_xdg_surface */ +static inline void +xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); +} + +/** @ingroup iface_xdg_surface */ +static inline void * +xdg_surface_get_user_data(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); +} + +static inline uint32_t +xdg_surface_get_version(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_surface); +} + +/** + * @ingroup iface_xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be destroyed + * after its role object has been destroyed, otherwise + * a defunct_role_object error is raised. + */ +static inline void +xdg_surface_destroy(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_toplevel object for the given xdg_surface and gives + * the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about what an + * xdg_toplevel is and how it is used. + */ +static inline struct xdg_toplevel * +xdg_surface_get_toplevel(struct xdg_surface *xdg_surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL); + + return (struct xdg_toplevel *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_popup object for the given xdg_surface and gives + * the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be specified using + * some other protocol, before committing the initial state. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline struct xdg_popup * +xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner); + + return (struct xdg_popup *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * The window geometry of a surface is its "visible bounds" from the + * user's perspective. Client-side decorations often have invisible + * portions like drop-shadows which should be ignored for the + * purposes of aligning, placing and constraining windows. + * + * The window geometry is double-buffered state, see wl_surface.commit. + * + * When maintaining a position, the compositor should treat the (x, y) + * coordinate of the window geometry as the top left corner of the window. + * A client changing the (x, y) window geometry coordinate should in + * general not alter the position of the window. + * + * Once the window geometry of the surface is set, it is not possible to + * unset it, and it will remain the same until set_window_geometry is + * called again, even if a new subsurface or buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface, and may extend outside + * of the wl_surface itself to mark parts of the subsurface tree as part of + * the window geometry. + * + * When applied, the effective window geometry will be the set window + * geometry clamped to the bounding rectangle of the combined + * geometry of the surface of the xdg_surface and the associated + * subsurfaces. + * + * The effective geometry will not be recalculated unless a new call to + * set_window_geometry is done and the new pending surface state is + * subsequently applied. + * + * The width and height of the effective window geometry must be + * greater than zero. Setting an invalid size will raise an + * invalid_size error. + */ +static inline void +xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height); +} + +/** + * @ingroup iface_xdg_surface + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client + * must make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use this + * information to move a surface to the top left only when the client has + * drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it + * can respond to one, it only has to ack the last configure event. + * Acking a configure event that was never sent raises an invalid_serial + * error. + * + * A client is not required to commit immediately after sending + * an ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before committing, but + * only the last request sent before a commit indicates which configure + * event the client really is responding to. + * + * Sending an ack_configure request consumes the serial number sent with + * the request, as well as serial numbers sent by all configure events + * sent on this xdg_surface prior to the configure event referenced by + * the committed serial. + * + * It is an error to issue multiple ack_configure requests referencing a + * serial from the same configure event, or to issue an ack_configure + * request referencing a serial from a configure event issued before the + * event identified by the last ack_configure request for the same + * xdg_surface. Doing so will raise an invalid_serial error. + */ +static inline void +xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface, + XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial); +} + +#ifndef XDG_TOPLEVEL_ERROR_ENUM +#define XDG_TOPLEVEL_ERROR_ENUM +enum xdg_toplevel_error { + /** + * provided value is not a valid variant of the resize_edge enum + */ + XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0, + /** + * invalid parent toplevel + */ + XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1, + /** + * client provided an invalid min or max size + */ + XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2, +}; +#endif /* XDG_TOPLEVEL_ERROR_ENUM */ + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * types of state on the surface + * + * The different state values used on the surface. This is designed for + * state values like maximized, fullscreen. It is paired with the + * configure event to ensure that both the client and the compositor + * setting the state can be synchronized. + * + * States set in this way are double-buffered, see wl_surface.commit. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + * the surface is maximized + * + * The surface is maximized. The window geometry specified in the + * configure event must be obeyed by the client, or the + * xdg_wm_base.invalid_surface_state error is raised. + * + * The client should draw without shadow or other decoration + * outside of the window geometry. + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + * the surface is fullscreen + * + * The surface is fullscreen. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. For a surface to cover the whole fullscreened area, + * the geometry dimensions must be obeyed by the client. For more + * details, see xdg_toplevel.set_fullscreen. + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + * the surface is being resized + * + * The surface is being resized. The window geometry specified in + * the configure event is a maximum; the client cannot resize + * beyond it. Clients that have aspect ratio or cell sizing + * configuration can use a smaller size, however. + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + * the surface is now activated + * + * Client window decorations should be painted as if the window + * is active. Do not assume this means that the window actually has + * keyboard or pointer focus. + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * the surface’s left edge is tiled + * + * The window is currently in a tiled layout and the left edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the left edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * the surface’s right edge is tiled + * + * The window is currently in a tiled layout and the right edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the right edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * the surface’s top edge is tiled + * + * The window is currently in a tiled layout and the top edge is + * considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the top edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * the surface’s bottom edge is tiled + * + * The window is currently in a tiled layout and the bottom edge + * is considered to be adjacent to another part of the tiling grid. + * + * The client should draw without shadow or other decoration + * outside of the window geometry on the bottom edge. + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + /** + * surface repaint is suspended + * + * The surface is currently not ordinarily being repainted; for + * example because its content is occluded by another window, or + * its outputs are switched off due to screen locking. + * @since 6 + */ + XDG_TOPLEVEL_STATE_SUSPENDED = 9, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM +enum xdg_toplevel_wm_capabilities { + /** + * show_window_menu is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1, + /** + * set_maximized and unset_maximized are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2, + /** + * set_fullscreen and unset_fullscreen are available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3, + /** + * set_minimized is available + */ + XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4, +}; +#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_listener + */ +struct xdg_toplevel_listener { + /** + * suggest a surface change + * + * This configure event asks the client to resize its toplevel + * surface or to change its state. The configured state should not + * be applied immediately. See xdg_surface.configure for details. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor needs to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + */ + void (*configure)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states); + /** + * surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any. + * + * This is only a request that the user intends to close the + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data, etc. + */ + void (*close)(void *data, + struct xdg_toplevel *xdg_toplevel); + /** + * recommended window geometry bounds + * + * The configure_bounds event may be sent prior to a + * xdg_toplevel.configure event to communicate the bounds a window + * geometry size is recommended to constrain to. + * + * The passed width and height are in surface coordinate space. If + * width and height are 0, it means bounds is unknown and + * equivalent to as if no configure_bounds event was ever sent for + * this surface. + * + * The bounds can for example correspond to the size of a monitor + * excluding any panels or other shell components, so that a + * surface isn't created in a way that it cannot fit. + * + * The bounds may change at any point, and in such a case, a new + * xdg_toplevel.configure_bounds will be sent, followed by + * xdg_toplevel.configure and xdg_surface.configure. + * @since 4 + */ + void (*configure_bounds)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height); + /** + * compositor capabilities + * + * This event advertises the capabilities supported by the + * compositor. If a capability isn't supported, clients should hide + * or disable the UI elements that expose this functionality. For + * instance, if the compositor doesn't advertise support for + * minimized toplevels, a button triggering the set_minimized + * request should not be displayed. + * + * The compositor will ignore requests it doesn't support. For + * instance, a compositor which doesn't advertise support for + * minimized will ignore set_minimized requests. + * + * Compositors must send this event once before the first + * xdg_surface.configure event. When the capabilities change, + * compositors must send this event again and then send an + * xdg_surface.configure event. + * + * The configured state should not be applied immediately. See + * xdg_surface.configure for details. + * + * The capabilities are sent as an array of 32-bit unsigned + * integers in native endianness. + * @param capabilities array of 32-bit capabilities + * @since 5 + */ + void (*wm_capabilities)(void *data, + struct xdg_toplevel *xdg_toplevel, + struct wl_array *capabilities); +}; + +/** + * @ingroup iface_xdg_toplevel + */ +static inline int +xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, + const struct xdg_toplevel_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel, + (void (**)(void)) listener, data); +} + +#define XDG_TOPLEVEL_DESTROY 0 +#define XDG_TOPLEVEL_SET_PARENT 1 +#define XDG_TOPLEVEL_SET_TITLE 2 +#define XDG_TOPLEVEL_SET_APP_ID 3 +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4 +#define XDG_TOPLEVEL_MOVE 5 +#define XDG_TOPLEVEL_RESIZE 6 +#define XDG_TOPLEVEL_SET_MAX_SIZE 7 +#define XDG_TOPLEVEL_SET_MIN_SIZE 8 +#define XDG_TOPLEVEL_SET_MAXIMIZED 9 +#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10 +#define XDG_TOPLEVEL_SET_FULLSCREEN 11 +#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12 +#define XDG_TOPLEVEL_SET_MINIMIZED 13 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel */ +static inline void +xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data); +} + +/** @ingroup iface_xdg_toplevel */ +static inline void * +xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel); +} + +static inline uint32_t +xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ +static inline void +xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set the "parent" of this surface. This surface should be stacked + * above the parent surface and all other ancestor surfaces. + * + * Parent surfaces should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the dialog + * is raised. + * + * Setting a null parent for a child surface unsets its parent. Setting + * a null parent for a surface which currently has no parent is a no-op. + * + * Only mapped surfaces can have child surfaces. Setting a parent which + * is not mapped is equivalent to setting a null parent. If a surface + * becomes unmapped, its children's parent is set to the parent of + * the now-unmapped surface. If the now-unmapped surface has no parent, + * its children's parent is unset. If the now-unmapped surface becomes + * mapped again, its parent-child relationship is not restored. + * + * The parent toplevel must not be one of the child toplevel's + * descendants, and the parent must be different from the child toplevel, + * otherwise the invalid_parent protocol error is raised. + */ +static inline void +xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group multiple + * surfaces together, or to determine how to launch a new application. + * + * For D-Bus activatable applications, the app ID is used as the D-Bus + * service name. + * + * The compositor shell will try to group application surfaces together + * by their app ID. As a best practice, it is suggested to select app + * ID's that match the basename of the application's .desktop file. + * For example, "org.freedesktop.FooViewer" where the .desktop file is + * "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after the + * xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] https://standards.freedesktop.org/desktop-entry-spec/ + */ +static inline void +xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Clients implementing client-side decorations might want to show + * a context menu when right-clicking on the decorations, giving the + * user a menu that they can use to maximize or minimize the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu items + * the window menu contains, or even if a window menu will be drawn + * at all. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. + */ +static inline void +xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive move (touch, + * pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed serial + * is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, such as + * updating a pointer cursor, during the move. There is no guarantee + * that the device focus will return when the move is completed. + */ +static inline void +xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive resize (touch, + * pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the "resize" + * enum value for more details about what is required. The client + * must also acknowledge configure events using "ack_configure". After + * the resize is completed, the client will receive another "configure" + * event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is no + * guarantee that the device focus will return when the resize is + * completed. + * + * The edges parameter specifies how the surface should be resized, and + * is one of the values of the resize_edge enum. Values not matching + * a variant of the enum will cause the invalid_resize_edge protocol error. + * The compositor may use this information to update the surface position + * for example when dragging the top left corner. The compositor may also + * use this information to adapt its behavior, e.g. choose an appropriate + * cursor image. + */ +static inline void +xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor does + * not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. + * As a result, a client wishing to reset the maximum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width or height will result in a + * invalid_size error. + */ +static inline void +xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor does + * not try to configure the window below this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered, see wl_surface.commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. + * As a result, a client wishing to reset the minimum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in an invalid_size error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in a + * invalid_size error. + */ +static inline void +xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the compositor + * will respond by emitting a configure event. Whether this configure + * actually sets the window maximized is subject to compositor policies. + * The client must then update its content, drawing in the configured + * state. The client must also acknowledge the configure when committing + * the new content (see ack_configure). + * + * It is up to the compositor to decide how and where to maximize the + * surface, for example which output and what region of the screen should + * be used. + * + * If the surface was already maximized, the compositor will still emit + * a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the compositor + * will respond by emitting a configure event. Whether this actually + * un-maximizes the window is subject to compositor policies. + * If available and applicable, the compositor will include the window + * geometry dimensions the window had prior to being maximized in the + * configure event. The client must then update its content, drawing it in + * the configured state. The client must also acknowledge the configure + * when committing the new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before maximizing, if + * applicable. + * + * If the surface was already not maximized, the compositor will still + * emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether the + * client is actually put into a fullscreen state is subject to compositor + * policies. The client must also acknowledge the configure when + * committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's preference as + * to which display it should be set fullscreen on. If this value is NULL, + * it's up to the compositor to choose which display will be used to map + * this surface. + * + * If the surface doesn't cover the whole output, the compositor will + * position the surface in the center of the output and compensate with + * with border fill covering the rest of the output. The content of the + * border fill is undefined, but should be assumed to be in some way that + * attempts to blend into the surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + */ +static inline void +xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. + * Whether this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based on the following: + * * the state(s) it may have had before becoming fullscreen + * * any state(s) decided by the compositor + * * any state(s) requested by the client while the surface was fullscreen + * + * The compositor may include the previous window geometry dimensions in + * the configure event, if applicable. + * + * The client must also acknowledge the configure when committing the new + * content (see ack_configure). + */ +static inline void +xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ +static inline void +xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_listener + */ +struct xdg_popup_listener { + /** + * configure the popup surface + * + * This event asks the popup surface to configure itself given + * the configuration. The configured state should not be applied + * immediately. See xdg_surface.configure for details. + * + * The x and y arguments represent the position the popup was + * placed at given the xdg_positioner rule, relative to the upper + * left corner of the window geometry of the parent surface. + * + * For version 2 or older, the configure event for an xdg_popup is + * only ever sent once for the initial configuration. Starting with + * version 3, it may be sent again if the popup is setup with an + * xdg_positioner with set_reactive requested, or in response to + * xdg_popup.reposition requests. + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ + void (*configure)(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct xdg_popup *xdg_popup); + /** + * signal the completion of a repositioned request + * + * The repositioned event is sent as part of a popup + * configuration sequence, together with xdg_popup.configure and + * lastly xdg_surface.configure to notify the completion of a + * reposition request. + * + * The repositioned event is to notify about the completion of a + * xdg_popup.reposition request. The token argument is the token + * passed in the xdg_popup.reposition request. + * + * Immediately after this event is emitted, xdg_popup.configure and + * xdg_surface.configure will be sent with the updated size and + * position, as well as a new configure serial. + * + * The client should optionally update the content of the popup, + * but must acknowledge the new popup configuration for the new + * position to take effect. See xdg_surface.ack_configure for + * details. + * @param token reposition request token + * @since 3 + */ + void (*repositioned)(void *data, + struct xdg_popup *xdg_popup, + uint32_t token); +}; + +/** + * @ingroup iface_xdg_popup + */ +static inline int +xdg_popup_add_listener(struct xdg_popup *xdg_popup, + const struct xdg_popup_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, + (void (**)(void)) listener, data); +} + +#define XDG_POPUP_DESTROY 0 +#define XDG_POPUP_GRAB 1 +#define XDG_POPUP_REPOSITION 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** @ingroup iface_xdg_popup */ +static inline void +xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); +} + +/** @ingroup iface_xdg_popup */ +static inline void * +xdg_popup_get_user_data(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); +} + +static inline uint32_t +xdg_popup_get_version(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_xdg_popup + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, the + * xdg_wm_base.not_the_topmost_popup protocol error will be sent. + */ +static inline void +xdg_popup_destroy(struct xdg_popup *xdg_popup) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_xdg_popup + * + * This request makes the created popup take an explicit grab. An explicit + * grab will be dismissed when the user dismisses the popup, or when the + * client destroys the xdg_popup. This can be done by the user clicking + * outside the surface, using the keyboard, or even locking the screen + * through closing the lid or a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user action like a + * button press, key press, or touch down event. The serial number of the + * event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel surface or + * another xdg_popup with an explicit grab. If the parent is another + * xdg_popup it means that the popups are nested, with this popup now being + * the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were created + * in, e.g. the only popup you are allowed to destroy at all times is the + * topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss every + * nested grabbing popup as well. When a compositor dismisses popups, it + * will follow the same dismissing order as required from the client. + * + * If the topmost grabbing popup is destroyed, the grab will be returned to + * the parent of the popup, if that parent previously had an explicit grab. + * + * If the parent is a grabbing popup which has already been dismissed, this + * popup will be immediately dismissed. If the parent is a popup that did + * not take an explicit grab, an error will be raised. + * + * During a popup grab, the client owning the grab will receive pointer + * and touch events for all their surfaces as normal (similar to an + * "owner-events" grab in X11 parlance), while the top most grabbing popup + * will always have keyboard focus. + */ +static inline void +xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial); +} + +/** + * @ingroup iface_xdg_popup + * + * Reposition an already-mapped popup. The popup will be placed given the + * details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any parameters set + * by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not take + * effect until the corresponding configure event is acknowledged by the + * client. See xdg_popup.repositioned for details. The token itself is + * opaque, and has no other special meaning. + * + * If multiple reposition requests are sent, the compositor may skip all + * but the last one. + * + * If the popup is repositioned in response to a configure event for its + * parent, the client should send an xdg_positioner.set_parent_configure + * and possibly an xdg_positioner.set_parent_size request to allow the + * compositor to properly constrain the popup. + * + * If the popup is repositioned together with a parent that is being + * resized, but not in response to a configure event, the client should + * send an xdg_positioner.set_parent_size request. + */ +static inline void +xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token) +{ + wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup, + XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/host/linux/wayland/xdg-shell-protocol.c b/examples/host/linux/wayland/xdg-shell-protocol.c new file mode 100644 index 00000000..d698c2ca --- /dev/null +++ b/examples/host/linux/wayland/xdg-shell-protocol.c @@ -0,0 +1,184 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * Copyright © 2015-2017 Samsung Electronics Co., Ltd + * Copyright © 2015-2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface xdg_positioner_interface; +extern const struct wl_interface xdg_surface_interface; +extern const struct wl_interface xdg_toplevel_interface; + +static const struct wl_interface *xdg_shell_types[] = { + NULL, + NULL, + NULL, + NULL, + &xdg_positioner_interface, + &xdg_surface_interface, + &wl_surface_interface, + &xdg_toplevel_interface, + &xdg_popup_interface, + &xdg_surface_interface, + &xdg_positioner_interface, + &xdg_toplevel_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, + &xdg_positioner_interface, + NULL, +}; + +static const struct wl_message xdg_wm_base_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "create_positioner", "n", xdg_shell_types + 4 }, + { "get_xdg_surface", "no", xdg_shell_types + 5 }, + { "pong", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_wm_base_events[] = { + { "ping", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", 6, + 4, xdg_wm_base_requests, + 1, xdg_wm_base_events, +}; + +static const struct wl_message xdg_positioner_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_size", "ii", xdg_shell_types + 0 }, + { "set_anchor_rect", "iiii", xdg_shell_types + 0 }, + { "set_anchor", "u", xdg_shell_types + 0 }, + { "set_gravity", "u", xdg_shell_types + 0 }, + { "set_constraint_adjustment", "u", xdg_shell_types + 0 }, + { "set_offset", "ii", xdg_shell_types + 0 }, + { "set_reactive", "3", xdg_shell_types + 0 }, + { "set_parent_size", "3ii", xdg_shell_types + 0 }, + { "set_parent_configure", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", 6, + 10, xdg_positioner_requests, + 0, NULL, +}; + +static const struct wl_message xdg_surface_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "get_toplevel", "n", xdg_shell_types + 7 }, + { "get_popup", "n?oo", xdg_shell_types + 8 }, + { "set_window_geometry", "iiii", xdg_shell_types + 0 }, + { "ack_configure", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_surface_events[] = { + { "configure", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_surface_interface = { + "xdg_surface", 6, + 5, xdg_surface_requests, + 1, xdg_surface_events, +}; + +static const struct wl_message xdg_toplevel_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_parent", "?o", xdg_shell_types + 11 }, + { "set_title", "s", xdg_shell_types + 0 }, + { "set_app_id", "s", xdg_shell_types + 0 }, + { "show_window_menu", "ouii", xdg_shell_types + 12 }, + { "move", "ou", xdg_shell_types + 16 }, + { "resize", "ouu", xdg_shell_types + 18 }, + { "set_max_size", "ii", xdg_shell_types + 0 }, + { "set_min_size", "ii", xdg_shell_types + 0 }, + { "set_maximized", "", xdg_shell_types + 0 }, + { "unset_maximized", "", xdg_shell_types + 0 }, + { "set_fullscreen", "?o", xdg_shell_types + 21 }, + { "unset_fullscreen", "", xdg_shell_types + 0 }, + { "set_minimized", "", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_toplevel_events[] = { + { "configure", "iia", xdg_shell_types + 0 }, + { "close", "", xdg_shell_types + 0 }, + { "configure_bounds", "4ii", xdg_shell_types + 0 }, + { "wm_capabilities", "5a", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", 6, + 14, xdg_toplevel_requests, + 4, xdg_toplevel_events, +}; + +static const struct wl_message xdg_popup_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "grab", "ou", xdg_shell_types + 22 }, + { "reposition", "3ou", xdg_shell_types + 24 }, +}; + +static const struct wl_message xdg_popup_events[] = { + { "configure", "iiii", xdg_shell_types + 0 }, + { "popup_done", "", xdg_shell_types + 0 }, + { "repositioned", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_popup_interface = { + "xdg_popup", 6, + 3, xdg_popup_requests, + 3, xdg_popup_events, +}; + diff --git a/examples/host/linux/wayland/xdgshell.cpp b/examples/host/linux/wayland/xdgshell.cpp new file mode 100644 index 00000000..c6ffba77 --- /dev/null +++ b/examples/host/linux/wayland/xdgshell.cpp @@ -0,0 +1,84 @@ +#include "xdgshell.h" + +using namespace WL; + +void XDGWmBase::bind(wl_registry *reg, uint32_t name, uint32_t version) noexcept +{ + registry(reg, name, version); + + static const xdg_wm_base_listener listener = { + .ping = [](void*, xdg_wm_base *wm_base, uint32_t serial){ + xdg_wm_base_pong(wm_base, serial); + } + }; + + xdg_wm_base_add_listener (c_ptr(), &listener, nullptr); +} + +Toplevel::Toplevel(const Display &dpy, uint32_t width, uint32_t height) + : Surface(dpy.compositor(), dpy.protocol()) + , m_xdg_surfase(xdg_wm_base_get_xdg_surface(dpy.ensureProtocol().c_ptr(), c_ptr()), + "Can't create xdg surface") + , m_top(xdg_surface_get_toplevel(m_xdg_surfase.c_ptr()), + "Can't create toplevel role") + , m_decor(dpy.protocol() ? + zxdg_decoration_manager_v1_get_toplevel_decoration( + dpy.protocol()->c_ptr(), m_top.c_ptr()) + :nullptr) + , m_width(width) + , m_height(height) + , m_state(0) +{ + static const xdg_toplevel_listener toplevel_lsr{ + .configure = [](void* data, xdg_toplevel *tt, + int32_t width, int32_t height, wl_array *states){ + + auto inst = static_cast(data); + + xdg_toplevel_state *pos; + inst->m_state = 0; + + for (pos = (xdg_toplevel_state*)states->data; + (const char *) pos < ((const char *) states->data + states->size); + (pos)++){ + + inst->m_state |= (1 << *pos); + } + + if (width && height){ + inst->m_width = width; + inst->m_height = height; + } + }, + .close = [](void *data, xdg_toplevel*){ + auto inst = static_cast(data); + inst->closed(); + }, + .configure_bounds = [](void* data, xdg_toplevel*, int32_t width, int32_t height){ + + }, + .wm_capabilities = [](void *data, + xdg_toplevel *xdg_toplevel, + wl_array *capabilities){ + } + }; + + xdg_toplevel_add_listener(m_top.c_ptr(), &toplevel_lsr, this); + + static const xdg_surface_listener surface_lsr{ + .configure = [](void* data, xdg_surface *xdg_surf, uint32_t serial){ + + auto inst = static_cast(data); + xdg_surface_ack_configure(xdg_surf, serial); + + inst->configure(inst->m_width, inst->m_height, inst->m_state); + } + }; + + xdg_surface_add_listener (this->m_xdg_surfase.c_ptr(), &surface_lsr, this); + commit(); + + if (m_decor) + zxdg_toplevel_decoration_v1_set_mode(m_decor.c_ptr(), + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +} diff --git a/examples/host/linux/wayland/xdgshell.h b/examples/host/linux/wayland/xdgshell.h new file mode 100644 index 00000000..0116d880 --- /dev/null +++ b/examples/host/linux/wayland/xdgshell.h @@ -0,0 +1,65 @@ +#ifndef XDGSHELL_H +#define XDGSHELL_H + +#include "display.h" +#include "xdg-shell-client-protocol.h" +#include "xdg-decoration-unstable-v1-client-protocol.h" + +namespace WL { + +enum XDGState +{ + resizing = 1 << XDG_TOPLEVEL_STATE_RESIZING, + maximized = 1 << XDG_TOPLEVEL_STATE_MAXIMIZED, + activated = 1 << XDG_TOPLEVEL_STATE_ACTIVATED, + fullscreen = 1 << XDG_TOPLEVEL_STATE_FULLSCREEN +}; + +class XDGWmBase final: public Protocol +{ +public: + void bind(wl_registry *reg, uint32_t name, uint32_t version) noexcept override; +}; + +//--------Decoration--------//////////////////////////////////////////// + +using XDGDecorateManager = Protocol; + +class Toplevel: public Surface +{ +public: + Toplevel(const Display &dpy, uint32_t width, uint32_t height); + + void setTitle(const char* title) + {xdg_toplevel_set_title(m_top.c_ptr(), title);} + + void setAppID(const char* id) + {xdg_toplevel_set_app_id(m_top.c_ptr(), id);} + +private: + Proxy m_xdg_surfase; + Proxy m_top; + Proxy m_decor; + +protected: + uint32_t m_width ; + uint32_t m_height; + uint32_t m_state ; + + virtual void closed() = 0; + + /** + * configure called by the composer when the state (s) + * and/or window dimensions (w, h) change + */ + virtual void configure(unsigned w, unsigned h, unsigned s) = 0; +}; + +} + +#endif // XDGSHELL_H diff --git a/examples/host/linux/x11/application.cpp b/examples/host/linux/x11/application.cpp new file mode 100644 index 00000000..4db1ebc3 --- /dev/null +++ b/examples/host/linux/x11/application.cpp @@ -0,0 +1,405 @@ +#include "../application.h" +#include "../skia_context.h" +#include "../logger.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace X11 { + + class ContextGLX final: public GlSkiaContext + { + public: + struct Buffer final + { + Window win_id{0}; + Colormap colormap{0}; + + void destroy(Display* dpy) + { + if (win_id){ + XFreeColormap (dpy, colormap); + XDestroyWindow(dpy, win_id); + } + } + }; + + struct Config final + { + explicit Config(Display* dpy, int width, int height); + ~Config() + {m_buffer.destroy(x11_dpy);} + + Buffer move_buffer() + { + auto id = m_buffer.win_id; + m_buffer.win_id = 0; + + return {id, m_buffer.colormap}; + } + + private: + Display* x11_dpy; + GLXFBConfig fb_config; + Buffer m_buffer; + + friend class ContextGLX; + }; + + void init(const Config &cfg); + void makeCurrent(const Buffer &buf); + void flush(Buffer &buf); + + ~ContextGLX(); + + Display* x11_display{nullptr}; + + private: + GLXContext m_context{nullptr}; + }; + + ContextGLX::Config::Config(Display* dpy, int width, int height): + x11_dpy(dpy) + { + auto screen_id = DefaultScreen(dpy); + + GLint majorGLX, minorGLX = 0; + glXQueryVersion(dpy, &majorGLX, &minorGLX); + + Logger::debug("GLX: %i.%i", majorGLX, minorGLX); + + GLint glxAttribs[] = { + GLX_X_RENDERABLE , True, + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, + GLX_RENDER_TYPE , GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, + GLX_RED_SIZE , 8, + GLX_GREEN_SIZE , 8, + GLX_BLUE_SIZE , 8, + GLX_ALPHA_SIZE , 8, + GLX_DEPTH_SIZE , 24, + GLX_STENCIL_SIZE , 8, + GLX_DOUBLEBUFFER , True, + None + }; + + XVisualInfo *info{nullptr}; + int fbcount; + GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen_id, glxAttribs, &fbcount); + if (fbc == 0) + throw std::runtime_error("Failed to retrieve framebuffer."); + + // Pick the FB config/visual with the most samples per pixel + int best_fbc = -1, best_num_samp = -1; + for (int i = 0; i < fbcount; ++i) { + XVisualInfo *vi = glXGetVisualFromFBConfig(dpy, fbc[i]); + if (vi) { + int samp_buf, samples; + glXGetFBConfigAttrib( dpy, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); + glXGetFBConfigAttrib( dpy, fbc[i], GLX_SAMPLES , &samples ); + + if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) ) { + best_fbc = i; + best_num_samp = samples; + if (info) + XFree(info); + info = vi; + } + else + XFree(vi); + } + } + + if (best_fbc < 0) + throw std::runtime_error("Failed to get a valid GLX visual"); + + fb_config = fbc[best_fbc]; + XFree(fbc); + + Window window_root_id = RootWindow(dpy, screen_id); + m_buffer.colormap = XCreateColormap(dpy, window_root_id, info->visual, AllocNone); + + XSetWindowAttributes windowAttribs; + windowAttribs.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask; + //windowAttribs.border_pixel = WhitePixel(m_display, screen_id); + //windowAttribs.background_pixel = WhitePixel(dpyx.display, screen_id); + //windowAttribs.override_redirect = True; + windowAttribs.colormap = m_buffer.colormap; + + m_buffer.win_id = XCreateWindow(dpy, + window_root_id, + 0, + 0, + width, + height, + 0, + info->depth, + InputOutput, + info->visual, + CWColormap | CWEventMask, // | CWBackPixel | CWBorderPixel, + &windowAttribs); + XFree(info); + } + + void ContextGLX::init(const Config &cfg) + { + assert(!m_context); // double initialization + + x11_display = cfg.x11_dpy; + + // Create GLX OpenGL context + typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = + (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte*) "glXCreateContextAttribsARB" ); + + int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 0, + //GLX_CONTEXT_FLAGS_ARB, 0, + 0, 0 + }; + + const char *glxExts = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display)); + if (strstr(glxExts, "GLX_ARB_create_context") == 0) { + std::cout << "GLX_ARB_create_context not supported"< void * { + return (void *) glXGetProcAddress((const GLubyte *)p); + }); + + Logger::debug("GL Renderer: %s, GL Version: %s, GLSL Version: %s", + glGetString(GL_RENDERER), + glGetString(GL_VERSION), + glGetString(GL_SHADING_LANGUAGE_VERSION)); + } + + ContextGLX::~ContextGLX() + { + glXDestroyContext(x11_display, m_context); + } + + void ContextGLX::makeCurrent(const Buffer &buf) + { + assert(x11_display); + + if (buf.win_id && m_context) + glXMakeContextCurrent(x11_display, buf.win_id, buf.win_id, m_context); + else + glXMakeCurrent(x11_display, 0, nullptr); + } + + void ContextGLX::flush(Buffer &buf) + { + assert(x11_display); + + if (m_context) + glXSwapBuffers(x11_display, buf.win_id); + } +} + +struct Surface::Impl +{ + Impl(Display* display, Surface* holder, int width, int height): + m_holder(holder), + m_need_redraw(false), + wm_delete_window_atom(XInternAtom(display, "WM_DELETE_WINDOW", False)) + { + X11::ContextGLX::Config cfg(display, width, height); + m_context.init(cfg); + + holder->skia_surf = m_context.makeSurface(width, height); + m_buffer = cfg.move_buffer(); + + XSetWMProtocols(display, m_buffer.win_id, &wm_delete_window_atom, 1); + XClearWindow(display, m_buffer.win_id); + XMapWindow(display, m_buffer.win_id); + } + + ~Impl() + { + m_context.makeCurrent({}); + m_buffer.destroy(m_context.x11_display); + } + + void event_process() + { + auto dpy = m_context.x11_display; + + if (m_need_redraw) draw(); + + while(XPending(dpy)){ + + XEvent xevent; + XNextEvent(dpy, &xevent); + + /* input */ + if (xevent.type==KeyPress) { + + /* resize */ + } else if (xevent.type == ConfigureNotify + && !xevent.xconfigure.send_event) { + + m_holder->configure(xevent.xconfigure.width, + xevent.xconfigure.height, + SurfaceState::resizing); + + /* draw graphics */ + } else if (xevent.type == Expose + && xevent.xexpose.count == 0 ) { + + if (xevent.xexpose.width == 1 && xevent.xexpose.height == 1) { + m_holder->configure(0, 0, SurfaceState::resizing); + continue; + } + + draw(); + + /* close window */ + } else if ( xevent.type == ClientMessage + && xevent.xclient.data.l[0] == wm_delete_window_atom ) { + + m_holder->closed(); + + }else if ( xevent.type == MapNotify ) { + std::cout << "MapNotify " <draw(1); + + m_holder->skia_surf->flush(); + m_context.flush(m_buffer); + } + + X11::ContextGLX m_context; + X11::ContextGLX::Buffer m_buffer; + Surface* m_holder; + bool m_need_redraw; + Atom wm_delete_window_atom; +}; + +class Application::DisplayImpl +{ +public: + static DisplayImpl& inst() + { + static DisplayImpl dpy; + return dpy; + } + + void start_event(bool &isrun); + + Display* display(){return m_display.get();} + +private: + DisplayImpl(): + syslogger("artist_lib_X11"), + m_display(XOpenDisplay(NULL)) + { + if (!m_display) + throw std::runtime_error("Could not open display"); + } + + struct DpyDeleter + { + void operator()(Display* data) const + { + XCloseDisplay(data); + } + }; + + Logger syslogger; + std::unique_ptr m_display; + Surface::Impl* m_win{nullptr}; + friend class Surface; +}; + +void Application::DisplayImpl::start_event(bool &isrun) +{ + auto dpy = m_display.get(); + pollfd m_fds[2]; + + m_fds[0].fd = ConnectionNumber(dpy); + m_fds[0].events = POLLIN; + m_fds[1].fd = -1; //To do add system interrupts + m_fds[1].events = POLLIN; + + XFlush(dpy); + + while (isrun){ + + int ret; + do { + ret = poll(m_fds, 1, -1); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + if (m_fds[0].revents & POLLHUP) + throw std::runtime_error("disconnected by display connection"); + + throw std::runtime_error("failed to poll():"); + } + + m_win->event_process(); + } +} + +void Application::run() +{ + if (isRuning) return; + isRuning = true; + + DisplayImpl::inst().start_event(isRuning); +} + +Surface::~Surface() = default; + +Surface::Surface(int width, int height): + impl(std::make_unique(Application::DisplayImpl::inst().display(), this, width, height)) +{ + Application::DisplayImpl::inst().m_win = impl.get(); +} + +void Surface::setTitle(const char* txt) +{ + XStoreName(impl->m_context.x11_display, impl->m_buffer.win_id, txt); +} + diff --git a/lib/impl/skia/detail/harfbuzz.cpp b/lib/impl/skia/detail/harfbuzz.cpp index e0b6afdc..d1fcaaa8 100644 --- a/lib/impl/skia/detail/harfbuzz.cpp +++ b/lib/impl/skia/detail/harfbuzz.cpp @@ -8,7 +8,7 @@ #include #include -#if defined(_MSC_VER) +#if defined(_MSC_VER) && _MSC_VER < 1800 extern "C" { float roundf(float x)