summaryrefslogtreecommitdiff
path: root/src/platform/cocoa
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/cocoa
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/cocoa')
-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
5 files changed, 831 insertions, 299 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;
}