summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cocoa/window.m84
-rw-r--r--src/common/native.c36
-rw-r--r--src/wayland/api.h1
-rw-r--r--src/x11/window.c72
4 files changed, 183 insertions, 10 deletions
diff --git a/src/cocoa/window.m b/src/cocoa/window.m
index 6235b77..7b59865 100644
--- a/src/cocoa/window.m
+++ b/src/cocoa/window.m
@@ -3,6 +3,7 @@
#import <QuartzCore/QuartzCore.h>
#include "cocoa/api.h"
+#include "yasl/native/cocoa.h"
#include "common/timing.h"
#include "common/loop.h"
#include "cocoa/keycodes.h"
@@ -112,6 +113,14 @@ struct cocoa_display {
YaslAppDelegate *delegate;
NSPoint cascade;
struct cocoa_surface *dead;
+ struct {
+ bool active;
+ struct cocoa_surface *origin;
+ struct cocoa_surface *carried;
+ struct yasl_vector2i carry_offset;
+ struct yasl_drag_listener listener;
+ void *ud;
+ } drag;
int depth;
bool open;
bool launched;
@@ -121,6 +130,18 @@ struct cocoa_display {
static struct cocoa_display darwin_ctx;
+static void drag_end(struct cocoa_display *d, enum yasl_drag_end how)
+{
+ if (!d || !d->drag.active) return;
+ struct yasl_drag_listener l = d->drag.listener;
+ void *ud = d->drag.ud;
+ d->drag.active = false;
+ d->drag.origin = NULL;
+ d->drag.carried = NULL;
+ if (l.end)
+ l.end(ud, how);
+}
+
static void render_and_commit(struct cocoa_surface *w);
static void reap_dead(struct cocoa_display *d);
@@ -341,6 +362,11 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer
},
};
input_queue_push(&w->input, &input_ev);
+ if (kind == YASL_PTR_MOTION && darwin_ctx.drag.active && darwin_ctx.drag.carried) {
+ cocoa_surface_place_under_pointer(darwin_ctx.drag.carried, darwin_ctx.drag.carry_offset);
+ } else if (kind == YASL_PTR_RELEASE && darwin_ctx.drag.active) {
+ drag_end(&darwin_ctx, YASL_DRAG_DROPPED);
+ }
if (proximity) {
w->tablet_device = YASL_PTR_DEV_MOUSE;
w->tablet_down = false;
@@ -1079,6 +1105,7 @@ struct cocoa_display *cocoa_display_open(struct yasl_loop *loop, const struct ya
void cocoa_display_close(struct cocoa_display *d)
{
if (!d) return;
+ drag_end(d, YASL_DRAG_CANCELLED);
assert(!d->count && "destroy every surface before its display");
reap_dead(d);
if (d->key_up_monitor) {
@@ -1101,7 +1128,8 @@ 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 |
+ return d ? (YASL_CAP_DRAG | YASL_CAP_DRAG_CARRY | YASL_CAP_PLACE_WINDOW |
+ YASL_CAP_CSD | YASL_CAP_NATIVE_GRAPHICS |
YASL_CAP_FRAME_PACING | YASL_CAP_TABLET) : 0;
}
@@ -1220,6 +1248,8 @@ void cocoa_surface_destroy(struct cocoa_surface *w)
{
assert([NSThread isMainThread]);
if (!w || w->destroyed) return;
+ if (darwin_ctx.drag.active && (darwin_ctx.drag.origin == w || darwin_ctx.drag.carried == w))
+ drag_end(&darwin_ctx, YASL_DRAG_CANCELLED);
darwin_ctx.depth++;
bool native_closed = w->closed;
static const struct yasl_surface_cbs no_callbacks = {0};
@@ -1374,22 +1404,40 @@ bool cocoa_surface_popup_reposition(struct cocoa_surface *popup,
return false;
}
+bool cocoa_surface_start_interactive_move(struct cocoa_surface *s)
+{
+ if (!s || !s->window) return false;
+ [s->window performWindowDragWithEvent:[NSApp currentEvent]];
+ return true;
+}
+
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)d; (void)origin; (void)image; (void)l; (void)ud;
- return false;
+ (void)image;
+ if (!d || !origin || d->drag.active || !l)
+ return false;
+ d->drag.active = true;
+ d->drag.origin = origin;
+ d->drag.carried = NULL;
+ d->drag.listener = *l;
+ d->drag.ud = ud;
+ return true;
}
-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; }
+void cocoa_display_drag_cancel(struct cocoa_display *d)
+{
+ drag_end(d, YASL_DRAG_CANCELLED);
+}
-bool cocoa_surface_start_interactive_move(struct cocoa_surface *s)
+bool cocoa_surface_drag_carry(struct cocoa_surface *w, struct yasl_vector2i offset)
{
- if (!s || !s->window) return false;
- [s->window performWindowDragWithEvent:[NSApp currentEvent]];
- return true;
+ if (!w || w->closed || !darwin_ctx.drag.active)
+ return false;
+ darwin_ctx.drag.carried = w;
+ darwin_ctx.drag.carry_offset = offset;
+ return cocoa_surface_place_under_pointer(w, offset);
}
bool cocoa_surface_start_interactive_resize(struct cocoa_surface *s, enum yasl_resize_edge edge)
@@ -1691,3 +1739,21 @@ const struct yasl_backend_ops yasl_cocoa_backend = {
.surface_get_native_handle = impl_surface_get_native_handle,
.surface_get_native_frame = impl_surface_get_native_frame,
};
+
+NSApplication *yasl_cocoa_display_get_application(struct yasl_display *d)
+{
+ return (d && yasl_display_backend(d) == YASL_BACKEND_COCOA) ?
+ (NSApplication *)yasl_display_get_native_handle(d) : nil;
+}
+
+NSWindow *yasl_cocoa_surface_get_window(struct yasl_surface *s)
+{
+ return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_COCOA) ?
+ (NSWindow *)yasl_surface_get_native_handle(s) : nil;
+}
+
+NSView *yasl_cocoa_surface_get_view(struct yasl_surface *s)
+{
+ NSWindow *w = yasl_cocoa_surface_get_window(s);
+ return w ? w.contentView : nil;
+}
diff --git a/src/common/native.c b/src/common/native.c
index 2d9c06f..6e1c69a 100644
--- a/src/common/native.c
+++ b/src/common/native.c
@@ -1,5 +1,13 @@
#include "backend.h"
+#if YASL_HAS_WAYLAND
+#include "yasl/native/wayland.h"
+#endif
+
+#if YASL_HAS_X11
+#include "yasl/native/x11.h"
+#endif
+
#include <errno.h>
void *yasl_display_get_native_handle(struct yasl_display *d)
@@ -14,6 +22,34 @@ void *yasl_surface_get_native_handle(struct yasl_surface *s)
s->display->ops->surface_get_native_handle(s) : NULL;
}
+#if YASL_HAS_WAYLAND
+struct wl_display *yasl_wayland_display_get_wl_display(struct yasl_display *d)
+{
+ return (d && yasl_display_backend(d) == YASL_BACKEND_WAYLAND) ?
+ (struct wl_display *)yasl_display_get_native_handle(d) : NULL;
+}
+
+struct wl_surface *yasl_wayland_surface_get_wl_surface(struct yasl_surface *s)
+{
+ return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_WAYLAND) ?
+ (struct wl_surface *)yasl_surface_get_native_handle(s) : NULL;
+}
+#endif
+
+#if YASL_HAS_X11
+Display *yasl_x11_display_get_display(struct yasl_display *d)
+{
+ return (d && yasl_display_backend(d) == YASL_BACKEND_X11) ?
+ (Display *)yasl_display_get_native_handle(d) : NULL;
+}
+
+uintptr_t yasl_x11_surface_get_window(struct yasl_surface *s)
+{
+ return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_X11) ?
+ (uintptr_t)yasl_surface_get_native_handle(s) : 0;
+}
+#endif
+
struct yasl_surface *yasl_surface_create_native(struct yasl_display *d,
const struct yasl_surface_spec *spec, void *graphics_device)
{
diff --git a/src/wayland/api.h b/src/wayland/api.h
index 87e896d..e68aca7 100644
--- a/src/wayland/api.h
+++ b/src/wayland/api.h
@@ -2,6 +2,7 @@
#define YASL_WAYLAND_API_H
#include "common/backend.h"
+#include "yasl/native/wayland.h"
struct wayland_display;
struct wayland_surface;
diff --git a/src/x11/window.c b/src/x11/window.c
index 85f1d22..5e3dba9 100644
--- a/src/x11/window.c
+++ b/src/x11/window.c
@@ -89,6 +89,14 @@ struct x11_display {
bool xi2;
Atom abs_pressure, abs_tilt_x, abs_tilt_y, tool_type, eraser;
struct x11_pointer *pointers;
+ struct {
+ bool active;
+ struct x11_surface *origin;
+ struct x11_surface *carried;
+ struct yasl_vector2i carry_offset;
+ struct yasl_drag_listener listener;
+ void *ud;
+ } drag;
};
static struct x11_display *display_of(const struct yasl_surface *s)
@@ -96,6 +104,10 @@ static struct x11_display *display_of(const struct yasl_surface *s)
return (struct x11_display *)s->display;
}
+static bool place(struct yasl_surface *base, struct yasl_vector2i at);
+static void drag_end(struct x11_display *d, enum yasl_drag_end how);
+static void drag_cancel(struct yasl_display *base);
+
static void leave(struct x11_display *d)
{
if (--d->depth) return;
@@ -284,6 +296,10 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
cookie->evtype != XI_ButtonRelease) return;
Window window = crossing ? ((XIEnterEvent *)cookie->data)->event :
((XIDeviceEvent *)cookie->data)->event;
+ if (cookie->evtype == XI_Motion && d->drag.active && d->drag.carried)
+ place(&d->drag.carried->base, d->drag.carry_offset);
+ else if (cookie->evtype == XI_ButtonRelease && d->drag.active)
+ drag_end(d, YASL_DRAG_DROPPED);
struct x11_surface *s = d->surfaces;
while (s && s->window != window) s = s->next;
if (!s) return;
@@ -357,6 +373,8 @@ static void surface_destroy(struct yasl_surface *base)
struct x11_surface *s = (struct x11_surface *)base;
if (s->destroyed) return;
struct x11_display *d = display_of(base);
+ if (d->drag.active && (d->drag.origin == s || d->drag.carried == s))
+ drag_end(d, YASL_DRAG_CANCELLED);
s->destroyed = true;
for (struct x11_surface **p = &d->surfaces; *p; p = &(*p)->next) {
if (*p == s) { *p = s->next; break; }
@@ -648,6 +666,8 @@ static void dispatch(struct yasl_display *base)
mouse.pos = (struct yasl_vector2i){event.xmotion.x, event.xmotion.y};
mouse.kind = YASL_PTR_MOTION;
state = event.xmotion.state;
+ if (d->drag.active && d->drag.carried)
+ place(&d->drag.carried->base, d->drag.carry_offset);
} else if (event.type == LeaveNotify) {
mouse.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
mouse.kind = YASL_PTR_LEAVE;
@@ -663,6 +683,8 @@ static void dispatch(struct yasl_display *base)
} else {
mouse.kind = event.type == ButtonPress ? YASL_PTR_PRESS : YASL_PTR_RELEASE;
mouse.button = pointer_button(button);
+ if (event.type == ButtonRelease && d->drag.active)
+ drag_end(d, YASL_DRAG_DROPPED);
}
}
d->mods = mouse.mods = modifiers(state);
@@ -849,6 +871,7 @@ static void display_close(struct yasl_display *base)
{
struct x11_display *d = (struct x11_display *)base;
assert(!d->surfaces && "destroy every surface before its display");
+ drag_cancel(base);
cancel_pastes(d, NULL);
if (d->loop && d->watch > 0) yasl_loop_del_fd(d->loop, d->watch);
if (d->owns_loop && d->loop) {
@@ -868,7 +891,8 @@ static void display_close(struct yasl_display *base)
static uint32_t caps(const struct yasl_display *d)
{
- return YASL_CAP_PLACE_WINDOW | YASL_CAP_PRIMARY_SELECTION |
+ return YASL_CAP_DRAG | YASL_CAP_DRAG_CARRY | YASL_CAP_PLACE_WINDOW |
+ YASL_CAP_PRIMARY_SELECTION |
(((const struct x11_display *)d)->xi2 ? YASL_CAP_TABLET : 0);
}
@@ -984,6 +1008,49 @@ static bool place(struct yasl_surface *base, struct yasl_vector2i at)
return true;
}
+static void drag_end(struct x11_display *d, enum yasl_drag_end how)
+{
+ if (!d || !d->drag.active) return;
+ struct yasl_drag_listener l = d->drag.listener;
+ void *ud = d->drag.ud;
+ d->drag.active = false;
+ d->drag.origin = NULL;
+ d->drag.carried = NULL;
+ if (l.end)
+ l.end(ud, how);
+}
+
+static bool drag_start(struct yasl_display *base, struct yasl_surface *origin,
+ const struct yasl_drag_image *image,
+ const struct yasl_drag_listener *l, void *ud)
+{
+ (void)image;
+ struct x11_display *d = (struct x11_display *)base;
+ if (!d || !origin || d->drag.active || !l)
+ return false;
+ d->drag.active = true;
+ d->drag.origin = (struct x11_surface *)origin;
+ d->drag.carried = NULL;
+ d->drag.listener = *l;
+ d->drag.ud = ud;
+ return true;
+}
+
+static void drag_cancel(struct yasl_display *base)
+{
+ drag_end((struct x11_display *)base, YASL_DRAG_CANCELLED);
+}
+
+static bool drag_carry(struct yasl_surface *base, struct yasl_vector2i offset)
+{
+ struct x11_display *d = display_of(base);
+ if (!d || !d->drag.active)
+ return false;
+ d->drag.carried = (struct x11_surface *)base;
+ d->drag.carry_offset = offset;
+ return place(base, offset);
+}
+
static bool interactive_move(struct yasl_surface *base)
{
struct x11_surface *s = (struct x11_surface *)base;
@@ -1008,6 +1075,8 @@ const struct yasl_backend_ops yasl_x11_backend = {
.display_modifiers = mods,
.display_copy = copy,
.display_paste = paste,
+ .display_drag_start = drag_start,
+ .display_drag_cancel = drag_cancel,
.surface_create_toplevel = create_toplevel,
.surface_destroy = surface_destroy,
.surface_display = surface_display,
@@ -1021,6 +1090,7 @@ const struct yasl_backend_ops yasl_x11_backend = {
.surface_timing = timing,
.surface_frame_time_ns = frame_time,
.surface_set_cursor = cursor,
+ .surface_drag_carry = drag_carry,
.surface_place_under_pointer = place,
.surface_start_interactive_move = interactive_move,
.display_get_native_handle = native_display,