summaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 23:41:31 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 23:41:31 +0300
commit76073fe5fad8799e5850805f2f090af2cb62c741 (patch)
tree9658019babe4760a3634bdab4da0731a10e42e68 /src/platform
parentdd1775a9927922c14f8679ccbc4d3ca8d5917e20 (diff)
Simplify the public event and CPU API
Applications now need far less ceremony: hello.c is a 20-line loop that handles REFRESH, CLOSE and QUIT and draws into the surface's own pixels. - Fold GEOMETRY, STATE and FOCUS into one WINDOW event carrying size, scale and state; unchanged values send nothing. - Guarantee REFRESH once a window has a size and after every resize, never at size zero. - Merge DROP_HOVER into DROP with over/leave/data actions and give drag and drop actions enums. - Keep event strings valid until the next wait and drop yasl_event_release; empty or failed waits report NONE. - Replace copy-in presentation with a lent pixel buffer: yasl_cpu_pixels and yasl_cpu_present. - Remove yasl_poll_event, yasl_cpu_read_pixels, unused event fields and comments that restated names. - Wayland: resize floating windows in request_size instead of reporting it unsupported, and stop marking new GPU surfaces as Vulkan so yasl_vulkan_create_surface no longer fails with NATIVE_WINDOW_IN_USE. Also includes the in-progress public API refactor that was uncommitted in the tree (removal of the app/loop layer, new surface, GL and Vulkan entry points). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/cocoa/api.h42
-rw-r--r--src/platform/cocoa/desktop.m8
-rw-r--r--src/platform/cocoa/keymap.c2
-rw-r--r--src/platform/cocoa/keymap.h6
-rw-r--r--src/platform/cocoa/window.m1072
-rw-r--r--src/platform/freedesktop/dbus.h4
-rw-r--r--src/platform/freedesktop/desktop.c12
-rw-r--r--src/platform/posix/loop.c156
-rw-r--r--src/platform/posix/yasl_platform_sync.h14
-rw-r--r--src/platform/sync.h8
-rw-r--r--src/platform/wayland/api.h50
-rw-r--r--src/platform/wayland/backend.c236
-rw-r--r--src/platform/wayland/buffer.c93
-rw-r--r--src/platform/wayland/clipboard.c60
-rw-r--r--src/platform/wayland/clipboard.h16
-rw-r--r--src/platform/wayland/drag.c54
-rw-r--r--src/platform/wayland/ime.c147
-rw-r--r--src/platform/wayland/internal.h70
-rw-r--r--src/platform/wayland/keyboard.c60
-rw-r--r--src/platform/wayland/keymap.c2
-rw-r--r--src/platform/wayland/keymap.h6
-rw-r--r--src/platform/wayland/native.c14
-rw-r--r--src/platform/wayland/pointer.c398
-rw-r--r--src/platform/wayland/popup.c79
-rw-r--r--src/platform/wayland/shell.c50
-rw-r--r--src/platform/wayland/surface.c119
-rw-r--r--src/platform/x11/keymap.c2
-rw-r--r--src/platform/x11/keymap.h6
-rw-r--r--src/platform/x11/native.c14
-rw-r--r--src/platform/x11/window.c1174
30 files changed, 2823 insertions, 1151 deletions
diff --git a/src/platform/cocoa/api.h b/src/platform/cocoa/api.h
index eaacc01..4a22410 100644
--- a/src/platform/cocoa/api.h
+++ b/src/platform/cocoa/api.h
@@ -1,40 +1,40 @@
-#ifndef YASL_COCOA_API_H
-#define YASL_COCOA_API_H
+#ifndef YASL_PRIVATE_COCOA_API_H
+#define YASL_PRIVATE_COCOA_API_H
-#include "yasl/yasl.h"
+#include "common/types.h"
struct cocoa_display;
struct cocoa_surface;
-struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec);
+struct cocoa_display *cocoa_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec);
void cocoa_display_close(struct cocoa_display *d);
uint32_t cocoa_display_caps(const struct cocoa_display *d);
int cocoa_display_dispatch_timeout(struct cocoa_display *d, int timeout_ms);
void cocoa_display_flush(struct cocoa_display *d);
int cocoa_display_modifiers(const struct cocoa_display *d);
-void cocoa_display_copy(struct cocoa_display *d, enum yasl_selection sel, const char *text);
-void cocoa_display_paste(struct cocoa_display *d, enum yasl_selection sel, struct cocoa_surface *target);
-bool cocoa_display_drag_start(struct cocoa_display *d, struct cocoa_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud);
+void cocoa_display_copy(struct cocoa_display *d, enum yasl_private_selection sel, const char *text);
+void cocoa_display_paste(struct cocoa_display *d, enum yasl_private_selection sel, struct cocoa_surface *target);
+bool cocoa_display_drag_start(struct cocoa_display *d, struct cocoa_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud);
struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
- const struct yasl_window_spec *spec, void *graphics_device);
-struct cocoa_surface *cocoa_surface_create_popup(struct cocoa_surface *parent, const struct yasl_popup_spec *spec);
-bool cocoa_surface_popup_reposition(struct cocoa_surface *popup, const struct yasl_popup_spec *spec);
+ const struct yasl_private_window_spec *spec, void *graphics_device);
+struct cocoa_surface *cocoa_surface_create_popup(struct cocoa_surface *parent, const struct yasl_private_popup_spec *spec);
+bool cocoa_surface_popup_reposition(struct cocoa_surface *popup, const struct yasl_private_popup_spec *spec);
void cocoa_surface_destroy(struct cocoa_surface *s);
-void cocoa_surface_set_callbacks(struct cocoa_surface *s, const struct yasl_window_cbs *cbs, void *ud);
+void cocoa_surface_set_callbacks(struct cocoa_surface *s, const struct yasl_private_window_cbs *cbs, void *ud);
void cocoa_surface_set_title(struct cocoa_surface *s, const char *title);
void cocoa_surface_schedule_redraw(struct cocoa_surface *s);
-bool cocoa_surface_present(struct cocoa_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage);
-bool cocoa_surface_poll_event(struct cocoa_surface *s, struct yasl_event *ev);
-struct yasl_geometry cocoa_surface_geometry(const struct cocoa_surface *s);
-struct yasl_timing cocoa_surface_timing(const struct cocoa_surface *s);
-void cocoa_surface_set_cursor(struct cocoa_surface *s, enum yasl_cursor cursor);
+bool cocoa_surface_present(struct cocoa_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage);
+bool cocoa_surface_poll_event(struct cocoa_surface *s, struct yasl_private_event *ev);
+struct yasl_private_geometry cocoa_surface_geometry(const struct cocoa_surface *s);
+struct yasl_private_timing cocoa_surface_timing(const struct cocoa_surface *s);
+void cocoa_surface_set_cursor(struct cocoa_surface *s, enum yasl_private_cursor cursor);
void cocoa_surface_set_background_color(struct cocoa_surface *s, uint32_t bg);
bool cocoa_surface_ime_preedit_cursor(const struct cocoa_surface *s, int *begin, int *end);
-void cocoa_surface_set_ime_caret(struct cocoa_surface *s, struct yasl_rect2i caret);
+void cocoa_surface_set_ime_caret(struct cocoa_surface *s, struct yasl_private_rect2i caret);
bool cocoa_surface_start_interactive_move(struct cocoa_surface *s);
-bool cocoa_surface_start_interactive_resize(struct cocoa_surface *s, enum yasl_resize_edge edge);
-bool cocoa_surface_show_window_menu(struct cocoa_surface *s, struct yasl_vector2i pos);
-bool cocoa_surface_drag_carry(struct cocoa_surface *s, struct yasl_vector2i offset);
-bool cocoa_surface_place_under_pointer(struct cocoa_surface *s, struct yasl_vector2i at);
+bool cocoa_surface_start_interactive_resize(struct cocoa_surface *s, enum yasl_private_resize_edge edge);
+bool cocoa_surface_show_window_menu(struct cocoa_surface *s, struct yasl_private_vector2i pos);
+bool cocoa_surface_drag_carry(struct cocoa_surface *s, struct yasl_private_vector2i offset);
+bool cocoa_surface_place_under_pointer(struct cocoa_surface *s, struct yasl_private_vector2i at);
#endif
diff --git a/src/platform/cocoa/desktop.m b/src/platform/cocoa/desktop.m
index 526cbb9..76aa551 100644
--- a/src/platform/cocoa/desktop.m
+++ b/src/platform/cocoa/desktop.m
@@ -2,7 +2,7 @@
#import <UserNotifications/UserNotifications.h>
#include "common/desktop.h"
-#include "yasl/desktop.h"
+#include "common/private_desktop.h"
#include <CoreFoundation/CoreFoundation.h>
#include <limits.h>
@@ -94,11 +94,11 @@ uint32_t desktop_appearance(void)
NSAppearanceName name = [NSApp.effectiveAppearance
bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
if ([name isEqualToString:NSAppearanceNameDarkAqua])
- flags |= YASL_APPEARANCE_DARK;
+ flags |= YASL_PRIVATE_APPEARANCE_DARK;
else if (name)
- flags |= YASL_APPEARANCE_LIGHT;
+ flags |= YASL_PRIVATE_APPEARANCE_LIGHT;
if ([NSWorkspace sharedWorkspace].accessibilityDisplayShouldIncreaseContrast)
- flags |= YASL_APPEARANCE_HIGH_CONTRAST;
+ flags |= YASL_PRIVATE_APPEARANCE_HIGH_CONTRAST;
return flags;
}
}
diff --git a/src/platform/cocoa/keymap.c b/src/platform/cocoa/keymap.c
index b81c364..c43837c 100644
--- a/src/platform/cocoa/keymap.c
+++ b/src/platform/cocoa/keymap.c
@@ -1,7 +1,7 @@
#include "keymap.h"
#include "keycodes.h"
-enum yasl_key yasl_key_from_cocoa(uint32_t code)
+enum yasl_key yasl_private_key_from_cocoa(uint32_t code)
{
switch (code) {
case kVK_ANSI_A: return YASL_KEY_A;
diff --git a/src/platform/cocoa/keymap.h b/src/platform/cocoa/keymap.h
index a5394e2..792b10d 100644
--- a/src/platform/cocoa/keymap.h
+++ b/src/platform/cocoa/keymap.h
@@ -1,8 +1,8 @@
-#ifndef YASL_COCOA_KEYMAP_H
-#define YASL_COCOA_KEYMAP_H
+#ifndef YASL_PRIVATE_COCOA_KEYMAP_H
+#define YASL_PRIVATE_COCOA_KEYMAP_H
#include "yasl/keycodes.h"
-enum yasl_key yasl_key_from_cocoa(uint32_t code);
+enum yasl_key yasl_private_key_from_cocoa(uint32_t code);
#endif
diff --git a/src/platform/cocoa/window.m b/src/platform/cocoa/window.m
index 60b20b0..7be78fd 100644
--- a/src/platform/cocoa/window.m
+++ b/src/platform/cocoa/window.m
@@ -1,10 +1,12 @@
#import <AppKit/AppKit.h>
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
+#import <OpenGL/OpenGL.h>
#include "platform/cocoa/api.h"
#include "common/backend.h"
-#include "yasl/native/cocoa.h"
+#include "common/public_internal.h"
+#include "common/private_native_cocoa.h"
#include "common/timing.h"
#include "common/loop.h"
#include "platform/cocoa/keycodes.h"
@@ -18,8 +20,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <dlfcn.h>
#include <sys/event.h>
#include <unistd.h>
+#include <objc/message.h>
+#include <objc/runtime.h>
#define LINK_IDLE_FRAMES 8
/* Application-defined event subtype that only wakes a waiting dispatch. */
@@ -63,6 +68,7 @@ struct cocoa_surface {
YaslWindowController *controller;
YaslView *view;
CAMetalLayer *layer;
+ NSOpenGLContext *gl_context;
id<MTLCommandQueue> software_queue;
id<MTLBuffer> software_buffer;
NSUInteger software_buffer_capacity;
@@ -70,16 +76,19 @@ struct cocoa_surface {
struct cocoa_surface *parent;
bool is_popup;
- struct yasl_vector2i content_offset;
+ struct yasl_private_vector2i content_offset;
- const struct yasl_window_cbs *cbs;
+ const struct yasl_private_window_cbs *cbs;
void *ud;
uint64_t frames_skipped;
char *preedit;
- struct yasl_rect2i ime_caret;
+ size_t preedit_begin, preedit_end;
+ NSUInteger marked_utf16_location;
+ uint64_t preedit_revision, preedit_generation;
+ struct yasl_private_rect2i ime_caret;
- struct yasl_vector2i size;
+ struct yasl_private_vector2i size;
uint32_t scale_120;
uint32_t bg_color;
uint32_t *pixels;
@@ -87,11 +96,11 @@ struct cocoa_surface {
id<CAMetalDrawable> drawable;
bool transaction;
- struct yasl_frame frame;
- struct yasl_damage_list damage;
+ struct yasl_private_frame frame;
+ struct yasl_private_damage_list damage;
bool did_present;
/* Extent of the frame in pixels, valid while did_present is set. */
- struct yasl_vector2i shown_size;
+ struct yasl_private_vector2i shown_size;
unsigned idle_frames;
bool want_draw;
bool frame_due;
@@ -102,27 +111,29 @@ struct cocoa_surface {
struct cocoa_surface *dead_next;
struct input_queue input;
- struct yasl_vector2i pointer;
+ struct yasl_private_vector2i pointer;
double scroll_x;
uint32_t mods;
uint32_t buttons;
- enum yasl_cursor cursor;
- enum yasl_pointer_device tablet_device;
+ enum yasl_private_cursor cursor;
+ enum yasl_private_pointer_device tablet_device;
bool tablet_down;
+ uint64_t pen_device_id, pen_tool_id;
+ uint32_t pen_buttons;
char title[160];
- struct yasl_frame_clock clock;
+ struct yasl_private_frame_clock clock;
};
struct cocoa_display {
- struct yasl_display base;
+ struct yasl_private_display base;
struct cocoa_surface **windows;
int count;
int capacity;
- const struct yasl_display_cbs *cbs;
+ const struct yasl_private_display_cbs *cbs;
void *ud;
char *app_id;
- struct yasl_loop *loop;
+ struct yasl_private_loop *loop;
id key_up_monitor;
NSCursor *hidden_cursor;
YaslAppDelegate *delegate;
@@ -132,15 +143,15 @@ struct cocoa_display {
bool active;
struct cocoa_surface *origin;
struct cocoa_surface *carried;
- struct yasl_vector2i carry_offset;
+ struct yasl_private_vector2i carry_offset;
struct cocoa_surface *hover;
- struct yasl_vector2i hover_pos;
- struct yasl_drag_listener listener;
+ struct yasl_private_vector2i hover_pos;
+ struct yasl_private_drag_listener listener;
void *ud;
NSImage *image;
NSWindow *image_window;
- struct yasl_vector2i image_size;
- struct yasl_vector2i image_hotspot;
+ struct yasl_private_vector2i image_size;
+ struct yasl_private_vector2i image_hotspot;
} drag;
int depth;
bool open;
@@ -151,16 +162,16 @@ struct cocoa_display {
static struct cocoa_display darwin_ctx;
-static void drag_end(struct cocoa_display *d, enum yasl_drag_end how)
+static void drag_end(struct cocoa_display *d, enum yasl_private_drag_end how)
{
if (!d || !d->drag.active) return;
- struct yasl_drag_listener l = d->drag.listener;
+ struct yasl_private_drag_listener l = d->drag.listener;
void *ud = d->drag.ud;
struct cocoa_surface *hover = d->drag.hover;
- struct yasl_vector2i pos = d->drag.hover_pos;
+ struct yasl_private_vector2i pos = d->drag.hover_pos;
d->drag.active = false;
- d->drag.listener = (struct yasl_drag_listener){0};
+ d->drag.listener = (struct yasl_private_drag_listener){0};
d->drag.hover = NULL;
d->drag.origin = NULL;
d->drag.carried = NULL;
@@ -175,10 +186,10 @@ static void drag_end(struct cocoa_display *d, enum yasl_drag_end how)
if (hover && !hover->destroyed) {
darwin_ctx.depth++;
- if (how == YASL_DRAG_DROPPED)
- yasl_surface_notify_drag(&hover->base, YASL_DRAG_DROP, pos);
+ if (how == YASL_PRIVATE_DRAG_DROPPED)
+ yasl_private_surface_notify_drag(&hover->base, YASL_PRIVATE_DRAG_DROP, pos);
else
- yasl_surface_notify_drag(&hover->base, YASL_DRAG_LEAVE, pos);
+ yasl_private_surface_notify_drag(&hover->base, YASL_PRIVATE_DRAG_LEAVE, pos);
darwin_ctx.depth--;
}
if (l.end)
@@ -187,6 +198,7 @@ static void drag_end(struct cocoa_display *d, enum yasl_drag_end how)
static void render_and_commit(struct cocoa_surface *w);
static void reap_dead(struct cocoa_display *d);
+static void push_pen(struct cocoa_surface *w, NSEvent *event, unsigned action, bool contact);
static void set_state(struct cocoa_surface *w, uint32_t bit, bool on)
{
@@ -197,21 +209,25 @@ static void set_state(struct cocoa_surface *w, uint32_t bit, bool on)
return;
w->base.state = next;
darwin_ctx.depth++;
- yasl_surface_notify_state(&w->base, next);
+ yasl_private_surface_notify_state(&w->base, next);
darwin_ctx.depth--;
}
static void check_pointer_reset(struct cocoa_surface *w)
{
if (!w || w->closed) return;
- if (w->buttons != 0 || w->tablet_down) {
- struct yasl_event ev = {
- .type = YASL_EVENT_INPUT_RESET,
+ if (w->buttons != 0 || w->tablet_down || w->tablet_device != YASL_PRIVATE_PTR_DEV_MOUSE) {
+ if (w->tablet_device != YASL_PRIVATE_PTR_DEV_MOUSE)
+ push_pen(w, nil, YASL_PRIVATE_PEN_CANCEL, false);
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_INPUT_RESET,
.surface = &w->base,
};
input_queue_push(&w->input, &ev);
w->buttons = 0;
w->tablet_down = false;
+ w->tablet_device = YASL_PRIVATE_PTR_DEV_MOUSE;
+ w->pen_device_id = w->pen_tool_id = 0;
}
}
@@ -221,14 +237,14 @@ static void push_focus(struct cocoa_surface *w, bool focused)
return;
if (!focused)
check_pointer_reset(w);
- struct yasl_event ev = {
- .type = YASL_EVENT_FOCUS,
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_FOCUS,
.surface = &w->base,
.focus = { .focused = focused },
};
input_queue_push(&w->input, &ev);
darwin_ctx.depth++;
- set_state(w, YASL_STATE_ACTIVATED, focused);
+ set_state(w, YASL_PRIVATE_STATE_ACTIVATED, focused);
if (!w->destroyed && !w->closed)
cocoa_surface_schedule_redraw(w);
darwin_ctx.depth--;
@@ -236,18 +252,18 @@ static void push_focus(struct cocoa_surface *w, bool focused)
static void sync_size(struct cocoa_surface *w, bool force)
{
- if (!w || w->destroyed || !w->layer || w->closed)
+ if (!w || w->destroyed || w->closed || !w->view || !w->window)
return;
- uint64_t start = yasl_loop_now_ns();
+ uint64_t start = yasl_private_loop_now_ns();
NSRect bounds = w->view.bounds;
CGFloat scale = w->window.backingScaleFactor;
if (scale < 1.0)
scale = 1.0;
- struct yasl_vector2i size = {
+ struct yasl_private_vector2i size = {
.x = (int)lround(bounds.size.width * scale),
.y = (int)lround(bounds.size.height * scale),
};
- uint32_t scale_120 = (uint32_t)lround(scale * YASL_SCALE_UNIT);
+ uint32_t scale_120 = (uint32_t)lround(scale * YASL_PRIVATE_SCALE_UNIT);
bool rescaled = force || scale_120 != w->scale_120;
bool resized = force || (size.x != w->size.x || size.y != w->size.y);
if (!rescaled && !resized)
@@ -255,15 +271,21 @@ static void sync_size(struct cocoa_surface *w, bool force)
darwin_ctx.depth++;
w->size = size;
w->scale_120 = scale_120;
- w->layer.contentsScale = scale;
- w->layer.drawableSize = CGSizeMake(size.x, size.y);
+ if (w->layer) {
+ w->layer.contentsScale = scale;
+ w->layer.drawableSize = CGSizeMake(size.x, size.y);
+ }
+ if (w->gl_context)
+ [w->gl_context update];
/* Common configure notification already requests a frame before invoking
* the legacy callback. Finish local bookkeeping before that callback can
* destroy this surface. */
- yasl_clock_note_resize(&w->clock, yasl_loop_now_ns() - start);
- yasl_surface_notify_configure(&w->base, (struct yasl_geometry){
+ yasl_private_clock_note_resize(&w->clock, yasl_private_loop_now_ns() - start);
+ yasl_private_surface_notify_configure(&w->base, (struct yasl_private_geometry){
.size = size, .scale_120 = scale_120,
});
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU)
+ yasl_private_surface_notify_refresh(&w->base);
if (!w->destroyed && !w->closed && w->view.inLiveResize)
render_and_commit(w);
darwin_ctx.depth--;
@@ -272,11 +294,11 @@ static void sync_size(struct cocoa_surface *w, bool force)
static unsigned cocoa_mods(NSEventModifierFlags m)
{
unsigned mods = 0;
- if (m & NSEventModifierFlagShift) mods |= YASL_MOD_SHIFT;
- if (m & NSEventModifierFlagOption) mods |= YASL_MOD_ALT;
- if (m & NSEventModifierFlagControl) mods |= YASL_MOD_CTRL;
- if (m & NSEventModifierFlagCommand) mods |= YASL_MOD_SUPER;
- if (m & NSEventModifierFlagCapsLock) mods |= YASL_MOD_CAPS;
+ if (m & NSEventModifierFlagShift) mods |= YASL_PRIVATE_MOD_SHIFT;
+ if (m & NSEventModifierFlagOption) mods |= YASL_PRIVATE_MOD_ALT;
+ if (m & NSEventModifierFlagControl) mods |= YASL_PRIVATE_MOD_CTRL;
+ if (m & NSEventModifierFlagCommand) mods |= YASL_PRIVATE_MOD_SUPER;
+ if (m & NSEventModifierFlagCapsLock) mods |= YASL_PRIVATE_MOD_CAPS;
return mods;
}
@@ -287,19 +309,19 @@ static uint32_t cocoa_key_label(NSString *characters)
if (!characters.length) return 0;
unichar first = [characters characterAtIndex:0];
if (characters.length == 1)
- return yasl_key_label(first);
+ return yasl_private_key_label(first);
if (characters.length == 2 && first >= 0xd800 && first <= 0xdbff) {
unichar second = [characters characterAtIndex:1];
if (second >= 0xdc00 && second <= 0xdfff)
- return yasl_key_label(0x10000 + ((first - 0xd800) << 10) + second - 0xdc00);
+ return yasl_private_key_label(0x10000 + ((first - 0xd800) << 10) + second - 0xdc00);
}
return 0;
}
-static struct yasl_key_event cocoa_key_event(NSEvent *ev, enum yasl_key_action action)
+static struct yasl_private_key_event cocoa_key_event(NSEvent *ev, enum yasl_key_action action)
{
- struct yasl_key_event k = {
- .key = yasl_key_from_cocoa(ev.keyCode),
+ struct yasl_private_key_event k = {
+ .key = yasl_private_key_from_cocoa(ev.keyCode),
.action = action,
.mods = cocoa_mods(ev.modifierFlags),
.native_code = ev.keyCode,
@@ -315,27 +337,15 @@ static struct yasl_key_event cocoa_key_event(NSEvent *ev, enum yasl_key_action a
static void on_key_event(struct cocoa_surface *w, NSEvent *ev, enum yasl_key_action action)
{
w->mods = cocoa_mods(ev.modifierFlags);
- struct yasl_key_event k = cocoa_key_event(ev, action);
- struct yasl_event input_ev = {
- .type = YASL_EVENT_KEY,
+ struct yasl_private_key_event k = cocoa_key_event(ev, action);
+ struct yasl_private_event input_ev = {
+ .type = YASL_PRIVATE_EVENT_KEY,
.surface = &w->base,
.key = k,
};
input_queue_push(&w->input, &input_ev);
}
-static void on_text_input(struct cocoa_surface *w, const char *text, size_t len)
-{
- if (len) {
- struct yasl_event ev = {
- .type = YASL_EVENT_TEXT,
- .surface = &w->base,
- .text = { .data = text, .len = len },
- };
- input_queue_push(&w->input, &ev);
- }
-}
-
static bool modifier_down(NSEvent *ev)
{
NSEventModifierFlags f = ev.modifierFlags;
@@ -356,22 +366,22 @@ static bool modifier_down(NSEvent *ev)
static int cocoa_button(NSInteger number)
{
switch (number) {
- case 0: return YASL_BUTTON_PRIMARY;
- case 1: return YASL_BUTTON_SECONDARY;
- case 2: return YASL_BUTTON_MIDDLE;
- case 3: return YASL_BUTTON_BACK;
- case 4: return YASL_BUTTON_FORWARD;
+ case 0: return YASL_PRIVATE_BUTTON_PRIMARY;
+ case 1: return YASL_PRIVATE_BUTTON_SECONDARY;
+ case 2: return YASL_PRIVATE_BUTTON_MIDDLE;
+ case 3: return YASL_PRIVATE_BUTTON_BACK;
+ case 4: return YASL_PRIVATE_BUTTON_FORWARD;
default: return -1;
}
}
-static struct yasl_vector2i event_pos(struct cocoa_surface *w, NSEvent *ev)
+static struct yasl_private_vector2i event_pos(struct cocoa_surface *w, NSEvent *ev)
{
NSPoint p = [w->view convertPoint:ev.locationInWindow fromView:nil];
CGFloat scale = w->window.backingScaleFactor;
if (scale < 1.0)
scale = 1.0;
- return (struct yasl_vector2i){
+ return (struct yasl_private_vector2i){
.x = (int)floor(p.x * scale),
.y = (int)floor((w->view.bounds.size.height - p.y) * scale),
};
@@ -389,7 +399,7 @@ static void update_drag_hover(struct cocoa_display *d, NSPoint screenPoint)
NSInteger winNum = [NSWindow windowNumberAtPoint:screenPoint belowWindowWithWindowNumber:excludeNum];
struct cocoa_surface *target = NULL;
- struct yasl_vector2i pos = {0};
+ struct yasl_private_vector2i pos = {0};
if (winNum > 0) {
NSWindow *nswin = [NSApp windowWithWindowNumber:winNum];
@@ -429,11 +439,11 @@ static void update_drag_hover(struct cocoa_display *d, NSPoint screenPoint)
if (target != d->drag.hover) {
if (d->drag.hover) {
struct cocoa_surface *old = d->drag.hover;
- struct yasl_vector2i old_pos = d->drag.hover_pos;
+ struct yasl_private_vector2i old_pos = d->drag.hover_pos;
d->drag.hover = NULL;
if (!old->destroyed) {
darwin_ctx.depth++;
- yasl_surface_notify_drag(&old->base, YASL_DRAG_LEAVE, old_pos);
+ yasl_private_surface_notify_drag(&old->base, YASL_PRIVATE_DRAG_LEAVE, old_pos);
darwin_ctx.depth--;
}
if (!d->drag.active) return;
@@ -443,23 +453,117 @@ static void update_drag_hover(struct cocoa_display *d, NSPoint screenPoint)
d->drag.hover_pos = pos;
if (target && !target->destroyed) {
darwin_ctx.depth++;
- yasl_surface_notify_drag(&target->base, YASL_DRAG_OVER, pos);
+ yasl_private_surface_notify_drag(&target->base, YASL_PRIVATE_DRAG_OVER, pos);
darwin_ctx.depth--;
}
} else if (target && !target->destroyed) {
d->drag.hover_pos = pos;
darwin_ctx.depth++;
- yasl_surface_notify_drag(&target->base, YASL_DRAG_OVER, pos);
+ yasl_private_surface_notify_drag(&target->base, YASL_PRIVATE_DRAG_OVER, pos);
darwin_ctx.depth--;
}
}
-static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_event_type type,
+static uint64_t event_integer(NSEvent *event, const char *name)
+{
+ SEL selector = sel_registerName(name);
+ if (![event respondsToSelector:selector]) return 0;
+ return (uint64_t)((NSInteger (*)(id, SEL))objc_msgSend)(event, selector);
+}
+
+static double event_double(NSEvent *event, const char *name)
+{
+ SEL selector = sel_registerName(name);
+ if (![event respondsToSelector:selector]) return 0;
+ return ((double (*)(id, SEL))objc_msgSend)(event, selector);
+}
+
+static void push_pen(struct cocoa_surface *w, NSEvent *event, unsigned action, bool contact)
+{
+ if (!w || w->closed || w->tablet_device == YASL_PRIVATE_PTR_DEV_MOUSE) return;
+ struct yasl_private_pen_sample pen = {
+ .device_id = w->pen_device_id,
+ .tool_id = w->pen_tool_id,
+ .x = w->pointer.x,
+ .y = w->pointer.y,
+ .tool = w->tablet_device == YASL_PRIVATE_PTR_DEV_ERASER ? 2u : 1u,
+ .action = action,
+ .in_contact = contact,
+ };
+ if (event) {
+ if (w->view && [event respondsToSelector:@selector(locationInWindow)]) {
+ NSPoint point = [w->view convertPoint:event.locationInWindow fromView:nil];
+ CGFloat scale = w->window.backingScaleFactor;
+ if (scale < 1.0) scale = 1.0;
+ pen.x = point.x * scale;
+ pen.y = (w->view.bounds.size.height - point.y) * scale;
+ }
+ if (event.buttonMask & NSEventButtonMaskPenTip)
+ pen.buttons |= YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY);
+ if (event.buttonMask & NSEventButtonMaskPenLowerSide)
+ pen.buttons |= YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_SECONDARY);
+ if (event.buttonMask & NSEventButtonMaskPenUpperSide)
+ pen.buttons |= YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_MIDDLE);
+ if (event.type == NSEventTypeTabletPoint || event.subtype == NSEventSubtypeTabletPoint) {
+ pen.pressure = fmax(0.0, fmin(1.0, event.pressure));
+ pen.axes_valid |= YASL_PRIVATE_PEN_PRESSURE;
+ pen.axes_changed |= YASL_PRIVATE_PEN_PRESSURE;
+ NSPoint tilt = event.tilt;
+ pen.tilt_x = fmax(-90.0, fmin(90.0, tilt.x * 90.0));
+ pen.tilt_y = fmax(-90.0, fmin(90.0, -tilt.y * 90.0));
+ pen.axes_valid |= YASL_PRIVATE_PEN_TILT;
+ pen.axes_changed |= YASL_PRIVATE_PEN_TILT;
+ if ([event respondsToSelector:@selector(rotation)]) {
+ pen.rotation = event_double(event, "rotation");
+ pen.axes_valid |= YASL_PRIVATE_PEN_ROTATION;
+ pen.axes_changed |= YASL_PRIVATE_PEN_ROTATION;
+ }
+ if ([event respondsToSelector:@selector(tangentialPressure)]) {
+ pen.tangential = event_double(event, "tangentialPressure");
+ pen.axes_valid |= YASL_PRIVATE_PEN_TANGENTIAL;
+ pen.axes_changed |= YASL_PRIVATE_PEN_TANGENTIAL;
+ }
+ }
+ uint64_t device = event_integer(event, "pointingDeviceID");
+ uint64_t tool = event_integer(event, "pointingDeviceSerialNumber");
+ if (device) pen.device_id = device;
+ if (tool) pen.tool_id = tool;
+ }
+ if (action == YASL_PRIVATE_PEN_DOWN) {
+ pen.buttons |= YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY);
+ pen.changed_button = YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY);
+ } else if (action == YASL_PRIVATE_PEN_UP) {
+ pen.buttons &= ~YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY);
+ pen.changed_button = YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY);
+ }
+ if (action == YASL_PRIVATE_PEN_LEAVE || action == YASL_PRIVATE_PEN_CANCEL) {
+ pen.buttons = 0;
+ pen.in_contact = false;
+ pen.pressure = 0;
+ w->pen_buttons = 0;
+ } else {
+ uint32_t changed = pen.buttons ^ w->pen_buttons;
+ if (action == YASL_PRIVATE_PEN_MOVE && changed) {
+ action = YASL_PRIVATE_PEN_BUTTON;
+ pen.changed_button = changed & (~changed + 1u);
+ }
+ w->pen_buttons = pen.buttons;
+ }
+ pen.action = action;
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_PEN,
+ .surface = &w->base,
+ .pen = pen,
+ };
+ input_queue_push(&w->input, &ev);
+}
+
+static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_private_event_type type,
int button)
{
if (!w || w->closed)
return;
- if ((type == YASL_EVENT_POINTER_DOWN || type == YASL_EVENT_POINTER_UP) &&
+ if ((type == YASL_PRIVATE_EVENT_POINTER_DOWN || type == YASL_PRIVATE_EVENT_POINTER_UP) &&
(button < 0 || button > 4))
return;
bool proximity = ev.type == NSEventTypeTabletProximity ||
@@ -467,26 +571,30 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_event_t
if (proximity) {
if (ev.isEnteringProximity) {
w->tablet_device = ev.pointingDeviceType == NSPointingDeviceTypeEraser ?
- YASL_PTR_DEV_ERASER : ev.pointingDeviceType == NSPointingDeviceTypePen ?
- YASL_PTR_DEV_PEN : YASL_PTR_DEV_MOUSE;
+ YASL_PRIVATE_PTR_DEV_ERASER : ev.pointingDeviceType == NSPointingDeviceTypePen ?
+ YASL_PRIVATE_PTR_DEV_PEN : YASL_PRIVATE_PTR_DEV_MOUSE;
+ w->pen_device_id = event_integer(ev, "pointingDeviceID");
+ w->pen_tool_id = event_integer(ev, "pointingDeviceSerialNumber");
+ if (w->tablet_device != YASL_PRIVATE_PTR_DEV_MOUSE)
+ push_pen(w, ev, YASL_PRIVATE_PEN_ENTER, false);
return;
}
- type = YASL_EVENT_POINTER_LEAVE;
+ type = YASL_PRIVATE_EVENT_POINTER_LEAVE;
}
w->mods = cocoa_mods(ev.modifierFlags);
- if (type != YASL_EVENT_POINTER_LEAVE)
+ if (type != YASL_PRIVATE_EVENT_POINTER_LEAVE)
w->pointer = event_pos(w, ev);
- enum yasl_pointer_device device = YASL_PTR_DEV_MOUSE;
- struct yasl_pointer_pen pen = {0};
+ enum yasl_private_pointer_device device = YASL_PRIVATE_PTR_DEV_MOUSE;
+ struct yasl_private_pointer_pen pen = {0};
- if (type == YASL_EVENT_POINTER_LEAVE && w->tablet_device != YASL_PTR_DEV_MOUSE) {
+ if (type == YASL_PRIVATE_EVENT_POINTER_LEAVE && w->tablet_device != YASL_PRIVATE_PTR_DEV_MOUSE) {
device = w->tablet_device;
w->tablet_down = false;
} else if (ev.type == NSEventTypeTabletPoint || ev.subtype == NSEventSubtypeTabletPoint) {
/* pointingDeviceType belongs to proximity events. Remember that
* event's tool so erasers and zero-pressure hover stay classified. */
- device = w->tablet_device == YASL_PTR_DEV_ERASER ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN;
+ device = w->tablet_device == YASL_PRIVATE_PTR_DEV_ERASER ? YASL_PRIVATE_PTR_DEV_ERASER : YASL_PRIVATE_PTR_DEV_PEN;
float press = (float)ev.pressure;
if (press > 1.0f) press = 1.0f;
if (press > 0.0f)
@@ -495,32 +603,40 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_event_t
NSPoint tilt = ev.tilt;
pen.tilt_x = (int8_t)lround(fmax(-1, fmin(1, tilt.x)) * 90.0);
pen.tilt_y = (int8_t)lround(fmax(-1, fmin(1, -tilt.y)) * 90.0);
- if (button == 0 && type == YASL_EVENT_POINTER_DOWN) w->tablet_down = true;
- if (button == 0 && type == YASL_EVENT_POINTER_UP) {
+ if (button == 0 && type == YASL_PRIVATE_EVENT_POINTER_DOWN) w->tablet_down = true;
+ if (button == 0 && type == YASL_PRIVATE_EVENT_POINTER_UP) {
w->tablet_down = false;
pen.pressure = 0;
}
}
- if (type == YASL_EVENT_POINTER_DOWN && button >= 0 && button < 32)
+ if (type == YASL_PRIVATE_EVENT_POINTER_DOWN && button >= 0 && button < 32)
w->buttons |= (1u << button);
- else if (type == YASL_EVENT_POINTER_UP && button >= 0 && button < 32)
+ else if (type == YASL_PRIVATE_EVENT_POINTER_UP && button >= 0 && button < 32)
w->buttons &= ~(1u << button);
- struct yasl_event input_ev = {
+ struct yasl_private_event input_ev = {
.type = type,
.surface = &w->base,
.pointer = {
.pos = w->pointer,
- .button = (type == YASL_EVENT_POINTER_DOWN || type == YASL_EVENT_POINTER_UP) ?
- (enum yasl_pointer_button)button : YASL_BUTTON_PRIMARY,
+ .button = (type == YASL_PRIVATE_EVENT_POINTER_DOWN || type == YASL_PRIVATE_EVENT_POINTER_UP) ?
+ (enum yasl_private_pointer_button)button : YASL_PRIVATE_BUTTON_PRIMARY,
.device = device,
.mods = w->mods,
.pen = pen,
},
};
input_queue_push(&w->input, &input_ev);
- if (type == YASL_EVENT_POINTER_MOTION && darwin_ctx.drag.active) {
+ if (type == YASL_PRIVATE_EVENT_POINTER_LEAVE && device != YASL_PRIVATE_PTR_DEV_MOUSE) {
+ push_pen(w, ev, YASL_PRIVATE_PEN_LEAVE, false);
+ } else if (ev.type == NSEventTypeTabletPoint || ev.subtype == NSEventSubtypeTabletPoint) {
+ unsigned action = button == YASL_PRIVATE_BUTTON_PRIMARY && type == YASL_PRIVATE_EVENT_POINTER_DOWN ? YASL_PRIVATE_PEN_DOWN :
+ button == YASL_PRIVATE_BUTTON_PRIMARY && type == YASL_PRIVATE_EVENT_POINTER_UP ? YASL_PRIVATE_PEN_UP :
+ YASL_PRIVATE_PEN_MOVE;
+ push_pen(w, ev, action, w->tablet_down);
+ }
+ if (type == YASL_PRIVATE_EVENT_POINTER_MOTION && darwin_ctx.drag.active) {
if (darwin_ctx.drag.carried) {
cocoa_surface_place_under_pointer(darwin_ctx.drag.carried, darwin_ctx.drag.carry_offset);
} else if (darwin_ctx.drag.image_window) {
@@ -534,23 +650,24 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_event_t
mouse.y - pt_h + darwin_ctx.drag.image_hotspot.y / scale)];
}
update_drag_hover(&darwin_ctx, [NSEvent mouseLocation]);
- } else if (type == YASL_EVENT_POINTER_UP && darwin_ctx.drag.active) {
+ } else if (type == YASL_PRIVATE_EVENT_POINTER_UP && darwin_ctx.drag.active) {
update_drag_hover(&darwin_ctx, [NSEvent mouseLocation]);
- drag_end(&darwin_ctx, YASL_DRAG_DROPPED);
+ drag_end(&darwin_ctx, YASL_PRIVATE_DRAG_DROPPED);
}
if (proximity) {
- w->tablet_device = YASL_PTR_DEV_MOUSE;
+ w->tablet_device = YASL_PRIVATE_PTR_DEV_MOUSE;
w->tablet_down = false;
+ w->pen_device_id = w->pen_tool_id = 0;
}
}
-static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
+static NSCursor *cocoa_cursor(enum yasl_private_cursor cursor)
{
switch (cursor) {
- case YASL_CURSOR_TEXT: return [NSCursor IBeamCursor];
- case YASL_CURSOR_LINK: return [NSCursor pointingHandCursor];
- case YASL_CURSOR_CROSSHAIR: return [NSCursor crosshairCursor];
- case YASL_CURSOR_HIDDEN:
+ case YASL_PRIVATE_CURSOR_TEXT: return [NSCursor IBeamCursor];
+ case YASL_PRIVATE_CURSOR_LINK: return [NSCursor pointingHandCursor];
+ case YASL_PRIVATE_CURSOR_CROSSHAIR: return [NSCursor crosshairCursor];
+ case YASL_PRIVATE_CURSOR_HIDDEN:
if (!darwin_ctx.hidden_cursor) {
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
[image lockFocus];
@@ -561,7 +678,7 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
[image release];
}
return darwin_ctx.hidden_cursor;
- case YASL_CURSOR_ARROW:
+ case YASL_PRIVATE_CURSOR_ARROW:
default: return [NSCursor arrowCursor];
}
}
@@ -570,14 +687,14 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
(void)sender;
- yasl_display_notify_event(&darwin_ctx.base, YASL_EVENT_DISPLAY_QUIT);
+ yasl_private_display_notify_event(&darwin_ctx.base, YASL_PRIVATE_EVENT_DISPLAY_QUIT);
return NSTerminateCancel;
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)visible
{
(void)sender;
if (!visible)
- yasl_display_notify_event(&darwin_ctx.base, YASL_EVENT_DISPLAY_REOPEN);
+ yasl_private_display_notify_event(&darwin_ctx.base, YASL_PRIVATE_EVENT_DISPLAY_REOPEN);
return YES;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
@@ -587,13 +704,13 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
}
@end
-static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> sender)
+static struct yasl_private_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> sender)
{
NSPoint p = [view convertPoint:[sender draggingLocation] fromView:nil];
NSWindow *win = view.window;
CGFloat scale = win ? win.backingScaleFactor : 1.0;
if (scale < 1.0) scale = 1.0;
- return (struct yasl_vector2i){
+ return (struct yasl_private_vector2i){
.x = (int)floor(p.x * scale),
.y = (int)floor((view.bounds.size.height - p.y) * scale),
};
@@ -619,9 +736,9 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
if ([pb canReadItemWithDataConformingToTypes:@[NSPasteboardTypeFileURL]]) {
struct cocoa_surface *w = self.surface;
if (w && !w->closed) {
- struct yasl_vector2i pos = dragging_pos(self, sender);
+ struct yasl_private_vector2i pos = dragging_pos(self, sender);
darwin_ctx.depth++;
- yasl_surface_notify_drop(&w->base, YASL_DROP_OVER, pos);
+ yasl_private_surface_notify_drop(&w->base, YASL_PRIVATE_DROP_OVER, pos);
darwin_ctx.depth--;
}
return NSDragOperationCopy;
@@ -640,9 +757,9 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
if ([pb canReadItemWithDataConformingToTypes:@[NSPasteboardTypeFileURL]]) {
struct cocoa_surface *w = self.surface;
if (w && !w->closed) {
- struct yasl_vector2i pos = dragging_pos(self, sender);
+ struct yasl_private_vector2i pos = dragging_pos(self, sender);
darwin_ctx.depth++;
- yasl_surface_notify_drop(&w->base, YASL_DROP_LEAVE, pos);
+ yasl_private_surface_notify_drop(&w->base, YASL_PRIVATE_DROP_LEAVE, pos);
darwin_ctx.depth--;
}
}
@@ -652,7 +769,7 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
{
struct cocoa_surface *w = self.surface;
if (!w) return NO;
- struct yasl_vector2i pos = dragging_pos(self, sender);
+ struct yasl_private_vector2i pos = dragging_pos(self, sender);
BOOL ok = NO;
NSPasteboard *pb = [sender draggingPasteboard];
@@ -666,8 +783,8 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
}
const char *utf8 = result.UTF8String;
if (utf8 && strlen(utf8)) {
- struct yasl_event ev = {
- .type = YASL_EVENT_DROP,
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_DROP,
.surface = &w->base,
.text = { .data = utf8, .len = strlen(utf8) },
};
@@ -678,7 +795,7 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
}
if (!w->destroyed) {
darwin_ctx.depth++;
- yasl_surface_notify_drop(&w->base, YASL_DROP_LEAVE, pos);
+ yasl_private_surface_notify_drop(&w->base, YASL_PRIVATE_DROP_LEAVE, pos);
darwin_ctx.depth--;
}
return ok;
@@ -704,6 +821,13 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
- (BOOL)canBecomeKeyView { return YES; }
- (BOOL)wantsUpdateLayer { return YES; }
+- (void)updateLayer
+{
+ struct cocoa_surface *w = self.surface;
+ if (w && !w->closed && w->base.presenter != YASL_PRIVATE_PRESENTER_CPU)
+ yasl_private_surface_notify_refresh(&w->base);
+}
+
- (void)setFrameSize:(NSSize)size
{
[super setFrameSize:size];
@@ -743,14 +867,14 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
if (period > 0.0 && period < 0.25)
w->clock.refresh_ns = period * 1e9;
w->frame_due = true;
- if (!w->want_draw || (w->base.state & YASL_STATE_SUSPENDED)) {
+ if (!w->want_draw || (w->base.state & YASL_PRIVATE_STATE_SUSPENDED)) {
if (++w->idle_frames >= LINK_IDLE_FRAMES)
link.paused = YES;
return;
}
w->idle_frames = 0;
if (darwin_ctx.loop)
- yasl_loop_kick(darwin_ctx.loop);
+ yasl_private_loop_kick(darwin_ctx.loop);
}
- (void)updateTrackingAreas
@@ -773,7 +897,7 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
{
(void)event;
struct cocoa_surface *w = self.surface;
- [cocoa_cursor(w ? w->cursor : YASL_CURSOR_ARROW) set];
+ [cocoa_cursor(w ? w->cursor : YASL_PRIVATE_CURSOR_ARROW) set];
}
- (void)keyDown:(NSEvent *)event
@@ -802,44 +926,44 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
- (void)mouseDown:(NSEvent *)event
{
[self.window makeFirstResponder:self];
- push_pointer(self.surface, event, YASL_EVENT_POINTER_DOWN, cocoa_button(event.buttonNumber));
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_DOWN, cocoa_button(event.buttonNumber));
}
- (void)rightMouseDown:(NSEvent *)event { [self mouseDown:event]; }
- (void)otherMouseDown:(NSEvent *)event { [self mouseDown:event]; }
- (void)mouseUp:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_EVENT_POINTER_UP, cocoa_button(event.buttonNumber));
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_UP, cocoa_button(event.buttonNumber));
}
- (void)rightMouseUp:(NSEvent *)event { [self mouseUp:event]; }
- (void)otherMouseUp:(NSEvent *)event { [self mouseUp:event]; }
- (void)mouseMoved:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_MOTION, 0);
}
- (void)mouseDragged:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_MOTION, 0);
}
- (void)rightMouseDragged:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_MOTION, 0);
}
- (void)otherMouseDragged:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_MOTION, 0);
}
- (void)mouseExited:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_EVENT_POINTER_LEAVE, 0);
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_LEAVE, 0);
}
- (void)tabletProximity:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
+ push_pointer(self.surface, event, YASL_PRIVATE_EVENT_POINTER_MOTION, 0);
}
- (void)tabletPoint:(NSEvent *)event
@@ -847,8 +971,8 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
struct cocoa_surface *w = self.surface;
if (!w) return;
bool down = (event.buttonMask & NSEventButtonMaskPenTip) != 0;
- enum yasl_event_type type = down == w->tablet_down ? YASL_EVENT_POINTER_MOTION :
- down ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ enum yasl_private_event_type type = down == w->tablet_down ? YASL_PRIVATE_EVENT_POINTER_MOTION :
+ down ? YASL_PRIVATE_EVENT_POINTER_DOWN : YASL_PRIVATE_EVENT_POINTER_UP;
push_pointer(w, event, type, 0);
}
@@ -864,8 +988,8 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
if (!isfinite(dx) || !isfinite(dy) || (dx == 0 && dy == 0)) return;
w->mods = cocoa_mods(event.modifierFlags);
w->pointer = event_pos(w, event);
- struct yasl_event input_ev = {
- .type = YASL_EVENT_POINTER_SCROLL,
+ struct yasl_private_event input_ev = {
+ .type = YASL_PRIVATE_EVENT_POINTER_SCROLL,
.surface = &w->base,
.pointer = {
.pos = w->pointer,
@@ -882,34 +1006,131 @@ static NSString *plain_string(id string)
? [(NSAttributedString *)string string] : (NSString *)string;
}
+static bool text_utf16_to_utf8(NSString *text, NSUInteger index, size_t *byte_offset)
+{
+ if (!text || index > text.length) return false;
+ const char *prefix = [[text substringToIndex:index] UTF8String];
+ if (!prefix) return false;
+ *byte_offset = strlen(prefix);
+ return true;
+}
+
+static bool text_utf8_to_utf16(const char *text, size_t byte_offset, NSUInteger *index)
+{
+ size_t len = text ? strlen(text) : 0;
+ if (byte_offset > len) return false;
+ NSString *prefix = [[NSString alloc] initWithBytes:text length:byte_offset
+ encoding:NSUTF8StringEncoding];
+ if (!prefix) return false;
+ *index = prefix.length;
+ [prefix release];
+ return true;
+}
+
+static bool text_edit_range(struct cocoa_surface *w, NSRange range, bool use_marked,
+ size_t *begin, size_t *end)
+{
+ if (range.location == NSNotFound) {
+ if (use_marked && w->preedit) {
+ if (w->preedit_revision != w->base.text_revision ||
+ w->preedit_generation != w->base.text_generation)
+ return false;
+ *begin = w->preedit_begin;
+ *end = w->preedit_end;
+ } else {
+ *begin = w->base.text_begin;
+ *end = w->base.text_end;
+ }
+ return *begin <= *end && *end <= w->base.text_length;
+ }
+ NSString *surrounding = [NSString stringWithUTF8String:w->base.text_surrounding ?: ""];
+ size_t a, b;
+ if (!surrounding || range.location > surrounding.length ||
+ range.length > surrounding.length - range.location ||
+ !text_utf16_to_utf8(surrounding, range.location, &a) ||
+ !text_utf16_to_utf8(surrounding, range.location + range.length, &b))
+ return false;
+ *begin = a;
+ *end = b;
+ return true;
+}
+
+static void push_text_edit(struct cocoa_surface *w, const char *text, size_t len,
+ size_t begin, size_t end)
+{
+ if (!w->base.text_input_active || begin > end || end > w->base.text_length) return;
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_TEXT_EDIT,
+ .surface = &w->base,
+ .text_edit = {
+ .data = text ?: "", .len = len,
+ .revision = w->base.text_revision,
+ .generation = w->base.text_generation,
+ .begin = begin, .end = end,
+ },
+ };
+ input_queue_push(&w->input, &ev);
+}
+
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
{
- (void)replacementRange;
struct cocoa_surface *w = self.surface;
- if (!w || w->destroyed || w->closed) return;
+ if (!w || w->destroyed || w->closed || !w->base.text_input_active) return;
const char *utf8 = plain_string(string).UTF8String;
size_t len = utf8 ? strlen(utf8) : 0;
+ size_t begin, end;
+ if (!text_edit_range(w, replacementRange, true, &begin, &end)) return;
bool had_preedit = w->preedit != NULL;
+ darwin_ctx.depth++;
+ push_text_edit(w, utf8, len, begin, end);
free(w->preedit);
w->preedit = NULL;
- darwin_ctx.depth++;
- on_text_input(w, utf8, len);
+ w->preedit_begin = w->preedit_end = 0;
if (had_preedit)
- yasl_surface_notify_composition(&w->base, NULL, -1, -1);
+ yasl_private_surface_notify_composition(&w->base, NULL, -1, -1);
if (!w->destroyed && !w->closed)
cocoa_surface_schedule_redraw(w);
darwin_ctx.depth--;
}
-- (void)doCommandBySelector:(SEL)selector { (void)selector; }
+- (void)doCommandBySelector:(SEL)selector
+{
+ struct cocoa_surface *w = self.surface;
+ if (!w || w->destroyed || w->closed || !w->base.text_input_active) return;
+ NSString *surrounding = [NSString stringWithUTF8String:w->base.text_surrounding ?: ""];
+ NSUInteger begin, end;
+ if (!sel_isEqual(selector, @selector(deleteBackward)) &&
+ !sel_isEqual(selector, @selector(deleteForward))) return;
+ if (!text_utf8_to_utf16(w->base.text_surrounding ?: "", w->base.text_begin, &begin) ||
+ !text_utf8_to_utf16(w->base.text_surrounding ?: "", w->base.text_end, &end)) return;
+ if (begin == end && sel_isEqual(selector, @selector(deleteBackward)) && begin > 0) {
+ NSRange composed = [surrounding rangeOfComposedCharacterSequenceAtIndex:begin - 1];
+ begin = composed.location;
+ } else if (begin == end && sel_isEqual(selector, @selector(deleteForward)) && end < surrounding.length) {
+ NSRange composed = [surrounding rangeOfComposedCharacterSequenceAtIndex:end];
+ end = NSMaxRange(composed);
+ }
+ size_t byte_begin, byte_end;
+ if (text_utf16_to_utf8(surrounding, begin, &byte_begin) &&
+ text_utf16_to_utf8(surrounding, end, &byte_end) && byte_begin != byte_end)
+ push_text_edit(w, "", 0, byte_begin, byte_end);
+}
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange
replacementRange:(NSRange)replacementRange
{
- (void)replacementRange;
struct cocoa_surface *w = self.surface;
- if (!w || w->destroyed || w->closed) return;
+ if (!w || w->destroyed || w->closed || !w->base.text_input_active) return;
NSString *str = plain_string(string);
+ size_t range_begin, range_end;
+ if (!text_edit_range(w, replacementRange, true, &range_begin, &range_end)) return;
+ w->preedit_begin = range_begin;
+ w->preedit_end = range_end;
+ w->preedit_revision = w->base.text_revision;
+ w->preedit_generation = w->base.text_generation;
+ if (!text_utf8_to_utf16(w->base.text_surrounding ?: "", range_begin,
+ &w->marked_utf16_location))
+ w->marked_utf16_location = 0;
const char *utf8 = str.length ? str.UTF8String : NULL;
free(w->preedit);
w->preedit = utf8 ? strdup(utf8) : NULL;
@@ -926,7 +1147,7 @@ static NSString *plain_string(id string)
}
}
darwin_ctx.depth++;
- yasl_surface_notify_composition(&w->base, w->preedit, begin, end);
+ yasl_private_surface_notify_composition(&w->base, w->preedit, begin, end);
if (!w->destroyed && !w->closed)
cocoa_surface_schedule_redraw(w);
darwin_ctx.depth--;
@@ -939,19 +1160,28 @@ static NSString *plain_string(id string)
free(w->preedit);
w->preedit = NULL;
darwin_ctx.depth++;
- yasl_surface_notify_composition(&w->base, NULL, -1, -1);
+ yasl_private_surface_notify_composition(&w->base, NULL, -1, -1);
if (!w->destroyed && !w->closed)
cocoa_surface_schedule_redraw(w);
darwin_ctx.depth--;
}
-- (NSRange)selectedRange { return NSMakeRange(NSNotFound, 0); }
+- (NSRange)selectedRange
+{
+ struct cocoa_surface *w = self.surface;
+ if (!w || !w->base.text_input_active) return NSMakeRange(NSNotFound, 0);
+ NSUInteger begin, end;
+ if (!text_utf8_to_utf16(w->base.text_surrounding ?: "", w->base.text_begin, &begin) ||
+ !text_utf8_to_utf16(w->base.text_surrounding ?: "", w->base.text_end, &end))
+ return NSMakeRange(NSNotFound, 0);
+ return NSMakeRange(begin, end - begin);
+}
- (NSRange)markedRange
{
struct cocoa_surface *w = self.surface;
if (!w || !w->preedit)
return NSMakeRange(NSNotFound, 0);
- return NSMakeRange(0, [NSString stringWithUTF8String:w->preedit].length);
+ return NSMakeRange(w->marked_utf16_location, [NSString stringWithUTF8String:w->preedit].length);
}
- (BOOL)hasMarkedText { return self.surface && self.surface->preedit != NULL; }
- (nullable NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range
@@ -1012,7 +1242,7 @@ static NSString *plain_string(id string)
if (!w) return;
bool visible = (self.window.occlusionState & NSWindowOcclusionStateVisible) != 0;
darwin_ctx.depth++;
- set_state(w, YASL_STATE_SUSPENDED, !visible);
+ set_state(w, YASL_PRIVATE_STATE_SUSPENDED, !visible);
if (!w->destroyed && !w->closed) {
if (visible)
cocoa_surface_schedule_redraw(w);
@@ -1042,8 +1272,8 @@ static NSString *plain_string(id string)
return;
darwin_ctx.depth++;
bool fullscreen = (self.window.styleMask & NSWindowStyleMaskFullScreen) != 0;
- set_state(w, YASL_STATE_FULLSCREEN, fullscreen);
- set_state(w, YASL_STATE_MAXIMIZED, !fullscreen && self.window.isZoomed);
+ set_state(w, YASL_PRIVATE_STATE_FULLSCREEN, fullscreen);
+ set_state(w, YASL_PRIVATE_STATE_MAXIMIZED, !fullscreen && self.window.isZoomed);
sync_size(w, false);
darwin_ctx.depth--;
}
@@ -1075,16 +1305,16 @@ static NSString *plain_string(id string)
darwin_ctx.depth++;
w->closed = true;
[w->link invalidate];
- yasl_surface_notify_close(&w->base);
+ yasl_private_surface_notify_close(&w->base);
darwin_ctx.depth--;
}
@end
-bool cocoa_surface_present(struct cocoa_surface *w, const struct yasl_framebuffer *fb,
- const struct yasl_damage_list *damage)
+bool cocoa_surface_present(struct cocoa_surface *w, const struct yasl_private_framebuffer *fb,
+ const struct yasl_private_damage_list *damage)
{
- if (!w || w->closed || !w->rendering || w->did_present || !fb || !damage ||
+ if (!w || w->base.presenter != YASL_PRIVATE_PRESENTER_CPU || w->closed || !w->rendering || w->did_present || !fb || !damage ||
fb->pixels != w->frame.target.pixels || fb->size.x != w->size.x ||
fb->size.y != w->size.y || !w->drawable)
return false;
@@ -1116,7 +1346,7 @@ bool cocoa_surface_present(struct cocoa_surface *w, const struct yasl_framebuffe
[command presentDrawable:drawable];
[command commit];
}
- yasl_clock_presented(&w->clock, yasl_loop_now_ns(), false);
+ yasl_private_clock_presented(&w->clock, yasl_private_loop_now_ns(), false);
w->did_present = true;
w->shown_size = w->size;
return true;
@@ -1124,8 +1354,8 @@ bool cocoa_surface_present(struct cocoa_surface *w, const struct yasl_framebuffe
static void render_and_commit(struct cocoa_surface *w)
{
- if (w->destroyed || w->closed || !w->cbs->draw || w->rendering || w->size.x <= 0 || w->size.y <= 0 ||
- (w->base.state & YASL_STATE_SUSPENDED))
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU || w->destroyed || w->closed || !w->cbs->draw || w->rendering || w->size.x <= 0 || w->size.y <= 0 ||
+ (w->base.state & YASL_PRIVATE_STATE_SUSPENDED))
return;
size_t count = (size_t)w->size.x * (size_t)w->size.y;
@@ -1143,17 +1373,17 @@ static void render_and_commit(struct cocoa_surface *w)
id<CAMetalDrawable> drawable = [w->layer nextDrawable];
w->drawable = drawable;
w->transaction = w->layer.presentsWithTransaction;
- w->damage = (struct yasl_damage_list){0};
- w->frame = (struct yasl_frame){
+ w->damage = (struct yasl_private_damage_list){0};
+ w->frame = (struct yasl_private_frame){
.surface = &w->base,
.target = {
- .generation = yasl_frame_begin(&w->base),
+ .generation = yasl_private_frame_begin(&w->base),
.pixels = w->software_queue ? w->pixels : NULL,
.size = w->size,
},
};
if (drawable)
- yasl_surface_draw(&w->base, &w->frame);
+ yasl_private_surface_draw(&w->base, &w->frame);
if (!w->destroyed && !w->closed && !w->did_present) {
w->want_draw = true;
w->frames_skipped++;
@@ -1191,7 +1421,7 @@ static void loop_ready(CFFileDescriptorRef fd, CFOptionFlags flags, void *info)
/* A kqueue mirroring the loop's poll set, or -1. complete is false when some
* descriptor could not be registered. */
-static int loop_kqueue(struct yasl_loop *loop, bool *complete)
+static int loop_kqueue(struct yasl_private_loop *loop, bool *complete)
{
*complete = true;
int kq = kqueue();
@@ -1200,7 +1430,7 @@ static int loop_kqueue(struct yasl_loop *loop, bool *complete)
return -1;
}
const struct pollfd *fds;
- int n = yasl_loop_poll_set(loop, &fds);
+ int n = yasl_private_loop_poll_set(loop, &fds);
for (int i = 0; i < n; i++) {
struct kevent change;
if (fds[i].events & POLLIN) {
@@ -1238,7 +1468,7 @@ int cocoa_display_dispatch_timeout(struct cocoa_display *d, int timeout_ms)
int count = 0;
@try {
if (d->loop) {
- int timer_to = yasl_loop_next_timeout_ms(d->loop);
+ int timer_to = yasl_private_loop_next_timeout_ms(d->loop);
if (timer_to >= 0 && (timeout_ms < 0 || timer_to < timeout_ms)) {
timeout_ms = timer_to;
}
@@ -1303,7 +1533,7 @@ int cocoa_display_dispatch_timeout(struct cocoa_display *d, int timeout_ms)
}
if (d->loop) {
- yasl_loop_step(d->loop, 0);
+ yasl_private_loop_step(d->loop, 0);
}
} @finally {
d->depth--;
@@ -1331,6 +1561,10 @@ void cocoa_display_flush(struct cocoa_display *d)
void cocoa_surface_schedule_redraw(struct cocoa_surface *w)
{
if (!w || w->closed) return;
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) {
+ yasl_private_surface_notify_refresh(&w->base);
+ return;
+ }
w->want_draw = true;
w->idle_frames = 0;
if (w->link.paused) {
@@ -1338,7 +1572,7 @@ void cocoa_surface_schedule_redraw(struct cocoa_surface *w)
w->link.paused = NO;
}
if (darwin_ctx.loop)
- yasl_loop_kick(darwin_ctx.loop);
+ yasl_private_loop_kick(darwin_ctx.loop);
}
static void app_init(const char *app_name)
@@ -1390,17 +1624,17 @@ static void place_window(NSWindow *window)
darwin_ctx.cascade = [window cascadeTopLeftFromPoint:darwin_ctx.cascade];
}
-struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec)
+struct cocoa_display *cocoa_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec)
{
assert([NSThread isMainThread]);
if (darwin_ctx.open) return NULL;
const char *name = spec && spec->app_id ? spec->app_id : "YASL";
@autoreleasepool { app_init(name); }
- darwin_ctx.base.ops = &yasl_cocoa_backend;
+ darwin_ctx.base.ops = &yasl_private_cocoa_backend;
darwin_ctx.base.native_handle = (__bridge void *)[NSApplication sharedApplication];
darwin_ctx.open = true;
if (!loop) {
- darwin_ctx.loop = yasl_loop_create();
+ darwin_ctx.loop = yasl_private_loop_create();
darwin_ctx.owns_loop = true;
} else {
darwin_ctx.loop = loop;
@@ -1408,7 +1642,7 @@ struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct ya
}
darwin_ctx.base.loop = darwin_ctx.loop;
if (spec) {
- darwin_ctx.base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_display_cbs){0};
+ darwin_ctx.base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0};
darwin_ctx.cbs = &darwin_ctx.base.callbacks;
darwin_ctx.ud = spec->ud;
darwin_ctx.base.callback_ud = spec->ud;
@@ -1421,7 +1655,7 @@ struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct ya
void cocoa_display_close(struct cocoa_display *d)
{
if (!d) return;
- drag_end(d, YASL_DRAG_CANCELLED);
+ drag_end(d, YASL_PRIVATE_DRAG_CANCELLED);
assert(!d->count && "destroy every surface before its display");
reap_dead(d);
if (d->key_up_monitor) {
@@ -1429,7 +1663,7 @@ void cocoa_display_close(struct cocoa_display *d)
d->key_up_monitor = nil;
}
if (d->owns_loop && d->loop) {
- yasl_loop_destroy(d->loop);
+ yasl_private_loop_destroy(d->loop);
d->loop = NULL;
d->base.loop = NULL;
}
@@ -1444,14 +1678,15 @@ void cocoa_display_close(struct cocoa_display *d)
uint32_t cocoa_display_caps(const struct cocoa_display *d)
{
- return d ? (YASL_CAP_POPUPS | YASL_CAP_DRAG | YASL_CAP_DRAG_CARRY |
- YASL_CAP_PLACE_WINDOW | YASL_CAP_PRIMARY_SELECTION |
- YASL_CAP_CSD | YASL_CAP_NATIVE_GRAPHICS |
- YASL_CAP_FRAME_PACING | YASL_CAP_TABLET) : 0;
+ return d ? (YASL_PRIVATE_CAP_POPUPS | YASL_PRIVATE_CAP_DRAG | YASL_PRIVATE_CAP_DRAG_CARRY |
+ YASL_PRIVATE_CAP_PLACE_WINDOW | YASL_PRIVATE_CAP_PRIMARY_SELECTION |
+ YASL_PRIVATE_CAP_CSD | YASL_PRIVATE_CAP_NATIVE_GRAPHICS |
+ YASL_PRIVATE_CAP_FRAME_PACING | YASL_PRIVATE_CAP_TABLET |
+ YASL_PRIVATE_CAP_TEXT_INPUT) : 0;
}
struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
- const struct yasl_window_spec *spec, void *graphics_device)
+ const struct yasl_private_window_spec *spec, void *graphics_device)
{
assert([NSThread isMainThread]);
if (!d || !d->open || !spec)
@@ -1468,15 +1703,24 @@ struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
struct cocoa_surface *w = calloc(1, sizeof(*w));
if (!w) return NULL;
w->base.display = &d->base;
+ w->base.creation_flags = spec->flags;
+ bool external_gpu = spec->external_gpu || graphics_device != NULL;
+ /* Leave an external-GPU surface unclaimed until the public bridge
+ * selects Metal or Vulkan. Both bridges request the layer while the
+ * presenter is still NONE. */
+ w->base.presenter = external_gpu ? YASL_PRIVATE_PRESENTER_NONE : YASL_PRIVATE_PRESENTER_CPU;
cocoa_surface_set_callbacks(w, NULL, NULL);
- w->clock.refresh_ns = YASL_REFRESH_DEFAULT_NS;
+ w->clock.refresh_ns = YASL_PRIVATE_REFRESH_DEFAULT_NS;
const char *t = spec->title ? spec->title : "YASL";
strncpy(w->title, t, sizeof(w->title) - 1);
int win_w = spec->size.x > 0 ? spec->size.x : 800;
int win_h = spec->size.y > 0 ? spec->size.y : 480;
- NSWindowStyleMask style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
- NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
+ NSWindowStyleMask style = (spec->flags & YASL_PRIVATE_SURFACE_UNDECORATED) ?
+ NSWindowStyleMaskBorderless : NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable;
+ if (!(spec->flags & (YASL_PRIVATE_SURFACE_UNDECORATED | YASL_PRIVATE_SURFACE_FIXED_SIZE)))
+ style |= NSWindowStyleMaskResizable;
w->window = [[YaslWindow alloc] initWithContentRect:NSMakeRect(0, 0, win_w, win_h)
styleMask:style
backing:NSBackingStoreBuffered
@@ -1499,7 +1743,7 @@ struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
w->layer = (CAMetalLayer *)w->view.layer;
if (graphics_device) {
w->layer.device = (id<MTLDevice>)graphics_device;
- } else {
+ } else if (!external_gpu) {
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
w->layer.device = device;
w->software_queue = [device newCommandQueue];
@@ -1526,13 +1770,14 @@ struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
w->view.surface = w;
darwin_ctx.windows[darwin_ctx.count++] = w;
- [w->window makeKeyAndOrderFront:nil];
- [w->window makeFirstResponder:w->view];
- [NSApp activate];
+ if (!(spec->flags & YASL_PRIVATE_SURFACE_HIDDEN)) {
+ [w->window makeKeyAndOrderFront:nil];
+ [w->window makeFirstResponder:w->view];
+ }
sync_size(w, true);
if (spec->tearing) {
- w->layer.displaySyncEnabled = NO;
+ if (w->layer) w->layer.displaySyncEnabled = NO;
w->unpaced = true;
}
if (spec->fullscreen)
@@ -1544,6 +1789,7 @@ struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
static void surface_free(struct cocoa_surface *w)
{
[w->link release];
+ [w->gl_context release];
[w->software_buffer release];
[w->software_queue release];
[w->view release];
@@ -1570,7 +1816,7 @@ void cocoa_surface_destroy(struct cocoa_surface *w)
if (!w || w->destroyed) return;
if (darwin_ctx.drag.active) {
if (darwin_ctx.drag.origin == w || darwin_ctx.drag.carried == w)
- drag_end(&darwin_ctx, YASL_DRAG_CANCELLED);
+ drag_end(&darwin_ctx, YASL_PRIVATE_DRAG_CANCELLED);
else if (darwin_ctx.drag.hover == w)
darwin_ctx.drag.hover = NULL;
}
@@ -1589,7 +1835,7 @@ void cocoa_surface_destroy(struct cocoa_surface *w)
w->tablet_down = false;
darwin_ctx.depth++;
bool native_closed = w->closed;
- static const struct yasl_window_cbs no_callbacks = {0};
+ static const struct yasl_private_window_cbs no_callbacks = {0};
w->destroyed = true;
w->closed = true;
w->cbs = &no_callbacks;
@@ -1619,7 +1865,7 @@ void cocoa_surface_destroy(struct cocoa_surface *w)
}
darwin_ctx.depth--;
if (darwin_ctx.loop)
- yasl_loop_kick(darwin_ctx.loop);
+ yasl_private_loop_kick(darwin_ctx.loop);
}
void cocoa_surface_set_title(struct cocoa_surface *w, const char *title)
@@ -1629,7 +1875,7 @@ void cocoa_surface_set_title(struct cocoa_surface *w, const char *title)
w->window.title = [NSString stringWithUTF8String:w->title] ?: @"YASL";
}
-static bool impl_surface_set_size(struct yasl_surface *surface, struct yasl_vector2i size)
+static bool impl_surface_set_size(struct yasl_surface *surface, struct yasl_private_vector2i size)
{
struct cocoa_surface *w = (struct cocoa_surface *)surface;
if (!w || w->closed || w->is_popup || size.x <= 0 || size.y <= 0) {
@@ -1693,16 +1939,16 @@ void cocoa_surface_set_background_color(struct cocoa_surface *w, uint32_t bg)
dark ? NSAppearanceNameDarkAqua : NSAppearanceNameAqua];
}
-void cocoa_surface_set_cursor(struct cocoa_surface *w, enum yasl_cursor cursor)
+void cocoa_surface_set_cursor(struct cocoa_surface *w, enum yasl_private_cursor cursor)
{
- if (!w || w->closed || cursor == w->cursor || (unsigned)cursor > YASL_CURSOR_HIDDEN) return;
+ if (!w || w->closed || cursor == w->cursor || (unsigned)cursor > YASL_PRIVATE_CURSOR_HIDDEN) return;
w->cursor = cursor;
NSPoint p = [w->view convertPoint:w->window.mouseLocationOutsideOfEventStream fromView:nil];
if (w->window.isKeyWindow && NSPointInRect(p, w->view.bounds))
[cocoa_cursor(cursor) set];
}
-bool cocoa_surface_place_under_pointer(struct cocoa_surface *w, struct yasl_vector2i at)
+bool cocoa_surface_place_under_pointer(struct cocoa_surface *w, struct yasl_private_vector2i at)
{
if (!w || w->closed || !w->window) return false;
CGFloat scale = w->window.backingScaleFactor;
@@ -1716,7 +1962,7 @@ bool cocoa_surface_place_under_pointer(struct cocoa_surface *w, struct yasl_vect
return true;
}
-void cocoa_surface_set_ime_caret(struct cocoa_surface *w, struct yasl_rect2i caret)
+void cocoa_surface_set_ime_caret(struct cocoa_surface *w, struct yasl_private_rect2i caret)
{
if (w) w->ime_caret = caret;
}
@@ -1727,26 +1973,26 @@ bool cocoa_surface_ime_preedit_cursor(const struct cocoa_surface *w, int *begin,
return false;
}
-static NSPasteboard *pasteboard_for_selection(enum yasl_selection sel)
+static NSPasteboard *pasteboard_for_selection(enum yasl_private_selection sel)
{
switch (sel) {
- case YASL_CLIPBOARD:
+ case YASL_PRIVATE_CLIPBOARD:
return [NSPasteboard generalPasteboard];
- case YASL_PRIMARY:
+ case YASL_PRIVATE_PRIMARY:
return [NSPasteboard pasteboardWithName:@"dev.wsap.yasl.primary"];
default:
return nil;
}
}
-static bool cocoa_display_copy_text(struct cocoa_display *d, enum yasl_selection sel, const char *text);
+static bool cocoa_display_copy_text(struct cocoa_display *d, enum yasl_private_selection sel, const char *text);
-void cocoa_display_copy(struct cocoa_display *d, enum yasl_selection sel, const char *text)
+void cocoa_display_copy(struct cocoa_display *d, enum yasl_private_selection sel, const char *text)
{
(void)cocoa_display_copy_text(d, sel, text);
}
-static bool cocoa_display_copy_text(struct cocoa_display *d, enum yasl_selection sel, const char *text)
+static bool cocoa_display_copy_text(struct cocoa_display *d, enum yasl_private_selection sel, const char *text)
{
assert([NSThread isMainThread]);
if (!d || !text) { errno = EINVAL; return false; }
@@ -1763,7 +2009,7 @@ static bool cocoa_display_copy_text(struct cocoa_display *d, enum yasl_selection
return true;
}
-static bool cocoa_display_request_paste(struct cocoa_display *d, enum yasl_selection sel,
+static bool cocoa_display_request_paste(struct cocoa_display *d, enum yasl_private_selection sel,
struct cocoa_surface *target, uint64_t id)
{
assert([NSThread isMainThread]);
@@ -1776,15 +2022,15 @@ static bool cocoa_display_request_paste(struct cocoa_display *d, enum yasl_selec
if (!pb) { errno = EINVAL; return false; }
NSString *s = [pb stringForType:NSPasteboardTypeString];
const char *utf8 = s ? s.UTF8String : NULL;
- enum yasl_transfer_status status = !s ? YASL_TRANSFER_UNAVAILABLE :
- utf8 ? YASL_TRANSFER_OK : YASL_TRANSFER_FAILED;
- yasl_surface_complete_paste(&target->base, id, status,
+ enum yasl_private_transfer_status status = !s ? YASL_PRIVATE_TRANSFER_UNAVAILABLE :
+ utf8 ? YASL_PRIVATE_TRANSFER_OK : YASL_PRIVATE_TRANSFER_FAILED;
+ yasl_private_surface_complete_paste(&target->base, id, status,
utf8 ? utf8 : NULL, utf8 ? strlen(utf8) : 0);
errno = 0;
return true;
}
-void cocoa_display_paste(struct cocoa_display *d, enum yasl_selection sel, struct cocoa_surface *target)
+void cocoa_display_paste(struct cocoa_display *d, enum yasl_private_selection sel, struct cocoa_surface *target)
{
(void)cocoa_display_request_paste(d, sel, target, 0);
}
@@ -1795,18 +2041,20 @@ int cocoa_display_modifiers(const struct cocoa_display *d)
return (int)cocoa_mods(NSEvent.modifierFlags);
}
-struct yasl_geometry cocoa_surface_geometry(const struct cocoa_surface *w)
+struct yasl_private_geometry cocoa_surface_geometry(const struct cocoa_surface *w)
{
- return (struct yasl_geometry){
- .size = w ? w->size : (struct yasl_vector2i){0},
- .scale_120 = w ? w->scale_120 : YASL_SCALE_UNIT,
+ return (struct yasl_private_geometry){
+ .size = w ? w->size : (struct yasl_private_vector2i){0},
+ .scale_120 = w ? w->scale_120 : YASL_PRIVATE_SCALE_UNIT,
};
}
static bool popup_spec_valid(const struct cocoa_surface *parent,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
if (!parent || !spec) return false;
+ if (spec->positioner_explicit && (spec->anchor_edges > 8 || spec->gravity > 8 ||
+ (spec->constraints & ~63u))) return false;
int parent_cx = parent->is_popup ? parent->content_offset.x : 0;
int parent_cy = parent->is_popup ? parent->content_offset.y : 0;
int64_t x = (int64_t)spec->anchor.x - parent_cx;
@@ -1821,7 +2069,7 @@ static bool popup_spec_valid(const struct cocoa_surface *parent,
(int64_t)spec->content_offset.y + spec->content_size.y <= spec->size.y;
}
-static NSRect popup_calc_frame(struct cocoa_surface *parent, const struct yasl_popup_spec *spec)
+static NSRect popup_calc_frame_legacy(struct cocoa_surface *parent, const struct yasl_private_popup_spec *spec)
{
CGFloat scale = parent->window ? parent->window.backingScaleFactor : 1.0;
if (scale < 1.0) scale = 1.0;
@@ -1885,8 +2133,153 @@ static NSRect popup_calc_frame(struct cocoa_surface *parent, const struct yasl_p
return frame;
}
+enum {
+ POPUP_EDGE_TOP = 1,
+ POPUP_EDGE_BOTTOM = 2,
+ POPUP_EDGE_LEFT = 3,
+ POPUP_EDGE_RIGHT = 4,
+ POPUP_EDGE_TOP_LEFT = 5,
+ POPUP_EDGE_BOTTOM_LEFT = 6,
+ POPUP_EDGE_TOP_RIGHT = 7,
+ POPUP_EDGE_BOTTOM_RIGHT = 8,
+ POPUP_CONSTRAINT_SLIDE_X = 1u << 0,
+ POPUP_CONSTRAINT_SLIDE_Y = 1u << 1,
+ POPUP_CONSTRAINT_FLIP_X = 1u << 2,
+ POPUP_CONSTRAINT_FLIP_Y = 1u << 3,
+ POPUP_CONSTRAINT_RESIZE_X = 1u << 4,
+ POPUP_CONSTRAINT_RESIZE_Y = 1u << 5,
+};
+
+static bool popup_edge_has_left(unsigned edge)
+{ return edge == POPUP_EDGE_LEFT || edge == POPUP_EDGE_TOP_LEFT || edge == POPUP_EDGE_BOTTOM_LEFT; }
+static bool popup_edge_has_right(unsigned edge)
+{ return edge == POPUP_EDGE_RIGHT || edge == POPUP_EDGE_TOP_RIGHT || edge == POPUP_EDGE_BOTTOM_RIGHT; }
+static bool popup_edge_has_top(unsigned edge)
+{ return edge == POPUP_EDGE_TOP || edge == POPUP_EDGE_TOP_LEFT || edge == POPUP_EDGE_TOP_RIGHT; }
+static bool popup_edge_has_bottom(unsigned edge)
+{ return edge == POPUP_EDGE_BOTTOM || edge == POPUP_EDGE_BOTTOM_LEFT || edge == POPUP_EDGE_BOTTOM_RIGHT; }
+
+static unsigned popup_flip_x_edge(unsigned edge)
+{
+ switch (edge) {
+ case POPUP_EDGE_LEFT: return POPUP_EDGE_RIGHT;
+ case POPUP_EDGE_RIGHT: return POPUP_EDGE_LEFT;
+ case POPUP_EDGE_TOP_LEFT: return POPUP_EDGE_TOP_RIGHT;
+ case POPUP_EDGE_BOTTOM_LEFT: return POPUP_EDGE_BOTTOM_RIGHT;
+ case POPUP_EDGE_TOP_RIGHT: return POPUP_EDGE_TOP_LEFT;
+ case POPUP_EDGE_BOTTOM_RIGHT: return POPUP_EDGE_BOTTOM_LEFT;
+ default: return edge;
+ }
+}
+
+static unsigned popup_flip_y_edge(unsigned edge)
+{
+ switch (edge) {
+ case POPUP_EDGE_TOP: return POPUP_EDGE_BOTTOM;
+ case POPUP_EDGE_BOTTOM: return POPUP_EDGE_TOP;
+ case POPUP_EDGE_TOP_LEFT: return POPUP_EDGE_BOTTOM_LEFT;
+ case POPUP_EDGE_TOP_RIGHT: return POPUP_EDGE_BOTTOM_RIGHT;
+ case POPUP_EDGE_BOTTOM_LEFT: return POPUP_EDGE_TOP_LEFT;
+ case POPUP_EDGE_BOTTOM_RIGHT: return POPUP_EDGE_TOP_RIGHT;
+ default: return edge;
+ }
+}
+
+static CGFloat popup_axis_overflow(CGFloat min, CGFloat max, CGFloat visible_min, CGFloat visible_max)
+{
+ return MAX(0, visible_min - min) + MAX(0, max - visible_max);
+}
+
+static NSRect popup_frame_explicit(struct cocoa_surface *parent,
+ const struct yasl_private_popup_spec *spec, unsigned anchor, unsigned gravity)
+{
+ CGFloat scale = parent->window.backingScaleFactor;
+ if (scale < 1.0) scale = 1.0;
+ CGFloat parent_x = (parent->is_popup ? parent->content_offset.x : 0) / scale;
+ CGFloat parent_y = (parent->is_popup ? parent->content_offset.y : 0) / scale;
+ CGFloat ax = spec->anchor.x / scale - parent_x;
+ CGFloat ay = spec->anchor.y / scale - parent_y;
+ CGFloat aw = spec->anchor.width / scale;
+ CGFloat ah = spec->anchor.height / scale;
+ CGFloat anchor_x = popup_edge_has_left(anchor) ? ax :
+ popup_edge_has_right(anchor) ? ax + aw : ax + aw * 0.5;
+ CGFloat anchor_y = popup_edge_has_top(anchor) ? ay :
+ popup_edge_has_bottom(anchor) ? ay + ah : ay + ah * 0.5;
+ CGFloat offset_x = spec->content_offset.x / scale;
+ CGFloat offset_y = spec->content_offset.y / scale;
+ CGFloat content_w = (spec->content_size.x ? spec->content_size.x : spec->size.x - spec->content_offset.x) / scale;
+ CGFloat content_h = (spec->content_size.y ? spec->content_size.y : spec->size.y - spec->content_offset.y) / scale;
+ CGFloat content_left = popup_edge_has_right(gravity) ? anchor_x :
+ popup_edge_has_left(gravity) ? anchor_x - content_w : anchor_x - content_w * 0.5;
+ CGFloat content_top = popup_edge_has_bottom(gravity) ? anchor_y :
+ popup_edge_has_top(gravity) ? anchor_y - content_h : anchor_y - content_h * 0.5;
+ CGFloat top_left_x = content_left - offset_x;
+ CGFloat top_left_y = content_top - offset_y;
+
+ CGFloat view_h = parent->view.bounds.size.height;
+ NSPoint in_view = NSMakePoint(top_left_x, view_h - top_left_y);
+ NSPoint in_window = [parent->view convertPoint:in_view toView:nil];
+ NSPoint screen_top_left = [parent->window convertPointToScreen:in_window];
+ CGFloat width = spec->size.x / scale;
+ CGFloat height = spec->size.y / scale;
+ return NSMakeRect(screen_top_left.x, screen_top_left.y - height, width, height);
+}
+
+static NSRect popup_calc_frame(struct cocoa_surface *parent, const struct yasl_private_popup_spec *spec)
+{
+ if (!spec->positioner_explicit)
+ return popup_calc_frame_legacy(parent, spec);
+
+ NSRect frame = popup_frame_explicit(parent, spec, spec->anchor_edges, spec->gravity);
+ NSScreen *screen = parent->window.screen ?: [NSScreen mainScreen];
+ if (!screen) return frame;
+ NSRect visible = screen.visibleFrame;
+ unsigned constraints = spec->constraints;
+
+ if (constraints & POPUP_CONSTRAINT_FLIP_X) {
+ NSRect flipped = popup_frame_explicit(parent, spec,
+ popup_flip_x_edge(spec->anchor_edges), popup_flip_x_edge(spec->gravity));
+ if (popup_axis_overflow(flipped.origin.x, NSMaxX(flipped), NSMinX(visible), NSMaxX(visible)) <
+ popup_axis_overflow(frame.origin.x, NSMaxX(frame), NSMinX(visible), NSMaxX(visible)))
+ frame = NSMakeRect(flipped.origin.x, frame.origin.y, flipped.size.width, frame.size.height);
+ }
+ if (constraints & POPUP_CONSTRAINT_FLIP_Y) {
+ NSRect flipped = popup_frame_explicit(parent, spec,
+ popup_flip_y_edge(spec->anchor_edges), popup_flip_y_edge(spec->gravity));
+ if (popup_axis_overflow(flipped.origin.y, NSMaxY(flipped), NSMinY(visible), NSMaxY(visible)) <
+ popup_axis_overflow(frame.origin.y, NSMaxY(frame), NSMinY(visible), NSMaxY(visible)))
+ frame = NSMakeRect(frame.origin.x, flipped.origin.y, frame.size.width, flipped.size.height);
+ }
+
+ if (constraints & POPUP_CONSTRAINT_SLIDE_X) {
+ if (NSMinX(frame) < NSMinX(visible)) frame.origin.x = NSMinX(visible);
+ if (NSMaxX(frame) > NSMaxX(visible)) frame.origin.x = NSMaxX(visible) - frame.size.width;
+ }
+ if (constraints & POPUP_CONSTRAINT_SLIDE_Y) {
+ if (NSMinY(frame) < NSMinY(visible)) frame.origin.y = NSMinY(visible);
+ if (NSMaxY(frame) > NSMaxY(visible)) frame.origin.y = NSMaxY(visible) - frame.size.height;
+ }
+ if (constraints & POPUP_CONSTRAINT_RESIZE_X) {
+ if (NSMinX(frame) < NSMinX(visible)) {
+ frame.size.width = MAX(0, frame.size.width - (NSMinX(visible) - NSMinX(frame)));
+ frame.origin.x = NSMinX(visible);
+ }
+ if (NSMaxX(frame) > NSMaxX(visible))
+ frame.size.width = MAX(0, NSMaxX(visible) - frame.origin.x);
+ }
+ if (constraints & POPUP_CONSTRAINT_RESIZE_Y) {
+ if (NSMinY(frame) < NSMinY(visible)) {
+ frame.size.height = MAX(0, frame.size.height - (NSMinY(visible) - NSMinY(frame)));
+ frame.origin.y = NSMinY(visible);
+ }
+ if (NSMaxY(frame) > NSMaxY(visible))
+ frame.size.height = MAX(0, NSMaxY(visible) - frame.origin.y);
+ }
+ return frame;
+}
+
struct cocoa_surface *cocoa_surface_create_popup(struct cocoa_surface *parent,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
assert([NSThread isMainThread]);
if (!parent || parent->closed || !parent->window || !parent->view ||
@@ -1905,8 +2298,10 @@ struct cocoa_surface *cocoa_surface_create_popup(struct cocoa_surface *parent,
struct cocoa_surface *w = calloc(1, sizeof(*w));
if (!w) return NULL;
w->base.display = parent->base.display;
+ w->base.presenter = parent->base.presenter;
+ w->base.creation_flags = parent->base.creation_flags;
cocoa_surface_set_callbacks(w, NULL, NULL);
- w->clock.refresh_ns = parent->clock.refresh_ns ? parent->clock.refresh_ns : YASL_REFRESH_DEFAULT_NS;
+ w->clock.refresh_ns = parent->clock.refresh_ns ? parent->clock.refresh_ns : YASL_PRIVATE_REFRESH_DEFAULT_NS;
w->parent = parent;
w->is_popup = true;
w->content_offset = spec->content_offset;
@@ -1968,7 +2363,7 @@ struct cocoa_surface *cocoa_surface_create_popup(struct cocoa_surface *parent,
}
bool cocoa_surface_popup_reposition(struct cocoa_surface *popup,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
if (!popup || popup->closed || !popup->is_popup || !popup->parent ||
!popup->parent->window || !popup->parent->view ||
@@ -2020,8 +2415,8 @@ static NSImage *image_from_pixels(const uint32_t *pixels, int width, int height)
}
bool cocoa_display_drag_start(struct cocoa_display *d, struct cocoa_surface *origin,
- const struct yasl_drag_image *image,
- const struct yasl_drag_listener *l, void *ud)
+ const struct yasl_private_drag_image *image,
+ const struct yasl_private_drag_listener *l, void *ud)
{
if (!d || !origin || d->drag.active || !l)
return false;
@@ -2029,7 +2424,7 @@ bool cocoa_display_drag_start(struct cocoa_display *d, struct cocoa_surface *ori
d->drag.origin = origin;
d->drag.carried = NULL;
d->drag.hover = NULL;
- d->drag.hover_pos = (struct yasl_vector2i){0};
+ d->drag.hover_pos = (struct yasl_private_vector2i){0};
d->drag.listener = *l;
d->drag.ud = ud;
[d->drag.image release];
@@ -2074,7 +2469,7 @@ bool cocoa_display_drag_start(struct cocoa_display *d, struct cocoa_surface *ori
return true;
}
-bool cocoa_surface_drag_carry(struct cocoa_surface *w, struct yasl_vector2i offset)
+bool cocoa_surface_drag_carry(struct cocoa_surface *w, struct yasl_private_vector2i offset)
{
if (!w || w->closed || !darwin_ctx.drag.active)
return false;
@@ -2088,33 +2483,33 @@ bool cocoa_surface_drag_carry(struct cocoa_surface *w, struct yasl_vector2i offs
return cocoa_surface_place_under_pointer(w, offset);
}
-bool cocoa_surface_start_interactive_resize(struct cocoa_surface *s, enum yasl_resize_edge edge)
+bool cocoa_surface_start_interactive_resize(struct cocoa_surface *s, enum yasl_private_resize_edge edge)
{
(void)s; (void)edge;
return false;
}
-bool cocoa_surface_show_window_menu(struct cocoa_surface *s, struct yasl_vector2i pos)
+bool cocoa_surface_show_window_menu(struct cocoa_surface *s, struct yasl_private_vector2i pos)
{
(void)s; (void)pos;
return false;
}
void cocoa_surface_set_callbacks(struct cocoa_surface *w,
- const struct yasl_window_cbs *cbs, void *ud)
+ const struct yasl_private_window_cbs *cbs, void *ud)
{
if (!w || w->closed) return;
- w->base.callbacks = cbs ? *cbs : (struct yasl_window_cbs){0};
+ w->base.callbacks = cbs ? *cbs : (struct yasl_private_window_cbs){0};
w->base.ud = ud;
w->cbs = &w->base.callbacks;
w->ud = ud;
}
-bool cocoa_surface_poll_event(struct cocoa_surface *w, struct yasl_event *ev)
+bool cocoa_surface_poll_event(struct cocoa_surface *w, struct yasl_private_event *ev)
{
if (!w || !ev || !input_queue_pop(&w->input, ev))
return false;
- if (ev->type == YASL_EVENT_INPUT_RESET) {
+ if (ev->type == YASL_PRIVATE_EVENT_INPUT_RESET) {
w->buttons = 0;
w->tablet_down = false;
w->mods = 0;
@@ -2126,103 +2521,103 @@ bool cocoa_surface_poll_event(struct cocoa_surface *w, struct yasl_event *ev)
return true;
}
-struct yasl_timing cocoa_surface_timing(const struct cocoa_surface *w)
+struct yasl_private_timing cocoa_surface_timing(const struct cocoa_surface *w)
{
- struct yasl_timing timing = {0};
+ struct yasl_private_timing timing = {0};
if (w) {
timing.refresh_ns = w->clock.refresh_ns;
timing.last_present_ns = w->clock.last_present_ns;
- timing.next_present_ns = yasl_clock_next_present_ns(&w->clock);
+ timing.next_present_ns = yasl_private_clock_next_present_ns(&w->clock);
timing.frames_skipped = w->frames_skipped;
timing.source = w->clock.source;
- yasl_clock_resize_stats(&w->clock, &timing.resize);
+ yasl_private_clock_resize_stats(&w->clock, &timing.resize);
}
return timing;
}
-static struct yasl_display *impl_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec)
+static struct yasl_private_display *impl_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec)
{
struct cocoa_display *result = cocoa_display_open(loop, spec);
return result ? &result->base : NULL;
}
-static void impl_display_close(struct yasl_display *d)
+static void impl_display_close(struct yasl_private_display *d)
{
cocoa_display_close((struct cocoa_display *)d);
}
-static uint32_t impl_display_caps(const struct yasl_display *d)
+static uint32_t impl_display_caps(const struct yasl_private_display *d)
{
return cocoa_display_caps((const struct cocoa_display *)d);
}
-static int impl_display_dispatch_timeout(struct yasl_display *d, int timeout_ms)
+static int impl_display_dispatch_timeout(struct yasl_private_display *d, int timeout_ms)
{
return cocoa_display_dispatch_timeout((struct cocoa_display *)d, timeout_ms);
}
-static void impl_display_flush(struct yasl_display *d)
+static void impl_display_flush(struct yasl_private_display *d)
{
cocoa_display_flush((struct cocoa_display *)d);
}
-static int impl_display_double_click_ms(const struct yasl_display *d)
+static int impl_display_double_click_ms(const struct yasl_private_display *d)
{
(void)d;
return (int)lround([NSEvent doubleClickInterval] * 1000.0);
}
-static int impl_display_modifiers(const struct yasl_display *d)
+static int impl_display_modifiers(const struct yasl_private_display *d)
{
return cocoa_display_modifiers((const struct cocoa_display *)d);
}
-static void impl_display_copy(struct yasl_display *d, enum yasl_selection sel, const char *text)
+static void impl_display_copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
{
cocoa_display_copy((struct cocoa_display *)d, sel, text);
}
-static void impl_display_paste(struct yasl_display *d, enum yasl_selection sel, struct yasl_surface *target)
+static void impl_display_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target)
{
cocoa_display_paste((struct cocoa_display *)d, sel, (struct cocoa_surface *)target);
}
-static bool impl_display_copy_text(struct yasl_display *d, enum yasl_selection sel, const char *text)
+static bool impl_display_copy_text(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
{
return cocoa_display_copy_text((struct cocoa_display *)d, sel, text);
}
-static bool impl_display_request_paste(struct yasl_display *d, enum yasl_selection sel,
+static bool impl_display_request_paste(struct yasl_private_display *d, enum yasl_private_selection sel,
struct yasl_surface *target, uint64_t request_id)
{
return cocoa_display_request_paste((struct cocoa_display *)d, sel,
(struct cocoa_surface *)target, request_id);
}
-static bool impl_display_drag_start(struct yasl_display *d, struct yasl_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud)
+static bool impl_display_drag_start(struct yasl_private_display *d, struct yasl_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud)
{
return cocoa_display_drag_start((struct cocoa_display *)d, (struct cocoa_surface *)origin, image, l, ud);
}
-static void impl_display_drag_cancel(struct yasl_display *d)
+static void impl_display_drag_cancel(struct yasl_private_display *d)
{
- drag_end((struct cocoa_display *)d, YASL_DRAG_CANCELLED);
+ drag_end((struct cocoa_display *)d, YASL_PRIVATE_DRAG_CANCELLED);
}
-static struct yasl_surface *impl_surface_create_toplevel(struct yasl_display *d,
- const struct yasl_window_spec *spec, void *graphics_device)
+static struct yasl_surface *impl_surface_create_toplevel(struct yasl_private_display *d,
+ const struct yasl_private_window_spec *spec, void *graphics_device)
{
struct cocoa_surface *result = cocoa_surface_create_toplevel((struct cocoa_display *)d, spec, graphics_device);
return result ? &result->base : NULL;
}
-static struct yasl_surface *impl_surface_create_popup(struct yasl_surface *parent, const struct yasl_popup_spec *spec)
+static struct yasl_surface *impl_surface_create_popup(struct yasl_surface *parent, const struct yasl_private_popup_spec *spec)
{
struct cocoa_surface *result = cocoa_surface_create_popup((struct cocoa_surface *)parent, spec);
return result ? &result->base : NULL;
}
-static bool impl_surface_popup_reposition(struct yasl_surface *popup, const struct yasl_popup_spec *spec)
+static bool impl_surface_popup_reposition(struct yasl_surface *popup, const struct yasl_private_popup_spec *spec)
{
return cocoa_surface_popup_reposition((struct cocoa_surface *)popup, spec);
}
@@ -2238,12 +2633,12 @@ static struct input_queue *impl_surface_input_queue(struct yasl_surface *s)
return w ? &w->input : NULL;
}
-static struct yasl_display *impl_surface_display(const struct yasl_surface *s)
+static struct yasl_private_display *impl_surface_display(const struct yasl_surface *s)
{
return s ? &darwin_ctx.base : NULL;
}
-static void impl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_window_cbs *cbs, void *ud)
+static void impl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_private_window_cbs *cbs, void *ud)
{
cocoa_surface_set_callbacks((struct cocoa_surface *)s, cbs, ud);
}
@@ -2258,17 +2653,17 @@ static void impl_surface_schedule_redraw(struct yasl_surface *s)
cocoa_surface_schedule_redraw((struct cocoa_surface *)s);
}
-static bool impl_surface_present(struct yasl_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage)
+static bool impl_surface_present(struct yasl_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage)
{
return cocoa_surface_present((struct cocoa_surface *)s, fb, damage);
}
-static struct yasl_geometry impl_surface_geometry(const struct yasl_surface *s)
+static struct yasl_private_geometry impl_surface_geometry(const struct yasl_surface *s)
{
return cocoa_surface_geometry((const struct cocoa_surface *)s);
}
-static struct yasl_timing impl_surface_timing(const struct yasl_surface *s)
+static struct yasl_private_timing impl_surface_timing(const struct yasl_surface *s)
{
return cocoa_surface_timing((const struct cocoa_surface *)s);
}
@@ -2276,10 +2671,10 @@ static struct yasl_timing impl_surface_timing(const struct yasl_surface *s)
static uint64_t impl_surface_frame_time_ns(struct yasl_surface *s, uint64_t now)
{
struct cocoa_surface *w = (struct cocoa_surface *)s;
- return w ? yasl_clock_frame_timestamp_ns(&w->clock, now) : now;
+ return w ? yasl_private_clock_frame_timestamp_ns(&w->clock, now) : now;
}
-static void impl_surface_set_cursor(struct yasl_surface *s, enum yasl_cursor cursor)
+static void impl_surface_set_cursor(struct yasl_surface *s, enum yasl_private_cursor cursor)
{
cocoa_surface_set_cursor((struct cocoa_surface *)s, cursor);
}
@@ -2300,7 +2695,7 @@ static bool impl_surface_ime_preedit_cursor(const struct yasl_surface *s, int *b
return cocoa_surface_ime_preedit_cursor((const struct cocoa_surface *)s, begin, end);
}
-static void impl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_rect2i caret)
+static void impl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_private_rect2i caret)
{
cocoa_surface_set_ime_caret((struct cocoa_surface *)s, caret);
}
@@ -2310,35 +2705,165 @@ static bool impl_surface_start_interactive_move(struct yasl_surface *s)
return cocoa_surface_start_interactive_move((struct cocoa_surface *)s);
}
-static bool impl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_resize_edge edge)
+static bool impl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_private_resize_edge edge)
{
return cocoa_surface_start_interactive_resize((struct cocoa_surface *)s, edge);
}
-static bool impl_surface_show_window_menu(struct yasl_surface *s, struct yasl_vector2i pos)
+static bool impl_surface_show_window_menu(struct yasl_surface *s, struct yasl_private_vector2i pos)
{
return cocoa_surface_show_window_menu((struct cocoa_surface *)s, pos);
}
-static bool impl_surface_drag_carry(struct yasl_surface *s, struct yasl_vector2i offset)
+static bool impl_surface_drag_carry(struct yasl_surface *s, struct yasl_private_vector2i offset)
{
return cocoa_surface_drag_carry((struct cocoa_surface *)s, offset);
}
-static bool impl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_vector2i at)
+static bool impl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_private_vector2i at)
{
return cocoa_surface_place_under_pointer((struct cocoa_surface *)s, at);
}
+static struct yasl_surface *impl_surface_create_gl(struct yasl_private_display *display,
+ const struct yasl_private_window_spec *spec, const int *attrs, struct yasl_surface *share)
+{
+ struct yasl_private_gl_options options;
+ if (!spec || !yasl_private_gl_parse_options(attrs, &options) ||
+ options.api != YASL_PRIVATE_GL_OPENGL || options.debug || (share &&
+ (share->display != display || share->presenter != YASL_PRIVATE_PRESENTER_GL)))
+ return NULL;
+ int profile = options.profile;
+ if (profile == YASL_PRIVATE_GL_ANY)
+ profile = options.major >= 3 ? YASL_PRIVATE_GL_CORE : YASL_PRIVATE_GL_COMPATIBILITY;
+ if (options.forward_compat && profile != YASL_PRIVATE_GL_CORE)
+ return NULL;
+ if ((profile == YASL_PRIVATE_GL_CORE &&
+ (options.major != 3 || options.minor != 2)) ||
+ (profile == YASL_PRIVATE_GL_COMPATIBILITY &&
+ (options.major > 2 || (options.major == 2 && options.minor > 1))))
+ return NULL;
+
+ struct yasl_private_window_spec gl_spec = *spec;
+ gl_spec.external_gpu = true;
+ struct cocoa_surface *w = cocoa_surface_create_toplevel((struct cocoa_display *)display, &gl_spec, NULL);
+ if (!w) return NULL;
+
+ NSOpenGLPixelFormatAttribute pixel_attrs[32];
+ NSUInteger n = 0;
+ pixel_attrs[n++] = NSOpenGLPFAAccelerated;
+ pixel_attrs[n++] = NSOpenGLPFADoubleBuffer;
+ pixel_attrs[n++] = NSOpenGLPFAColorSize;
+ pixel_attrs[n++] = options.red_bits + options.green_bits + options.blue_bits + options.alpha_bits;
+ pixel_attrs[n++] = NSOpenGLPFAAlphaSize;
+ pixel_attrs[n++] = options.alpha_bits;
+ pixel_attrs[n++] = NSOpenGLPFADepthSize;
+ pixel_attrs[n++] = options.depth_bits;
+ pixel_attrs[n++] = NSOpenGLPFAStencilSize;
+ pixel_attrs[n++] = options.stencil_bits;
+ if (options.samples > 0) {
+ pixel_attrs[n++] = NSOpenGLPFASampleBuffers;
+ pixel_attrs[n++] = 1;
+ pixel_attrs[n++] = NSOpenGLPFASamples;
+ pixel_attrs[n++] = options.samples;
+ }
+ if (options.srgb) pixel_attrs[n++] = NSOpenGLPFASRGB;
+ if (profile == YASL_PRIVATE_GL_CORE) {
+ pixel_attrs[n++] = NSOpenGLPFAOpenGLProfile;
+ pixel_attrs[n++] = NSOpenGLProfileVersion3_2Core;
+ } else if (profile == YASL_PRIVATE_GL_COMPATIBILITY) {
+ pixel_attrs[n++] = NSOpenGLPFAOpenGLProfile;
+ pixel_attrs[n++] = NSOpenGLProfileVersionLegacy;
+ }
+ pixel_attrs[n++] = 0;
+
+ NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixel_attrs];
+ NSOpenGLContext *shared = share ? ((struct cocoa_surface *)share)->gl_context : nil;
+ if (format)
+ w->gl_context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:shared];
+ [format release];
+ if (!w->gl_context) {
+ cocoa_surface_destroy(w);
+ reap_dead((struct cocoa_display *)display);
+ return NULL;
+ }
+ [w->view setLayer:[CALayer layer]];
+ w->layer = nil;
+ [w->gl_context setView:w->view];
+ w->base.presenter = YASL_PRIVATE_PRESENTER_GL;
+ return &w->base;
+}
+
+static bool impl_gl_make_current(struct yasl_private_display *display, struct yasl_surface *surface)
+{
+ (void)display;
+ if (!surface) {
+ [NSOpenGLContext clearCurrentContext];
+ return true;
+ }
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_GL || !w->gl_context || w->closed)
+ return false;
+ [w->gl_context makeCurrentContext];
+ return [NSOpenGLContext currentContext] == w->gl_context;
+}
+
+static yasl_private_gl_proc impl_gl_get_proc_address(struct yasl_private_display *display, const char *name)
+{
+ (void)display;
+ return name ? (yasl_private_gl_proc)dlsym(RTLD_DEFAULT, name) : NULL;
+}
+
+static bool impl_gl_swap_interval(struct yasl_private_display *display, struct yasl_surface *surface, int interval)
+{
+ (void)display;
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (!w || w->base.presenter != YASL_PRIVATE_PRESENTER_GL || !w->gl_context || w->closed)
+ return false;
+ [w->gl_context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
+ return true;
+}
+
+static bool impl_gl_swap_buffers(struct yasl_private_display *display, struct yasl_surface *surface)
+{
+ (void)display;
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (!w || w->base.presenter != YASL_PRIVATE_PRESENTER_GL || !w->gl_context || w->closed)
+ return false;
+ [w->gl_context flushBuffer];
+ yasl_private_clock_presented(&w->clock, yasl_private_loop_now_ns(), false);
+ return true;
+}
+
+static void *impl_surface_get_metal_layer(struct yasl_surface *surface)
+{
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ return w && (w->base.presenter == YASL_PRIVATE_PRESENTER_NONE ||
+ w->base.presenter == YASL_PRIVATE_PRESENTER_METAL) ? (void *)w->layer : NULL;
+}
+
+static bool impl_surface_update_text_input(struct yasl_surface *surface)
+{
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (!w || w->closed || w->destroyed || !w->view) return false;
+ if (w->base.text_input_active) {
+ [w->window makeFirstResponder:w->view];
+ } else {
+ [w->view.inputContext discardMarkedText];
+ if (w->preedit) [w->view unmarkText];
+ }
+ return true;
+}
+
static bool impl_surface_read_pixels(struct yasl_surface *s, uint32_t *out, size_t cap,
- struct yasl_vector2i *size)
+ struct yasl_private_vector2i *size)
{
struct cocoa_surface *w = (struct cocoa_surface *)s;
/* did_present stays set from the last draw until the next one starts, and
* pixels are reallocated only when a draw starts. */
if (w->closed || w->rendering || !w->did_present || !w->software_queue || !w->pixels)
return false;
- return yasl_copy_frame(w->pixels, w->shown_size, out, cap, size);
+ return yasl_private_copy_frame(w->pixels, w->shown_size, out, cap, size);
}
static bool impl_surface_bell(struct yasl_surface *s)
@@ -2349,7 +2874,7 @@ static bool impl_surface_bell(struct yasl_surface *s)
return true;
}
-static void *impl_display_get_native_handle(struct yasl_display *d)
+static void *impl_display_get_native_handle(struct yasl_private_display *d)
{
return d ? (void *)NSApp : NULL;
}
@@ -2361,19 +2886,26 @@ static void *impl_surface_get_native_handle(struct yasl_surface *s)
}
static bool impl_surface_get_native_frame(struct yasl_surface *s,
- const struct yasl_framebuffer *target, struct yasl_native_frame *out)
+ const struct yasl_private_framebuffer *target, struct yasl_private_native_frame *out)
{
struct cocoa_surface *w = (struct cocoa_surface *)s;
if (w->closed || !w->rendering || w->did_present || !w->drawable ||
target->pixels != w->frame.target.pixels ||
target->size.x != w->size.x || target->size.y != w->size.y)
return false;
- *out = (struct yasl_native_frame){(void *)w->drawable, w->transaction};
+ *out = (struct yasl_private_native_frame){(void *)w->drawable, w->transaction};
return true;
}
-const struct yasl_backend_ops yasl_cocoa_backend = {
- .type = YASL_BACKEND_COCOA,
+const struct yasl_private_backend_ops yasl_private_cocoa_backend = {
+ .type = YASL_PRIVATE_BACKEND_COCOA,
+ .surface_create_gl = impl_surface_create_gl,
+ .gl_make_current = impl_gl_make_current,
+ .gl_get_proc_address = impl_gl_get_proc_address,
+ .gl_swap_interval = impl_gl_swap_interval,
+ .gl_swap_buffers = impl_gl_swap_buffers,
+ .surface_get_metal_layer = impl_surface_get_metal_layer,
+ .surface_update_text_input = impl_surface_update_text_input,
.display_open = impl_display_open,
.display_close = impl_display_close,
.display_caps = impl_display_caps,
@@ -2421,20 +2953,20 @@ const struct yasl_backend_ops yasl_cocoa_backend = {
.surface_get_native_frame = impl_surface_get_native_frame,
};
-NSApplication *yasl_cocoa_display_get_application(struct yasl_display *d)
+NSApplication *yasl_private_cocoa_display_get_application(struct yasl_private_display *d)
{
- return (d && yasl_display_backend(d) == YASL_BACKEND_COCOA) ?
- (NSApplication *)yasl_display_get_native_handle(d) : nil;
+ return (d && yasl_private_display_backend(d) == YASL_PRIVATE_BACKEND_COCOA) ?
+ (NSApplication *)yasl_private_display_get_native_handle(d) : nil;
}
-NSWindow *yasl_cocoa_surface_get_window(struct yasl_surface *s)
+NSWindow *yasl_private_cocoa_surface_get_window(struct yasl_surface *s)
{
- return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_COCOA) ?
- (NSWindow *)yasl_surface_get_native_handle(s) : nil;
+ return (s && s->display && yasl_private_display_backend(s->display) == YASL_PRIVATE_BACKEND_COCOA) ?
+ (NSWindow *)yasl_private_surface_get_native_handle(s) : nil;
}
-NSView *yasl_cocoa_surface_get_view(struct yasl_surface *s)
+NSView *yasl_private_cocoa_surface_get_view(struct yasl_surface *s)
{
- NSWindow *w = yasl_cocoa_surface_get_window(s);
+ NSWindow *w = yasl_private_cocoa_surface_get_window(s);
return w ? w.contentView : nil;
}
diff --git a/src/platform/freedesktop/dbus.h b/src/platform/freedesktop/dbus.h
index fd0aeb1..beda62b 100644
--- a/src/platform/freedesktop/dbus.h
+++ b/src/platform/freedesktop/dbus.h
@@ -1,5 +1,5 @@
-#ifndef YASL_FREEDESKTOP_DBUS_H
-#define YASL_FREEDESKTOP_DBUS_H
+#ifndef YASL_PRIVATE_FREEDESKTOP_DBUS_H
+#define YASL_PRIVATE_FREEDESKTOP_DBUS_H
#include <stdbool.h>
#include <stdint.h>
diff --git a/src/platform/freedesktop/desktop.c b/src/platform/freedesktop/desktop.c
index a8b9bc7..f90701a 100644
--- a/src/platform/freedesktop/desktop.c
+++ b/src/platform/freedesktop/desktop.c
@@ -1,7 +1,7 @@
#define _GNU_SOURCE
#include "common/desktop.h"
#include "platform/freedesktop/dbus.h"
-#include "yasl/desktop.h"
+#include "common/private_desktop.h"
#include <errno.h>
#include <fcntl.h>
@@ -105,21 +105,21 @@ uint32_t desktop_appearance(void)
int64_t value;
if (portal_read_int("org.freedesktop.appearance", "color-scheme", &value)) {
portal = true;
- if (value == 1) flags |= YASL_APPEARANCE_DARK;
- else if (value == 2) flags |= YASL_APPEARANCE_LIGHT;
+ if (value == 1) flags |= YASL_PRIVATE_APPEARANCE_DARK;
+ else if (value == 2) flags |= YASL_PRIVATE_APPEARANCE_LIGHT;
}
if (portal_read_int("org.freedesktop.appearance", "contrast", &value)) {
portal = true;
- if (value == 1) flags |= YASL_APPEARANCE_HIGH_CONTRAST;
+ if (value == 1) flags |= YASL_PRIVATE_APPEARANCE_HIGH_CONTRAST;
}
if (portal) return flags;
/* GTK_THEME is "Name" or "Name:variant", as in "Adwaita:dark". */
const char *theme = getenv("GTK_THEME");
if (!theme) return 0;
- if (strstr(theme, "HighContrast")) flags |= YASL_APPEARANCE_HIGH_CONTRAST;
+ if (strstr(theme, "HighContrast")) flags |= YASL_PRIVATE_APPEARANCE_HIGH_CONTRAST;
if (strstr(theme, ":dark") || strstr(theme, "HighContrastInverse"))
- flags |= YASL_APPEARANCE_DARK;
+ flags |= YASL_PRIVATE_APPEARANCE_DARK;
return flags;
}
diff --git a/src/platform/posix/loop.c b/src/platform/posix/loop.c
index 3c3d730..49132f8 100644
--- a/src/platform/posix/loop.c
+++ b/src/platform/posix/loop.c
@@ -14,35 +14,35 @@
#include <time.h>
#include <unistd.h>
-#define YASL_LOOP_INIT_CAP 32
+#define YASL_PRIVATE_LOOP_INIT_CAP 32
-typedef int (*yasl_loop_fd_fn)(int fd, short revents, void *ud);
+typedef int (*yasl_private_loop_fd_fn)(int fd, short revents, void *ud);
-struct yasl_fd_source {
- yasl_loop_fd_fn fn;
+struct yasl_private_fd_source {
+ yasl_private_loop_fd_fn fn;
void *ud;
int id;
int fd;
short events;
};
-struct yasl_timer_source {
- yasl_timer_cb fn;
+struct yasl_private_timer_source {
+ yasl_private_timer_cb fn;
void *ud;
uint64_t interval_ns;
uint64_t deadline_ns;
- yasl_timer_id id;
+ yasl_private_timer_id id;
bool deleted;
};
-struct yasl_post {
+struct yasl_private_post {
void (*fn)(void *ud);
void *ud;
- struct yasl_post *next;
+ struct yasl_private_post *next;
};
/* Signals this loop watches; the previous actions are restored on unwatch. */
-struct yasl_signal_watch {
+struct yasl_private_signal_watch {
void (*cb)(void *ud, int signo);
void *ud;
int count;
@@ -50,8 +50,8 @@ struct yasl_signal_watch {
struct sigaction old[NSIG];
};
-struct yasl_loop {
- struct yasl_fd_source *fds;
+struct yasl_private_loop {
+ struct yasl_private_fd_source *fds;
struct pollfd *pollfds;
int count;
int capacity;
@@ -61,17 +61,17 @@ struct yasl_loop {
int wake_wfd;
int wake_watch;
- struct yasl_timer_source *timers;
+ struct yasl_private_timer_source *timers;
int timer_count;
int timer_capacity;
uint32_t next_timer_id;
int timer_firing_depth;
- yasl_mutex post_mutex;
- struct yasl_post *post_head;
- struct yasl_post *post_tail;
+ yasl_private_mutex post_mutex;
+ struct yasl_private_post *post_head;
+ struct yasl_private_post *post_tail;
- struct yasl_signal_watch *signals;
+ struct yasl_private_signal_watch *signals;
};
/* Handlers run on any thread, so they only touch lock-free atomics: they mark
@@ -79,34 +79,34 @@ struct yasl_loop {
* stored as fd + 1 so that the zero initializer means no pipe. */
static atomic_int signal_wake_fd[NSIG];
static atomic_bool signal_pending[NSIG];
-static struct yasl_loop *signal_owner[NSIG];
+static struct yasl_private_loop *signal_owner[NSIG];
-uint64_t yasl_loop_now_ns(void)
+uint64_t yasl_private_loop_now_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec;
}
-static void run_posts(struct yasl_loop *l)
+static void run_posts(struct yasl_private_loop *l)
{
- yasl_mutex_lock(&l->post_mutex);
- struct yasl_post *p = l->post_head;
+ yasl_private_mutex_lock(&l->post_mutex);
+ struct yasl_private_post *p = l->post_head;
l->post_head = l->post_tail = NULL;
- yasl_mutex_unlock(&l->post_mutex);
+ yasl_private_mutex_unlock(&l->post_mutex);
while (p) {
- struct yasl_post *next = p->next;
+ struct yasl_private_post *next = p->next;
p->fn(p->ud);
free(p);
p = next;
}
}
-static void run_signals(struct yasl_loop *l)
+static void run_signals(struct yasl_private_loop *l)
{
/* A callback may unwatch, so re-check the watch before each delivery. */
for (int signo = 1; signo < NSIG; signo++) {
- struct yasl_signal_watch *w = l->signals;
+ struct yasl_private_signal_watch *w = l->signals;
if (!w) return;
if (signal_owner[signo] != l || !atomic_exchange(&signal_pending[signo], false))
continue;
@@ -120,18 +120,18 @@ static int loop_wake_cb(int fd, short revents, void *ud)
char buf[128];
ssize_t n;
while ((n = read(fd, buf, sizeof(buf))) > 0 || (n < 0 && errno == EINTR)) {}
- struct yasl_loop *l = ud;
+ struct yasl_private_loop *l = ud;
run_posts(l);
run_signals(l);
return 0;
}
-struct yasl_loop *yasl_loop_create(void)
+struct yasl_private_loop *yasl_private_loop_create(void)
{
- struct yasl_loop *l = calloc(1, sizeof(*l));
+ struct yasl_private_loop *l = calloc(1, sizeof(*l));
if (!l) return NULL;
- l->capacity = YASL_LOOP_INIT_CAP;
+ l->capacity = YASL_PRIVATE_LOOP_INIT_CAP;
l->fds = malloc((size_t)l->capacity * sizeof(*l->fds));
l->pollfds = malloc((size_t)l->capacity * sizeof(*l->pollfds));
if (!l->fds || !l->pollfds) {
@@ -141,7 +141,7 @@ struct yasl_loop *yasl_loop_create(void)
return NULL;
}
- if (yasl_mutex_init(&l->post_mutex) != 0) {
+ if (yasl_private_mutex_init(&l->post_mutex) != 0) {
free(l->fds);
free(l->pollfds);
free(l);
@@ -173,23 +173,23 @@ struct yasl_loop *yasl_loop_create(void)
#endif
if (l->wake_rfd >= 0) {
- l->wake_watch = yasl_loop_add_fd(l, l->wake_rfd, POLLIN, loop_wake_cb, l);
+ l->wake_watch = yasl_private_loop_add_fd(l, l->wake_rfd, POLLIN, loop_wake_cb, l);
}
return l;
}
-void yasl_loop_destroy(struct yasl_loop *l)
+void yasl_private_loop_destroy(struct yasl_private_loop *l)
{
if (!l) return;
- yasl_loop_unwatch_signals(l);
- for (struct yasl_post *p = l->post_head; p;) {
- struct yasl_post *next = p->next;
+ yasl_private_loop_unwatch_signals(l);
+ for (struct yasl_private_post *p = l->post_head; p;) {
+ struct yasl_private_post *next = p->next;
free(p);
p = next;
}
- yasl_mutex_destroy(&l->post_mutex);
+ yasl_private_mutex_destroy(&l->post_mutex);
if (l->wake_watch > 0)
- yasl_loop_del_fd(l, l->wake_watch);
+ yasl_private_loop_del_fd(l, l->wake_watch);
if (l->wake_rfd >= 0)
close(l->wake_rfd);
if (l->wake_wfd >= 0)
@@ -200,15 +200,15 @@ void yasl_loop_destroy(struct yasl_loop *l)
free(l);
}
-int yasl_loop_add_fd(struct yasl_loop *l, int fd, short events,
+int yasl_private_loop_add_fd(struct yasl_private_loop *l, int fd, short events,
int (*fn)(int fd, short revents, void *ud), void *ud)
{
if (!l || fd < 0)
return -1;
if (l->count >= l->capacity) {
- int new_cap = l->capacity ? l->capacity * 2 : YASL_LOOP_INIT_CAP;
- struct yasl_fd_source *new_fds = realloc(l->fds, (size_t)new_cap * sizeof(*new_fds));
+ int new_cap = l->capacity ? l->capacity * 2 : YASL_PRIVATE_LOOP_INIT_CAP;
+ struct yasl_private_fd_source *new_fds = realloc(l->fds, (size_t)new_cap * sizeof(*new_fds));
if (!new_fds) return -1;
l->fds = new_fds;
@@ -221,7 +221,7 @@ int yasl_loop_add_fd(struct yasl_loop *l, int fd, short events,
int id = l->next_id++;
if (l->next_id <= 0) l->next_id = 1;
- l->fds[l->count] = (struct yasl_fd_source){
+ l->fds[l->count] = (struct yasl_private_fd_source){
.fn = fn, .ud = ud, .id = id, .fd = fd, .events = events,
};
l->pollfds[l->count] = (struct pollfd){
@@ -231,7 +231,7 @@ int yasl_loop_add_fd(struct yasl_loop *l, int fd, short events,
return id;
}
-int yasl_loop_del_fd(struct yasl_loop *l, int id)
+int yasl_private_loop_del_fd(struct yasl_private_loop *l, int id)
{
if (!l || id <= 0) return -1;
for (int i = 0; i < l->count; i++) {
@@ -245,7 +245,7 @@ int yasl_loop_del_fd(struct yasl_loop *l, int id)
return -1;
}
-int yasl_loop_set_fd_events(struct yasl_loop *l, int id, short events)
+int yasl_private_loop_set_fd_events(struct yasl_private_loop *l, int id, short events)
{
if (!l || id <= 0) return -1;
for (int i = 0; i < l->count; i++) {
@@ -270,25 +270,25 @@ static void wake_write(int fd)
errno = saved;
}
-void yasl_loop_kick(struct yasl_loop *l)
+void yasl_private_loop_kick(struct yasl_private_loop *l)
{
if (!l || l->wake_wfd < 0) return;
wake_write(l->wake_wfd);
}
-bool yasl_loop_post(struct yasl_loop *l, void (*fn)(void *ud), void *ud)
+bool yasl_private_loop_post(struct yasl_private_loop *l, void (*fn)(void *ud), void *ud)
{
if (!l || !fn || l->wake_wfd < 0) return false;
- struct yasl_post *p = malloc(sizeof(*p));
+ struct yasl_private_post *p = malloc(sizeof(*p));
if (!p) return false;
- *p = (struct yasl_post){.fn = fn, .ud = ud};
- yasl_mutex_lock(&l->post_mutex);
+ *p = (struct yasl_private_post){.fn = fn, .ud = ud};
+ yasl_private_mutex_lock(&l->post_mutex);
if (l->post_tail)
l->post_tail->next = p;
else
l->post_head = p;
l->post_tail = p;
- yasl_mutex_unlock(&l->post_mutex);
+ yasl_private_mutex_unlock(&l->post_mutex);
wake_write(l->wake_wfd);
return true;
}
@@ -305,7 +305,7 @@ static bool signal_valid(int signo)
return signo > 0 && signo < NSIG && signo != SIGKILL && signo != SIGSTOP;
}
-bool yasl_loop_watch_signals(struct yasl_loop *l, const int *signals, int n,
+bool yasl_private_loop_watch_signals(struct yasl_private_loop *l, const int *signals, int n,
void (*cb)(void *ud, int signo), void *ud)
{
if (!l || !signals || n <= 0 || !cb || l->wake_wfd < 0) {
@@ -324,14 +324,14 @@ bool yasl_loop_watch_signals(struct yasl_loop *l, const int *signals, int n,
}
wanted[signals[i]] = true;
}
- struct yasl_signal_watch *w = calloc(1, sizeof(*w));
+ struct yasl_private_signal_watch *w = calloc(1, sizeof(*w));
if (!w) return false;
w->cb = cb;
w->ud = ud;
/* Keep the old watch's saved actions for signals that stay watched, so
* that unwatch restores what the application had before any watch. */
- struct yasl_signal_watch *old = l->signals;
+ struct yasl_private_signal_watch *old = l->signals;
struct sigaction sa = {.sa_handler = signal_handler, .sa_flags = SA_RESTART};
sigemptyset(&sa.sa_mask);
for (int signo = 1; signo < NSIG; signo++) {
@@ -380,10 +380,10 @@ bool yasl_loop_watch_signals(struct yasl_loop *l, const int *signals, int n,
return true;
}
-void yasl_loop_unwatch_signals(struct yasl_loop *l)
+void yasl_private_loop_unwatch_signals(struct yasl_private_loop *l)
{
if (!l || !l->signals) return;
- struct yasl_signal_watch *w = l->signals;
+ struct yasl_private_signal_watch *w = l->signals;
l->signals = NULL;
for (int i = 0; i < w->count; i++) {
int signo = w->signals[i];
@@ -395,19 +395,19 @@ void yasl_loop_unwatch_signals(struct yasl_loop *l)
free(w);
}
-static void timer_cleanup_deleted(struct yasl_loop *l)
+static void timer_cleanup_deleted(struct yasl_private_loop *l)
{
if (!l || l->timer_firing_depth > 0) return;
int dest = 0;
for (int src = 0; src < l->timer_count; src++) {
- struct yasl_timer_source t = l->timers[src];
+ struct yasl_private_timer_source t = l->timers[src];
l->timers[dest] = t;
dest += !t.deleted;
}
l->timer_count = dest;
}
-bool yasl_loop_timer_armed(const struct yasl_loop *l, yasl_timer_id id)
+bool yasl_private_loop_timer_armed(const struct yasl_private_loop *l, yasl_private_timer_id id)
{
if (!l || id == 0) return false;
for (int i = 0; i < l->timer_count; i++)
@@ -416,7 +416,7 @@ bool yasl_loop_timer_armed(const struct yasl_loop *l, yasl_timer_id id)
return false;
}
-int yasl_loop_poll_set(const struct yasl_loop *l, const struct pollfd **fds)
+int yasl_private_loop_poll_set(const struct yasl_private_loop *l, const struct pollfd **fds)
{
if (!l) {
*fds = NULL;
@@ -426,10 +426,10 @@ int yasl_loop_poll_set(const struct yasl_loop *l, const struct pollfd **fds)
return l->count;
}
-int yasl_loop_next_timeout_ms(const struct yasl_loop *l)
+int yasl_private_loop_next_timeout_ms(const struct yasl_private_loop *l)
{
if (!l || l->timer_count <= 0) return -1;
- uint64_t now = yasl_loop_now_ns();
+ uint64_t now = yasl_private_loop_now_ns();
uint64_t min_deadline = UINT64_MAX;
bool has_active = false;
for (int i = 0; i < l->timer_count; i++) {
@@ -446,14 +446,14 @@ int yasl_loop_next_timeout_ms(const struct yasl_loop *l)
return (ms > (uint64_t)INT_MAX) ? INT_MAX : (int)ms;
}
-yasl_timer_id yasl_loop_add_timer(struct yasl_loop *l, uint64_t interval_ns,
- yasl_timer_cb cb, void *ud)
+yasl_private_timer_id yasl_private_loop_add_timer(struct yasl_private_loop *l, uint64_t interval_ns,
+ yasl_private_timer_cb cb, void *ud)
{
if (!l || !cb || interval_ns == 0) return 0;
if (l->timer_count >= l->timer_capacity) {
int new_cap = l->timer_capacity ? l->timer_capacity * 2 : 16;
- struct yasl_timer_source *new_timers = realloc(l->timers, (size_t)new_cap * sizeof(*new_timers));
+ struct yasl_private_timer_source *new_timers = realloc(l->timers, (size_t)new_cap * sizeof(*new_timers));
if (!new_timers) return 0;
l->timers = new_timers;
l->timer_capacity = new_cap;
@@ -462,8 +462,8 @@ yasl_timer_id yasl_loop_add_timer(struct yasl_loop *l, uint64_t interval_ns,
uint32_t id = l->next_timer_id++;
if (l->next_timer_id == 0) l->next_timer_id = 1;
- uint64_t now = yasl_loop_now_ns();
- l->timers[l->timer_count++] = (struct yasl_timer_source){
+ uint64_t now = yasl_private_loop_now_ns();
+ l->timers[l->timer_count++] = (struct yasl_private_timer_source){
.fn = cb,
.ud = ud,
.id = id,
@@ -472,11 +472,11 @@ yasl_timer_id yasl_loop_add_timer(struct yasl_loop *l, uint64_t interval_ns,
.deleted = false,
};
- yasl_loop_kick(l);
+ yasl_private_loop_kick(l);
return id;
}
-bool yasl_loop_del_timer(struct yasl_loop *l, yasl_timer_id id)
+bool yasl_private_loop_del_timer(struct yasl_private_loop *l, yasl_private_timer_id id)
{
if (!l || id == 0) return false;
for (int i = l->timer_count - 1; i >= 0; i--) {
@@ -496,11 +496,11 @@ bool yasl_loop_del_timer(struct yasl_loop *l, yasl_timer_id id)
return false;
}
-int yasl_loop_step(struct yasl_loop *l, int timeout_ms)
+int yasl_private_loop_step(struct yasl_private_loop *l, int timeout_ms)
{
if (!l) return -1;
- int timer_to = yasl_loop_next_timeout_ms(l);
+ int timer_to = yasl_private_loop_next_timeout_ms(l);
int effective_timeout = timeout_ms;
if (timer_to >= 0) {
if (effective_timeout < 0 || timer_to < effective_timeout)
@@ -528,9 +528,9 @@ int yasl_loop_step(struct yasl_loop *l, int timeout_ms)
if (l->count > 0) {
int count = l->count;
- struct yasl_fd_source sstack[32];
+ struct yasl_private_fd_source sstack[32];
struct pollfd pstack[32];
- struct yasl_fd_source *scopy = (count <= 32) ? sstack : malloc((size_t)count * sizeof(*scopy));
+ struct yasl_private_fd_source *scopy = (count <= 32) ? sstack : malloc((size_t)count * sizeof(*scopy));
struct pollfd *pcopy = (count <= 32) ? pstack : malloc((size_t)count * sizeof(*pcopy));
if (!scopy || !pcopy) {
if (scopy && scopy != sstack) free(scopy);
@@ -570,7 +570,7 @@ int yasl_loop_step(struct yasl_loop *l, int timeout_ms)
}
if (l->timer_count > 0) {
- uint64_t now = yasl_loop_now_ns();
+ uint64_t now = yasl_private_loop_now_ns();
l->timer_firing_depth++;
int initial_count = l->timer_count;
for (int i = 0; i < initial_count; i++) {
@@ -578,10 +578,10 @@ int yasl_loop_step(struct yasl_loop *l, int timeout_ms)
if (l->timers[i].deleted || l->timers[i].deadline_ns > now)
continue;
- yasl_timer_id tid = l->timers[i].id;
+ yasl_private_timer_id tid = l->timers[i].id;
uint64_t interval = l->timers[i].interval_ns;
void *ud = l->timers[i].ud;
- struct yasl_timer_source timer_src = l->timers[i];
+ struct yasl_private_timer_source timer_src = l->timers[i];
uint64_t next_interval = timer_src.fn(ud, tid, interval);
handled++;
@@ -623,18 +623,18 @@ int yasl_loop_step(struct yasl_loop *l, int timeout_ms)
return handled;
}
-int yasl_loop_run(struct yasl_loop *l)
+int yasl_private_loop_run(struct yasl_private_loop *l)
{
if (!l) return -1;
l->running = true;
while (l->running) {
- if (yasl_loop_step(l, -1) < 0)
+ if (yasl_private_loop_step(l, -1) < 0)
return -1;
}
return 0;
}
-void yasl_loop_quit(struct yasl_loop *l)
+void yasl_private_loop_quit(struct yasl_private_loop *l)
{
if (l) l->running = false;
}
diff --git a/src/platform/posix/yasl_platform_sync.h b/src/platform/posix/yasl_platform_sync.h
index f94a25d..972eef2 100644
--- a/src/platform/posix/yasl_platform_sync.h
+++ b/src/platform/posix/yasl_platform_sync.h
@@ -1,26 +1,26 @@
-#ifndef YASL_POSIX_SYNC_H
-#define YASL_POSIX_SYNC_H
+#ifndef YASL_PRIVATE_POSIX_SYNC_H
+#define YASL_PRIVATE_POSIX_SYNC_H
#include <pthread.h>
-typedef pthread_mutex_t yasl_mutex;
+typedef pthread_mutex_t yasl_private_mutex;
-static inline int yasl_mutex_init(yasl_mutex *mutex)
+static inline int yasl_private_mutex_init(yasl_private_mutex *mutex)
{
return pthread_mutex_init(mutex, NULL);
}
-static inline void yasl_mutex_destroy(yasl_mutex *mutex)
+static inline void yasl_private_mutex_destroy(yasl_private_mutex *mutex)
{
pthread_mutex_destroy(mutex);
}
-static inline void yasl_mutex_lock(yasl_mutex *mutex)
+static inline void yasl_private_mutex_lock(yasl_private_mutex *mutex)
{
pthread_mutex_lock(mutex);
}
-static inline void yasl_mutex_unlock(yasl_mutex *mutex)
+static inline void yasl_private_mutex_unlock(yasl_private_mutex *mutex)
{
pthread_mutex_unlock(mutex);
}
diff --git a/src/platform/sync.h b/src/platform/sync.h
index 43b4a34..444ff03 100644
--- a/src/platform/sync.h
+++ b/src/platform/sync.h
@@ -1,8 +1,8 @@
-#ifndef YASL_PLATFORM_SYNC_H
-#define YASL_PLATFORM_SYNC_H
+#ifndef YASL_PRIVATE_PLATFORM_SYNC_H
+#define YASL_PRIVATE_PLATFORM_SYNC_H
-/* The OS support directory selected by Meson provides yasl_mutex and the
- * yasl_mutex_init/destroy/lock/unlock operations. Init returns zero on success
+/* The OS support directory selected by Meson provides yasl_private_mutex and the
+ * yasl_private_mutex_init/destroy/lock/unlock operations. Init returns zero on success
* or an errno value on failure. The other operations require an initialized
* mutex. Native types and calls stay in the selected implementation header. */
#include "yasl_platform_sync.h" // IWYU pragma: export
diff --git a/src/platform/wayland/api.h b/src/platform/wayland/api.h
index 0f935b2..9670af1 100644
--- a/src/platform/wayland/api.h
+++ b/src/platform/wayland/api.h
@@ -1,48 +1,48 @@
-#ifndef YASL_WAYLAND_API_H
-#define YASL_WAYLAND_API_H
+#ifndef YASL_PRIVATE_WAYLAND_API_H
+#define YASL_PRIVATE_WAYLAND_API_H
-#include "yasl/yasl.h"
+#include "common/types.h"
struct wayland_display;
struct wayland_surface;
-struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec);
+struct wayland_display *wayland_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec);
void wayland_display_close(struct wayland_display *d);
uint32_t wayland_display_caps(const struct wayland_display *d);
int wayland_display_dispatch_timeout(struct wayland_display *d, int timeout_ms);
void wayland_display_flush(struct wayland_display *d);
int wayland_display_modifiers(const struct wayland_display *d);
-void wayland_display_copy(struct wayland_display *d, enum yasl_selection sel, const char *text);
-void wayland_display_paste(struct wayland_display *d, enum yasl_selection sel, struct wayland_surface *target);
-bool wayland_display_copy_text(struct wayland_display *d, enum yasl_selection sel, const char *text);
-bool wayland_display_request_paste(struct wayland_display *d, enum yasl_selection sel,
+void wayland_display_copy(struct wayland_display *d, enum yasl_private_selection sel, const char *text);
+void wayland_display_paste(struct wayland_display *d, enum yasl_private_selection sel, struct wayland_surface *target);
+bool wayland_display_copy_text(struct wayland_display *d, enum yasl_private_selection sel, const char *text);
+bool wayland_display_request_paste(struct wayland_display *d, enum yasl_private_selection sel,
struct wayland_surface *target, uint64_t request_id);
-bool wayland_display_drag_start(struct wayland_display *d, struct wayland_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud);
+bool wayland_display_drag_start(struct wayland_display *d, struct wayland_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud);
void wayland_display_drag_cancel(struct wayland_display *d);
struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display *d,
- const struct yasl_window_spec *spec, void *graphics_device);
-struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *parent, const struct yasl_popup_spec *spec);
-bool wayland_surface_popup_reposition(struct wayland_surface *popup, const struct yasl_popup_spec *spec);
+ const struct yasl_private_window_spec *spec, void *graphics_device);
+struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *parent, const struct yasl_private_popup_spec *spec);
+bool wayland_surface_popup_reposition(struct wayland_surface *popup, const struct yasl_private_popup_spec *spec);
void wayland_surface_destroy(struct wayland_surface *s);
-void wayland_surface_set_callbacks(struct wayland_surface *s, const struct yasl_window_cbs *cbs, void *ud);
+void wayland_surface_set_callbacks(struct wayland_surface *s, const struct yasl_private_window_cbs *cbs, void *ud);
void wayland_surface_set_title(struct wayland_surface *s, const char *title);
void wayland_surface_schedule_redraw(struct wayland_surface *s);
-bool wayland_surface_present(struct wayland_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage);
-bool wayland_surface_poll_event(struct wayland_surface *s, struct yasl_event *ev);
-struct yasl_geometry wayland_surface_geometry(const struct wayland_surface *s);
-struct yasl_timing wayland_surface_timing(const struct wayland_surface *s);
-void wayland_surface_set_cursor(struct wayland_surface *s, enum yasl_cursor cursor);
-bool wayland_surface_set_pointer_mode(struct wayland_surface *s, enum yasl_pointer_mode mode);
+bool wayland_surface_present(struct wayland_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage);
+bool wayland_surface_poll_event(struct wayland_surface *s, struct yasl_private_event *ev);
+struct yasl_private_geometry wayland_surface_geometry(const struct wayland_surface *s);
+struct yasl_private_timing wayland_surface_timing(const struct wayland_surface *s);
+void wayland_surface_set_cursor(struct wayland_surface *s, enum yasl_private_cursor cursor);
+bool wayland_surface_set_pointer_mode(struct wayland_surface *s, enum yasl_private_pointer_mode mode);
void wayland_surface_set_background_color(struct wayland_surface *s, uint32_t bg);
bool wayland_surface_ime_preedit_cursor(const struct wayland_surface *s, int *begin, int *end);
-void wayland_surface_set_ime_caret(struct wayland_surface *s, struct yasl_rect2i caret);
+void wayland_surface_set_ime_caret(struct wayland_surface *s, struct yasl_private_rect2i caret);
bool wayland_surface_start_interactive_move(struct wayland_surface *s);
-bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_resize_edge edge);
-bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_vector2i pos);
-bool wayland_surface_drag_carry(struct wayland_surface *s, struct yasl_vector2i offset);
-bool wayland_surface_place_under_pointer(struct wayland_surface *s, struct yasl_vector2i at);
+bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_private_resize_edge edge);
+bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_private_vector2i pos);
+bool wayland_surface_drag_carry(struct wayland_surface *s, struct yasl_private_vector2i offset);
+bool wayland_surface_place_under_pointer(struct wayland_surface *s, struct yasl_private_vector2i at);
bool wayland_surface_bell(struct wayland_surface *s);
bool wayland_surface_read_pixels(struct wayland_surface *s, uint32_t *out, size_t cap,
- struct yasl_vector2i *size);
+ struct yasl_private_vector2i *size);
#endif
diff --git a/src/platform/wayland/backend.c b/src/platform/wayland/backend.c
index 7026a8c..02aae59 100644
--- a/src/platform/wayland/backend.c
+++ b/src/platform/wayland/backend.c
@@ -2,50 +2,50 @@
#include "platform/freedesktop/dbus.h"
#include <errno.h>
-static struct yasl_display *impl_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec)
+static struct yasl_private_display *impl_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec)
{
struct wayland_display *result = wayland_display_open(loop, spec);
return result ? &result->base : NULL;
}
-static void impl_display_close(struct yasl_display *d)
+static void impl_display_close(struct yasl_private_display *d)
{
wayland_display_close((struct wayland_display *)d);
}
-static uint32_t impl_display_caps(const struct yasl_display *d)
+static uint32_t impl_display_caps(const struct yasl_private_display *d)
{
return wayland_display_caps((const struct wayland_display *)d);
}
-static int impl_display_dispatch_timeout(struct yasl_display *d, int timeout_ms)
+static int impl_display_dispatch_timeout(struct yasl_private_display *d, int timeout_ms)
{
return wayland_display_dispatch_timeout((struct wayland_display *)d, timeout_ms);
}
-static void impl_display_flush(struct yasl_display *d)
+static void impl_display_flush(struct yasl_private_display *d)
{
wayland_display_flush((struct wayland_display *)d);
}
-static int impl_display_modifiers(const struct yasl_display *d)
+static int impl_display_modifiers(const struct yasl_private_display *d)
{
return wayland_display_modifiers((const struct wayland_display *)d);
}
-static int impl_display_double_click_ms(const struct yasl_display *d)
+static int impl_display_double_click_ms(const struct yasl_private_display *d)
{
/* Wayland has no protocol for it; desktops publish it as a setting. */
(void)d;
return portal_double_click_ms();
}
-static void impl_display_copy(struct yasl_display *d, enum yasl_selection sel, const char *text)
+static void impl_display_copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
{
wayland_display_copy((struct wayland_display *)d, sel, text);
}
-static bool impl_display_copy_text(struct yasl_display *d, enum yasl_selection sel,
+static bool impl_display_copy_text(struct yasl_private_display *d, enum yasl_private_selection sel,
const char *text)
{
bool ok = wayland_display_copy_text((struct wayland_display *)d, sel, text);
@@ -53,12 +53,12 @@ static bool impl_display_copy_text(struct yasl_display *d, enum yasl_selection s
return ok;
}
-static void impl_display_paste(struct yasl_display *d, enum yasl_selection sel, struct yasl_surface *target)
+static void impl_display_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target)
{
wayland_display_paste((struct wayland_display *)d, sel, (struct wayland_surface *)target);
}
-static bool impl_display_request_paste(struct yasl_display *d, enum yasl_selection sel,
+static bool impl_display_request_paste(struct yasl_private_display *d, enum yasl_private_selection sel,
struct yasl_surface *target, uint64_t request_id)
{
bool ok = wayland_display_request_paste((struct wayland_display *)d, sel,
@@ -67,30 +67,171 @@ static bool impl_display_request_paste(struct yasl_display *d, enum yasl_selecti
return ok;
}
-static bool impl_display_drag_start(struct yasl_display *d, struct yasl_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud)
+static bool impl_display_drag_start(struct yasl_private_display *d, struct yasl_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud)
{
return wayland_display_drag_start((struct wayland_display *)d, (struct wayland_surface *)origin, image, l, ud);
}
-static void impl_display_drag_cancel(struct yasl_display *d)
+static void impl_display_drag_cancel(struct yasl_private_display *d)
{
wayland_display_drag_cancel((struct wayland_display *)d);
}
-static struct yasl_surface *impl_surface_create_toplevel(struct yasl_display *d,
- const struct yasl_window_spec *spec, void *graphics_device)
+static struct yasl_surface *impl_surface_create_toplevel(struct yasl_private_display *d,
+ const struct yasl_private_window_spec *spec, void *graphics_device)
{
struct wayland_surface *result = wayland_surface_create_toplevel((struct wayland_display *)d, spec, graphics_device);
return result ? &result->base : NULL;
}
-static struct yasl_surface *impl_surface_create_popup(struct yasl_surface *parent, const struct yasl_popup_spec *spec)
+static bool impl_surface_update_text_input(struct yasl_surface *s)
+{
+ return wayland_surface_update_text_input((struct wayland_surface *)s);
+}
+
+#if YASL_HAS_EGL
+static bool egl_configure(struct wayland_display *d, const struct yasl_private_gl_options *o, EGLConfig *config)
+{
+ if (!d->egl_initialized) return false;
+ EGLint renderable = o->api == YASL_PRIVATE_GL_OPENGL_ES
+ ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT;
+#ifdef EGL_OPENGL_ES_BIT
+ if (o->api == YASL_PRIVATE_GL_OPENGL_ES && o->major < 2)
+ renderable = EGL_OPENGL_ES_BIT;
+#endif
+#ifdef EGL_OPENGL_ES3_BIT_KHR
+ if (o->api == YASL_PRIVATE_GL_OPENGL_ES && o->major >= 3)
+ renderable = EGL_OPENGL_ES3_BIT_KHR;
+#endif
+ EGLint attrs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, renderable,
+ EGL_RED_SIZE, o->red_bits,
+ EGL_GREEN_SIZE, o->green_bits,
+ EGL_BLUE_SIZE, o->blue_bits,
+ EGL_ALPHA_SIZE, o->alpha_bits,
+ EGL_DEPTH_SIZE, o->depth_bits,
+ EGL_STENCIL_SIZE, o->stencil_bits,
+ EGL_SAMPLE_BUFFERS, o->samples > 0 ? 1 : 0,
+ EGL_SAMPLES, o->samples,
+ EGL_NONE,
+ };
+ EGLint api = o->api == YASL_PRIVATE_GL_OPENGL_ES ? EGL_OPENGL_ES_API : EGL_OPENGL_API;
+ if (d->egl_api && d->egl_api != api) return false;
+ EGLint count = 0;
+ if (!eglChooseConfig(d->egl_display, attrs, config, 1, &count) || count < 1)
+ return false;
+ d->egl_api = api;
+ return eglBindAPI(api) == EGL_TRUE;
+}
+
+static struct yasl_surface *impl_surface_create_gl(struct yasl_private_display *display,
+ const struct yasl_private_window_spec *spec, const int *attributes, struct yasl_surface *share)
+{
+ struct wayland_display *d = (struct wayland_display *)display;
+ struct yasl_private_gl_options o;
+ if (!spec || !yasl_private_gl_parse_options(attributes, &o) || !d || !d->egl_initialized)
+ return NULL;
+ struct yasl_private_window_spec gl_spec = *spec;
+ gl_spec.external_gpu = true;
+ gl_spec.flags &= ~YASL_PRIVATE_SURFACE_CPU;
+ struct wayland_surface *w = wayland_surface_create_toplevel(d, &gl_spec, NULL);
+ if (!w) return NULL;
+ if (!egl_configure(d, &o, &w->egl_config)) goto fail;
+ EGLContext share_context = share && share->display == display
+ ? ((struct wayland_surface *)share)->egl_context : EGL_NO_CONTEXT;
+ if (share && share_context == EGL_NO_CONTEXT) goto fail;
+ w->egl_window = wl_egl_window_create(w->surface, w->width, w->height);
+ if (!w->egl_window) goto fail;
+ EGLint context_attrs[12];
+ int n = 0;
+ if (o.api == YASL_PRIVATE_GL_OPENGL_ES) {
+ context_attrs[n++] = EGL_CONTEXT_CLIENT_VERSION;
+ context_attrs[n++] = o.major;
+ } else {
+ context_attrs[n++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
+ context_attrs[n++] = o.major;
+ context_attrs[n++] = EGL_CONTEXT_MINOR_VERSION_KHR;
+ context_attrs[n++] = o.minor;
+ if (o.profile != YASL_PRIVATE_GL_ANY) {
+ context_attrs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
+ context_attrs[n++] = o.profile == YASL_PRIVATE_GL_CORE
+ ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
+ : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
+ }
+ EGLint flags = (o.debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0) |
+ (o.forward_compat ? EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR : 0);
+ if (flags) {
+ context_attrs[n++] = EGL_CONTEXT_FLAGS_KHR;
+ context_attrs[n++] = flags;
+ }
+ }
+ context_attrs[n] = EGL_NONE;
+ w->egl_context = eglCreateContext(d->egl_display, w->egl_config, share_context, context_attrs);
+ if (w->egl_context == EGL_NO_CONTEXT) goto fail;
+ EGLint surface_attrs[] = {
+#ifdef EGL_GL_COLORSPACE_KHR
+ EGL_GL_COLORSPACE_KHR, o.srgb ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR,
+#endif
+ EGL_NONE,
+ };
+ w->egl_surface = eglCreateWindowSurface(d->egl_display, w->egl_config,
+ (EGLNativeWindowType)w->egl_window, surface_attrs);
+ if (w->egl_surface == EGL_NO_SURFACE) { w->egl_surface = 0; goto fail; }
+ w->base.presenter = YASL_PRIVATE_PRESENTER_GL;
+ return &w->base;
+fail:
+ wayland_surface_destroy(w);
+ return NULL;
+}
+
+static bool impl_gl_make_current(struct yasl_private_display *display, struct yasl_surface *surface)
+{
+ struct wayland_display *d = (struct wayland_display *)display;
+ struct wayland_surface *w = (struct wayland_surface *)surface;
+ if (!d) return false;
+ if (!w)
+ return eglMakeCurrent(d->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE;
+ return w->conn == d && w->base.presenter == YASL_PRIVATE_PRESENTER_GL &&
+ eglMakeCurrent(d->egl_display, w->egl_surface, w->egl_surface, w->egl_context) == EGL_TRUE;
+}
+
+static yasl_private_gl_proc impl_gl_get_proc_address(struct yasl_private_display *display, const char *name)
+{
+ (void)display;
+ return name ? (yasl_private_gl_proc)eglGetProcAddress(name) : NULL;
+}
+
+static bool impl_gl_swap_interval(struct yasl_private_display *display, struct yasl_surface *surface, int interval)
+{
+ struct wayland_display *d = (struct wayland_display *)display;
+ struct wayland_surface *w = (struct wayland_surface *)surface;
+ return d && w && w->conn == d && w->base.presenter == YASL_PRIVATE_PRESENTER_GL &&
+ impl_gl_make_current(display, surface) && eglSwapInterval(d->egl_display, interval) == EGL_TRUE;
+}
+
+static bool impl_gl_swap_buffers(struct yasl_private_display *display, struct yasl_surface *surface)
+{
+ struct wayland_display *d = (struct wayland_display *)display;
+ struct wayland_surface *w = (struct wayland_surface *)surface;
+ if (!d || !w || w->conn != d || w->closed || !w->configured ||
+ w->base.presenter != YASL_PRIVATE_PRESENTER_GL)
+ return false;
+ if (!impl_gl_make_current(display, surface)) return false;
+ wayland_surface_arm_frame(w);
+ surface_request_presentation_feedback(w);
+ if (!eglSwapBuffers(d->egl_display, w->egl_surface)) return false;
+ return true;
+}
+#endif
+
+static struct yasl_surface *impl_surface_create_popup(struct yasl_surface *parent, const struct yasl_private_popup_spec *spec)
{
struct wayland_surface *result = wayland_surface_create_popup((struct wayland_surface *)parent, spec);
return result ? &result->base : NULL;
}
-static bool impl_surface_popup_reposition(struct yasl_surface *popup, const struct yasl_popup_spec *spec)
+static bool impl_surface_popup_reposition(struct yasl_surface *popup, const struct yasl_private_popup_spec *spec)
{
return wayland_surface_popup_reposition((struct wayland_surface *)popup, spec);
}
@@ -106,7 +247,7 @@ static struct input_queue *impl_surface_input_queue(struct yasl_surface *s)
return w ? &w->input : NULL;
}
-static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_vector2i size)
+static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_private_vector2i size)
{
struct wayland_surface *w = (struct wayland_surface *)s;
if (!w || w->closed || w->destroyed || !w->toplevel ||
@@ -114,8 +255,19 @@ static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_vector2i s
errno = EINVAL;
return false;
}
- errno = ENOTSUP;
- return false;
+ /* Floating windows choose their own size; constrained states keep it for later. */
+ w->floating_width = size.x;
+ w->floating_height = size.y;
+ if (w->base.state & (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_TILED))
+ return true;
+ w->req_width = w->req_height = 0;
+ w->size_pending = true;
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU && w->configured && apply_pending_geometry(w) < 0) {
+ errno = EIO;
+ return false;
+ }
+ wayland_surface_schedule_redraw(w);
+ return true;
}
static bool impl_surface_set_fullscreen(struct yasl_surface *s, bool enabled)
@@ -153,14 +305,14 @@ static bool impl_surface_minimize(struct yasl_surface *s)
return true;
}
-static struct yasl_display *impl_surface_display(const struct yasl_surface *s)
+static struct yasl_private_display *impl_surface_display(const struct yasl_surface *s)
{
const struct wayland_surface *w = (const struct wayland_surface *)s;
struct wayland_display *result = w ? w->conn : NULL;
return result ? &result->base : NULL;
}
-static void impl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_window_cbs *cbs, void *ud)
+static void impl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_private_window_cbs *cbs, void *ud)
{
wayland_surface_set_callbacks((struct wayland_surface *)s, cbs, ud);
}
@@ -175,37 +327,37 @@ static void impl_surface_schedule_redraw(struct yasl_surface *s)
wayland_surface_schedule_redraw((struct wayland_surface *)s);
}
-static bool impl_surface_present(struct yasl_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage)
+static bool impl_surface_present(struct yasl_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage)
{
return wayland_surface_present((struct wayland_surface *)s, fb, damage);
}
-static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev)
+static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_private_event *ev)
{
return wayland_surface_poll_event((struct wayland_surface *)s, ev);
}
-static struct yasl_geometry impl_surface_geometry(const struct yasl_surface *s)
+static struct yasl_private_geometry impl_surface_geometry(const struct yasl_surface *s)
{
return wayland_surface_geometry((const struct wayland_surface *)s);
}
-static struct yasl_timing impl_surface_timing(const struct yasl_surface *s)
+static struct yasl_private_timing impl_surface_timing(const struct yasl_surface *s)
{
return wayland_surface_timing((const struct wayland_surface *)s);
}
static uint64_t impl_surface_frame_time_ns(struct yasl_surface *s, uint64_t now)
{
- return yasl_clock_frame_timestamp_ns(&((struct wayland_surface *)s)->clock, now);
+ return yasl_private_clock_frame_timestamp_ns(&((struct wayland_surface *)s)->clock, now);
}
-static void impl_surface_set_cursor(struct yasl_surface *s, enum yasl_cursor cursor)
+static void impl_surface_set_cursor(struct yasl_surface *s, enum yasl_private_cursor cursor)
{
wayland_surface_set_cursor((struct wayland_surface *)s, cursor);
}
-static bool impl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_pointer_mode mode)
+static bool impl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_private_pointer_mode mode)
{
return wayland_surface_set_pointer_mode((struct wayland_surface *)s, mode);
}
@@ -226,7 +378,7 @@ static bool impl_surface_ime_preedit_cursor(const struct yasl_surface *s, int *b
return wayland_surface_ime_preedit_cursor((const struct wayland_surface *)s, begin, end);
}
-static void impl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_rect2i caret)
+static void impl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_private_rect2i caret)
{
wayland_surface_set_ime_caret((struct wayland_surface *)s, caret);
}
@@ -236,28 +388,28 @@ static bool impl_surface_start_interactive_move(struct yasl_surface *s)
return wayland_surface_start_interactive_move((struct wayland_surface *)s);
}
-static bool impl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_resize_edge edge)
+static bool impl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_private_resize_edge edge)
{
return wayland_surface_start_interactive_resize((struct wayland_surface *)s, edge);
}
-static bool impl_surface_show_window_menu(struct yasl_surface *s, struct yasl_vector2i pos)
+static bool impl_surface_show_window_menu(struct yasl_surface *s, struct yasl_private_vector2i pos)
{
return wayland_surface_show_window_menu((struct wayland_surface *)s, pos);
}
-static bool impl_surface_drag_carry(struct yasl_surface *s, struct yasl_vector2i offset)
+static bool impl_surface_drag_carry(struct yasl_surface *s, struct yasl_private_vector2i offset)
{
return wayland_surface_drag_carry((struct wayland_surface *)s, offset);
}
-static bool impl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_vector2i at)
+static bool impl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_private_vector2i at)
{
return wayland_surface_place_under_pointer((struct wayland_surface *)s, at);
}
static bool impl_surface_read_pixels(struct yasl_surface *s, uint32_t *out, size_t cap,
- struct yasl_vector2i *size)
+ struct yasl_private_vector2i *size)
{
return wayland_surface_read_pixels((struct wayland_surface *)s, out, cap, size);
}
@@ -267,7 +419,7 @@ static bool impl_surface_bell(struct yasl_surface *s)
return wayland_surface_bell((struct wayland_surface *)s);
}
-static void *impl_display_get_native_handle(struct yasl_display *d)
+static void *impl_display_get_native_handle(struct yasl_private_display *d)
{
struct wayland_display *w = (struct wayland_display *)d;
return w ? w->wl : NULL;
@@ -279,8 +431,16 @@ static void *impl_surface_get_native_handle(struct yasl_surface *s)
return w ? w->surface : NULL;
}
-const struct yasl_backend_ops yasl_wayland_backend = {
- .type = YASL_BACKEND_WAYLAND,
+const struct yasl_private_backend_ops yasl_private_wayland_backend = {
+#if YASL_HAS_EGL
+ .surface_create_gl = impl_surface_create_gl,
+ .gl_make_current = impl_gl_make_current,
+ .gl_get_proc_address = impl_gl_get_proc_address,
+ .gl_swap_interval = impl_gl_swap_interval,
+ .gl_swap_buffers = impl_gl_swap_buffers,
+#endif
+ .surface_update_text_input = impl_surface_update_text_input,
+ .type = YASL_PRIVATE_BACKEND_WAYLAND,
.display_open = impl_display_open,
.display_close = impl_display_close,
.display_caps = impl_display_caps,
diff --git a/src/platform/wayland/buffer.c b/src/platform/wayland/buffer.c
index 874cc76..bbc055d 100644
--- a/src/platform/wayland/buffer.c
+++ b/src/platform/wayland/buffer.c
@@ -24,7 +24,7 @@ static const struct wl_buffer_listener buffer_listener;
int device_px(int logical, uint32_t scale_120)
{
- int64_t px = ((int64_t)logical * scale_120 + YASL_SCALE_UNIT / 2) / YASL_SCALE_UNIT;
+ int64_t px = ((int64_t)logical * scale_120 + YASL_PRIVATE_SCALE_UNIT / 2) / YASL_PRIVATE_SCALE_UNIT;
return px > 0 && px <= INT_MAX ? (int)px : -1;
}
@@ -58,7 +58,7 @@ int buffer_reserve(struct wayland_surface *w, struct buffer *b, size_t needed)
if (b->busy || needed > INT32_MAX) return -1;
size_t capacity = b->capacity <= INT32_MAX / 2 ? b->capacity * 2 : INT32_MAX;
if (capacity < needed) capacity = needed;
- int fd = memfd_create("yasl_surface_buffer", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ int fd = memfd_create("yasl_private_surface_buffer", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd < 0) return -1;
if (!fd_truncate(fd, capacity) ||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL) < 0) {
@@ -89,7 +89,7 @@ int buffer_prepare(struct wayland_surface *w, struct buffer *b, int width, int h
{
if (b->proxy && !b->busy && b->width == width && b->height == height) return 0;
long faults_before = minor_faults();
- uint64_t t0 = yasl_loop_now_ns();
+ uint64_t t0 = yasl_private_loop_now_ns();
size_t bytes;
if (!buffer_size(width, height, &bytes) || buffer_reserve(w, b, bytes) < 0)
return -1;
@@ -104,7 +104,7 @@ int buffer_prepare(struct wayland_surface *w, struct buffer *b, int width, int h
b->busy = false;
b->presented = false;
wl_buffer_add_listener(proxy, listener, b);
- yasl_clock_note_resize(&w->clock, yasl_loop_now_ns() - t0);
+ yasl_private_clock_note_resize(&w->clock, yasl_private_loop_now_ns() - t0);
long faults = minor_faults() - faults_before;
if (faults > 0) w->clock.resize_minflt += faults;
return 0;
@@ -114,10 +114,10 @@ static void publish_surface_scale(struct wayland_surface *w)
{
if (w->viewport) {
wp_viewport_set_destination(w->viewport, w->logical_width, w->logical_height);
- } else if (w->scale_120 % YASL_SCALE_UNIT == 0 &&
+ } else if (w->scale_120 % YASL_PRIVATE_SCALE_UNIT == 0 &&
wl_proxy_get_version((struct wl_proxy *)w->surface) >=
WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) {
- wl_surface_set_buffer_scale(w->surface, (int32_t)(w->scale_120 / YASL_SCALE_UNIT));
+ wl_surface_set_buffer_scale(w->surface, (int32_t)(w->scale_120 / YASL_PRIVATE_SCALE_UNIT));
}
}
@@ -137,16 +137,16 @@ int apply_pending_geometry(struct wayland_surface *w)
return 0;
}
bool floating = !w->parent && !(w->base.state &
- (YASL_STATE_MAXIMIZED | YASL_STATE_FULLSCREEN | YASL_STATE_TILED));
+ (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_TILED));
int free_w = floating && w->floating_width > 0 ? w->floating_width : w->logical_width;
int free_h = floating && w->floating_height > 0 ? w->floating_height : w->logical_height;
int logical_w = !w->parent && w->req_width > 0 ? w->req_width : free_w;
int logical_h = !w->parent && w->req_height > 0 ? w->req_height : free_h;
if (!w->parent) {
- if (logical_w < YASL_MIN_LOGICAL_PX) logical_w = YASL_MIN_LOGICAL_PX;
- if (logical_h < YASL_MIN_LOGICAL_PX) logical_h = YASL_MIN_LOGICAL_PX;
+ if (logical_w < YASL_PRIVATE_MIN_LOGICAL_PX) logical_w = YASL_PRIVATE_MIN_LOGICAL_PX;
+ if (logical_h < YASL_PRIVATE_MIN_LOGICAL_PX) logical_h = YASL_PRIVATE_MIN_LOGICAL_PX;
}
- if (!(w->base.state & YASL_STATE_FULLSCREEN)) {
+ if (!(w->base.state & YASL_PRIVATE_STATE_FULLSCREEN)) {
if (w->bound_width > 0 && logical_w > w->bound_width)
logical_w = w->bound_width;
if (w->bound_height > 0 && logical_h > w->bound_height)
@@ -155,7 +155,9 @@ int apply_pending_geometry(struct wayland_surface *w)
int width = device_px(logical_w, w->pending_scale_120);
int height = device_px(logical_h, w->pending_scale_120);
size_t bytes;
- if (!buffer_size(width, height, &bytes)) {
+ if (width <= 0 || height <= 0 ||
+ (w->base.presenter == YASL_PRIVATE_PRESENTER_CPU &&
+ !buffer_size(width, height, &bytes))) {
return -1;
}
bool rescaled = w->scale_120 != w->pending_scale_120;
@@ -169,13 +171,17 @@ int apply_pending_geometry(struct wayland_surface *w)
return 0;
w->scale_120 = w->pending_scale_120;
- w->scale_factor = (double)w->scale_120 / YASL_SCALE_UNIT;
+ w->scale_factor = (double)w->scale_120 / YASL_PRIVATE_SCALE_UNIT;
w->width = width;
w->height = height;
- w->base.size = (struct yasl_vector2i){width, height};
+ w->base.size = (struct yasl_private_vector2i){width, height};
w->base.scale_120 = w->scale_120;
w->logical_width = logical_w;
w->logical_height = logical_h;
+#if YASL_HAS_EGL
+ if (w->egl_window && (resized || rescaled))
+ wl_egl_window_resize(w->egl_window, width, height, 0, 0);
+#endif
surface_update_opaque_region(w);
if (resized || rescaled) {
for (int i = 0; i < NBUF; i++)
@@ -183,7 +189,7 @@ int apply_pending_geometry(struct wayland_surface *w)
}
publish_surface_scale(w);
if (resized || rescaled) {
- yasl_surface_notify_configure(&w->base, (struct yasl_geometry){
+ yasl_private_surface_notify_configure(&w->base, (struct yasl_private_geometry){
.size = { .x = width, .y = height }, .scale_120 = w->scale_120,
});
if (w->closed || w->destroyed)
@@ -225,7 +231,7 @@ void surface_follow_outputs(struct wayland_surface *w)
w->clock.refresh_ns = refresh;
if (need_scale)
- surface_request_scale(w, (uint32_t)max_scale * YASL_SCALE_UNIT);
+ surface_request_scale(w, (uint32_t)max_scale * YASL_PRIVATE_SCALE_UNIT);
}
static void surface_enter(void *data, struct wl_surface *surface, struct wl_output *output)
@@ -250,7 +256,7 @@ static void surface_preferred_scale(void *data, struct wl_surface *surface, int3
struct wayland_surface *w = data;
if (w->frac_scale || w->parent || factor <= 0)
return;
- surface_request_scale(w, (uint32_t)factor * YASL_SCALE_UNIT);
+ surface_request_scale(w, (uint32_t)factor * YASL_PRIVATE_SCALE_UNIT);
}
static void surface_preferred_transform(void *data, struct wl_surface *surface,
@@ -285,13 +291,15 @@ static void frame_done(void *data, struct wl_callback *cb, uint32_t ms)
wl_callback_destroy(cb);
w->frame_cb = NULL;
- uint64_t now = yasl_loop_now_ns();
+ uint64_t now = yasl_private_loop_now_ns();
if (!w->conn->pres_clock_known) {
- yasl_clock_presented(&w->clock, yasl_clock_extend_ms(ms, now), w->sample_refresh);
- w->clock.source = YASL_TIMING_FRAME_CALLBACK;
+ yasl_private_clock_presented(&w->clock, yasl_private_clock_extend_ms(ms, now), w->sample_refresh);
+ w->clock.source = YASL_PRIVATE_TIMING_FRAME_CALLBACK;
}
- if (w->want_draw)
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU)
+ yasl_private_surface_notify_refresh(&w->base);
+ else if (w->want_draw)
wayland_surface_schedule_redraw(w);
}
@@ -299,14 +307,14 @@ static const struct wl_callback_listener frame_listener = {
.done = frame_done,
};
-static void arm_frame(struct wayland_surface *w)
+void wayland_surface_arm_frame(struct wayland_surface *w)
{
if (!w->configured || w->closed || w->frame_cb)
return;
w->frame_cb = wl_surface_frame(w->surface);
if (!w->frame_cb) { surface_fail(w); return; }
w->sample_refresh = w->clock.last_present_ns &&
- yasl_loop_now_ns() - w->clock.last_present_ns <
+ yasl_private_loop_now_ns() - w->clock.last_present_ns <
(uint64_t)(w->clock.refresh_ns / 2);
if (wl_callback_add_listener(w->frame_cb, &frame_listener, w) < 0) {
wl_callback_destroy(w->frame_cb);
@@ -365,7 +373,7 @@ static void presented(void *data, struct wp_presentation_feedback *fb,
(((uint64_t)tv_sec_hi << 32) | tv_sec_lo) * 1000000000ull + tv_nsec);
if (refresh) w->clock.refresh_ns = refresh;
w->clock.last_present_ns = ns;
- w->clock.source = YASL_TIMING_PRESENTATION;
+ w->clock.source = YASL_PRIVATE_TIMING_PRESENTATION;
}
(void)fb;
feedback_destroy(feedback);
@@ -419,7 +427,7 @@ static void commit_buffer(struct wayland_surface *w, int idx)
{
wl_surface_attach(w->surface, w->buffers[idx].proxy, 0, 0);
- const struct yasl_damage_list *d = &w->damage;
+ const struct yasl_private_damage_list *d = &w->damage;
if (d->n < 0 || !w->buffers[idx].presented)
wl_surface_damage_buffer(w->surface, 0, 0, w->width, w->height);
else
@@ -438,8 +446,8 @@ static void commit_buffer(struct wayland_surface *w, int idx)
wp_fifo_v1_set_barrier(w->fifo);
}
if (w->commit_timer && w->conn->pres_clock_known) {
- uint64_t now = yasl_loop_now_ns();
- uint64_t next = yasl_clock_next_present_ns(&w->clock);
+ uint64_t now = yasl_private_loop_now_ns();
+ uint64_t next = yasl_private_clock_next_present_ns(&w->clock);
bool soon = next > now && next - now < (uint64_t)(w->clock.refresh_ns * 1.5);
next = conn_mono_to_pres(w->conn, next);
if (soon)
@@ -458,10 +466,11 @@ static void commit_buffer(struct wayland_surface *w, int idx)
w->buffers[idx].presented = true;
}
-bool wayland_surface_present(struct wayland_surface *w, const struct yasl_framebuffer *fb,
- const struct yasl_damage_list *damage)
+bool wayland_surface_present(struct wayland_surface *w, const struct yasl_private_framebuffer *fb,
+ const struct yasl_private_damage_list *damage)
{
- if (!w || w->closed || !w->frame_active || w->frame_presented || !fb ||
+ if (!w || w->base.presenter != YASL_PRIVATE_PRESENTER_CPU ||
+ w->closed || !w->frame_active || w->frame_presented || !fb ||
!damage || fb->pixels != w->frame.target.pixels ||
fb->size.x != w->width || fb->size.y != w->height)
return false;
@@ -470,7 +479,7 @@ bool wayland_surface_present(struct wayland_surface *w, const struct yasl_frameb
w->damage.bounds = damage->bounds;
if (damage->n > 0)
memcpy(w->damage.rects, damage->rects, (size_t)damage->n * sizeof(damage->rects[0]));
- arm_frame(w);
+ wayland_surface_arm_frame(w);
if (w->closed)
return false;
commit_buffer(w, w->cur);
@@ -481,17 +490,17 @@ bool wayland_surface_present(struct wayland_surface *w, const struct yasl_frameb
}
bool wayland_surface_read_pixels(struct wayland_surface *w, uint32_t *out, size_t cap,
- struct yasl_vector2i *size)
+ struct yasl_private_vector2i *size)
{
if (!w || w->closed || w->frame_active || !w->has_shown) return false;
const struct buffer *b = &w->buffers[w->shown];
if (!b->pixels) return false;
- return yasl_copy_frame(b->pixels, (struct yasl_vector2i){b->width, b->height}, out, cap, size);
+ return yasl_private_copy_frame(b->pixels, (struct yasl_private_vector2i){b->width, b->height}, out, cap, size);
}
void surface_draw_frame(struct wayland_surface *w)
{
- if (w->closed || !w->configured)
+ if (w->closed || !w->configured || w->base.presenter != YASL_PRIVATE_PRESENTER_CPU)
return;
if (apply_pending_geometry(w) < 0) {
surface_fail(w);
@@ -517,18 +526,18 @@ void surface_draw_frame(struct wayland_surface *w)
if (w->parent)
memset(w->buffers[idx].pixels, 0, (size_t)w->width * (size_t)w->height * sizeof(uint32_t));
- w->damage = (struct yasl_damage_list){0};
- w->frame = (struct yasl_frame){
+ w->damage = (struct yasl_private_damage_list){0};
+ w->frame = (struct yasl_private_frame){
.surface = &w->base,
.target = {
- .generation = yasl_frame_begin(&w->base),
+ .generation = yasl_private_frame_begin(&w->base),
.pixels = w->buffers[idx].pixels,
.size = { .x = w->width, .y = w->height },
},
};
w->frame_active = true;
w->frame_presented = false;
- yasl_surface_draw(&w->base, &w->frame);
+ yasl_private_surface_draw(&w->base, &w->frame);
if (w->closed || w->destroyed)
return;
w->frame_active = false;
@@ -555,21 +564,21 @@ int surface_init_scaling(struct wayland_surface *w)
void wayland_surface_set_title(struct wayland_surface *w, const char *title)
{
if (!w || !w->toplevel || !title) return;
- char *copy = yasl_utf8_sanitize_dup(title);
+ char *copy = yasl_private_utf8_sanitize_dup(title);
if (!copy) return;
xdg_toplevel_set_title(w->toplevel, copy);
free(copy);
}
-struct yasl_timing wayland_surface_timing(const struct wayland_surface *w)
+struct yasl_private_timing wayland_surface_timing(const struct wayland_surface *w)
{
- struct yasl_timing t = {
+ struct yasl_private_timing t = {
.refresh_ns = w->clock.refresh_ns,
.last_present_ns = w->clock.last_present_ns,
- .next_present_ns = yasl_clock_next_present_ns(&w->clock),
+ .next_present_ns = yasl_private_clock_next_present_ns(&w->clock),
.frames_skipped = w->frames_skipped,
.source = w->clock.source,
};
- yasl_clock_resize_stats(&w->clock, &t.resize);
+ yasl_private_clock_resize_stats(&w->clock, &t.resize);
return t;
}
diff --git a/src/platform/wayland/clipboard.c b/src/platform/wayland/clipboard.c
index 8ca9b93..cf39b6c 100644
--- a/src/platform/wayland/clipboard.c
+++ b/src/platform/wayland/clipboard.c
@@ -25,7 +25,7 @@ struct transfer {
struct offer *drop;
struct wl_surface *drop_surface;
int fd, id;
- yasl_timer_id timeout;
+ yasl_private_timer_id timeout;
char *text;
size_t len, offset, capacity;
uint64_t request_id;
@@ -48,7 +48,7 @@ struct clipboard {
struct offer *drag_offer;
struct primary_offer *primary_selection;
struct primary_offer *primary_pending_offers;
- struct yasl_loop *loop;
+ struct yasl_private_loop *loop;
struct transfer *transfers;
char *text;
char *primary_text;
@@ -70,7 +70,7 @@ const char *clipboard_drag_mime(void)
return mime;
}
-static void drag_event(struct clipboard *c, enum yasl_drag_event ev,
+static void drag_event(struct clipboard *c, enum yasl_private_drag_event ev,
wl_fixed_t x, wl_fixed_t y)
{
if (c->drag)
@@ -78,7 +78,7 @@ static void drag_event(struct clipboard *c, enum yasl_drag_event ev,
c->drag_ud);
}
-static void drop_event(struct clipboard *c, enum yasl_drop_event ev)
+static void drop_event(struct clipboard *c, enum yasl_private_drop_event ev)
{
if (c->drop && c->drag_surface)
c->drop(ev, c->drag_surface, wl_fixed_to_double(c->drag_x),
@@ -89,7 +89,7 @@ static void free_offer(struct offer *o);
static void transfer_end(struct transfer *t, bool complete);
-static uint64_t transfer_timeout(void *ud, yasl_timer_id id, uint64_t interval)
+static uint64_t transfer_timeout(void *ud, yasl_private_timer_id id, uint64_t interval)
{
(void)interval;
struct transfer *t = ud;
@@ -106,9 +106,9 @@ static void transfer_end(struct transfer *t, bool complete)
struct transfer **p = &owner->transfers;
while (*p && *p != t) p = &(*p)->next;
if (*p) *p = t->next;
- yasl_loop_del_fd(owner->loop, t->id);
+ yasl_private_loop_del_fd(owner->loop, t->id);
if (t->timeout)
- yasl_loop_del_timer(owner->loop, t->timeout);
+ yasl_private_loop_del_timer(owner->loop, t->timeout);
close(t->fd);
if (t->drop) {
if (complete && wl_data_offer_get_version(t->drop->proxy) >=
@@ -124,7 +124,7 @@ static void transfer_end(struct transfer *t, bool complete)
struct wl_surface *surface = t->drop_surface;
uint64_t request_id = t->request_id;
bool uri_list = t->uri_list;
- enum yasl_transfer_status status = complete ? YASL_TRANSFER_OK : YASL_TRANSFER_FAILED;
+ enum yasl_private_transfer_status status = complete ? YASL_PRIVATE_TRANSFER_OK : YASL_PRIVATE_TRANSFER_FAILED;
const char *text = complete ? (t->text ? t->text : "") : NULL;
size_t len = complete ? t->len : 0;
if (notify)
@@ -156,7 +156,7 @@ static int transfer_io(int fd, short events, void *ud)
if (n > 0) {
t->len += (size_t)n;
} else if (n == 0) {
- bool valid = yasl_utf8_validate(t->text, t->len);
+ bool valid = yasl_private_utf8_validate(t->text, t->len);
transfer_end(t, valid);
} else if (errno != EAGAIN && errno != EINTR) transfer_end(t, false);
}
@@ -176,12 +176,12 @@ static struct transfer *start_transfer_text(struct clipboard *c, int fd, bool se
if (!t->text) { close(fd); free(t); return NULL; }
t->len = strlen(t->text);
}
- t->id = yasl_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t);
+ t->id = yasl_private_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t);
if (t->id < 0) { close(fd); free(t->text); free(t); return NULL; }
- t->timeout = yasl_loop_add_timer(c->loop, CLIPBOARD_TRANSFER_TIMEOUT_NS,
+ t->timeout = yasl_private_loop_add_timer(c->loop, CLIPBOARD_TRANSFER_TIMEOUT_NS,
transfer_timeout, t);
if (!t->timeout) {
- yasl_loop_del_fd(c->loop, t->id);
+ yasl_private_loop_del_fd(c->loop, t->id);
close(fd);
free(t->text);
free(t);
@@ -311,9 +311,9 @@ static void drag_offer_enter(void *ud, struct wl_data_device *device, uint32_t s
c->drag_y = y;
c->drag_surface = surface;
if (o && o->tab)
- drag_event(c, YASL_DRAG_OVER, x, y);
+ drag_event(c, YASL_PRIVATE_DRAG_OVER, x, y);
else if (o && !o->tab && (o->uri_list || o->mime))
- drop_event(c, YASL_DROP_OVER);
+ drop_event(c, YASL_PRIVATE_DROP_OVER);
}
}
static void drag_offer_clear(void *ud, struct wl_data_device *device)
@@ -321,10 +321,10 @@ static void drag_offer_clear(void *ud, struct wl_data_device *device)
(void)device;
struct clipboard *c = ud;
if (c->drag_offer && c->drag_offer->tab)
- drag_event(c, YASL_DRAG_LEAVE, c->drag_x, c->drag_y);
+ drag_event(c, YASL_PRIVATE_DRAG_LEAVE, c->drag_x, c->drag_y);
else if (c->drag_offer && !c->drag_offer->tab &&
(c->drag_offer->uri_list || c->drag_offer->mime))
- drop_event(c, YASL_DROP_LEAVE);
+ drop_event(c, YASL_PRIVATE_DROP_LEAVE);
free_offer(c->drag_offer);
c->drag_offer = NULL;
c->drag_surface = NULL;
@@ -336,10 +336,10 @@ static void drag_motion(void *ud, struct wl_data_device *device, uint32_t time,
c->drag_x = x;
c->drag_y = y;
if (c->drag_offer && c->drag_offer->tab)
- drag_event(c, YASL_DRAG_OVER, x, y);
+ drag_event(c, YASL_PRIVATE_DRAG_OVER, x, y);
else if (c->drag_offer && !c->drag_offer->tab &&
(c->drag_offer->uri_list || c->drag_offer->mime))
- drop_event(c, YASL_DROP_OVER);
+ drop_event(c, YASL_PRIVATE_DROP_OVER);
}
static void drag_drop(void *ud, struct wl_data_device *device)
{
@@ -350,11 +350,11 @@ static void drag_drop(void *ud, struct wl_data_device *device)
c->drag_offer = NULL;
bool v3 = wl_data_offer_get_version(o->proxy) >= 3;
if (o->tab) {
- drag_event(c, YASL_DRAG_DROP, c->drag_x, c->drag_y);
+ drag_event(c, YASL_PRIVATE_DRAG_DROP, c->drag_x, c->drag_y);
if (v3)
wl_data_offer_finish(o->proxy);
} else if (o && !o->tab && (o->uri_list || o->mime)) {
- drop_event(c, YASL_DROP_LEAVE);
+ drop_event(c, YASL_PRIVATE_DROP_LEAVE);
int fds[2];
if (pipe2(fds, O_CLOEXEC) == 0) {
wl_data_offer_receive(o->proxy, o->uri_list ? "text/uri-list" : o->mime, fds[1]);
@@ -522,7 +522,7 @@ struct wl_data_device *clipboard_data_device(const struct clipboard *c)
}
struct clipboard *clipboard_create(struct wl_display *display, struct wl_data_device_manager *manager,
- struct wl_seat *seat, struct yasl_loop *loop,
+ struct wl_seat *seat, struct yasl_private_loop *loop,
clipboard_receive_fn receive, void *ud)
{
if (!manager || !seat) return NULL;
@@ -603,7 +603,7 @@ bool clipboard_copy(struct clipboard *c, const char *text, uint32_t serial)
void clipboard_paste(struct clipboard *c, struct wl_surface *target)
{
if (c && target)
- (void)clipboard_request_paste(c, YASL_CLIPBOARD, target, 0);
+ (void)clipboard_request_paste(c, YASL_PRIVATE_CLIPBOARD, target, 0);
}
bool clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t serial)
@@ -630,24 +630,24 @@ bool clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t seri
void clipboard_paste_primary(struct clipboard *c, struct wl_surface *target)
{
if (c && target)
- (void)clipboard_request_paste(c, YASL_PRIMARY, target, 0);
+ (void)clipboard_request_paste(c, YASL_PRIVATE_PRIMARY, target, 0);
}
-bool clipboard_request_paste(struct clipboard *c, enum yasl_selection selection,
+bool clipboard_request_paste(struct clipboard *c, enum yasl_private_selection selection,
struct wl_surface *target, uint64_t request_id)
{
if (!c || !target || !c->receive)
return false;
int fds[2];
- if (selection == YASL_PRIMARY) {
+ if (selection == YASL_PRIVATE_PRIMARY) {
if (!c->primary_device || !c->primary_selection || !c->primary_selection->mime) {
c->receive(NULL, 0, false, target, request_id,
- YASL_TRANSFER_UNAVAILABLE, c->ud);
+ YASL_PRIVATE_TRANSFER_UNAVAILABLE, c->ud);
return true;
}
if (pipe2(fds, O_CLOEXEC) < 0) {
c->receive(NULL, 0, false, target, request_id,
- YASL_TRANSFER_FAILED, c->ud);
+ YASL_PRIVATE_TRANSFER_FAILED, c->ud);
return true;
}
zwp_primary_selection_offer_v1_receive(c->primary_selection->proxy,
@@ -656,12 +656,12 @@ bool clipboard_request_paste(struct clipboard *c, enum yasl_selection selection,
} else {
if (!c->device || !c->selection || !c->selection->mime) {
c->receive(NULL, 0, false, target, request_id,
- YASL_TRANSFER_UNAVAILABLE, c->ud);
+ YASL_PRIVATE_TRANSFER_UNAVAILABLE, c->ud);
return true;
}
if (pipe2(fds, O_CLOEXEC) < 0) {
c->receive(NULL, 0, false, target, request_id,
- YASL_TRANSFER_FAILED, c->ud);
+ YASL_PRIVATE_TRANSFER_FAILED, c->ud);
return true;
}
wl_data_offer_receive(c->selection->proxy, c->selection->mime, fds[1]);
@@ -670,7 +670,7 @@ bool clipboard_request_paste(struct clipboard *c, enum yasl_selection selection,
struct transfer *transfer = start_transfer_paste(c, fds[0], target, request_id);
if (!transfer) {
c->receive(NULL, 0, false, target, request_id,
- YASL_TRANSFER_FAILED, c->ud);
+ YASL_PRIVATE_TRANSFER_FAILED, c->ud);
return true;
}
if (wl_display_flush(c->display) < 0 && errno != EAGAIN)
diff --git a/src/platform/wayland/clipboard.h b/src/platform/wayland/clipboard.h
index 133cc14..d03df17 100644
--- a/src/platform/wayland/clipboard.h
+++ b/src/platform/wayland/clipboard.h
@@ -1,10 +1,10 @@
-#ifndef YASL_WAYLAND_CLIPBOARD_H
-#define YASL_WAYLAND_CLIPBOARD_H
+#ifndef YASL_PRIVATE_WAYLAND_CLIPBOARD_H
+#define YASL_PRIVATE_WAYLAND_CLIPBOARD_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
-#include "yasl/yasl.h"
+#include "common/types.h"
struct wl_display;
struct wl_data_device_manager;
@@ -16,27 +16,27 @@ struct zwp_primary_selection_device_manager_v1;
typedef void (*clipboard_receive_fn)(const char *, size_t, bool uri_list,
struct wl_surface *on, uint64_t request_id,
- enum yasl_transfer_status, void *);
+ enum yasl_private_transfer_status, void *);
struct clipboard *clipboard_create(struct wl_display *, struct wl_data_device_manager *,
- struct wl_seat *, struct yasl_loop *,
+ struct wl_seat *, struct yasl_private_loop *,
clipboard_receive_fn, void *);
void clipboard_destroy(struct clipboard *);
bool clipboard_set_seat(struct clipboard *, struct wl_seat *);
void clipboard_set_primary_manager(struct clipboard *, struct zwp_primary_selection_device_manager_v1 *);
bool clipboard_copy(struct clipboard *, const char *, uint32_t);
void clipboard_paste(struct clipboard *, struct wl_surface *target);
-bool clipboard_request_paste(struct clipboard *, enum yasl_selection,
+bool clipboard_request_paste(struct clipboard *, enum yasl_private_selection,
struct wl_surface *target, uint64_t request_id);
void clipboard_forget_surface(struct clipboard *, struct wl_surface *);
bool clipboard_copy_primary(struct clipboard *, const char *, uint32_t);
void clipboard_paste_primary(struct clipboard *, struct wl_surface *target);
-typedef void (*clipboard_drag_fn)(enum yasl_drag_event, struct wl_surface *on,
+typedef void (*clipboard_drag_fn)(enum yasl_private_drag_event, struct wl_surface *on,
double x, double y, void *);
void clipboard_set_drag_handler(struct clipboard *, clipboard_drag_fn, void *);
-typedef void (*clipboard_drop_fn)(enum yasl_drop_event, struct wl_surface *on,
+typedef void (*clipboard_drop_fn)(enum yasl_private_drop_event, struct wl_surface *on,
double x, double y, void *);
void clipboard_set_drop_handler(struct clipboard *, clipboard_drop_fn, void *);
const char *clipboard_drag_mime(void);
diff --git a/src/platform/wayland/drag.c b/src/platform/wayland/drag.c
index 1f4a78b..07e31b5 100644
--- a/src/platform/wayland/drag.c
+++ b/src/platform/wayland/drag.c
@@ -11,13 +11,13 @@ static void icon_clear(struct drag_icon *icon)
*icon = (struct drag_icon){0};
}
-static bool icon_create(struct wayland_display *c, const struct yasl_drag_image *image)
+static bool icon_create(struct wayland_display *c, const struct yasl_private_drag_image *image)
{
struct drag_icon *icon = &c->drag.icon;
size_t bytes;
if (!image->pixels || !buffer_size(image->size.x, image->size.y, &bytes))
return false;
- int fd = memfd_create("yasl_drag_icon", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ int fd = memfd_create("yasl_private_drag_icon", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd < 0)
return false;
void *mapping = MAP_FAILED;
@@ -48,7 +48,7 @@ static bool icon_create(struct wayland_display *c, const struct yasl_drag_image
return true;
}
-static void icon_show(struct wayland_display *c, const struct yasl_drag_image *image)
+static void icon_show(struct wayland_display *c, const struct yasl_private_drag_image *image)
{
struct drag_icon *icon = &c->drag.icon;
uint32_t scale = c->drag.scale_120;
@@ -56,18 +56,18 @@ static void icon_show(struct wayland_display *c, const struct yasl_drag_image *i
icon->viewport = wp_viewporter_get_viewport(c->viewporter, icon->surface);
if (icon->viewport)
wp_viewport_set_destination(icon->viewport,
- yasl_scale_to_logical(image->size.x, scale),
- yasl_scale_to_logical(image->size.y, scale));
- } else if (scale % YASL_SCALE_UNIT == 0 &&
+ yasl_private_scale_to_logical(image->size.x, scale),
+ yasl_private_scale_to_logical(image->size.y, scale));
+ } else if (scale % YASL_PRIVATE_SCALE_UNIT == 0 &&
wl_proxy_get_version((struct wl_proxy *)icon->surface) >=
WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION) {
- wl_surface_set_buffer_scale(icon->surface, (int32_t)(scale / YASL_SCALE_UNIT));
+ wl_surface_set_buffer_scale(icon->surface, (int32_t)(scale / YASL_PRIVATE_SCALE_UNIT));
}
if (wl_proxy_get_version((struct wl_proxy *)icon->surface) >=
WL_SURFACE_OFFSET_SINCE_VERSION)
wl_surface_offset(icon->surface,
- -yasl_scale_to_logical(image->hotspot.x, scale),
- -yasl_scale_to_logical(image->hotspot.y, scale));
+ -yasl_private_scale_to_logical(image->hotspot.x, scale),
+ -yasl_private_scale_to_logical(image->hotspot.y, scale));
wl_surface_attach(icon->surface, icon->buffer, 0, 0);
wl_surface_damage_buffer(icon->surface, 0, 0, image->size.x, image->size.y);
wl_surface_commit(icon->surface);
@@ -88,9 +88,9 @@ static void drag_clear(struct wayland_display *c, bool ended)
*d = (struct conn_drag){0};
}
-static void drag_finish(struct wayland_display *c, enum yasl_drag_end how, bool ended)
+static void drag_finish(struct wayland_display *c, enum yasl_private_drag_end how, bool ended)
{
- struct yasl_drag_listener l = c->drag.listener;
+ struct yasl_private_drag_listener l = c->drag.listener;
void *ud = c->drag.ud;
drag_clear(c, ended);
if (l.end)
@@ -100,7 +100,7 @@ static void drag_finish(struct wayland_display *c, enum yasl_drag_end how, bool
void conn_drag_end(struct wayland_display *c)
{
if (c && c->drag.source)
- drag_finish(c, YASL_DRAG_CANCELLED, false);
+ drag_finish(c, YASL_PRIVATE_DRAG_CANCELLED, false);
}
static void source_target(void *ud, struct wl_data_source *s, const char *mime) { (void)ud; (void)s; (void)mime; }
@@ -112,7 +112,7 @@ static void source_cancelled(void *ud, struct wl_data_source *s)
(void)s;
struct wayland_display *c = ud;
bool released = c->drag.dropped;
- drag_finish(c, released ? YASL_DRAG_DROPPED : YASL_DRAG_CANCELLED, true);
+ drag_finish(c, released ? YASL_PRIVATE_DRAG_DROPPED : YASL_PRIVATE_DRAG_CANCELLED, true);
}
static void source_dropped(void *ud, struct wl_data_source *s)
@@ -124,7 +124,7 @@ static void source_dropped(void *ud, struct wl_data_source *s)
static void source_finished(void *ud, struct wl_data_source *s)
{
(void)s;
- drag_finish(ud, YASL_DRAG_DROPPED, true);
+ drag_finish(ud, YASL_PRIVATE_DRAG_DROPPED, true);
}
static const struct wl_data_source_listener source_listener = {
@@ -150,8 +150,8 @@ static struct seat *drag_seat(struct wayland_display *c, struct wayland_surface
}
bool wayland_display_drag_start(struct wayland_display *c, struct wayland_surface *origin,
- const struct yasl_drag_image *image,
- const struct yasl_drag_listener *l, void *ud)
+ const struct yasl_private_drag_image *image,
+ const struct yasl_private_drag_listener *l, void *ud)
{
if (!c || !origin || origin->conn != c || !l || c->drag.source)
return false;
@@ -190,39 +190,39 @@ bool wayland_display_drag_start(struct wayland_display *c, struct wayland_surfac
void wayland_display_drag_cancel(struct wayland_display *c)
{
if (c && c->drag.source)
- drag_finish(c, YASL_DRAG_CANCELLED, false);
+ drag_finish(c, YASL_PRIVATE_DRAG_CANCELLED, false);
}
-bool wayland_surface_drag_carry(struct wayland_surface *w, struct yasl_vector2i offset)
+bool wayland_surface_drag_carry(struct wayland_surface *w, struct yasl_private_vector2i offset)
{
struct wayland_display *c = w ? w->conn : NULL;
if (!c || !c->drag.source || !c->drag.toplevel || !w->toplevel)
return false;
uint32_t scale = c->drag.scale_120;
xdg_toplevel_drag_v1_attach(c->drag.toplevel, w->toplevel,
- yasl_scale_to_logical(offset.x, scale),
- yasl_scale_to_logical(offset.y, scale));
+ yasl_private_scale_to_logical(offset.x, scale),
+ yasl_private_scale_to_logical(offset.y, scale));
c->drag.carrying = true;
return true;
}
-bool wayland_surface_place_under_pointer(struct wayland_surface *w, struct yasl_vector2i at)
+bool wayland_surface_place_under_pointer(struct wayland_surface *w, struct yasl_private_vector2i at)
{
(void)w;
(void)at;
return false;
}
-static struct yasl_vector2i drag_device_pos(const struct wayland_surface *w, double x, double y)
+static struct yasl_private_vector2i drag_device_pos(const struct wayland_surface *w, double x, double y)
{
double dx = x * w->scale_factor, dy = y * w->scale_factor;
- return (struct yasl_vector2i){
+ return (struct yasl_private_vector2i){
.x = (int)(dx < 0 ? dx - 0.5 : dx + 0.5),
.y = (int)(dy < 0 ? dy - 0.5 : dy + 0.5),
};
}
-void conn_drop_target(struct wayland_display *c, enum yasl_drop_event ev,
+void conn_drop_target(struct wayland_display *c, enum yasl_private_drop_event ev,
struct wl_surface *on, double x, double y)
{
(void)c;
@@ -230,10 +230,10 @@ void conn_drop_target(struct wayland_display *c, enum yasl_drop_event ev,
(struct wayland_surface *)wl_surface_get_user_data(on) : NULL;
if (!w || w->parent || w->closed)
return;
- yasl_surface_notify_drop(&w->base, ev, drag_device_pos(w, x, y));
+ yasl_private_surface_notify_drop(&w->base, ev, drag_device_pos(w, x, y));
}
-void conn_drag_target(struct wayland_display *c, enum yasl_drag_event ev,
+void conn_drag_target(struct wayland_display *c, enum yasl_private_drag_event ev,
struct wl_surface *on, double x, double y)
{
(void)c;
@@ -241,5 +241,5 @@ void conn_drag_target(struct wayland_display *c, enum yasl_drag_event ev,
(struct wayland_surface *)wl_surface_get_user_data(on) : NULL;
if (!w || w->parent || w->closed)
return;
- yasl_surface_notify_drag(&w->base, ev, drag_device_pos(w, x, y));
+ yasl_private_surface_notify_drag(&w->base, ev, drag_device_pos(w, x, y));
}
diff --git a/src/platform/wayland/ime.c b/src/platform/wayland/ime.c
index 4a091d8..62e5936 100644
--- a/src/platform/wayland/ime.c
+++ b/src/platform/wayland/ime.c
@@ -1,5 +1,7 @@
#include "internal.h"
+#include <errno.h>
+
#define IME_TEXT_MAX (256u * 1024)
static void show_preedit(struct wayland_surface *w, char *text, int begin, int end)
@@ -12,7 +14,7 @@ static void show_preedit(struct wayland_surface *w, char *text, int begin, int e
w->ime_shown_begin = begin;
w->ime_shown_end = end;
if (changed) {
- yasl_surface_notify_composition(&w->base, w->ime_shown,
+ yasl_private_surface_notify_composition(&w->base, w->ime_shown,
w->ime_shown_begin, w->ime_shown_end);
wayland_surface_schedule_redraw(w);
}
@@ -24,21 +26,63 @@ void ime_reset(struct wayland_surface *w)
w->ime_preedit = NULL;
free(w->ime_commit);
w->ime_commit = NULL;
+ w->ime_delete_pending = false;
show_preedit(w, NULL, -1, -1);
}
void ime_send_caret(struct wayland_surface *w)
{
+ wayland_surface_update_text_input(w);
+}
+
+bool wayland_surface_update_text_input(struct wayland_surface *w)
+{
+ if (!w || !w->conn) {
+ errno = EINVAL;
+ return false;
+ }
+ if (!w->conn->text_input_mgr) {
+ errno = ENOTSUP;
+ return false;
+ }
struct seat *seat = w->ime_seat;
- if (!seat || !seat->text_input)
- return;
- uint32_t scale = w->scale_120 ? w->scale_120 : YASL_SCALE_UNIT;
+ if (!seat || !seat->text_input || seat->ime_focus != w)
+ return true;
+ if (!w->base.text_input_active) {
+ if (seat->ime_enabled) {
+ zwp_text_input_v3_disable(seat->text_input);
+ zwp_text_input_v3_commit(seat->text_input);
+ seat->ime_enabled = false;
+ }
+ ime_reset(w);
+ return true;
+ }
+ if (!seat->ime_enabled) {
+ zwp_text_input_v3_enable(seat->text_input);
+ seat->ime_enabled = true;
+ }
+ unsigned purpose = w->base.text_purpose;
+ if (purpose > ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL)
+ purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL;
+ zwp_text_input_v3_set_content_type(seat->text_input,
+ ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, purpose);
+ const char *surrounding = w->base.text_surrounding ? w->base.text_surrounding : "";
+ size_t length = w->base.text_surrounding ? w->base.text_length : 0;
+ size_t cursor = w->base.text_surrounding ? w->base.text_end : 0;
+ size_t anchor = w->base.text_surrounding ? w->base.text_begin : 0;
+ if (cursor > length) cursor = length;
+ if (anchor > length) anchor = length;
+ if (length <= INT32_MAX && cursor <= INT32_MAX && anchor <= INT32_MAX)
+ zwp_text_input_v3_set_surrounding_text(seat->text_input, surrounding,
+ (int32_t)cursor, (int32_t)anchor);
+ uint32_t scale = w->scale_120 ? w->scale_120 : YASL_PRIVATE_SCALE_UNIT;
zwp_text_input_v3_set_cursor_rectangle(seat->text_input,
- yasl_scale_to_logical(w->ime_caret.x, scale),
- yasl_scale_to_logical(w->ime_caret.y, scale),
- yasl_scale_to_logical(w->ime_caret.width, scale),
- yasl_scale_to_logical(w->ime_caret.height, scale));
+ yasl_private_scale_to_logical(w->ime_caret.x, scale),
+ yasl_private_scale_to_logical(w->ime_caret.y, scale),
+ yasl_private_scale_to_logical(w->ime_caret.width, scale),
+ yasl_private_scale_to_logical(w->ime_caret.height, scale));
zwp_text_input_v3_commit(seat->text_input);
+ return true;
}
bool wayland_surface_ime_preedit_cursor(const struct wayland_surface *w, int *begin, int *end)
@@ -50,7 +94,7 @@ bool wayland_surface_ime_preedit_cursor(const struct wayland_surface *w, int *be
return true;
}
-void wayland_surface_set_ime_caret(struct wayland_surface *w, struct yasl_rect2i caret)
+void wayland_surface_set_ime_caret(struct wayland_surface *w, struct yasl_private_rect2i caret)
{
if (!w || (w->ime_caret.x == caret.x && w->ime_caret.y == caret.y &&
w->ime_caret.width == caret.width && w->ime_caret.height == caret.height))
@@ -62,17 +106,14 @@ void wayland_surface_set_ime_caret(struct wayland_surface *w, struct yasl_rect2i
static void text_input_enter(void *data, struct zwp_text_input_v3 *text_input,
struct wl_surface *surface)
{
+ (void)text_input;
struct seat *s = data;
struct wayland_surface *w = surface_root(surface ?
(struct wayland_surface *)wl_surface_get_user_data(surface) : NULL);
s->ime_focus = w;
if (!w) return;
- zwp_text_input_v3_enable(text_input);
- zwp_text_input_v3_set_content_type(text_input,
- ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
- ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL);
w->ime_seat = s;
- ime_send_caret(w);
+ wayland_surface_update_text_input(w);
}
static void text_input_leave(void *data, struct zwp_text_input_v3 *text_input,
@@ -83,8 +124,11 @@ static void text_input_leave(void *data, struct zwp_text_input_v3 *text_input,
struct wayland_surface *w = s->ime_focus;
s->ime_focus = NULL;
if (!w) return;
- zwp_text_input_v3_disable(text_input);
- zwp_text_input_v3_commit(text_input);
+ if (s->ime_enabled) {
+ zwp_text_input_v3_disable(text_input);
+ zwp_text_input_v3_commit(text_input);
+ s->ime_enabled = false;
+ }
if (w->ime_seat == s)
w->ime_seat = NULL;
ime_reset(w);
@@ -110,7 +154,7 @@ static void text_input_preedit_string(void *data,
{
(void)text_input;
struct wayland_surface *w = ((struct seat *)data)->ime_focus;
- if (!w) return;
+ if (!w || !w->base.text_input_active) return;
keyboard_text_reset((struct seat *)data);
free(w->ime_preedit);
w->ime_preedit = text ? copy_text(text) : NULL;
@@ -126,7 +170,7 @@ static void text_input_commit_string(void *data,
{
(void)text_input;
struct wayland_surface *w = ((struct seat *)data)->ime_focus;
- if (!w) return;
+ if (!w || !w->base.text_input_active) return;
keyboard_text_reset((struct seat *)data);
free(w->ime_commit);
w->ime_commit = (text && text[0]) ? copy_text(text) : NULL;
@@ -136,7 +180,31 @@ static void text_input_delete_surrounding_text(void *data,
struct zwp_text_input_v3 *text_input, uint32_t before_length,
uint32_t after_length)
{
- (void)data; (void)text_input; (void)before_length; (void)after_length;
+ (void)text_input;
+ struct seat *seat = data;
+ struct wayland_surface *w = seat->ime_focus;
+ if (!w || !w->base.text_input_active || !w->base.text_surrounding)
+ return;
+ size_t length = w->base.text_length;
+ size_t cursor = w->base.text_end <= length ? w->base.text_end : length;
+ while (cursor && cursor < length &&
+ (((unsigned char)w->base.text_surrounding[cursor] & 0xc0) == 0x80))
+ cursor--;
+ size_t begin = before_length > cursor ? 0 : cursor - before_length;
+ size_t end = after_length > length - cursor ? length : cursor + after_length;
+ while (begin && begin < length &&
+ (((unsigned char)w->base.text_surrounding[begin] & 0xc0) == 0x80))
+ begin--;
+ while (end < length && (((unsigned char)w->base.text_surrounding[end] & 0xc0) == 0x80))
+ end++;
+ /* text_input_v3 batches deletion and commit into one `done` group. Keep
+ * the replacement range paired with that group's committed text and
+ * enqueue both together below, preserving snapshot metadata. */
+ w->ime_delete_pending = true;
+ w->ime_delete_begin = begin;
+ w->ime_delete_end = end;
+ w->ime_delete_revision = w->base.text_revision;
+ w->ime_delete_generation = w->base.text_generation;
}
static void text_input_done(void *data, struct zwp_text_input_v3 *text_input,
@@ -144,17 +212,46 @@ static void text_input_done(void *data, struct zwp_text_input_v3 *text_input,
{
(void)text_input; (void)serial;
struct wayland_surface *w = ((struct seat *)data)->ime_focus;
- if (!w) return;
- if (w->ime_commit) {
- struct yasl_event ev = {
- .type = YASL_EVENT_TEXT,
+ if (!w || !w->base.text_input_active) return;
+ bool has_snapshot = w->base.text_surrounding != NULL &&
+ w->base.text_length <= INT32_MAX;
+ bool has_commit = w->ime_commit && w->ime_commit[0];
+ bool edit = w->ime_delete_pending || (has_commit && has_snapshot);
+ if (edit) {
+ size_t begin = w->ime_delete_pending ? w->ime_delete_begin : w->base.text_begin;
+ size_t end = w->ime_delete_pending ? w->ime_delete_end : w->base.text_end;
+ if (begin > w->base.text_length) begin = w->base.text_length;
+ if (end > w->base.text_length) end = w->base.text_length;
+ if (end < begin) end = begin;
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_TEXT_EDIT,
+ .surface = &w->base,
+ .text_edit = {
+ .data = has_commit ? w->ime_commit : "",
+ .len = has_commit ? strlen(w->ime_commit) : 0,
+ .revision = w->ime_delete_revision,
+ .generation = w->ime_delete_generation,
+ .begin = begin,
+ .end = end,
+ },
+ };
+ if (!w->ime_delete_pending) {
+ ev.text_edit.revision = w->base.text_revision;
+ ev.text_edit.generation = w->base.text_generation;
+ }
+ input_queue_push(&w->input, &ev);
+ w->ime_delete_pending = false;
+ }
+ if (w->ime_commit && !edit) {
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_TEXT,
.surface = &w->base,
.text = { .data = w->ime_commit, .len = strlen(w->ime_commit) },
};
input_queue_push(&w->input, &ev);
- free(w->ime_commit);
- w->ime_commit = NULL;
}
+ free(w->ime_commit);
+ w->ime_commit = NULL;
char *preedit = w->ime_preedit && w->ime_preedit[0] ? w->ime_preedit : NULL;
if (!preedit)
free(w->ime_preedit);
diff --git a/src/platform/wayland/internal.h b/src/platform/wayland/internal.h
index 34d4133..a479e2b 100644
--- a/src/platform/wayland/internal.h
+++ b/src/platform/wayland/internal.h
@@ -1,5 +1,5 @@
-#ifndef YASL_WAYLAND_INTERNAL_H
-#define YASL_WAYLAND_INTERNAL_H
+#ifndef YASL_PRIVATE_WAYLAND_INTERNAL_H
+#define YASL_PRIVATE_WAYLAND_INTERNAL_H
#define _GNU_SOURCE
@@ -10,6 +10,11 @@
#include <wayland-client.h>
#include <wayland-cursor.h>
+#if YASL_HAS_EGL
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <wayland-egl.h>
+#endif
#include "protocols/xdg-shell-client-protocol.h"
#include "protocols/xdg-decoration-client-protocol.h"
#include "protocols/cursor-shape-v1-client-protocol.h"
@@ -73,7 +78,7 @@ struct wl_conn_output {
struct pending_press {
struct wayland_surface *surface;
- struct yasl_vector2i pos;
+ struct yasl_private_vector2i pos;
int button;
bool release;
};
@@ -105,7 +110,7 @@ struct conn_drag {
struct wl_data_source *source;
struct xdg_toplevel_drag_v1 *toplevel;
struct drag_icon icon;
- struct yasl_drag_listener listener;
+ struct yasl_private_drag_listener listener;
void *ud;
struct seat *seat;
uint32_t scale_120;
@@ -160,15 +165,20 @@ struct seat {
uint64_t pointer_buttons;
uint64_t tool_buttons;
double axis[2], axis_value120[2];
+ double axis_pixels[2];
int64_t axis_discrete[2];
+ uint32_t axis_source;
+ bool scroll_gesture, axis_stop_pending;
+ unsigned axis_phase;
+ bool ime_enabled;
bool axis_has_value120[2], axis_has_discrete[2];
double touch_scroll_y;
/* Embedded structs */
xkb_mod_mask_t input_mod_masks[8];
- struct yasl_vector2i pointer_pos;
- struct yasl_vector2i ptr_left_pos;
- struct yasl_vector2i tool_pos;
+ struct yasl_private_vector2i pointer_pos;
+ struct yasl_private_vector2i ptr_left_pos;
+ struct yasl_private_vector2i tool_pos;
struct touch_point touch_points[SEAT_TOUCH_POINTS];
struct press_queue ptr_presses;
struct press_queue tool_presses;
@@ -183,7 +193,7 @@ struct seat {
uint32_t press_serial;
uint32_t pointer_serial;
int cursor_shape;
- struct yasl_pointer_pen pen;
+ struct yasl_private_pointer_pen pen;
int tool_wheel;
/* 1-byte booleans grouped tightly */
@@ -199,9 +209,14 @@ struct seat {
#include "common/input.h"
struct wayland_display {
- struct yasl_display base;
+ struct yasl_private_display base;
/* 8-byte pointers & 64-bit masks */
struct wl_display *wl;
+#if YASL_HAS_EGL
+ EGLDisplay egl_display;
+ EGLint egl_api;
+ bool egl_initialized;
+#endif
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shm *shm;
@@ -228,8 +243,8 @@ struct wayland_display {
struct wp_fifo_manager_v1 *fifo_mgr;
struct wp_commit_timing_manager_v1 *commit_timing_mgr;
struct xkb_context *xkb_ctx;
- struct yasl_loop *loop;
- const struct yasl_display_cbs *cbs;
+ struct yasl_private_loop *loop;
+ const struct yasl_private_display_cbs *cbs;
void *ud;
char *app_id;
struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr;
@@ -243,6 +258,7 @@ struct wayland_display {
clockid_t pres_clock;
int watch;
int depth;
+ uint64_t next_tool_id;
/* 1-byte booleans */
bool owns_loop;
@@ -266,6 +282,12 @@ struct wayland_surface {
struct wayland_surface *dead_next;
struct wayland_surface *parent;
struct wl_surface *surface;
+#if YASL_HAS_EGL
+ struct wl_egl_window *egl_window;
+ EGLSurface egl_surface;
+ EGLContext egl_context;
+ EGLConfig egl_config;
+#endif
struct xdg_surface *xdg_surface;
struct xdg_toplevel *toplevel;
struct xdg_popup *popup;
@@ -276,6 +298,8 @@ struct wayland_surface {
char *ime_commit;
char *ime_shown;
struct seat *ime_seat;
+ size_t ime_delete_begin, ime_delete_end;
+ uint64_t ime_delete_revision, ime_delete_generation;
struct wp_tearing_control_v1 *tearing_control;
struct latency_feedback *latency_feedbacks;
struct latency_feedback latency_pool[8];
@@ -285,24 +309,24 @@ struct wayland_surface {
/* Persistent lock held while relative; lock_seat owns the locked wl_pointer. */
struct zwp_locked_pointer_v1 *pointer_lock;
struct seat *lock_seat;
- const struct yasl_window_cbs *cbs;
+ const struct yasl_private_window_cbs *cbs;
void *ud;
uint64_t frames_skipped;
uint64_t outputs;
double scale_factor;
/* Sub-structures */
- struct yasl_rect2i ime_caret;
- struct yasl_rect2i content;
- struct yasl_frame_clock clock;
+ struct yasl_private_rect2i ime_caret;
+ struct yasl_private_rect2i content;
+ struct yasl_private_frame_clock clock;
struct buffer buffers[NBUF];
- struct yasl_frame frame;
- struct yasl_damage_list damage;
+ struct yasl_private_frame frame;
+ struct yasl_private_damage_list damage;
int ime_cursor_begin;
struct input_queue input;
/* 4-byte integers */
- enum yasl_cursor cursor;
+ enum yasl_private_cursor cursor;
int ime_cursor_end;
int ime_shown_begin, ime_shown_end;
int floating_width, floating_height;
@@ -331,6 +355,7 @@ struct wayland_surface {
bool want_draw;
bool relative;
bool pointer_locked;
+ bool ime_delete_pending;
};
@@ -343,7 +368,7 @@ int buffer_prepare(struct wayland_surface *w, struct buffer *b, int width, int
const struct wl_buffer_listener *listener);
int apply_pending_geometry(struct wayland_surface *w);
-static inline void wl_damage_list(struct wl_surface *s, const struct yasl_damage_list *d)
+static inline void wl_damage_list(struct wl_surface *s, const struct yasl_private_damage_list *d)
{
if (d->n < 0) {
wl_surface_damage_buffer(s, d->bounds.x, d->bounds.y,
@@ -365,6 +390,7 @@ void surface_follow_outputs(struct wayland_surface *w);
uint64_t conn_pres_to_mono(const struct wayland_display *c, uint64_t ns);
uint64_t conn_mono_to_pres(const struct wayland_display *c, uint64_t ns);
void surface_draw_frame(struct wayland_surface *w);
+void wayland_surface_arm_frame(struct wayland_surface *w);
void surface_fail(struct wayland_surface *w);
void display_leave(struct wayland_display *c);
@@ -376,9 +402,9 @@ static inline struct wayland_surface *surface_root(struct wayland_surface *w)
}
void conn_drag_end(struct wayland_display *c);
-void conn_drop_target(struct wayland_display *c, enum yasl_drop_event ev,
+void conn_drop_target(struct wayland_display *c, enum yasl_private_drop_event ev,
struct wl_surface *on, double x, double y);
-void conn_drag_target(struct wayland_display *c, enum yasl_drag_event ev,
+void conn_drag_target(struct wayland_display *c, enum yasl_private_drag_event ev,
struct wl_surface *on, double x, double y);
void seat_bind(struct wayland_display *c, struct wl_registry *registry,
@@ -386,6 +412,7 @@ void seat_bind(struct wayland_display *c, struct wl_registry *registry,
bool seat_remove(struct wayland_display *c, uint32_t name);
void seat_destroy(struct seat *s);
void seat_note_input(struct seat *s, uint32_t serial);
+void seat_ensure_text_input(struct seat *s);
void seat_forget_surface(struct seat *s, struct wayland_surface *w);
void seat_clipboard_ensure(struct seat *s);
int display_input_init(struct wayland_display *c);
@@ -409,6 +436,7 @@ extern const struct zwp_text_input_v3_listener text_input_listener;
void ime_reset(struct wayland_surface *w);
void keyboard_text_reset(struct seat *s);
void ime_send_caret(struct wayland_surface *w);
+bool wayland_surface_update_text_input(struct wayland_surface *w);
int surface_init_shell(struct wayland_surface *w, const char *title);
extern const struct xdg_surface_listener shell_surface_listener;
diff --git a/src/platform/wayland/keyboard.c b/src/platform/wayland/keyboard.c
index 7f8274d..6f9dec9 100644
--- a/src/platform/wayland/keyboard.c
+++ b/src/platform/wayland/keyboard.c
@@ -133,8 +133,8 @@ bool conn_keyboard_on(const struct wayland_display *c, const struct wayland_surf
static void push_focus(struct wayland_surface *w, bool focused)
{
- struct yasl_event ev = {
- .type = YASL_EVENT_FOCUS,
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_FOCUS,
.surface = &w->base,
.focus = { .focused = focused },
};
@@ -218,18 +218,18 @@ static uint32_t key_codepoint_at_level(struct seat *s, uint32_t key, xkb_layout_
return n == 1 ? xkb_keysym_to_utf32(syms[0]) : 0;
}
-static struct yasl_key_event xkb_key_event(struct seat *s, uint32_t key,
+static struct yasl_private_key_event xkb_key_event(struct seat *s, uint32_t key,
enum yasl_key_action action)
{
uint32_t code = key + XKB_EVDEV_OFFSET;
xkb_layout_index_t layout = xkb_state_key_get_layout(s->xkb_state, code);
- struct yasl_key_event k = {
- .key = yasl_key_from_evdev(key),
+ struct yasl_private_key_event k = {
+ .key = yasl_private_key_from_evdev(key),
.action = action,
.mods = input_modifiers(s),
- .codepoint = yasl_key_label(key_codepoint_at_level(s, key, layout, 0)),
- .shifted = yasl_key_label(key_codepoint_at_level(s, key, layout, 1)),
+ .codepoint = yasl_private_key_label(key_codepoint_at_level(s, key, layout, 0)),
+ .shifted = yasl_private_key_label(key_codepoint_at_level(s, key, layout, 1)),
.native_code = key,
};
return k;
@@ -239,8 +239,8 @@ static void keyboard_text(struct seat *s, struct wayland_surface *w, uint32_t ke
{
uint32_t code = key + XKB_EVDEV_OFFSET;
unsigned mods = input_modifiers(s);
- if ((mods & (YASL_MOD_CTRL | YASL_MOD_SUPER)) ||
- ((mods & YASL_MOD_ALT) &&
+ if ((mods & (YASL_PRIVATE_MOD_CTRL | YASL_PRIVATE_MOD_SUPER)) ||
+ ((mods & YASL_PRIVATE_MOD_ALT) &&
!xkb_state_mod_index_is_consumed(s->xkb_state, code, s->mod_alt))) {
keyboard_text_reset(s);
return;
@@ -278,13 +278,13 @@ static void keyboard_text(struct seat *s, struct wayland_surface *w, uint32_t ke
else xkb_state_key_get_utf8(s->xkb_state, code, text, (size_t)len + 1);
/* Editing commands belong to key events, not text insertion. */
if ((unsigned char)text[0] >= 0x20 && text[0] != 0x7f) {
- struct yasl_event ev = {.type = YASL_EVENT_TEXT,
+ struct yasl_private_event ev = {.type = YASL_PRIVATE_EVENT_TEXT,
.surface = &w->base, .text = {.data = text, .len = (size_t)len}};
input_queue_push(&w->input, &ev);
}
if (text != local) free(text);
} else {
- struct yasl_event ev = {.type = YASL_EVENT_INPUT_RESET, .surface = &w->base};
+ struct yasl_private_event ev = {.type = YASL_PRIVATE_EVENT_INPUT_RESET, .surface = &w->base};
input_queue_push(&w->input, &ev);
}
}
@@ -296,9 +296,9 @@ static bool keyboard_dispatch_key(struct seat *s, struct wayland_surface *w, uin
{
if (!s->xkb_state || !w->cbs) return false;
- struct yasl_key_event k = xkb_key_event(s, key, action);
- struct yasl_event ev = {
- .type = YASL_EVENT_KEY,
+ struct yasl_private_key_event k = xkb_key_event(s, key, action);
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_KEY,
.surface = &w->base,
.key = k,
};
@@ -329,7 +329,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
if (keyboard_dispatch_key(s, w, key, YASL_KEY_PRESS) && repeatable) {
s->repeat_key = key;
s->repeat_held = true;
- s->repeat_started_ns = yasl_loop_now_ns();
+ s->repeat_started_ns = yasl_private_loop_now_ns();
keyboard_repeat_sync(s);
}
}
@@ -389,7 +389,7 @@ int keyboard_repeat_init(struct seat *s)
if (s->repeat_fd >= 0) return 0;
s->repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (s->repeat_fd < 0) return -1;
- s->repeat_watch = yasl_loop_add_fd(s->conn->loop, s->repeat_fd, POLLIN,
+ s->repeat_watch = yasl_private_loop_add_fd(s->conn->loop, s->repeat_fd, POLLIN,
keyboard_repeat_ready, s);
if (s->repeat_watch <= 0) {
s->repeat_watch = 0;
@@ -406,18 +406,18 @@ int seat_modifiers(const struct seat *s)
if (unlikely(!s || !s->xkb_state)) return 0;
return ((s->mod_shift != XKB_MOD_INVALID &&
xkb_state_mod_index_is_active(s->xkb_state, s->mod_shift,
- XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_SHIFT) |
+ XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_SHIFT) |
((s->mod_alt != XKB_MOD_INVALID &&
xkb_state_mod_index_is_active(s->xkb_state, s->mod_alt,
- XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_ALT) |
+ XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_ALT) |
((s->mod_ctrl != XKB_MOD_INVALID &&
xkb_state_mod_index_is_active(s->xkb_state, s->mod_ctrl,
- XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_CTRL) |
+ XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_CTRL) |
((s->mod_super != XKB_MOD_INVALID &&
xkb_state_mod_index_is_active(s->xkb_state, s->mod_super,
- XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_SUPER) |
+ XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_SUPER) |
((xkb_state_mod_name_is_active(s->xkb_state, XKB_MOD_NAME_CAPS,
- XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_MOD_CAPS);
+ XKB_STATE_MODS_EFFECTIVE) > 0) * YASL_PRIVATE_MOD_CAPS);
}
int wayland_display_modifiers(const struct wayland_display *c)
@@ -425,12 +425,12 @@ int wayland_display_modifiers(const struct wayland_display *c)
return c ? seat_modifiers(c->active_seat ? c->active_seat : c->seats) : 0;
}
-void wayland_display_copy(struct wayland_display *c, enum yasl_selection sel, const char *text)
+void wayland_display_copy(struct wayland_display *c, enum yasl_private_selection sel, const char *text)
{
(void)wayland_display_copy_text(c, sel, text);
}
-bool wayland_display_copy_text(struct wayland_display *c, enum yasl_selection sel,
+bool wayland_display_copy_text(struct wayland_display *c, enum yasl_private_selection sel,
const char *text)
{
struct seat *s = c ? (c->active_seat ? c->active_seat : c->seats) : NULL;
@@ -447,28 +447,28 @@ bool wayland_display_copy_text(struct wayland_display *c, enum yasl_selection se
return false;
}
errno = 0;
- bool ok = sel == YASL_PRIMARY ?
+ bool ok = sel == YASL_PRIVATE_PRIMARY ?
clipboard_copy_primary(s->clipboard, text, s->input_serial) :
clipboard_copy(s->clipboard, text, s->input_serial);
return ok;
}
-void wayland_display_paste(struct wayland_display *c, enum yasl_selection sel, struct wayland_surface *target)
+void wayland_display_paste(struct wayland_display *c, enum yasl_private_selection sel, struct wayland_surface *target)
{
struct seat *s = c ? (c->active_seat ? c->active_seat : c->seats) : NULL;
if (!target || target->closed || target->destroyed) return;
if (!s || !s->clipboard) {
- yasl_surface_complete_paste(&target->base, 0,
- YASL_TRANSFER_UNAVAILABLE, NULL, 0);
+ yasl_private_surface_complete_paste(&target->base, 0,
+ YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0);
return;
}
- if (sel == YASL_PRIMARY)
+ if (sel == YASL_PRIVATE_PRIMARY)
clipboard_paste_primary(s->clipboard, target->surface);
else
clipboard_paste(s->clipboard, target->surface);
}
-bool wayland_display_request_paste(struct wayland_display *c, enum yasl_selection sel,
+bool wayland_display_request_paste(struct wayland_display *c, enum yasl_private_selection sel,
struct wayland_surface *target, uint64_t request_id)
{
struct seat *s = c ? (c->active_seat ? c->active_seat : c->seats) : NULL;
@@ -486,7 +486,7 @@ bool wayland_display_request_paste(struct wayland_display *c, enum yasl_selectio
return ok;
}
-bool wayland_surface_poll_event(struct wayland_surface *w, struct yasl_event *ev)
+bool wayland_surface_poll_event(struct wayland_surface *w, struct yasl_private_event *ev)
{
return w && ev && input_queue_pop(&w->input, ev);
}
diff --git a/src/platform/wayland/keymap.c b/src/platform/wayland/keymap.c
index d626f30..6c3b4dd 100644
--- a/src/platform/wayland/keymap.c
+++ b/src/platform/wayland/keymap.c
@@ -1,7 +1,7 @@
#include "keymap.h"
/* Numeric Linux evdev codes; no platform headers are needed by this table. */
-enum yasl_key yasl_key_from_evdev(uint32_t code)
+enum yasl_key yasl_private_key_from_evdev(uint32_t code)
{
switch (code) {
case 1: return YASL_KEY_ESCAPE; /* KEY_ESC */
diff --git a/src/platform/wayland/keymap.h b/src/platform/wayland/keymap.h
index c0ff81e..26b6ed4 100644
--- a/src/platform/wayland/keymap.h
+++ b/src/platform/wayland/keymap.h
@@ -1,8 +1,8 @@
-#ifndef YASL_WAYLAND_KEYMAP_H
-#define YASL_WAYLAND_KEYMAP_H
+#ifndef YASL_PRIVATE_WAYLAND_KEYMAP_H
+#define YASL_PRIVATE_WAYLAND_KEYMAP_H
#include "yasl/keycodes.h"
-enum yasl_key yasl_key_from_evdev(uint32_t code);
+enum yasl_key yasl_private_key_from_evdev(uint32_t code);
#endif
diff --git a/src/platform/wayland/native.c b/src/platform/wayland/native.c
index 55ce445..54ca184 100644
--- a/src/platform/wayland/native.c
+++ b/src/platform/wayland/native.c
@@ -1,14 +1,14 @@
#include "common/backend.h"
-#include "yasl/native/wayland.h"
+#include "common/private_native_wayland.h"
-struct wl_display *yasl_wayland_display_get_wl_display(struct yasl_display *d)
+struct wl_display *yasl_private_wayland_display_get_wl_display(struct yasl_private_display *d)
{
- return (d && yasl_display_backend(d) == YASL_BACKEND_WAYLAND) ?
- (struct wl_display *)yasl_display_get_native_handle(d) : NULL;
+ return (d && yasl_private_display_backend(d) == YASL_PRIVATE_BACKEND_WAYLAND) ?
+ (struct wl_display *)yasl_private_display_get_native_handle(d) : NULL;
}
-struct wl_surface *yasl_wayland_surface_get_wl_surface(struct yasl_surface *s)
+struct wl_surface *yasl_private_wayland_surface_get_wl_surface(struct yasl_surface *s)
{
- return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_WAYLAND) ?
- (struct wl_surface *)yasl_surface_get_native_handle(s) : NULL;
+ return (s && s->display && yasl_private_display_backend(s->display) == YASL_PRIVATE_BACKEND_WAYLAND) ?
+ (struct wl_surface *)yasl_private_surface_get_native_handle(s) : NULL;
}
diff --git a/src/platform/wayland/pointer.c b/src/platform/wayland/pointer.c
index da666da..5f486ae 100644
--- a/src/platform/wayland/pointer.c
+++ b/src/platform/wayland/pointer.c
@@ -12,12 +12,22 @@ struct tablet_tool {
struct zwp_tablet_tool_v2 *proxy;
struct wp_cursor_shape_device_v1 *shape_dev;
uint32_t proximity_serial;
+ uint64_t device_id, tool_id;
+ uint32_t axes_valid, axes_changed, capability_mask;
+ double x, y;
+ double pressure, tilt_x, tilt_y, rotation, distance, tangential, wheel_degrees;
+ unsigned changed_button;
+ unsigned pending_actions[8], pending_buttons[8], pending_action_count;
+ bool pending_contacts[8];
+ unsigned kind;
+ bool in_contact, pen_in_proximity;
bool eraser;
};
struct tablet_device {
struct tablet_device *next;
struct zwp_tablet_v2 *proxy;
+ uint64_t id;
};
struct tablet_pad {
@@ -25,10 +35,10 @@ struct tablet_pad {
struct zwp_tablet_pad_v2 *proxy;
};
-static struct yasl_vector2i device_from_fixed(const struct wayland_surface *w,
+static struct yasl_private_vector2i device_from_fixed(const struct wayland_surface *w,
wl_fixed_t x, wl_fixed_t y)
{
- return (struct yasl_vector2i){
+ return (struct yasl_private_vector2i){
.x = (int)lrint(wl_fixed_to_double(x) * w->scale_factor),
.y = (int)lrint(wl_fixed_to_double(y) * w->scale_factor),
};
@@ -41,10 +51,10 @@ void seat_note_input(struct seat *s, uint32_t serial)
}
static void push_pointer(struct seat *s, struct wayland_surface *w,
- enum yasl_event_type type, struct yasl_pointer_event ev)
+ enum yasl_private_event_type type, struct yasl_private_pointer_event ev)
{
ev.mods = (uint32_t)seat_modifiers(s);
- struct yasl_event input_ev = {
+ struct yasl_private_event input_ev = {
.type = type,
.surface = &w->base,
.pointer = ev,
@@ -52,13 +62,15 @@ static void push_pointer(struct seat *s, struct wayland_surface *w,
input_queue_push(&surface_root(w)->input, &input_ev);
}
-static void report_wheel(struct seat *s, struct wayland_surface *w,
- struct yasl_vector2i pos, double x, double y)
+static unsigned scroll_source_of(uint32_t source)
{
- if ((x == 0 && y == 0) || !isfinite(x) || !isfinite(y)) return;
- push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){
- .pos = pos, .scroll = {x, y},
- });
+ switch (source) {
+ case WL_POINTER_AXIS_SOURCE_WHEEL: return 1;
+ case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: return 1;
+ case WL_POINTER_AXIS_SOURCE_FINGER: return 2;
+ case WL_POINTER_AXIS_SOURCE_CONTINUOUS: return 3;
+ default: return 0;
+ }
}
static bool cursor_theme_for(struct wayland_display *c, int scale)
@@ -90,10 +102,10 @@ static bool seat_cursor_surface(struct seat *s)
}
static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w,
- enum yasl_cursor shape)
+ enum yasl_private_cursor shape)
{
struct wayland_display *c = s->conn;
- int scale = (int)((w->scale_120 + YASL_SCALE_UNIT - 1) / YASL_SCALE_UNIT);
+ int scale = (int)((w->scale_120 + YASL_PRIVATE_SCALE_UNIT - 1) / YASL_PRIVATE_SCALE_UNIT);
if (scale < 1) scale = 1;
if (!seat_cursor_surface(s) || !cursor_theme_for(c, scale)) return;
static const char *names[][2] = {
@@ -107,7 +119,7 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w,
{"ew-resize", "ew-resize"},
{"ns-resize", "ns-resize"},
};
- int idx = (unsigned)shape < YASL_CURSOR_HIDDEN ? (int)shape : 0;
+ int idx = (unsigned)shape < YASL_PRIVATE_CURSOR_HIDDEN ? (int)shape : 0;
struct wl_cursor *cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][0]);
if (!cursor) cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][1]);
if (!cursor || !cursor->image_count) return;
@@ -117,11 +129,11 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w,
int theme_scale = c->cursor_theme_scale;
if (s->cursor_viewport) {
- uint32_t scale_120 = (uint32_t)theme_scale * YASL_SCALE_UNIT;
+ uint32_t scale_120 = (uint32_t)theme_scale * YASL_PRIVATE_SCALE_UNIT;
wp_viewport_set_destination(s->cursor_viewport,
- (int)(((int64_t)(int)img->width * YASL_SCALE_UNIT + scale_120 - 1) /
+ (int)(((int64_t)(int)img->width * YASL_PRIVATE_SCALE_UNIT + scale_120 - 1) /
scale_120),
- (int)(((int64_t)(int)img->height * YASL_SCALE_UNIT + scale_120 - 1) /
+ (int)(((int64_t)(int)img->height * YASL_PRIVATE_SCALE_UNIT + scale_120 - 1) /
scale_120));
} else {
if (img->width % (uint32_t)theme_scale || img->height % (uint32_t)theme_scale)
@@ -137,17 +149,17 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w,
wl_surface_commit(s->cursor_surface);
}
-static uint32_t cursor_shape_of(enum yasl_cursor shape)
+static uint32_t cursor_shape_of(enum yasl_private_cursor shape)
{
switch (shape) {
- case YASL_CURSOR_TEXT: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT;
- case YASL_CURSOR_LINK: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;
- case YASL_CURSOR_CROSSHAIR: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
- case YASL_CURSOR_MOVE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE;
- case YASL_CURSOR_RESIZE_EW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE;
- case YASL_CURSOR_RESIZE_NS: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE;
- case YASL_CURSOR_RESIZE_NWSE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE;
- case YASL_CURSOR_RESIZE_NESW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE;
+ case YASL_PRIVATE_CURSOR_TEXT: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT;
+ case YASL_PRIVATE_CURSOR_LINK: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;
+ case YASL_PRIVATE_CURSOR_CROSSHAIR: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
+ case YASL_PRIVATE_CURSOR_MOVE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE;
+ case YASL_PRIVATE_CURSOR_RESIZE_EW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE;
+ case YASL_PRIVATE_CURSOR_RESIZE_NS: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE;
+ case YASL_PRIVATE_CURSOR_RESIZE_NWSE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE;
+ case YASL_PRIVATE_CURSOR_RESIZE_NESW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE;
default: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
}
}
@@ -155,11 +167,11 @@ static uint32_t cursor_shape_of(enum yasl_cursor shape)
/* Relative mode hides the pointer but keeps w->cursor for the return to NORMAL. */
static void seat_set_cursor(struct seat *s, struct wayland_surface *w)
{
- enum yasl_cursor shape = w->relative ? YASL_CURSOR_HIDDEN : w->cursor;
+ enum yasl_private_cursor shape = w->relative ? YASL_PRIVATE_CURSOR_HIDDEN : w->cursor;
if (!s->pointer || !s->pointer_serial || s->pointer_focus != w ||
s->cursor_shape == (int)shape)
return;
- if (shape == YASL_CURSOR_HIDDEN)
+ if (shape == YASL_PRIVATE_CURSOR_HIDDEN)
wl_pointer_set_cursor(s->pointer, s->pointer_serial, NULL, 0, 0);
else if (s->cursor_shape_dev)
wp_cursor_shape_device_v1_set_shape(s->cursor_shape_dev,
@@ -169,20 +181,20 @@ static void seat_set_cursor(struct seat *s, struct wayland_surface *w)
s->cursor_shape = shape;
}
-static void tool_set_cursor(struct tablet_tool *t, enum yasl_cursor shape)
+static void tool_set_cursor(struct tablet_tool *t, enum yasl_private_cursor shape)
{
if (!t->proximity_serial)
return;
- if (shape == YASL_CURSOR_HIDDEN)
+ if (shape == YASL_PRIVATE_CURSOR_HIDDEN)
zwp_tablet_tool_v2_set_cursor(t->proxy, t->proximity_serial, NULL, 0, 0);
else if (t->shape_dev)
wp_cursor_shape_device_v1_set_shape(t->shape_dev, t->proximity_serial,
cursor_shape_of(shape));
}
-void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_cursor shape)
+void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_private_cursor shape)
{
- if (!w || !w->conn || w->destroyed || (unsigned)shape > YASL_CURSOR_HIDDEN) return;
+ if (!w || !w->conn || w->destroyed || (unsigned)shape > YASL_PRIVATE_CURSOR_HIDDEN) return;
w->cursor = shape;
for (struct seat *s = w->conn->seats; s; s = s->next) {
seat_set_cursor(s, w);
@@ -193,7 +205,7 @@ void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_cursor shap
static void press_queue_flush(struct seat *s, struct press_queue *q,
struct wayland_surface *only, uint64_t *buttons,
- struct yasl_pointer_event like)
+ struct yasl_private_pointer_event like)
{
int kept = 0;
int count = q->n;
@@ -206,10 +218,10 @@ static void press_queue_flush(struct seat *s, struct press_queue *q,
if (!p.surface) continue;
uint64_t mask = 1ull << p.button;
*buttons = (*buttons & ~mask) | ((uint64_t)(!p.release) << p.button);
- struct yasl_pointer_event ev = like;
+ struct yasl_private_pointer_event ev = like;
ev.pos = p.pos;
- ev.button = (enum yasl_pointer_button)p.button;
- enum yasl_event_type type = p.release ? YASL_EVENT_POINTER_UP : YASL_EVENT_POINTER_DOWN;
+ ev.button = (enum yasl_private_pointer_button)p.button;
+ enum yasl_private_event_type type = p.release ? YASL_PRIVATE_EVENT_POINTER_UP : YASL_PRIVATE_EVENT_POINTER_DOWN;
push_pointer(s, p.surface, type, ev);
}
q->head = 0;
@@ -217,7 +229,7 @@ static void press_queue_flush(struct seat *s, struct press_queue *q,
}
static void press_queue_push(struct press_queue *q, struct wayland_surface *w,
- struct yasl_vector2i pos, int button, bool release)
+ struct yasl_private_vector2i pos, int button, bool release)
{
if (q->n == 8) {
q->head = (q->head + 1) & 7;
@@ -244,10 +256,15 @@ void seat_pointer_reset(struct seat *s)
s->pointer_serial = 0;
s->motion_pending = false;
memset(s->axis, 0, sizeof(s->axis));
+ memset(s->axis_pixels, 0, sizeof(s->axis_pixels));
memset(s->axis_value120, 0, sizeof(s->axis_value120));
memset(s->axis_discrete, 0, sizeof(s->axis_discrete));
memset(s->axis_has_value120, 0, sizeof(s->axis_has_value120));
memset(s->axis_has_discrete, 0, sizeof(s->axis_has_discrete));
+ s->axis_stop_pending = false;
+ s->scroll_gesture = false;
+ s->axis_phase = 0;
+ s->axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
s->cursor_shape = -1;
}
@@ -263,7 +280,7 @@ static void flush_pending_motion(struct seat *s, struct wayland_surface *w)
{
if (!s->motion_pending) return;
s->motion_pending = false;
- push_pointer(s, w, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){
+ push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){
.pos = s->pointer_pos,
});
}
@@ -356,6 +373,13 @@ static void pointer_axis(void *data, struct wl_pointer *pointer,
double v = wl_fixed_to_double(value);
if (likely(axis < 2)) {
s->axis[axis] += v;
+ s->axis_pixels[axis] += v;
+ if (s->axis_source == WL_POINTER_AXIS_SOURCE_FINGER ||
+ s->axis_source == WL_POINTER_AXIS_SOURCE_CONTINUOUS) {
+ if (!s->scroll_gesture) s->axis_phase = 1u;
+ else if (s->axis_phase != 1u) s->axis_phase = 2u;
+ s->scroll_gesture = true;
+ }
}
pointer_event_done(s);
}
@@ -363,13 +387,14 @@ static void pointer_axis(void *data, struct wl_pointer *pointer,
static void pointer_axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source)
{
(void)pointer;
- (void)data; (void)axis_source;
+ ((struct seat *)data)->axis_source = axis_source;
}
static void pointer_axis_stop(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis)
{
/* A stop ends a gesture, not the offsets already received in this frame. */
- (void)data; (void)pointer; (void)time; (void)axis;
+ (void)pointer; (void)time; (void)axis;
+ ((struct seat *)data)->axis_stop_pending = true;
}
static void pointer_axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete)
@@ -405,7 +430,28 @@ static void pointer_frame_scroll(struct seat *s, struct wayland_surface *w)
s->axis_discrete[axis] = 0;
s->axis_has_value120[axis] = s->axis_has_discrete[axis] = false;
}
- report_wheel(s, w, s->pointer_pos, lines[1], lines[0]);
+ bool stopped = s->axis_stop_pending;
+ unsigned source = scroll_source_of(s->axis_source);
+ unsigned phase = source == 2 || source == 3
+ ? (stopped ? 3u : s->axis_phase) : 0u;
+ bool has_pixels = (source == 2 || source == 3) &&
+ (s->axis_pixels[0] != 0 || s->axis_pixels[1] != 0);
+ if (lines[0] != 0 || lines[1] != 0 || stopped) {
+ push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_SCROLL,
+ (struct yasl_private_pointer_event){
+ .pos = s->pointer_pos,
+ .scroll = {lines[1], lines[0]},
+ .pixel_scroll = {s->axis_pixels[1] * w->scale_factor,
+ s->axis_pixels[0] * w->scale_factor},
+ .scroll_valid = 1u | (has_pixels ? 2u : 0u),
+ .scroll_source = source,
+ .scroll_phase = phase,
+ });
+ }
+ memset(s->axis_pixels, 0, sizeof(s->axis_pixels));
+ s->axis_stop_pending = false;
+ if (stopped) s->scroll_gesture = false;
+ s->axis_phase = 0;
}
static void pointer_frame(void *data, struct wl_pointer *pointer)
@@ -416,14 +462,14 @@ static void pointer_frame(void *data, struct wl_pointer *pointer)
if (left) {
s->ptr_left = NULL;
if (s->ptr_left_motion)
- push_pointer(s, left, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){
+ push_pointer(s, left, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){
.pos = s->ptr_left_pos,
});
- press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_pointer_event){0});
- push_pointer(s, left, YASL_EVENT_POINTER_LEAVE, (struct yasl_pointer_event){
+ press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_private_pointer_event){0});
+ push_pointer(s, left, YASL_PRIVATE_EVENT_POINTER_LEAVE, (struct yasl_private_pointer_event){
.pos = s->ptr_left_pos,
});
- struct yasl_vector2i pos = s->pointer_pos;
+ struct yasl_private_vector2i pos = s->pointer_pos;
bool motion = s->motion_pending;
uint32_t serial = s->pointer_focus ? s->pointer_serial : 0;
int shape = s->pointer_focus ? s->cursor_shape : -1;
@@ -440,7 +486,7 @@ static void pointer_frame(void *data, struct wl_pointer *pointer)
}
flush_pending_motion(s, w);
- press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_pointer_event){0});
+ press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_private_pointer_event){0});
pointer_frame_scroll(s, w);
}
@@ -460,7 +506,7 @@ static void relative_motion(void *data, struct zwp_relative_pointer_v1 *pointer,
/* Unlocked movement arrives as wl_pointer.motion; the queue derives its delta. */
if (!w || !w->pointer_locked || w->lock_seat != s) return;
flush_pending_motion(s, w);
- push_pointer(s, w, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){
+ push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){
.pos = s->pointer_pos,
.delta = {wl_fixed_to_double(dx) * w->scale_factor,
wl_fixed_to_double(dy) * w->scale_factor},
@@ -525,12 +571,12 @@ static void seat_lock_surfaces(struct seat *s)
surface_lock_pointer(w, s);
}
-bool wayland_surface_set_pointer_mode(struct wayland_surface *w, enum yasl_pointer_mode mode)
+bool wayland_surface_set_pointer_mode(struct wayland_surface *w, enum yasl_private_pointer_mode mode)
{
if (!w || !w->conn || w->destroyed)
return false;
struct wayland_display *c = w->conn;
- bool relative = mode == YASL_POINTER_RELATIVE;
+ bool relative = mode == YASL_PRIVATE_POINTER_RELATIVE;
if (relative && (!c->relative_pointer_mgr || !c->pointer_constraints))
return false;
w->relative = relative;
@@ -572,10 +618,10 @@ static struct touch_point *touch_find(struct seat *s, int32_t id)
return NULL;
}
-static struct yasl_vector2i touch_pos(const struct touch_point *p)
+static struct yasl_private_vector2i touch_pos(const struct touch_point *p)
{
double scale = p->surface->scale_factor;
- return (struct yasl_vector2i){
+ return (struct yasl_private_vector2i){
.x = (int)lrint(p->x * scale), .y = (int)lrint(p->y * scale),
};
}
@@ -583,11 +629,11 @@ static struct yasl_vector2i touch_pos(const struct touch_point *p)
static void touch_report(struct seat *s, struct touch_point *p, int button,
- enum yasl_event_type type)
+ enum yasl_private_event_type type)
{
- push_pointer(s, p->surface, type, (struct yasl_pointer_event){
- .pos = touch_pos(p), .button = (enum yasl_pointer_button)button,
- .device = YASL_PTR_DEV_TOUCH,
+ push_pointer(s, p->surface, type, (struct yasl_private_pointer_event){
+ .pos = touch_pos(p), .button = (enum yasl_private_pointer_button)button,
+ .device = YASL_PRIVATE_PTR_DEV_TOUCH,
});
}
@@ -644,7 +690,7 @@ static void touch_frame(void *data, struct wl_touch *touch)
if (p->down && !s->touch_primary && !s->touch_scrolling) {
s->touch_primary = p;
s->touch_pressed = true;
- touch_report(s, p, 0, YASL_EVENT_POINTER_DOWN);
+ touch_report(s, p, 0, YASL_PRIVATE_EVENT_POINTER_DOWN);
}
if (!p->up) {
active_n++;
@@ -657,7 +703,7 @@ static void touch_frame(void *data, struct wl_touch *touch)
struct touch_point *primary = s->touch_primary;
if (primary && !s->touch_scrolling && active_n >= 2) {
if (s->touch_pressed)
- touch_report(s, primary, 0, YASL_EVENT_POINTER_UP);
+ touch_report(s, primary, 0, YASL_PRIVATE_EVENT_POINTER_UP);
s->touch_pressed = false;
s->touch_scrolling = true;
s->touch_scroll_y = centroid_n ? centroid_sum / centroid_n : 0;
@@ -667,14 +713,14 @@ static void touch_frame(void *data, struct wl_touch *touch)
s->touch_scroll_y = y;
if (dy != 0.0) {
double lines = dy / SCROLL_PX_PER_LINE;
- push_pointer(s, primary->surface, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){
+ push_pointer(s, primary->surface, YASL_PRIVATE_EVENT_POINTER_SCROLL, (struct yasl_private_pointer_event){
.pos = touch_pos(primary),
.scroll = {0, -lines},
- .device = YASL_PTR_DEV_TOUCH,
+ .device = YASL_PRIVATE_PTR_DEV_TOUCH,
});
}
} else if (primary && primary->moved && s->touch_pressed) {
- touch_report(s, primary, 0, YASL_EVENT_POINTER_MOTION);
+ touch_report(s, primary, 0, YASL_PRIVATE_EVENT_POINTER_MOTION);
}
for (int i = 0; i < SEAT_TOUCH_POINTS; i++) {
struct touch_point *p = &s->touch_points[i];
@@ -683,7 +729,7 @@ static void touch_frame(void *data, struct wl_touch *touch)
active_n--;
if (p == s->touch_primary) {
if (s->touch_pressed)
- touch_report(s, p, 0, YASL_EVENT_POINTER_UP);
+ touch_report(s, p, 0, YASL_PRIVATE_EVENT_POINTER_UP);
s->touch_pressed = false;
s->touch_primary = NULL;
}
@@ -701,7 +747,7 @@ static void touch_cancel(void *data, struct wl_touch *touch)
(void)touch;
struct seat *s = data;
if (s->touch_primary && s->touch_pressed)
- touch_report(s, s->touch_primary, 0, YASL_EVENT_POINTER_UP);
+ touch_report(s, s->touch_primary, 0, YASL_PRIVATE_EVENT_POINTER_UP);
memset(s->touch_points, 0, sizeof(s->touch_points));
s->touch_primary = NULL;
s->touch_pressed = false;
@@ -719,29 +765,100 @@ static const struct wl_touch_listener touch_listener = {
.frame = touch_frame, .cancel = touch_cancel,
};
-static struct yasl_pointer_event tool_event(const struct seat *s)
+static struct yasl_private_pointer_event tool_event(const struct seat *s)
{
- return (struct yasl_pointer_event){
- .device = s->tool && s->tool->eraser ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN,
+ return (struct yasl_private_pointer_event){
+ .device = s->tool && s->tool->eraser ? YASL_PRIVATE_PTR_DEV_ERASER : YASL_PRIVATE_PTR_DEV_PEN,
.pen = s->pen,
};
}
+static void push_pen_sample(struct tablet_tool *tool, struct wayland_surface *w,
+ unsigned action, uint32_t changed)
+{
+ struct seat *s = tool->seat;
+ if (!w) return;
+ uint64_t buttons = s->tool_buttons;
+ for (int i = 0; i < s->tool_presses.n; i++) {
+ const struct pending_press *press = &s->tool_presses.ev[(s->tool_presses.head + i) & 7];
+ if (press->surface && press->button >= 0 && press->button < 32) {
+ uint64_t bit = 1ull << press->button;
+ buttons = (buttons & ~bit) | ((uint64_t)!press->release << press->button);
+ }
+ }
+ if (action == YASL_PRIVATE_PEN_LEAVE || action == YASL_PRIVATE_PEN_CANCEL)
+ buttons = 0;
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_PEN,
+ .surface = &w->base,
+ .pen = {
+ .device_id = tool->device_id,
+ .tool_id = tool->tool_id,
+ .x = tool->x,
+ .y = tool->y,
+ .pressure = tool->pressure,
+ .tilt_x = tool->tilt_x,
+ .tilt_y = tool->tilt_y,
+ .rotation = tool->rotation,
+ .distance = tool->distance,
+ .tangential = tool->tangential,
+ .wheel_degrees = tool->wheel_degrees,
+ .axes_valid = tool->axes_valid,
+ .axes_changed = changed,
+ .buttons = (uint32_t)buttons,
+ .changed_button = tool->changed_button,
+ .in_contact = tool->in_contact,
+ .tool = tool->kind,
+ .action = action,
+ },
+ };
+ input_queue_push(&surface_root(w)->input, &ev);
+}
+
+static void pen_action_push(struct tablet_tool *tool, unsigned action, unsigned button)
+{
+ if (tool->pending_action_count == 8) {
+ memmove(tool->pending_actions, tool->pending_actions + 1,
+ 7 * sizeof(tool->pending_actions[0]));
+ memmove(tool->pending_buttons, tool->pending_buttons + 1,
+ 7 * sizeof(tool->pending_buttons[0]));
+ memmove(tool->pending_contacts, tool->pending_contacts + 1,
+ 7 * sizeof(tool->pending_contacts[0]));
+ tool->pending_action_count--;
+ }
+ unsigned i = tool->pending_action_count++;
+ tool->pending_actions[i] = action;
+ tool->pending_buttons[i] = button;
+ tool->pending_contacts[i] = tool->in_contact;
+}
+
static void tablet_tool_proximity_in(void *data,
struct zwp_tablet_tool_v2 *tool, uint32_t serial,
struct zwp_tablet_v2 *tablet, struct wl_surface *surface)
{
- (void)tool; (void)tablet;
+ (void)tool;
struct tablet_tool *t = data;
struct seat *s = t->seat;
struct wayland_surface *w = surface ?
(struct wayland_surface *)wl_surface_get_user_data(surface) : NULL;
s->tablet_focus = w;
s->tool = t;
+ t->device_id = 0;
+ for (struct tablet_device *device = s->tablet_devices; device; device = device->next)
+ if (device->proxy == tablet) { t->device_id = device->id; break; }
+ t->pen_in_proximity = true;
+ t->in_contact = false;
+ t->pending_action_count = 0;
+ pen_action_push(t, YASL_PRIVATE_PEN_ENTER, 0);
+ t->axes_changed = 0;
+ t->pressure = t->tilt_x = t->tilt_y = t->rotation = t->distance = 0;
+ t->tangential = t->wheel_degrees = 0;
s->tool_buttons = 0;
- s->pen = (struct yasl_pointer_pen){0};
+ s->pen = (struct yasl_private_pointer_pen){0};
t->proximity_serial = serial;
if (!w) return;
+ t->x = s->tool_pos.x;
+ t->y = s->tool_pos.y;
if (s->conn->cursor_shape_mgr && !t->shape_dev)
t->shape_dev = wp_cursor_shape_manager_v1_get_tablet_tool_v2(
s->conn->cursor_shape_mgr, t->proxy);
@@ -756,11 +873,14 @@ static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *too
struct seat *s = t->seat;
struct wayland_surface *w = s->tablet_focus;
if (w) {
+ t->in_contact = false;
+ t->pressure = 0;
+ push_pen_sample(t, w, YASL_PRIVATE_PEN_LEAVE, 0);
press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, tool_event(s));
s->pen.pressure = 0;
- struct yasl_pointer_event ev = tool_event(s);
+ struct yasl_private_pointer_event ev = tool_event(s);
ev.pos = s->tool_pos;
- push_pointer(s, w, YASL_EVENT_POINTER_LEAVE, ev);
+ push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_LEAVE, ev);
}
s->tool_presses.n = 0;
s->tablet_focus = NULL;
@@ -769,28 +889,38 @@ static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *too
s->tool_wheel = 0;
s->tool_buttons = 0;
t->proximity_serial = 0;
+ t->pen_in_proximity = false;
+ t->in_contact = false;
}
static void tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial)
{
(void)tool;
- struct seat *s = ((struct tablet_tool *)data)->seat;
+ struct tablet_tool *t = data;
+ struct seat *s = t->seat;
struct wayland_surface *w = s->tablet_focus;
if (!w) return;
seat_note_input(s, serial);
s->press_serial = serial;
s->press_surface = w;
press_queue_push(&s->tool_presses, w, s->tool_pos, 0, false);
+ t->in_contact = true;
+ pen_action_push(t, YASL_PRIVATE_PEN_DOWN, 0);
}
static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *tool)
{
(void)tool;
struct seat *s = ((struct tablet_tool *)data)->seat;
+ struct tablet_tool *t = data;
struct wayland_surface *w = s->tablet_focus;
if (!w) return;
s->pen.pressure = 0;
press_queue_push(&s->tool_presses, w, s->tool_pos, 0, true);
+ t->pressure = 0;
+ t->in_contact = false;
+ pen_action_push(t, YASL_PRIVATE_PEN_UP, 0);
+ t->axes_changed |= YASL_PRIVATE_PEN_PRESSURE;
}
static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_fixed_t x, wl_fixed_t y)
@@ -800,6 +930,9 @@ static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_f
struct wayland_surface *w = s->tablet_focus;
if (!w) return;
s->tool_pos = device_from_fixed(w, x, y);
+ struct tablet_tool *owned = data;
+ owned->x = wl_fixed_to_double(x) * w->scale_factor;
+ owned->y = wl_fixed_to_double(y) * w->scale_factor;
s->tool_motion = true;
}
@@ -807,7 +940,8 @@ static void tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *tool,
uint32_t serial, uint32_t button, uint32_t state)
{
(void)tool;
- struct seat *s = ((struct tablet_tool *)data)->seat;
+ struct tablet_tool *t = data;
+ struct seat *s = t->seat;
struct wayland_surface *w = s->tablet_focus;
if (!w) return;
seat_note_input(s, serial);
@@ -820,13 +954,18 @@ static void tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *tool,
}
bool release = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED;
press_queue_push(&s->tool_presses, w, s->tool_pos, b, release);
+ pen_action_push(t, YASL_PRIVATE_PEN_BUTTON, (unsigned)b);
}
static void tool_pressure(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v)
{
(void)t;
struct seat *s = ((struct tablet_tool *)d)->seat;
+ struct tablet_tool *owned = d;
s->pen.pressure = v > 65535 ? 65535 : (uint16_t)v;
+ owned->pressure = (double)(v > 65535 ? 65535 : v) / 65535.0;
+ owned->axes_valid |= YASL_PRIVATE_PEN_PRESSURE;
+ owned->axes_changed |= YASL_PRIVATE_PEN_PRESSURE;
s->tool_motion = true;
}
@@ -840,40 +979,68 @@ static void tool_tilt(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t x, wl_fi
{
(void)t;
struct seat *s = ((struct tablet_tool *)d)->seat;
+ struct tablet_tool *owned = d;
s->pen.tilt_x = tilt_degrees(x);
s->pen.tilt_y = tilt_degrees(y);
+ owned->tilt_x = wl_fixed_to_double(x);
+ owned->tilt_y = wl_fixed_to_double(y);
+ owned->axes_valid |= YASL_PRIVATE_PEN_TILT;
+ owned->axes_changed |= YASL_PRIVATE_PEN_TILT;
s->tool_motion = true;
}
static void tool_wheel(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg, int32_t clicks)
{
- (void)t; (void)deg;
- ((struct tablet_tool *)d)->seat->tool_wheel += clicks;
+ (void)t;
+ struct tablet_tool *owned = d;
+ owned->seat->tool_wheel += clicks;
+ owned->wheel_degrees += wl_fixed_to_double(deg);
+ owned->axes_valid |= YASL_PRIVATE_PEN_WHEEL;
+ owned->axes_changed |= YASL_PRIVATE_PEN_WHEEL;
}
static void tool_frame(void *d, struct zwp_tablet_tool_v2 *t, uint32_t time)
{
(void)t; (void)time;
struct seat *s = ((struct tablet_tool *)d)->seat;
+ struct tablet_tool *owned = d;
struct wayland_surface *w = s->tablet_focus;
if (!w) {
s->tool_presses.n = 0;
s->tool_wheel = 0;
return;
}
- struct yasl_pointer_event like = tool_event(s);
+ struct yasl_private_pointer_event like = tool_event(s);
+ if (owned->pending_action_count) {
+ unsigned actions = owned->pending_action_count;
+ bool contact = owned->in_contact;
+ for (unsigned i = 0; i < actions; i++) {
+ owned->changed_button = owned->pending_buttons[i];
+ owned->in_contact = owned->pending_contacts[i];
+ push_pen_sample(owned, w, owned->pending_actions[i],
+ i + 1 == actions ? owned->axes_changed : 0);
+ }
+ owned->in_contact = contact;
+ owned->pending_action_count = 0;
+ owned->axes_changed = 0;
+ owned->changed_button = 0;
+ } else if (s->tool_motion || owned->axes_changed) {
+ push_pen_sample(owned, w, YASL_PRIVATE_PEN_MOVE, owned->axes_changed);
+ owned->axes_changed = 0;
+ owned->changed_button = 0;
+ }
if (s->tool_motion) {
- struct yasl_pointer_event ev = like;
+ struct yasl_private_pointer_event ev = like;
ev.pos = s->tool_pos;
- push_pointer(s, w, YASL_EVENT_POINTER_MOTION, ev);
+ push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, ev);
s->tool_motion = false;
}
press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, like);
if (s->tool_wheel) {
- struct yasl_pointer_event ev = like;
+ struct yasl_private_pointer_event ev = like;
ev.pos = s->tool_pos;
ev.scroll.y = s->tool_wheel;
- push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, ev);
+ push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_SCROLL, ev);
s->tool_wheel = 0;
}
}
@@ -899,16 +1066,43 @@ static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *tool)
static void tool_type(void *d, struct zwp_tablet_tool_v2 *t, uint32_t type)
{
(void)t;
- ((struct tablet_tool *)d)->eraser = type == ZWP_TABLET_TOOL_V2_TYPE_ERASER;
+ struct tablet_tool *tool = d;
+ tool->eraser = type == ZWP_TABLET_TOOL_V2_TYPE_ERASER;
+ switch (type) {
+ case ZWP_TABLET_TOOL_V2_TYPE_PEN: tool->kind = 1; break;
+ case ZWP_TABLET_TOOL_V2_TYPE_ERASER: tool->kind = 2; break;
+ case ZWP_TABLET_TOOL_V2_TYPE_BRUSH: tool->kind = 3; break;
+ case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH: tool->kind = 4; break;
+ case ZWP_TABLET_TOOL_V2_TYPE_PENCIL: tool->kind = 5; break;
+ default: tool->kind = 0; break;
+ }
}
-static void tool_hardware_serial(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; }
+static void tool_hardware_serial(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo)
+{ (void)t; struct tablet_tool *tool = d; uint64_t id = ((uint64_t)hi << 32) | lo; if (id) tool->tool_id = id; }
static void tool_hardware_id_wacom(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; }
-static void tool_capability(void *d, struct zwp_tablet_tool_v2 *t, uint32_t cap) { (void)d; (void)t; (void)cap; }
+static void tool_capability(void *d, struct zwp_tablet_tool_v2 *t, uint32_t cap)
+{
+ (void)t;
+ struct tablet_tool *tool = d;
+ tool->capability_mask |= 1u << cap;
+ switch (cap) {
+ case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE: tool->axes_valid |= YASL_PRIVATE_PEN_PRESSURE; break;
+ case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT: tool->axes_valid |= YASL_PRIVATE_PEN_TILT; break;
+ case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION: tool->axes_valid |= YASL_PRIVATE_PEN_ROTATION; break;
+ case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE: tool->axes_valid |= YASL_PRIVATE_PEN_DISTANCE; break;
+ case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER: tool->axes_valid |= YASL_PRIVATE_PEN_TANGENTIAL; break;
+ case ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL: tool->axes_valid |= YASL_PRIVATE_PEN_WHEEL; break;
+ default: break;
+ }
+}
static void tool_done(void *d, struct zwp_tablet_tool_v2 *t) { (void)d; (void)t; }
-static void tool_distance(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) { (void)d; (void)t; (void)v; }
-static void tool_rotation(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg) { (void)d; (void)t; (void)deg; }
-static void tool_slider(void *d, struct zwp_tablet_tool_v2 *t, int32_t pos) { (void)d; (void)t; (void)pos; }
+static void tool_distance(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v)
+{ (void)t; struct tablet_tool *tool = d; tool->distance = (double)(v > 65535 ? 65535 : v) / 65535.0; tool->axes_valid |= YASL_PRIVATE_PEN_DISTANCE; tool->axes_changed |= YASL_PRIVATE_PEN_DISTANCE; }
+static void tool_rotation(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg)
+{ (void)t; struct tablet_tool *tool = d; tool->rotation = wl_fixed_to_double(deg); tool->axes_valid |= YASL_PRIVATE_PEN_ROTATION; tool->axes_changed |= YASL_PRIVATE_PEN_ROTATION; }
+static void tool_slider(void *d, struct zwp_tablet_tool_v2 *t, int32_t pos)
+{ (void)t; struct tablet_tool *tool = d; tool->tangential = pos / 65535.0; if (tool->tangential < -1) tool->tangential = -1; if (tool->tangential > 1) tool->tangential = 1; tool->axes_valid |= YASL_PRIVATE_PEN_TANGENTIAL; tool->axes_changed |= YASL_PRIVATE_PEN_TANGENTIAL; }
static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
.type = tool_type, .hardware_serial = tool_hardware_serial,
@@ -997,6 +1191,7 @@ static void tablet_seat_tablet_added(void *data, struct zwp_tablet_seat_v2 *tabl
struct tablet_device *owned = calloc(1, sizeof(*owned));
if (!owned) { zwp_tablet_v2_destroy(tablet); return; }
owned->proxy = tablet;
+ owned->id = ++s->conn->next_tool_id;
owned->next = s->tablet_devices;
s->tablet_devices = owned;
zwp_tablet_v2_add_listener(tablet, &tablet_listener, s);
@@ -1010,6 +1205,7 @@ static void tablet_seat_tool_added(void *data, struct zwp_tablet_seat_v2 *tablet
if (!owned) { zwp_tablet_tool_v2_destroy(tool); return; }
owned->proxy = tool;
owned->seat = s;
+ owned->tool_id = ++s->conn->next_tool_id;
owned->next = s->tablet_tools;
s->tablet_tools = owned;
zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, owned);
@@ -1035,7 +1231,7 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
static void clipboard_received(const char *text, size_t len, bool uri_list,
struct wl_surface *on, uint64_t request_id,
- enum yasl_transfer_status status, void *ud)
+ enum yasl_private_transfer_status status, void *ud)
{
(void)ud;
struct wayland_surface *w = on ?
@@ -1043,13 +1239,13 @@ static void clipboard_received(const char *text, size_t len, bool uri_list,
if (uri_list) w = surface_root(w);
if (!w || w->closed || w->destroyed) return;
if (!uri_list) {
- yasl_surface_complete_paste(&w->base, request_id, status, text, len);
+ yasl_private_surface_complete_paste(&w->base, request_id, status, text, len);
return;
}
- if (status != YASL_TRANSFER_OK) return;
- struct yasl_event ev = {
+ if (status != YASL_PRIVATE_TRANSFER_OK) return;
+ struct yasl_private_event ev = {
.surface = &w->base,
- .type = uri_list ? YASL_EVENT_DROP : YASL_EVENT_PASTE,
+ .type = uri_list ? YASL_PRIVATE_EVENT_DROP : YASL_PRIVATE_EVENT_PASTE,
.text = {
.data = text,
.len = len,
@@ -1058,14 +1254,14 @@ static void clipboard_received(const char *text, size_t len, bool uri_list,
input_queue_push(&w->input, &ev);
}
-static void clipboard_drag(enum yasl_drag_event ev, struct wl_surface *on,
+static void clipboard_drag(enum yasl_private_drag_event ev, struct wl_surface *on,
double x, double y, void *ud)
{
struct seat *s = ud;
conn_drag_target(s->conn, ev, on, x, y);
}
-static void clipboard_drop_hover(enum yasl_drop_event ev, struct wl_surface *on,
+static void clipboard_drop_hover(enum yasl_private_drop_event ev, struct wl_surface *on,
double x, double y, void *ud)
{
struct seat *s = ud;
@@ -1152,6 +1348,16 @@ static void seat_drop_touch(struct seat *s)
}
}
+void seat_ensure_text_input(struct seat *s)
+{
+ if (!s || !s->conn->text_input_mgr || s->text_input || !s->proxy)
+ return;
+ s->text_input = zwp_text_input_manager_v3_get_text_input(
+ s->conn->text_input_mgr, s->proxy);
+ if (s->text_input)
+ zwp_text_input_v3_add_listener(s->text_input, &text_input_listener, s);
+}
+
static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps)
{
struct seat *s = data;
@@ -1209,11 +1415,7 @@ static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps)
zwp_tablet_seat_v2_add_listener(s->tablet_seat, &tablet_seat_listener, s);
}
- if (c->text_input_mgr && !s->text_input) {
- s->text_input = zwp_text_input_manager_v3_get_text_input(c->text_input_mgr, proxy);
- if (s->text_input)
- zwp_text_input_v3_add_listener(s->text_input, &text_input_listener, s);
- }
+ seat_ensure_text_input(s);
seat_clipboard_ensure(s);
}
@@ -1297,8 +1499,8 @@ void seat_destroy(struct seat *s)
seat_drop_keyboard(s);
struct wayland_surface *left = s->focus_leaving;
if (left && !conn_keyboard_on(c, left, NULL)) {
- struct yasl_event ev = {
- .type = YASL_EVENT_FOCUS,
+ struct yasl_private_event ev = {
+ .type = YASL_PRIVATE_EVENT_FOCUS,
.surface = &left->base,
.focus = { .focused = false },
};
@@ -1306,7 +1508,7 @@ void seat_destroy(struct seat *s)
}
seat_drop_touch(s);
clipboard_destroy(s->clipboard);
- if (s->repeat_watch > 0) yasl_loop_del_fd(c->loop, s->repeat_watch);
+ if (s->repeat_watch > 0) yasl_private_loop_del_fd(c->loop, s->repeat_watch);
if (s->repeat_fd >= 0) close(s->repeat_fd);
if (s->cursor_viewport) wp_viewport_destroy(s->cursor_viewport);
if (s->cursor_surface) wl_surface_destroy(s->cursor_surface);
diff --git a/src/platform/wayland/popup.c b/src/platform/wayland/popup.c
index 44c7206..c563eb4 100644
--- a/src/platform/wayland/popup.c
+++ b/src/platform/wayland/popup.c
@@ -24,9 +24,19 @@ static const struct xdg_popup_listener popup_listener = {
};
static bool popup_spec_valid(const struct wayland_surface *parent,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
if (!parent || !spec) return false;
+ if (spec->positioner_explicit &&
+ (spec->anchor_edges > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT ||
+ spec->gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT ||
+ (spec->constraints & ~(unsigned)(XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X |
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y))))
+ return false;
int64_t x = (int64_t)spec->anchor.x - parent->content.x;
int64_t y = (int64_t)spec->anchor.y - parent->content.y;
return x >= INT_MIN && x <= INT_MAX && y >= INT_MIN && y <= INT_MAX &&
@@ -37,29 +47,29 @@ static bool popup_spec_valid(const struct wayland_surface *parent,
(int64_t)spec->content_offset.y + spec->content_size.y <= spec->size.y;
}
-static bool popup_apply_spec(struct wayland_surface *w, const struct yasl_popup_spec *spec)
+static bool popup_apply_spec(struct wayland_surface *w, const struct yasl_private_popup_spec *spec)
{
uint32_t scale = w->parent->scale_120;
- struct yasl_vector2i logical = {
- .x = (int)(((int64_t)spec->size.x * YASL_SCALE_UNIT + scale - 1) / scale),
- .y = (int)(((int64_t)spec->size.y * YASL_SCALE_UNIT + scale - 1) / scale),
+ struct yasl_private_vector2i logical = {
+ .x = (int)(((int64_t)spec->size.x * YASL_PRIVATE_SCALE_UNIT + scale - 1) / scale),
+ .y = (int)(((int64_t)spec->size.y * YASL_PRIVATE_SCALE_UNIT + scale - 1) / scale),
};
int width = device_px(logical.x, scale);
int height = device_px(logical.y, scale);
size_t bytes;
if (logical.x <= 0 || logical.y <= 0 || !buffer_size(width, height, &bytes))
return false;
- struct yasl_vector2i content = spec->content_size;
+ struct yasl_private_vector2i content = spec->content_size;
if (!content.x) content.x = spec->size.x - spec->content_offset.x;
if (!content.y) content.y = spec->size.y - spec->content_offset.y;
bool rescaled = scale != w->scale_120;
w->scale_120 = w->pending_scale_120 = scale;
- w->scale_factor = (double)scale / YASL_SCALE_UNIT;
+ w->scale_factor = (double)scale / YASL_PRIVATE_SCALE_UNIT;
w->width = width;
w->height = height;
w->logical_width = logical.x;
w->logical_height = logical.y;
- w->content = (struct yasl_rect2i){
+ w->content = (struct yasl_private_rect2i){
.x = spec->content_offset.x, .y = spec->content_offset.y,
.width = content.x, .height = content.y
};
@@ -67,20 +77,20 @@ static bool popup_apply_spec(struct wayland_surface *w, const struct yasl_popup_
w->buffers[i].presented = false;
if (w->viewport)
wp_viewport_set_destination(w->viewport, logical.x, logical.y);
- else if ((rescaled || !w->configured) && scale % YASL_SCALE_UNIT == 0 &&
+ else if ((rescaled || !w->configured) && scale % YASL_PRIVATE_SCALE_UNIT == 0 &&
wl_proxy_get_version((struct wl_proxy *)w->surface) >=
WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
- wl_surface_set_buffer_scale(w->surface, (int32_t)(scale / YASL_SCALE_UNIT));
+ wl_surface_set_buffer_scale(w->surface, (int32_t)(scale / YASL_PRIVATE_SCALE_UNIT));
return true;
}
static void popup_set_geometry(struct wayland_surface *w)
{
uint32_t scale = w->scale_120;
- int gx = yasl_scale_to_logical(w->content.x, scale);
- int gy = yasl_scale_to_logical(w->content.y, scale);
- int gw = yasl_scale_to_logical(w->content.width, scale);
- int gh = yasl_scale_to_logical(w->content.height, scale);
+ int gx = yasl_private_scale_to_logical(w->content.x, scale);
+ int gy = yasl_private_scale_to_logical(w->content.y, scale);
+ int gw = yasl_private_scale_to_logical(w->content.width, scale);
+ int gh = yasl_private_scale_to_logical(w->content.height, scale);
if (gw < 1) gw = 1;
if (gh < 1) gh = 1;
if (gx + gw > w->logical_width)
@@ -91,41 +101,45 @@ static void popup_set_geometry(struct wayland_surface *w)
}
static struct xdg_positioner *popup_positioner(struct wayland_surface *w,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
struct wayland_surface *parent = w->parent;
struct xdg_positioner *pos = xdg_wm_base_create_positioner(w->conn->wm_base);
if (!pos)
return NULL;
uint32_t scale = parent->scale_120;
- int gw = yasl_scale_to_logical(w->content.width, scale);
- int gh = yasl_scale_to_logical(w->content.height, scale);
+ int gw = yasl_private_scale_to_logical(w->content.width, scale);
+ int gh = yasl_private_scale_to_logical(w->content.height, scale);
xdg_positioner_set_size(pos, gw > 0 ? gw : 1, gh > 0 ? gh : 1);
- struct yasl_vector2i at = {
+ struct yasl_private_vector2i at = {
.x = spec->anchor.x - parent->content.x,
.y = spec->anchor.y - parent->content.y,
};
- int aw = yasl_scale_to_logical(spec->anchor.width, scale);
- int ah = yasl_scale_to_logical(spec->anchor.height, scale);
+ int aw = yasl_private_scale_to_logical(spec->anchor.width, scale);
+ int ah = yasl_private_scale_to_logical(spec->anchor.height, scale);
xdg_positioner_set_anchor_rect(pos,
- yasl_scale_to_logical(at.x, scale),
- yasl_scale_to_logical(at.y, scale),
+ yasl_private_scale_to_logical(at.x, scale),
+ yasl_private_scale_to_logical(at.y, scale),
aw > 0 ? aw : 1, ah > 0 ? ah : 1);
- xdg_positioner_set_anchor(pos, spec->beside ? XDG_POSITIONER_ANCHOR_TOP_RIGHT
- : XDG_POSITIONER_ANCHOR_TOP_LEFT);
- xdg_positioner_set_gravity(pos, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT);
- xdg_positioner_set_constraint_adjustment(pos,
+ uint32_t anchor = spec->positioner_explicit ? spec->anchor_edges :
+ (spec->beside ? XDG_POSITIONER_ANCHOR_TOP_RIGHT : XDG_POSITIONER_ANCHOR_TOP_LEFT);
+ uint32_t gravity = spec->positioner_explicit ? spec->gravity :
+ XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
+ uint32_t constraints = spec->positioner_explicit ? spec->constraints :
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X |
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y |
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
+ xdg_positioner_set_anchor(pos, anchor);
+ xdg_positioner_set_gravity(pos, gravity);
+ xdg_positioner_set_constraint_adjustment(pos, constraints);
if (xdg_positioner_get_version(pos) >= XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION)
xdg_positioner_set_reactive(pos);
return pos;
}
struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *parent,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
struct wayland_display *c = parent ? parent->conn : NULL;
struct seat *seat = c ? (c->active_seat ? c->active_seat : c->seats) : NULL;
@@ -137,7 +151,8 @@ struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *par
if (!w)
return NULL;
w->base.display = &c->base;
- w->base.state = YASL_STATE_CSD;
+ w->base.state = YASL_PRIVATE_STATE_CSD;
+ w->base.presenter = YASL_PRIVATE_PRESENTER_CPU;
w->input.leave_ends_press = true;
w->conn = c;
w->conn_next = c->surfaces;
@@ -150,7 +165,7 @@ struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *par
if (!w->surface)
goto err;
w->base.native_handle = w->surface;
- w->base.size = (struct yasl_vector2i){spec->size.x, spec->size.y};
+ w->base.size = (struct yasl_private_vector2i){spec->size.x, spec->size.y};
w->base.scale_120 = parent->scale_120;
wl_surface_set_user_data(w->surface, w);
if (surface_init_scaling(w) < 0)
@@ -180,13 +195,13 @@ err:
return NULL;
}
-bool wayland_surface_popup_reposition(struct wayland_surface *w, const struct yasl_popup_spec *spec)
+bool wayland_surface_popup_reposition(struct wayland_surface *w, const struct yasl_private_popup_spec *spec)
{
if (!w || !w->popup || w->closed || !w->conn || w->conn->lost ||
!popup_spec_valid(w->parent, spec) ||
xdg_popup_get_version(w->popup) < XDG_POPUP_REPOSITION_SINCE_VERSION)
return false;
- struct yasl_popup_spec old = {
+ struct yasl_private_popup_spec old = {
.size = { .x = w->width, .y = w->height },
.content_offset = { .x = w->content.x, .y = w->content.y },
.content_size = { .x = w->content.width, .y = w->content.height },
diff --git a/src/platform/wayland/shell.c b/src/platform/wayland/shell.c
index fc2ce2e..c2578e7 100644
--- a/src/platform/wayland/shell.c
+++ b/src/platform/wayland/shell.c
@@ -173,7 +173,7 @@ uint32_t conn_output_scale_120(const struct wayland_display *c, uint64_t outputs
for (const struct wl_conn_output *o = c->outputs; o; o = o->next)
if ((o->mask & outputs) && o->scale > scale)
scale = o->scale;
- return (uint32_t)scale * YASL_SCALE_UNIT;
+ return (uint32_t)scale * YASL_PRIVATE_SCALE_UNIT;
}
static void registry_global(void *data, struct wl_registry *registry,
@@ -227,6 +227,8 @@ static void registry_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) {
c->text_input_mgr = wl_registry_bind(registry, name,
&zwp_text_input_manager_v3_interface, 1);
+ for (struct seat *seat = c->seats; seat; seat = seat->next)
+ seat_ensure_text_input(seat);
} else if (strcmp(interface, wp_tearing_control_manager_v1_interface.name) == 0) {
c->tearing_mgr = wl_registry_bind(registry, name,
&wp_tearing_control_manager_v1_interface, 1);
@@ -277,7 +279,7 @@ static void set_state(struct wayland_surface *w, uint32_t state)
{
if (state == w->base.state) return;
w->base.state = state;
- yasl_surface_notify_state(&w->base, state);
+ yasl_private_surface_notify_state(&w->base, state);
}
static void toplevel_configure(void *data, struct xdg_toplevel *toplevel,
@@ -286,21 +288,21 @@ static void toplevel_configure(void *data, struct xdg_toplevel *toplevel,
(void)toplevel;
struct wayland_surface *w = data;
- uint32_t state = w->base.state & ~(YASL_STATE_FULLSCREEN |
- YASL_STATE_MAXIMIZED | YASL_STATE_ACTIVATED |
- YASL_STATE_SUSPENDED | YASL_STATE_TILED);
+ uint32_t state = w->base.state & ~(YASL_PRIVATE_STATE_FULLSCREEN |
+ YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_ACTIVATED |
+ YASL_PRIVATE_STATE_SUSPENDED | YASL_PRIVATE_STATE_TILED);
uint32_t *s;
wl_array_for_each(s, states) {
switch (*s) {
- case XDG_TOPLEVEL_STATE_FULLSCREEN: state |= YASL_STATE_FULLSCREEN; break;
- case XDG_TOPLEVEL_STATE_MAXIMIZED: state |= YASL_STATE_MAXIMIZED; break;
- case XDG_TOPLEVEL_STATE_ACTIVATED: state |= YASL_STATE_ACTIVATED; break;
- case XDG_TOPLEVEL_STATE_SUSPENDED: state |= YASL_STATE_SUSPENDED; break;
+ case XDG_TOPLEVEL_STATE_FULLSCREEN: state |= YASL_PRIVATE_STATE_FULLSCREEN; break;
+ case XDG_TOPLEVEL_STATE_MAXIMIZED: state |= YASL_PRIVATE_STATE_MAXIMIZED; break;
+ case XDG_TOPLEVEL_STATE_ACTIVATED: state |= YASL_PRIVATE_STATE_ACTIVATED; break;
+ case XDG_TOPLEVEL_STATE_SUSPENDED: state |= YASL_PRIVATE_STATE_SUSPENDED; break;
case XDG_TOPLEVEL_STATE_TILED_LEFT:
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
case XDG_TOPLEVEL_STATE_TILED_TOP:
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
- state |= YASL_STATE_TILED;
+ state |= YASL_PRIVATE_STATE_TILED;
break;
default: break;
}
@@ -316,7 +318,7 @@ static void toplevel_close(void *data, struct xdg_toplevel *toplevel)
(void)toplevel;
struct wayland_surface *w = data;
if (w && !w->closed)
- yasl_surface_notify_close(&w->base);
+ yasl_private_surface_notify_close(&w->base);
}
static void toplevel_configure_bounds(void *data, struct xdg_toplevel *toplevel,
@@ -349,11 +351,21 @@ static const struct xdg_toplevel_listener toplevel_listener = {
static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
{
struct wayland_surface *w = data;
- (void)xdg_surface;
w->pending_serial = serial;
w->has_pending_serial = true;
w->size_pending = true;
w->configured = true;
+ /* CPU surfaces acknowledge with their SHM commit. External presenters
+ * commit through EGL/Vulkan, so apply the configure and acknowledge it
+ * before renderer code can submit that first native buffer. */
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) {
+ xdg_surface_ack_configure(xdg_surface, serial);
+ w->has_pending_serial = false;
+ if (apply_pending_geometry(w) < 0) {
+ surface_fail(w);
+ return;
+ }
+ }
wayland_surface_schedule_redraw(w);
}
@@ -368,9 +380,9 @@ static void toplevel_decoration_configure(void *data,
struct wayland_surface *w = data;
uint32_t state = w->base.state;
if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
- state &= ~YASL_STATE_CSD;
+ state &= ~YASL_PRIVATE_STATE_CSD;
else
- state |= YASL_STATE_CSD;
+ state |= YASL_PRIVATE_STATE_CSD;
set_state(w, state);
}
@@ -387,11 +399,11 @@ int surface_init_shell(struct wayland_surface *w, const char *title)
if (!w->toplevel) return -1;
xdg_toplevel_add_listener(w->toplevel, &toplevel_listener, w);
- wayland_surface_set_title(w, title ? title : "yasl_app");
+ wayland_surface_set_title(w, title ? title : "yasl_private_app");
- const char *app_id = w->conn->app_id ? w->conn->app_id : "yasl_app";
+ const char *app_id = w->conn->app_id ? w->conn->app_id : "yasl_private_app";
xdg_toplevel_set_app_id(w->toplevel, app_id);
- xdg_toplevel_set_min_size(w->toplevel, YASL_MIN_LOGICAL_PX, YASL_MIN_LOGICAL_PX);
+ xdg_toplevel_set_min_size(w->toplevel, YASL_PRIVATE_MIN_LOGICAL_PX, YASL_PRIVATE_MIN_LOGICAL_PX);
if (w->conn->decor_mgr) {
w->toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
@@ -400,7 +412,9 @@ int surface_init_shell(struct wayland_surface *w, const char *title)
zxdg_toplevel_decoration_v1_add_listener(w->toplevel_decor,
&toplevel_decoration_listener, w);
zxdg_toplevel_decoration_v1_set_mode(w->toplevel_decor,
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+ (w->base.creation_flags & YASL_PRIVATE_SURFACE_UNDECORATED)
+ ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
+ : ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
return 0;
}
diff --git a/src/platform/wayland/surface.c b/src/platform/wayland/surface.c
index 2e85e2b..31096f4 100644
--- a/src/platform/wayland/surface.c
+++ b/src/platform/wayland/surface.c
@@ -52,7 +52,7 @@ static void display_lose(struct wayland_display *c)
surface_fail(w);
}
display_leave(c);
- yasl_display_notify_event(&c->base, YASL_EVENT_DISPLAY_LOST);
+ yasl_private_display_notify_event(&c->base, YASL_PRIVATE_EVENT_DISPLAY_LOST);
}
void surface_fail(struct wayland_surface *w)
@@ -60,7 +60,7 @@ void surface_fail(struct wayland_surface *w)
if (w->closed)
return;
w->closed = true;
- yasl_surface_notify_close(&w->base);
+ yasl_private_surface_notify_close(&w->base);
}
static int display_ready(int fd, short revents, void *ud)
@@ -80,7 +80,7 @@ static int display_ready(int fd, short revents, void *ud)
if (revents & POLLOUT) {
if (wl_display_flush(c->wl) >= 0) {
if (c->loop && c->watch > 0)
- yasl_loop_set_fd_events(c->loop, c->watch, POLLIN);
+ yasl_private_loop_set_fd_events(c->loop, c->watch, POLLIN);
} else if (errno != EAGAIN) {
display_lose(c);
}
@@ -113,7 +113,7 @@ static bool display_arm(struct wayland_display *c)
events |= POLLOUT;
}
if (c->loop && c->watch > 0)
- yasl_loop_set_fd_events(c->loop, c->watch, events);
+ yasl_private_loop_set_fd_events(c->loop, c->watch, events);
return had_pending;
}
@@ -154,7 +154,7 @@ int wayland_display_dispatch_timeout(struct wayland_display *c, int timeout_ms)
int n = 0;
if (c->loop) {
- n = yasl_loop_step(c->loop, timeout_ms);
+ n = yasl_private_loop_step(c->loop, timeout_ms);
}
if (c->reading) {
@@ -190,7 +190,7 @@ void wayland_display_flush(struct wayland_display *c)
static void display_free(struct wayland_display *c)
{
conn_drag_end(c);
- if (c->loop && c->watch > 0) yasl_loop_del_fd(c->loop, c->watch);
+ if (c->loop && c->watch > 0) yasl_private_loop_del_fd(c->loop, c->watch);
if (c->wl) display_cancel_read(c);
while (c->seats)
seat_destroy(c->seats);
@@ -217,9 +217,12 @@ static void display_free(struct wayland_display *c)
if (c->shm) wl_shm_destroy(c->shm);
if (c->compositor) wl_compositor_destroy(c->compositor);
if (c->registry) wl_registry_destroy(c->registry);
+#if YASL_HAS_EGL
+ if (c->egl_initialized) eglTerminate(c->egl_display);
+#endif
if (c->wl) wl_display_disconnect(c->wl);
if (c->owns_loop && c->loop) {
- yasl_loop_destroy(c->loop);
+ yasl_private_loop_destroy(c->loop);
c->loop = NULL;
c->base.loop = NULL;
}
@@ -227,13 +230,13 @@ static void display_free(struct wayland_display *c)
free(c);
}
-struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec)
+struct wayland_display *wayland_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec)
{
struct wayland_display *c = calloc(1, sizeof(*c));
if (!c) return NULL;
- c->base.ops = &yasl_wayland_backend;
+ c->base.ops = &yasl_private_wayland_backend;
if (!loop) {
- c->loop = yasl_loop_create();
+ c->loop = yasl_private_loop_create();
c->owns_loop = true;
} else {
c->loop = loop;
@@ -241,7 +244,7 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc
c->base.loop = c->loop;
if (!c->loop) goto err;
if (spec) {
- c->base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_display_cbs){0};
+ c->base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0};
c->cbs = &c->base.callbacks;
c->ud = spec->ud;
if (spec->app_id) c->app_id = strdup(spec->app_id);
@@ -251,6 +254,13 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc
c->wl = c->xkb_ctx ? wl_display_connect(NULL) : NULL;
if (!c->wl) goto err;
c->base.native_handle = c->wl;
+#if YASL_HAS_EGL
+ c->egl_display = eglGetDisplay((EGLNativeDisplayType)c->wl);
+ if (c->egl_display != EGL_NO_DISPLAY) {
+ EGLint major = 0, minor = 0;
+ c->egl_initialized = eglInitialize(c->egl_display, &major, &minor) == EGL_TRUE;
+ }
+#endif
c->registry = wl_display_get_registry(c->wl);
if (!c->registry) goto err;
@@ -260,7 +270,7 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc
surface_init_cursor(c);
if (c->loop) {
- c->watch = yasl_loop_add_fd(c->loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c);
+ c->watch = yasl_private_loop_add_fd(c->loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c);
if (c->watch <= 0) { c->watch = 0; goto err; }
}
if (display_input_init(c) < 0)
@@ -282,16 +292,18 @@ void wayland_display_close(struct wayland_display *c)
uint32_t wayland_display_caps(const struct wayland_display *c)
{
if (!c) return 0;
- uint32_t caps = YASL_CAP_POPUPS | YASL_CAP_CSD | YASL_CAP_FRAME_PACING;
- if (c->tablet_mgr) caps |= YASL_CAP_TABLET;
+ uint32_t caps = YASL_PRIVATE_CAP_POPUPS | YASL_PRIVATE_CAP_CSD |
+ YASL_PRIVATE_CAP_FRAME_PACING | YASL_PRIVATE_CAP_NATIVE_GRAPHICS;
+ if (c->tablet_mgr) caps |= YASL_PRIVATE_CAP_TABLET;
+ if (c->text_input_mgr) caps |= YASL_PRIVATE_CAP_TEXT_INPUT;
struct seat *s = c->active_seat ? c->active_seat : c->seats;
const struct wl_data_device *device = s ? clipboard_data_device(s->clipboard) : NULL;
if (device && wl_data_device_get_version((struct wl_data_device *)device) >= 3)
- caps |= YASL_CAP_DRAG;
+ caps |= YASL_PRIVATE_CAP_DRAG;
if (c->toplevel_drag_mgr)
- caps |= YASL_CAP_DRAG_CARRY;
+ caps |= YASL_PRIVATE_CAP_DRAG_CARRY;
if (c->primary_selection_mgr)
- caps |= YASL_CAP_PRIMARY_SELECTION;
+ caps |= YASL_PRIVATE_CAP_PRIMARY_SELECTION;
return caps;
}
@@ -321,15 +333,18 @@ static void conn_unlink(struct wayland_surface *w)
}
-static bool spec_valid(const struct yasl_window_spec *spec)
+static bool spec_valid(const struct yasl_private_window_spec *spec)
{
size_t bytes;
- return spec && spec->size.x > 0 && spec->size.y > 0 &&
- buffer_size(spec->size.x, spec->size.y, &bytes);
+ if (!spec || spec->size.x <= 0 || spec->size.y <= 0)
+ return false;
+ return spec->external_gpu && !(spec->flags & YASL_PRIVATE_SURFACE_CPU)
+ ? spec->size.x <= INT32_MAX && spec->size.y <= INT32_MAX
+ : buffer_size(spec->size.x, spec->size.y, &bytes);
}
struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display *c,
- const struct yasl_window_spec *spec, void *graphics_device)
+ const struct yasl_private_window_spec *spec, void *graphics_device)
{
(void)graphics_device;
if (!c || c->lost || !spec_valid(spec))
@@ -340,28 +355,35 @@ struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display *
if (!w) return NULL;
c->depth++;
conn_link(c, w);
- w->base.state = YASL_STATE_CSD;
+ w->base.state = YASL_PRIVATE_STATE_CSD;
+ w->base.creation_flags = spec->flags;
+ w->base.presenter = (spec->external_gpu && !(spec->flags & YASL_PRIVATE_SURFACE_CPU))
+ ? YASL_PRIVATE_PRESENTER_NONE : YASL_PRIVATE_PRESENTER_CPU;
wayland_surface_set_callbacks(w, NULL, NULL);
- w->cursor = YASL_CURSOR_TEXT;
+ w->cursor = YASL_PRIVATE_CURSOR_TEXT;
w->req_width = width;
w->req_height = height;
w->logical_width = width;
w->logical_height = height;
- w->scale_120 = YASL_SCALE_UNIT;
- w->pending_scale_120 = YASL_SCALE_UNIT;
+ w->scale_120 = YASL_PRIVATE_SCALE_UNIT;
+ w->pending_scale_120 = YASL_PRIVATE_SCALE_UNIT;
w->scale_factor = 1.0;
w->size_pending = true;
w->clock.refresh_ns = c->outputs && c->outputs->refresh_ns
- ? c->outputs->refresh_ns : YASL_REFRESH_DEFAULT_NS;
+ ? c->outputs->refresh_ns : YASL_PRIVATE_REFRESH_DEFAULT_NS;
w->surface = wl_compositor_create_surface(c->compositor);
if (!w->surface) goto err;
w->base.native_handle = w->surface;
- w->base.size = (struct yasl_vector2i){width, height};
- w->base.scale_120 = YASL_SCALE_UNIT;
+ w->base.size = (struct yasl_private_vector2i){width, height};
+ w->base.scale_120 = YASL_PRIVATE_SCALE_UNIT;
wl_surface_set_user_data(w->surface, w);
if (surface_init_scaling(w) < 0) goto err;
if (surface_init_shell(w, spec->title) < 0) goto err;
+ if (spec->flags & YASL_PRIVATE_SURFACE_FIXED_SIZE) {
+ xdg_toplevel_set_min_size(w->toplevel, width, height);
+ xdg_toplevel_set_max_size(w->toplevel, width, height);
+ }
w->opaque = spec->fullscreen;
if (spec->fullscreen)
xdg_toplevel_set_fullscreen(w->toplevel, NULL);
@@ -389,10 +411,10 @@ err:
return NULL;
}
-void wayland_surface_set_callbacks(struct wayland_surface *w, const struct yasl_window_cbs *cbs, void *ud)
+void wayland_surface_set_callbacks(struct wayland_surface *w, const struct yasl_private_window_cbs *cbs, void *ud)
{
if (w && !w->closed) {
- w->base.callbacks = cbs ? *cbs : (struct yasl_window_cbs){0};
+ w->base.callbacks = cbs ? *cbs : (struct yasl_private_window_cbs){0};
w->base.ud = ud;
w->cbs = &w->base.callbacks;
w->ud = ud;
@@ -410,6 +432,15 @@ void wayland_surface_destroy(struct wayland_surface *w)
free(w->ime_commit);
free(w->ime_shown);
if (w->tearing_control) wp_tearing_control_v1_destroy(w->tearing_control);
+#if YASL_HAS_EGL
+ if (w->egl_context) {
+ if (eglGetCurrentContext() == w->egl_context)
+ eglMakeCurrent(w->conn->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(w->conn->egl_display, w->egl_context);
+ }
+ if (w->egl_surface) eglDestroySurface(w->conn->egl_display, w->egl_surface);
+ if (w->egl_window) wl_egl_window_destroy(w->egl_window);
+#endif
if (w->fifo) wp_fifo_v1_destroy(w->fifo);
if (w->commit_timer) wp_commit_timer_v1_destroy(w->commit_timer);
surface_feedback_destroy(w);
@@ -427,7 +458,7 @@ void wayland_surface_destroy(struct wayland_surface *w)
}
struct wayland_display *c = w->conn;
conn_unlink(w);
- static const struct yasl_window_cbs no_callbacks = {0};
+ static const struct yasl_private_window_cbs no_callbacks = {0};
*w = (struct wayland_surface){
.base = w->base,
.conn_next = w->conn_next,
@@ -446,16 +477,20 @@ void wayland_surface_destroy(struct wayland_surface *w)
void wayland_surface_schedule_redraw(struct wayland_surface *w)
{
if (!w || w->closed) return;
+ if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) {
+ yasl_private_surface_notify_refresh(&w->base);
+ return;
+ }
w->want_draw = true;
if (w->conn && w->conn->loop)
- yasl_loop_kick(w->conn->loop);
+ yasl_private_loop_kick(w->conn->loop);
}
-struct yasl_geometry wayland_surface_geometry(const struct wayland_surface *w)
+struct yasl_private_geometry wayland_surface_geometry(const struct wayland_surface *w)
{
- return (struct yasl_geometry){
- .size = w ? (struct yasl_vector2i){w->width, w->height} : (struct yasl_vector2i){0},
- .scale_120 = w ? w->scale_120 : YASL_SCALE_UNIT,
+ return (struct yasl_private_geometry){
+ .size = w ? (struct yasl_private_vector2i){w->width, w->height} : (struct yasl_private_vector2i){0},
+ .scale_120 = w ? w->scale_120 : YASL_PRIVATE_SCALE_UNIT,
};
}
@@ -473,23 +508,23 @@ bool wayland_surface_start_interactive_move(struct wayland_surface *s)
return true;
}
-bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_resize_edge edge)
+bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_private_resize_edge edge)
{
- if (!s || !s->toplevel || !s->conn || edge == YASL_EDGE_NONE) return false;
+ if (!s || !s->toplevel || !s->conn || edge == YASL_PRIVATE_EDGE_NONE) return false;
struct seat *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats;
if (!seat || !seat->proxy || !seat->press_serial) return false;
xdg_toplevel_resize(s->toplevel, seat->proxy, seat->press_serial, (uint32_t)edge);
return true;
}
-bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_vector2i pos)
+bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_private_vector2i pos)
{
if (!s || !s->toplevel || !s->conn) return false;
struct seat *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats;
if (!seat || !seat->proxy || !seat->press_serial) return false;
- uint32_t scale = s->scale_120 ? s->scale_120 : YASL_SCALE_UNIT;
+ uint32_t scale = s->scale_120 ? s->scale_120 : YASL_PRIVATE_SCALE_UNIT;
xdg_toplevel_show_window_menu(s->toplevel, seat->proxy, seat->press_serial,
- yasl_scale_to_logical(pos.x, scale),
- yasl_scale_to_logical(pos.y, scale));
+ yasl_private_scale_to_logical(pos.x, scale),
+ yasl_private_scale_to_logical(pos.y, scale));
return true;
}
diff --git a/src/platform/x11/keymap.c b/src/platform/x11/keymap.c
index 3c566b3..35178dd 100644
--- a/src/platform/x11/keymap.c
+++ b/src/platform/x11/keymap.c
@@ -2,7 +2,7 @@
#include <string.h>
/* XKB standard physical key names, independent of server numeric keycodes. */
-enum yasl_key yasl_key_from_xkb_name(const char name[4])
+enum yasl_key yasl_private_key_from_xkb_name(const char name[4])
{
static const struct { char name[4]; enum yasl_key key; } keys[] = {
{{'T', 'L', 'D', 'E'}, YASL_KEY_GRAVE},
diff --git a/src/platform/x11/keymap.h b/src/platform/x11/keymap.h
index 8114fb5..9bb009d 100644
--- a/src/platform/x11/keymap.h
+++ b/src/platform/x11/keymap.h
@@ -1,8 +1,8 @@
-#ifndef YASL_X11_KEYMAP_H
-#define YASL_X11_KEYMAP_H
+#ifndef YASL_PRIVATE_X11_KEYMAP_H
+#define YASL_PRIVATE_X11_KEYMAP_H
#include "yasl/keycodes.h"
-enum yasl_key yasl_key_from_xkb_name(const char name[4]);
+enum yasl_key yasl_private_key_from_xkb_name(const char name[4]);
#endif
diff --git a/src/platform/x11/native.c b/src/platform/x11/native.c
index 249adec..fffe171 100644
--- a/src/platform/x11/native.c
+++ b/src/platform/x11/native.c
@@ -1,14 +1,14 @@
#include "common/backend.h"
-#include "yasl/native/x11.h"
+#include "common/private_native_x11.h"
-Display *yasl_x11_display_get_display(struct yasl_display *d)
+Display *yasl_private_x11_display_get_display(struct yasl_private_display *d)
{
- return (d && yasl_display_backend(d) == YASL_BACKEND_X11) ?
- (Display *)yasl_display_get_native_handle(d) : NULL;
+ return (d && yasl_private_display_backend(d) == YASL_PRIVATE_BACKEND_X11) ?
+ (Display *)yasl_private_display_get_native_handle(d) : NULL;
}
-uintptr_t yasl_x11_surface_get_window(struct yasl_surface *s)
+uintptr_t yasl_private_x11_surface_get_window(struct yasl_surface *s)
{
- return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_X11) ?
- (uintptr_t)yasl_surface_get_native_handle(s) : 0;
+ return (s && s->display && yasl_private_display_backend(s->display) == YASL_PRIVATE_BACKEND_X11) ?
+ (uintptr_t)yasl_private_surface_get_native_handle(s) : 0;
}
diff --git a/src/platform/x11/window.c b/src/platform/x11/window.c
index 004d56c..8129dd5 100644
--- a/src/platform/x11/window.c
+++ b/src/platform/x11/window.c
@@ -16,6 +16,10 @@
#include <X11/keysym.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XShm.h>
+#if YASL_HAS_EGL
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
#include <sys/ipc.h>
#include <sys/shm.h>
#if YASL_HAS_XRANDR
@@ -35,7 +39,7 @@
#include <wchar.h>
#define TEXT_LIMIT (16 * 1024 * 1024)
-#define PASTE_TIMEOUT_NS YASL_MS_TO_NS(30000)
+#define PASTE_TIMEOUT_NS YASL_PRIVATE_MS_TO_NS(30000)
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
@@ -50,26 +54,33 @@ struct x11_surface {
struct x11_surface *dead_next;
Window window;
GC gc;
+ Colormap colormap;
XIC ic;
+#if YASL_HAS_EGL
+ EGLContext gl_context;
+ EGLSurface gl_surface;
+ EGLConfig gl_config;
+#endif
XImage *image;
uint32_t *pixels;
bool shm_active;
XShmSegmentInfo shm_info;
- struct yasl_vector2i size;
- const struct yasl_window_cbs *cbs;
+ struct yasl_private_vector2i size;
+ const struct yasl_private_window_cbs *cbs;
void *ud;
struct input_queue input;
- struct yasl_frame frame;
- struct yasl_damage_list damage;
- struct yasl_frame_clock clock;
+ struct yasl_private_frame frame;
+ struct yasl_private_damage_list damage;
+ struct yasl_private_frame_clock clock;
bool want_draw, drawing, presented, destroyed;
+ bool focused;
struct x11_surface *parent;
bool is_popup;
- struct yasl_vector2i content_offset;
+ struct yasl_private_vector2i content_offset;
char *ime_preedit;
int ime_cursor_begin;
int ime_cursor_end;
- struct yasl_rect2i ime_caret;
+ struct yasl_private_rect2i ime_caret;
};
struct paste_request {
@@ -79,33 +90,45 @@ struct paste_request {
Window window;
Atom selection;
uint64_t id;
- yasl_timer_id timeout;
+ yasl_private_timer_id timeout;
};
struct tablet_axis {
int number;
double min, max, value;
+ bool valid;
+};
+
+struct x11_scroll_axis {
+ int number;
+ double increment, value;
+ bool valid, initialized;
+ int type;
};
struct x11_pointer {
struct x11_pointer *next;
int id;
- enum yasl_pointer_device device;
- struct tablet_axis pressure, tilt_x, tilt_y;
+ enum yasl_private_pointer_device device;
+ unsigned tool;
+ struct tablet_axis pressure, tilt_x, tilt_y, rotation, distance, tangential, wheel;
+ struct x11_scroll_axis scroll_x, scroll_y;
+ uint32_t buttons;
+ bool finger_scroll;
};
struct x11_display {
- struct yasl_display base;
+ struct yasl_private_display base;
Display *native;
int screen;
- struct yasl_loop *loop;
+ struct yasl_private_loop *loop;
int watch;
struct x11_surface *surfaces, *dead;
int depth;
XIM im;
Window selection_window;
Atom protocols, delete_window, utf8, clipboard, targets, paste_property, incr;
- Atom net_name, net_state, fullscreen, maximized_h, maximized_v;
+ Atom net_name, net_state, fullscreen, maximized_h, maximized_v, motif_hints;
Atom xdnd_aware, xdnd_enter, xdnd_position, xdnd_status, xdnd_leave, xdnd_drop, xdnd_finished;
Atom xdnd_selection, xdnd_action_copy, xdnd_type_list, uri_list;
char *selection[2];
@@ -121,20 +144,26 @@ struct x11_display {
int xkb_event;
enum yasl_key keys[256];
Cursor cursors[16];
- Atom abs_pressure, abs_tilt_x, abs_tilt_y, tool_type, eraser;
+ Atom abs_pressure, abs_tilt_x, abs_tilt_y, abs_rotation, abs_distance, abs_tangential, abs_wheel;
+ Atom tool_type, eraser;
+ Atom brush, airbrush, pencil;
struct x11_pointer *pointers;
+#if YASL_HAS_EGL
+ EGLDisplay egl;
+ bool egl_ready;
+#endif
struct {
bool active;
struct x11_surface *origin;
struct x11_surface *carried;
- struct yasl_vector2i carry_offset;
- struct yasl_drag_listener listener;
+ struct yasl_private_vector2i carry_offset;
+ struct yasl_private_drag_listener listener;
void *ud;
struct x11_surface *hover;
- struct yasl_vector2i hover_pos;
+ struct yasl_private_vector2i hover_pos;
Window icon_window;
Pixmap icon_pixmap;
- struct yasl_vector2i hotspot;
+ struct yasl_private_vector2i hotspot;
} drag;
struct {
Window source;
@@ -142,7 +171,7 @@ struct x11_display {
bool accepts;
bool has_uri_list;
struct x11_surface *surface;
- struct yasl_vector2i pos;
+ struct yasl_private_vector2i pos;
Time time;
} xdnd;
struct {
@@ -153,11 +182,11 @@ struct x11_display {
} pending_drop;
};
-static bool place(struct yasl_surface *base, struct yasl_vector2i at);
-static void drag_end(struct x11_display *d, enum yasl_drag_end how);
-static void drag_cancel(struct yasl_display *base);
+static bool place(struct yasl_surface *base, struct yasl_private_vector2i at);
+static void drag_end(struct x11_display *d, enum yasl_private_drag_end how);
+static void drag_cancel(struct yasl_private_display *base);
static void schedule_redraw(struct yasl_surface *base);
-static uint64_t paste_timeout(void *ud, yasl_timer_id id, uint64_t interval_ns);
+static uint64_t paste_timeout(void *ud, yasl_private_timer_id id, uint64_t interval_ns);
static void leave(struct x11_display *d)
{
@@ -169,7 +198,7 @@ static void leave(struct x11_display *d)
}
}
-static void push(struct x11_surface *s, struct yasl_event event,
+static void push(struct x11_surface *s, struct yasl_private_event event,
const char *text, size_t len)
{
if (s->destroyed) return;
@@ -189,39 +218,39 @@ static unsigned long component(uint32_t color, unsigned long mask)
return (((unsigned long)color * m + 127) / 255) << shift;
}
-static void drag_set_hover(struct x11_display *d, struct x11_surface *s, struct yasl_vector2i pos)
+static void drag_set_hover(struct x11_display *d, struct x11_surface *s, struct yasl_private_vector2i pos)
{
if (!d->drag.active) return;
if (d->drag.hover && d->drag.hover != s) {
struct x11_surface *old = d->drag.hover;
- struct yasl_vector2i old_pos = d->drag.hover_pos;
+ struct yasl_private_vector2i old_pos = d->drag.hover_pos;
d->drag.hover = NULL;
if (!old->destroyed)
- yasl_surface_notify_drag(&old->base, YASL_DRAG_LEAVE, old_pos);
+ yasl_private_surface_notify_drag(&old->base, YASL_PRIVATE_DRAG_LEAVE, old_pos);
if (!d->drag.active || (s && s->destroyed)) return;
}
if (s && s->destroyed) return;
d->drag.hover = s;
d->drag.hover_pos = pos;
if (s && !s->destroyed)
- yasl_surface_notify_drag(&s->base, YASL_DRAG_OVER, pos);
+ yasl_private_surface_notify_drag(&s->base, YASL_PRIVATE_DRAG_OVER, pos);
}
-static void drag_leave_hover(struct x11_display *d, struct x11_surface *s, struct yasl_vector2i pos)
+static void drag_leave_hover(struct x11_display *d, struct x11_surface *s, struct yasl_private_vector2i pos)
{
if (!d->drag.active || d->drag.hover != s) return;
d->drag.hover = NULL;
if (s && !s->destroyed)
- yasl_surface_notify_drag(&s->base, YASL_DRAG_LEAVE, pos);
+ yasl_private_surface_notify_drag(&s->base, YASL_PRIVATE_DRAG_LEAVE, pos);
}
static void drag_drop_hover(struct x11_display *d)
{
if (!d->drag.active) return;
- drag_end(d, YASL_DRAG_DROPPED);
+ drag_end(d, YASL_PRIVATE_DRAG_DROPPED);
}
-static int yasl_x11_error_handler(Display *native, XErrorEvent *event)
+static int yasl_private_x11_error_handler(Display *native, XErrorEvent *event)
{
(void)native;
(void)event;
@@ -230,7 +259,7 @@ static int yasl_x11_error_handler(Display *native, XErrorEvent *event)
return 0;
}
-static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, int ry, struct yasl_vector2i *out_pos)
+static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, int ry, struct yasl_private_vector2i *out_pos)
{
if (!d->native) return NULL;
Window ignore_icon = d->drag.icon_window;
@@ -243,7 +272,7 @@ static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, in
if (XTranslateCoordinates(d->native, RootWindow(d->native, d->screen),
s->window, rx, ry, &tx, &ty, &sub)) {
if (tx >= 0 && ty >= 0 && tx < s->size.x && ty < s->size.y) {
- if (out_pos) *out_pos = (struct yasl_vector2i){tx, ty};
+ if (out_pos) *out_pos = (struct yasl_private_vector2i){tx, ty};
return s;
}
}
@@ -253,19 +282,31 @@ static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, in
static uint32_t modifiers(unsigned state)
{
- return ((state & ShiftMask) ? YASL_MOD_SHIFT : 0) |
- ((state & ControlMask) ? YASL_MOD_CTRL : 0) |
- ((state & Mod1Mask) ? YASL_MOD_ALT : 0) |
- ((state & Mod4Mask) ? YASL_MOD_SUPER : 0) |
- ((state & LockMask) ? YASL_MOD_CAPS : 0);
+ return ((state & ShiftMask) ? YASL_PRIVATE_MOD_SHIFT : 0) |
+ ((state & ControlMask) ? YASL_PRIVATE_MOD_CTRL : 0) |
+ ((state & Mod1Mask) ? YASL_PRIVATE_MOD_ALT : 0) |
+ ((state & Mod4Mask) ? YASL_PRIVATE_MOD_SUPER : 0) |
+ ((state & LockMask) ? YASL_PRIVATE_MOD_CAPS : 0);
}
static void pointer_info(struct x11_display *d, struct x11_pointer *p,
const XIDeviceInfo *info)
{
p->id = info->deviceid;
- p->device = YASL_PTR_DEV_MOUSE;
+ p->device = YASL_PRIVATE_PTR_DEV_MOUSE;
+ p->tool = 0;
+ p->buttons = 0;
p->pressure.number = p->tilt_x.number = p->tilt_y.number = -1;
+ p->rotation.number = p->distance.number = p->tangential.number = p->wheel.number = -1;
+ p->scroll_x.number = p->scroll_y.number = -1;
+ if (info->name) {
+ for (const char *s = info->name; *s; s++) {
+ if (!strncasecmp(s, "touchpad", 8) || !strncasecmp(s, "trackpad", 8)) {
+ p->finger_scroll = true;
+ break;
+ }
+ }
+ }
bool touch = false;
for (int i = 0; i < info->num_classes; i++) {
XIAnyClassInfo *c = info->classes[i];
@@ -275,17 +316,42 @@ static void pointer_info(struct x11_display *d, struct x11_pointer *p,
if (v->mode != XIModeAbsolute) continue;
struct tablet_axis *axis = v->label == d->abs_pressure ? &p->pressure :
v->label == d->abs_tilt_x ? &p->tilt_x :
- v->label == d->abs_tilt_y ? &p->tilt_y : NULL;
- if (axis) *axis = (struct tablet_axis){v->number, v->min, v->max, v->value};
+ v->label == d->abs_tilt_y ? &p->tilt_y :
+ v->label == d->abs_rotation ? &p->rotation :
+ v->label == d->abs_distance ? &p->distance :
+ v->label == d->abs_tangential ? &p->tangential :
+ v->label == d->abs_wheel ? &p->wheel : NULL;
+ if (axis) *axis = (struct tablet_axis){v->number, v->min, v->max, v->value, true};
+ }
+ for (int i = 0; i < info->num_classes; i++) {
+ XIAnyClassInfo *c = info->classes[i];
+ if (c->type != XIScrollClass) continue;
+ XIScrollClassInfo *scroll = (XIScrollClassInfo *)c;
+ struct x11_scroll_axis *axis = scroll->scroll_type == XIScrollTypeVertical ?
+ &p->scroll_y : scroll->scroll_type == XIScrollTypeHorizontal ? &p->scroll_x : NULL;
+ if (!axis) continue;
+ *axis = (struct x11_scroll_axis){.number = scroll->number,
+ .increment = scroll->increment, .type = scroll->scroll_type};
+ for (int j = 0; j < info->num_classes; j++) {
+ XIAnyClassInfo *vclass = info->classes[j];
+ if (vclass->type != XIValuatorClass) continue;
+ XIValuatorClassInfo *v = (XIValuatorClassInfo *)vclass;
+ if (v->number == scroll->number) {
+ axis->value = v->value;
+ axis->initialized = axis->valid = true;
+ break;
+ }
+ }
}
if (!touch && p->pressure.number >= 0) {
- p->device = YASL_PTR_DEV_PEN;
+ p->device = YASL_PRIVATE_PTR_DEV_PEN;
+ p->tool = 1;
/* Xorg's Wacom and libinput drivers expose separate eraser devices.
* Use the tool property when available, with the device name as a
* fallback for servers (including Xwayland) without that property. */
if (info->name) {
for (const char *s = info->name; *s; s++)
- if (!strncasecmp(s, "eraser", 6)) { p->device = YASL_PTR_DEV_ERASER; break; }
+ if (!strncasecmp(s, "eraser", 6)) { p->device = YASL_PRIVATE_PTR_DEV_ERASER; break; }
}
}
}
@@ -301,17 +367,21 @@ static struct x11_pointer *pointer_for(struct x11_display *d, int id)
struct x11_pointer *p = count ? calloc(1, sizeof(*p)) : NULL;
if (p) {
pointer_info(d, p, info);
- if (p->device == YASL_PTR_DEV_PEN || p->device == YASL_PTR_DEV_ERASER) {
+ if (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER) {
Atom type;
int format;
unsigned long n, after;
unsigned char *value = NULL;
if (XIGetProperty(d->native, id, d->tool_type, 0, 1, False,
XA_ATOM, &type, &format, &n, &after, &value) == Success &&
- type == XA_ATOM && format == 32 && n == 1 && value)
+ type == XA_ATOM && format == 32 && n == 1 && value) {
/* XIGetProperty packs format-32 values as uint32_t, unlike
* XGetWindowProperty's array of native-sized longs. */
- p->device = *(uint32_t *)value == d->eraser ? YASL_PTR_DEV_ERASER : p->device;
+ if (*(uint32_t *)value == d->eraser) p->device = YASL_PRIVATE_PTR_DEV_ERASER;
+ else if (d->brush && *(uint32_t *)value == d->brush) p->tool = 3;
+ else if (d->airbrush && *(uint32_t *)value == d->airbrush) p->tool = 4;
+ else if (d->pencil && *(uint32_t *)value == d->pencil) p->tool = 5;
+ }
if (value) XFree(value);
}
p->next = d->pointers;
@@ -330,21 +400,61 @@ static void clear_pointers(struct x11_display *d)
}
}
-static void update_axes(struct x11_pointer *p, const XIValuatorState *state)
+static uint32_t update_axes(struct x11_pointer *p, const XIValuatorState *state)
{
+ uint32_t changed = 0;
const double *value = state->values;
for (int i = 0; i < state->mask_len * 8; i++) {
if (!XIMaskIsSet(state->mask, i)) continue;
- struct tablet_axis *axes[] = {&p->pressure, &p->tilt_x, &p->tilt_y};
+ struct tablet_axis *axes[] = {&p->pressure, &p->tilt_x, &p->tilt_y, &p->rotation,
+ &p->distance, &p->tangential, &p->wheel};
+ const uint32_t bits[] = {YASL_PRIVATE_PEN_PRESSURE, YASL_PRIVATE_PEN_TILT,
+ YASL_PRIVATE_PEN_TILT, YASL_PRIVATE_PEN_ROTATION, YASL_PRIVATE_PEN_DISTANCE,
+ YASL_PRIVATE_PEN_TANGENTIAL, YASL_PRIVATE_PEN_WHEEL};
for (unsigned a = 0; a < sizeof(axes) / sizeof(axes[0]); a++)
- if (axes[a]->number == i && isfinite(*value)) axes[a]->value = *value;
+ if (axes[a]->number == i && isfinite(*value)) {
+ axes[a]->value = *value;
+ axes[a]->valid = true;
+ changed |= bits[a];
+ }
+ value++;
+ }
+ return changed;
+}
+
+static void update_scroll(struct x11_pointer *p, const XIValuatorState *state,
+ struct yasl_private_pointer_event *out)
+{
+ const double *value = state->values;
+ for (int i = 0; i < state->mask_len * 8; i++) {
+ if (!XIMaskIsSet(state->mask, i)) continue;
+ struct x11_scroll_axis *axes[] = {&p->scroll_x, &p->scroll_y};
+ for (unsigned a = 0; a < 2; a++) {
+ struct x11_scroll_axis *axis = axes[a];
+ if (axis->number != i || !isfinite(*value)) continue;
+ if (axis->initialized) {
+ double delta = *value - axis->value;
+ if (axis->increment != 0 && isfinite(delta)) {
+ double lines = delta / axis->increment;
+ if (a == 0) out->scroll.x += lines;
+ else out->scroll.y += lines;
+ if (lines != 0) {
+ out->scroll_valid |= 1u;
+ out->scroll_source = p->finger_scroll ? 2u : 1u;
+ out->scroll_phase = 2u;
+ }
+ }
+ }
+ axis->value = *value;
+ axis->initialized = true;
+ }
value++;
}
}
static uint16_t pressure_value(const struct tablet_axis *a)
{
- if (a->number < 0 || !(a->max > a->min) || !isfinite(a->value)) return 0;
+ if (a->number < 0 || !(a->max > a->min) || !a->valid || !isfinite(a->value)) return 0;
double v = (a->value - a->min) / (a->max - a->min);
return (uint16_t)lround(fmax(0, fmin(1, v)) * 65535);
}
@@ -352,50 +462,121 @@ static uint16_t pressure_value(const struct tablet_axis *a)
static int8_t tilt_value(const struct tablet_axis *a)
{
/* Xorg tablet tilt valuators are already in degrees. */
- return a->number < 0 || !isfinite(a->value) ? 0 :
+ return a->number < 0 || !a->valid || !isfinite(a->value) ? 0 :
(int8_t)lround(fmax(-90, fmin(90, a->value)));
}
-static enum yasl_pointer_button pointer_button(unsigned button)
+static enum yasl_private_pointer_button pointer_button(unsigned button)
+{
+ return button == 1 ? YASL_PRIVATE_BUTTON_PRIMARY :
+ button == 2 ? YASL_PRIVATE_BUTTON_MIDDLE :
+ button == 3 ? YASL_PRIVATE_BUTTON_SECONDARY :
+ button >= 8 && button <= INT16_MAX ? (enum yasl_private_pointer_button)(button - 5) :
+ YASL_PRIVATE_BUTTON_BACK;
+}
+
+static uint32_t pen_axes_valid(const struct x11_pointer *p)
{
- return button == 1 ? YASL_BUTTON_PRIMARY :
- button == 2 ? YASL_BUTTON_MIDDLE :
- button == 3 ? YASL_BUTTON_SECONDARY :
- button >= 8 && button <= INT16_MAX ? (enum yasl_pointer_button)(button - 5) :
- YASL_BUTTON_BACK;
+ return (p->pressure.valid ? YASL_PRIVATE_PEN_PRESSURE : 0) |
+ (p->tilt_x.valid || p->tilt_y.valid ? YASL_PRIVATE_PEN_TILT : 0) |
+ (p->rotation.valid ? YASL_PRIVATE_PEN_ROTATION : 0) |
+ (p->distance.valid ? YASL_PRIVATE_PEN_DISTANCE : 0) |
+ (p->tangential.valid ? YASL_PRIVATE_PEN_TANGENTIAL : 0) |
+ (p->wheel.valid ? YASL_PRIVATE_PEN_WHEEL : 0);
+}
+
+static double axis_normalized(const struct tablet_axis *axis)
+{
+ return axis->valid && axis->max > axis->min && isfinite(axis->value) ?
+ fmax(0, fmin(1, (axis->value - axis->min) / (axis->max - axis->min))) : 0;
+}
+
+static void push_pen_sample(struct x11_surface *s, struct x11_pointer *p,
+ unsigned action, double x, double y, uint32_t changed, unsigned changed_button)
+{
+ if (!p || (p->device != YASL_PRIVATE_PTR_DEV_PEN && p->device != YASL_PRIVATE_PTR_DEV_ERASER)) return;
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_PEN,
+ .pen = {
+ .device_id = (uint64_t)(unsigned)p->id,
+ .tool_id = 0, /* XI2 exposes source IDs, but not a stable per-tool serial. */
+ .x = x, .y = y,
+ .pressure = p->pressure.valid && p->pressure.max > p->pressure.min ?
+ fmax(0, fmin(1, (p->pressure.value - p->pressure.min) /
+ (p->pressure.max - p->pressure.min))) : 0,
+ .tilt_x = p->tilt_x.valid ? fmax(-90, fmin(90, p->tilt_x.value)) : 0,
+ .tilt_y = p->tilt_y.valid ? fmax(-90, fmin(90, p->tilt_y.value)) : 0,
+ .rotation = p->rotation.valid ? p->rotation.value : 0,
+ .distance = axis_normalized(&p->distance),
+ .tangential = p->tangential.valid && p->tangential.max > p->tangential.min ?
+ fmax(-1, fmin(1, 2 * axis_normalized(&p->tangential) - 1)) : 0,
+ .wheel_degrees = p->wheel.valid ? p->wheel.value : 0,
+ .axes_valid = pen_axes_valid(p), .axes_changed = changed,
+ .buttons = p->buttons, .changed_button = changed_button,
+ .in_contact = (p->buttons & YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY)) != 0,
+ .tool = p->device == YASL_PRIVATE_PTR_DEV_ERASER ? 2u : p->tool,
+ .action = action,
+ }}, NULL, 0);
}
static void xi_pointer_event(struct x11_surface *s, const XIDeviceEvent *ev)
{
struct x11_display *d = (struct x11_display *)s->base.display;
struct x11_pointer *p = pointer_for(d, ev->sourceid);
- struct yasl_event event = {
+ struct yasl_private_event event = {
.pointer = {
- .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
- .device = p ? p->device : YASL_PTR_DEV_MOUSE,
+ .pos = {yasl_private_scale_to_device(ev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(ev->event_y, YASL_PRIVATE_SCALE_UNIT)},
+ .device = p ? p->device : YASL_PRIVATE_PTR_DEV_MOUSE,
.mods = modifiers(ev->mods.effective),
},
};
- if (p && (p->device == YASL_PTR_DEV_PEN || p->device == YASL_PTR_DEV_ERASER)) {
- update_axes(p, &ev->valuators);
- if (ev->evtype == XI_ButtonRelease && ev->detail == 1)
+ uint32_t pen_changed = 0;
+ if (p && (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER)) {
+ pen_changed = update_axes(p, &ev->valuators);
+ if (ev->evtype == XI_ButtonRelease && ev->detail == 1) {
p->pressure.value = p->pressure.min;
- event.pointer.pen = (struct yasl_pointer_pen){
+ pen_changed |= p->pressure.valid ? YASL_PRIVATE_PEN_PRESSURE : 0;
+ }
+ if (ev->evtype == XI_ButtonPress || ev->evtype == XI_ButtonRelease) {
+ enum yasl_private_pointer_button button = pointer_button(ev->detail);
+ uint32_t mask = YASL_PRIVATE_BUTTON_BIT(button);
+ if (ev->evtype == XI_ButtonPress) p->buttons |= mask;
+ else p->buttons &= ~mask;
+ }
+ event.pointer.pen = (struct yasl_private_pointer_pen){
pressure_value(&p->pressure), tilt_value(&p->tilt_x), tilt_value(&p->tilt_y)};
}
- if (ev->evtype == XI_Motion) event.type = YASL_EVENT_POINTER_MOTION;
+ if (p) update_scroll(p, &ev->valuators, &event.pointer);
+ if (ev->evtype == XI_Motion) event.type = YASL_PRIVATE_EVENT_POINTER_MOTION;
else if (ev->detail >= 4 && ev->detail <= 7) {
if (ev->evtype == XI_ButtonRelease) return;
- event.type = YASL_EVENT_POINTER_SCROLL;
+ event.type = YASL_PRIVATE_EVENT_POINTER_SCROLL;
if (ev->detail <= 5) event.pointer.scroll.y = ev->detail == 4 ? -1 : 1;
else event.pointer.scroll.x = ev->detail == 6 ? -1 : 1;
+ event.pointer.scroll_valid = 1u;
+ event.pointer.scroll_source = p && p->finger_scroll ? 2u : 1u;
+ event.pointer.scroll_phase = 2u;
} else {
- event.type = ev->evtype == XI_ButtonPress ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ event.type = ev->evtype == XI_ButtonPress ? YASL_PRIVATE_EVENT_POINTER_DOWN : YASL_PRIVATE_EVENT_POINTER_UP;
event.pointer.button = pointer_button(ev->detail);
}
d->mods = event.pointer.mods;
+ if (p && (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER) &&
+ ev->detail != 4 && ev->detail != 5 && ev->detail != 6 && ev->detail != 7) {
+ unsigned action = ev->evtype == XI_Motion ? YASL_PRIVATE_PEN_MOVE :
+ ev->evtype == XI_ButtonPress ? (ev->detail == 1 ? YASL_PRIVATE_PEN_DOWN : YASL_PRIVATE_PEN_BUTTON) :
+ (ev->detail == 1 ? YASL_PRIVATE_PEN_UP : YASL_PRIVATE_PEN_BUTTON);
+ push_pen_sample(s, p, action, ev->event_x, ev->event_y, pen_changed,
+ ev->evtype == XI_Motion ? 0u : (unsigned)ev->detail);
+ }
push(s, event, NULL, 0);
+ if (event.type == YASL_PRIVATE_EVENT_POINTER_MOTION && event.pointer.scroll_valid) {
+ event.type = YASL_PRIVATE_EVENT_POINTER_SCROLL;
+ event.pointer.pos = (struct yasl_private_vector2i){
+ yasl_private_scale_to_device(ev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(ev->event_y, YASL_PRIVATE_SCALE_UNIT)};
+ push(s, event, NULL, 0);
+ }
}
static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
@@ -403,15 +584,20 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
if (cookie->evtype == XI_HierarchyChanged || cookie->evtype == XI_DeviceChanged) {
if (cookie->evtype == XI_DeviceChanged &&
((XIDeviceChangedEvent *)cookie->data)->reason == XISlaveSwitch) return;
+ for (struct x11_pointer *p = d->pointers; p; p = p->next) {
+ if (!p->buttons) continue;
+ for (struct x11_surface *s = d->surfaces; s; s = s->next)
+ push_pen_sample(s, p, YASL_PRIVATE_PEN_CANCEL, 0, 0, 0, 0);
+ }
clear_pointers(d);
if (cookie->evtype == XI_HierarchyChanged &&
(((XIHierarchyEvent *)cookie->data)->flags &
(XISlaveRemoved | XIDeviceDisabled | XISlaveDetached | XIMasterRemoved))) {
/* Removal/disable may interrupt a drag before a release arrives. */
if (d->drag.active)
- drag_end(d, YASL_DRAG_CANCELLED);
+ drag_end(d, YASL_PRIVATE_DRAG_CANCELLED);
for (struct x11_surface *s = d->surfaces; s; s = s->next)
- push(s, (struct yasl_event){.type = YASL_EVENT_INPUT_RESET}, NULL, 0);
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_INPUT_RESET}, NULL, 0);
}
return;
}
@@ -430,22 +616,22 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
XMoveWindow(d->native, d->drag.icon_window,
(int)round(mev->root_x) - d->drag.hotspot.x,
(int)round(mev->root_y) - d->drag.hotspot.y);
- struct yasl_vector2i hpos = {yasl_scale_to_device(mev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(mev->event_y, YASL_SCALE_UNIT)};
+ struct yasl_private_vector2i hpos = {yasl_private_scale_to_device(mev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(mev->event_y, YASL_PRIVATE_SCALE_UNIT)};
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, (int)round(mev->root_x), (int)round(mev->root_y), &hpos) : s;
drag_set_hover(d, hsurf, hpos);
} else if (cookie->evtype == XI_Enter && d->drag.active) {
const XIEnterEvent *eev = cookie->data;
- struct yasl_vector2i hpos = {yasl_scale_to_device(eev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(eev->event_y, YASL_SCALE_UNIT)};
+ struct yasl_private_vector2i hpos = {yasl_private_scale_to_device(eev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(eev->event_y, YASL_PRIVATE_SCALE_UNIT)};
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, (int)round(eev->root_x), (int)round(eev->root_y), &hpos) : s;
drag_set_hover(d, hsurf, hpos);
} else if (cookie->evtype == XI_Leave && d->drag.active) {
const XIEnterEvent *lev = cookie->data;
- struct yasl_vector2i lpos = {yasl_scale_to_device(lev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(lev->event_y, YASL_SCALE_UNIT)};
+ struct yasl_private_vector2i lpos = {yasl_private_scale_to_device(lev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(lev->event_y, YASL_PRIVATE_SCALE_UNIT)};
drag_leave_hover(d, s, lpos);
} else if (cookie->evtype == XI_ButtonRelease && d->drag.active) {
drag_drop_hover(d);
@@ -455,24 +641,35 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
else {
const XIEnterEvent *ev = cookie->data;
struct x11_pointer *p = pointer_for(d, ev->sourceid);
- if (p) p->pressure.value = p->pressure.min;
- push(s, (struct yasl_event){
- .type = cookie->evtype == XI_Leave ? YASL_EVENT_POINTER_LEAVE : YASL_EVENT_POINTER_MOTION,
+ if (p && cookie->evtype == XI_Leave) {
+ p->pressure.value = p->pressure.min;
+ if (p->pressure.valid) push_pen_sample(s, p, YASL_PRIVATE_PEN_LEAVE,
+ ev->event_x, ev->event_y, YASL_PRIVATE_PEN_PRESSURE, 0);
+ } else if (p && (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER)) {
+ push_pen_sample(s, p, YASL_PRIVATE_PEN_ENTER, ev->event_x, ev->event_y, 0, 0);
+ }
+ push(s, (struct yasl_private_event){
+ .type = cookie->evtype == XI_Leave ? YASL_PRIVATE_EVENT_POINTER_LEAVE : YASL_PRIVATE_EVENT_POINTER_MOTION,
.pointer = {
- .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
- .device = p ? p->device : YASL_PTR_DEV_MOUSE,
+ .pos = {yasl_private_scale_to_device(ev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(ev->event_y, YASL_PRIVATE_SCALE_UNIT)},
+ .device = p ? p->device : YASL_PRIVATE_PTR_DEV_MOUSE,
.mods = modifiers(ev->mods.effective),
},
}, NULL, 0);
}
}
-static bool resize(struct x11_surface *s, struct yasl_vector2i size)
+static bool resize(struct x11_surface *s, struct yasl_private_vector2i size)
{
if (size.x <= 0 || size.y <= 0 || size.x > 32767 || size.y > 32767 ||
(size_t)size.x > SIZE_MAX / sizeof(uint32_t) / (size_t)size.y)
return false;
+ if (s->base.presenter != YASL_PRIVATE_PRESENTER_CPU) {
+ s->size = size;
+ s->base.size = size;
+ return true;
+ }
if (s->image && size.x == s->size.x && size.y == s->size.y) return true;
struct x11_display *d = (struct x11_display *)s->base.display;
if (!d->native) {
@@ -480,7 +677,7 @@ static bool resize(struct x11_surface *s, struct yasl_vector2i size)
s->want_draw = true;
return true;
}
- uint64_t start = yasl_loop_now_ns();
+ uint64_t start = yasl_private_loop_now_ns();
/* The presented frame goes with the old pixels. */
s->presented = false;
@@ -557,9 +754,9 @@ static bool resize(struct x11_surface *s, struct yasl_vector2i size)
s->pixels = pixels;
s->size = size;
s->base.size = size;
- s->base.scale_120 = YASL_SCALE_UNIT;
+ s->base.scale_120 = YASL_PRIVATE_SCALE_UNIT;
s->want_draw = true;
- yasl_clock_note_resize(&s->clock, yasl_loop_now_ns() - start);
+ yasl_private_clock_note_resize(&s->clock, yasl_private_loop_now_ns() - start);
return true;
}
@@ -575,7 +772,7 @@ static void cancel_pastes(struct x11_display *d, struct x11_surface *target)
p = &r->next;
} else if (!target) {
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
XDestroyWindow(d->native, r->window);
free(r);
} else {
@@ -584,7 +781,7 @@ static void cancel_pastes(struct x11_display *d, struct x11_surface *target)
}
}
-static uint64_t paste_timeout(void *ud, yasl_timer_id id, uint64_t interval_ns)
+static uint64_t paste_timeout(void *ud, yasl_private_timer_id id, uint64_t interval_ns)
{
(void)id;
(void)interval_ns;
@@ -597,7 +794,7 @@ static uint64_t paste_timeout(void *ud, yasl_timer_id id, uint64_t interval_ns)
r->timeout = 0; /* The loop retires this one-shot timer after the callback. */
XDestroyWindow(d->native, r->window);
if (s && !s->destroyed)
- yasl_surface_complete_paste(&s->base, r->id, YASL_TRANSFER_FAILED, NULL, 0);
+ yasl_private_surface_complete_paste(&s->base, r->id, YASL_PRIVATE_TRANSFER_FAILED, NULL, 0);
free(r);
return 0;
}
@@ -609,7 +806,7 @@ static void surface_destroy(struct yasl_surface *base)
struct x11_display *d = (struct x11_display *)base->display;
if (d->drag.active) {
if (d->drag.origin == s || d->drag.carried == s)
- drag_end(d, YASL_DRAG_CANCELLED);
+ drag_end(d, YASL_PRIVATE_DRAG_CANCELLED);
else if (d->drag.hover == s)
d->drag.hover = NULL;
}
@@ -627,6 +824,10 @@ static void surface_destroy(struct yasl_surface *base)
free(s->ime_preedit);
s->ime_preedit = NULL;
if (s->ic) XDestroyIC(s->ic);
+#if YASL_HAS_EGL
+ if (s->gl_context && d->egl_ready) eglDestroyContext(d->egl, s->gl_context);
+ if (s->gl_surface && d->egl_ready) eglDestroySurface(d->egl, s->gl_surface);
+#endif
if (s->shm_active) {
XShmDetach(d->native, &s->shm_info);
if (s->image) XDestroyImage(s->image);
@@ -643,6 +844,7 @@ static void surface_destroy(struct yasl_surface *base)
if (d->native) {
if (s->gc) XFreeGC(d->native, s->gc);
if (s->window) XDestroyWindow(d->native, s->window);
+ if (s->colormap) XFreeColormap(d->native, s->colormap);
}
input_queue_clear(&s->input);
if (d->depth) {
@@ -652,11 +854,11 @@ static void surface_destroy(struct yasl_surface *base)
}
static void set_callbacks(struct yasl_surface *base,
- const struct yasl_window_cbs *cbs, void *ud)
+ const struct yasl_private_window_cbs *cbs, void *ud)
{
struct x11_surface *s = (struct x11_surface *)base;
if (s->destroyed) return;
- s->base.callbacks = cbs ? *cbs : (struct yasl_window_cbs){0};
+ s->base.callbacks = cbs ? *cbs : (struct yasl_private_window_cbs){0};
s->cbs = &s->base.callbacks;
s->base.ud = ud;
s->ud = ud;
@@ -685,7 +887,7 @@ static bool net_message(struct x11_surface *s, Atom type,
SubstructureRedirectMask | SubstructureNotifyMask, &event) != 0;
}
-static bool surface_set_size(struct yasl_surface *base, struct yasl_vector2i size)
+static bool surface_set_size(struct yasl_surface *base, struct yasl_private_vector2i size)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -817,7 +1019,7 @@ static char *xim_text_dup(const XIMText *text, size_t *len)
if (converted != text->length) { free(out); return NULL; }
}
out[used] = '\0';
- if (!yasl_utf8_validate(out, used)) { free(out); return NULL; }
+ if (!yasl_private_utf8_validate(out, used)) { free(out); return NULL; }
*len = used;
return out;
}
@@ -831,7 +1033,7 @@ static void xim_preedit_done(XIM im, XPointer client_data, XPointer call_data)
free(s->ime_preedit);
s->ime_preedit = NULL;
s->ime_cursor_begin = s->ime_cursor_end = -1;
- yasl_surface_notify_composition(&s->base, NULL, -1, -1);
+ yasl_private_surface_notify_composition(&s->base, NULL, -1, -1);
}
static int xim_preedit_start(XIM im, XPointer client_data, XPointer call_data)
@@ -880,7 +1082,7 @@ static void xim_preedit_draw(XIM im, XPointer client_data, XPointer call_data)
int caret = draw->caret < 0 ? -1 : (int)utf8_offset_for_chars(
s->ime_preedit ? s->ime_preedit : "", new_len, draw->caret);
s->ime_cursor_begin = s->ime_cursor_end = caret;
- yasl_surface_notify_composition(&s->base, s->ime_preedit, caret, caret);
+ yasl_private_surface_notify_composition(&s->base, s->ime_preedit, caret, caret);
}
static void xim_preedit_caret(XIM im, XPointer client_data, XPointer call_data)
@@ -892,7 +1094,7 @@ static void xim_preedit_caret(XIM im, XPointer client_data, XPointer call_data)
int offset = caret->position < 0 ? -1 : (int)utf8_offset_for_chars(
s->ime_preedit, strlen(s->ime_preedit), caret->position);
s->ime_cursor_begin = s->ime_cursor_end = offset;
- yasl_surface_notify_composition(&s->base, s->ime_preedit, offset, offset);
+ yasl_private_surface_notify_composition(&s->base, s->ime_preedit, offset, offset);
}
static XIC create_ic(struct x11_display *d, struct x11_surface *s)
@@ -923,22 +1125,35 @@ static XIC create_ic(struct x11_display *d, struct x11_surface *s)
return ic;
}
-static struct yasl_surface *create_toplevel(struct yasl_display *base,
- const struct yasl_window_spec *spec, void *graphics_device)
+static struct yasl_surface *create_toplevel_visual(struct yasl_private_display *base,
+ const struct yasl_private_window_spec *spec, Visual *visual, int depth,
+ enum yasl_private_presenter presenter)
{
- (void)graphics_device;
if (!spec) return NULL;
struct x11_display *d = (struct x11_display *)base;
struct x11_surface *s = calloc(1, sizeof(*s));
if (!s) return NULL;
s->base.display = base;
- s->clock.refresh_ns = YASL_REFRESH_DEFAULT_NS;
+ s->base.creation_flags = spec->flags | (spec->external_gpu ? 0u : YASL_PRIVATE_SURFACE_CPU);
+ s->base.presenter = presenter;
+ s->clock.refresh_ns = YASL_PRIVATE_REFRESH_DEFAULT_NS;
if (!resize(s, spec->size)) { free(s); return NULL; }
- s->window = XCreateSimpleWindow(d->native, RootWindow(d->native, d->screen),
- 0, 0, (unsigned)spec->size.x, (unsigned)spec->size.y, 0, 0, 0);
+ if (!visual) visual = DefaultVisual(d->native, d->screen);
+ if (!depth) depth = DefaultDepth(d->native, d->screen);
+ s->colormap = XCreateColormap(d->native, RootWindow(d->native, d->screen), visual, AllocNone);
+ XSetWindowAttributes attrs = {.colormap = s->colormap, .border_pixel = 0, .background_pixel = 0};
+ s->window = XCreateWindow(d->native, RootWindow(d->native, d->screen), 0, 0,
+ (unsigned)spec->size.x, (unsigned)spec->size.y, 0, depth, InputOutput,
+ visual, CWBorderPixel | CWBackPixel | CWColormap, &attrs);
+ if (!s->window) {
+ XFreeColormap(d->native, s->colormap);
+ free(s);
+ errno = ENODEV;
+ return NULL;
+ }
s->base.native_handle = (void *)(uintptr_t)s->window;
s->base.size = s->size;
- s->base.scale_120 = YASL_SCALE_UNIT;
+ s->base.scale_120 = YASL_PRIVATE_SCALE_UNIT;
s->gc = XCreateGC(d->native, s->window, 0, NULL);
XSelectInput(d->native, s->window, ExposureMask | StructureNotifyMask |
FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask |
@@ -955,6 +1170,19 @@ static struct yasl_surface *create_toplevel(struct yasl_display *base,
XISelectEvents(d->native, s->window, &mask, 1);
}
XSetWMProtocols(d->native, s->window, &d->delete_window, 1);
+ if (spec->flags & YASL_PRIVATE_SURFACE_UNDECORATED) {
+ struct { unsigned long flags, functions, decorations; long input_mode; unsigned long status; } hints = {
+ .flags = 1, .decorations = 0,
+ };
+ XChangeProperty(d->native, s->window, d->motif_hints, d->motif_hints, 32,
+ PropModeReplace, (unsigned char *)&hints, 5);
+ }
+ if (spec->flags & YASL_PRIVATE_SURFACE_FIXED_SIZE) {
+ XSizeHints size_hints = {.flags = PMinSize | PMaxSize,
+ .min_width = spec->size.x, .max_width = spec->size.x,
+ .min_height = spec->size.y, .max_height = spec->size.y};
+ XSetWMNormalHints(d->native, s->window, &size_hints);
+ }
XClassHint hint = { .res_name = d->app_id, .res_class = d->app_id };
XSetClassHint(d->native, s->window, &hint);
Atom xdnd_version = 5;
@@ -967,17 +1195,197 @@ static struct yasl_surface *create_toplevel(struct yasl_display *base,
if (spec->fullscreen) {
XChangeProperty(d->native, s->window, d->net_state, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&d->fullscreen, 1);
- s->base.state |= YASL_STATE_FULLSCREEN;
+ s->base.state |= YASL_PRIVATE_STATE_FULLSCREEN;
}
- XMapWindow(d->native, s->window);
+ if (!(spec->flags & YASL_PRIVATE_SURFACE_HIDDEN)) XMapWindow(d->native, s->window);
XFlush(d->native);
return &s->base;
}
+static struct yasl_surface *create_toplevel(struct yasl_private_display *base,
+ const struct yasl_private_window_spec *spec, void *graphics_device)
+{
+ if (!spec) return NULL;
+ if (graphics_device) { errno = ENOTSUP; return NULL; }
+ return create_toplevel_visual(base, spec, NULL, 0,
+ spec->external_gpu ? YASL_PRIVATE_PRESENTER_NONE : YASL_PRIVATE_PRESENTER_CPU);
+}
+
+#if YASL_HAS_EGL
+static bool egl_open(struct x11_display *d)
+{
+ if (d->egl_ready) return true;
+ d->egl = eglGetDisplay((EGLNativeDisplayType)d->native);
+ EGLint major = 0, minor = 0;
+ if (d->egl == EGL_NO_DISPLAY || !eglInitialize(d->egl, &major, &minor)) {
+ errno = ENOTSUP;
+ return false;
+ }
+ d->egl_ready = true;
+ return true;
+}
+
+static struct yasl_surface *create_gl_surface(struct yasl_private_display *base,
+ const struct yasl_private_window_spec *spec, const int *attrs,
+ struct yasl_surface *share)
+{
+ if (!spec) { errno = EINVAL; return NULL; }
+ struct x11_display *d = (struct x11_display *)base;
+ struct yasl_private_gl_options options;
+ if (!yasl_private_gl_parse_options(attrs, &options)) { errno = EINVAL; return NULL; }
+ if (!egl_open(d)) return NULL;
+ if (options.srgb) {
+ const char *extensions = eglQueryString(d->egl, EGL_EXTENSIONS);
+ if (!extensions || !strstr(extensions, "EGL_KHR_gl_colorspace")) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+ }
+
+ EGLint renderable = options.api == YASL_PRIVATE_GL_OPENGL_ES ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT;
+ EGLint config_attrs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, renderable,
+ EGL_RED_SIZE, options.red_bits,
+ EGL_GREEN_SIZE, options.green_bits,
+ EGL_BLUE_SIZE, options.blue_bits,
+ EGL_ALPHA_SIZE, options.alpha_bits,
+ EGL_DEPTH_SIZE, options.depth_bits,
+ EGL_STENCIL_SIZE, options.stencil_bits,
+ EGL_SAMPLE_BUFFERS, options.samples > 0 ? 1 : 0,
+ EGL_SAMPLES, options.samples,
+ EGL_NONE,
+ };
+ EGLConfig config = NULL;
+ EGLint count = 0;
+ if (!eglChooseConfig(d->egl, config_attrs, &config, 1, &count) || !count) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+ EGLint visual_id = 0, depth = 0;
+ if (!eglGetConfigAttrib(d->egl, config, EGL_NATIVE_VISUAL_ID, &visual_id) ||
+ !eglGetConfigAttrib(d->egl, config, EGL_BUFFER_SIZE, &depth)) {
+ errno = ENODEV;
+ return NULL;
+ }
+ XVisualInfo visual_query = {.visualid = (VisualID)visual_id};
+ int visual_count = 0;
+ XVisualInfo *visual_info = XGetVisualInfo(d->native, VisualIDMask, &visual_query, &visual_count);
+ if (!visual_info || !visual_count) {
+ if (visual_info) XFree(visual_info);
+ errno = ENODEV;
+ return NULL;
+ }
+ Visual *visual = visual_info[0].visual;
+ depth = visual_info[0].depth;
+ struct yasl_private_window_spec gl_spec = *spec;
+ gl_spec.external_gpu = true;
+ gl_spec.flags &= ~YASL_PRIVATE_SURFACE_CPU;
+ struct yasl_surface *base_surface = create_toplevel_visual(base, &gl_spec, visual, depth,
+ YASL_PRIVATE_PRESENTER_GL);
+ XFree(visual_info);
+ if (!base_surface) return NULL;
+ struct x11_surface *s = (struct x11_surface *)base_surface;
+ s->gl_config = config;
+ EGLint surface_attrs[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE};
+ s->gl_surface = eglCreateWindowSurface(d->egl, config,
+ (EGLNativeWindowType)s->window, options.srgb ? surface_attrs : NULL);
+ if (s->gl_surface == EGL_NO_SURFACE) {
+ surface_destroy(base_surface);
+ errno = ENODEV;
+ return NULL;
+ }
+ if (options.api == YASL_PRIVATE_GL_OPENGL) {
+ if (!eglBindAPI(EGL_OPENGL_API)) { surface_destroy(base_surface); errno = ENOTSUP; return NULL; }
+ } else if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ surface_destroy(base_surface); errno = ENOTSUP; return NULL;
+ }
+ EGLContext share_context = EGL_NO_CONTEXT;
+ if (share) {
+ struct x11_surface *shared = (struct x11_surface *)share;
+ if (share->display != base || shared->base.presenter != YASL_PRIVATE_PRESENTER_GL ||
+ shared->gl_context == EGL_NO_CONTEXT) {
+ surface_destroy(base_surface); errno = EINVAL; return NULL;
+ }
+ share_context = shared->gl_context;
+ }
+ EGLint context_attrs[12];
+ EGLint n = 0;
+ context_attrs[n++] = EGL_CONTEXT_MAJOR_VERSION;
+ context_attrs[n++] = options.major;
+ context_attrs[n++] = EGL_CONTEXT_MINOR_VERSION;
+ context_attrs[n++] = options.minor;
+ if (options.api == YASL_PRIVATE_GL_OPENGL && options.profile != YASL_PRIVATE_GL_ANY) {
+ context_attrs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
+ context_attrs[n++] = options.profile == YASL_PRIVATE_GL_CORE ?
+ EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
+ }
+ EGLint context_flags = (options.debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0) |
+ (options.forward_compat ? EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR : 0);
+ if (context_flags) {
+ context_attrs[n++] = EGL_CONTEXT_FLAGS_KHR;
+ context_attrs[n++] = context_flags;
+ }
+ context_attrs[n] = EGL_NONE;
+ s->gl_context = eglCreateContext(d->egl, config, share_context, context_attrs);
+ if (s->gl_context == EGL_NO_CONTEXT) {
+ surface_destroy(base_surface);
+ errno = ENOTSUP;
+ return NULL;
+ }
+ return base_surface;
+}
+
+static bool gl_make_current(struct yasl_private_display *base, struct yasl_surface *surface)
+{
+ struct x11_display *d = (struct x11_display *)base;
+ if (!d->egl_ready) { errno = ENOTSUP; return false; }
+ if (!surface) return eglMakeCurrent(d->egl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ struct x11_surface *s = (struct x11_surface *)surface;
+ if (surface->display != base || s->base.presenter != YASL_PRIVATE_PRESENTER_GL || !s->gl_context) {
+ errno = EINVAL;
+ return false;
+ }
+ return eglMakeCurrent(d->egl, s->gl_surface, s->gl_surface, s->gl_context) == EGL_TRUE;
+}
+
+static yasl_private_gl_proc gl_get_proc_address(struct yasl_private_display *base, const char *name)
+{
+ (void)base;
+ return name ? (yasl_private_gl_proc)eglGetProcAddress(name) : NULL;
+}
+
+static bool gl_swap_interval(struct yasl_private_display *base, struct yasl_surface *surface, int interval)
+{
+ struct x11_display *d = (struct x11_display *)base;
+ if (!surface || surface->display != base || ((struct x11_surface *)surface)->base.presenter != YASL_PRIVATE_PRESENTER_GL) {
+ errno = EINVAL;
+ return false;
+ }
+ return d->egl_ready && eglSwapInterval(d->egl, interval) == EGL_TRUE;
+}
+
+static bool gl_swap_buffers(struct yasl_private_display *base, struct yasl_surface *surface)
+{
+ struct x11_display *d = (struct x11_display *)base;
+ struct x11_surface *s = (struct x11_surface *)surface;
+ if (!surface || surface->display != base || s->base.presenter != YASL_PRIVATE_PRESENTER_GL || !d->egl_ready) {
+ errno = EINVAL;
+ return false;
+ }
+ if (!eglSwapBuffers(d->egl, s->gl_surface)) return false;
+ s->presented = true;
+ yasl_private_clock_presented(&s->clock, yasl_private_loop_now_ns(), false);
+ return true;
+}
+#endif
+
static bool popup_spec_valid(const struct x11_surface *parent,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
if (!parent || !spec) return false;
+ if (spec->positioner_explicit && (spec->anchor_edges > 8 || spec->gravity > 8 ||
+ (spec->constraints & ~63u))) return false;
int parent_cx = parent->is_popup ? parent->content_offset.x : 0;
int parent_cy = parent->is_popup ? parent->content_offset.y : 0;
int64_t x = (int64_t)spec->anchor.x - parent_cx;
@@ -992,10 +1400,87 @@ static bool popup_spec_valid(const struct x11_surface *parent,
(int64_t)spec->content_offset.y + spec->content_size.y <= spec->size.y;
}
+enum { X11_ANCHOR_NONE, X11_ANCHOR_TOP, X11_ANCHOR_BOTTOM, X11_ANCHOR_LEFT,
+ X11_ANCHOR_RIGHT, X11_ANCHOR_TOP_LEFT, X11_ANCHOR_BOTTOM_LEFT,
+ X11_ANCHOR_TOP_RIGHT, X11_ANCHOR_BOTTOM_RIGHT };
+enum { X11_CONSTRAINT_SLIDE_X = 1u, X11_CONSTRAINT_SLIDE_Y = 2u,
+ X11_CONSTRAINT_FLIP_X = 4u, X11_CONSTRAINT_FLIP_Y = 8u,
+ X11_CONSTRAINT_RESIZE_X = 16u, X11_CONSTRAINT_RESIZE_Y = 32u };
+
+static void popup_anchor_point(const struct yasl_private_popup_spec *spec, int *x, int *y)
+{
+ switch (spec->anchor_edges) {
+ case X11_ANCHOR_TOP: *x = spec->anchor.x + spec->anchor.width / 2; *y = spec->anchor.y; break;
+ case X11_ANCHOR_BOTTOM: *x = spec->anchor.x + spec->anchor.width / 2; *y = spec->anchor.y + spec->anchor.height; break;
+ case X11_ANCHOR_LEFT: *x = spec->anchor.x; *y = spec->anchor.y + spec->anchor.height / 2; break;
+ case X11_ANCHOR_RIGHT: *x = spec->anchor.x + spec->anchor.width; *y = spec->anchor.y + spec->anchor.height / 2; break;
+ case X11_ANCHOR_TOP_LEFT: *x = spec->anchor.x; *y = spec->anchor.y; break;
+ case X11_ANCHOR_BOTTOM_LEFT: *x = spec->anchor.x; *y = spec->anchor.y + spec->anchor.height; break;
+ case X11_ANCHOR_TOP_RIGHT: *x = spec->anchor.x + spec->anchor.width; *y = spec->anchor.y; break;
+ case X11_ANCHOR_BOTTOM_RIGHT: *x = spec->anchor.x + spec->anchor.width; *y = spec->anchor.y + spec->anchor.height; break;
+ default: *x = spec->anchor.x + spec->anchor.width / 2; *y = spec->anchor.y + spec->anchor.height / 2; break;
+ }
+}
+
+static unsigned popup_flip_x(unsigned gravity)
+{
+ switch (gravity) {
+ case X11_ANCHOR_LEFT: return X11_ANCHOR_RIGHT;
+ case X11_ANCHOR_RIGHT: return X11_ANCHOR_LEFT;
+ case X11_ANCHOR_TOP_LEFT: return X11_ANCHOR_TOP_RIGHT;
+ case X11_ANCHOR_BOTTOM_LEFT: return X11_ANCHOR_BOTTOM_RIGHT;
+ case X11_ANCHOR_TOP_RIGHT: return X11_ANCHOR_TOP_LEFT;
+ case X11_ANCHOR_BOTTOM_RIGHT: return X11_ANCHOR_BOTTOM_LEFT;
+ default: return gravity;
+ }
+}
+
+static unsigned popup_flip_y(unsigned gravity)
+{
+ switch (gravity) {
+ case X11_ANCHOR_TOP: return X11_ANCHOR_BOTTOM;
+ case X11_ANCHOR_BOTTOM: return X11_ANCHOR_TOP;
+ case X11_ANCHOR_TOP_LEFT: return X11_ANCHOR_BOTTOM_LEFT;
+ case X11_ANCHOR_TOP_RIGHT: return X11_ANCHOR_BOTTOM_RIGHT;
+ case X11_ANCHOR_BOTTOM_LEFT: return X11_ANCHOR_TOP_LEFT;
+ case X11_ANCHOR_BOTTOM_RIGHT: return X11_ANCHOR_TOP_RIGHT;
+ default: return gravity;
+ }
+}
+
+static void popup_position_at(const struct yasl_private_popup_spec *spec, int ax, int ay,
+ unsigned gravity, struct yasl_private_vector2i size, int *x, int *y)
+{
+ int content_w = spec->content_size.x ? spec->content_size.x : size.x - spec->content_offset.x;
+ int content_h = spec->content_size.y ? spec->content_size.y : size.y - spec->content_offset.y;
+ switch (gravity) {
+ case X11_ANCHOR_LEFT: case X11_ANCHOR_TOP_LEFT: case X11_ANCHOR_BOTTOM_LEFT:
+ *x = ax - content_w - spec->content_offset.x; break;
+ case X11_ANCHOR_RIGHT: case X11_ANCHOR_TOP_RIGHT: case X11_ANCHOR_BOTTOM_RIGHT:
+ *x = ax - spec->content_offset.x; break;
+ default: *x = ax - content_w / 2 - spec->content_offset.x; break;
+ }
+ switch (gravity) {
+ case X11_ANCHOR_TOP: case X11_ANCHOR_TOP_LEFT: case X11_ANCHOR_TOP_RIGHT:
+ *y = ay - content_h - spec->content_offset.y; break;
+ case X11_ANCHOR_BOTTOM: case X11_ANCHOR_BOTTOM_LEFT: case X11_ANCHOR_BOTTOM_RIGHT:
+ *y = ay - spec->content_offset.y; break;
+ default: *y = ay - content_h / 2 - spec->content_offset.y; break;
+ }
+}
+
+static int popup_overflow(int pos, int extent, int low, int high)
+{
+ int64_t end = (int64_t)pos + extent;
+ int64_t overflow = (pos < low ? (int64_t)low - pos : 0) + (end > high ? end - high : 0);
+ return overflow > INT_MAX ? INT_MAX : (int)overflow;
+}
+
static void popup_calculate_position(struct x11_display *d,
struct x11_surface *parent,
- const struct yasl_popup_spec *spec,
- int *out_x, int *out_y)
+ const struct yasl_private_popup_spec *spec,
+ int *out_x, int *out_y,
+ struct yasl_private_vector2i *out_size)
{
int parent_rx = 0, parent_ry = 0;
if (d->native) {
@@ -1007,16 +1492,23 @@ static void popup_calculate_position(struct x11_display *d,
int parent_cx = parent->is_popup ? parent->content_offset.x : 0;
int parent_cy = parent->is_popup ? parent->content_offset.y : 0;
- int anchor_x = parent_rx + (spec->anchor.x - parent_cx);
- int anchor_y = parent_ry + (spec->anchor.y - parent_cy);
-
- int root_x, root_y;
- if (spec->beside) {
- root_x = anchor_x + spec->anchor.width - spec->content_offset.x;
- root_y = anchor_y - spec->content_offset.y;
+ struct yasl_private_vector2i size = spec->size;
+ int anchor_x, anchor_y, root_x, root_y;
+ if (spec->positioner_explicit) {
+ popup_anchor_point(spec, &anchor_x, &anchor_y);
+ anchor_x += parent_rx - parent_cx;
+ anchor_y += parent_ry - parent_cy;
+ popup_position_at(spec, anchor_x, anchor_y, spec->gravity, size, &root_x, &root_y);
} else {
- root_x = anchor_x - spec->content_offset.x;
- root_y = anchor_y + spec->anchor.height - spec->content_offset.y;
+ anchor_x = parent_rx + (spec->anchor.x - parent_cx);
+ anchor_y = parent_ry + (spec->anchor.y - parent_cy);
+ if (spec->beside) {
+ root_x = anchor_x + spec->anchor.width - spec->content_offset.x;
+ root_y = anchor_y - spec->content_offset.y;
+ } else {
+ root_x = anchor_x - spec->content_offset.x;
+ root_y = anchor_y + spec->anchor.height - spec->content_offset.y;
+ }
}
int mon_x = 0, mon_y = 0;
@@ -1043,29 +1535,69 @@ static void popup_calculate_position(struct x11_display *d,
}
#endif
- if (spec->beside) {
- if (root_x + spec->size.x > mon_x + mon_w) {
- int flipped_x = anchor_x - spec->size.x + spec->content_offset.x;
- if (flipped_x >= mon_x) root_x = flipped_x;
+ if (spec->positioner_explicit) {
+ if (spec->constraints & X11_CONSTRAINT_FLIP_X) {
+ int flip_x, flip_y;
+ /* Reflect the selected anchor edge across the anchor rectangle center. */
+ int anchor_origin_x = parent_rx - parent_cx + spec->anchor.x;
+ int flipped_anchor_x = 2 * anchor_origin_x + spec->anchor.width - anchor_x;
+ popup_position_at(spec, flipped_anchor_x, anchor_y, popup_flip_x(spec->gravity), size, &flip_x, &flip_y);
+ if (popup_overflow(flip_x, size.x, mon_x, mon_x + mon_w) <
+ popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) root_x = flip_x;
+ }
+ if (spec->constraints & X11_CONSTRAINT_FLIP_Y) {
+ int flip_x, flip_y;
+ int anchor_origin_y = parent_ry - parent_cy + spec->anchor.y;
+ int flipped_anchor_y = 2 * anchor_origin_y + spec->anchor.height - anchor_y;
+ popup_position_at(spec, anchor_x, flipped_anchor_y, popup_flip_y(spec->gravity), size, &flip_x, &flip_y);
+ if (popup_overflow(flip_y, size.y, mon_y, mon_y + mon_h) <
+ popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) root_y = flip_y;
+ }
+ if (spec->constraints & X11_CONSTRAINT_SLIDE_X) {
+ if (root_x < mon_x) root_x = mon_x;
+ if (root_x + size.x > mon_x + mon_w) root_x = mon_x + mon_w - size.x;
+ }
+ if (spec->constraints & X11_CONSTRAINT_SLIDE_Y) {
+ if (root_y < mon_y) root_y = mon_y;
+ if (root_y + size.y > mon_y + mon_h) root_y = mon_y + mon_h - size.y;
+ }
+ if ((spec->constraints & X11_CONSTRAINT_RESIZE_X) &&
+ popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) {
+ if (root_x >= mon_x + mon_w) root_x = mon_x + mon_w - 1;
+ if (root_x < mon_x) { size.x -= mon_x - root_x; root_x = mon_x; }
+ if (root_x + size.x > mon_x + mon_w) size.x = mon_x + mon_w - root_x;
+ if (size.x < 1) size.x = 1;
+ }
+ if ((spec->constraints & X11_CONSTRAINT_RESIZE_Y) &&
+ popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) {
+ if (root_y >= mon_y + mon_h) root_y = mon_y + mon_h - 1;
+ if (root_y < mon_y) { size.y -= mon_y - root_y; root_y = mon_y; }
+ if (root_y + size.y > mon_y + mon_h) size.y = mon_y + mon_h - root_y;
+ if (size.y < 1) size.y = 1;
}
} else {
- if (root_y + spec->size.y > mon_y + mon_h) {
- int flipped_y = anchor_y - spec->size.y + spec->content_offset.y;
+ if (spec->beside) {
+ if (root_x + size.x > mon_x + mon_w) {
+ int flipped_x = anchor_x - size.x + spec->content_offset.x;
+ if (flipped_x >= mon_x) root_x = flipped_x;
+ }
+ } else if (root_y + size.y > mon_y + mon_h) {
+ int flipped_y = anchor_y - size.y + spec->content_offset.y;
if (flipped_y >= mon_y) root_y = flipped_y;
}
+ if (root_x + size.x > mon_x + mon_w) root_x = mon_x + mon_w - size.x;
+ if (root_x < mon_x) root_x = mon_x;
+ if (root_y + size.y > mon_y + mon_h) root_y = mon_y + mon_h - size.y;
+ if (root_y < mon_y) root_y = mon_y;
}
- if (root_x + spec->size.x > mon_x + mon_w) root_x = mon_x + mon_w - spec->size.x;
- if (root_x < mon_x) root_x = mon_x;
- if (root_y + spec->size.y > mon_y + mon_h) root_y = mon_y + mon_h - spec->size.y;
- if (root_y < mon_y) root_y = mon_y;
-
*out_x = root_x;
*out_y = root_y;
+ if (out_size) *out_size = size;
}
static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_base,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
struct x11_surface *parent = (struct x11_surface *)parent_base;
if (!parent || parent->destroyed || !popup_spec_valid(parent, spec))
@@ -1074,14 +1606,17 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
struct x11_surface *s = calloc(1, sizeof(*s));
if (!s) return NULL;
s->base.display = parent_base->display;
+ s->base.creation_flags = parent_base->creation_flags;
+ s->base.presenter = (parent_base->creation_flags & YASL_PRIVATE_SURFACE_CPU) ?
+ YASL_PRIVATE_PRESENTER_CPU : YASL_PRIVATE_PRESENTER_NONE;
s->parent = parent;
s->is_popup = true;
s->content_offset = spec->content_offset;
s->clock.refresh_ns = parent->clock.refresh_ns;
- if (!resize(s, spec->size)) { free(s); return NULL; }
-
int root_x = 0, root_y = 0;
- popup_calculate_position(d, parent, spec, &root_x, &root_y);
+ struct yasl_private_vector2i actual_size;
+ popup_calculate_position(d, parent, spec, &root_x, &root_y, &actual_size);
+ if (!resize(s, actual_size)) { free(s); return NULL; }
if (d->native) {
XSetWindowAttributes attrs = {
@@ -1089,7 +1624,7 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
.save_under = True,
};
s->window = XCreateWindow(d->native, RootWindow(d->native, d->screen),
- root_x, root_y, (unsigned)spec->size.x, (unsigned)spec->size.y,
+ root_x, root_y, (unsigned)actual_size.x, (unsigned)actual_size.y,
0, CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder, &attrs);
if (!s->window) {
@@ -1098,7 +1633,7 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
}
s->base.native_handle = (void *)(uintptr_t)s->window;
s->base.size = s->size;
- s->base.scale_120 = YASL_SCALE_UNIT;
+ s->base.scale_120 = YASL_PRIVATE_SCALE_UNIT;
s->gc = XCreateGC(d->native, s->window, 0, NULL);
XSelectInput(d->native, s->window, ExposureMask | StructureNotifyMask |
FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask |
@@ -1127,25 +1662,27 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
}
static bool surface_popup_reposition(struct yasl_surface *popup_base,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
struct x11_surface *s = (struct x11_surface *)popup_base;
if (!s || s->destroyed || !s->is_popup || !s->parent || s->parent->destroyed ||
!popup_spec_valid(s->parent, spec))
return false;
struct x11_display *d = (struct x11_display *)popup_base->display;
- if (spec->size.x != s->size.x || spec->size.y != s->size.y) {
- if (!resize(s, spec->size))
- return false;
- }
s->content_offset = spec->content_offset;
int root_x = 0, root_y = 0;
- popup_calculate_position(d, s->parent, spec, &root_x, &root_y);
+ struct yasl_private_vector2i actual_size;
+ popup_calculate_position(d, s->parent, spec, &root_x, &root_y, &actual_size);
+ bool changed_size = actual_size.x != s->size.x || actual_size.y != s->size.y;
+ if (changed_size && !resize(s, actual_size)) return false;
if (d->native && s->window) {
XMoveResizeWindow(d->native, s->window, root_x, root_y,
- (unsigned)spec->size.x, (unsigned)spec->size.y);
+ (unsigned)actual_size.x, (unsigned)actual_size.y);
XFlush(d->native);
}
+ if (changed_size)
+ yasl_private_surface_notify_configure(&s->base,
+ (struct yasl_private_geometry){actual_size, YASL_PRIVATE_SCALE_UNIT});
schedule_redraw(&s->base);
return true;
}
@@ -1157,22 +1694,22 @@ static void update_state(struct x11_surface *s)
int format;
unsigned long count, left;
unsigned char *data = NULL;
- uint32_t state = s->base.state & ~(YASL_STATE_FULLSCREEN | YASL_STATE_MAXIMIZED);
+ uint32_t state = s->base.state & ~(YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_MAXIMIZED);
if (XGetWindowProperty(d->native, s->window, d->net_state, 0, 64, False,
XA_ATOM, &actual, &format, &count, &left, &data) == Success && format == 32) {
Atom *atoms = (Atom *)data;
bool h = false, v = false;
for (unsigned long i = 0; i < count; i++) {
- if (atoms[i] == d->fullscreen) state |= YASL_STATE_FULLSCREEN;
+ if (atoms[i] == d->fullscreen) state |= YASL_PRIVATE_STATE_FULLSCREEN;
if (atoms[i] == d->maximized_h) h = true;
if (atoms[i] == d->maximized_v) v = true;
}
- if (h && v) state |= YASL_STATE_MAXIMIZED;
+ if (h && v) state |= YASL_PRIVATE_STATE_MAXIMIZED;
}
if (data) XFree(data);
if (state == s->base.state) return;
s->base.state = state;
- yasl_surface_notify_state(&s->base, state);
+ yasl_private_surface_notify_state(&s->base, state);
}
static void selection_request(struct x11_display *d, XSelectionRequestEvent *request)
@@ -1184,10 +1721,10 @@ static void selection_request(struct x11_display *d, XSelectionRequestEvent *req
.target = request->target, .time = request->time,
};
Atom property = request->property ? request->property : request->target;
- int slot = request->selection == XA_PRIMARY ? YASL_PRIMARY : YASL_CLIPBOARD;
+ int slot = request->selection == XA_PRIMARY ? YASL_PRIVATE_PRIMARY : YASL_PRIVATE_CLIPBOARD;
const char *text = d->selection[slot];
size_t latin1_len = 0;
- char *latin1 = text ? yasl_utf8_to_latin1(text, &latin1_len) : NULL;
+ char *latin1 = text ? yasl_private_utf8_to_latin1(text, &latin1_len) : NULL;
if (text && request->target == d->targets) {
Atom targets[] = {d->targets, d->utf8, XA_STRING};
XChangeProperty(d->native, request->requestor, property, XA_ATOM, 32,
@@ -1267,7 +1804,7 @@ static void xdnd_selection_notify(struct x11_display *d, XSelectionEvent *event)
size_t out_len = 0;
char *parsed = parse_file_uris((const char *)data, count, &out_len);
if (parsed && out_len > 0) {
- push(s, (struct yasl_event){.type = YASL_EVENT_DROP}, parsed, out_len);
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_DROP}, parsed, out_len);
free(parsed);
success = true;
}
@@ -1304,20 +1841,20 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
/* Surface destruction detached this accepted request. The reply means
* the owner has finished writing the initial property; retire safely. */
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
XDestroyWindow(d->native, r->window);
free(r);
return;
}
if (event->property == None) {
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
- enum yasl_transfer_status status =
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
+ enum yasl_private_transfer_status status =
XGetSelectionOwner(d->native, r->selection) == None
- ? YASL_TRANSFER_UNAVAILABLE : YASL_TRANSFER_FAILED;
+ ? YASL_PRIVATE_TRANSFER_UNAVAILABLE : YASL_PRIVATE_TRANSFER_FAILED;
XDestroyWindow(d->native, r->window);
if (s && !s->destroyed)
- yasl_surface_complete_paste(&s->base, r->id, status, NULL, 0);
+ yasl_private_surface_complete_paste(&s->base, r->id, status, NULL, 0);
free(r);
return;
}
@@ -1333,14 +1870,14 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
&probe_count, &probe_left, &probe_data);
if (probe_data) XFree(probe_data);
if (probe_result == Success && probe_type == d->incr) {
- yasl_surface_complete_paste(&s->base, r->id,
- YASL_TRANSFER_FAILED, NULL, 0);
+ yasl_private_surface_complete_paste(&s->base, r->id,
+ YASL_PRIVATE_TRANSFER_FAILED, NULL, 0);
r->target = NULL;
r->id = 0;
return;
}
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
Atom actual = None;
int format = 0;
unsigned long count = 0, left = 0;
@@ -1389,17 +1926,17 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
}
if (complete && actual == XA_STRING) {
size_t utf8_len;
- char *utf8 = yasl_utf8_from_latin1(buf, total, &utf8_len);
+ char *utf8 = yasl_private_utf8_from_latin1(buf, total, &utf8_len);
free(buf);
buf = utf8;
if (buf) total = utf8_len;
}
- enum yasl_transfer_status status = YASL_TRANSFER_FAILED;
- if (complete && buf && yasl_utf8_validate(buf, total))
- status = YASL_TRANSFER_OK;
- yasl_surface_complete_paste(&s->base, r->id, status,
- status == YASL_TRANSFER_OK ? buf : NULL,
- status == YASL_TRANSFER_OK ? total : 0);
+ enum yasl_private_transfer_status status = YASL_PRIVATE_TRANSFER_FAILED;
+ if (complete && buf && yasl_private_utf8_validate(buf, total))
+ status = YASL_PRIVATE_TRANSFER_OK;
+ yasl_private_surface_complete_paste(&s->base, r->id, status,
+ status == YASL_PRIVATE_TRANSFER_OK ? buf : NULL,
+ status == YASL_PRIVATE_TRANSFER_OK ? total : 0);
free(buf);
XDestroyWindow(d->native, r->window);
free(r);
@@ -1413,7 +1950,7 @@ static void refresh_keyboard(struct x11_display *d)
if (!keyboard) return;
if (keyboard->names && keyboard->names->keys) {
for (unsigned code = keyboard->min_key_code; code <= keyboard->max_key_code; code++)
- d->keys[code] = yasl_key_from_xkb_name(keyboard->names->keys[code].name);
+ d->keys[code] = yasl_private_key_from_xkb_name(keyboard->names->keys[code].name);
}
XkbFreeKeyboard(keyboard, XkbAllComponentsMask, True);
}
@@ -1460,18 +1997,18 @@ static void key_event(struct x11_surface *s, XKeyEvent *key, bool repeat)
}
}
uint32_t cp = xkb_keysym_to_utf32((xkb_keysym_t)base);
- push(s, (struct yasl_event){
- .type = YASL_EVENT_KEY,
+ push(s, (struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_KEY,
.key = {.key = key->keycode < 256 ? d->keys[key->keycode] : YASL_KEY_UNKNOWN,
- .codepoint = yasl_key_label(cp), .native_code = key->keycode,
- .shifted = yasl_key_label(xkb_keysym_to_utf32((xkb_keysym_t)shifted)),
+ .codepoint = yasl_private_key_label(cp), .native_code = key->keycode,
+ .shifted = yasl_private_key_label(xkb_keysym_to_utf32((xkb_keysym_t)shifted)),
.mods = d->mods,
.action = key->type == KeyRelease ? YASL_KEY_RELEASE :
repeat ? YASL_KEY_REPEAT : YASL_KEY_PRESS},
}, NULL, 0);
if (len > 0 && text && (unsigned char)text[0] >= 0x20 && text[0] != 0x7f &&
- !(d->mods & (YASL_MOD_CTRL | YASL_MOD_SUPER | YASL_MOD_ALT)))
- push(s, (struct yasl_event){.type = YASL_EVENT_TEXT}, text, (size_t)len);
+ !(d->mods & (YASL_PRIVATE_MOD_CTRL | YASL_PRIVATE_MOD_SUPER | YASL_PRIVATE_MOD_ALT)))
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_TEXT}, text, (size_t)len);
if (text != local) free(text);
}
@@ -1480,7 +2017,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
{
if (ev->message_type == d->protocols &&
(Atom)ev->data.l[0] == d->delete_window) {
- yasl_surface_notify_close(&s->base);
+ yasl_private_surface_notify_close(&s->base);
} else if (ev->message_type == d->xdnd_enter) {
Window source = (Window)ev->data.l[0];
int version = (int)((unsigned long)ev->data.l[1] >> 24);
@@ -1521,19 +2058,19 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
XTranslateCoordinates(d->native, RootWindow(d->native, d->screen), target,
rx, ry, &wx, &wy, &child);
}
- struct yasl_vector2i pos = {wx, wy};
+ struct yasl_private_vector2i pos = {wx, wy};
if (d->xdnd.surface && d->xdnd.surface != s) {
struct x11_surface *old = d->xdnd.surface;
- struct yasl_vector2i old_pos = d->xdnd.pos;
+ struct yasl_private_vector2i old_pos = d->xdnd.pos;
d->xdnd.surface = NULL;
if (d->xdnd.accepts && !old->destroyed)
- yasl_surface_notify_drop(&old->base, YASL_DROP_LEAVE, old_pos);
+ yasl_private_surface_notify_drop(&old->base, YASL_PRIVATE_DROP_LEAVE, old_pos);
}
d->xdnd.surface = s;
d->xdnd.pos = pos;
d->xdnd.time = t;
if (d->xdnd.accepts && !s->destroyed)
- yasl_surface_notify_drop(&s->base, YASL_DROP_OVER, pos);
+ yasl_private_surface_notify_drop(&s->base, YASL_PRIVATE_DROP_OVER, pos);
if (d->native) {
XEvent reply = {0};
@@ -1556,7 +2093,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
} else if (ev->message_type == d->xdnd_leave) {
if (d->xdnd.surface == s) {
if (d->xdnd.accepts && !s->destroyed)
- yasl_surface_notify_drop(&s->base, YASL_DROP_LEAVE, d->xdnd.pos);
+ yasl_private_surface_notify_drop(&s->base, YASL_PRIVATE_DROP_LEAVE, d->xdnd.pos);
}
d->xdnd = (typeof(d->xdnd)){0};
} else if (ev->message_type == d->xdnd_drop) {
@@ -1566,7 +2103,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
bool was_accepting = d->xdnd.accepts && d->xdnd.has_uri_list && (d->xdnd.source == source);
if (d->xdnd.surface == s) {
if (was_accepting && !s->destroyed)
- yasl_surface_notify_drop(&s->base, YASL_DROP_LEAVE, d->xdnd.pos);
+ yasl_private_surface_notify_drop(&s->base, YASL_PRIVATE_DROP_LEAVE, d->xdnd.pos);
}
if (was_accepting && !s->destroyed) {
d->pending_drop.active = true;
@@ -1593,7 +2130,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
}
}
-static void dispatch(struct yasl_display *base)
+static void dispatch(struct yasl_private_display *base)
{
struct x11_display *d = (struct x11_display *)base;
d->depth++;
@@ -1636,11 +2173,11 @@ static void dispatch(struct yasl_display *base)
switch (event.type) {
case Expose: s->want_draw = true; break;
case ConfigureNotify: {
- struct yasl_vector2i size = {event.xconfigure.width, event.xconfigure.height};
+ struct yasl_private_vector2i size = {event.xconfigure.width, event.xconfigure.height};
if (size.x == s->size.x && size.y == s->size.y) break;
if (resize(s, size))
- yasl_surface_notify_configure(&s->base,
- (struct yasl_geometry){size, YASL_SCALE_UNIT});
+ yasl_private_surface_notify_configure(&s->base,
+ (struct yasl_private_geometry){size, YASL_PRIVATE_SCALE_UNIT});
break;
}
case ClientMessage:
@@ -1648,12 +2185,16 @@ static void dispatch(struct yasl_display *base)
break;
case FocusIn: case FocusOut: {
bool focused = event.type == FocusIn;
- if (s->ic) { if (focused) XSetICFocus(s->ic); else XUnsetICFocus(s->ic); }
- if (focused) s->base.state |= YASL_STATE_ACTIVATED;
- else s->base.state &= ~YASL_STATE_ACTIVATED;
- push(s, (struct yasl_event){
- .type = YASL_EVENT_FOCUS, .focus.focused = focused}, NULL, 0);
- yasl_surface_notify_state(&s->base, s->base.state);
+ s->focused = focused;
+ if (s->ic) {
+ if (focused && s->base.text_input_active) XSetICFocus(s->ic);
+ else XUnsetICFocus(s->ic);
+ }
+ if (focused) s->base.state |= YASL_PRIVATE_STATE_ACTIVATED;
+ else s->base.state &= ~YASL_PRIVATE_STATE_ACTIVATED;
+ push(s, (struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_FOCUS, .focus.focused = focused}, NULL, 0);
+ yasl_private_surface_notify_state(&s->base, s->base.state);
break;
}
case PropertyNotify:
@@ -1674,13 +2215,13 @@ static void dispatch(struct yasl_display *base)
break;
}
case MotionNotify: case LeaveNotify: case EnterNotify: case ButtonPress: case ButtonRelease: {
- struct yasl_event ev = {
- .pointer = {.device = YASL_PTR_DEV_MOUSE},
+ struct yasl_private_event ev = {
+ .pointer = {.device = YASL_PRIVATE_PTR_DEV_MOUSE},
};
unsigned state;
if (event.type == MotionNotify) {
- ev.pointer.pos = (struct yasl_vector2i){event.xmotion.x, event.xmotion.y};
- ev.type = YASL_EVENT_POINTER_MOTION;
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xmotion.x, event.xmotion.y};
+ ev.type = YASL_PRIVATE_EVENT_POINTER_MOTION;
state = event.xmotion.state;
if (d->drag.active) {
if (d->drag.carried)
@@ -1689,38 +2230,41 @@ static void dispatch(struct yasl_display *base)
XMoveWindow(d->native, d->drag.icon_window,
event.xmotion.x_root - d->drag.hotspot.x,
event.xmotion.y_root - d->drag.hotspot.y);
- struct yasl_vector2i hpos = ev.pointer.pos;
+ struct yasl_private_vector2i hpos = ev.pointer.pos;
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, event.xmotion.x_root, event.xmotion.y_root, &hpos) : s;
drag_set_hover(d, hsurf, hpos);
}
} else if (event.type == EnterNotify) {
- ev.pointer.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
- ev.type = YASL_EVENT_POINTER_MOTION;
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xcrossing.x, event.xcrossing.y};
+ ev.type = YASL_PRIVATE_EVENT_POINTER_MOTION;
state = event.xcrossing.state;
if (d->drag.active) {
- struct yasl_vector2i hpos = ev.pointer.pos;
+ struct yasl_private_vector2i hpos = ev.pointer.pos;
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, event.xcrossing.x_root, event.xcrossing.y_root, &hpos) : s;
drag_set_hover(d, hsurf, hpos);
}
} else if (event.type == LeaveNotify) {
- ev.pointer.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
- ev.type = YASL_EVENT_POINTER_LEAVE;
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xcrossing.x, event.xcrossing.y};
+ ev.type = YASL_PRIVATE_EVENT_POINTER_LEAVE;
state = event.xcrossing.state;
if (d->drag.active)
drag_leave_hover(d, s, ev.pointer.pos);
} else {
- ev.pointer.pos = (struct yasl_vector2i){event.xbutton.x, event.xbutton.y};
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xbutton.x, event.xbutton.y};
state = event.xbutton.state;
unsigned button = event.xbutton.button;
if (button >= 4 && button <= 7) {
if (event.type == ButtonRelease) break;
- ev.type = YASL_EVENT_POINTER_SCROLL;
+ ev.type = YASL_PRIVATE_EVENT_POINTER_SCROLL;
if (button <= 5) ev.pointer.scroll.y = button == 4 ? -1 : 1;
else ev.pointer.scroll.x = button == 6 ? -1 : 1;
+ ev.pointer.scroll_valid = 1u;
+ ev.pointer.scroll_source = 1u;
+ ev.pointer.scroll_phase = 2u;
} else {
- ev.type = event.type == ButtonPress ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ ev.type = event.type == ButtonPress ? YASL_PRIVATE_EVENT_POINTER_DOWN : YASL_PRIVATE_EVENT_POINTER_UP;
ev.pointer.button = pointer_button(button);
if (event.type == ButtonRelease && d->drag.active)
drag_drop_hover(d);
@@ -1735,13 +2279,13 @@ static void dispatch(struct yasl_display *base)
leave(d);
}
-static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb,
- const struct yasl_damage_list *damage)
+static bool present(struct yasl_surface *base, const struct yasl_private_framebuffer *fb,
+ const struct yasl_private_damage_list *damage)
{
struct x11_surface *s = (struct x11_surface *)base;
if (s->destroyed || !s->drawing || s->presented || !fb || !damage ||
fb->pixels != s->pixels || fb->size.x != s->size.x || fb->size.y != s->size.y ||
- damage->n < -1 || damage->n > YASL_DAMAGE_MAX) return false;
+ damage->n < -1 || damage->n > YASL_PRIVATE_DAMAGE_MAX) return false;
struct x11_display *d = (struct x11_display *)base->display;
XImage *im = s->image;
if (s->shm_active) {
@@ -1749,7 +2293,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XShmPutImage(d->native, s->window, s->gc, im, 0, 0, 0, 0,
(unsigned)s->size.x, (unsigned)s->size.y, False);
else for (int i = 0; i < damage->n; i++) {
- struct yasl_rect2i r = damage->rects[i];
+ struct yasl_private_rect2i r = damage->rects[i];
int64_t right = (int64_t)r.x + r.width, bottom = (int64_t)r.y + r.height;
int x = r.x > 0 ? r.x : 0, y = r.y > 0 ? r.y : 0;
int w = (int)(right < s->size.x ? right : s->size.x) - x;
@@ -1758,7 +2302,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XShmPutImage(d->native, s->window, s->gc, im, x, y, x, y, (unsigned)w, (unsigned)h, False);
}
s->presented = true;
- yasl_clock_presented(&s->clock, yasl_loop_now_ns(), false);
+ yasl_private_clock_presented(&s->clock, yasl_private_loop_now_ns(), false);
return true;
}
bool direct = im->bits_per_pixel == 32 && im->red_mask == 0xff0000 &&
@@ -1769,7 +2313,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
y_start = s->size.y; y_end = 0;
x_start = s->size.x; x_end = 0;
for (int i = 0; i < damage->n; i++) {
- struct yasl_rect2i r = damage->rects[i];
+ struct yasl_private_rect2i r = damage->rects[i];
int y0 = r.y > 0 ? r.y : 0;
int y1 = (r.y + r.height < s->size.y) ? r.y + r.height : s->size.y;
int x0 = r.x > 0 ? r.x : 0;
@@ -1798,7 +2342,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XPutImage(d->native, s->window, s->gc, im, 0, 0, 0, 0,
(unsigned)s->size.x, (unsigned)s->size.y);
else for (int i = 0; i < damage->n; i++) {
- struct yasl_rect2i r = damage->rects[i];
+ struct yasl_private_rect2i r = damage->rects[i];
int64_t right = (int64_t)r.x + r.width, bottom = (int64_t)r.y + r.height;
int x = r.x > 0 ? r.x : 0, y = r.y > 0 ? r.y : 0;
int w = (int)(right < s->size.x ? right : s->size.x) - x;
@@ -1807,27 +2351,33 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XPutImage(d->native, s->window, s->gc, im, x, y, x, y, (unsigned)w, (unsigned)h);
}
s->presented = true;
- yasl_clock_presented(&s->clock, yasl_loop_now_ns(), false);
+ yasl_private_clock_presented(&s->clock, yasl_private_loop_now_ns(), false);
return true;
}
-static void flush(struct yasl_display *base)
+static void flush(struct yasl_private_display *base)
{
struct x11_display *d = (struct x11_display *)base;
d->depth++;
for (struct x11_surface *s = d->surfaces, *next; s; s = next) {
next = s->next;
- if (s->destroyed || !s->want_draw || !s->cbs || !s->cbs->draw || s->drawing) continue;
+ if (s->destroyed || !s->want_draw || s->drawing) continue;
+ if (s->base.presenter != YASL_PRIVATE_PRESENTER_CPU) {
+ s->want_draw = false;
+ yasl_private_surface_notify_refresh(&s->base);
+ continue;
+ }
+ if (!s->cbs || !s->cbs->draw) continue;
s->want_draw = false;
s->drawing = true;
s->presented = false;
- s->damage = (struct yasl_damage_list){0};
- s->frame = (struct yasl_frame){
+ s->damage = (struct yasl_private_damage_list){0};
+ s->frame = (struct yasl_private_frame){
.surface = &s->base,
- .target = {.generation = yasl_frame_begin(&s->base),
+ .target = {.generation = yasl_private_frame_begin(&s->base),
.pixels = s->pixels, .size = s->size},
};
- yasl_surface_draw(&s->base, &s->frame);
+ yasl_private_surface_draw(&s->base, &s->frame);
if (!s->destroyed) s->drawing = false;
}
XFlush(d->native);
@@ -1837,11 +2387,11 @@ static void flush(struct yasl_display *base)
static int ready(int fd, short events, void *ud)
{
(void)fd;
- struct yasl_display *base = ud;
+ struct yasl_private_display *base = ud;
struct x11_display *d = (struct x11_display *)base;
if ((events & (POLLERR | POLLHUP)) && !d->lost) {
d->lost = true;
- yasl_display_notify_event(base, YASL_EVENT_DISPLAY_LOST);
+ yasl_private_display_notify_event(base, YASL_PRIVATE_EVENT_DISPLAY_LOST);
return 0;
}
if ((events & POLLIN) && !d->lost) {
@@ -1851,7 +2401,7 @@ static int ready(int fd, short events, void *ud)
return 0;
}
-static int dispatch_timeout(struct yasl_display *base, int timeout_ms)
+static int dispatch_timeout(struct yasl_private_display *base, int timeout_ms)
{
struct x11_display *d = (struct x11_display *)base;
if (unlikely(!d || !d->native || d->lost)) return -1;
@@ -1867,26 +2417,26 @@ static int dispatch_timeout(struct yasl_display *base, int timeout_ms)
if (XEventsQueued(d->native, QueuedAlready) > 0)
timeout_ms = 0;
if (!XPending(d->native) && timeout_ms != 0) {
- yasl_loop_step(d->loop, timeout_ms);
+ yasl_private_loop_step(d->loop, timeout_ms);
dispatch(base);
} else {
- yasl_loop_step(d->loop, 0);
+ yasl_private_loop_step(d->loop, 0);
dispatch(base);
}
}
return 0;
}
-static struct yasl_display *display_open(struct yasl_loop *loop,
- const struct yasl_display_spec *spec)
+static struct yasl_private_display *display_open(struct yasl_private_loop *loop,
+ const struct yasl_private_display_spec *spec)
{
struct x11_display *d = calloc(1, sizeof(*d));
if (!d) return NULL;
- d->base.ops = &yasl_x11_backend;
- d->base.callbacks = spec && spec->cbs ? *spec->cbs : (struct yasl_display_cbs){0};
+ d->base.ops = &yasl_private_x11_backend;
+ d->base.callbacks = spec && spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0};
d->native = XOpenDisplay(NULL);
if (!d->native) { free(d); errno = ENODEV; return NULL; }
- XSetErrorHandler(yasl_x11_error_handler);
+ XSetErrorHandler(yasl_private_x11_error_handler);
d->base.native_handle = d->native;
d->screen = DefaultScreen(d->native);
d->has_shm = XShmQueryExtension(d->native);
@@ -1908,8 +2458,15 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
d->abs_pressure = XInternAtom(d->native, "Abs Pressure", False);
d->abs_tilt_x = XInternAtom(d->native, "Abs Tilt X", False);
d->abs_tilt_y = XInternAtom(d->native, "Abs Tilt Y", False);
+ d->abs_rotation = XInternAtom(d->native, "Abs Rotation", False);
+ d->abs_distance = XInternAtom(d->native, "Abs Distance", False);
+ d->abs_tangential = XInternAtom(d->native, "Abs TPressure", False);
+ d->abs_wheel = XInternAtom(d->native, "Abs Wheel", False);
d->tool_type = XInternAtom(d->native, "Wacom Tool Type", False);
d->eraser = XInternAtom(d->native, "ERASER", False);
+ d->brush = XInternAtom(d->native, "BRUSH", False);
+ d->airbrush = XInternAtom(d->native, "AIRBRUSH", False);
+ d->pencil = XInternAtom(d->native, "PENCIL", False);
unsigned char bits[XIMaskLen(XI_LASTEVENT)] = {0};
XISetMask(bits, XI_HierarchyChanged);
XISetMask(bits, XI_DeviceChanged);
@@ -1917,7 +2474,7 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
XISelectEvents(d->native, RootWindow(d->native, d->screen), &mask, 1);
}
if (!loop) {
- d->loop = yasl_loop_create();
+ d->loop = yasl_private_loop_create();
d->owns_loop = true;
} else {
d->loop = loop;
@@ -1926,7 +2483,7 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
d->app_id = strdup(spec && spec->app_id ? spec->app_id : "YASL");
d->base.app_id = d->app_id;
if (!d->loop || !d->app_id) {
- if (d->owns_loop) yasl_loop_destroy(d->loop);
+ if (d->owns_loop) yasl_private_loop_destroy(d->loop);
free(d->app_id);
XCloseDisplay(d->native);
free(d);
@@ -1941,10 +2498,11 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
ATOM(utf8, "UTF8_STRING");
ATOM(clipboard, "CLIPBOARD");
ATOM(targets, "TARGETS");
- ATOM(paste_property, "YASL_SELECTION");
+ ATOM(paste_property, "YASL_PRIVATE_SELECTION");
ATOM(incr, "INCR");
ATOM(net_name, "_NET_WM_NAME");
ATOM(net_state, "_NET_WM_STATE");
+ ATOM(motif_hints, "_MOTIF_WM_HINTS");
ATOM(fullscreen, "_NET_WM_STATE_FULLSCREEN");
ATOM(maximized_h, "_NET_WM_STATE_MAXIMIZED_HORZ");
ATOM(maximized_v, "_NET_WM_STATE_MAXIMIZED_VERT");
@@ -1961,13 +2519,13 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
ATOM(uri_list, "text/uri-list");
#undef ATOM
if (d->loop) {
- d->watch = yasl_loop_add_fd(d->loop, ConnectionNumber(d->native), POLLIN, ready, &d->base);
+ d->watch = yasl_private_loop_add_fd(d->loop, ConnectionNumber(d->native), POLLIN, ready, &d->base);
if (d->watch < 0) {
if (d->im) XCloseIM(d->im);
XDestroyWindow(d->native, d->selection_window);
XCloseDisplay(d->native);
free(d->app_id);
- if (d->owns_loop) yasl_loop_destroy(d->loop);
+ if (d->owns_loop) yasl_private_loop_destroy(d->loop);
free(d);
return NULL;
}
@@ -1975,21 +2533,24 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
return &d->base;
}
-static void display_close(struct yasl_display *base)
+static void display_close(struct yasl_private_display *base)
{
struct x11_display *d = (struct x11_display *)base;
assert(!d->surfaces && "destroy every surface before its display");
drag_cancel(base);
cancel_pastes(d, NULL);
d->pending_drop.active = false;
- if (d->loop && d->watch > 0) yasl_loop_del_fd(d->loop, d->watch);
+ if (d->loop && d->watch > 0) yasl_private_loop_del_fd(d->loop, d->watch);
if (d->owns_loop && d->loop) {
- yasl_loop_destroy(d->loop);
+ yasl_private_loop_destroy(d->loop);
d->loop = NULL;
d->base.loop = NULL;
}
if (d->im) XCloseIM(d->im);
clear_pointers(d);
+#if YASL_HAS_EGL
+ if (d->egl_ready) eglTerminate(d->egl);
+#endif
for (size_t i = 0; i < sizeof(d->cursors) / sizeof(d->cursors[0]); i++) {
if (d->cursors[i]) {
XFreeCursor(d->native, d->cursors[i]);
@@ -2004,16 +2565,16 @@ static void display_close(struct yasl_display *base)
free(d);
}
-static uint32_t caps(const struct yasl_display *d)
+static uint32_t caps(const struct yasl_private_display *d)
{
- return YASL_CAP_POPUPS | YASL_CAP_DRAG | YASL_CAP_DRAG_CARRY | YASL_CAP_PLACE_WINDOW |
- YASL_CAP_PRIMARY_SELECTION | YASL_CAP_CSD |
- (((const struct x11_display *)d)->xi2 ? YASL_CAP_TABLET : 0);
+ return YASL_PRIVATE_CAP_POPUPS | YASL_PRIVATE_CAP_DRAG | YASL_PRIVATE_CAP_DRAG_CARRY | YASL_PRIVATE_CAP_PLACE_WINDOW |
+ YASL_PRIVATE_CAP_PRIMARY_SELECTION | YASL_PRIVATE_CAP_CSD | YASL_PRIVATE_CAP_NATIVE_GRAPHICS |
+ (((const struct x11_display *)d)->xi2 ? YASL_PRIVATE_CAP_TABLET : 0);
}
-static bool copy_text(struct yasl_display *base, enum yasl_selection sel, const char *text)
+static bool copy_text(struct yasl_private_display *base, enum yasl_private_selection sel, const char *text)
{
- if (!text || (sel != YASL_CLIPBOARD && sel != YASL_PRIMARY)) {
+ if (!text || (sel != YASL_PRIVATE_CLIPBOARD && sel != YASL_PRIVATE_PRIMARY)) {
errno = EINVAL;
return false;
}
@@ -2022,39 +2583,39 @@ static bool copy_text(struct yasl_display *base, enum yasl_selection sel, const
if (!value) { errno = ENOMEM; return false; }
free(d->selection[sel]);
d->selection[sel] = value;
- XSetSelectionOwner(d->native, sel == YASL_PRIMARY ? XA_PRIMARY : d->clipboard,
+ XSetSelectionOwner(d->native, sel == YASL_PRIVATE_PRIMARY ? XA_PRIMARY : d->clipboard,
d->selection_window, CurrentTime);
XFlush(d->native);
return true;
}
-static void copy(struct yasl_display *base, enum yasl_selection sel, const char *text)
+static void copy(struct yasl_private_display *base, enum yasl_private_selection sel, const char *text)
{
(void)copy_text(base, sel, text);
}
-static bool request_paste(struct yasl_display *base, enum yasl_selection sel,
+static bool request_paste(struct yasl_private_display *base, enum yasl_private_selection sel,
struct yasl_surface *target, uint64_t id)
{
- if (!target || (sel != YASL_CLIPBOARD && sel != YASL_PRIMARY)) {
+ if (!target || (sel != YASL_PRIVATE_CLIPBOARD && sel != YASL_PRIVATE_PRIMARY)) {
errno = EINVAL;
return false;
}
struct x11_display *d = (struct x11_display *)base;
struct x11_surface *s = (struct x11_surface *)target;
if (s->destroyed || target->display != base) { errno = EINVAL; return false; }
- Atom selection = sel == YASL_PRIMARY ? XA_PRIMARY : d->clipboard;
+ Atom selection = sel == YASL_PRIVATE_PRIMARY ? XA_PRIMARY : d->clipboard;
Window owner = XGetSelectionOwner(d->native, selection);
if (owner == None) {
- yasl_surface_complete_paste(target, id, YASL_TRANSFER_UNAVAILABLE, NULL, 0);
+ yasl_private_surface_complete_paste(target, id, YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0);
return true;
}
if (owner == d->selection_window) {
const char *text = d->selection[sel];
if (text)
- yasl_surface_complete_paste(target, id, YASL_TRANSFER_OK, text, strlen(text));
+ yasl_private_surface_complete_paste(target, id, YASL_PRIVATE_TRANSFER_OK, text, strlen(text));
else
- yasl_surface_complete_paste(target, id, YASL_TRANSFER_UNAVAILABLE, NULL, 0);
+ yasl_private_surface_complete_paste(target, id, YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0);
return true;
} else {
struct paste_request *r = calloc(1, sizeof(*r));
@@ -2067,7 +2628,7 @@ static bool request_paste(struct yasl_display *base, enum yasl_selection sel,
r->selection = selection;
r->id = id;
errno = 0;
- r->timeout = yasl_loop_add_timer(d->loop, PASTE_TIMEOUT_NS,
+ r->timeout = yasl_private_loop_add_timer(d->loop, PASTE_TIMEOUT_NS,
paste_timeout, r);
if (!r->timeout) {
XDestroyWindow(d->native, r->window);
@@ -2084,17 +2645,17 @@ static bool request_paste(struct yasl_display *base, enum yasl_selection sel,
}
}
-static void paste(struct yasl_display *base, enum yasl_selection sel,
+static void paste(struct yasl_private_display *base, enum yasl_private_selection sel,
struct yasl_surface *target)
{
(void)request_paste(base, sel, target, 0);
}
-static bool input_poll(struct yasl_surface *base, struct yasl_event *event)
+static bool input_poll(struct yasl_surface *base, struct yasl_private_event *event)
{
struct x11_surface *s = (struct x11_surface *)base;
if (s->destroyed) return false;
- if (base->display->events) return yasl_events_poll_surface(base, event);
+ if (base->display->events) return yasl_private_events_poll_surface(base, event);
return input_queue_pop(&s->input, event);
}
@@ -2110,47 +2671,47 @@ static void schedule_redraw(struct yasl_surface *base)
s->want_draw = true;
struct x11_display *d = (struct x11_display *)base->display;
if (d && d->loop)
- yasl_loop_kick(d->loop);
+ yasl_private_loop_kick(d->loop);
}
}
-static struct yasl_display *surface_display(const struct yasl_surface *s) { return s->display; }
-static struct yasl_geometry geometry(const struct yasl_surface *s)
+static struct yasl_private_display *surface_display(const struct yasl_surface *s) { return s->display; }
+static struct yasl_private_geometry geometry(const struct yasl_surface *s)
{
- return (struct yasl_geometry){((const struct x11_surface *)s)->size, YASL_SCALE_UNIT};
+ return (struct yasl_private_geometry){((const struct x11_surface *)s)->size, YASL_PRIVATE_SCALE_UNIT};
}
-static int mods(const struct yasl_display *d) { return (int)((const struct x11_display *)d)->mods; }
-static void *native_display(struct yasl_display *d) { return ((struct x11_display *)d)->native; }
+static int mods(const struct yasl_private_display *d) { return (int)((const struct x11_display *)d)->mods; }
+static void *native_display(struct yasl_private_display *d) { return ((struct x11_display *)d)->native; }
static void *native_surface(struct yasl_surface *s) { return (void *)(uintptr_t)((struct x11_surface *)s)->window; }
-static struct yasl_timing timing(const struct yasl_surface *base)
+static struct yasl_private_timing timing(const struct yasl_surface *base)
{
const struct x11_surface *s = (const struct x11_surface *)base;
- struct yasl_timing t = {.refresh_ns = s->clock.refresh_ns,
+ struct yasl_private_timing t = {.refresh_ns = s->clock.refresh_ns,
.last_present_ns = s->clock.last_present_ns,
- .next_present_ns = yasl_clock_next_present_ns(&s->clock),
+ .next_present_ns = yasl_private_clock_next_present_ns(&s->clock),
.source = s->clock.source};
- yasl_clock_resize_stats(&s->clock, &t.resize);
+ yasl_private_clock_resize_stats(&s->clock, &t.resize);
return t;
}
static uint64_t frame_time(struct yasl_surface *s, uint64_t now)
{
- return yasl_clock_frame_timestamp_ns(&((struct x11_surface *)s)->clock, now);
+ return yasl_private_clock_frame_timestamp_ns(&((struct x11_surface *)s)->clock, now);
}
-static void cursor(struct yasl_surface *base, enum yasl_cursor cursor)
+static void cursor(struct yasl_surface *base, enum yasl_private_cursor cursor)
{
static const unsigned shapes[] = {XC_left_ptr, XC_xterm, XC_hand2, XC_crosshair,
XC_fleur, XC_bottom_right_corner, XC_bottom_left_corner,
XC_sb_h_double_arrow, XC_sb_v_double_arrow};
struct x11_surface *s = (struct x11_surface *)base;
- if (s->destroyed || (unsigned)cursor > YASL_CURSOR_HIDDEN) return;
+ if (s->destroyed || (unsigned)cursor > YASL_PRIVATE_CURSOR_HIDDEN) return;
struct x11_display *d = (struct x11_display *)base->display;
if (!d->native) return;
if (!d->cursors[cursor]) {
- if (cursor == YASL_CURSOR_HIDDEN) {
+ if (cursor == YASL_PRIVATE_CURSOR_HIDDEN) {
char bits[] = {0};
Pixmap pixmap = XCreateBitmapFromData(d->native, s->window, bits, 1, 1);
XColor color = {0};
@@ -2164,7 +2725,7 @@ static void cursor(struct yasl_surface *base, enum yasl_cursor cursor)
XDefineCursor(d->native, s->window, d->cursors[cursor]);
}
-static bool place(struct yasl_surface *base, struct yasl_vector2i at)
+static bool place(struct yasl_surface *base, struct yasl_private_vector2i at)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -2227,7 +2788,7 @@ static bool xsettings_int(const unsigned char *p, size_t len, const char *name,
return false;
}
-static int double_click_ms(const struct yasl_display *base)
+static int double_click_ms(const struct yasl_private_display *base)
{
const struct x11_display *d = (const struct x11_display *)base;
if (d->native) {
@@ -2255,12 +2816,12 @@ static int double_click_ms(const struct yasl_display *base)
}
static bool read_pixels(struct yasl_surface *base, uint32_t *out, size_t cap,
- struct yasl_vector2i *size)
+ struct yasl_private_vector2i *size)
{
struct x11_surface *s = (struct x11_surface *)base;
/* presented stays set from the last draw until the next one starts. */
if (s->destroyed || s->drawing || !s->presented || !s->pixels) return false;
- return yasl_copy_frame(s->pixels, s->size, out, cap, size);
+ return yasl_private_copy_frame(s->pixels, s->size, out, cap, size);
}
static bool bell(struct yasl_surface *base)
@@ -2275,16 +2836,16 @@ static bool bell(struct yasl_surface *base)
return true;
}
-static void drag_end(struct x11_display *d, enum yasl_drag_end how)
+static void drag_end(struct x11_display *d, enum yasl_private_drag_end how)
{
if (!d || !d->drag.active) return;
- struct yasl_drag_listener l = d->drag.listener;
+ struct yasl_private_drag_listener l = d->drag.listener;
void *ud = d->drag.ud;
struct x11_surface *hover = d->drag.hover;
- struct yasl_vector2i hover_pos = d->drag.hover_pos;
+ struct yasl_private_vector2i hover_pos = d->drag.hover_pos;
d->drag.active = false;
- d->drag.listener = (struct yasl_drag_listener){0};
+ d->drag.listener = (struct yasl_private_drag_listener){0};
d->drag.hover = NULL;
d->drag.origin = NULL;
d->drag.carried = NULL;
@@ -2299,19 +2860,19 @@ static void drag_end(struct x11_display *d, enum yasl_drag_end how)
}
if (hover && !hover->destroyed) {
- if (how == YASL_DRAG_DROPPED)
- yasl_surface_notify_drag(&hover->base, YASL_DRAG_DROP, hover_pos);
+ if (how == YASL_PRIVATE_DRAG_DROPPED)
+ yasl_private_surface_notify_drag(&hover->base, YASL_PRIVATE_DRAG_DROP, hover_pos);
else
- yasl_surface_notify_drag(&hover->base, YASL_DRAG_LEAVE, hover_pos);
+ yasl_private_surface_notify_drag(&hover->base, YASL_PRIVATE_DRAG_LEAVE, hover_pos);
}
if (l.end)
l.end(ud, how);
}
-static bool drag_start(struct yasl_display *base, struct yasl_surface *origin,
- const struct yasl_drag_image *image,
- const struct yasl_drag_listener *l, void *ud)
+static bool drag_start(struct yasl_private_display *base, struct yasl_surface *origin,
+ const struct yasl_private_drag_image *image,
+ const struct yasl_private_drag_listener *l, void *ud)
{
struct x11_display *d = (struct x11_display *)base;
if (!d || !origin || d->drag.active || !l)
@@ -2383,12 +2944,12 @@ static bool drag_start(struct yasl_display *base, struct yasl_surface *origin,
return true;
}
-static void drag_cancel(struct yasl_display *base)
+static void drag_cancel(struct yasl_private_display *base)
{
- drag_end((struct x11_display *)base, YASL_DRAG_CANCELLED);
+ drag_end((struct x11_display *)base, YASL_PRIVATE_DRAG_CANCELLED);
}
-static bool drag_carry(struct yasl_surface *base, struct yasl_vector2i offset)
+static bool drag_carry(struct yasl_surface *base, struct yasl_private_vector2i offset)
{
struct x11_display *d = (struct x11_display *)base->display;
if (!d || !d->drag.active)
@@ -2420,7 +2981,7 @@ static bool interactive_move(struct yasl_surface *base)
return true;
}
-static bool interactive_resize(struct yasl_surface *base, enum yasl_resize_edge edge)
+static bool interactive_resize(struct yasl_surface *base, enum yasl_private_resize_edge edge)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -2432,14 +2993,14 @@ static bool interactive_resize(struct yasl_surface *base, enum yasl_resize_edge
int dir;
switch (edge) {
- case YASL_EDGE_TOP_LEFT: dir = 0; break;
- case YASL_EDGE_TOP: dir = 1; break;
- case YASL_EDGE_TOP_RIGHT: dir = 2; break;
- case YASL_EDGE_RIGHT: dir = 3; break;
- case YASL_EDGE_BOTTOM_RIGHT: dir = 4; break;
- case YASL_EDGE_BOTTOM: dir = 5; break;
- case YASL_EDGE_BOTTOM_LEFT: dir = 6; break;
- case YASL_EDGE_LEFT: dir = 7; break;
+ case YASL_PRIVATE_EDGE_TOP_LEFT: dir = 0; break;
+ case YASL_PRIVATE_EDGE_TOP: dir = 1; break;
+ case YASL_PRIVATE_EDGE_TOP_RIGHT: dir = 2; break;
+ case YASL_PRIVATE_EDGE_RIGHT: dir = 3; break;
+ case YASL_PRIVATE_EDGE_BOTTOM_RIGHT: dir = 4; break;
+ case YASL_PRIVATE_EDGE_BOTTOM: dir = 5; break;
+ case YASL_PRIVATE_EDGE_BOTTOM_LEFT: dir = 6; break;
+ case YASL_PRIVATE_EDGE_LEFT: dir = 7; break;
default: return false;
}
@@ -2448,7 +3009,7 @@ static bool interactive_resize(struct yasl_surface *base, enum yasl_resize_edge
return true;
}
-static bool show_window_menu(struct yasl_surface *base, struct yasl_vector2i pos)
+static bool show_window_menu(struct yasl_surface *base, struct yasl_private_vector2i pos)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -2458,7 +3019,18 @@ static bool show_window_menu(struct yasl_surface *base, struct yasl_vector2i pos
return true;
}
-static void set_ime_caret(struct yasl_surface *base, struct yasl_rect2i caret)
+static bool surface_update_text_input(struct yasl_surface *base)
+{
+ struct x11_surface *s = (struct x11_surface *)base;
+ if (!s || s->destroyed || !base->display) return false;
+ if (s->ic) {
+ if (s->focused && base->text_input_active) XSetICFocus(s->ic);
+ else XUnsetICFocus(s->ic);
+ }
+ return true;
+}
+
+static void set_ime_caret(struct yasl_surface *base, struct yasl_private_rect2i caret)
{
struct x11_surface *s = (struct x11_surface *)base;
if (!s) return;
@@ -2489,8 +3061,15 @@ static bool ime_preedit_cursor(const struct yasl_surface *base, int *begin, int
return true;
}
-const struct yasl_backend_ops yasl_x11_backend = {
- .type = YASL_BACKEND_X11,
+const struct yasl_private_backend_ops yasl_private_x11_backend = {
+#if YASL_HAS_EGL
+ .surface_create_gl = create_gl_surface,
+ .gl_make_current = gl_make_current,
+ .gl_get_proc_address = gl_get_proc_address,
+ .gl_swap_interval = gl_swap_interval,
+ .gl_swap_buffers = gl_swap_buffers,
+#endif
+ .type = YASL_PRIVATE_BACKEND_X11,
.display_open = display_open,
.display_close = display_close,
.display_caps = caps,
@@ -2530,6 +3109,7 @@ const struct yasl_backend_ops yasl_x11_backend = {
.surface_start_interactive_move = interactive_move,
.surface_start_interactive_resize = interactive_resize,
.surface_show_window_menu = show_window_menu,
+ .surface_update_text_input = surface_update_text_input,
.surface_set_ime_caret = set_ime_caret,
.surface_ime_preedit = ime_preedit,
.surface_ime_preedit_cursor = ime_preedit_cursor,