diff --git a/implementations/Crafter.Graphics-ComputeShader.cpp b/implementations/Crafter.Graphics-ComputeShader.cpp index 3af554b..f1daa93 100644 --- a/implementations/Crafter.Graphics-ComputeShader.cpp +++ b/implementations/Crafter.Graphics-ComputeShader.cpp @@ -74,8 +74,12 @@ void ComputeShader::Load(const std::filesystem::path& spvPath, DescriptorHeapVul }, .layout = layout, }; - Device::CheckVkResult(vkCreateComputePipelines( - Device::device, Device::pipelineCache, 1, &info, nullptr, &pipeline)); + const VkResult created = vkCreateComputePipelines( + Device::device, Device::pipelineCache, 1, &info, nullptr, &pipeline); + // The module is only an input to pipeline creation; VulkanShader does + // not destroy it, so it is released here either way. + vkDestroyShaderModule(Device::device, shader.shader, nullptr); + Device::CheckVkResult(created); return; } @@ -106,8 +110,10 @@ void ComputeShader::Load(const std::filesystem::path& spvPath, DescriptorHeapVul }, .layout = VK_NULL_HANDLE, }; - Device::CheckVkResult(vkCreateComputePipelines( - Device::device, Device::pipelineCache, 1, &info, nullptr, &pipeline)); + const VkResult created = vkCreateComputePipelines( + Device::device, Device::pipelineCache, 1, &info, nullptr, &pipeline); + vkDestroyShaderModule(Device::device, shader.shader, nullptr); + Device::CheckVkResult(created); } void ComputeShader::Dispatch(VkCommandBuffer cmd, diff --git a/implementations/Crafter.Graphics-Device.cpp b/implementations/Crafter.Graphics-Device.cpp index 138107c..f9414c6 100644 --- a/implementations/Crafter.Graphics-Device.cpp +++ b/implementations/Crafter.Graphics-Device.cpp @@ -15,6 +15,7 @@ module; #include "../lib/wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "../lib/fractional-scale-v1.h" #include "../lib/viewporter.h" +#include "../lib/text-input-unstable-v3-client-protocol.h" #include #include #include @@ -303,6 +304,10 @@ void Device::handle_global(void *data, wl_registry *registry, std::uint32_t name if (dataDeviceManager != nullptr && dataDevice == nullptr) { dataDevice = wl_data_device_manager_get_data_device(dataDeviceManager, seat); } + if (textInputManager != nullptr && textInput == nullptr) { + textInput = zwp_text_input_manager_v3_get_text_input(textInputManager, seat); + zwp_text_input_v3_add_listener(textInput, &text_input_listener, nullptr); + } } else if (compositor == nullptr && strcmp(interface, wl_compositor_interface.name) == 0) { compositor = reinterpret_cast(wl_registry_bind(registry, name, &wl_compositor_interface, 3)); } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { @@ -324,9 +329,136 @@ void Device::handle_global(void *data, wl_registry *registry, std::uint32_t name if (seat != nullptr && dataDevice == nullptr) { dataDevice = wl_data_device_manager_get_data_device(dataDeviceManager, seat); } + } else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) { + textInputManager = reinterpret_cast(wl_registry_bind(registry, name, &zwp_text_input_manager_v3_interface, 1)); + if (seat != nullptr && textInput == nullptr) { + textInput = zwp_text_input_manager_v3_get_text_input(textInputManager, seat); + zwp_text_input_v3_add_listener(textInput, &text_input_listener, nullptr); + } } } +namespace { + // A finger's slot by id, or a free one for a new finger; nullptr with more + // than ten fingers down. + Crafter::Device::TouchSlot* SlotFor(std::int32_t id) { + Crafter::Device::TouchSlot* free = nullptr; + for (Crafter::Device::TouchSlot& slot : Crafter::Device::touchSlots) { + if (slot.used && slot.id == id) return &slot; + if (!slot.used && free == nullptr) free = &slot; + } + if (free != nullptr) { + free->used = true; + free->id = id; + free->window = nullptr; + } + return free; + } + + bool AnyTouch() { + for (const Crafter::Device::TouchSlot& slot : Crafter::Device::touchSlots) { + if (slot.used) return true; + } + return false; + } + + // The text input's pending strings live here, as function-local statics: + // an inline static std::string in the interface made clang 23.1 crash + // in ThinLTO for aarch64-alpine-linux-musl. + struct TextInputStrings { + std::string preedit; + std::string shown; // what the window was last told + std::string commit; + }; + + TextInputStrings& TextStrings() { + static TextInputStrings strings; + return strings; + } +} + +void Device::text_input_enter(void*, zwp_text_input_v3*, wl_surface* surface) { + textInputWindow = nullptr; + for (Window* window : windows) { + if (window->surface == surface) textInputWindow = window; + } + if (textInputWindow != nullptr && textInputWindow->textInputActive_) ApplyTextInput(textInputWindow); +} + +// The compositor's leave ends the enable and the composition: the window +// hears that its composing text is gone, and the next enter enables anew. +void Device::text_input_leave(void*, zwp_text_input_v3*, wl_surface*) { + Window* window = textInputWindow; + textInputWindow = nullptr; + textInputHasPreedit = textInputHasCommit = textInputHasDelete = false; + TextStrings().preedit.clear(); + if (window != nullptr) { + window->textInputEnabled_ = false; + if (!TextStrings().shown.empty()) window->onPreedit.Invoke(std::string_view()); + } + TextStrings().shown.clear(); +} + +void Device::text_input_preedit(void*, zwp_text_input_v3*, const char* text, std::int32_t, std::int32_t) { + TextStrings().preedit = text == nullptr ? "" : text; + textInputHasPreedit = true; +} + +void Device::text_input_commit(void*, zwp_text_input_v3*, const char* text) { + TextStrings().commit = text == nullptr ? "" : text; + textInputHasCommit = true; +} + +void Device::text_input_delete(void*, zwp_text_input_v3*, std::uint32_t before, std::uint32_t after) { + textInputDeleteBefore = before; + textInputDeleteAfter = after; + textInputHasDelete = true; +} + +// The protocol's order: the deletion around the cursor, then the committed +// text at the cursor, then the composing text after it. The pending values +// reset with every done, so a round that set no preedit means an empty one; +// the window hears about it only when that differs from what it shows. +void Device::text_input_done(void*, zwp_text_input_v3*, std::uint32_t) { + Window* window = textInputWindow; + TextInputStrings& strings = TextStrings(); + if (!textInputHasPreedit) strings.preedit.clear(); + if (window != nullptr) { + if (textInputHasDelete && (textInputDeleteBefore > 0 || textInputDeleteAfter > 0)) window->onTextInputDelete.Invoke({ textInputDeleteBefore, textInputDeleteAfter }); + if (textInputHasCommit && !strings.commit.empty()) window->onTextInput.Invoke(strings.commit); + if (strings.preedit != strings.shown || (textInputHasCommit && !strings.commit.empty())) { + strings.shown = strings.preedit; + window->onPreedit.Invoke(strings.preedit); + } + } + textInputHasPreedit = textInputHasCommit = textInputHasDelete = false; + strings.commit.clear(); +} + +// enable resets the input method's state, so it goes once per focus; a +// caret that moved sends its rectangle alone. +void Device::ApplyTextInput(Window* window) { + if (textInput == nullptr || window == nullptr || textInputWindow != window) return; + if (window->textInputActive_) { + if (!window->textInputEnabled_) zwp_text_input_v3_enable(textInput); + window->textInputEnabled_ = true; + const bool phone = window->textInputPurpose_ == TextInputPurpose::Phone; + zwp_text_input_v3_set_content_type(textInput, + phone ? ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE : (ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK | ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION), + phone ? ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE : ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL); + const float s = window->scale > 0.0f ? window->scale : 1.0f; + zwp_text_input_v3_set_cursor_rectangle(textInput, + static_cast(window->textInputRect_[0] / s), static_cast(window->textInputRect_[1] / s), + std::max(1, static_cast(window->textInputRect_[2] / s)), std::max(1, static_cast(window->textInputRect_[3] / s))); + } else { + if (!window->textInputEnabled_) return; + window->textInputEnabled_ = false; + zwp_text_input_v3_disable(textInput); + } + zwp_text_input_v3_commit(textInput); + wl_display_flush(display); +} + void Device::handle_global_remove(void* data, wl_registry* registry, uint32_t name) { } @@ -441,11 +573,23 @@ void Device::keyboard_keymap(void *data, wl_keyboard *keyboard, uint32_t format, } void Device::keyboard_enter(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface, wl_array *keys) { - + for (Window* window : windows) { + if (window->surface == surface) { + keyboardWindow = window; + return; + } + } + keyboardWindow = nullptr; } void Device::keyboard_leave(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface) { - + // Releases happen elsewhere while the focus is away: nothing we still + // hold is held, and a repeat must not keep firing into a window that + // lost the keyboard. + if (keyboardWindow != nullptr) keyboardWindow->heldKeys.clear(); + keyboardWindow = nullptr; + keyRepeat.active = false; + keyRepeat.utf8.clear(); } void Device::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { @@ -456,12 +600,16 @@ void Device::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t serial, ui KeyCode code = key; xkb_keycode_t xkbKeycode = key + 8; + // No enter for any of our surfaces (a compositor quirk, or a key for a + // window already gone): nowhere to deliver it. + if (keyboardWindow == nullptr) return; + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - if (focusedWindow->heldKeys.contains(code)) { - focusedWindow->onRawKeyHold.Invoke(code); + if (keyboardWindow->heldKeys.contains(code)) { + keyboardWindow->onRawKeyHold.Invoke(code); } else { - focusedWindow->heldKeys.insert(code); - focusedWindow->onRawKeyDown.Invoke(code); + keyboardWindow->heldKeys.insert(code); + keyboardWindow->onRawKeyDown.Invoke(code); } std::string buf; @@ -471,7 +619,7 @@ void Device::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t serial, ui if (n > 0 && (unsigned char)buf[0] >= 0x20 && buf[0] != 0x7f) { buf.resize(n); utf8 = buf; - focusedWindow->onTextInput.Invoke(utf8); + keyboardWindow->onTextInput.Invoke(utf8); } // Replace the active repeat with this key — most recent press wins, @@ -482,8 +630,8 @@ void Device::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t serial, ui keyRepeat.pressTime = std::chrono::steady_clock::now(); keyRepeat.lastFireTime = keyRepeat.pressTime; } else { - focusedWindow->heldKeys.erase(code); - focusedWindow->onRawKeyUp.Invoke(code); + keyboardWindow->heldKeys.erase(code); + keyboardWindow->onRawKeyUp.Invoke(code); // If the released key was the one repeating, stop. Otherwise leave // the existing repeat alone (user pressed/released a modifier @@ -506,7 +654,7 @@ void Device::keyboard_repeat_info(void *data, wl_keyboard *keyboard, int32_t rat } void Device::TickKeyRepeats() { - if (!keyRepeat.active || !focusedWindow) return; + if (!keyRepeat.active || !keyboardWindow) return; if (keyRepeat.rate <= 0) return; auto now = std::chrono::steady_clock::now(); @@ -521,24 +669,111 @@ void Device::TickKeyRepeats() { // Catch up — emit one event per missed period so a paused frame doesn't // make the repeat permanently lag behind. while (now - keyRepeat.lastFireTime >= period) { - focusedWindow->onRawKeyDown.Invoke(keyRepeat.key); - focusedWindow->onRawKeyHold.Invoke(keyRepeat.key); + keyboardWindow->onRawKeyDown.Invoke(keyRepeat.key); + keyboardWindow->onRawKeyHold.Invoke(keyRepeat.key); if (!keyRepeat.utf8.empty()) { - focusedWindow->onTextInput.Invoke(keyRepeat.utf8); + keyboardWindow->onTextInput.Invoke(keyRepeat.utf8); } keyRepeat.lastFireTime += period; } } -void Device::seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities) { - seat = seat; - if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - wl_pointer* pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(pointer, &pointer_listener, nullptr); +void Device::ForgetTouches() { + for (TouchSlot& slot : touchSlots) slot = TouchSlot{}; +} + +// The first finger stands in for the pointer: it enters the window (so the +// clipboard has a serial and Device::focusedWindow a window), presses the +// left button, moves it and releases it. Every finger is also reported as +// such, in physical pixels. +void Device::touch_down(void*, wl_touch*, std::uint32_t serial, std::uint32_t, wl_surface* surface, std::int32_t id, wl_fixed_t x, wl_fixed_t y) { + Window* window = nullptr; + for (Window* candidate : windows) { + if (candidate->surface == surface) window = candidate; + } + if (window == nullptr) return; + touchWindow = window; + window->lastPointerSerial_ = serial; + const Vector pos = Vector(wl_fixed_to_double(x), wl_fixed_to_double(y)) * window->scale; + if (TouchSlot* slot = SlotFor(id)) { + slot->x = pos.x; + slot->y = pos.y; + slot->window = window; + } + window->onTouchDown.Invoke({ id, pos }); + if (window->primaryTouchId < 0) { + window->primaryTouchId = id; + focusedWindow = window; + window->currentMousePos = pos; + window->mouseLeftHeld = true; + window->onMouseLeftClick.Invoke(); + } +} + +void Device::touch_up(void*, wl_touch*, std::uint32_t, std::uint32_t, std::int32_t id) { + if (touchWindow == nullptr) return; + Window* window = touchWindow; + Vector pos = window->currentMousePos; + if (TouchSlot* slot = SlotFor(id)) { + if (slot->window != nullptr) window = slot->window; + pos = Vector(slot->x, slot->y); + *slot = TouchSlot{}; + } + window->onTouchUp.Invoke({ id, pos }); + if (id == window->primaryTouchId) { + window->primaryTouchId = -1; + window->mouseLeftHeld = false; + window->onMouseLeftRelease.Invoke(); + } + if (!AnyTouch()) touchWindow = nullptr; +} + +void Device::touch_motion(void*, wl_touch*, std::uint32_t, std::int32_t id, wl_fixed_t x, wl_fixed_t y) { + if (touchWindow == nullptr) return; + Window* window = touchWindow; + TouchSlot* slot = SlotFor(id); + if (slot != nullptr && slot->window != nullptr) window = slot->window; + const Vector pos = Vector(wl_fixed_to_double(x), wl_fixed_to_double(y)) * window->scale; + if (slot != nullptr) { + slot->x = pos.x; + slot->y = pos.y; + } + window->onTouchMove.Invoke({ id, pos }); + if (id == window->primaryTouchId) { + window->currentMousePos = pos; + window->onMouseMove.Invoke(); + } +} + +void Device::touch_frame(void*, wl_touch*) {} + +void Device::touch_cancel(void*, wl_touch*) { + if (touchWindow == nullptr) return; + Window* window = touchWindow; + ForgetTouches(); + touchWindow = nullptr; + if (window->primaryTouchId >= 0) { + window->primaryTouchId = -1; + window->mouseLeftHeld = false; + window->onMouseLeftRelease.Invoke(); + } + window->onTouchCancel.Invoke(); +} + +// Capabilities come again when a device appears or goes; each object is +// created once, or every event would arrive once per copy. +void Device::seat_handle_capabilities(void*, wl_seat* seat, uint32_t capabilities) { + if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && seatPointer == nullptr) { + seatPointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(seatPointer, &pointer_listener, nullptr); } - if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - wl_keyboard* keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(keyboard, &keyboard_listener, nullptr); + if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) && wlTouch == nullptr) { + wlTouch = wl_seat_get_touch(seat); + wl_touch_add_listener(wlTouch, &touch_listener, nullptr); + } + if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && seatKeyboard == nullptr) { + seatKeyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(seatKeyboard, &keyboard_listener, nullptr); } } diff --git a/implementations/Crafter.Graphics-Window.cpp b/implementations/Crafter.Graphics-Window.cpp index 017121c..e26022c 100644 --- a/implementations/Crafter.Graphics-Window.cpp +++ b/implementations/Crafter.Graphics-Window.cpp @@ -11,6 +11,7 @@ module; #include "../lib/wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "../lib/fractional-scale-v1.h" #include "../lib/viewporter.h" +#include "../lib/text-input-unstable-v3-client-protocol.h" #include #include #include @@ -299,7 +300,7 @@ Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height wl_surface_commit(surface); - zxdg_toplevel_decoration_v1* decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(Device::manager, xdgToplevel); + decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(Device::manager, xdgToplevel); zxdg_toplevel_decoration_v1_set_mode(decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); wpViewport = wp_viewporter_get_viewport(Device::wpViewporter, surface); @@ -515,6 +516,58 @@ Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height currentMousePos = {0,0}; } +#ifndef CRAFTER_GRAPHICS_WINDOW_DOM +Window::~Window() { + // Nothing may still run against the semaphores, fences or images below. + if (Device::device != VK_NULL_HANDLE) vkDeviceWaitIdle(Device::device); + if (Device::device != VK_NULL_HANDLE) { + if (drawCmdBuffers[0] != VK_NULL_HANDLE) vkFreeCommandBuffers(Device::device, Device::commandPool, numFrames, drawCmdBuffers); + for (std::uint8_t i = 0; i < numFrames; i++) { + if (renderFinishedSemaphores[i]) vkDestroySemaphore(Device::device, renderFinishedSemaphores[i], nullptr); + if (waitFences[i]) vkDestroyFence(Device::device, waitFences[i], nullptr); + } + for (std::uint8_t i = 0; i < numAcquireSemaphores; i++) { + if (imageAcquiredSemaphores[i]) vkDestroySemaphore(Device::device, imageAcquiredSemaphores[i], nullptr); + } + if (swapChain != VK_NULL_HANDLE) vkDestroySwapchainKHR(Device::device, swapChain, nullptr); + swapChain = VK_NULL_HANDLE; + } + if (vulkanSurface != VK_NULL_HANDLE) vkDestroySurfaceKHR(Device::instance, vulkanSurface, nullptr); + vulkanSurface = VK_NULL_HANDLE; + + #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND + SetDefaultCursor(); + // A pending frame callback would still dispatch into this window; + // destroying the proxy makes libwayland drop its event. + if (cb) wl_callback_destroy(cb); + cb = nullptr; + if (wpViewport) wp_viewport_destroy(wpViewport); + if (wp_scale) { + wp_fractional_scale_v1_destroy(wp_scale); + wp_scale = nullptr; + } + if (decoration) zxdg_toplevel_decoration_v1_destroy(decoration); + if (xdgToplevel) xdg_toplevel_destroy(xdgToplevel); + if (xdgSurface) xdg_surface_destroy(xdgSurface); + if (surface) wl_surface_destroy(surface); + wpViewport = nullptr; + decoration = nullptr; + xdgToplevel = nullptr; + xdgSurface = nullptr; + surface = nullptr; + if (Device::display) wl_display_flush(Device::display); + std::erase(Device::windows, this); + if (Device::focusedWindow == this) Device::focusedWindow = nullptr; + if (Device::keyboardWindow == this) Device::keyboardWindow = nullptr; + if (Device::touchWindow == this) { + Device::touchWindow = nullptr; + Device::ForgetTouches(); + } + if (Device::textInputWindow == this) Device::textInputWindow = nullptr; + #endif +} +#endif + void Window::Resize(std::uint32_t newWidth, std::uint32_t newHeight) { // Skip degenerate resizes. Win32 minimised windows give (0, 0); Wayland // sometimes echoes the current size in a configure. @@ -568,6 +621,24 @@ void Window::SetTitle(const std::string_view title) { #endif } +void Window::SetAppId(const std::string_view id) { + #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND + xdg_toplevel_set_app_id(xdgToplevel, std::string(id).c_str()); + #endif +} + +void Window::SetTextInput(bool active, std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height, TextInputPurpose purpose) { + #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND + textInputActive_ = active; + textInputRect_[0] = x; + textInputRect_[1] = y; + textInputRect_[2] = width; + textInputRect_[3] = height; + textInputPurpose_ = purpose; + Device::ApplyTextInput(this); + #endif +} + void Window::SetCursorImage(std::uint16_t width, std::uint16_t height, std::uint16_t hotspotX, std::uint16_t hotspotY, const std::uint8_t* pixels) { @@ -1229,12 +1300,13 @@ void Window::wl_surface_frame_done(void* data, struct wl_callback *cb, uint32_t wl_callback_destroy(cb); Window* window = reinterpret_cast(data); + // The member names the live callback, so the destructor can cancel it. if(window->updating) { - cb = wl_surface_frame(window->surface); - wl_callback_add_listener(cb, &Window::wl_callback_listener, window); + window->cb = wl_surface_frame(window->surface); + wl_callback_add_listener(window->cb, &Window::wl_callback_listener, window); window->Update(); } else { - cb = nullptr; + window->cb = nullptr; } } @@ -1568,6 +1640,10 @@ void Window::SetTitle(const std::string_view title) { Crafter::DomEnv::domSetTitle(title.data(), static_cast(title.size())); } +void Window::SetAppId(const std::string_view) {} + +void Window::SetTextInput(bool, std::int32_t, std::int32_t, std::int32_t, std::int32_t, TextInputPurpose) {} + void Window::Resize(std::uint32_t newWidth, std::uint32_t newHeight) { if (newWidth == 0 || newHeight == 0) return; if (newWidth == width && newHeight == height) return; diff --git a/interfaces/Crafter.Graphics-Device.cppm b/interfaces/Crafter.Graphics-Device.cppm index d461eb6..30e7959 100644 --- a/interfaces/Crafter.Graphics-Device.cppm +++ b/interfaces/Crafter.Graphics-Device.cppm @@ -12,6 +12,7 @@ module; #include "../lib/wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "../lib/fractional-scale-v1.h" #include "../lib/viewporter.h" +#include "../lib/text-input-unstable-v3-client-protocol.h" #include #endif export module Crafter.Graphics:Device; @@ -49,12 +50,32 @@ export namespace Crafter { inline static xkb_keymap* xkb_keymap; inline static wl_compositor* compositor = nullptr; inline static Window* focusedWindow = nullptr; + // The window with keyboard focus (wl_keyboard.enter/leave), apart from + // the pointer's: a key arrives without the pointer ever having entered + // (a touch phone, a key typed while the pointer hovers elsewhere), so the + // keyboard handlers route by this and never by focusedWindow. + inline static Window* keyboardWindow = nullptr; inline static wl_shm* shm = nullptr; inline static wp_viewporter* wpViewporter = nullptr; inline static xkb_context* xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); inline static xkb_state* xkb_state; inline static std::vector windows; inline static wl_pointer* wlPointer; + inline static wl_pointer* seatPointer = nullptr; + inline static wl_keyboard* seatKeyboard = nullptr; + inline static wl_touch* wlTouch = nullptr; + inline static Window* touchWindow = nullptr; // the window under the fingers + // The fingers down, by the compositor's id, in physical pixels. Plain + // data: the statics here are constant-initialised on purpose. + struct TouchSlot { + std::int32_t id; + float x; + float y; + bool used; + Window* window; + }; + inline static std::array touchSlots{}; + static void ForgetTouches(); // wl_data_device_manager + wl_data_device drive copy/paste. Bound // lazily in handle_global; the data device is created once both // the manager and the seat are present (registry binding order @@ -68,6 +89,19 @@ export namespace Crafter { // whole detent yet is carried here so smooth-scroll devices add up // across events. Reset on pointer leave. inline static double scrollDetentRemainder = 0.0; + // zwp_text_input_v3: one object per seat; the compositor says which + // surface it follows (enter/leave), the events are state that done() + // applies as a whole. + inline static zwp_text_input_manager_v3* textInputManager = nullptr; + inline static zwp_text_input_v3* textInput = nullptr; + inline static Window* textInputWindow = nullptr; + inline static std::uint32_t textInputDeleteBefore = 0; + inline static std::uint32_t textInputDeleteAfter = 0; + inline static bool textInputHasPreedit = false; + inline static bool textInputHasCommit = false; + inline static bool textInputHasDelete = false; + // Sends the window's wanted text-input state when it has the focus. + static void ApplyTextInput(Window* window); static void seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities); static void xdg_surface_handle_preferred_scale(void* data, wp_fractional_scale_v1*, std::uint32_t scale); @@ -85,6 +119,17 @@ export namespace Crafter { static void PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t time, std::uint32_t axis, wl_fixed_t value); static void PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, std::uint32_t serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y); static void PointerListenerHandleLeave(void*, wl_pointer*, std::uint32_t, wl_surface*); + static void touch_down(void* data, wl_touch* touch, std::uint32_t serial, std::uint32_t time, wl_surface* surface, std::int32_t id, wl_fixed_t x, wl_fixed_t y); + static void touch_up(void* data, wl_touch* touch, std::uint32_t serial, std::uint32_t time, std::int32_t id); + static void touch_motion(void* data, wl_touch* touch, std::uint32_t time, std::int32_t id, wl_fixed_t x, wl_fixed_t y); + static void touch_frame(void* data, wl_touch* touch); + static void touch_cancel(void* data, wl_touch* touch); + static void text_input_enter(void* data, zwp_text_input_v3* textInput, wl_surface* surface); + static void text_input_leave(void* data, zwp_text_input_v3* textInput, wl_surface* surface); + static void text_input_preedit(void* data, zwp_text_input_v3* textInput, const char* text, std::int32_t cursorBegin, std::int32_t cursorEnd); + static void text_input_commit(void* data, zwp_text_input_v3* textInput, const char* text); + static void text_input_delete(void* data, zwp_text_input_v3* textInput, std::uint32_t before, std::uint32_t after); + static void text_input_done(void* data, zwp_text_input_v3* textInput, std::uint32_t serial); constexpr static wl_pointer_listener pointer_listener = { .enter = PointerListenerHandleEnter, @@ -93,6 +138,21 @@ export namespace Crafter { .button = pointer_handle_button, .axis = PointerListenerHandleAxis, }; + constexpr static wl_touch_listener touch_listener = { + .down = touch_down, + .up = touch_up, + .motion = touch_motion, + .frame = touch_frame, + .cancel = touch_cancel, + }; + constexpr static zwp_text_input_v3_listener text_input_listener = { + .enter = text_input_enter, + .leave = text_input_leave, + .preedit_string = text_input_preedit, + .commit_string = text_input_commit, + .delete_surrounding_text = text_input_delete, + .done = text_input_done, + }; constexpr static wl_keyboard_listener keyboard_listener = { .keymap = keyboard_keymap, .enter = keyboard_enter, diff --git a/interfaces/Crafter.Graphics-FontAtlas.cppm b/interfaces/Crafter.Graphics-FontAtlas.cppm index 4f72522..f5f2ea1 100644 --- a/interfaces/Crafter.Graphics-FontAtlas.cppm +++ b/interfaces/Crafter.Graphics-FontAtlas.cppm @@ -96,6 +96,20 @@ export namespace Crafter { bool dirty = false; DirtyRect dirtyRect; +#ifndef CRAFTER_GRAPHICS_WINDOW_DOM + FontAtlas() = default; + FontAtlas(const FontAtlas&) = delete; + FontAtlas& operator=(const FontAtlas&) = delete; + // The image goes with the atlas, once the GPU is done with it; in + // sets mode the owner destroys the heap holding the image's view + // before the atlas. + ~FontAtlas() { + if (image.image == VK_NULL_HANDLE) return; + if (Device::queue != VK_NULL_HANDLE) vkQueueWaitIdle(Device::queue); + image.Destroy(); + } +#endif + void Initialize(GraphicsCommandBuffer cmd); // Returns the row-major byte pointer the CPU writes pixels into. diff --git a/interfaces/Crafter.Graphics-ImageVulkan.cppm b/interfaces/Crafter.Graphics-ImageVulkan.cppm index 3864d60..8ae4df8 100644 --- a/interfaces/Crafter.Graphics-ImageVulkan.cppm +++ b/interfaces/Crafter.Graphics-ImageVulkan.cppm @@ -56,8 +56,8 @@ export namespace Crafter { std::uint16_t width; std::uint16_t height; std::uint8_t mipLevels; - VkImage image; - VkDeviceMemory imageMemory; + VkImage image = VK_NULL_HANDLE; + VkDeviceMemory imageMemory = VK_NULL_HANDLE; VulkanBuffer buffer; // Transient host-visible staging for the compressed Update path. Same // lifetime contract as Mesh::compressedStaging: the compressed Update @@ -66,7 +66,7 @@ export namespace Crafter { // submit's frame has cleared instead of pinning it for the image's life. // Between Updates the handle is null; the next Update's Resize re-creates it. VulkanBuffer compressedStaging; - VkImageView imageView; + VkImageView imageView = VK_NULL_HANDLE; VkDescriptorImageInfo descriptor; // Pipeline stage that samples this image after upload. Set once at // Create and reused by every Update so the upload barrier's dst (and @@ -378,6 +378,9 @@ export namespace Crafter { vkDestroyImageView(Device::device, imageView, nullptr); vkDestroyImage(Device::device, image, nullptr); vkFreeMemory(Device::device, imageMemory, nullptr); + imageView = VK_NULL_HANDLE; + image = VK_NULL_HANDLE; + imageMemory = VK_NULL_HANDLE; // Free any staging this image still owns: a streamed image's // persistent `buffer`, or either staging buffer on an image // destroyed before its first upload released them (issue #114). diff --git a/interfaces/Crafter.Graphics-Types.cppm b/interfaces/Crafter.Graphics-Types.cppm index a7d5eeb..1cab5c8 100644 --- a/interfaces/Crafter.Graphics-Types.cppm +++ b/interfaces/Crafter.Graphics-Types.cppm @@ -18,6 +18,22 @@ export namespace Crafter { Vector mouseDelta; }; + // One finger on a touchscreen, in the window's physical pixels; the id is + // the compositor's and stays with the finger until it lifts. + struct TouchPoint { + std::int32_t id; + Vector position; + }; + + // The input method asks for bytes around the cursor to go (text-input-v3 + // counts UTF-8 bytes). + struct TextDelete { + std::uint32_t beforeBytes; + std::uint32_t afterBytes; + }; + + enum class TextInputPurpose : std::uint8_t { Normal, Phone }; + struct ScaleData2D { Vector position; Vector size; diff --git a/interfaces/Crafter.Graphics-Window.cppm b/interfaces/Crafter.Graphics-Window.cppm index 37e97f4..1426cd0 100644 --- a/interfaces/Crafter.Graphics-Window.cppm +++ b/interfaces/Crafter.Graphics-Window.cppm @@ -13,6 +13,7 @@ module; #include "../lib/wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "../lib/fractional-scale-v1.h" #include "../lib/viewporter.h" +#include "../lib/text-input-unstable-v3-client-protocol.h" #include #include #include @@ -98,6 +99,19 @@ export namespace Crafter { // touchpads, free-spinning wheels) is accumulated backend-side // until a whole detent is reached. Event onMouseScroll; + // Touch, from the seat's wl_touch. The first finger down also drives + // currentMousePos and the left-button events until it lifts, so a + // pointer-only application works on a touchscreen as it is. + Event onTouchDown; + Event onTouchMove; + Event onTouchUp; + Event onTouchCancel; + std::int32_t primaryTouchId = -1; + // Text input (zwp_text_input_v3): the input method's composing text + // (an empty string clears it) and its deletions around the cursor; + // the text it commits arrives as onTextInput, like a key's. + Event onPreedit; + Event onTextInputDelete; Vector currentMousePos; Vector lastMousePos; Vector mouseDelta; @@ -110,16 +124,19 @@ export namespace Crafter { Window(Window&) = delete; Window(Window&&) = delete; Window& operator=(const Window&) = delete; - #ifdef CRAFTER_GRAPHICS_WINDOW_DOM // DOM mode keeps a process-global pointer to the live Window so // the JS bridge can deliver document/window events back. If the // Window is destroyed (e.g. it was stack-allocated in main and // main returned), the global must be cleared so subsequent // browser callbacks become no-ops instead of dereferencing - // freed memory. Native builds have nothing to clean up at the - // Window level (Vulkan resources teardown is the user's job). + // freed memory. Native builds release what the constructor made: + // after a device wait, the command buffers, semaphores and fences, + // the swapchain and the Vulkan surface, then (Wayland) the cursor, + // viewport, fractional scale, decoration, xdg toplevel, xdg surface + // and wl_surface, and the window leaves Device::windows and the + // focus pointers — so a window can be closed and another created, + // which a resident app does on every hide and show. ~Window(); - #endif // Enter the platform event loop and never return. In DOM mode this // hands the loop to requestAnimationFrame and _Exit(0)s so the wasm @@ -140,6 +157,14 @@ export namespace Crafter { void StartUpdate(); void StopUpdate(); void SetTitle(const std::string_view title); + // The xdg app id, which the compositor matches to a .desktop file + // for the icon, the task switcher and activation. + void SetAppId(const std::string_view id); + // Tells the compositor's input method that a text field has focus + // (an on-screen keyboard opens) and where its caret is, in physical + // pixels, or that none has. Remembered: it is applied again whenever + // the keyboard focus comes back to this window. + void SetTextInput(bool active, std::int32_t x = 0, std::int32_t y = 0, std::int32_t width = 0, std::int32_t height = 0, TextInputPurpose purpose = TextInputPurpose::Normal); void Resize(std::uint32_t width, std::uint32_t height); void Render(); void Update(); @@ -191,6 +216,7 @@ export namespace Crafter { std::int32_t pendingLogicalWidth = 0; std::int32_t pendingLogicalHeight = 0; xdg_toplevel* xdgToplevel = nullptr; + zxdg_toplevel_decoration_v1* decoration = nullptr; wp_viewport* wpViewport = nullptr; wl_surface* surface = nullptr; xdg_surface* xdgSurface = nullptr; @@ -207,6 +233,10 @@ export namespace Crafter { // Needed so `SetCursorImage` can re-issue `wl_pointer_set_cursor` // mid-session (the hotspot only updates when set_cursor is recalled). std::uint32_t lastPointerSerial_ = 0; + bool textInputActive_ = false; + bool textInputEnabled_ = false; // enable sent and not taken back since + std::int32_t textInputRect_[4] = { 0, 0, 0, 0 }; + TextInputPurpose textInputPurpose_ = TextInputPurpose::Normal; static void xdg_surface_handle_preferred_scale(void* data, wp_fractional_scale_v1*, std::uint32_t scale); static void wl_surface_frame_done(void *data, wl_callback *cb, uint32_t time); @@ -227,7 +257,7 @@ export namespace Crafter { constexpr static wp_fractional_scale_v1_listener wp_fractional_scale_v1_listener = { .preferred_scale = xdg_surface_handle_preferred_scale, }; - inline static wp_fractional_scale_v1* wp_scale = nullptr; + wp_fractional_scale_v1* wp_scale = nullptr; #endif #ifndef CRAFTER_GRAPHICS_WINDOW_DOM @@ -269,7 +299,7 @@ export namespace Crafter { // lazily in Render() (post-acquire) rather than up front. std::array imageInitialised{}; std::thread thread; - VkCommandBuffer drawCmdBuffers[numFrames]; + VkCommandBuffer drawCmdBuffers[numFrames] = {}; // Per-frame Vulkan info structs whose contents are almost entirely // invariant. Initialised once in the constructor; Render() patches only // the few fields that change each frame (the two barriers' image and diff --git a/lib/text-input-unstable-v3-client-protocol.h b/lib/text-input-unstable-v3-client-protocol.h new file mode 100644 index 0000000..b2d3624 --- /dev/null +++ b/lib/text-input-unstable-v3-client-protocol.h @@ -0,0 +1,1103 @@ +/* Generated by wayland-scanner 1.26.0 */ + +#ifndef TEXT_INPUT_UNSTABLE_V3_CLIENT_PROTOCOL_H +#define TEXT_INPUT_UNSTABLE_V3_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_text_input_unstable_v3 The text_input_unstable_v3 protocol + * Protocol for composing text + * + * @section page_desc_text_input_unstable_v3 Description + * + * This protocol allows compositors to act as input methods and to send text + * to applications. A text input object is used to manage state of what are + * typically text entry fields in the application. + * + * This document adheres to the RFC 2119 when using words like "must", + * "should", "may", etc. + * + * 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_ifaces_text_input_unstable_v3 Interfaces + * - @subpage page_iface_zwp_text_input_v3 - text input + * - @subpage page_iface_zwp_text_input_manager_v3 - text input manager + * @section page_copyright_text_input_unstable_v3 Copyright + *
+ *
+ * Copyright © 2012, 2013 Intel Corporation
+ * Copyright © 2015, 2016 Jan Arne Petersen
+ * Copyright © 2017, 2018 Red Hat, Inc.
+ * Copyright © 2018       Purism SPC
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ * 
+ */ +struct wl_seat; +struct wl_surface; +struct zwp_text_input_manager_v3; +struct zwp_text_input_v3; + +#ifndef ZWP_TEXT_INPUT_V3_INTERFACE +#define ZWP_TEXT_INPUT_V3_INTERFACE +/** + * @page page_iface_zwp_text_input_v3 zwp_text_input_v3 + * @section page_iface_zwp_text_input_v3_desc Description + * + * The zwp_text_input_v3 interface represents text input and input methods + * associated with a seat. It provides enter/leave events to follow the + * text input focus for a seat. + * + * Requests are used to enable/disable the text-input object and set + * state information like surrounding and selected text or the content type. + * The information about the entered text is sent to the text-input object + * via the preedit_string and commit_string events. + * + * Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices + * must not point to middle bytes inside a code point: they must either + * point to the first byte of a code point or to the end of the buffer. + * Lengths must be measured between two valid indices. + * + * Focus moving throughout surfaces will result in the emission of + * zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused + * surface must commit zwp_text_input_v3.enable and + * zwp_text_input_v3.disable requests as the keyboard focus moves across + * editable and non-editable elements of the UI. Those two requests are not + * expected to be paired with each other, the compositor must be able to + * handle consecutive series of the same request. + * + * State is sent by the state requests (set_surrounding_text, + * set_content_type and set_cursor_rectangle) and a commit request. After an + * enter event or disable request all state information is invalidated and + * needs to be resent by the client. + * @section page_iface_zwp_text_input_v3_api API + * See @ref iface_zwp_text_input_v3. + */ +/** + * @defgroup iface_zwp_text_input_v3 The zwp_text_input_v3 interface + * + * The zwp_text_input_v3 interface represents text input and input methods + * associated with a seat. It provides enter/leave events to follow the + * text input focus for a seat. + * + * Requests are used to enable/disable the text-input object and set + * state information like surrounding and selected text or the content type. + * The information about the entered text is sent to the text-input object + * via the preedit_string and commit_string events. + * + * Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices + * must not point to middle bytes inside a code point: they must either + * point to the first byte of a code point or to the end of the buffer. + * Lengths must be measured between two valid indices. + * + * Focus moving throughout surfaces will result in the emission of + * zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused + * surface must commit zwp_text_input_v3.enable and + * zwp_text_input_v3.disable requests as the keyboard focus moves across + * editable and non-editable elements of the UI. Those two requests are not + * expected to be paired with each other, the compositor must be able to + * handle consecutive series of the same request. + * + * State is sent by the state requests (set_surrounding_text, + * set_content_type and set_cursor_rectangle) and a commit request. After an + * enter event or disable request all state information is invalidated and + * needs to be resent by the client. + */ +extern const struct wl_interface zwp_text_input_v3_interface; +#endif +#ifndef ZWP_TEXT_INPUT_MANAGER_V3_INTERFACE +#define ZWP_TEXT_INPUT_MANAGER_V3_INTERFACE +/** + * @page page_iface_zwp_text_input_manager_v3 zwp_text_input_manager_v3 + * @section page_iface_zwp_text_input_manager_v3_desc Description + * + * A factory for text-input objects. This object is a global singleton. + * @section page_iface_zwp_text_input_manager_v3_api API + * See @ref iface_zwp_text_input_manager_v3. + */ +/** + * @defgroup iface_zwp_text_input_manager_v3 The zwp_text_input_manager_v3 interface + * + * A factory for text-input objects. This object is a global singleton. + */ +extern const struct wl_interface zwp_text_input_manager_v3_interface; +#endif + +#ifndef ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM +#define ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * text change reason + * + * Reason for the change of surrounding text or cursor posision. + */ +enum zwp_text_input_v3_change_cause { + /** + * input method caused the change + */ + ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD = 0, + /** + * something else than the input method caused the change + */ + ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_OTHER = 1, +}; +#endif /* ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * content hint + * + * Content hint is a bitmask to allow to modify the behavior of the text + * input. + */ +enum zwp_text_input_v3_content_hint { + /** + * no special behavior + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE = 0x0, + /** + * suggest word completions + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION = 0x1, + /** + * suggest word corrections + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK = 0x2, + /** + * switch to uppercase letters at the start of a sentence + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION = 0x4, + /** + * prefer lowercase letters + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE = 0x8, + /** + * prefer uppercase letters + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE = 0x10, + /** + * prefer casing for titles and headings (can be language dependent) + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_TITLECASE = 0x20, + /** + * characters should be hidden + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT = 0x40, + /** + * typed text should not be stored + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA = 0x80, + /** + * just Latin characters should be entered + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN = 0x100, + /** + * the text input is multiline + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE = 0x200, + /** + * an on-screen way to fill in the input is already provided by the client + * @since 2 + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED = 0x400, + /** + * prefer not offering emoji support + * @since 2 + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_NO_EMOJI = 0x800, + /** + * the text input will display preedit text in place + * @since 2 + */ + ZWP_TEXT_INPUT_V3_CONTENT_HINT_PREEDIT_SHOWN = 0x1000, +}; +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_NO_EMOJI_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_CONTENT_HINT_PREEDIT_SHOWN_SINCE_VERSION 2 +#endif /* ZWP_TEXT_INPUT_V3_CONTENT_HINT_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM +#define ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * content purpose + * + * The content purpose allows to specify the primary purpose of a text + * input. + * + * This allows an input method to show special purpose input panels with + * extra characters or to disallow some characters. + */ +enum zwp_text_input_v3_content_purpose { + /** + * default input, allowing all characters + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL = 0, + /** + * allow only alphabetic characters + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ALPHA = 1, + /** + * allow only digits + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DIGITS = 2, + /** + * input a number (including decimal separator and sign) + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER = 3, + /** + * input a phone number + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE = 4, + /** + * input an URL + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_URL = 5, + /** + * input an email address + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL = 6, + /** + * input a name of a person + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NAME = 7, + /** + * input a password (combine with sensitive_data hint) + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD = 8, + /** + * input is a numeric password (combine with sensitive_data hint) + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN = 9, + /** + * input a date + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATE = 10, + /** + * input a time + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TIME = 11, + /** + * input a date and time + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATETIME = 12, + /** + * input for a terminal + */ + ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL = 13, +}; +#endif /* ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_ERROR_ENUM +#define ZWP_TEXT_INPUT_V3_ERROR_ENUM +enum zwp_text_input_v3_error { + /** + * an invalid or duplicate action was specified + */ + ZWP_TEXT_INPUT_V3_ERROR_INVALID_ACTION = 0, +}; +#endif /* ZWP_TEXT_INPUT_V3_ERROR_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_ACTION_ENUM +#define ZWP_TEXT_INPUT_V3_ACTION_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * action + * + * A possible action to perform on a text input. + * + * The submit action is intended for input entries that expect some sort of + * activation after user interaction, e.g. the URL entry in a browser. + */ +enum zwp_text_input_v3_action { + /** + * no action + */ + ZWP_TEXT_INPUT_V3_ACTION_NONE = 0, + /** + * the action is submitted + */ + ZWP_TEXT_INPUT_V3_ACTION_SUBMIT = 1, +}; +#endif /* ZWP_TEXT_INPUT_V3_ACTION_ENUM */ + +#ifndef ZWP_TEXT_INPUT_V3_PREEDIT_HINT_ENUM +#define ZWP_TEXT_INPUT_V3_PREEDIT_HINT_ENUM +/** + * @ingroup iface_zwp_text_input_v3 + * preedit style hint + * + * Style hints for the preedit string. + */ +enum zwp_text_input_v3_preedit_hint { + /** + * simple pre-edit text style, typically underlined + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_WHOLE = 1, + /** + * hint for a selected piece of text, e.g. per-character navigation and composition + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SELECTION = 2, + /** + * predicted text, not typed by the user + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_PREDICTION = 3, + /** + * prefixed text not being currently edited, e.g. prior to a 'selection' section + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_PREFIX = 4, + /** + * suffixed text not being currently edited, e.g. after a 'selection' section + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SUFFIX = 5, + /** + * spelling error + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SPELLING_ERROR = 6, + /** + * wrong composition, e.g. user input that can not be transliterated + */ + ZWP_TEXT_INPUT_V3_PREEDIT_HINT_COMPOSE_ERROR = 7, +}; +#endif /* ZWP_TEXT_INPUT_V3_PREEDIT_HINT_ENUM */ + +/** + * @ingroup iface_zwp_text_input_v3 + * @struct zwp_text_input_v3_listener + */ +struct zwp_text_input_v3_listener { + /** + * enter event + * + * Notification that this seat's text-input focus is on a certain + * surface. + * + * If client has created multiple text input objects, compositor + * must send this event to all of them. + * + * When the seat has the keyboard capability the text-input focus + * follows the keyboard focus. This event sets the current surface + * for the text-input object. + */ + void (*enter)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + struct wl_surface *surface); + /** + * leave event + * + * Notification that this seat's text-input focus is no longer on + * a certain surface. The client should reset any preedit string + * previously set. + * + * The leave notification clears the current surface. It is sent + * before the enter notification for the new focus. After leave + * event, compositor must ignore requests from any text input + * instances until next enter event. + * + * When the seat has the keyboard capability the text-input focus + * follows the keyboard focus. + */ + void (*leave)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + struct wl_surface *surface); + /** + * pre-edit + * + * Notify when a new composing text (pre-edit) should be set at + * the current cursor position. Any previously set composing text + * must be removed. Any previously existing selected text must be + * removed. + * + * The argument text contains the pre-edit string buffer. + * + * The parameters cursor_begin and cursor_end are counted in bytes + * relative to the beginning of the submitted text buffer. Cursor + * should be hidden when both are equal to -1. + * + * They could be represented by the client as a line if both values + * are the same, or as a text highlight otherwise. + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial value of text is an empty string, and cursor_begin, + * cursor_end and cursor_hidden are all 0. + */ + void (*preedit_string)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *text, + int32_t cursor_begin, + int32_t cursor_end); + /** + * text commit + * + * Notify when text should be inserted into the editor widget. + * The text to commit could be either just a single character after + * a key press or the result of some composing (pre-edit). + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial value of text is an empty string. + */ + void (*commit_string)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *text); + /** + * delete surrounding text + * + * Notify when the text around the current cursor position should + * be deleted. + * + * Before_length and after_length are the number of bytes before + * and after the current cursor index (excluding the selection) to + * delete. + * + * If a preedit text is present, in effect before_length is counted + * from the beginning of it, and after_length from its end (see + * done event sequence). + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial values of both before_length and after_length are 0. + * @param before_length length of text before current cursor position + * @param after_length length of text after current cursor position + */ + void (*delete_surrounding_text)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t before_length, + uint32_t after_length); + /** + * apply changes + * + * Instruct the application to apply changes to state requested + * by the preedit_string, commit_string delete_surrounding_text, + * and action events. + * + * The state relating to these events is double-buffered, and each + * one modifies the pending state. This event replaces the current + * state with the pending state. + * + * The application must proceed by evaluating the changes in the + * following order: + * + * 1. Replace existing preedit string with the cursor. 2. Delete + * requested surrounding text. 3. Insert commit string with the + * cursor at its end. 4. Calculate surrounding text to send. 5. + * Insert new preedit text in cursor position. 6. Place cursor + * inside preedit text. 7. Perform the requested action. + * + * The serial number reflects the last state of the + * zwp_text_input_v3 object known to the compositor. The value of + * the serial argument must be equal to the number of commit + * requests already issued on that object. + * + * When the client receives a done event with a serial different + * than the number of past commit requests, it must proceed with + * evaluating and applying the changes as normal, except it should + * not change the current state of the zwp_text_input_v3 object. + * All pending state requests (set_surrounding_text, + * set_content_type and set_cursor_rectangle) on the + * zwp_text_input_v3 object should be sent and committed after + * receiving a zwp_text_input_v3.done event with a matching serial. + */ + void (*done)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t serial); + /** + * action performed + * + * An action was performed on this text input. + * + * Values set with this event are double-buffered. They must be + * applied and reset to initial on the next zwp_text_input_v3.done + * event. + * + * The initial value of action is none. + * @param action action performed + * @param serial serial number of the action event + * @since 2 + */ + void (*action)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t action, + uint32_t serial); + /** + * notify of language selection + * + * Notify the application of language used by the input method. + * + * This event will be sent on creation if known and for all + * subsequent changes. + * + * The language should be specified as an IETF BCP 47 tag. Setting + * an empty string will reset any known language back to the + * default unknown state. + * @param language new language set by IME + * @since 2 + */ + void (*language)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + const char *language); + /** + * pre-edit + * + * Notify of contextual hints for the pre-edit string. This event + * is always sent together with a zwp_text_input_v3.preedit_string + * event. + * + * The parameters start and end are counted in bytes relative to + * the beginning of the text buffer submitted through + * zwp_text_input_v3.preedit_string, and represent the substring in + * the pre-edit text affected by the hint. + * + * Multiple events may be submitted if the preedit string has + * different sections. The extent of hints may overlap. The parts + * of the preedit string that are not covered by any + * zwp_text_input_v3.preedit_hint event, the text will be + * considered unhinted. This is also the case if no preedit_hint + * event is sent. + * + * Clients should provide recognizable visuals to these hints. if + * they are unable to comply with this requisition, it may be + * preferable for them keep the preedit_shown content hint + * disabled. + * + * Values set with this event are double-buffered. They must be + * applied and reset on the next zwp_text_input_v3.done event. + * @param start starting point of the affected substring + * @param end end point of the affected substring + * @param hint hint to apply + * @since 2 + */ + void (*preedit_hint)(void *data, + struct zwp_text_input_v3 *zwp_text_input_v3, + uint32_t start, + uint32_t end, + uint32_t hint); +}; + +/** + * @ingroup iface_zwp_text_input_v3 + */ +static inline int +zwp_text_input_v3_add_listener(struct zwp_text_input_v3 *zwp_text_input_v3, + const struct zwp_text_input_v3_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_text_input_v3, + (void (**)(void)) listener, data); +} + +#define ZWP_TEXT_INPUT_V3_DESTROY 0 +#define ZWP_TEXT_INPUT_V3_ENABLE 1 +#define ZWP_TEXT_INPUT_V3_DISABLE 2 +#define ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT 3 +#define ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE 4 +#define ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE 5 +#define ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE 6 +#define ZWP_TEXT_INPUT_V3_COMMIT 7 +#define ZWP_TEXT_INPUT_V3_SET_AVAILABLE_ACTIONS 8 +#define ZWP_TEXT_INPUT_V3_SHOW_INPUT_PANEL 9 +#define ZWP_TEXT_INPUT_V3_HIDE_INPUT_PANEL 10 + +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_ENTER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_LEAVE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_PREEDIT_STRING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_COMMIT_STRING_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DELETE_SURROUNDING_TEXT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_ACTION_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_LANGUAGE_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_PREEDIT_HINT_SINCE_VERSION 2 + +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_ENABLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_DISABLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_COMMIT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SET_AVAILABLE_ACTIONS_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_SHOW_INPUT_PANEL_SINCE_VERSION 2 +/** + * @ingroup iface_zwp_text_input_v3 + */ +#define ZWP_TEXT_INPUT_V3_HIDE_INPUT_PANEL_SINCE_VERSION 2 + +/** @ingroup iface_zwp_text_input_v3 */ +static inline void +zwp_text_input_v3_set_user_data(struct zwp_text_input_v3 *zwp_text_input_v3, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_text_input_v3, user_data); +} + +/** @ingroup iface_zwp_text_input_v3 */ +static inline void * +zwp_text_input_v3_get_user_data(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_text_input_v3); +} + +static inline uint32_t +zwp_text_input_v3_get_version(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Destroy the wp_text_input object. Also disables all surfaces enabled + * through this wp_text_input object. + */ +static inline void +zwp_text_input_v3_destroy(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Requests text input on the surface previously obtained from the enter + * event. + * + * This request must be issued every time the focused text input changes + * to a new one, including within the current surface. Use + * zwp_text_input_v3.disable when there is no longer any input focus on + * the current surface. + * + * Clients must not enable more than one text input on the single seat + * and should disable the current text input before enabling the new one. + * Requests to enable a text input when another text input is enabled + * on the same seat must be ignored by compositor. + * + * This request resets all state associated with previous enable, disable, + * set_surrounding_text, set_text_change_cause, set_content_type, and + * set_cursor_rectangle requests, as well as the state associated with + * preedit_string, commit_string, and delete_surrounding_text events. + * + * The set_surrounding_text, set_content_type and set_cursor_rectangle + * requests must follow if the text input supports the necessary + * functionality. + * + * State set with this request is double-buffered. It will get applied on + * the next zwp_text_input_v3.commit request, and stay valid until the + * next committed enable or disable request. + * + * The changes must be applied by the compositor after issuing a + * zwp_text_input_v3.commit request. + */ +static inline void +zwp_text_input_v3_enable(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_ENABLE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Explicitly disable text input on the current surface (typically when + * there is no focus on any text entry inside the surface). + * + * State set with this request is double-buffered. It will get applied on + * the next zwp_text_input_v3.commit request. + */ +static inline void +zwp_text_input_v3_disable(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_DISABLE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Sets the surrounding plain text around the input, excluding the preedit + * text. + * + * The client should notify the compositor of any changes in any of the + * values carried with this request, including changes caused by handling + * incoming text-input events as well as changes caused by other + * mechanisms like keyboard typing. + * + * If the client is unaware of the text around the cursor, it should not + * issue this request, to signify lack of support to the compositor. + * + * Text is UTF-8 encoded, and should include the cursor position, the + * complete selection and additional characters before and after them. + * There is a maximum length of wayland messages, so text can not be + * longer than 4000 bytes. + * + * Cursor is the byte offset of the cursor within text buffer. + * + * Anchor is the byte offset of the selection anchor within text buffer. + * If there is no selected text, anchor is the same as cursor. + * + * If any preedit text is present, it is replaced with a cursor for the + * purpose of this event. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request, and stay valid until the + * next committed enable or disable request. + * + * The initial state for affected fields is empty, meaning that the text + * input does not support sending surrounding text. If the empty values + * get applied, subsequent attempts to change them may have no effect. + */ +static inline void +zwp_text_input_v3_set_surrounding_text(struct zwp_text_input_v3 *zwp_text_input_v3, const char *text, int32_t cursor, int32_t anchor) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_SURROUNDING_TEXT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, text, cursor, anchor); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Tells the compositor why the text surrounding the cursor changed. + * + * Whenever the client detects an external change in text, cursor, or + * anchor posision, it must issue this request to the compositor. This + * request is intended to give the input method a chance to update the + * preedit text in an appropriate way, e.g. by removing it when the user + * starts typing with a keyboard. + * + * cause describes the source of the change. + * + * The value set with this request is double-buffered. It must be applied + * and reset to initial at the next zwp_text_input_v3.commit request. + * + * The initial value of cause is input_method. + */ +static inline void +zwp_text_input_v3_set_text_change_cause(struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t cause) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_TEXT_CHANGE_CAUSE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, cause); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Sets the content purpose and content hint. While the purpose is the + * basic purpose of an input field, the hint flags allow to modify some of + * the behavior. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request. + * Subsequent attempts to update them may have no effect. The values + * remain valid until the next committed enable or disable request. + * + * The initial value for hint is none, and the initial value for purpose + * is normal. + */ +static inline void +zwp_text_input_v3_set_content_type(struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t hint, uint32_t purpose) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_CONTENT_TYPE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, hint, purpose); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Marks an area around the cursor as a x, y, width, height rectangle in + * surface local coordinates. + * + * Allows the compositor to put a window with word suggestions near the + * cursor, without obstructing the text being input. + * + * If the client is unaware of the position of edited text, it should not + * issue this request, to signify lack of support to the compositor. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request, and stay valid until the + * next committed enable or disable request. + * + * The initial values describing a cursor rectangle are empty. That means + * the text input does not support describing the cursor area. If the + * empty values get applied, subsequent attempts to change them may have + * no effect. + * + * As of version 2, the zwp_text_input_v3.commit request does not apply + * values sent with this request. Instead, it stores them in a separate + * "committed" area. The committed values, if still valid, get applied on + * the next wl_surface.commit request on the surface with text-input focus. + * Both committed and applied values get invalidated on: + * + * - the next committed enable or disable request, or + * - a change of the focused surface of the text-input (leave or enter events). + * + * This double stage application allows the compositor to position + * the input method popup in the same frame as the contents + * of the text on the surface are updated. + */ +static inline void +zwp_text_input_v3_set_cursor_rectangle(struct zwp_text_input_v3 *zwp_text_input_v3, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_CURSOR_RECTANGLE, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, x, y, width, height); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Atomically applies state changes recently sent to the compositor. + * + * The commit request establishes and updates the state of the client, and + * must be issued after any changes to apply them. + * + * Text input state (enabled status, content purpose, content hint, + * surrounding text and change cause, cursor rectangle) is conceptually + * double-buffered within the context of a text input, i.e. between a + * committed enable request and the following committed enable or disable + * request. + * + * Protocol requests modify the pending state, as opposed to the current + * state in use by the input method. A commit request atomically applies + * all pending state, replacing the current state. After commit, the new + * pending state is as documented for each related request. + * + * Requests are applied in the order of arrival. + * + * Neither current nor pending state are modified unless noted otherwise. + * + * The compositor must count the number of commit requests coming from + * each zwp_text_input_v3 object and use the count as the serial in done + * events. + */ +static inline void +zwp_text_input_v3_commit(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Set the actions available for this text input. + * + * Values set with this request are double-buffered. They will get applied + * on the next zwp_text_input_v3.commit request. + * + * If the available_actions array contains the none action, or contains the + * same action multiple times, the compositor must raise the invalid_action + * protocol error. + * + * Initially, no actions are available. + */ +static inline void +zwp_text_input_v3_set_available_actions(struct zwp_text_input_v3 *zwp_text_input_v3, struct wl_array *available_actions) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SET_AVAILABLE_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0, available_actions); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Requests an input panel to be shown (e.g. a on-screen keyboard). + * + * This request only hints the desired interaction pattern from the + * client side, and its effect may be ignored by compositors given + * other environmental factors. Repeated calls will be ignored. + */ +static inline void +zwp_text_input_v3_show_input_panel(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_SHOW_INPUT_PANEL, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +/** + * @ingroup iface_zwp_text_input_v3 + * + * Requests an input panel to be hidden. + * + * This request only hints the desired interaction pattern from the + * client side, and its effect may be ignored by compositors given + * other environmental factors. Repeated calls will be ignored. + */ +static inline void +zwp_text_input_v3_hide_input_panel(struct zwp_text_input_v3 *zwp_text_input_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_v3, + ZWP_TEXT_INPUT_V3_HIDE_INPUT_PANEL, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_v3), 0); +} + +#define ZWP_TEXT_INPUT_MANAGER_V3_DESTROY 0 +#define ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT 1 + + +/** + * @ingroup iface_zwp_text_input_manager_v3 + */ +#define ZWP_TEXT_INPUT_MANAGER_V3_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_text_input_manager_v3 + */ +#define ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT_SINCE_VERSION 1 + +/** @ingroup iface_zwp_text_input_manager_v3 */ +static inline void +zwp_text_input_manager_v3_set_user_data(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_text_input_manager_v3, user_data); +} + +/** @ingroup iface_zwp_text_input_manager_v3 */ +static inline void * +zwp_text_input_manager_v3_get_user_data(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_text_input_manager_v3); +} + +static inline uint32_t +zwp_text_input_manager_v3_get_version(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_text_input_manager_v3); +} + +/** + * @ingroup iface_zwp_text_input_manager_v3 + * + * Destroy the wp_text_input_manager object. + */ +static inline void +zwp_text_input_manager_v3_destroy(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3) +{ + wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_manager_v3, + ZWP_TEXT_INPUT_MANAGER_V3_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_manager_v3), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_zwp_text_input_manager_v3 + * + * Creates a new text-input object for a given seat. + */ +static inline struct zwp_text_input_v3 * +zwp_text_input_manager_v3_get_text_input(struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3, struct wl_seat *seat) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_text_input_manager_v3, + ZWP_TEXT_INPUT_MANAGER_V3_GET_TEXT_INPUT, &zwp_text_input_v3_interface, wl_proxy_get_version((struct wl_proxy *) zwp_text_input_manager_v3), 0, NULL, seat); + + return (struct zwp_text_input_v3 *) id; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/text-input-unstable-v3-protocol.c b/lib/text-input-unstable-v3-protocol.c new file mode 100644 index 0000000..053ebf3 --- /dev/null +++ b/lib/text-input-unstable-v3-protocol.c @@ -0,0 +1,103 @@ +/* Generated by wayland-scanner 1.26.0 */ + +/* + * Copyright © 2012, 2013 Intel Corporation + * Copyright © 2015, 2016 Jan Arne Petersen + * Copyright © 2017, 2018 Red Hat, Inc. + * Copyright © 2018 Purism SPC + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS 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_text_input_v3_interface; + +static const struct wl_interface *text_input_unstable_v3_types[] = { + NULL, + NULL, + NULL, + NULL, + &wl_surface_interface, + &wl_surface_interface, + &zwp_text_input_v3_interface, + &wl_seat_interface, +}; + +static const struct wl_message zwp_text_input_v3_requests[] = { + { "destroy", "", text_input_unstable_v3_types + 0 }, + { "enable", "", text_input_unstable_v3_types + 0 }, + { "disable", "", text_input_unstable_v3_types + 0 }, + { "set_surrounding_text", "sii", text_input_unstable_v3_types + 0 }, + { "set_text_change_cause", "u", text_input_unstable_v3_types + 0 }, + { "set_content_type", "uu", text_input_unstable_v3_types + 0 }, + { "set_cursor_rectangle", "iiii", text_input_unstable_v3_types + 0 }, + { "commit", "", text_input_unstable_v3_types + 0 }, + { "set_available_actions", "2a", text_input_unstable_v3_types + 0 }, + { "show_input_panel", "2", text_input_unstable_v3_types + 0 }, + { "hide_input_panel", "2", text_input_unstable_v3_types + 0 }, +}; + +static const struct wl_message zwp_text_input_v3_events[] = { + { "enter", "o", text_input_unstable_v3_types + 4 }, + { "leave", "o", text_input_unstable_v3_types + 5 }, + { "preedit_string", "?sii", text_input_unstable_v3_types + 0 }, + { "commit_string", "?s", text_input_unstable_v3_types + 0 }, + { "delete_surrounding_text", "uu", text_input_unstable_v3_types + 0 }, + { "done", "u", text_input_unstable_v3_types + 0 }, + { "action", "2uu", text_input_unstable_v3_types + 0 }, + { "language", "2s", text_input_unstable_v3_types + 0 }, + { "preedit_hint", "2uuu", text_input_unstable_v3_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_text_input_v3_interface = { + "zwp_text_input_v3", 2, + 11, zwp_text_input_v3_requests, + 9, zwp_text_input_v3_events, +}; + +static const struct wl_message zwp_text_input_manager_v3_requests[] = { + { "destroy", "", text_input_unstable_v3_types + 0 }, + { "get_text_input", "no", text_input_unstable_v3_types + 6 }, +}; + +WL_PRIVATE const struct wl_interface zwp_text_input_manager_v3_interface = { + "zwp_text_input_manager_v3", 2, + 2, zwp_text_input_manager_v3_requests, + 0, NULL, +}; + diff --git a/project.cpp b/project.cpp index 92643c0..643a44e 100644 --- a/project.cpp +++ b/project.cpp @@ -89,6 +89,7 @@ extern "C" Configuration CrafterBuildProject(std::span a cfg.cFiles.push_back("lib/wayland-xdg-decoration-unstable-v1-client-protocol"); cfg.cFiles.push_back("lib/fractional-scale-v1"); cfg.cFiles.push_back("lib/viewporter"); + cfg.cFiles.push_back("lib/text-input-unstable-v3-protocol"); } // Vulkan is the only renderer on native targets. Software fallback is