mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-11-02 09:01:39 -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
|
send a NULL type or x-wayland/root-something type if the source
|
||||||
offers that.
|
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
|
How do we animate the drag icon back to the drag origin in case of
|
||||||
a failed drag?
|
a failed drag?
|
||||||
|
|
||||||
|
|
@ -48,18 +36,6 @@ Core wayland protocol
|
||||||
that will participate in dnd. Or just assume client is not
|
that will participate in dnd. Or just assume client is not
|
||||||
participating until we receive an accept request.
|
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:
|
- Pointer image issue:
|
||||||
|
|
||||||
- A touch input device doesn't have a pointer; indicate that
|
- A touch input device doesn't have a pointer; indicate that
|
||||||
|
|
|
||||||
287
clients/dnd.c
287
clients/dnd.c
|
|
@ -44,12 +44,21 @@ struct dnd {
|
||||||
struct display *display;
|
struct display *display;
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
struct item *items[16];
|
struct item *items[16];
|
||||||
|
};
|
||||||
|
|
||||||
struct wl_buffer *translucent_buffer;
|
struct dnd_drag {
|
||||||
struct wl_buffer *opaque_buffer;
|
cairo_surface_t *translucent;
|
||||||
|
cairo_surface_t *opaque;
|
||||||
int hotspot_x, hotspot_y;
|
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;
|
const char *drag_type;
|
||||||
|
uint32_t tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct item {
|
struct item {
|
||||||
|
|
@ -108,7 +117,7 @@ item_create(struct display *display, int x, int y)
|
||||||
cairo_curve_to(cr,
|
cairo_curve_to(cr,
|
||||||
x1 - y1 * u, y1 + x1 * u,
|
x1 - y1 * u, y1 + x1 * u,
|
||||||
x2 + y2 * v, y2 - x2 * v,
|
x2 + y2 * v, y2 - x2 * v,
|
||||||
x2, y2);
|
x2, y2);
|
||||||
|
|
||||||
cairo_curve_to(cr,
|
cairo_curve_to(cr,
|
||||||
x2 - y2 * v, y2 + x2 * v,
|
x2 - y2 * v, y2 + x2 * v,
|
||||||
|
|
@ -218,91 +227,131 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
|
||||||
return NULL;
|
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
|
static void
|
||||||
drag_target(void *data,
|
drag_target(void *data,
|
||||||
struct wl_drag *drag, const char *mime_type)
|
struct wl_drag *drag, const char *mime_type)
|
||||||
{
|
{
|
||||||
struct dnd *dnd = data;
|
struct dnd_drag *dnd_drag = data;
|
||||||
struct input *input;
|
struct dnd *dnd = dnd_drag->dnd;
|
||||||
struct wl_input_device *device;
|
struct wl_input_device *device;
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
struct wl_buffer *buffer;
|
||||||
|
|
||||||
fprintf(stderr, "target %s\n", mime_type);
|
fprintf(stderr, "target %s\n", mime_type);
|
||||||
input = wl_drag_get_user_data(drag);
|
device = input_get_input_device(dnd_drag->input);
|
||||||
device = input_get_input_device(input);
|
|
||||||
if (mime_type)
|
if (mime_type)
|
||||||
wl_input_device_attach(device, dnd->opaque_buffer,
|
surface = dnd_drag->opaque;
|
||||||
dnd->hotspot_x, dnd->hotspot_y);
|
|
||||||
else
|
else
|
||||||
wl_input_device_attach(device, dnd->translucent_buffer,
|
surface = dnd_drag->translucent;
|
||||||
dnd->hotspot_x, dnd->hotspot_y);
|
|
||||||
|
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
|
static gboolean
|
||||||
drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
|
drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
|
||||||
{
|
{
|
||||||
struct dnd *dnd = data;
|
struct dnd_offer *dnd_offer = data;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int fd;
|
int fd;
|
||||||
unsigned int len;
|
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);
|
fprintf(stderr, "read %d bytes: %s\n", len, buffer);
|
||||||
fd = g_io_channel_unix_get_fd(source);
|
fd = g_io_channel_unix_get_fd(source);
|
||||||
close(fd);
|
close(fd);
|
||||||
g_source_remove(dnd->tag);
|
g_source_remove(dnd_offer->tag);
|
||||||
|
|
||||||
g_io_channel_unref(source);
|
g_io_channel_unref(source);
|
||||||
|
|
||||||
|
|
@ -320,13 +369,13 @@ drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
drag_drop(void *data, struct wl_drag *drag)
|
drag_offer_drop(void *data, struct wl_drag_offer *offer)
|
||||||
{
|
{
|
||||||
struct dnd *dnd = data;
|
struct dnd_offer *dnd_offer = data;
|
||||||
int p[2];
|
|
||||||
GIOChannel *channel;
|
GIOChannel *channel;
|
||||||
|
int p[2];
|
||||||
|
|
||||||
if (!dnd->drag_type) {
|
if (!dnd_offer->drag_type) {
|
||||||
fprintf(stderr, "got 'drop', but no target\n");
|
fprintf(stderr, "got 'drop', but no target\n");
|
||||||
/* FIXME: Should send response so compositor and
|
/* FIXME: Should send response so compositor and
|
||||||
* source knows it's over. Can't send -1 to indicate
|
* 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");
|
fprintf(stderr, "got 'drop', sending write end of pipe\n");
|
||||||
|
|
||||||
pipe(p);
|
pipe(p);
|
||||||
wl_drag_receive(drag, p[1]);
|
wl_drag_offer_receive(offer, p[1]);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
|
|
||||||
channel = g_io_channel_unix_new(p[0]);
|
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
|
static const struct wl_drag_offer_listener drag_offer_listener = {
|
||||||
drag_finish(void *data, struct wl_drag *drag, int fd)
|
drag_offer_offer,
|
||||||
{
|
drag_offer_pointer_focus,
|
||||||
char text[] = "[drop data]";
|
drag_offer_motion,
|
||||||
|
drag_offer_drop,
|
||||||
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 cairo_surface_t *
|
static void
|
||||||
create_drag_cursor(struct dnd *dnd, struct item *item, int32_t x, int32_t y,
|
drag_offer_handler(struct wl_drag_offer *offer, struct display *display)
|
||||||
double opacity)
|
|
||||||
{
|
{
|
||||||
|
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;
|
cairo_surface_t *surface, *pointer;
|
||||||
int32_t pointer_width, pointer_height, hotspot_x, hotspot_y;
|
int32_t pointer_width, pointer_height, hotspot_x, hotspot_y;
|
||||||
struct rectangle rectangle;
|
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);
|
display_flush_cairo_device(dnd->display);
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
|
|
||||||
dnd->hotspot_x = pointer_width + x - item->x;
|
dnd_drag->hotspot_x = pointer_width + x - item->x;
|
||||||
dnd->hotspot_y = pointer_height + y - item->y;
|
dnd_drag->hotspot_y = pointer_height + y - item->y;
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
@ -423,8 +473,8 @@ dnd_button_handler(struct window *window,
|
||||||
struct dnd *dnd = data;
|
struct dnd *dnd = data;
|
||||||
int32_t x, y;
|
int32_t x, y;
|
||||||
struct item *item;
|
struct item *item;
|
||||||
cairo_surface_t *surface;
|
|
||||||
struct rectangle rectangle;
|
struct rectangle rectangle;
|
||||||
|
struct dnd_drag *dnd_drag;
|
||||||
|
|
||||||
window_get_child_rectangle(dnd->window, &rectangle);
|
window_get_child_rectangle(dnd->window, &rectangle);
|
||||||
input_get_position(input, &x, &y);
|
input_get_position(input, &x, &y);
|
||||||
|
|
@ -435,18 +485,17 @@ dnd_button_handler(struct window *window,
|
||||||
if (item && state == 1) {
|
if (item && state == 1) {
|
||||||
fprintf(stderr, "start drag, item %p\n", item);
|
fprintf(stderr, "start drag, item %p\n", item);
|
||||||
|
|
||||||
surface = create_drag_cursor(dnd, item, x, y, 1);
|
dnd_drag = malloc(sizeof *dnd_drag);
|
||||||
dnd->opaque_buffer =
|
dnd_drag->dnd = dnd;
|
||||||
display_get_buffer_for_surface(dnd->display, surface);
|
dnd_drag->input = input;
|
||||||
|
|
||||||
surface = create_drag_cursor(dnd, item, x, y, 0.2);
|
dnd_drag->opaque =
|
||||||
dnd->translucent_buffer =
|
create_drag_cursor(dnd_drag, item, x, y, 1);
|
||||||
display_get_buffer_for_surface(dnd->display, surface);
|
dnd_drag->translucent =
|
||||||
|
create_drag_cursor(dnd_drag, item, x, y, 0.2);
|
||||||
|
|
||||||
window_start_drag(window, input, time);
|
window_start_drag(window, input, time,
|
||||||
|
&drag_listener, dnd_drag);
|
||||||
/* FIXME: We leak the surface because we can't free it
|
|
||||||
* until the server has referenced it. */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -509,8 +558,6 @@ dnd_create(struct display *display)
|
||||||
rectangle.height = 4 * (item_height + item_padding) + item_padding;
|
rectangle.height = 4 * (item_height + item_padding) + item_padding;
|
||||||
window_set_child_size(dnd->window, &rectangle);
|
window_set_child_size(dnd->window, &rectangle);
|
||||||
|
|
||||||
display_add_drag_listener(display, &drag_listener, dnd);
|
|
||||||
|
|
||||||
dnd_draw(dnd);
|
dnd_draw(dnd);
|
||||||
|
|
||||||
return dnd;
|
return dnd;
|
||||||
|
|
@ -532,6 +579,8 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
d = display_create(&argc, &argv, option_entries);
|
d = display_create(&argc, &argv, option_entries);
|
||||||
|
|
||||||
|
display_set_drag_offer_handler(d, drag_offer_handler);
|
||||||
|
|
||||||
dnd = dnd_create (d);
|
dnd = dnd_create (d);
|
||||||
|
|
||||||
display_run(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;
|
cairo_surface_t *active_frame, *inactive_frame, *shadow;
|
||||||
struct xkb_desc *xkb;
|
struct xkb_desc *xkb;
|
||||||
cairo_surface_t **pointer_surfaces;
|
cairo_surface_t **pointer_surfaces;
|
||||||
|
|
||||||
|
display_drag_offer_handler_t drag_offer_handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct window {
|
struct window {
|
||||||
|
|
@ -107,7 +109,6 @@ struct window {
|
||||||
struct input {
|
struct input {
|
||||||
struct display *display;
|
struct display *display;
|
||||||
struct wl_input_device *input_device;
|
struct wl_input_device *input_device;
|
||||||
struct wl_drag *drag;
|
|
||||||
struct window *pointer_focus;
|
struct window *pointer_focus;
|
||||||
struct window *keyboard_focus;
|
struct window *keyboard_focus;
|
||||||
uint32_t modifiers;
|
uint32_t modifiers;
|
||||||
|
|
@ -744,25 +745,21 @@ input_get_input_device(struct input *input)
|
||||||
return input->input_device;
|
return input->input_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
struct wl_drag *
|
||||||
display_add_drag_listener(struct display *display,
|
window_start_drag(struct window *window, struct input *input, uint32_t time,
|
||||||
const struct wl_drag_listener *drag_listener,
|
const struct wl_drag_listener *listener, void *data)
|
||||||
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);
|
cairo_device_flush (window->display->device);
|
||||||
|
|
||||||
wl_drag_prepare(input->drag, window->surface, time);
|
drag = wl_shell_create_drag(window->display->shell);
|
||||||
wl_drag_offer(input->drag, "text/plain");
|
wl_drag_offer(drag, "text/plain");
|
||||||
wl_drag_activate(input->drag);
|
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
|
static void
|
||||||
|
|
@ -902,6 +899,12 @@ window_set_user_data(struct window *window, void *data)
|
||||||
window->user_data = data;
|
window->user_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
window_get_user_data(struct window *window)
|
||||||
|
{
|
||||||
|
return window->user_data;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
window_set_resize_handler(struct window *window,
|
window_set_resize_handler(struct window *window,
|
||||||
window_resize_handler_t handler)
|
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);
|
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
|
static void
|
||||||
display_handle_global(struct wl_display *display, uint32_t id,
|
display_handle_global(struct wl_display *display, uint32_t id,
|
||||||
const char *interface, uint32_t version, void *data)
|
const char *interface, uint32_t version, void *data)
|
||||||
{
|
{
|
||||||
struct display *d = data;
|
struct display *d = data;
|
||||||
struct wl_drag *drag;
|
struct wl_drag_offer *offer;
|
||||||
|
|
||||||
if (strcmp(interface, "compositor") == 0) {
|
if (strcmp(interface, "compositor") == 0) {
|
||||||
d->compositor = wl_compositor_create(display, id);
|
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) {
|
} else if (strcmp(interface, "drm") == 0) {
|
||||||
d->drm = wl_drm_create(display, id);
|
d->drm = wl_drm_create(display, id);
|
||||||
wl_drm_add_listener(d->drm, &drm_listener, d);
|
wl_drm_add_listener(d->drm, &drm_listener, d);
|
||||||
} else if (strcmp(interface, "drag") == 0) {
|
} else if (strcmp(interface, "drag_offer") == 0) {
|
||||||
drag = wl_drag_create(display, id);
|
offer = wl_drag_offer_create(display, id);
|
||||||
wl_drag_add_listener(drag, &drag_listener, NULL);
|
d->drag_offer_handler(offer, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1363,3 +1307,10 @@ display_run(struct display *d)
|
||||||
{
|
{
|
||||||
g_main_loop_run(d->loop);
|
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 x, int32_t y,
|
||||||
int32_t sx, int32_t sy, void *data);
|
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 *
|
struct window *
|
||||||
window_create(struct display *display, const char *title,
|
window_create(struct display *display, const char *title,
|
||||||
int32_t x, int32_t y, int32_t width, int32_t height);
|
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
|
void
|
||||||
window_set_user_data(struct window *window, void *data);
|
window_set_user_data(struct window *window, void *data);
|
||||||
|
|
||||||
|
void *
|
||||||
|
window_get_user_data(struct window *window);
|
||||||
|
|
||||||
void
|
void
|
||||||
window_set_redraw_handler(struct window *window,
|
window_set_redraw_handler(struct window *window,
|
||||||
window_redraw_handler_t handler);
|
window_redraw_handler_t handler);
|
||||||
|
|
@ -191,7 +197,13 @@ window_set_frame_handler(struct window *window,
|
||||||
window_frame_handler_t handler);
|
window_frame_handler_t handler);
|
||||||
|
|
||||||
void
|
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
|
void
|
||||||
input_get_position(struct input *input, int32_t *x, int32_t *y);
|
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);
|
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 = {
|
const static struct wl_shell_interface shell_interface = {
|
||||||
shell_move,
|
shell_move,
|
||||||
shell_resize
|
shell_resize,
|
||||||
|
shell_create_drag
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -589,7 +629,7 @@ compositor_create_surface(struct wl_client *client,
|
||||||
if (surface == NULL) {
|
if (surface == NULL) {
|
||||||
wl_client_post_event(client,
|
wl_client_post_event(client,
|
||||||
(struct wl_object *) ec->wl_display,
|
(struct wl_object *) ec->wl_display,
|
||||||
WL_DISPLAY_NO_MEMORY, 0);
|
WL_DISPLAY_NO_MEMORY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -695,8 +735,6 @@ pick_surface(struct wlsc_input_device *device, int32_t *sx, int32_t *sy)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
wl_drag_reset(struct wl_drag *drag);
|
|
||||||
static void
|
static void
|
||||||
wl_drag_set_pointer_focus(struct wl_drag *drag,
|
wl_drag_set_pointer_focus(struct wl_drag *drag,
|
||||||
struct wlsc_surface *surface, uint32_t time,
|
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:
|
case WLSC_DEVICE_GRAB_DRAG:
|
||||||
es = pick_surface(device, &sx, &sy);
|
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);
|
es, time, x, y, sx, sy);
|
||||||
if (es)
|
if (es)
|
||||||
wl_surface_post_event(&es->base, &device->drag.base,
|
wl_surface_post_event(&es->base,
|
||||||
WL_DRAG_MOTION,
|
&device->drag->drag_offer.base,
|
||||||
|
WL_DRAG_OFFER_MOTION,
|
||||||
time, x, y, sx, sy);
|
time, x, y, sx, sy);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -817,7 +856,7 @@ notify_motion(struct wlsc_input_device *device, uint32_t time, int x, int y)
|
||||||
static void
|
static void
|
||||||
wlsc_input_device_end_grab(struct wlsc_input_device *device, uint32_t time)
|
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;
|
struct wlsc_surface *es;
|
||||||
int32_t sx, sy;
|
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:
|
case WLSC_DEVICE_GRAB_DRAG:
|
||||||
if (drag->target)
|
if (drag->target)
|
||||||
wl_client_post_event(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_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
|
||||||
wl_drag_reset(drag);
|
device->drag = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -1012,80 +1052,89 @@ wl_drag_set_pointer_focus(struct wl_drag *drag,
|
||||||
if (drag->pointer_focus &&
|
if (drag->pointer_focus &&
|
||||||
(!surface || drag->pointer_focus->client != surface->base.client))
|
(!surface || drag->pointer_focus->client != surface->base.client))
|
||||||
wl_surface_post_event(drag->pointer_focus,
|
wl_surface_post_event(drag->pointer_focus,
|
||||||
&drag->base,
|
&drag->drag_offer.base,
|
||||||
WL_DRAG_POINTER_FOCUS,
|
WL_DRAG_OFFER_POINTER_FOCUS,
|
||||||
time, NULL, 0, 0, 0, 0);
|
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,
|
wl_surface_post_event(&surface->base,
|
||||||
&drag->base,
|
(struct wl_object *) surface->compositor->wl_display,
|
||||||
WL_DRAG_POINTER_FOCUS,
|
WL_DISPLAY_GLOBAL,
|
||||||
time, &surface->base,
|
&drag->drag_offer.base,
|
||||||
x, y, sx, sy);
|
drag->drag_offer.base.interface->name,
|
||||||
|
drag->drag_offer.base.interface->version);
|
||||||
|
|
||||||
end = drag->types.data + drag->types.size;
|
end = drag->types.data + drag->types.size;
|
||||||
for (p = drag->types.data; p < end; p++)
|
for (p = drag->types.data; p < end; p++)
|
||||||
wl_surface_post_event(&surface->base,
|
wl_surface_post_event(&surface->base,
|
||||||
&drag->base,
|
&drag->drag_offer.base,
|
||||||
WL_DRAG_OFFER, *p);
|
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 = &surface->base;
|
||||||
|
drag->pointer_focus_time = time;
|
||||||
drag->target = NULL;
|
drag->target = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
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;
|
end = drag->types.data + drag->types.size;
|
||||||
for (p = drag->types.data; p < end; p++)
|
for (p = drag->types.data; p < end; p++)
|
||||||
free(*p);
|
if (type && strcmp(*p, type) == 0)
|
||||||
wl_array_release(&drag->types);
|
drag->type = *p;
|
||||||
wl_array_init(&drag->types);
|
|
||||||
|
|
||||||
/* FIXME: We need to reset drag->target too, but can't right
|
wl_surface_post_event(drag->source, &drag->resource.base,
|
||||||
* now because we need it for send/drop.
|
WL_DRAG_TARGET, drag->type);
|
||||||
*
|
|
||||||
* drag->target = NULL;
|
|
||||||
* drag->source = NULL;
|
|
||||||
*/
|
|
||||||
drag->time = 0;
|
|
||||||
drag->pointer_focus = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
drag_prepare(struct wl_client *client,
|
drag_offer_receive(struct wl_client *client,
|
||||||
struct wl_drag *drag, struct wl_surface *surface, uint32_t time)
|
struct wl_drag_offer *offer, int fd)
|
||||||
{
|
{
|
||||||
struct wlsc_input_device *device =
|
struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer);
|
||||||
(struct wlsc_input_device *) drag->input_device;
|
|
||||||
|
|
||||||
if (&device->pointer_focus->base != surface ||
|
wl_surface_post_event(drag->source, &drag->resource.base,
|
||||||
device->grab_time != time)
|
WL_DRAG_FINISH, fd);
|
||||||
return;
|
close(fd);
|
||||||
|
|
||||||
wl_drag_reset(drag);
|
|
||||||
drag->source = surface;
|
|
||||||
drag->time = time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct wl_drag_offer_interface drag_offer_interface = {
|
||||||
|
drag_offer_accept,
|
||||||
|
drag_offer_receive
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type)
|
drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type)
|
||||||
{
|
{
|
||||||
struct wl_display *display = wl_client_get_display (client);
|
struct wl_display *display = wl_client_get_display (client);
|
||||||
struct wlsc_input_device *device =
|
|
||||||
(struct wlsc_input_device *) drag->input_device;
|
|
||||||
char **p;
|
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);
|
p = wl_array_add(&drag->types, sizeof *p);
|
||||||
if (p)
|
if (p)
|
||||||
*p = strdup(type);
|
*p = strdup(type);
|
||||||
|
|
@ -1097,25 +1146,36 @@ drag_offer(struct wl_client *client, struct wl_drag *drag, const char *type)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
drag_activate(struct wl_client *client,
|
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 *device =
|
||||||
(struct wlsc_input_device *) drag->input_device;
|
(struct wlsc_input_device *) input_device;
|
||||||
struct wlsc_surface *surface;
|
struct wlsc_surface *target;
|
||||||
int32_t sx, sy;
|
int32_t sx, sy;
|
||||||
|
|
||||||
if (drag->source == NULL ||
|
if (device->grab != WLSC_DEVICE_GRAB_MOTION ||
|
||||||
drag->source->client != client ||
|
&device->pointer_focus->base != surface ||
|
||||||
device->grab != WLSC_DEVICE_GRAB_MOTION ||
|
device->grab_time != time)
|
||||||
&device->pointer_focus->base != drag->source ||
|
|
||||||
device->grab_time != drag->time)
|
|
||||||
return;
|
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);
|
WLSC_DEVICE_GRAB_DRAG);
|
||||||
|
|
||||||
surface = pick_surface(device, &sx, &sy);
|
device->drag = drag;
|
||||||
wl_drag_set_pointer_focus(&device->drag, surface, drag->time,
|
target = pick_surface(device, &sx, &sy);
|
||||||
|
wl_drag_set_pointer_focus(device->drag, target, time,
|
||||||
device->x, device->y, sx, sy);
|
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 *device =
|
||||||
(struct wlsc_input_device *) drag->input_device;
|
(struct wlsc_input_device *) drag->input_device;
|
||||||
|
|
||||||
if (drag->source == NULL ||
|
if (drag->source == NULL || drag->source->client != client)
|
||||||
drag->source->client != client ||
|
|
||||||
device->grab != WLSC_DEVICE_GRAB_DRAG)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wlsc_input_device_end_grab(device, get_time());
|
wlsc_input_device_end_grab(device, get_time());
|
||||||
}
|
device->drag = NULL;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_drag_interface drag_interface = {
|
static const struct wl_drag_interface drag_interface = {
|
||||||
drag_prepare,
|
|
||||||
drag_offer,
|
drag_offer,
|
||||||
drag_activate,
|
drag_activate,
|
||||||
drag_cancel,
|
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
|
void
|
||||||
wlsc_input_device_init(struct wlsc_input_device *device,
|
wlsc_input_device_init(struct wlsc_input_device *device,
|
||||||
struct wlsc_compositor *ec)
|
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_object(ec->wl_display, &device->base.base);
|
||||||
wl_display_add_global(ec->wl_display, &device->base.base, NULL);
|
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->x = 100;
|
||||||
device->y = 100;
|
device->y = 100;
|
||||||
device->ec = ec;
|
device->ec = ec;
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ struct wlsc_input_device {
|
||||||
int32_t grab_width, grab_height;
|
int32_t grab_width, grab_height;
|
||||||
int32_t grab_dx, grab_dy;
|
int32_t grab_dx, grab_dy;
|
||||||
uint32_t grab_button;
|
uint32_t grab_button;
|
||||||
struct wl_drag drag;
|
struct wl_drag *drag;
|
||||||
|
|
||||||
struct wlsc_listener listener;
|
struct wlsc_listener listener;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
104
protocol.xml
104
protocol.xml
|
|
@ -66,7 +66,7 @@
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<interface name="buffer" version="1">
|
<interface name="buffer" version="1">
|
||||||
<request name="destroy"/>
|
<request name="destroy" type="destructor"/>
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<interface name="shell" version="1">
|
<interface name="shell" version="1">
|
||||||
|
|
@ -84,6 +84,10 @@
|
||||||
<arg name="edges" type="uint"/>
|
<arg name="edges" type="uint"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
|
<request name="create_drag">
|
||||||
|
<arg name="id" type="new_id" interface="drag"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
<event name="configure">
|
<event name="configure">
|
||||||
<arg name="time" type="uint"/>
|
<arg name="time" type="uint"/>
|
||||||
<!-- Same as edges except also move (16) -->
|
<!-- Same as edges except also move (16) -->
|
||||||
|
|
@ -97,46 +101,65 @@
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
<interface name="drag" version="1">
|
<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
|
<!-- Add an offered mime type. Can be called several times to
|
||||||
offer multiple types, but must be called before 'activate'. -->
|
offer multiple types, but must be called before 'activate'. -->
|
||||||
<request name="offer">
|
<request name="offer">
|
||||||
<arg name="type" type="string"/>
|
<arg name="type" type="string"/>
|
||||||
</request>
|
</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. -->
|
<!-- Destroy the drag and cancel the session. -->
|
||||||
<request name="cancel"/>
|
<request name="destroy" type="destructor"/>
|
||||||
|
|
||||||
<!-- Called by the drag target to accept the offer of the given
|
<!-- Sent when a target accepts pointer_focus or motion events.
|
||||||
type -->
|
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">
|
<request name="accept">
|
||||||
|
<arg name="time" type="uint"/>
|
||||||
<arg name="type" type="string"/>
|
<arg name="type" type="string"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<!-- Called by the drag target to initiate the drag finish
|
<!-- Called to initiate the drag finish sequence. Sends the pipe
|
||||||
sequence. Send the pipe fd to the compositor, which forwards
|
fd to the compositor, which forwards it to the source in the
|
||||||
it to the source in the 'finish' event -->
|
'finish' event -->
|
||||||
<request name="receive">
|
<request name="receive">
|
||||||
<arg name="fd" type="fd"/>
|
<arg name="fd" type="fd"/>
|
||||||
</request>
|
</request>
|
||||||
|
|
||||||
<!-- Sent at connect time to announce the association -->
|
<!-- Sent before the pointer_focus event to announce the types
|
||||||
<event name="device">
|
offered. One event per offered mime type. -->
|
||||||
<arg name="device" type="object" interface="input_device"/>
|
<event name="offer">
|
||||||
|
<arg name="type" type="string"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<!-- Similar to device::pointer_focus. Sent to potential
|
<!-- Similar to device::pointer_focus. Sent to potential target
|
||||||
target surfaces to offer drag data. If the device
|
surfaces to offer drag data. If the device leaves the
|
||||||
leaves the window, the drag stops or the originator cancels
|
window, the drag stops or the originator cancels the drag,
|
||||||
the drag, this event is sent with the NULL surface. -->
|
this event is sent with the NULL surface, at which point the
|
||||||
|
drag object may no longer be valid. -->
|
||||||
<event name="pointer_focus">
|
<event name="pointer_focus">
|
||||||
<arg name="time" type="uint"/>
|
<arg name="time" type="uint"/>
|
||||||
<arg name="surface" type="object" interface="surface"/>
|
<arg name="surface" type="object" interface="surface"/>
|
||||||
|
|
@ -146,12 +169,6 @@
|
||||||
<arg name="surface_y" type="int"/>
|
<arg name="surface_y" type="int"/>
|
||||||
</event>
|
</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
|
<!-- Similar to device::motion. Sent to potential target surfaces
|
||||||
as the drag pointer moves around in the surface. -->
|
as the drag pointer moves around in the surface. -->
|
||||||
<event name="motion">
|
<event name="motion">
|
||||||
|
|
@ -162,34 +179,15 @@
|
||||||
<arg name="surface_y" type="int"/>
|
<arg name="surface_y" type="int"/>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<!-- Sent to drag originator in response to pointer_focus and
|
<!-- Sent to indicate that the drag is finishing. The last
|
||||||
motion events. If a target does not accept any of the
|
motion/pointer_focus event gives the location of the drop.
|
||||||
offered types, type is NULL -->
|
Target must respond with the 'receive' request, which sends
|
||||||
<event name="target">
|
an fd to the source for writing the drag data. -->
|
||||||
<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. -->
|
|
||||||
<event name="drop"/>
|
<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>
|
||||||
|
|
||||||
<interface name="surface" version="1">
|
<interface name="surface" version="1">
|
||||||
<request name="destroy"/>
|
<request name="destroy" type="destructor"/>
|
||||||
|
|
||||||
<request name="attach">
|
<request name="attach">
|
||||||
<arg name="buffer" type="object" interface="buffer"/>
|
<arg name="buffer" type="object" interface="buffer"/>
|
||||||
|
|
|
||||||
42
scanner.c
42
scanner.c
|
|
@ -74,6 +74,7 @@ struct message {
|
||||||
char *uppercase_name;
|
char *uppercase_name;
|
||||||
struct wl_list arg_list;
|
struct wl_list arg_list;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
int destructor;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum arg_type {
|
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,
|
wl_list_insert(ctx->interface->event_list.prev,
|
||||||
&message->link);
|
&message->link);
|
||||||
|
|
||||||
|
if (type != NULL && strcmp(type, "destructor") == 0)
|
||||||
|
message->destructor = 1;
|
||||||
|
else
|
||||||
|
message->destructor = 0;
|
||||||
|
|
||||||
ctx->message = message;
|
ctx->message = message;
|
||||||
} else if (strcmp(element_name, "arg") == 0) {
|
} else if (strcmp(element_name, "arg") == 0) {
|
||||||
arg = malloc(sizeof *arg);
|
arg = malloc(sizeof *arg);
|
||||||
|
|
@ -263,6 +269,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
|
||||||
{
|
{
|
||||||
struct message *m;
|
struct message *m;
|
||||||
struct arg *a, *ret;
|
struct arg *a, *ret;
|
||||||
|
int has_destructor, has_destroy;
|
||||||
|
|
||||||
/* We provide a hand written constructor for the display object */
|
/* We provide a hand written constructor for the display object */
|
||||||
if (strcmp(interface->name, "display") != 0)
|
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, 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))
|
if (wl_list_empty(message_list))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -347,6 +381,11 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
|
||||||
}
|
}
|
||||||
printf(");\n");
|
printf(");\n");
|
||||||
|
|
||||||
|
if (m->destructor)
|
||||||
|
printf("\n\twl_proxy_destroy("
|
||||||
|
"(struct wl_proxy *) %s);\n",
|
||||||
|
interface->name);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
printf("\n\treturn (struct wl_%s *) %s;\n",
|
printf("\n\treturn (struct wl_%s *) %s;\n",
|
||||||
ret->interface_name, ret->name);
|
ret->interface_name, ret->name);
|
||||||
|
|
@ -442,6 +481,9 @@ static const char client_prototypes[] =
|
||||||
"wl_proxy_create_for_id(struct wl_display *display,\n"
|
"wl_proxy_create_for_id(struct wl_display *display,\n"
|
||||||
"\t\t const struct wl_interface *interface, uint32_t id);\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"
|
"extern int\n"
|
||||||
"wl_proxy_add_listener(struct wl_proxy *proxy,\n"
|
"wl_proxy_add_listener(struct wl_proxy *proxy,\n"
|
||||||
"\t\t void (**implementation)(void), void *data);\n\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_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_EXPORT int
|
||||||
wl_proxy_add_listener(struct wl_proxy *proxy,
|
wl_proxy_add_listener(struct wl_proxy *proxy,
|
||||||
void (**implementation)(void), void *data)
|
void (**implementation)(void), void *data)
|
||||||
|
|
|
||||||
|
|
@ -124,8 +124,13 @@ struct wl_visual {
|
||||||
struct wl_object base;
|
struct wl_object base;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wl_drag {
|
struct wl_drag_offer {
|
||||||
struct wl_object base;
|
struct wl_object base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wl_drag {
|
||||||
|
struct wl_resource resource;
|
||||||
|
struct wl_drag_offer drag_offer;
|
||||||
struct wl_surface *source;
|
struct wl_surface *source;
|
||||||
struct wl_surface *pointer_focus;
|
struct wl_surface *pointer_focus;
|
||||||
struct wl_client *target;
|
struct wl_client *target;
|
||||||
|
|
@ -133,7 +138,7 @@ struct wl_drag {
|
||||||
struct wl_input_device *input_device;
|
struct wl_input_device *input_device;
|
||||||
struct wl_array types;
|
struct wl_array types;
|
||||||
const char *type;
|
const char *type;
|
||||||
uint32_t time;
|
uint32_t pointer_focus_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue