summaryrefslogtreecommitdiff
path: root/src/cocoa
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 10:17:33 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 10:17:33 +0300
commit881fb6cb1d64868132287bd9637f4ae1cbc3504c (patch)
tree5688d5f8be69805ccf290178675b522802155e6d /src/cocoa
parent3b8af02be94a510e385f44d58c35c86bb89424a6 (diff)
cursor hidden and tablet support
Diffstat (limited to 'src/cocoa')
-rw-r--r--src/cocoa/window.m78
1 files changed, 63 insertions, 15 deletions
diff --git a/src/cocoa/window.m b/src/cocoa/window.m
index 6e1e457..6235b77 100644
--- a/src/cocoa/window.m
+++ b/src/cocoa/window.m
@@ -91,6 +91,8 @@ struct cocoa_surface {
uint32_t state;
uint32_t mods;
enum yasl_cursor cursor;
+ enum yasl_pointer_device tablet_device;
+ bool tablet_down;
char title[160];
struct yasl_frame_clock clock;
@@ -106,6 +108,7 @@ struct cocoa_display {
char *app_id;
struct yasl_loop *loop;
id key_up_monitor;
+ NSCursor *hidden_cursor;
YaslAppDelegate *delegate;
NSPoint cascade;
struct cocoa_surface *dead;
@@ -284,6 +287,18 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer
{
if (!w || w->closed || button < 0)
return;
+ bool proximity = ev.type == NSEventTypeTabletProximity ||
+ ev.subtype == NSEventSubtypeTabletProximity;
+ if (proximity) {
+ if (ev.isEnteringProximity) {
+ w->tablet_device = ev.pointingDeviceType == NSPointingDeviceTypeEraser ?
+ YASL_PTR_DEV_ERASER : ev.pointingDeviceType == NSPointingDeviceTypePen ?
+ YASL_PTR_DEV_PEN : YASL_PTR_DEV_MOUSE;
+ return;
+ }
+ kind = YASL_PTR_LEAVE;
+ button = 3;
+ }
w->mods = cocoa_mods(ev.modifierFlags);
if (kind != YASL_PTR_LEAVE)
w->pointer = event_pos(w, ev);
@@ -291,20 +306,26 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer
enum yasl_pointer_device device = YASL_PTR_DEV_MOUSE;
struct yasl_pointer_pen pen = {0};
- float press = (float)ev.pressure;
- if (ev.subtype == NSEventSubtypeTabletPoint || press > 0.0f) {
- if (ev.pointingDeviceType == NSPointingDeviceTypeEraser)
- device = YASL_PTR_DEV_ERASER;
- else if (ev.pointingDeviceType == NSPointingDeviceTypePen)
- device = YASL_PTR_DEV_PEN;
-
+ if (kind == YASL_PTR_LEAVE && w->tablet_device != YASL_PTR_DEV_MOUSE) {
+ device = w->tablet_device;
+ w->tablet_down = false;
+ } else if (ev.type == NSEventTypeTabletPoint || ev.subtype == NSEventSubtypeTabletPoint) {
+ /* pointingDeviceType belongs to proximity events. Remember that
+ * event's tool so erasers and zero-pressure hover stay classified. */
+ device = w->tablet_device == YASL_PTR_DEV_ERASER ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN;
+ float press = (float)ev.pressure;
if (press > 1.0f) press = 1.0f;
if (press > 0.0f)
pen.pressure = (uint16_t)(press * 65535.0f);
NSPoint tilt = ev.tilt;
- pen.tilt_x = (int8_t)(tilt.x * 90.0);
- pen.tilt_y = (int8_t)(tilt.y * 90.0);
+ pen.tilt_x = (int8_t)lround(fmax(-1, fmin(1, tilt.x)) * 90.0);
+ pen.tilt_y = (int8_t)lround(fmax(-1, fmin(1, -tilt.y)) * 90.0);
+ if (button == 0 && kind == YASL_PTR_PRESS) w->tablet_down = true;
+ if (button == 0 && kind == YASL_PTR_RELEASE) {
+ w->tablet_down = false;
+ pen.pressure = 0;
+ }
}
struct yasl_input_event input_ev = {
@@ -320,6 +341,10 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer
},
};
input_queue_push(&w->input, &input_ev);
+ if (proximity) {
+ w->tablet_device = YASL_PTR_DEV_MOUSE;
+ w->tablet_down = false;
+ }
}
static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
@@ -328,6 +353,17 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
case YASL_CURSOR_TEXT: return [NSCursor IBeamCursor];
case YASL_CURSOR_LINK: return [NSCursor pointingHandCursor];
case YASL_CURSOR_CROSSHAIR: return [NSCursor crosshairCursor];
+ case YASL_CURSOR_HIDDEN:
+ if (!darwin_ctx.hidden_cursor) {
+ NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
+ [image lockFocus];
+ [[NSColor clearColor] set];
+ NSRectFillUsingOperation(NSMakeRect(0, 0, 1, 1), NSCompositingOperationCopy);
+ [image unlockFocus];
+ darwin_ctx.hidden_cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSZeroPoint];
+ [image release];
+ }
+ return darwin_ctx.hidden_cursor;
case YASL_CURSOR_ARROW:
default: return [NSCursor arrowCursor];
}
@@ -566,6 +602,21 @@ static NSCursor *cocoa_cursor(enum yasl_cursor cursor)
push_pointer(self.surface, event, YASL_PTR_LEAVE, 3);
}
+- (void)tabletProximity:(NSEvent *)event
+{
+ push_pointer(self.surface, event, YASL_PTR_MOTION, 3);
+}
+
+- (void)tabletPoint:(NSEvent *)event
+{
+ struct cocoa_surface *w = self.surface;
+ if (!w) return;
+ bool down = (event.buttonMask & NSEventButtonMaskPenTip) != 0;
+ enum yasl_pointer_kind kind = down == w->tablet_down ? YASL_PTR_MOTION :
+ down ? YASL_PTR_PRESS : YASL_PTR_RELEASE;
+ push_pointer(w, event, kind, 0);
+}
+
- (void)scrollWheel:(NSEvent *)event
{
struct cocoa_surface *w = self.surface;
@@ -1042,6 +1093,7 @@ void cocoa_display_close(struct cocoa_display *d)
NSApp.delegate = nil;
[d->delegate release];
d->delegate = nil;
+ [d->hidden_cursor release];
free(d->app_id);
free(d->windows);
*d = (struct cocoa_display){0};
@@ -1050,7 +1102,7 @@ void cocoa_display_close(struct cocoa_display *d)
uint32_t cocoa_display_caps(const struct cocoa_display *d)
{
return d ? (YASL_CAP_PLACE_WINDOW | YASL_CAP_CSD | YASL_CAP_NATIVE_GRAPHICS |
- YASL_CAP_FRAME_PACING) : 0;
+ YASL_CAP_FRAME_PACING | YASL_CAP_TABLET) : 0;
}
struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
@@ -1230,12 +1282,8 @@ void cocoa_surface_set_background_color(struct cocoa_surface *w, uint32_t bg)
void cocoa_surface_set_cursor(struct cocoa_surface *w, enum yasl_cursor cursor)
{
- if (!w || w->closed || cursor == w->cursor) return;
+ if (!w || w->closed || cursor == w->cursor || (unsigned)cursor > YASL_CURSOR_HIDDEN) return;
w->cursor = cursor;
- if (cursor == YASL_CURSOR_NONE) {
- [NSCursor setHiddenUntilMouseMoves:YES];
- return;
- }
NSPoint p = [w->view convertPoint:w->window.mouseLocationOutsideOfEventStream fromView:nil];
if (w->window.isKeyWindow && NSPointInRect(p, w->view.bounds))
[cocoa_cursor(cursor) set];