diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-11 23:51:43 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-11 23:51:43 +0300 |
| commit | e813252e685d761235ad45e170d97c9375f51958 (patch) | |
| tree | e57bae545c0eb22aac4119a890b8344ee7cd09d2 /src/cocoa/window.m | |
| parent | 608b49052178ea74f593c925cdeedf352aa1c357 (diff) | |
| parent | 6eac0a5f2c552728efca420b1129fae7d4fea773 (diff) | |
Merge branch 'backend-selection' into main
- Implement runtime backend selection (Wayland, X11, Cocoa)
- Add native X11 backend with clipboard, keyboard, mouse, and placement
- Integrate multi-backend integration tests running under Weston and Xwayland
- Retain zero-hole struct packing, branchless ALU/LUT primitives, and paced event loop
Diffstat (limited to 'src/cocoa/window.m')
| -rw-r--r-- | src/cocoa/window.m | 528 |
1 files changed, 426 insertions, 102 deletions
diff --git a/src/cocoa/window.m b/src/cocoa/window.m index 451f448..8712ce8 100644 --- a/src/cocoa/window.m +++ b/src/cocoa/window.m @@ -2,7 +2,7 @@ #import <Metal/Metal.h> #import <QuartzCore/QuartzCore.h> -#include "yasl/yasl.h" +#include "cocoa/api.h" #include "yasl/timing.h" #include "cocoa/keycodes.h" @@ -27,18 +27,18 @@ enum { }; @interface YaslView : NSView <NSTextInputClient> -@property (nonatomic, assign) struct yasl_surface *surface; +@property (nonatomic, assign) struct cocoa_surface *surface; @end @interface YaslAppDelegate : NSObject <NSApplicationDelegate> @end @interface YaslWindow : NSWindow -@property (nonatomic, assign) struct yasl_surface *surface; +@property (nonatomic, assign) struct cocoa_surface *surface; @end @interface YaslWindowController : NSWindowController <NSWindowDelegate> -@property (nonatomic, assign) struct yasl_surface *surface; +@property (nonatomic, assign) struct cocoa_surface *surface; @property (nonatomic, assign) BOOL fullscreenTransition; @end @@ -72,11 +72,13 @@ static inline void input_queue_clear(struct input_queue *q) q->head = q->tail = q->count = 0; } -struct yasl_surface { +struct cocoa_surface { + struct yasl_surface base; YaslWindow *window; YaslWindowController *controller; YaslView *view; CAMetalLayer *layer; + id<MTLCommandQueue> software_queue; CADisplayLink *link; const struct yasl_surface_cbs *cbs; @@ -106,7 +108,7 @@ struct yasl_surface { bool rendering; bool closed; bool destroyed; - struct yasl_surface *dead_next; + struct cocoa_surface *dead_next; struct input_queue input; struct yasl_vector2i pointer; @@ -119,8 +121,9 @@ struct yasl_surface { struct yasl_frame_clock clock; }; -struct yasl_display { - struct yasl_surface **windows; +struct cocoa_display { + struct yasl_display base; + struct cocoa_surface **windows; int count; int capacity; const struct yasl_display_cbs *cbs; @@ -130,17 +133,17 @@ struct yasl_display { id key_up_monitor; YaslAppDelegate *delegate; NSPoint cascade; - struct yasl_surface *dead; + struct cocoa_surface *dead; int depth; bool open; bool launched; bool pumping; }; -static struct yasl_display darwin_ctx; +static struct cocoa_display darwin_ctx; -static void render_and_commit(struct yasl_surface *w); -static void reap_dead(struct yasl_display *d); +static void render_and_commit(struct cocoa_surface *w); +static void reap_dead(struct cocoa_display *d); static uint64_t media_to_loop_ns(CFTimeInterval t) { @@ -151,7 +154,7 @@ static uint64_t media_to_loop_ns(CFTimeInterval t) return (uint64_t)((double)now + delta); } -static void set_state(struct yasl_surface *w, uint32_t bit, bool on) +static void set_state(struct cocoa_surface *w, uint32_t bit, bool on) { if (!w || w->closed) return; @@ -161,27 +164,27 @@ static void set_state(struct yasl_surface *w, uint32_t bit, bool on) w->state = next; darwin_ctx.depth++; if (w->cbs->state) - w->cbs->state(w, w->state, w->ud); + w->cbs->state(&w->base, w->state, w->ud); darwin_ctx.depth--; } -static void push_focus(struct yasl_surface *w, bool focused) +static void push_focus(struct cocoa_surface *w, bool focused) { if (!w || w->closed) return; struct yasl_input_event ev = { .kind = YASL_INPUT_FOCUS, - .surface = w, + .surface = &w->base, .focus = { .focused = focused }, }; input_queue_push(&w->input, &ev); darwin_ctx.depth++; set_state(w, YASL_STATE_ACTIVATED, focused); - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); darwin_ctx.depth--; } -static void sync_size(struct yasl_surface *w, bool force) +static void sync_size(struct cocoa_surface *w, bool force) { if (!w || !w->layer || w->closed) return; @@ -205,10 +208,10 @@ static void sync_size(struct yasl_surface *w, bool force) w->layer.contentsScale = scale; w->layer.drawableSize = CGSizeMake(size.x, size.y); if (w->cbs->configure) - w->cbs->configure(w, (struct yasl_geometry){ + w->cbs->configure(&w->base, (struct yasl_geometry){ .size = size, .scale_120 = scale_120, }, w->ud); - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); if (w->view.inLiveResize) render_and_commit(w); yasl_clock_note_resize(&w->clock, yasl_loop_now_ns() - start); @@ -246,24 +249,24 @@ static struct yasl_key_event cocoa_key_event(NSEvent *ev, enum yasl_key_action a return k; } -static void on_key_event(struct yasl_surface *w, NSEvent *ev, enum yasl_key_action action) +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_input_event input_ev = { .kind = YASL_INPUT_KEY, - .surface = w, + .surface = &w->base, .key = k, }; input_queue_push(&w->input, &input_ev); } -static void on_text_input(struct yasl_surface *w, const char *text, size_t len) +static void on_text_input(struct cocoa_surface *w, const char *text, size_t len) { if (len) { struct yasl_input_event ev = { .kind = YASL_INPUT_TEXT, - .surface = w, + .surface = &w->base, .text = { .text = text, .len = len }, }; input_queue_push(&w->input, &ev); @@ -297,7 +300,7 @@ static int cocoa_button(NSInteger number) } } -static struct yasl_vector2i event_pos(struct yasl_surface *w, NSEvent *ev) +static struct yasl_vector2i event_pos(struct cocoa_surface *w, NSEvent *ev) { NSPoint p = [w->view convertPoint:ev.locationInWindow fromView:nil]; CGFloat scale = w->window.backingScaleFactor; @@ -309,7 +312,7 @@ static struct yasl_vector2i event_pos(struct yasl_surface *w, NSEvent *ev) }; } -static void push_pointer(struct yasl_surface *w, NSEvent *ev, enum yasl_pointer_kind kind, +static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer_kind kind, int button) { if (!w || w->closed || button < 0) @@ -338,7 +341,7 @@ static void push_pointer(struct yasl_surface *w, NSEvent *ev, enum yasl_pointer_ } struct yasl_input_event input_ev = { - .surface = w, + .surface = &w->base, .kind = YASL_INPUT_MOUSE, .mouse = { .pos = w->pointer, @@ -414,7 +417,7 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return NO; NSPasteboard *pb = [sender draggingPasteboard]; NSArray<NSURL *> *urls = [pb readObjectsForClasses:@[[NSURL class]] @@ -431,11 +434,11 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) if (utf8 && strlen(utf8)) { struct yasl_input_event ev = { .kind = YASL_INPUT_DROP_FILES, - .surface = w, + .surface = &w->base, .drop_files = { .files = utf8, .len = strlen(utf8) }, }; input_queue_push(&w->input, &ev); - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); return YES; } return NO; @@ -476,7 +479,7 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) - (void)viewWillStartLiveResize { [super viewWillStartLiveResize]; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (w) w->layer.presentsWithTransaction = YES; } @@ -484,16 +487,16 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) - (void)viewDidEndLiveResize { [super viewDidEndLiveResize]; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return; w->layer.presentsWithTransaction = NO; - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); } - (void)displayLinkFired:(CADisplayLink *)link { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w || w->closed) return; CFTimeInterval period = link.targetTimestamp - link.timestamp; @@ -530,13 +533,13 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) - (void)cursorUpdate:(NSEvent *)event { (void)event; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; [cocoa_cursor(w ? w->cursor : YASL_CURSOR_ARROW) set]; } - (void)keyDown:(NSEvent *)event { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return; on_key_event(w, event, event.isARepeat ? YASL_KEY_REPEAT : YASL_KEY_PRESS); NSString *chars = event.characters; @@ -546,14 +549,14 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) - (void)keyUp:(NSEvent *)event { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (w) on_key_event(w, event, YASL_KEY_RELEASE); } - (void)flagsChanged:(NSEvent *)event { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return; w->mods = cocoa_mods(event.modifierFlags); on_key_event(w, event, modifier_down(event) ? YASL_KEY_PRESS : YASL_KEY_RELEASE); @@ -599,7 +602,7 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) - (void)scrollWheel:(NSEvent *)event { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return; double dx = event.scrollingDeltaX, dy = event.scrollingDeltaY; if (event.hasPreciseScrollingDeltas) { @@ -611,7 +614,7 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor) if (dy != 0.0) { struct yasl_input_event input_ev = { .kind = YASL_INPUT_MOUSE, - .surface = w, + .surface = &w->base, .mouse = { .pos = w->pointer, .button = dy > 0.0 ? 4 : 5, @@ -634,14 +637,14 @@ static NSString *plain_string(id string) - (void)insertText:(id)string replacementRange:(NSRange)replacementRange { (void)replacementRange; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return; const char *utf8 = plain_string(string).UTF8String; size_t len = utf8 ? strlen(utf8) : 0; free(w->preedit); w->preedit = NULL; on_text_input(w, utf8, len); - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); } - (void)doCommandBySelector:(SEL)selector { (void)selector; } @@ -651,28 +654,28 @@ static NSString *plain_string(id string) { (void)selectedRange; (void)replacementRange; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return; NSString *str = plain_string(string); const char *utf8 = str.length ? str.UTF8String : NULL; free(w->preedit); w->preedit = utf8 ? strdup(utf8) : NULL; - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); } - (void)unmarkText { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w || !w->preedit) return; free(w->preedit); w->preedit = NULL; - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); } - (NSRange)selectedRange { return NSMakeRange(NSNotFound, 0); } - (NSRange)markedRange { - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w || !w->preedit) return NSMakeRange(NSNotFound, 0); return NSMakeRange(0, [NSString stringWithUTF8String:w->preedit].length); @@ -688,7 +691,7 @@ static NSString *plain_string(id string) - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange { (void)range; (void)actualRange; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w || !w->window) return NSZeroRect; CGFloat scale = w->window.backingScaleFactor; if (scale < 1.0) scale = 1.0; @@ -732,13 +735,13 @@ static NSString *plain_string(id string) - (void)windowDidChangeOcclusionState:(NSNotification *)notification { (void)notification; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w) return; bool visible = (self.window.occlusionState & NSWindowOcclusionStateVisible) != 0; darwin_ctx.depth++; set_state(w, YASL_STATE_SUSPENDED, !visible); if (visible) - yasl_surface_schedule_redraw(w); + cocoa_surface_schedule_redraw(w); else w->link.paused = YES; darwin_ctx.depth--; @@ -759,7 +762,7 @@ static NSString *plain_string(id string) - (void)syncWindowState { self.fullscreenTransition = NO; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w || w->closed) return; darwin_ctx.depth++; @@ -791,31 +794,56 @@ static NSString *plain_string(id string) - (void)windowWillClose:(NSNotification *)notification { (void)notification; - struct yasl_surface *w = self.surface; + struct cocoa_surface *w = self.surface; if (!w || w->closed) return; darwin_ctx.depth++; w->closed = true; [w->link invalidate]; if (w->cbs->close) - w->cbs->close(w, w->ud); + w->cbs->close(&w->base, w->ud); darwin_ctx.depth--; } @end -bool yasl_surface_present(struct yasl_surface *w, const struct yasl_framebuffer *fb, +bool cocoa_surface_present(struct cocoa_surface *w, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage) { (void)damage; if (!w || w->closed || !w->rendering || w->did_present || !fb || !fb->native_drawable || fb->native_drawable != w->frame.target.native_drawable) return false; + if (w->software_queue) { + if (fb->pixels != w->pixels || fb->size.x != w->size.x || fb->size.y != w->size.y) + return false; + NSUInteger row_bytes = ((NSUInteger)w->size.x * 4 + 255) & ~(NSUInteger)255; + NSUInteger length = row_bytes * (NSUInteger)w->size.y; + id<MTLBuffer> buffer = [w->layer.device newBufferWithLength:length + options:MTLResourceStorageModeShared]; + if (!buffer) return false; + for (int y = 0; y < w->size.y; y++) + memcpy((char *)buffer.contents + (NSUInteger)y * row_bytes, + w->pixels + (size_t)y * w->size.x, (size_t)w->size.x * 4); + id<MTLCommandBuffer> command = [w->software_queue commandBuffer]; + id<MTLBlitCommandEncoder> blit = [command blitCommandEncoder]; + if (!blit) { [buffer release]; return false; } + id<CAMetalDrawable> drawable = (id<CAMetalDrawable>)fb->native_drawable; + [blit copyFromBuffer:buffer sourceOffset:0 sourceBytesPerRow:row_bytes + sourceBytesPerImage:length sourceSize:MTLSizeMake(w->size.x, w->size.y, 1) + toTexture:drawable.texture destinationSlice:0 destinationLevel:0 + destinationOrigin:MTLOriginMake(0, 0, 0)]; + [blit endEncoding]; + [command presentDrawable:drawable]; + [command commit]; + [buffer release]; + } + yasl_clock_presented(&w->clock, yasl_loop_now_ns(), false); w->did_present = true; return true; } -static void render_and_commit(struct yasl_surface *w) +static void render_and_commit(struct cocoa_surface *w) { if (w->closed || !w->cbs->draw || w->rendering || w->size.x <= 0 || w->size.y <= 0 || (w->state & YASL_STATE_SUSPENDED)) @@ -836,7 +864,7 @@ static void render_and_commit(struct yasl_surface *w) id<CAMetalDrawable> drawable = [w->layer nextDrawable]; w->damage = (struct yasl_damage_list){0}; w->frame = (struct yasl_frame){ - .surface = w, + .surface = &w->base, .target = { .pixels = w->pixels, .size = w->size, @@ -846,7 +874,7 @@ static void render_and_commit(struct yasl_surface *w) }, }; if (drawable) - w->cbs->draw(w, &w->frame, w->ud); + w->cbs->draw(&w->base, &w->frame, w->ud); if (!w->closed && !w->did_present) { w->want_draw = true; w->frames_skipped++; @@ -856,7 +884,7 @@ static void render_and_commit(struct yasl_surface *w) darwin_ctx.depth--; } -static void pump_window(struct yasl_surface *w) +static void pump_window(struct cocoa_surface *w) { if (!w || w->closed || !w->want_draw || !w->cbs->draw) return; @@ -865,7 +893,7 @@ static void pump_window(struct yasl_surface *w) @autoreleasepool { render_and_commit(w); } } -int yasl_display_dispatch_timeout(struct yasl_display *d, int timeout_ms) +int cocoa_display_dispatch_timeout(struct cocoa_display *d, int timeout_ms) { assert([NSThread isMainThread]); if (!d || d->pumping) @@ -909,21 +937,21 @@ int yasl_display_dispatch_timeout(struct yasl_display *d, int timeout_ms) return count; } -void yasl_display_dispatch(struct yasl_display *d) +void cocoa_display_dispatch(struct cocoa_display *d) { if (!d) return; bool immediate = false; for (int i = 0; i < d->count; i++) { - struct yasl_surface *w = d->windows[i]; + struct cocoa_surface *w = d->windows[i]; if (w->input.count > 0 || (w->want_draw && (!w->link || w->frame_due || w->unpaced))) { immediate = true; break; } } - yasl_display_dispatch_timeout(d, immediate ? 0 : -1); + cocoa_display_dispatch_timeout(d, immediate ? 0 : -1); } -void yasl_display_flush(struct yasl_display *d) +void cocoa_display_flush(struct cocoa_display *d) { assert([NSThread isMainThread]); if (!d) return; @@ -939,7 +967,7 @@ void yasl_display_flush(struct yasl_display *d) reap_dead(d); } -void yasl_surface_schedule_redraw(struct yasl_surface *w) +void cocoa_surface_schedule_redraw(struct cocoa_surface *w) { if (!w || w->closed) return; w->want_draw = true; @@ -1001,12 +1029,13 @@ static void place_window(NSWindow *window) darwin_ctx.cascade = [window cascadeTopLeftFromPoint:darwin_ctx.cascade]; } -struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec) +struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct yasl_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.open = true; darwin_ctx.loop = loop; if (spec) { @@ -1017,7 +1046,7 @@ struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl return &darwin_ctx; } -void yasl_display_close(struct yasl_display *d) +void cocoa_display_close(struct cocoa_display *d) { if (!d) return; assert(!d->count && "destroy every surface before its display"); @@ -1031,32 +1060,33 @@ void yasl_display_close(struct yasl_display *d) d->delegate = nil; free(d->app_id); free(d->windows); - *d = (struct yasl_display){0}; + *d = (struct cocoa_display){0}; } -uint32_t yasl_display_caps(const struct yasl_display *d) +uint32_t cocoa_display_caps(const struct cocoa_display *d) { return d ? (YASL_CAP_PLACE_WINDOW | YASL_CAP_CSD) : 0; } -struct yasl_surface *yasl_surface_create_toplevel(struct yasl_display *d, +struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d, const struct yasl_surface_spec *spec) { assert([NSThread isMainThread]); - if (!d || !d->open || !spec || !spec->graphics_device) + if (!d || !d->open || !spec) return NULL; @autoreleasepool { if (darwin_ctx.count >= darwin_ctx.capacity) { int cap = darwin_ctx.capacity ? darwin_ctx.capacity * 2 : 16; - struct yasl_surface **wins = realloc(darwin_ctx.windows, (size_t)cap * sizeof(*wins)); + struct cocoa_surface **wins = realloc(darwin_ctx.windows, (size_t)cap * sizeof(*wins)); if (!wins) return NULL; darwin_ctx.windows = wins; darwin_ctx.capacity = cap; } - struct yasl_surface *w = calloc(1, sizeof(*w)); + struct cocoa_surface *w = calloc(1, sizeof(*w)); if (!w) return NULL; - yasl_surface_set_callbacks(w, NULL, NULL); + w->base.display = &d->base; + cocoa_surface_set_callbacks(w, NULL, NULL); w->clock.refresh_ns = YASL_REFRESH_DEFAULT_NS; const char *t = spec->title ? spec->title : "YASL"; strncpy(w->title, t, sizeof(w->title) - 1); @@ -1082,7 +1112,25 @@ struct yasl_surface *yasl_surface_create_toplevel(struct yasl_display *d, w->view = [[YaslView alloc] initWithFrame:w->window.contentView.bounds]; w->window.contentView = w->view; w->layer = (CAMetalLayer *)w->view.layer; - w->layer.device = (id<MTLDevice>)spec->graphics_device; + if (spec->graphics_device) { + w->layer.device = (id<MTLDevice>)spec->graphics_device; + } else { + id<MTLDevice> device = MTLCreateSystemDefaultDevice(); + w->layer.device = device; + w->software_queue = [device newCommandQueue]; + [device release]; + if (!w->software_queue) { + w->window.delegate = nil; + w->controller.surface = NULL; + [w->window close]; + [w->view release]; + [w->controller release]; + [w->window release]; + free(w); + return NULL; + } + w->layer.framebufferOnly = NO; + } w->link = [[w->view displayLinkWithTarget:w->view selector:@selector(displayLinkFired:)] retain]; @@ -1108,9 +1156,10 @@ struct yasl_surface *yasl_surface_create_toplevel(struct yasl_display *d, } } -static void surface_free(struct yasl_surface *w) +static void surface_free(struct cocoa_surface *w) { [w->link release]; + [w->software_queue release]; [w->view release]; [w->controller release]; [w->window release]; @@ -1120,17 +1169,17 @@ static void surface_free(struct yasl_surface *w) free(w); } -static void reap_dead(struct yasl_display *d) +static void reap_dead(struct cocoa_display *d) { assert(d->depth == 0); while (d->dead) { - struct yasl_surface *w = d->dead; + struct cocoa_surface *w = d->dead; d->dead = w->dead_next; surface_free(w); } } -void yasl_surface_destroy(struct yasl_surface *w) +void cocoa_surface_destroy(struct cocoa_surface *w) { assert([NSThread isMainThread]); if (!w || w->destroyed) return; @@ -1169,19 +1218,19 @@ void yasl_surface_destroy(struct yasl_surface *w) yasl_loop_kick(darwin_ctx.loop); } -struct yasl_display *yasl_surface_display(const struct yasl_surface *w) +struct cocoa_display *cocoa_surface_display(const struct cocoa_surface *w) { return w ? &darwin_ctx : NULL; } -void yasl_surface_set_title(struct yasl_surface *w, const char *title) +void cocoa_surface_set_title(struct cocoa_surface *w, const char *title) { if (!w || w->closed || !title) return; strncpy(w->title, title, sizeof(w->title) - 1); w->window.title = [NSString stringWithUTF8String:w->title] ?: @"YASL"; } -void yasl_surface_set_background_color(struct yasl_surface *w, uint32_t bg) +void cocoa_surface_set_background_color(struct cocoa_surface *w, uint32_t bg) { if (!w || w->closed) return; w->bg_color = bg; @@ -1194,7 +1243,7 @@ void yasl_surface_set_background_color(struct yasl_surface *w, uint32_t bg) dark ? NSAppearanceNameDarkAqua : NSAppearanceNameAqua]; } -void yasl_surface_set_cursor(struct yasl_surface *w, enum yasl_cursor cursor) +void cocoa_surface_set_cursor(struct cocoa_surface *w, enum yasl_cursor cursor) { if (!w || w->closed || cursor == w->cursor) return; w->cursor = cursor; @@ -1207,7 +1256,7 @@ void yasl_surface_set_cursor(struct yasl_surface *w, enum yasl_cursor cursor) [cocoa_cursor(cursor) set]; } -bool yasl_surface_place_under_pointer(struct yasl_surface *w, struct yasl_vector2i at) +bool cocoa_surface_place_under_pointer(struct cocoa_surface *w, struct yasl_vector2i at) { if (!w || w->closed || !w->window) return false; CGFloat scale = w->window.backingScaleFactor; @@ -1221,23 +1270,23 @@ bool yasl_surface_place_under_pointer(struct yasl_surface *w, struct yasl_vector return true; } -void yasl_surface_set_ime_caret(struct yasl_surface *w, struct yasl_rect2i caret) +void cocoa_surface_set_ime_caret(struct cocoa_surface *w, struct yasl_rect2i caret) { if (w) w->ime_caret = caret; } -const char *yasl_surface_ime_preedit(const struct yasl_surface *w) +const char *cocoa_surface_ime_preedit(const struct cocoa_surface *w) { return w ? w->preedit : NULL; } -bool yasl_surface_ime_preedit_cursor(const struct yasl_surface *w, int *begin, int *end) +bool cocoa_surface_ime_preedit_cursor(const struct cocoa_surface *w, int *begin, int *end) { (void)w; (void)begin; (void)end; return false; } -void yasl_display_copy(struct yasl_display *d, enum yasl_selection sel, const char *text) +void cocoa_display_copy(struct cocoa_display *d, enum yasl_selection sel, const char *text) { (void)d; (void)sel; if (!text) return; @@ -1248,7 +1297,7 @@ void yasl_display_copy(struct yasl_display *d, enum yasl_selection sel, const ch [pb setString:s forType:NSPasteboardTypeString]; } -void yasl_display_paste(struct yasl_display *d, enum yasl_selection sel, struct yasl_surface *target) +void cocoa_display_paste(struct cocoa_display *d, enum yasl_selection sel, struct cocoa_surface *target) { (void)d; (void)sel; if (!target) return; @@ -1257,44 +1306,44 @@ void yasl_display_paste(struct yasl_display *d, enum yasl_selection sel, struct if (utf8) { struct yasl_input_event ev = { .kind = YASL_INPUT_PASTE, - .surface = target, + .surface = &target->base, .paste = { .text = utf8, .len = strlen(utf8) }, }; input_queue_push(&target->input, &ev); } } -int yasl_display_modifiers(const struct yasl_display *d) +int cocoa_display_modifiers(const struct cocoa_display *d) { (void)d; return (int)cocoa_mods(NSEvent.modifierFlags); } -struct yasl_vector2i yasl_surface_size(const struct yasl_surface *w) +struct yasl_vector2i cocoa_surface_size(const struct cocoa_surface *w) { return w ? w->size : (struct yasl_vector2i){0}; } -uint32_t yasl_surface_scale_120(const struct yasl_surface *w) +uint32_t cocoa_surface_scale_120(const struct cocoa_surface *w) { return w ? w->scale_120 : YASL_SCALE_UNIT; } -struct yasl_surface *yasl_surface_create_popup(struct yasl_surface *parent, +struct cocoa_surface *cocoa_surface_create_popup(struct cocoa_surface *parent, const struct yasl_popup_spec *spec) { (void)parent; (void)spec; return NULL; } -bool yasl_surface_popup_reposition(struct yasl_surface *popup, +bool cocoa_surface_popup_reposition(struct cocoa_surface *popup, const struct yasl_popup_spec *spec) { (void)popup; (void)spec; return false; } -bool yasl_display_drag_start(struct yasl_display *d, struct yasl_surface *origin, +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) { @@ -1302,34 +1351,309 @@ bool yasl_display_drag_start(struct yasl_display *d, struct yasl_surface *origin return false; } -void yasl_display_drag_cancel(struct yasl_display *d) { (void)d; } -bool yasl_surface_drag_carry(struct yasl_surface *w, struct yasl_vector2i offset) { (void)w; (void)offset; return false; } +void cocoa_display_drag_cancel(struct cocoa_display *d) { (void)d; } +bool cocoa_surface_drag_carry(struct cocoa_surface *w, struct yasl_vector2i offset) { (void)w; (void)offset; return false; } -bool yasl_surface_start_interactive_move(struct yasl_surface *s) +bool cocoa_surface_start_interactive_move(struct cocoa_surface *s) { if (!s || !s->window) return false; [s->window performWindowDragWithEvent:[NSApp currentEvent]]; return true; } -bool yasl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_resize_edge edge) +bool cocoa_surface_start_interactive_resize(struct cocoa_surface *s, enum yasl_resize_edge edge) { (void)s; (void)edge; return false; } -bool yasl_surface_show_window_menu(struct yasl_surface *s, struct yasl_vector2i pos) +bool cocoa_surface_show_window_menu(struct cocoa_surface *s, struct yasl_vector2i pos) { (void)s; (void)pos; return false; } -void *yasl_display_get_native_handle(struct yasl_display *d) +void *cocoa_display_get_native_handle(struct cocoa_display *d) { return d ? (void *)d : NULL; } -void *yasl_surface_get_native_handle(struct yasl_surface *s) +void *cocoa_surface_get_native_handle(struct cocoa_surface *s) { return s ? (void *)s->view : NULL; } + + + +void cocoa_surface_set_callbacks(struct cocoa_surface *w, + const struct yasl_surface_cbs *cbs, void *ud) +{ + static const struct yasl_surface_cbs empty = {0}; + if (!w || w->closed) return; + w->cbs = cbs ? cbs : ∅ + w->ud = ud; +} + +bool cocoa_surface_input_poll(struct cocoa_surface *w, struct yasl_input_event *ev) +{ + return w && ev && input_queue_pop(&w->input, ev); +} + +uint32_t cocoa_surface_state(const struct cocoa_surface *w) +{ + return w ? w->state : 0; +} + +struct yasl_timing cocoa_surface_timing(const struct cocoa_surface *w) +{ + struct yasl_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.frames_skipped = w->frames_skipped; + yasl_clock_resize_stats(&w->clock, &timing.resize); + } + return timing; +} + +uint64_t cocoa_surface_frame_time_ns(struct cocoa_surface *w, uint64_t now) +{ + return w ? yasl_clock_frame_timestamp_ns(&w->clock, now) : now; +} + +static struct yasl_display *impl_display_open(struct yasl_loop *loop, const struct yasl_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) +{ + cocoa_display_close((struct cocoa_display *)d); +} + +static uint32_t impl_display_caps(const struct yasl_display *d) +{ + return cocoa_display_caps((const struct cocoa_display *)d); +} + +static void impl_display_dispatch(struct yasl_display *d) +{ + cocoa_display_dispatch((struct cocoa_display *)d); +} + +static int impl_display_dispatch_timeout(struct yasl_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) +{ + cocoa_display_flush((struct cocoa_display *)d); +} + +static int impl_display_modifiers(const struct yasl_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) +{ + 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) +{ + cocoa_display_paste((struct cocoa_display *)d, sel, (struct cocoa_surface *)target); +} + +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) +{ + 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) +{ + cocoa_display_drag_cancel((struct cocoa_display *)d); +} + +static struct yasl_surface *impl_surface_create_toplevel(struct yasl_display *d, const struct yasl_surface_spec *spec) +{ + struct cocoa_surface *result = cocoa_surface_create_toplevel((struct cocoa_display *)d, spec); + return result ? &result->base : NULL; +} + +static struct yasl_surface *impl_surface_create_popup(struct yasl_surface *parent, const struct yasl_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) +{ + return cocoa_surface_popup_reposition((struct cocoa_surface *)popup, spec); +} + +static void impl_surface_destroy(struct yasl_surface *s) +{ + cocoa_surface_destroy((struct cocoa_surface *)s); +} + +static struct yasl_display *impl_surface_display(const struct yasl_surface *s) +{ + struct cocoa_display *result = cocoa_surface_display((const struct cocoa_surface *)s); + return result ? &result->base : NULL; +} + +static void impl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_surface_cbs *cbs, void *ud) +{ + cocoa_surface_set_callbacks((struct cocoa_surface *)s, cbs, ud); +} + +static void impl_surface_set_title(struct yasl_surface *s, const char *title) +{ + cocoa_surface_set_title((struct cocoa_surface *)s, title); +} + +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) +{ + return cocoa_surface_present((struct cocoa_surface *)s, fb, damage); +} + +static bool impl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev) +{ + return cocoa_surface_input_poll((struct cocoa_surface *)s, ev); +} + +static struct yasl_vector2i impl_surface_size(const struct yasl_surface *s) +{ + return cocoa_surface_size((const struct cocoa_surface *)s); +} + +static uint32_t impl_surface_scale_120(const struct yasl_surface *s) +{ + return cocoa_surface_scale_120((const struct cocoa_surface *)s); +} + +static uint32_t impl_surface_state(const struct yasl_surface *s) +{ + return cocoa_surface_state((const struct cocoa_surface *)s); +} + +static struct yasl_timing impl_surface_timing(const struct yasl_surface *s) +{ + return cocoa_surface_timing((const struct cocoa_surface *)s); +} + +static uint64_t impl_surface_frame_time_ns(struct yasl_surface *s, uint64_t now) +{ + return cocoa_surface_frame_time_ns((struct cocoa_surface *)s, now); +} + +static void impl_surface_set_cursor(struct yasl_surface *s, enum yasl_cursor cursor) +{ + cocoa_surface_set_cursor((struct cocoa_surface *)s, cursor); +} + +static void impl_surface_set_background_color(struct yasl_surface *s, uint32_t bg) +{ + cocoa_surface_set_background_color((struct cocoa_surface *)s, bg); +} + +static const char *impl_surface_ime_preedit(const struct yasl_surface *s) +{ + return cocoa_surface_ime_preedit((const struct cocoa_surface *)s); +} + +static bool impl_surface_ime_preedit_cursor(const struct yasl_surface *s, int *begin, int *end) +{ + 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) +{ + cocoa_surface_set_ime_caret((struct cocoa_surface *)s, caret); +} + +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) +{ + 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) +{ + 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) +{ + 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) +{ + return cocoa_surface_place_under_pointer((struct cocoa_surface *)s, at); +} + +static void *impl_display_get_native_handle(struct yasl_display *d) +{ + return cocoa_display_get_native_handle((struct cocoa_display *)d); +} + +static void *impl_surface_get_native_handle(struct yasl_surface *s) +{ + return cocoa_surface_get_native_handle((struct cocoa_surface *)s); +} + +const struct yasl_backend_ops yasl_cocoa_backend = { + .type = YASL_BACKEND_COCOA, + .display_open = impl_display_open, + .display_close = impl_display_close, + .display_caps = impl_display_caps, + .display_dispatch = impl_display_dispatch, + .display_dispatch_timeout = impl_display_dispatch_timeout, + .display_flush = impl_display_flush, + .display_modifiers = impl_display_modifiers, + .display_copy = impl_display_copy, + .display_paste = impl_display_paste, + .display_drag_start = impl_display_drag_start, + .display_drag_cancel = impl_display_drag_cancel, + .surface_create_toplevel = impl_surface_create_toplevel, + .surface_create_popup = impl_surface_create_popup, + .surface_popup_reposition = impl_surface_popup_reposition, + .surface_destroy = impl_surface_destroy, + .surface_display = impl_surface_display, + .surface_set_callbacks = impl_surface_set_callbacks, + .surface_set_title = impl_surface_set_title, + .surface_schedule_redraw = impl_surface_schedule_redraw, + .surface_present = impl_surface_present, + .surface_input_poll = impl_surface_input_poll, + .surface_size = impl_surface_size, + .surface_scale_120 = impl_surface_scale_120, + .surface_state = impl_surface_state, + .surface_timing = impl_surface_timing, + .surface_frame_time_ns = impl_surface_frame_time_ns, + .surface_set_cursor = impl_surface_set_cursor, + .surface_set_background_color = impl_surface_set_background_color, + .surface_ime_preedit = impl_surface_ime_preedit, + .surface_ime_preedit_cursor = impl_surface_ime_preedit_cursor, + .surface_set_ime_caret = impl_surface_set_ime_caret, + .surface_start_interactive_move = impl_surface_start_interactive_move, + .surface_start_interactive_resize = impl_surface_start_interactive_resize, + .surface_show_window_menu = impl_surface_show_window_menu, + .surface_drag_carry = impl_surface_drag_carry, + .surface_place_under_pointer = impl_surface_place_under_pointer, + .display_get_native_handle = impl_display_get_native_handle, + .surface_get_native_handle = impl_surface_get_native_handle, +}; |
