summaryrefslogtreecommitdiff
path: root/src/platform/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/cocoa')
-rw-r--r--src/platform/cocoa/window.m275
1 files changed, 205 insertions, 70 deletions
diff --git a/src/platform/cocoa/window.m b/src/platform/cocoa/window.m
index 2f9f8e5..60b20b0 100644
--- a/src/platform/cocoa/window.m
+++ b/src/platform/cocoa/window.m
@@ -12,6 +12,7 @@
#include "keymap.h"
#include <assert.h>
+#include <errno.h>
#include <math.h>
#include <poll.h>
#include <stdio.h>
@@ -172,11 +173,13 @@ static void drag_end(struct cocoa_display *d, enum yasl_drag_end how)
[d->drag.image release];
d->drag.image = nil;
- if (hover && !hover->destroyed && hover->cbs && hover->cbs->drag) {
+ if (hover && !hover->destroyed) {
+ darwin_ctx.depth++;
if (how == YASL_DRAG_DROPPED)
- hover->cbs->drag(&hover->base, YASL_DRAG_DROP, pos, hover->ud);
+ yasl_surface_notify_drag(&hover->base, YASL_DRAG_DROP, pos);
else
- hover->cbs->drag(&hover->base, YASL_DRAG_LEAVE, pos, hover->ud);
+ yasl_surface_notify_drag(&hover->base, YASL_DRAG_LEAVE, pos);
+ darwin_ctx.depth--;
}
if (l.end)
l.end(ud, how);
@@ -187,15 +190,14 @@ static void reap_dead(struct cocoa_display *d);
static void set_state(struct cocoa_surface *w, uint32_t bit, bool on)
{
- if (!w || w->closed)
+ if (!w || w->destroyed || w->closed)
return;
uint32_t next = on ? (w->base.state | bit) : (w->base.state & ~bit);
if (next == w->base.state)
return;
w->base.state = next;
darwin_ctx.depth++;
- if (w->cbs->state)
- w->cbs->state(&w->base, next, w->ud);
+ yasl_surface_notify_state(&w->base, next);
darwin_ctx.depth--;
}
@@ -227,13 +229,14 @@ static void push_focus(struct cocoa_surface *w, bool focused)
input_queue_push(&w->input, &ev);
darwin_ctx.depth++;
set_state(w, YASL_STATE_ACTIVATED, focused);
- cocoa_surface_schedule_redraw(w);
+ if (!w->destroyed && !w->closed)
+ cocoa_surface_schedule_redraw(w);
darwin_ctx.depth--;
}
static void sync_size(struct cocoa_surface *w, bool force)
{
- if (!w || !w->layer || w->closed)
+ if (!w || w->destroyed || !w->layer || w->closed)
return;
uint64_t start = yasl_loop_now_ns();
NSRect bounds = w->view.bounds;
@@ -254,14 +257,15 @@ static void sync_size(struct cocoa_surface *w, bool force)
w->scale_120 = scale_120;
w->layer.contentsScale = scale;
w->layer.drawableSize = CGSizeMake(size.x, size.y);
- if (w->cbs->configure)
- w->cbs->configure(&w->base, (struct yasl_geometry){
+ /* 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){
.size = size, .scale_120 = scale_120,
- }, w->ud);
- cocoa_surface_schedule_redraw(w);
- if (w->view.inLiveResize)
+ });
+ if (!w->destroyed && !w->closed && w->view.inLiveResize)
render_and_commit(w);
- yasl_clock_note_resize(&w->clock, yasl_loop_now_ns() - start);
darwin_ctx.depth--;
}
@@ -427,19 +431,26 @@ static void update_drag_hover(struct cocoa_display *d, NSPoint screenPoint)
struct cocoa_surface *old = d->drag.hover;
struct yasl_vector2i old_pos = d->drag.hover_pos;
d->drag.hover = NULL;
- if (old->cbs && old->cbs->drag && !old->destroyed)
- old->cbs->drag(&old->base, YASL_DRAG_LEAVE, old_pos, old->ud);
+ if (!old->destroyed) {
+ darwin_ctx.depth++;
+ yasl_surface_notify_drag(&old->base, YASL_DRAG_LEAVE, old_pos);
+ darwin_ctx.depth--;
+ }
if (!d->drag.active) return;
}
if (target && target->destroyed) target = NULL;
d->drag.hover = target;
d->drag.hover_pos = pos;
- if (target && !target->destroyed && target->cbs && target->cbs->drag)
- target->cbs->drag(&target->base, YASL_DRAG_OVER, pos, target->ud);
+ if (target && !target->destroyed) {
+ darwin_ctx.depth++;
+ yasl_surface_notify_drag(&target->base, YASL_DRAG_OVER, pos);
+ darwin_ctx.depth--;
+ }
} else if (target && !target->destroyed) {
d->drag.hover_pos = pos;
- if (target->cbs && target->cbs->drag)
- target->cbs->drag(&target->base, YASL_DRAG_OVER, pos, target->ud);
+ darwin_ctx.depth++;
+ yasl_surface_notify_drag(&target->base, YASL_DRAG_OVER, pos);
+ darwin_ctx.depth--;
}
}
@@ -559,15 +570,14 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
(void)sender;
- if (darwin_ctx.cbs && darwin_ctx.cbs->quit)
- darwin_ctx.cbs->quit(darwin_ctx.ud);
+ yasl_display_notify_event(&darwin_ctx.base, YASL_EVENT_DISPLAY_QUIT);
return NSTerminateCancel;
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)visible
{
(void)sender;
- if (!visible && darwin_ctx.cbs && darwin_ctx.cbs->reopen)
- darwin_ctx.cbs->reopen(darwin_ctx.ud);
+ if (!visible)
+ yasl_display_notify_event(&darwin_ctx.base, YASL_EVENT_DISPLAY_REOPEN);
return YES;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
@@ -608,9 +618,11 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
NSPasteboard *pb = [sender draggingPasteboard];
if ([pb canReadItemWithDataConformingToTypes:@[NSPasteboardTypeFileURL]]) {
struct cocoa_surface *w = self.surface;
- if (w && w->cbs && w->cbs->drop) {
+ if (w && !w->closed) {
struct yasl_vector2i pos = dragging_pos(self, sender);
- w->cbs->drop(&w->base, YASL_DROP_OVER, pos, w->ud);
+ darwin_ctx.depth++;
+ yasl_surface_notify_drop(&w->base, YASL_DROP_OVER, pos);
+ darwin_ctx.depth--;
}
return NSDragOperationCopy;
}
@@ -627,9 +639,11 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
NSPasteboard *pb = [sender draggingPasteboard];
if ([pb canReadItemWithDataConformingToTypes:@[NSPasteboardTypeFileURL]]) {
struct cocoa_surface *w = self.surface;
- if (w && w->cbs && w->cbs->drop) {
+ if (w && !w->closed) {
struct yasl_vector2i pos = dragging_pos(self, sender);
- w->cbs->drop(&w->base, YASL_DROP_LEAVE, pos, w->ud);
+ darwin_ctx.depth++;
+ yasl_surface_notify_drop(&w->base, YASL_DROP_LEAVE, pos);
+ darwin_ctx.depth--;
}
}
}
@@ -662,8 +676,11 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
ok = YES;
}
}
- if (w->cbs && w->cbs->drop)
- w->cbs->drop(&w->base, YASL_DROP_LEAVE, pos, w->ud);
+ if (!w->destroyed) {
+ darwin_ctx.depth++;
+ yasl_surface_notify_drop(&w->base, YASL_DROP_LEAVE, pos);
+ darwin_ctx.depth--;
+ }
return ok;
}
@@ -869,13 +886,19 @@ static NSString *plain_string(id string)
{
(void)replacementRange;
struct cocoa_surface *w = self.surface;
- if (!w) return;
+ if (!w || w->destroyed || w->closed) return;
const char *utf8 = plain_string(string).UTF8String;
size_t len = utf8 ? strlen(utf8) : 0;
+ bool had_preedit = w->preedit != NULL;
free(w->preedit);
w->preedit = NULL;
+ darwin_ctx.depth++;
on_text_input(w, utf8, len);
- cocoa_surface_schedule_redraw(w);
+ if (had_preedit)
+ yasl_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; }
@@ -883,24 +906,43 @@ static NSString *plain_string(id string)
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange
replacementRange:(NSRange)replacementRange
{
- (void)selectedRange;
(void)replacementRange;
struct cocoa_surface *w = self.surface;
- if (!w) return;
+ if (!w || w->destroyed || w->closed) return;
NSString *str = plain_string(string);
const char *utf8 = str.length ? str.UTF8String : NULL;
free(w->preedit);
w->preedit = utf8 ? strdup(utf8) : NULL;
- cocoa_surface_schedule_redraw(w);
+ int begin = -1, end = -1;
+ if (w->preedit && selectedRange.location != NSNotFound &&
+ selectedRange.location <= str.length && selectedRange.length <= str.length - selectedRange.location) {
+ NSString *prefix = [str substringToIndex:selectedRange.location];
+ NSString *selection = [str substringWithRange:selectedRange];
+ const char *prefix_utf8 = prefix.UTF8String;
+ const char *selection_utf8 = selection.UTF8String;
+ if (prefix_utf8 && selection_utf8) {
+ begin = (int)strlen(prefix_utf8);
+ end = begin + (int)strlen(selection_utf8);
+ }
+ }
+ darwin_ctx.depth++;
+ yasl_surface_notify_composition(&w->base, w->preedit, begin, end);
+ if (!w->destroyed && !w->closed)
+ cocoa_surface_schedule_redraw(w);
+ darwin_ctx.depth--;
}
- (void)unmarkText
{
struct cocoa_surface *w = self.surface;
- if (!w || !w->preedit) return;
+ if (!w || w->destroyed || w->closed || !w->preedit) return;
free(w->preedit);
w->preedit = NULL;
- cocoa_surface_schedule_redraw(w);
+ darwin_ctx.depth++;
+ yasl_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); }
@@ -971,10 +1013,12 @@ static NSString *plain_string(id string)
bool visible = (self.window.occlusionState & NSWindowOcclusionStateVisible) != 0;
darwin_ctx.depth++;
set_state(w, YASL_STATE_SUSPENDED, !visible);
- if (visible)
- cocoa_surface_schedule_redraw(w);
- else
- w->link.paused = YES;
+ if (!w->destroyed && !w->closed) {
+ if (visible)
+ cocoa_surface_schedule_redraw(w);
+ else
+ w->link.paused = YES;
+ }
darwin_ctx.depth--;
}
@@ -1031,8 +1075,7 @@ static NSString *plain_string(id string)
darwin_ctx.depth++;
w->closed = true;
[w->link invalidate];
- if (w->cbs->close)
- w->cbs->close(&w->base, w->ud);
+ yasl_surface_notify_close(&w->base);
darwin_ctx.depth--;
}
@@ -1081,7 +1124,7 @@ bool cocoa_surface_present(struct cocoa_surface *w, const struct yasl_framebuffe
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 ||
+ if (w->destroyed || w->closed || !w->cbs->draw || w->rendering || w->size.x <= 0 || w->size.y <= 0 ||
(w->base.state & YASL_STATE_SUSPENDED))
return;
@@ -1110,8 +1153,8 @@ static void render_and_commit(struct cocoa_surface *w)
},
};
if (drawable)
- w->cbs->draw(&w->base, &w->frame, w->ud);
- if (!w->closed && !w->did_present) {
+ yasl_surface_draw(&w->base, &w->frame);
+ if (!w->destroyed && !w->closed && !w->did_present) {
w->want_draw = true;
w->frames_skipped++;
}
@@ -1122,7 +1165,7 @@ static void render_and_commit(struct cocoa_surface *w)
static void pump_window(struct cocoa_surface *w)
{
- if (!w || w->closed || !w->want_draw || !w->cbs->draw)
+ if (!w || w->destroyed || w->closed || !w->want_draw || !w->cbs->draw)
return;
if (w->link && !w->frame_due && !w->unpaced)
return;
@@ -1368,6 +1411,7 @@ struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct ya
darwin_ctx.base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_display_cbs){0};
darwin_ctx.cbs = &darwin_ctx.base.callbacks;
darwin_ctx.ud = spec->ud;
+ darwin_ctx.base.callback_ud = spec->ud;
if (spec->app_id) darwin_ctx.app_id = strdup(spec->app_id);
darwin_ctx.base.app_id = darwin_ctx.app_id;
}
@@ -1585,6 +1629,57 @@ 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)
+{
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (!w || w->closed || w->is_popup || size.x <= 0 || size.y <= 0) {
+ errno = EINVAL;
+ return false;
+ }
+ [w->window setContentSize:NSMakeSize(size.x, size.y)];
+ errno = 0;
+ return true;
+}
+
+static bool impl_surface_set_fullscreen(struct yasl_surface *surface, bool enabled)
+{
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (!w || w->closed || w->is_popup || !w->window) {
+ errno = EINVAL;
+ return false;
+ }
+ bool fullscreen = (w->window.styleMask & NSWindowStyleMaskFullScreen) != 0;
+ if (fullscreen != enabled)
+ [w->window toggleFullScreen:nil];
+ errno = 0;
+ return true;
+}
+
+static bool impl_surface_set_maximized(struct yasl_surface *surface, bool enabled)
+{
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (!w || w->closed || w->is_popup || !w->window) {
+ errno = EINVAL;
+ return false;
+ }
+ if (w->window.isZoomed != enabled)
+ [w->window zoom:nil];
+ errno = 0;
+ return true;
+}
+
+static bool impl_surface_minimize(struct yasl_surface *surface)
+{
+ struct cocoa_surface *w = (struct cocoa_surface *)surface;
+ if (!w || w->closed || w->is_popup || !w->window) {
+ errno = EINVAL;
+ return false;
+ }
+ [w->window miniaturize:nil];
+ errno = 0;
+ return true;
+}
+
void cocoa_surface_set_background_color(struct cocoa_surface *w, uint32_t bg)
{
if (!w || w->closed) return;
@@ -1644,34 +1739,54 @@ static NSPasteboard *pasteboard_for_selection(enum yasl_selection sel)
}
}
+static bool cocoa_display_copy_text(struct cocoa_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;
- if (!text) return;
+ (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)
+{
+ assert([NSThread isMainThread]);
+ if (!d || !text) { errno = EINVAL; return false; }
NSPasteboard *pb = pasteboard_for_selection(sel);
- if (!pb) return;
+ if (!pb) { errno = EINVAL; return false; }
NSString *s = [NSString stringWithUTF8String:text];
- if (!s) return;
+ if (!s) { errno = EINVAL; return false; }
[pb clearContents];
- [pb setString:s forType:NSPasteboardTypeString];
+ if (![pb setString:s forType:NSPasteboardTypeString]) {
+ errno = EIO;
+ return false;
+ }
+ errno = 0;
+ return true;
}
-void cocoa_display_paste(struct cocoa_display *d, enum yasl_selection sel, struct cocoa_surface *target)
+static bool cocoa_display_request_paste(struct cocoa_display *d, enum yasl_selection sel,
+ struct cocoa_surface *target, uint64_t id)
{
- (void)d;
- if (!target) return;
+ assert([NSThread isMainThread]);
+ if (!d || !target || target->destroyed || target->closed ||
+ target->base.display != &d->base) {
+ errno = EINVAL;
+ return false;
+ }
NSPasteboard *pb = pasteboard_for_selection(sel);
- if (!pb) return;
+ if (!pb) { errno = EINVAL; return false; }
NSString *s = [pb stringForType:NSPasteboardTypeString];
const char *utf8 = s ? s.UTF8String : NULL;
- if (utf8) {
- struct yasl_event ev = {
- .type = YASL_EVENT_PASTE,
- .surface = &target->base,
- .text = { .data = utf8, .len = strlen(utf8) },
- };
- input_queue_push(&target->input, &ev);
- }
+ enum yasl_transfer_status status = !s ? YASL_TRANSFER_UNAVAILABLE :
+ utf8 ? YASL_TRANSFER_OK : YASL_TRANSFER_FAILED;
+ yasl_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_request_paste(d, sel, target, 0);
}
int cocoa_display_modifiers(const struct cocoa_display *d)
@@ -1990,6 +2105,7 @@ void cocoa_surface_set_callbacks(struct cocoa_surface *w,
{
if (!w || w->closed) return;
w->base.callbacks = cbs ? *cbs : (struct yasl_window_cbs){0};
+ w->base.ud = ud;
w->cbs = &w->base.callbacks;
w->ud = ud;
}
@@ -2071,6 +2187,18 @@ static void impl_display_paste(struct yasl_display *d, enum yasl_selection sel,
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)
+{
+ 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,
+ 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)
{
return cocoa_display_drag_start((struct cocoa_display *)d, (struct cocoa_surface *)origin, image, l, ud);
@@ -2104,6 +2232,12 @@ static void impl_surface_destroy(struct yasl_surface *s)
cocoa_surface_destroy((struct cocoa_surface *)s);
}
+static struct input_queue *impl_surface_input_queue(struct yasl_surface *s)
+{
+ struct cocoa_surface *w = (struct cocoa_surface *)s;
+ return w ? &w->input : NULL;
+}
+
static struct yasl_display *impl_surface_display(const struct yasl_surface *s)
{
return s ? &darwin_ctx.base : NULL;
@@ -2129,11 +2263,6 @@ static bool impl_surface_present(struct yasl_surface *s, const struct yasl_frame
return cocoa_surface_present((struct cocoa_surface *)s, fb, damage);
}
-static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev)
-{
- return cocoa_surface_poll_event((struct cocoa_surface *)s, ev);
-}
-
static struct yasl_geometry impl_surface_geometry(const struct yasl_surface *s)
{
return cocoa_surface_geometry((const struct cocoa_surface *)s);
@@ -2254,18 +2383,24 @@ const struct yasl_backend_ops yasl_cocoa_backend = {
.display_double_click_ms = impl_display_double_click_ms,
.display_copy = impl_display_copy,
.display_paste = impl_display_paste,
+ .display_copy_text = impl_display_copy_text,
+ .display_request_paste = impl_display_request_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_input_queue = impl_surface_input_queue,
+ .surface_set_size = impl_surface_set_size,
+ .surface_set_fullscreen = impl_surface_set_fullscreen,
+ .surface_set_maximized = impl_surface_set_maximized,
+ .surface_minimize = impl_surface_minimize,
.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_poll_event = impl_surface_poll_event,
.surface_geometry = impl_surface_geometry,
.surface_timing = impl_surface_timing,
.surface_frame_time_ns = impl_surface_frame_time_ns,