summaryrefslogtreecommitdiff
path: root/src/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/cocoa')
-rw-r--r--src/cocoa/api.h47
-rw-r--r--src/cocoa/meson.build1
-rw-r--r--src/cocoa/window.m516
3 files changed, 465 insertions, 99 deletions
diff --git a/src/cocoa/api.h b/src/cocoa/api.h
new file mode 100644
index 0000000..ad259df
--- /dev/null
+++ b/src/cocoa/api.h
@@ -0,0 +1,47 @@
+#ifndef YASL_COCOA_API_H
+#define YASL_COCOA_API_H
+
+#include "common/backend.h"
+
+struct cocoa_display;
+struct cocoa_surface;
+
+struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec);
+void cocoa_display_close(struct cocoa_display *d);
+uint32_t cocoa_display_caps(const struct cocoa_display *d);
+void cocoa_display_dispatch(struct cocoa_display *d);
+void cocoa_display_flush(struct cocoa_display *d);
+int cocoa_display_modifiers(const struct cocoa_display *d);
+void cocoa_display_copy(struct cocoa_display *d, enum yasl_selection sel, const char *text);
+void cocoa_display_paste(struct cocoa_display *d, enum yasl_selection sel, struct cocoa_surface *target);
+bool cocoa_display_drag_start(struct cocoa_display *d, struct cocoa_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud);
+void cocoa_display_drag_cancel(struct cocoa_display *d);
+struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d, const struct yasl_surface_spec *spec);
+struct cocoa_surface *cocoa_surface_create_popup(struct cocoa_surface *parent, const struct yasl_popup_spec *spec);
+bool cocoa_surface_popup_reposition(struct cocoa_surface *popup, const struct yasl_popup_spec *spec);
+void cocoa_surface_destroy(struct cocoa_surface *s);
+struct cocoa_display *cocoa_surface_display(const struct cocoa_surface *s);
+void cocoa_surface_set_callbacks(struct cocoa_surface *s, const struct yasl_surface_cbs *cbs, void *ud);
+void cocoa_surface_set_title(struct cocoa_surface *s, const char *title);
+void cocoa_surface_schedule_redraw(struct cocoa_surface *s);
+bool cocoa_surface_present(struct cocoa_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage);
+bool cocoa_surface_input_poll(struct cocoa_surface *s, struct yasl_input_event *ev);
+struct yasl_vector2i cocoa_surface_size(const struct cocoa_surface *s);
+uint32_t cocoa_surface_scale_120(const struct cocoa_surface *s);
+uint32_t cocoa_surface_state(const struct cocoa_surface *s);
+struct yasl_timing cocoa_surface_timing(const struct cocoa_surface *s);
+uint64_t cocoa_surface_frame_time_ns(struct cocoa_surface *s, uint64_t now);
+void cocoa_surface_set_cursor(struct cocoa_surface *s, enum yasl_cursor cursor);
+void cocoa_surface_set_background_color(struct cocoa_surface *s, uint32_t bg);
+const char *cocoa_surface_ime_preedit(const struct cocoa_surface *s);
+bool cocoa_surface_ime_preedit_cursor(const struct cocoa_surface *s, int *begin, int *end);
+void cocoa_surface_set_ime_caret(struct cocoa_surface *s, struct yasl_rect2i caret);
+bool cocoa_surface_start_interactive_move(struct cocoa_surface *s);
+bool cocoa_surface_start_interactive_resize(struct cocoa_surface *s, enum yasl_resize_edge edge);
+bool cocoa_surface_show_window_menu(struct cocoa_surface *s, struct yasl_vector2i pos);
+bool cocoa_surface_drag_carry(struct cocoa_surface *s, struct yasl_vector2i offset);
+bool cocoa_surface_place_under_pointer(struct cocoa_surface *s, struct yasl_vector2i at);
+void *cocoa_display_get_native_handle(struct cocoa_display *d);
+void *cocoa_surface_get_native_handle(struct cocoa_surface *s);
+
+#endif
diff --git a/src/cocoa/meson.build b/src/cocoa/meson.build
new file mode 100644
index 0000000..0bd40a3
--- /dev/null
+++ b/src/cocoa/meson.build
@@ -0,0 +1 @@
+sources += files('window.m')
diff --git a/src/cocoa/window.m b/src/cocoa/window.m
index 0edf694..bc6060f 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)
@@ -319,7 +322,7 @@ static void push_pointer(struct yasl_surface *w, NSEvent *ev, enum yasl_pointer_
w->pointer = event_pos(w, ev);
struct yasl_input_event input_ev = {
.kind = YASL_INPUT_MOUSE,
- .surface = w,
+ .surface = &w->base,
.mouse = {
.pos = w->pointer,
.button = button,
@@ -392,7 +395,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]]
@@ -409,11 +412,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;
@@ -454,7 +457,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;
}
@@ -462,16 +465,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;
@@ -508,13 +511,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;
@@ -524,14 +527,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);
@@ -577,7 +580,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) {
@@ -589,7 +592,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,
@@ -612,14 +615,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; }
@@ -629,28 +632,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);
@@ -666,7 +669,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;
@@ -710,13 +713,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--;
@@ -737,7 +740,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++;
@@ -769,31 +772,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))
@@ -814,7 +842,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,
@@ -824,7 +852,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++;
@@ -834,7 +862,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;
@@ -843,7 +871,7 @@ static void pump_window(struct yasl_surface *w)
@autoreleasepool { render_and_commit(w); }
}
-void yasl_display_dispatch(struct yasl_display *d)
+void cocoa_display_dispatch(struct cocoa_display *d)
{
assert([NSThread isMainThread]);
if (!d || d->pumping)
@@ -868,7 +896,7 @@ void yasl_display_dispatch(struct yasl_display *d)
}
}
-void yasl_display_flush(struct yasl_display *d)
+void cocoa_display_flush(struct cocoa_display *d)
{
assert([NSThread isMainThread]);
if (!d) return;
@@ -884,7 +912,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;
@@ -946,12 +974,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) {
@@ -962,7 +991,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");
@@ -976,32 +1005,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);
@@ -1027,7 +1057,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];
@@ -1053,9 +1101,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];
@@ -1065,17 +1114,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;
@@ -1114,19 +1163,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;
@@ -1139,7 +1188,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;
@@ -1152,7 +1201,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;
@@ -1166,23 +1215,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;
@@ -1193,7 +1242,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;
@@ -1202,44 +1251,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)
{
@@ -1247,34 +1296,303 @@ 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 : &empty;
+ 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 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_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,
+};