mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-11-03 09:01:42 -05:00
Use a transient object for the dnd session
This commit is contained in:
parent
5c63df7f1e
commit
e9d37bdc5f
10 changed files with 448 additions and 428 deletions
24
TODO
24
TODO
|
|
@ -27,18 +27,6 @@ Core wayland protocol
|
|||
send a NULL type or x-wayland/root-something type if the source
|
||||
offers that.
|
||||
|
||||
Races between pointer motion, ending the drag, the target sending
|
||||
accept request and the source receiving the target event.
|
||||
|
||||
- We've sent a drag focus or motion event to the source, but
|
||||
haven't received an accept request corresponding to that event
|
||||
and now the button is release. The compositor could wait for
|
||||
the source to reply to outstanding focus/motion events before
|
||||
sending the finish event to the source. Or we could send the
|
||||
finish event through the source so that it needs to reply to the
|
||||
finish event too. Either way, the state of the drag blocks on
|
||||
the client. What if we drag to a client that doesn't doo dnd?
|
||||
|
||||
How do we animate the drag icon back to the drag origin in case of
|
||||
a failed drag?
|
||||
|
||||
|
|
@ -48,18 +36,6 @@ Core wayland protocol
|
|||
that will participate in dnd. Or just assume client is not
|
||||
participating until we receive an accept request.
|
||||
|
||||
May need to look at all offer events before we can decide which one
|
||||
to go with. Problem is, we don't know when we've seen that last
|
||||
offer event.
|
||||
|
||||
Create transient dnd object when a client starts a drag. Announce
|
||||
the dnd object to clients first time the drag enters one of its
|
||||
surfaces. Track if we've already announced the object by comparing
|
||||
the drag start timestamp/serial with the clients last-event
|
||||
timestamp/serial? Wont work if we send other events to a client
|
||||
after creating the drag object. Maybe just keep the transient
|
||||
object on the initiator side?
|
||||
|
||||
- Pointer image issue:
|
||||
|
||||
- A touch input device doesn't have a pointer; indicate that
|
||||
|
|
|
|||
285
clients/dnd.c
285
clients/dnd.c
|
|
@ -44,12 +44,21 @@ struct dnd {
|
|||
struct display *display;
|
||||
uint32_t key;
|
||||
struct item *items[16];
|
||||
};
|
||||
|
||||
struct wl_buffer *translucent_buffer;
|
||||
struct wl_buffer *opaque_buffer;
|
||||
struct dnd_drag {
|
||||
cairo_surface_t *translucent;
|
||||
cairo_surface_t *opaque;
|
||||
int hotspot_x, hotspot_y;
|
||||
uint32_t tag;
|
||||
struct dnd *dnd;
|
||||
struct input *input;
|
||||
};
|
||||
|
||||
struct dnd_offer {
|
||||
struct dnd *dnd;
|
||||
struct wl_array types;
|
||||
const char *drag_type;
|
||||
uint32_t tag;
|
||||
};
|
||||
|
||||
struct item {
|
||||
|
|
@ -218,91 +227,131 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_handle_device(void *data,
|
||||
struct wl_drag *drag, struct wl_input_device *device)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drag_pointer_focus(void *data,
|
||||
struct wl_drag *drag,
|
||||
uint32_t time, struct wl_surface *surface,
|
||||
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
|
||||
{
|
||||
struct dnd *dnd = data;
|
||||
|
||||
/* FIXME: We need the offered types before we get the
|
||||
* pointer_focus event so we know which one we want and can
|
||||
* send the accept request back. */
|
||||
|
||||
fprintf(stderr, "drag pointer focus %p\n", surface);
|
||||
|
||||
if (!surface) {
|
||||
dnd->drag_type = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dnd_get_item(dnd, surface_x, surface_y)) {
|
||||
wl_drag_accept(drag, "text/plain");
|
||||
dnd->drag_type = "text/plain";
|
||||
} else {
|
||||
wl_drag_accept(drag, NULL);
|
||||
dnd->drag_type = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_offer(void *data,
|
||||
struct wl_drag *drag, const char *type)
|
||||
{
|
||||
fprintf(stderr, "drag offer %s\n", type);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_motion(void *data,
|
||||
struct wl_drag *drag,
|
||||
uint32_t time,
|
||||
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
|
||||
{
|
||||
struct dnd *dnd = data;
|
||||
|
||||
/* FIXME: Need to correlate this with the offer event.
|
||||
* Problem is, we don't know when we've seen that last offer
|
||||
* event, and we might need to look at all of them before we
|
||||
* can decide which one to go with. */
|
||||
if (!dnd_get_item(dnd, surface_x, surface_y)) {
|
||||
wl_drag_accept(drag, "text/plain");
|
||||
dnd->drag_type = "text/plain";
|
||||
} else {
|
||||
wl_drag_accept(drag, NULL);
|
||||
dnd->drag_type = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_target(void *data,
|
||||
struct wl_drag *drag, const char *mime_type)
|
||||
{
|
||||
struct dnd *dnd = data;
|
||||
struct input *input;
|
||||
struct dnd_drag *dnd_drag = data;
|
||||
struct dnd *dnd = dnd_drag->dnd;
|
||||
struct wl_input_device *device;
|
||||
cairo_surface_t *surface;
|
||||
struct wl_buffer *buffer;
|
||||
|
||||
fprintf(stderr, "target %s\n", mime_type);
|
||||
input = wl_drag_get_user_data(drag);
|
||||
device = input_get_input_device(input);
|
||||
device = input_get_input_device(dnd_drag->input);
|
||||
if (mime_type)
|
||||
wl_input_device_attach(device, dnd->opaque_buffer,
|
||||
dnd->hotspot_x, dnd->hotspot_y);
|
||||
surface = dnd_drag->opaque;
|
||||
else
|
||||
wl_input_device_attach(device, dnd->translucent_buffer,
|
||||
dnd->hotspot_x, dnd->hotspot_y);
|
||||
surface = dnd_drag->translucent;
|
||||
|
||||
buffer = display_get_buffer_for_surface(dnd->display, surface);
|
||||
wl_input_device_attach(device, buffer,
|
||||
dnd_drag->hotspot_x, dnd_drag->hotspot_y);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_finish(void *data, struct wl_drag *drag, int fd)
|
||||
{
|
||||
struct dnd_drag *dnd_drag = data;
|
||||
char text[] = "[drop data]";
|
||||
|
||||
fprintf(stderr, "got 'finish', fd %d, sending message\n", fd);
|
||||
|
||||
write(fd, text, sizeof text);
|
||||
close(fd);
|
||||
|
||||
/* The 'finish' event marks the end of the session on the drag
|
||||
* source side and we need to clean up the drag object created
|
||||
* and the local state. */
|
||||
wl_drag_destroy(drag);
|
||||
cairo_surface_destroy(dnd_drag->translucent);
|
||||
cairo_surface_destroy(dnd_drag->opaque);
|
||||
free(dnd_drag);
|
||||
}
|
||||
|
||||
static const struct wl_drag_listener drag_listener = {
|
||||
drag_target,
|
||||
drag_finish
|
||||
};
|
||||
|
||||
static void
|
||||
drag_offer_offer(void *data,
|
||||
struct wl_drag_offer *offer, const char *type)
|
||||
{
|
||||
struct dnd_offer *dnd_offer = data;
|
||||
char **p;
|
||||
|
||||
p = wl_array_add(&dnd_offer->types, sizeof *p);
|
||||
if (p)
|
||||
*p = strdup(type);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_offer_pointer_focus(void *data,
|
||||
struct wl_drag_offer *offer,
|
||||
uint32_t time, struct wl_surface *surface,
|
||||
int32_t x, int32_t y,
|
||||
int32_t surface_x, int32_t surface_y)
|
||||
{
|
||||
struct dnd_offer *dnd_offer = data;
|
||||
struct window *window;
|
||||
char **p, **end;
|
||||
|
||||
/* The last event in a dnd session is pointer_focus with a
|
||||
* NULL surface, whether or not we get the drop event. We
|
||||
* need to clean up the dnd_offer proxy and whatever state we
|
||||
* allocated. */
|
||||
if (!surface) {
|
||||
fprintf(stderr, "pointer focus NULL, session over\n");
|
||||
wl_array_release(&dnd_offer->types);
|
||||
free(dnd_offer);
|
||||
wl_drag_offer_destroy(offer);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "drag pointer focus %p\n", surface);
|
||||
fprintf(stderr, "offered types:\n");
|
||||
end = dnd_offer->types.data + dnd_offer->types.size;
|
||||
for (p = dnd_offer->types.data; p < end; p++)
|
||||
fprintf(stderr, "\%s\n", *p);
|
||||
|
||||
window = wl_surface_get_user_data(surface);
|
||||
dnd_offer->dnd = window_get_user_data(window);
|
||||
|
||||
if (!dnd_get_item(dnd_offer->dnd, surface_x, surface_y)) {
|
||||
wl_drag_offer_accept(offer, time, "text/plain");
|
||||
dnd_offer->drag_type = "text/plain";
|
||||
} else {
|
||||
wl_drag_offer_accept(offer, time, NULL);
|
||||
dnd_offer->drag_type = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_offer_motion(void *data,
|
||||
struct wl_drag_offer *offer, uint32_t time,
|
||||
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
|
||||
{
|
||||
struct dnd_offer *dnd_offer = data;
|
||||
struct dnd *dnd = dnd_offer->dnd;
|
||||
|
||||
if (!dnd_get_item(dnd, surface_x, surface_y)) {
|
||||
fprintf(stderr, "drag offer motion %d, %d, accepting\n",
|
||||
surface_x, surface_y);
|
||||
wl_drag_offer_accept(offer, time, "text/plain");
|
||||
dnd_offer->drag_type = "text/plain";
|
||||
} else {
|
||||
fprintf(stderr, "drag offer motion %d, %d, declining\n",
|
||||
surface_x, surface_y);
|
||||
wl_drag_offer_accept(offer, time, NULL);
|
||||
dnd_offer->drag_type = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
|
||||
{
|
||||
struct dnd *dnd = data;
|
||||
struct dnd_offer *dnd_offer = data;
|
||||
char buffer[256];
|
||||
int fd;
|
||||
unsigned int len;
|
||||
|
|
@ -312,7 +361,7 @@ drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
|
|||
fprintf(stderr, "read %d bytes: %s\n", len, buffer);
|
||||
fd = g_io_channel_unix_get_fd(source);
|
||||
close(fd);
|
||||
g_source_remove(dnd->tag);
|
||||
g_source_remove(dnd_offer->tag);
|
||||
|
||||
g_io_channel_unref(source);
|
||||
|
||||
|
|
@ -320,13 +369,13 @@ drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
|
|||
}
|
||||
|
||||
static void
|
||||
drag_drop(void *data, struct wl_drag *drag)
|
||||
drag_offer_drop(void *data, struct wl_drag_offer *offer)
|
||||
{
|
||||
struct dnd *dnd = data;
|
||||
int p[2];
|
||||
struct dnd_offer *dnd_offer = data;
|
||||
GIOChannel *channel;
|
||||
int p[2];
|
||||
|
||||
if (!dnd->drag_type) {
|
||||
if (!dnd_offer->drag_type) {
|
||||
fprintf(stderr, "got 'drop', but no target\n");
|
||||
/* FIXME: Should send response so compositor and
|
||||
* source knows it's over. Can't send -1 to indicate
|
||||
|
|
@ -338,38 +387,39 @@ drag_drop(void *data, struct wl_drag *drag)
|
|||
fprintf(stderr, "got 'drop', sending write end of pipe\n");
|
||||
|
||||
pipe(p);
|
||||
wl_drag_receive(drag, p[1]);
|
||||
wl_drag_offer_receive(offer, p[1]);
|
||||
close(p[1]);
|
||||
|
||||
channel = g_io_channel_unix_new(p[0]);
|
||||
dnd->tag = g_io_add_watch(channel, G_IO_IN, drop_io_func, dnd);
|
||||
dnd_offer->tag = g_io_add_watch(channel, G_IO_IN,
|
||||
drop_io_func, dnd_offer);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_finish(void *data, struct wl_drag *drag, int fd)
|
||||
{
|
||||
char text[] = "[drop data]";
|
||||
|
||||
fprintf(stderr, "got 'finish', fd %d, sending message\n", fd);
|
||||
|
||||
write(fd, text, sizeof text);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static const struct wl_drag_listener drag_listener = {
|
||||
drag_handle_device,
|
||||
drag_pointer_focus,
|
||||
drag_offer,
|
||||
drag_motion,
|
||||
drag_target,
|
||||
drag_drop,
|
||||
drag_finish
|
||||
static const struct wl_drag_offer_listener drag_offer_listener = {
|
||||
drag_offer_offer,
|
||||
drag_offer_pointer_focus,
|
||||
drag_offer_motion,
|
||||
drag_offer_drop,
|
||||
};
|
||||
|
||||
static cairo_surface_t *
|
||||
create_drag_cursor(struct dnd *dnd, struct item *item, int32_t x, int32_t y,
|
||||
double opacity)
|
||||
static void
|
||||
drag_offer_handler(struct wl_drag_offer *offer, struct display *display)
|
||||
{
|
||||
struct dnd_offer *dnd_offer;
|
||||
|
||||
dnd_offer = malloc(sizeof *dnd_offer);
|
||||
if (dnd_offer == NULL)
|
||||
return;
|
||||
|
||||
wl_drag_offer_add_listener(offer, &drag_offer_listener, dnd_offer);
|
||||
wl_array_init(&dnd_offer->types);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
create_drag_cursor(struct dnd_drag *dnd_drag,
|
||||
struct item *item, int32_t x, int32_t y, double opacity)
|
||||
{
|
||||
struct dnd *dnd = dnd_drag->dnd;
|
||||
cairo_surface_t *surface, *pointer;
|
||||
int32_t pointer_width, pointer_height, hotspot_x, hotspot_y;
|
||||
struct rectangle rectangle;
|
||||
|
|
@ -409,8 +459,8 @@ create_drag_cursor(struct dnd *dnd, struct item *item, int32_t x, int32_t y,
|
|||
display_flush_cairo_device(dnd->display);
|
||||
cairo_destroy(cr);
|
||||
|
||||
dnd->hotspot_x = pointer_width + x - item->x;
|
||||
dnd->hotspot_y = pointer_height + y - item->y;
|
||||
dnd_drag->hotspot_x = pointer_width + x - item->x;
|
||||
dnd_drag->hotspot_y = pointer_height + y - item->y;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
|
@ -423,8 +473,8 @@ dnd_button_handler(struct window *window,
|
|||
struct dnd *dnd = data;
|
||||
int32_t x, y;
|
||||
struct item *item;
|
||||
cairo_surface_t *surface;
|
||||
struct rectangle rectangle;
|
||||
struct dnd_drag *dnd_drag;
|
||||
|
||||
window_get_child_rectangle(dnd->window, &rectangle);
|
||||
input_get_position(input, &x, &y);
|
||||
|
|
@ -435,18 +485,17 @@ dnd_button_handler(struct window *window,
|
|||
if (item && state == 1) {
|
||||
fprintf(stderr, "start drag, item %p\n", item);
|
||||
|
||||
surface = create_drag_cursor(dnd, item, x, y, 1);
|
||||
dnd->opaque_buffer =
|
||||
display_get_buffer_for_surface(dnd->display, surface);
|
||||
dnd_drag = malloc(sizeof *dnd_drag);
|
||||
dnd_drag->dnd = dnd;
|
||||
dnd_drag->input = input;
|
||||
|
||||
surface = create_drag_cursor(dnd, item, x, y, 0.2);
|
||||
dnd->translucent_buffer =
|
||||
display_get_buffer_for_surface(dnd->display, surface);
|
||||
dnd_drag->opaque =
|
||||
create_drag_cursor(dnd_drag, item, x, y, 1);
|
||||
dnd_drag->translucent =
|
||||
create_drag_cursor(dnd_drag, item, x, y, 0.2);
|
||||
|
||||
window_start_drag(window, input, time);
|
||||
|
||||
/* FIXME: We leak the surface because we can't free it
|
||||
* until the server has referenced it. */
|
||||
window_start_drag(window, input, time,
|
||||
&drag_listener, dnd_drag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -509,8 +558,6 @@ dnd_create(struct display *display)
|
|||
rectangle.height = 4 * (item_height + item_padding) + item_padding;
|
||||
window_set_child_size(dnd->window, &rectangle);
|
||||
|
||||
display_add_drag_listener(display, &drag_listener, dnd);
|
||||
|
||||
dnd_draw(dnd);
|
||||
|
||||
return dnd;
|
||||
|
|
@ -532,6 +579,8 @@ main(int argc, char *argv[])
|
|||
|
||||
d = display_create(&argc, &argv, option_entries);
|
||||
|
||||
display_set_drag_offer_handler(d, drag_offer_handler);
|
||||
|
||||
dnd = dnd_create (d);
|
||||
|
||||
display_run(d);
|
||||
|
|
|
|||
109
clients/window.c
109
clients/window.c
|
|
@ -71,6 +71,8 @@ struct display {
|
|||
cairo_surface_t *active_frame, *inactive_frame, *shadow;
|
||||
struct xkb_desc *xkb;
|
||||
cairo_surface_t **pointer_surfaces;
|
||||
|
||||
display_drag_offer_handler_t drag_offer_handler;
|
||||
};
|
||||
|
||||
struct window {
|
||||
|
|
@ -107,7 +109,6 @@ struct window {
|
|||
struct input {
|
||||
struct display *display;
|
||||
struct wl_input_device *input_device;
|
||||
struct wl_drag *drag;
|
||||
struct window *pointer_focus;
|
||||
struct window *keyboard_focus;
|
||||
uint32_t modifiers;
|
||||
|
|
@ -744,25 +745,21 @@ input_get_input_device(struct input *input)
|
|||
return input->input_device;
|
||||
}
|
||||
|
||||
void
|
||||
display_add_drag_listener(struct display *display,
|
||||
const struct wl_drag_listener *drag_listener,
|
||||
void *data)
|
||||
struct wl_drag *
|
||||
window_start_drag(struct window *window, struct input *input, uint32_t time,
|
||||
const struct wl_drag_listener *listener, void *data)
|
||||
{
|
||||
struct input *input;
|
||||
struct wl_drag *drag;
|
||||
|
||||
wl_list_for_each(input, &display->input_list, link)
|
||||
wl_drag_add_listener(input->drag, drag_listener, data);
|
||||
}
|
||||
|
||||
void
|
||||
window_start_drag(struct window *window, struct input *input, uint32_t time)
|
||||
{
|
||||
cairo_device_flush (window->display->device);
|
||||
|
||||
wl_drag_prepare(input->drag, window->surface, time);
|
||||
wl_drag_offer(input->drag, "text/plain");
|
||||
wl_drag_activate(input->drag);
|
||||
drag = wl_shell_create_drag(window->display->shell);
|
||||
wl_drag_offer(drag, "text/plain");
|
||||
wl_drag_offer(drag, "text/html");
|
||||
wl_drag_activate(drag, window->surface, input->input_device, time);
|
||||
wl_drag_add_listener(drag, listener, data);
|
||||
|
||||
return drag;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -902,6 +899,12 @@ window_set_user_data(struct window *window, void *data)
|
|||
window->user_data = data;
|
||||
}
|
||||
|
||||
void *
|
||||
window_get_user_data(struct window *window)
|
||||
{
|
||||
return window->user_data;
|
||||
}
|
||||
|
||||
void
|
||||
window_set_resize_handler(struct window *window,
|
||||
window_resize_handler_t handler)
|
||||
|
|
@ -1099,71 +1102,12 @@ display_add_input(struct display *d, uint32_t id)
|
|||
wl_input_device_set_user_data(input->input_device, input);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_handle_device(void *data,
|
||||
struct wl_drag *drag, struct wl_input_device *device)
|
||||
{
|
||||
struct input *input;
|
||||
|
||||
input = wl_input_device_get_user_data(device);
|
||||
input->drag = drag;
|
||||
wl_drag_set_user_data(drag, input);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_pointer_focus(void *data,
|
||||
struct wl_drag *drag,
|
||||
uint32_t time, struct wl_surface *surface,
|
||||
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drag_offer(void *data,
|
||||
struct wl_drag *drag, const char *type)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drag_motion(void *data,
|
||||
struct wl_drag *drag,
|
||||
uint32_t time,
|
||||
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drag_target(void *data,
|
||||
struct wl_drag *drag, const char *mime_type)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drag_drop(void *data, struct wl_drag *drag)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drag_finish(void *data, struct wl_drag *drag, int fd)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_drag_listener drag_listener = {
|
||||
drag_handle_device,
|
||||
drag_pointer_focus,
|
||||
drag_offer,
|
||||
drag_motion,
|
||||
drag_target,
|
||||
drag_drop,
|
||||
drag_finish
|
||||
};
|
||||
|
||||
static void
|
||||
display_handle_global(struct wl_display *display, uint32_t id,
|
||||
const char *interface, uint32_t version, void *data)
|
||||
{
|
||||
struct display *d = data;
|
||||
struct wl_drag *drag;
|
||||
struct wl_drag_offer *offer;
|
||||
|
||||
if (strcmp(interface, "compositor") == 0) {
|
||||
d->compositor = wl_compositor_create(display, id);
|
||||
|
|
@ -1180,9 +1124,9 @@ display_handle_global(struct wl_display *display, uint32_t id,
|
|||
} else if (strcmp(interface, "drm") == 0) {
|
||||
d->drm = wl_drm_create(display, id);
|
||||
wl_drm_add_listener(d->drm, &drm_listener, d);
|
||||
} else if (strcmp(interface, "drag") == 0) {
|
||||
drag = wl_drag_create(display, id);
|
||||
wl_drag_add_listener(drag, &drag_listener, NULL);
|
||||
} else if (strcmp(interface, "drag_offer") == 0) {
|
||||
offer = wl_drag_offer_create(display, id);
|
||||
d->drag_offer_handler(offer, d);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1363,3 +1307,10 @@ display_run(struct display *d)
|
|||
{
|
||||
g_main_loop_run(d->loop);
|
||||
}
|
||||
|
||||
void
|
||||
display_set_drag_offer_handler(struct display *display,
|
||||
display_drag_offer_handler_t handler)
|
||||
{
|
||||
display->drag_offer_handler = handler;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,9 @@ typedef int (*window_motion_handler_t)(struct window *window,
|
|||
int32_t x, int32_t y,
|
||||
int32_t sx, int32_t sy, void *data);
|
||||
|
||||
typedef void (*display_drag_offer_handler_t)(struct wl_drag_offer *offer,
|
||||
struct display *display);
|
||||
|
||||
struct window *
|
||||
window_create(struct display *display, const char *title,
|
||||
int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
|
|
@ -149,6 +152,9 @@ window_set_fullscreen(struct window *window, int fullscreen);
|
|||
void
|
||||
window_set_user_data(struct window *window, void *data);
|
||||
|
||||
void *
|
||||
window_get_user_data(struct window *window);
|
||||
|
||||
void
|
||||
window_set_redraw_handler(struct window *window,
|
||||
window_redraw_handler_t handler);
|
||||
|
|
@ -191,7 +197,13 @@ window_set_frame_handler(struct window *window,
|
|||
window_frame_handler_t handler);
|
||||
|
||||
void
|
||||
window_start_drag(struct window *window, struct input *input, uint32_t time);
|
||||
display_set_drag_offer_handler(struct display *display,
|
||||
display_drag_offer_handler_t handler);
|
||||
|
||||
struct wl_drag *
|
||||
window_start_drag(struct window *window, struct input *input, uint32_t time,
|
||||
const struct wl_drag_listener *listener, void *data);
|
||||
|
||||
|
||||
void
|
||||
input_get_position(struct input *input, int32_t *x, int32_t *y);
|
||||
|
|
|
|||
273
compositor.c
273
compositor.c
|
|
@ -573,9 +573,49 @@ shell_resize(struct wl_client *client, struct wl_shell *shell,
|
|||
wlsc_input_device_set_pointer_image(wd, pointer);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_drag(struct wl_resource *resource, struct wl_client *client)
|
||||
{
|
||||
struct wl_drag *drag =
|
||||
container_of(resource, struct wl_drag, resource);
|
||||
|
||||
/* FIXME: More stuff */
|
||||
|
||||
free(drag);
|
||||
}
|
||||
|
||||
const static struct wl_drag_interface drag_interface;
|
||||
|
||||
static void
|
||||
shell_create_drag(struct wl_client *client,
|
||||
struct wl_shell *shell, uint32_t id)
|
||||
{
|
||||
struct wl_display *display = wl_client_get_display(client);
|
||||
struct wl_drag *drag;
|
||||
|
||||
drag = malloc(sizeof *drag);
|
||||
if (drag == NULL) {
|
||||
wl_client_post_event(client,
|
||||
(struct wl_object *) display,
|
||||
WL_DISPLAY_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(drag, 0, sizeof *drag);
|
||||
drag->resource.base.id = id;
|
||||
drag->resource.base.interface = &wl_drag_interface;
|
||||
drag->resource.base.implementation =
|
||||
(void (**)(void)) &drag_interface;
|
||||
|
||||
drag->resource.destroy = destroy_drag;
|
||||
|
||||
wl_client_add_resource(client, &drag->resource);
|
||||
}
|
||||
|
||||
const static struct wl_shell_interface shell_interface = {
|
||||
shell_move,
|
||||
shell_resize
|
||||
shell_resize,
|
||||
shell_create_drag
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
@ -589,7 +629,7 @@ compositor_create_surface(struct wl_client *client,
|
|||
if (surface == NULL) {
|
||||
wl_client_post_event(client,
|
||||
(struct wl_object *) ec->wl_display,
|
||||
WL_DISPLAY_NO_MEMORY, 0);
|
||||
WL_DISPLAY_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -695,8 +735,6 @@ pick_surface(struct wlsc_input_device *device, int32_t *sx, int32_t *sy)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_drag_reset(struct wl_drag *drag);
|
||||
static void
|
||||
wl_drag_set_pointer_focus(struct wl_drag *drag,
|
||||
struct wlsc_surface *surface, uint32_t time,
|
||||
|
|
@ -797,11 +835,12 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y)
|
|||
|
||||
case WLSC_DEVICE_GRAB_DRAG:
|
||||
es = pick_surface(device, &sx, &sy);
|
||||
wl_drag_set_pointer_focus(&device->drag,
|
||||
wl_drag_set_pointer_focus(device->drag,
|
||||
es, time, x, y, sx, sy);
|
||||
if (es)
|
||||
wl_surface_post_event(&es->base, &device->drag.base,
|
||||
WL_DRAG_MOTION,
|
||||
wl_surface_post_event(&es->base,
|
||||
&device->drag->drag_offer.base,
|
||||
WL_DRAG_OFFER_MOTION,
|
||||
time, x, y, sx, sy);
|
||||
break;
|
||||
|
||||
|
|
@ -817,7 +856,7 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y)
|
|||
static void
|
||||
wlsc_input_device_end_grab(struct wlsc_input_device *device, uint32_t time)
|
||||
{
|
||||
struct wl_drag *drag = &device->drag;
|
||||
struct wl_drag *drag = device->drag;
|
||||
struct wlsc_surface *es;
|
||||
int32_t sx, sy;
|
||||
|
||||
|
|
@ -825,9 +864,10 @@ wlsc_input_device_end_grab(struct wlsc_input_device *device, uint32_t time)
|
|||
case WLSC_DEVICE_GRAB_DRAG:
|
||||
if (drag->target)
|
||||
wl_client_post_event(drag->target,
|
||||
&drag->base, WL_DRAG_DROP);
|
||||
&drag->drag_offer.base,
|
||||
WL_DRAG_OFFER_DROP);
|
||||
wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
|
||||
wl_drag_reset(drag);
|
||||
device->drag = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1012,80 +1052,89 @@ wl_drag_set_pointer_focus(struct wl_drag *drag,
|
|||
if (drag->pointer_focus &&
|
||||
(!surface || drag->pointer_focus->client != surface->base.client))
|
||||
wl_surface_post_event(drag->pointer_focus,
|
||||
&drag->base,
|
||||
WL_DRAG_POINTER_FOCUS,
|
||||
&drag->drag_offer.base,
|
||||
WL_DRAG_OFFER_POINTER_FOCUS,
|
||||
time, NULL, 0, 0, 0, 0);
|
||||
if (surface) {
|
||||
|
||||
if (surface &&
|
||||
(!drag->pointer_focus ||
|
||||
drag->pointer_focus->client != surface->base.client)) {
|
||||
wl_surface_post_event(&surface->base,
|
||||
&drag->base,
|
||||
WL_DRAG_POINTER_FOCUS,
|
||||
time, &surface->base,
|
||||
x, y, sx, sy);
|
||||
(struct wl_object *) surface->compositor->wl_display,
|
||||
WL_DISPLAY_GLOBAL,
|
||||
&drag->drag_offer.base,
|
||||
drag->drag_offer.base.interface->name,
|
||||
drag->drag_offer.base.interface->version);
|
||||
|
||||
end = drag->types.data + drag->types.size;
|
||||
for (p = drag->types.data; p < end; p++)
|
||||
wl_surface_post_event(&surface->base,
|
||||
&drag->base,
|
||||
WL_DRAG_OFFER, *p);
|
||||
&drag->drag_offer.base,
|
||||
WL_DRAG_OFFER_OFFER, *p);
|
||||
}
|
||||
|
||||
if (surface) {
|
||||
wl_surface_post_event(&surface->base,
|
||||
&drag->drag_offer.base,
|
||||
WL_DRAG_OFFER_POINTER_FOCUS,
|
||||
time, &surface->base,
|
||||
x, y, sx, sy);
|
||||
|
||||
}
|
||||
|
||||
drag->pointer_focus = &surface->base;
|
||||
drag->pointer_focus_time = time;
|
||||
drag->target = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_drag_reset(struct wl_drag *drag)
|
||||
drag_offer_accept(struct wl_client *client,
|
||||
struct wl_drag_offer *offer, uint32_t time, const char *type)
|
||||
{
|
||||
struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
|
||||
char **p, **end;
|
||||
|
||||
/* If the client responds to drag pointer_focus or motion
|
||||
* events after the pointer has left the surface, we just
|
||||
* discard the accept requests. The drag source just won't
|
||||
* get the corresponding 'target' events and eventually the
|
||||
* next surface/root will start sending events. */
|
||||
if (time < drag->pointer_focus_time)
|
||||
return;
|
||||
|
||||
drag->target = client;
|
||||
drag->type = NULL;
|
||||
end = drag->types.data + drag->types.size;
|
||||
for (p = drag->types.data; p < end; p++)
|
||||
free(*p);
|
||||
wl_array_release(&drag->types);
|
||||
wl_array_init(&drag->types);
|
||||
if (type && strcmp(*p, type) == 0)
|
||||
drag->type = *p;
|
||||
|
||||
/* FIXME: We need to reset drag->target too, but can't right
|
||||
* now because we need it for send/drop.
|
||||
*
|
||||
* drag->target = NULL;
|
||||
* drag->source = NULL;
|
||||
*/
|
||||
drag->time = 0;
|
||||
drag->pointer_focus = NULL;
|
||||
wl_surface_post_event(drag->source, &drag->resource.base,
|
||||
WL_DRAG_TARGET, drag->type);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_prepare(struct wl_client *client,
|
||||
struct wl_drag *drag, struct wl_surface *surface, uint32_t time)
|
||||
drag_offer_receive(struct wl_client *client,
|
||||
struct wl_drag_offer *offer, int fd)
|
||||
{
|
||||
struct wlsc_input_device *device =
|
||||
(struct wlsc_input_device *) drag->input_device;
|
||||
struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
|
||||
|
||||
if (&device->pointer_focus->base != surface ||
|
||||
device->grab_time != time)
|
||||
return;
|
||||
|
||||
wl_drag_reset(drag);
|
||||
drag->source = surface;
|
||||
drag->time = time;
|
||||
wl_surface_post_event(drag->source, &drag->resource.base,
|
||||
WL_DRAG_FINISH, fd);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static const struct wl_drag_offer_interface drag_offer_interface = {
|
||||
drag_offer_accept,
|
||||
drag_offer_receive
|
||||
};
|
||||
|
||||
static void
|
||||
drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type)
|
||||
{
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
struct wlsc_input_device *device =
|
||||
(struct wlsc_input_device *) drag->input_device;
|
||||
char **p;
|
||||
|
||||
if (drag->source == NULL ||
|
||||
drag->source->client != client ||
|
||||
device->grab != WLSC_DEVICE_GRAB_MOTION ||
|
||||
&device->pointer_focus->base != drag->source ||
|
||||
device->grab_time != drag->time)
|
||||
return;
|
||||
|
||||
p = wl_array_add(&drag->types, sizeof *p);
|
||||
if (p)
|
||||
*p = strdup(type);
|
||||
|
|
@ -1097,25 +1146,36 @@ drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type)
|
|||
|
||||
static void
|
||||
drag_activate(struct wl_client *client,
|
||||
struct wl_drag *drag)
|
||||
struct wl_drag *drag,
|
||||
struct wl_surface *surface,
|
||||
struct wl_input_device *input_device, uint32_t time)
|
||||
{
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
struct wlsc_input_device *device =
|
||||
(struct wlsc_input_device *) drag->input_device;
|
||||
struct wlsc_surface *surface;
|
||||
(struct wlsc_input_device *) input_device;
|
||||
struct wlsc_surface *target;
|
||||
int32_t sx, sy;
|
||||
|
||||
if (drag->source == NULL ||
|
||||
drag->source->client != client ||
|
||||
device->grab != WLSC_DEVICE_GRAB_MOTION ||
|
||||
&device->pointer_focus->base != drag->source ||
|
||||
device->grab_time != drag->time)
|
||||
if (device->grab != WLSC_DEVICE_GRAB_MOTION ||
|
||||
&device->pointer_focus->base != surface ||
|
||||
device->grab_time != time)
|
||||
return;
|
||||
|
||||
wlsc_input_device_start_grab(device, drag->time,
|
||||
drag->source = surface;
|
||||
drag->input_device = input_device;
|
||||
|
||||
drag->drag_offer.base.interface = &wl_drag_offer_interface;
|
||||
drag->drag_offer.base.implementation =
|
||||
(void (**)(void)) &drag_offer_interface;
|
||||
|
||||
wl_display_add_object(display, &drag->drag_offer.base);
|
||||
|
||||
wlsc_input_device_start_grab(device, time,
|
||||
WLSC_DEVICE_GRAB_DRAG);
|
||||
|
||||
surface = pick_surface(device, &sx, &sy);
|
||||
wl_drag_set_pointer_focus(&device->drag, surface, drag->time,
|
||||
device->drag = drag;
|
||||
target = pick_surface(device, &sx, &sy);
|
||||
wl_drag_set_pointer_focus(device->drag, target, time,
|
||||
device->x, device->y, sx, sy);
|
||||
}
|
||||
|
||||
|
|
@ -1125,102 +1185,19 @@ drag_cancel(struct wl_client *client, struct wl_drag *drag)
|
|||
struct wlsc_input_device *device =
|
||||
(struct wlsc_input_device *) drag->input_device;
|
||||
|
||||
if (drag->source == NULL ||
|
||||
drag->source->client != client ||
|
||||
device->grab != WLSC_DEVICE_GRAB_DRAG)
|
||||
if (drag->source == NULL || drag->source->client != client)
|
||||
return;
|
||||
|
||||
wlsc_input_device_end_grab(device, get_time());
|
||||
}
|
||||
|
||||
static void
|
||||
drag_accept(struct wl_client *client,
|
||||
struct wl_drag *drag, const char *type)
|
||||
{
|
||||
char **p, **end;
|
||||
|
||||
/* If the client responds to drag motion events after the
|
||||
* pointer has left the surface, we just discard the accept
|
||||
* requests. The drag source just won't get the corresponding
|
||||
* 'target' events and the next surface/root will start
|
||||
* sending events. */
|
||||
if (drag->pointer_focus == NULL)
|
||||
return;
|
||||
|
||||
/* The accept request may arrive after the pointer has left
|
||||
* the surface that received the drag motion events that
|
||||
* triggered the request. But if the pointer re-enters the
|
||||
* surface (or another surface from the same client) and we
|
||||
* receive the 'accept' requests from the first visit to the
|
||||
* surface later, this check will pass. Then we end up
|
||||
* sending the 'target' event for the old 'accept' requests
|
||||
* events *after* potentially sending 'target' from the root
|
||||
* surface, out of order. So we need to track the time of
|
||||
* pointer_focus and this request needs a time stamp so we can
|
||||
* compare and reject 'accept' requests that are older than
|
||||
* the pointer_focus in timestamp. */
|
||||
if (drag->pointer_focus->client != client)
|
||||
return;
|
||||
|
||||
/* FIXME: We need a serial number here to correlate the accept
|
||||
* request with a pointer_focus/motion event. */
|
||||
drag->target = client;
|
||||
|
||||
if (type == NULL) {
|
||||
drag->type = NULL;
|
||||
} else {
|
||||
end = drag->types.data + drag->types.size;
|
||||
for (p = drag->types.data; p < end; p++)
|
||||
if (strcmp(*p, type) == 0)
|
||||
drag->type = *p;
|
||||
}
|
||||
|
||||
wl_surface_post_event(drag->source, &drag->base,
|
||||
WL_DRAG_TARGET, drag->type);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_receive(struct wl_client *client,
|
||||
struct wl_drag *drag, int fd)
|
||||
{
|
||||
wl_surface_post_event(drag->source, &drag->base, WL_DRAG_FINISH, fd);
|
||||
close(fd);
|
||||
device->drag = NULL;
|
||||
}
|
||||
|
||||
static const struct wl_drag_interface drag_interface = {
|
||||
drag_prepare,
|
||||
drag_offer,
|
||||
drag_activate,
|
||||
drag_cancel,
|
||||
drag_accept,
|
||||
drag_receive
|
||||
};
|
||||
|
||||
static void
|
||||
wl_drag_post_device(struct wl_client *client, struct wl_object *global)
|
||||
{
|
||||
struct wl_drag *drag = container_of(global, struct wl_drag, base);
|
||||
|
||||
wl_client_post_event(client, global,
|
||||
WL_DRAG_DEVICE, drag->input_device);
|
||||
}
|
||||
|
||||
static void
|
||||
wl_drag_init(struct wl_drag *drag,
|
||||
struct wl_display *display, struct wl_input_device *input_device)
|
||||
{
|
||||
drag->base.interface = &wl_drag_interface;
|
||||
drag->base.implementation = (void (**)(void))
|
||||
&drag_interface;
|
||||
|
||||
wl_display_add_object(display, &drag->base);
|
||||
wl_display_add_global(display, &drag->base, wl_drag_post_device);
|
||||
|
||||
drag->source = NULL;
|
||||
wl_array_init(&drag->types);
|
||||
drag->input_device = input_device;
|
||||
}
|
||||
|
||||
void
|
||||
wlsc_input_device_init(struct wlsc_input_device *device,
|
||||
struct wlsc_compositor *ec)
|
||||
|
|
@ -1231,8 +1208,6 @@ wlsc_input_device_init(struct wlsc_input_device *device,
|
|||
wl_display_add_object(ec->wl_display, &device->base.base);
|
||||
wl_display_add_global(ec->wl_display, &device->base.base, NULL);
|
||||
|
||||
wl_drag_init(&device->drag, ec->wl_display, &device->base);
|
||||
|
||||
device->x = 100;
|
||||
device->y = 100;
|
||||
device->ec = ec;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ struct wlsc_input_device {
|
|||
int32_t grab_width, grab_height;
|
||||
int32_t grab_dx, grab_dy;
|
||||
uint32_t grab_button;
|
||||
struct wl_drag drag;
|
||||
struct wl_drag *drag;
|
||||
|
||||
struct wlsc_listener listener;
|
||||
};
|
||||
|
|
|
|||
104
protocol.xml
104
protocol.xml
|
|
@ -66,7 +66,7 @@
|
|||
</interface>
|
||||
|
||||
<interface name="buffer" version="1">
|
||||
<request name="destroy"/>
|
||||
<request name="destroy" type="destructor"/>
|
||||
</interface>
|
||||
|
||||
<interface name="shell" version="1">
|
||||
|
|
@ -84,6 +84,10 @@
|
|||
<arg name="edges" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="create_drag">
|
||||
<arg name="id" type="new_id" interface="drag"/>
|
||||
</request>
|
||||
|
||||
<event name="configure">
|
||||
<arg name="time" type="uint"/>
|
||||
<!-- Same as edges except also move (16) -->
|
||||
|
|
@ -97,46 +101,65 @@
|
|||
</interface>
|
||||
|
||||
<interface name="drag" version="1">
|
||||
<request name="prepare">
|
||||
<!-- Start a drag action from given surface and device for the
|
||||
grab started by the button click at time -->
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="time" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Add an offered mime type. Can be called several times to
|
||||
offer multiple types, but must be called before 'activate'. -->
|
||||
<request name="offer">
|
||||
<arg name="type" type="string"/>
|
||||
</request>
|
||||
|
||||
<request name="activate"/>
|
||||
<request name="activate">
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="input_device" type="object" interface="input_device"/>
|
||||
<arg name="time" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Cancel the drag. -->
|
||||
<request name="cancel"/>
|
||||
<!-- Destroy the drag and cancel the session. -->
|
||||
<request name="destroy" type="destructor"/>
|
||||
|
||||
<!-- Called by the drag target to accept the offer of the given
|
||||
type -->
|
||||
<!-- Sent when a target accepts pointer_focus or motion events.
|
||||
If a target does not accept any of the offered types, type is
|
||||
NULL -->
|
||||
<event name="target">
|
||||
<arg name="mime_type" type="string"/>
|
||||
</event>
|
||||
|
||||
<!-- Sent when the drag is finished. The final mime type is that
|
||||
of the last target event. If that was NULL, no drag target
|
||||
was valid when the drag finished, fd is undefined and the
|
||||
source should not send data. The event is also sent in case
|
||||
a drag source tries to activate a drag after the grab was
|
||||
released, in which case mime_type will also be NULL. -->
|
||||
<event name="finish">
|
||||
<arg name="fd" type="fd"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
|
||||
<interface name="drag_offer" version="1">
|
||||
<!-- Call to accept the offer of the given type -->
|
||||
<request name="accept">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="type" type="string"/>
|
||||
</request>
|
||||
|
||||
<!-- Called by the drag target to initiate the drag finish
|
||||
sequence. Send the pipe fd to the compositor, which forwards
|
||||
it to the source in the 'finish' event -->
|
||||
<!-- Called to initiate the drag finish sequence. Sends the pipe
|
||||
fd to the compositor, which forwards it to the source in the
|
||||
'finish' event -->
|
||||
<request name="receive">
|
||||
<arg name="fd" type="fd"/>
|
||||
</request>
|
||||
|
||||
<!-- Sent at connect time to announce the association -->
|
||||
<event name="device">
|
||||
<arg name="device" type="object" interface="input_device"/>
|
||||
<!-- Sent before the pointer_focus event to announce the types
|
||||
offered. One event per offered mime type. -->
|
||||
<event name="offer">
|
||||
<arg name="type" type="string"/>
|
||||
</event>
|
||||
|
||||
<!-- Similar to device::pointer_focus. Sent to potential
|
||||
target surfaces to offer drag data. If the device
|
||||
leaves the window, the drag stops or the originator cancels
|
||||
the drag, this event is sent with the NULL surface. -->
|
||||
<!-- Similar to device::pointer_focus. Sent to potential target
|
||||
surfaces to offer drag data. If the device leaves the
|
||||
window, the drag stops or the originator cancels the drag,
|
||||
this event is sent with the NULL surface, at which point the
|
||||
drag object may no longer be valid. -->
|
||||
<event name="pointer_focus">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
|
|
@ -146,12 +169,6 @@
|
|||
<arg name="surface_y" type="int"/>
|
||||
</event>
|
||||
|
||||
<!-- Sent after the pointer_focus event to announce the types
|
||||
offered. One event per offered mime type. -->
|
||||
<event name="offer">
|
||||
<arg name="type" type="string"/>
|
||||
</event>
|
||||
|
||||
<!-- Similar to device::motion. Sent to potential target surfaces
|
||||
as the drag pointer moves around in the surface. -->
|
||||
<event name="motion">
|
||||
|
|
@ -162,34 +179,15 @@
|
|||
<arg name="surface_y" type="int"/>
|
||||
</event>
|
||||
|
||||
<!-- Sent to drag originator in response to pointer_focus and
|
||||
motion events. If a target does not accept any of the
|
||||
offered types, type is NULL -->
|
||||
<event name="target">
|
||||
<arg name="mime_type" type="string"/>
|
||||
</event>
|
||||
|
||||
<!-- Sent to target, to indicate that the drag is finishing. The
|
||||
last motion/pointer_focus event gives the location of the
|
||||
drop. Target must respond with the 'receive' request, which
|
||||
sends an fd to the source for writing the drag data. -->
|
||||
<!-- Sent to indicate that the drag is finishing. The last
|
||||
motion/pointer_focus event gives the location of the drop.
|
||||
Target must respond with the 'receive' request, which sends
|
||||
an fd to the source for writing the drag data. -->
|
||||
<event name="drop"/>
|
||||
|
||||
<!-- Sent to drag source when the drag is finished. The final
|
||||
mime type is that of the last target event. If that was
|
||||
NULL, no drag target was valid when the drag finished, fd is
|
||||
undefined and the source should not send data. The event is
|
||||
also sent in case a drag source tries to activate a drag
|
||||
after the grab was released, in which case mime_type will
|
||||
also be NULL. -->
|
||||
<event name="finish">
|
||||
<arg name="fd" type="fd"/>
|
||||
</event>
|
||||
|
||||
</interface>
|
||||
|
||||
<interface name="surface" version="1">
|
||||
<request name="destroy"/>
|
||||
<request name="destroy" type="destructor"/>
|
||||
|
||||
<request name="attach">
|
||||
<arg name="buffer" type="object" interface="buffer"/>
|
||||
|
|
|
|||
42
scanner.c
42
scanner.c
|
|
@ -74,6 +74,7 @@ struct message {
|
|||
char *uppercase_name;
|
||||
struct wl_list arg_list;
|
||||
struct wl_list link;
|
||||
int destructor;
|
||||
};
|
||||
|
||||
enum arg_type {
|
||||
|
|
@ -177,6 +178,11 @@ start_element(void *data, const char *element_name, const char **atts)
|
|||
wl_list_insert(ctx->interface->event_list.prev,
|
||||
&message->link);
|
||||
|
||||
if (type != NULL && strcmp(type, "destructor") == 0)
|
||||
message->destructor = 1;
|
||||
else
|
||||
message->destructor = 0;
|
||||
|
||||
ctx->message = message;
|
||||
} else if (strcmp(element_name, "arg") == 0) {
|
||||
arg = malloc(sizeof *arg);
|
||||
|
|
@ -263,6 +269,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
|
|||
{
|
||||
struct message *m;
|
||||
struct arg *a, *ret;
|
||||
int has_destructor, has_destroy;
|
||||
|
||||
/* We provide a hand written constructor for the display object */
|
||||
if (strcmp(interface->name, "display") != 0)
|
||||
|
|
@ -293,6 +300,33 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
|
|||
interface->name, interface->name, interface->name,
|
||||
interface->name);
|
||||
|
||||
has_destructor = 0;
|
||||
has_destroy = 0;
|
||||
wl_list_for_each(m, message_list, link) {
|
||||
if (m->destructor)
|
||||
has_destructor = 1;
|
||||
if (strcmp(m->name, "destroy)") == 0)
|
||||
has_destroy = 1;
|
||||
}
|
||||
|
||||
if (!has_destructor && has_destroy) {
|
||||
fprintf(stderr,
|
||||
"interface %s has method named destroy but"
|
||||
"no destructor", interface->name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* And we have a hand-written display destructor */
|
||||
if (!has_destructor && strcmp(interface->name, "display") != 0)
|
||||
printf("static inline void\n"
|
||||
"wl_%s_destroy(struct wl_%s *%s)\n"
|
||||
"{\n"
|
||||
"\twl_proxy_destroy("
|
||||
"(struct wl_proxy *) %s);\n"
|
||||
"}\n\n",
|
||||
interface->name, interface->name, interface->name,
|
||||
interface->name);
|
||||
|
||||
if (wl_list_empty(message_list))
|
||||
return;
|
||||
|
||||
|
|
@ -347,6 +381,11 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
|
|||
}
|
||||
printf(");\n");
|
||||
|
||||
if (m->destructor)
|
||||
printf("\n\twl_proxy_destroy("
|
||||
"(struct wl_proxy *) %s);\n",
|
||||
interface->name);
|
||||
|
||||
if (ret)
|
||||
printf("\n\treturn (struct wl_%s *) %s;\n",
|
||||
ret->interface_name, ret->name);
|
||||
|
|
@ -442,6 +481,9 @@ static const char client_prototypes[] =
|
|||
"wl_proxy_create_for_id(struct wl_display *display,\n"
|
||||
"\t\t const struct wl_interface *interface, uint32_t id);\n"
|
||||
|
||||
"extern void\n"
|
||||
"wl_proxy_destroy(struct wl_proxy *proxy);\n\n"
|
||||
|
||||
"extern int\n"
|
||||
"wl_proxy_add_listener(struct wl_proxy *proxy,\n"
|
||||
"\t\t void (**implementation)(void), void *data);\n\n"
|
||||
|
|
|
|||
|
|
@ -146,6 +146,18 @@ wl_proxy_create(struct wl_proxy *factory,
|
|||
wl_display_allocate_id(factory->display));
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
wl_proxy_destroy(struct wl_proxy *proxy)
|
||||
{
|
||||
struct wl_listener *listener, *next;
|
||||
|
||||
wl_list_for_each_safe(listener, next, &proxy->listener_list, link)
|
||||
free(listener);
|
||||
|
||||
wl_hash_table_remove(proxy->display->objects, proxy->base.id);
|
||||
free(proxy);
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
wl_proxy_add_listener(struct wl_proxy *proxy,
|
||||
void (**implementation)(void), void *data)
|
||||
|
|
|
|||
|
|
@ -124,8 +124,13 @@ struct wl_visual {
|
|||
struct wl_object base;
|
||||
};
|
||||
|
||||
struct wl_drag {
|
||||
struct wl_drag_offer {
|
||||
struct wl_object base;
|
||||
};
|
||||
|
||||
struct wl_drag {
|
||||
struct wl_resource resource;
|
||||
struct wl_drag_offer drag_offer;
|
||||
struct wl_surface *source;
|
||||
struct wl_surface *pointer_focus;
|
||||
struct wl_client *target;
|
||||
|
|
@ -133,7 +138,7 @@ struct wl_drag {
|
|||
struct wl_input_device *input_device;
|
||||
struct wl_array types;
|
||||
const char *type;
|
||||
uint32_t time;
|
||||
uint32_t pointer_focus_time;
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue