Compare commits

...

18 Commits

Author SHA1 Message Date
410b37bc53 wayland: Update focus window during DnD motion
But don't emit crossing events, since the DnD grab is in effect.

https://bugzilla.gnome.org/show_bug.cgi?id=728030
2014-09-30 17:34:32 +02:00
6dfdc6d6ec wayland: Add emit_crossing argument to meta_wayland_pointer_set_focus()
This is TRUE in every place it was previously called.

https://bugzilla.gnome.org/show_bug.cgi?id=728030
2014-09-30 17:34:32 +02:00
869d12c36d wayland: Trigger the DnD failed animation if no DnD is to happen
If there is no focus window, focus data_source or target selected,
DnD will fail and show the fancy animation.
2014-09-30 17:30:54 +02:00
827e0c23c5 wayland: Store whether the wl_data_source has a target selected
It will be useful to check whether DnD is going to fail or not.
2014-09-30 17:30:54 +02:00
9efd96be7b wayland: Unset local DnD surface if destroyed early during DnD 2014-09-30 17:30:54 +02:00
102d1e62a2 wayland: Keep track of the origin surface and drag point on DnD
Keeping track of the surface will be necessary in case it is destroyed
during DnD, and the coordinates will be useful when figuring out the
snap back coordinates.
2014-09-30 17:30:54 +02:00
aba81603b9 backend: Add "DnD failed" plumbing to the MetaCursorTracker 2014-09-30 17:30:54 +02:00
10c6056ce0 backend: Add "DnD failed" animation plumbing on MetaCursorRenderer
The MetaCursorRenderer is the object aware of the offsets applying to
the DnD surface, so translate the given coordinates by that.
2014-09-30 17:30:54 +02:00
79fdbbfe1a backend: Add "DnD failed" animation
This is currently handled by the MetaStage, when DnD is hinted to be
failed, the current overlay will be copied and used on the snap back/
fade out animation, after the animation is finished, the extra overlay
will be freed.
2014-09-30 17:30:54 +02:00
572727e6e8 backend: Add meta_overlay_copy()
This function will be useful to transfer an overlay so it can be
temporarily rendered differently. Will be mainly useful for DnD
animations.
2014-09-30 17:30:54 +02:00
1dbc9e868f detach dnd surface and pointer 2014-09-30 17:30:54 +02:00
a181ea3cde surface: honor wl_surface_commit()s on the DnD surface
And update the surface when this happens.
2014-09-30 17:30:54 +02:00
78477dd56a data-device: Update the DnD surface on drag grab updates 2014-09-30 17:30:54 +02:00
30cc4e1d0a data-device: Store the current drag grab
And bail out if any further start_drag() is attempted.
2014-09-30 17:30:54 +02:00
4b83b031bc cursor-tracker: Wrap cursor renderer's DnD surface setter 2014-09-30 17:30:54 +02:00
40a85e0e99 cursor-renderer: Add setter for the DnD surface
The DnD surface will be always updated/redrawn when the cursor position
changes, and it will never go through backend-specific handling of hw
cursors, so the stage will always need updating when a drag is in effect.
2014-09-30 17:30:54 +02:00
dfde1ff327 stage: Add overlay for the DnD surface
This will be rendered similarly to the pointer cursor.
2014-09-30 17:30:54 +02:00
92b7daab61 wayland: Record the offset position
This is needed for DND surfaces. We should probably test to see if it's
used for cursor surfaces at all.
2014-09-30 17:30:54 +02:00
12 changed files with 503 additions and 55 deletions

View File

@ -35,13 +35,21 @@
#include "meta-stage.h"
typedef struct
{
CoglTexture *texture;
MetaRectangle current_rect;
int current_x, current_y;
} MetaCursorLayer;
struct _MetaCursorRendererPrivate
{
int current_x, current_y;
MetaRectangle current_rect;
MetaCursorLayer core_layer;
MetaCursorLayer dnd_layer;
MetaCursorReference *displayed_cursor;
gboolean handled_by_backend;
int dnd_surface_offset_x, dnd_surface_offset_y;
gboolean cursor_handled_by_backend;
};
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
@ -59,12 +67,19 @@ queue_redraw (MetaCursorRenderer *renderer)
if (!stage)
return;
if (priv->displayed_cursor && !priv->handled_by_backend)
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, NULL, NULL);
/* Pointer cursor */
if (!priv->cursor_handled_by_backend)
texture = priv->core_layer.texture;
else
texture = NULL;
meta_stage_set_cursor (META_STAGE (stage), texture, &priv->current_rect);
meta_stage_set_cursor (META_STAGE (stage), texture,
&priv->core_layer.current_rect);
/* DnD surface */
meta_stage_set_dnd_surface (META_STAGE (stage),
priv->dnd_layer.texture,
&priv->dnd_layer.current_rect);
}
static gboolean
@ -85,46 +100,76 @@ meta_cursor_renderer_init (MetaCursorRenderer *renderer)
}
static void
update_cursor (MetaCursorRenderer *renderer)
update_layer (MetaCursorRenderer *renderer,
MetaCursorLayer *layer,
CoglTexture *texture,
int offset_x,
int offset_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend;
gboolean should_redraw = FALSE;
layer->texture = texture;
if (priv->displayed_cursor)
if (layer->texture)
{
CoglTexture *texture;
int hot_x, hot_y;
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor, &hot_x, &hot_y);
priv->current_rect.x = priv->current_x - hot_x;
priv->current_rect.y = priv->current_y - hot_y;
priv->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (texture));
priv->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (texture));
layer->current_rect.x = layer->current_x + offset_x;
layer->current_rect.y = layer->current_y + offset_y;
layer->current_rect.width = cogl_texture_get_width (layer->texture);
layer->current_rect.height = cogl_texture_get_height (layer->texture);
}
else
{
priv->current_rect.x = 0;
priv->current_rect.y = 0;
priv->current_rect.width = 0;
priv->current_rect.height = 0;
layer->current_rect.x = 0;
layer->current_rect.y = 0;
layer->current_rect.width = 0;
layer->current_rect.height = 0;
}
}
static void
emit_update_cursor (MetaCursorRenderer *renderer,
gboolean force)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
gboolean handled_by_backend, should_redraw = FALSE;
handled_by_backend = META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer);
if (handled_by_backend != priv->handled_by_backend)
if (handled_by_backend != priv->cursor_handled_by_backend)
{
priv->handled_by_backend = handled_by_backend;
priv->cursor_handled_by_backend = handled_by_backend;
should_redraw = TRUE;
}
if (!handled_by_backend)
if (force || !handled_by_backend || priv->dnd_layer.texture)
should_redraw = TRUE;
if (should_redraw)
queue_redraw (renderer);
}
static void
update_cursor (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
CoglTexture *texture;
int hot_x, hot_y;
/* Cursor layer */
if (priv->displayed_cursor)
{
texture = meta_cursor_reference_get_cogl_texture (priv->displayed_cursor,
&hot_x, &hot_y);
}
else
{
texture = NULL;
hot_x = 0;
hot_y = 0;
}
update_layer (renderer, &priv->core_layer, texture, -hot_x, -hot_y);
emit_update_cursor (renderer, FALSE);
}
MetaCursorRenderer *
meta_cursor_renderer_new (void)
{
@ -144,6 +189,23 @@ meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
update_cursor (renderer);
}
void
meta_cursor_renderer_set_dnd_surface (MetaCursorRenderer *renderer,
CoglTexture *texture,
int offset_x,
int offset_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
g_assert (meta_is_wayland_compositor ());
priv->dnd_surface_offset_x = offset_x;
priv->dnd_surface_offset_y = offset_y;
update_layer (renderer, &priv->dnd_layer, texture, offset_x, offset_y);
emit_update_cursor (renderer, TRUE);
}
void
meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
int x, int y)
@ -152,12 +214,46 @@ meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
g_assert (meta_is_wayland_compositor ());
priv->current_x = x;
priv->current_y = y;
priv->core_layer.current_x = x;
priv->core_layer.current_y = y;
update_cursor (renderer);
}
void
meta_cursor_renderer_set_dnd_surface_position (MetaCursorRenderer *renderer,
int x,
int y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
g_assert (meta_is_wayland_compositor ());
priv->dnd_layer.current_x = x;
priv->dnd_layer.current_y = y;
update_layer (renderer, &priv->dnd_layer, priv->dnd_layer.texture,
priv->dnd_surface_offset_x, priv->dnd_surface_offset_y);
emit_update_cursor (renderer, FALSE);
}
void
meta_cursor_renderer_dnd_failed (MetaCursorRenderer *renderer,
int dest_x,
int dest_y)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
g_assert (meta_is_wayland_compositor ());
if (priv->dnd_layer.texture)
meta_stage_dnd_failed (META_STAGE (stage),
dest_x + priv->dnd_surface_offset_x,
dest_y + priv->dnd_surface_offset_y);
}
MetaCursorReference *
meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
{
@ -171,5 +267,5 @@ meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
return &priv->current_rect;
return &priv->core_layer.current_rect;
}

View File

@ -67,4 +67,14 @@ void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
MetaCursorReference * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
const MetaRectangle * meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer);
void meta_cursor_renderer_set_dnd_surface (MetaCursorRenderer *renderer,
CoglTexture *texture,
int offset_x,
int offset_y);
void meta_cursor_renderer_set_dnd_surface_position (MetaCursorRenderer *renderer,
int x, int y);
void meta_cursor_renderer_dnd_failed (MetaCursorRenderer *renderer,
int dest_x, int dest_y);
#endif /* META_CURSOR_RENDERER_H */

View File

@ -62,10 +62,20 @@ void meta_cursor_tracker_set_window_cursor (MetaCursorTracker *tracker,
void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursorReference *cursor);
void meta_cursor_tracker_set_dnd_surface (MetaCursorTracker *tracker,
CoglTexture *texture,
int offset_x,
int offset_y);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_update_dnd_surface_position (MetaCursorTracker *tracker,
int new_x,
int new_y);
void meta_cursor_tracker_dnd_failed (MetaCursorTracker *tracker,
int dest_x,
int dest_y);
MetaCursorReference * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);

View File

@ -358,6 +358,28 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
sync_cursor (tracker);
}
void
meta_cursor_tracker_set_dnd_surface (MetaCursorTracker *tracker,
CoglTexture *texture,
int offset_x,
int offset_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_dnd_surface (tracker->renderer, texture,
offset_x, offset_y);
}
void
meta_cursor_tracker_dnd_failed (MetaCursorTracker *tracker,
int dest_x,
int dest_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_dnd_failed (tracker->renderer, dest_x, dest_y);
}
void
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
int new_x,
@ -368,6 +390,17 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
meta_cursor_renderer_set_position (tracker->renderer, new_x, new_y);
}
void
meta_cursor_tracker_update_dnd_surface_position (MetaCursorTracker *tracker,
int new_x,
int new_y)
{
g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_dnd_surface_position (tracker->renderer,
new_x, new_y);
}
static void
get_pointer_position_gdk (int *x,
int *y,

View File

@ -28,6 +28,8 @@
#include <meta/meta-backend.h>
#include <meta/util.h>
#define DRAG_FAILED_MSECS 500
typedef struct {
gboolean enabled;
@ -39,8 +41,20 @@ typedef struct {
gboolean previous_is_valid;
} MetaOverlay;
typedef struct {
MetaStage *stage;
MetaOverlay overlay;
ClutterTimeline *timeline;
int orig_x;
int orig_y;
int dest_x;
int dest_y;
} MetaDragFailedAnimation;
struct _MetaStagePrivate {
MetaOverlay dnd_overlay;
MetaOverlay cursor_overlay;
GList *drag_failed_animations;
};
typedef struct _MetaStagePrivate MetaStagePrivate;
@ -54,6 +68,15 @@ meta_overlay_init (MetaOverlay *overlay)
overlay->pipeline = cogl_pipeline_new (ctx);
}
static void
meta_overlay_copy (MetaOverlay *src,
MetaOverlay *dst)
{
*dst = *src;
dst->pipeline = cogl_pipeline_copy (src->pipeline);
dst->texture = src->texture;
}
static void
meta_overlay_free (MetaOverlay *overlay)
{
@ -112,6 +135,7 @@ meta_stage_finalize (GObject *object)
MetaStage *stage = META_STAGE (object);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_free (&priv->dnd_overlay);
meta_overlay_free (&priv->cursor_overlay);
}
@ -120,9 +144,18 @@ meta_stage_paint (ClutterActor *actor)
{
MetaStage *stage = META_STAGE (actor);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *animation;
GList *l;
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
for (l = priv->drag_failed_animations; l; l = l->next)
{
animation = l->data;
meta_overlay_paint (&animation->overlay);
}
meta_overlay_paint (&priv->dnd_overlay);
meta_overlay_paint (&priv->cursor_overlay);
}
@ -142,6 +175,7 @@ meta_stage_init (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_init (&priv->dnd_overlay);
meta_overlay_init (&priv->cursor_overlay);
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE);
@ -183,6 +217,19 @@ queue_redraw_for_overlay (MetaStage *stage,
}
}
void
meta_stage_set_dnd_surface (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
g_assert (meta_is_wayland_compositor ());
meta_overlay_set (&priv->dnd_overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->dnd_overlay);
}
void
meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
@ -195,3 +242,84 @@ meta_stage_set_cursor (MetaStage *stage,
meta_overlay_set (&priv->cursor_overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->cursor_overlay);
}
static void
drag_failed_animation_frame_cb (ClutterTimeline *timeline,
guint pos,
gpointer user_data)
{
MetaDragFailedAnimation *data = user_data;
gdouble progress = clutter_timeline_get_progress (timeline);
CoglColor color;
cogl_color_init_from_4f (&color, 0, 0, 0, 1 - progress);
cogl_pipeline_set_layer_combine_constant (data->overlay.pipeline, 0, &color);
data->overlay.current_rect.x = data->orig_x + ((data->dest_x - data->orig_x) * progress);
data->overlay.current_rect.y = data->orig_y + ((data->dest_y - data->orig_y) * progress);
queue_redraw_for_overlay (data->stage, &data->overlay);
}
static void
meta_drag_failed_animation_free (MetaDragFailedAnimation *data)
{
MetaStage *stage = data->stage;
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
priv->drag_failed_animations =
g_list_remove (priv->drag_failed_animations, data);
g_object_unref (data->timeline);
meta_overlay_free (&data->overlay);
g_slice_free (MetaDragFailedAnimation, data);
}
static MetaDragFailedAnimation *
meta_drag_failed_animation_new (MetaStage *stage,
int dest_x,
int dest_y)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *data;
data = g_slice_new0 (MetaDragFailedAnimation);
data->stage = stage;
data->orig_x = priv->dnd_overlay.current_rect.x;
data->orig_y = priv->dnd_overlay.current_rect.y;
data->dest_x = dest_x;
data->dest_y = dest_y;
meta_overlay_copy (&priv->dnd_overlay, &data->overlay);
data->timeline = clutter_timeline_new (DRAG_FAILED_MSECS);
clutter_timeline_set_progress_mode (data->timeline, CLUTTER_EASE_OUT_CUBIC);
g_signal_connect (data->timeline, "new-frame",
G_CALLBACK (drag_failed_animation_frame_cb), data);
g_signal_connect_swapped (data->timeline, "completed",
G_CALLBACK (meta_drag_failed_animation_free), data);
priv->drag_failed_animations =
g_list_prepend (priv->drag_failed_animations, data);
cogl_pipeline_set_layer_combine (data->overlay.pipeline, 0,
"RGBA = MODULATE (TEXTURE, CONSTANT[A])",
NULL);
return data;
}
void
meta_stage_dnd_failed (MetaStage *stage,
int dest_x,
int dest_y)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaDragFailedAnimation *data;
g_assert (meta_is_wayland_compositor ());
if (!priv->dnd_overlay.enabled)
return;
data = meta_drag_failed_animation_new (stage, dest_x, dest_y);
clutter_timeline_start (data->timeline);
}

View File

@ -51,9 +51,18 @@ GType meta_stage_get_type (void) G_GNUC_CONST;
ClutterActor *meta_stage_new (void);
void meta_stage_set_dnd_surface (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_dnd_failed (MetaStage *stage,
int dest_x,
int dest_y);
G_END_DECLS
#endif /* META_STAGE_H */

View File

@ -34,6 +34,7 @@
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
#include "meta-cursor-tracker-private.h"
typedef struct
{
@ -46,6 +47,7 @@ struct _MetaWaylandDataSource
{
struct wl_resource *resource;
struct wl_array mime_types;
gboolean has_target;
};
static void
@ -67,7 +69,10 @@ data_offer_accept (struct wl_client *client,
* this be a wl_data_device request? */
if (offer->source)
wl_data_source_send_target (offer->source->resource, mime_type);
{
wl_data_source_send_target (offer->source->resource, mime_type);
offer->source->has_target = mime_type != NULL;
}
}
static void
@ -162,7 +167,7 @@ static struct wl_data_source_interface data_source_interface = {
data_source_destroy
};
typedef struct {
struct _MetaWaylandDragGrab {
MetaWaylandPointerGrab generic;
MetaWaylandSeat *seat;
@ -177,7 +182,12 @@ typedef struct {
MetaWaylandDataSource *drag_data_source;
struct wl_listener drag_data_source_listener;
} MetaWaylandDragGrab;
MetaWaylandSurface *drag_origin;
struct wl_listener drag_origin_listener;
int drag_start_x, drag_start_y;
};
static void
destroy_drag_focus (struct wl_listener *listener, void *data)
@ -202,6 +212,8 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
if (drag_grab->drag_focus == surface)
return;
meta_wayland_pointer_set_focus (&seat->pointer, surface, FALSE);
if (drag_grab->drag_focus_data_device)
{
wl_data_device_send_leave (drag_grab->drag_focus_data_device);
@ -241,6 +253,40 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
wl_resource_add_destroy_listener (data_device_resource, &drag_grab->drag_focus_listener);
}
static void
drag_grab_update_dnd_surface_position (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSeat *seat = drag_grab->seat;
ClutterPoint pos;
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
meta_cursor_tracker_update_dnd_surface_position (seat->pointer.cursor_tracker,
(int) pos.x, (int) pos.y);
}
static void
drag_grab_update_dnd_surface (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSurface *surface = drag_grab->drag_surface;
MetaWaylandSeat *seat = drag_grab->seat;
CoglTexture *texture = NULL;
int offset_x, offset_y;
if (surface)
{
if (surface->buffer)
texture = surface->buffer->texture;
offset_x = surface->offset_x;
offset_y = surface->offset_y;
}
else
offset_x = offset_y = 0;
meta_cursor_tracker_set_dnd_surface (seat->pointer.cursor_tracker,
texture, offset_x, offset_y);
}
static void
drag_grab_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
@ -248,6 +294,8 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
wl_fixed_t sx, sy;
drag_grab_update_dnd_surface_position (drag_grab);
if (drag_grab->drag_focus_data_device)
{
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
@ -259,9 +307,38 @@ drag_grab_motion (MetaWaylandPointerGrab *grab,
}
}
static void
data_device_dnd_failed (MetaWaylandDragGrab *drag_grab)
{
MetaWaylandSurface *surface = drag_grab->drag_origin;
MetaWaylandSeat *seat = drag_grab->seat;
ClutterPoint dest;
if (drag_grab->drag_origin &&
!meta_window_is_hidden (surface->window))
{
/* Find out the snap back position */
clutter_actor_get_transformed_position (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
&dest.x, &dest.y);
dest.x += drag_grab->drag_start_x;
dest.y += drag_grab->drag_start_y;
}
else
clutter_input_device_get_coords (seat->pointer.device, NULL, &dest);
meta_cursor_tracker_dnd_failed (seat->pointer.cursor_tracker,
dest.x, dest.y);
}
static void
data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
{
if (drag_grab->drag_origin)
{
drag_grab->drag_origin = NULL;
wl_list_remove (&drag_grab->drag_origin_listener.link);
}
if (drag_grab->drag_surface)
{
drag_grab->drag_surface = NULL;
@ -269,9 +346,15 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
}
if (drag_grab->drag_data_source)
wl_list_remove (&drag_grab->drag_data_source_listener.link);
{
drag_grab->drag_data_source->has_target = FALSE;
wl_list_remove (&drag_grab->drag_data_source_listener.link);
}
drag_grab->seat->data_device.current_grab = NULL;
drag_grab_focus (&drag_grab->generic, NULL);
drag_grab_update_dnd_surface (drag_grab);
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
g_slice_free (MetaWaylandDragGrab, drag_grab);
@ -285,10 +368,15 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
MetaWaylandSeat *seat = drag_grab->seat;
ClutterEventType event_type = clutter_event_type (event);
if (drag_grab->drag_focus_data_device &&
drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
event_type == CLUTTER_BUTTON_RELEASE)
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
{
if (drag_grab->drag_focus_data_device &&
drag_grab->drag_data_source->has_target)
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
else
data_device_dnd_failed (drag_grab);
}
if (seat->pointer.button_count == 0 &&
event_type == CLUTTER_BUTTON_RELEASE)
@ -301,6 +389,16 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
drag_grab_button,
};
static void
destroy_data_device_origin (struct wl_listener *listener, void *data)
{
MetaWaylandDragGrab *drag_grab =
wl_container_of (listener, drag_grab, drag_origin_listener);
drag_grab->drag_origin = NULL;
data_device_end_drag_grab (drag_grab);
}
static void
destroy_data_device_source (struct wl_listener *listener, void *data)
{
@ -318,6 +416,7 @@ destroy_data_device_icon (struct wl_listener *listener, void *data)
wl_container_of (listener, drag_grab, drag_data_source_listener);
drag_grab->drag_surface = NULL;
drag_grab_update_dnd_surface (drag_grab);
}
static void
@ -329,20 +428,29 @@ data_device_start_drag (struct wl_client *client,
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
MetaWaylandSurface *surface = NULL;
MetaWaylandDragGrab *drag_grab;
ClutterPoint pos;
if ((seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource)))
if (origin_resource)
surface = wl_resource_get_user_data (origin_resource);
if (!surface)
return;
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
!seat->pointer.focus_surface ||
seat->pointer.focus_surface != surface)
return;
/* FIXME: Check that the data source type array isn't empty. */
if (seat->pointer.grab != &seat->pointer.default_grab)
if (data_device->current_grab ||
seat->pointer.grab != &seat->pointer.default_grab)
return;
drag_grab = g_slice_new0 (MetaWaylandDragGrab);
data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
drag_grab->generic.interface = &drag_grab_interface;
drag_grab->generic.pointer = &seat->pointer;
@ -350,6 +458,17 @@ data_device_start_drag (struct wl_client *client,
drag_grab->drag_client = client;
drag_grab->seat = seat;
drag_grab->drag_origin = surface;
drag_grab->drag_origin_listener.notify = destroy_data_device_origin;
wl_resource_add_destroy_listener (origin_resource,
&drag_grab->drag_origin_listener);
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
pos.x, pos.y, &pos.x, &pos.y);
drag_grab->drag_start_x = pos.x;
drag_grab->drag_start_y = pos.y;
if (source_resource)
{
drag_grab->drag_data_source = wl_resource_get_user_data (source_resource);
@ -366,8 +485,10 @@ data_device_start_drag (struct wl_client *client,
&drag_grab->drag_icon_listener);
}
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
meta_wayland_pointer_set_focus (&seat->pointer, NULL, TRUE);
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab);
drag_grab_update_dnd_surface_position (drag_grab);
drag_grab_update_dnd_surface (drag_grab);
}
static void
@ -551,3 +672,18 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
wl_data_device_send_selection (data_device_resource, offer);
}
}
gboolean
meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface)
{
return data_device->current_grab &&
data_device->current_grab->drag_surface == surface;
}
void
meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device)
{
if (data_device->current_grab)
drag_grab_update_dnd_surface (data_device->current_grab);
}

View File

@ -27,12 +27,15 @@
#include "meta-wayland-types.h"
typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab;
struct _MetaWaylandDataDevice
{
uint32_t selection_serial;
MetaWaylandDataSource *selection_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list resource_list;
MetaWaylandDragGrab *current_grab;
};
void meta_wayland_data_device_manager_init (MetaWaylandCompositor *compositor);
@ -41,4 +44,8 @@ void meta_wayland_data_device_init (MetaWaylandDataDevice *data_device);
void meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device);
gboolean meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device,
MetaWaylandSurface *surface);
void meta_wayland_data_device_update_dnd_surface (MetaWaylandDataDevice *data_device);
#endif /* META_WAYLAND_DATA_DEVICE_H */

View File

@ -95,7 +95,7 @@ pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
{
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener);
meta_wayland_pointer_set_focus (pointer, NULL);
meta_wayland_pointer_set_focus (pointer, NULL, TRUE);
}
static void
@ -107,7 +107,7 @@ default_grab_focus (MetaWaylandPointerGrab *grab,
if (pointer->button_count > 0)
return;
meta_wayland_pointer_set_focus (pointer, surface);
meta_wayland_pointer_set_focus (pointer, surface, TRUE);
}
static void
@ -178,7 +178,7 @@ default_grab_button (MetaWaylandPointerGrab *grab,
}
if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE)
meta_wayland_pointer_set_focus (pointer, pointer->current);
meta_wayland_pointer_set_focus (pointer, pointer->current, TRUE);
}
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
@ -218,7 +218,7 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_release (MetaWaylandPointer *pointer)
{
meta_wayland_pointer_set_focus (pointer, NULL);
meta_wayland_pointer_set_focus (pointer, NULL, TRUE);
set_cursor_surface (pointer, NULL);
pointer->display = NULL;
@ -480,7 +480,8 @@ broadcast_focus (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
MetaWaylandSurface *surface,
gboolean emit_crossing)
{
if (pointer->display == NULL)
return;
@ -500,9 +501,12 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
if (emit_crossing)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
wl_resource_for_each (resource, l)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
}
}
move_resources (&pointer->resource_list, &pointer->focus_resource_list);
@ -533,7 +537,7 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
wl_resource_get_client (pointer->focus_surface->resource));
l = &pointer->focus_resource_list;
if (!wl_list_empty (l))
if (emit_crossing && !wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
@ -595,9 +599,9 @@ popup_grab_focus (MetaWaylandPointerGrab *grab,
/* Popup grabs are in owner-events mode (ie, events for the same client
are reported as normal) */
if (surface && wl_resource_get_client (surface->resource) == popup_grab->grab_client)
meta_wayland_pointer_set_focus (grab->pointer, surface);
meta_wayland_pointer_set_focus (grab->pointer, surface, TRUE);
else
meta_wayland_pointer_set_focus (grab->pointer, NULL);
meta_wayland_pointer_set_focus (grab->pointer, NULL, TRUE);
}
static void

View File

@ -86,7 +86,8 @@ gboolean meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
const ClutterEvent *event);
void meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface);
MetaWaylandSurface *surface,
gboolean emit_crossing);
void meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
MetaWaylandPointerGrab *grab);

View File

@ -175,6 +175,13 @@ cursor_surface_commit (MetaWaylandSurface *surface,
meta_wayland_seat_update_cursor_surface (surface->compositor->seat);
}
static void
dnd_surface_commit (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
{
meta_wayland_data_device_update_dnd_surface (&surface->compositor->seat->data_device);
}
static void
calculate_surface_window_geometry (MetaWaylandSurface *surface,
MetaRectangle *total_geometry,
@ -429,6 +436,9 @@ commit_pending_state (MetaWaylandSurface *surface,
if (!cairo_region_is_empty (pending->damage))
surface_process_damage (surface, pending->damage);
surface->offset_x += pending->dx;
surface->offset_y += pending->dy;
if (pending->opaque_region)
{
pending->opaque_region = scale_region (pending->opaque_region, surface->scale);
@ -442,6 +452,8 @@ commit_pending_state (MetaWaylandSurface *surface,
if (surface == compositor->seat->pointer.cursor_surface)
cursor_surface_commit (surface, pending);
else if (meta_wayland_data_device_is_dnd_surface (&compositor->seat->data_device, surface))
dnd_surface_commit (surface, pending);
else if (surface->window)
toplevel_surface_commit (surface, pending);
else if (surface->subsurface.resource)

View File

@ -115,6 +115,8 @@ struct _MetaWaylandSurface
GSList *pending_placement_ops;
} sub;
int32_t offset_x, offset_y;
gboolean has_set_geometry;
/* All the pending state that wl_surface.commit will apply. */