From 76073fe5fad8799e5850805f2f090af2cb62c741 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Tue, 13 Oct 2026 23:41:31 +0300 Subject: 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 --- src/platform/cocoa/window.m | 1072 ++++++++++++++++++++++++++++++++----------- 1 file changed, 802 insertions(+), 270 deletions(-) (limited to 'src/platform/cocoa/window.m') 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 #import #import +#import #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 #include #include +#include #include #include +#include +#include #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 software_queue; id 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 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 sender) +static struct yasl_private_vector2i dragging_pos(YaslView *view, id 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 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 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 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 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 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 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 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 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 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 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 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 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)graphics_device; - } else { + } else if (!external_gpu) { id 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; } -- cgit v1.2.3