Compare commits
15 Commits
main
...
wip/garnac
Author | SHA1 | Date | |
---|---|---|---|
|
3f27073f55 | ||
|
79d7f6b415 | ||
|
9daf885dcc | ||
|
5afe78cf99 | ||
|
be016ad745 | ||
|
9038313a1a | ||
|
a7c6d906ed | ||
|
b7bb9d9025 | ||
|
6fcfc4f7c6 | ||
|
c2e043b7d6 | ||
|
3da9ad48b1 | ||
|
3600602fb3 | ||
|
6d6bbe6605 | ||
|
049cd5f9d6 | ||
|
5aee1b5e5a |
223
gdk/gdkdnd.c
223
gdk/gdkdnd.c
@@ -27,7 +27,33 @@
|
||||
#include "gdkdndprivate.h"
|
||||
#include "gdkdisplay.h"
|
||||
#include "gdkwindow.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkenumtypes.h"
|
||||
#include "gdkcursor.h"
|
||||
|
||||
static struct {
|
||||
GdkDragAction action;
|
||||
const gchar *name;
|
||||
GdkCursor *cursor;
|
||||
} drag_cursors[] = {
|
||||
{ GDK_ACTION_DEFAULT, NULL, NULL },
|
||||
{ GDK_ACTION_ASK, "dnd-ask", NULL },
|
||||
{ GDK_ACTION_COPY, "dnd-copy", NULL },
|
||||
{ GDK_ACTION_MOVE, "dnd-move", NULL },
|
||||
{ GDK_ACTION_LINK, "dnd-link", NULL },
|
||||
{ 0, "dnd-none", NULL },
|
||||
};
|
||||
|
||||
enum {
|
||||
CANCEL,
|
||||
DROP_PERFORMED,
|
||||
DND_FINISHED,
|
||||
ACTION_CHANGED,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[N_SIGNALS] = { 0 };
|
||||
static GList *contexts = NULL;
|
||||
|
||||
/**
|
||||
* SECTION:dnd
|
||||
@@ -217,6 +243,7 @@ G_DEFINE_TYPE (GdkDragContext, gdk_drag_context, G_TYPE_OBJECT)
|
||||
static void
|
||||
gdk_drag_context_init (GdkDragContext *context)
|
||||
{
|
||||
contexts = g_list_prepend (contexts, context);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -224,6 +251,7 @@ gdk_drag_context_finalize (GObject *object)
|
||||
{
|
||||
GdkDragContext *context = GDK_DRAG_CONTEXT (object);
|
||||
|
||||
contexts = g_list_remove (contexts, context);
|
||||
g_list_free (context->targets);
|
||||
|
||||
if (context->source_window)
|
||||
@@ -241,6 +269,90 @@ gdk_drag_context_class_init (GdkDragContextClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gdk_drag_context_finalize;
|
||||
|
||||
/**
|
||||
* GdkDragContext::cancel:
|
||||
*
|
||||
* The drag and drop operation was cancelled.
|
||||
*
|
||||
* This signal will only be emitted if the #GdkDragContext manages
|
||||
* the drag and drop operation. See gdk_drag_context_manage_dnd()
|
||||
* for more information.
|
||||
*
|
||||
* Since: 3.20
|
||||
*/
|
||||
signals[CANCEL] =
|
||||
g_signal_new (P_("cancel"),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GdkDragContextClass, cancel),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* GdkDragContext::drop-performed:
|
||||
* @time: the time at which the drop happened.
|
||||
*
|
||||
* The drag and drop operation was performed on an accepting client.
|
||||
*
|
||||
* This signal will only be emitted if the #GdkDragContext manages
|
||||
* the drag and drop operation. See gdk_drag_context_manage_dnd()
|
||||
* for more information.
|
||||
*
|
||||
* Since: 3.20
|
||||
*/
|
||||
signals[DROP_PERFORMED] =
|
||||
g_signal_new (P_("drop-performed"),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GdkDragContextClass, drop_performed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__INT,
|
||||
G_TYPE_NONE, 1, G_TYPE_INT);
|
||||
|
||||
/**
|
||||
* GdkDragContext::dnd-finished:
|
||||
*
|
||||
* The drag and drop operation was finished, the drag destination
|
||||
* finished reading all data. The drag source can now free all
|
||||
* miscellaneous data.
|
||||
*
|
||||
* This signal will only be emitted if the #GdkDragContext manages
|
||||
* the drag and drop operation. See gdk_drag_context_manage_dnd()
|
||||
* for more information.
|
||||
*
|
||||
* Since: 3.20
|
||||
*/
|
||||
signals[DND_FINISHED] =
|
||||
g_signal_new (P_("dnd-finished"),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GdkDragContextClass, dnd_finished),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* GdkDragContext::action-changed:
|
||||
* @action: The action currently chosen
|
||||
*
|
||||
* A new action is being chosen for the drag and drop operation.
|
||||
*
|
||||
* This signal will only be emitted if the #GdkDragContext manages
|
||||
* the drag and drop operation. See gdk_drag_context_manage_dnd()
|
||||
* for more information.
|
||||
*
|
||||
* Since: 3.20
|
||||
*/
|
||||
signals[ACTION_CHANGED] =
|
||||
g_signal_new (P_("action-changed"),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GdkDragContextClass, action_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__FLAGS,
|
||||
G_TYPE_NONE, 1, GDK_TYPE_DRAG_ACTION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,6 +428,9 @@ gdk_drag_status (GdkDragContext *context,
|
||||
*
|
||||
* This function is called by the drag source.
|
||||
*
|
||||
* This function does not need to be called in managed drag and drop
|
||||
* operations. See gdk_drag_context_manage_dnd() for more information.
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
gboolean
|
||||
@@ -349,6 +464,9 @@ gdk_drag_motion (GdkDragContext *context,
|
||||
* Aborts a drag without dropping.
|
||||
*
|
||||
* This function is called by the drag source.
|
||||
*
|
||||
* This function does not need to be called in managed drag and drop
|
||||
* operations. See gdk_drag_context_manage_dnd() for more information.
|
||||
*/
|
||||
void
|
||||
gdk_drag_abort (GdkDragContext *context,
|
||||
@@ -367,6 +485,9 @@ gdk_drag_abort (GdkDragContext *context,
|
||||
* Drops on the current destination.
|
||||
*
|
||||
* This function is called by the drag source.
|
||||
*
|
||||
* This function does not need to be called in managed drag and drop
|
||||
* operations. See gdk_drag_context_manage_dnd() for more information.
|
||||
*/
|
||||
void
|
||||
gdk_drag_drop (GdkDragContext *context,
|
||||
@@ -527,3 +648,105 @@ gdk_drag_drop_done (GdkDragContext *context,
|
||||
if (GDK_DRAG_CONTEXT_GET_CLASS (context)->drop_done)
|
||||
GDK_DRAG_CONTEXT_GET_CLASS (context)->drop_done (context, success);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_drag_context_manage_dnd:
|
||||
* @context: a #GdkDragContext
|
||||
* @ipc_window: Window to use for IPC messaging/events
|
||||
* @actions: the actions supported by the drag source
|
||||
*
|
||||
* Requests the drag and drop operation to be managed by @context.
|
||||
* When a drag and drop operation becomes managed, the #GdkDragContext
|
||||
* will internally handle all input and source-side #GdkEventDND events
|
||||
* as required by the windowing system.
|
||||
*
|
||||
* Once the drag and drop operation is managed, the drag context will
|
||||
* emit the following signals:
|
||||
* - The #GdkDragContext::action-changed signal whenever the final action
|
||||
* to be performed by the drag and drop operation changes.
|
||||
* - The #GdkDragContext::drop-performed signal after the user performs
|
||||
* the drag and drop gesture (typically by releasing the mouse button).
|
||||
* - The #GdkDragContext::dnd-finished signal after the drag and drop
|
||||
* operation concludes (after all #GdkSelection transfers happen).
|
||||
* - The #GdkDragContext::cancel signal if the drag and drop operation is
|
||||
* finished but doesn't happen over an accepting destination, or is
|
||||
* cancelled through other means.
|
||||
*
|
||||
* Returns: #TRUE if the drag and drop operation is managed.
|
||||
**/
|
||||
gboolean
|
||||
gdk_drag_context_manage_dnd (GdkDragContext *context,
|
||||
GdkWindow *ipc_window,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE);
|
||||
g_return_val_if_fail (GDK_IS_WINDOW (ipc_window), FALSE);
|
||||
|
||||
if (GDK_DRAG_CONTEXT_GET_CLASS (context)->manage_dnd)
|
||||
return GDK_DRAG_CONTEXT_GET_CLASS (context)->manage_dnd (context, ipc_window,
|
||||
actions);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_drag_context_set_cursor (GdkDragContext *context,
|
||||
GdkCursor *cursor)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
|
||||
|
||||
if (GDK_DRAG_CONTEXT_GET_CLASS (context)->set_cursor)
|
||||
GDK_DRAG_CONTEXT_GET_CLASS (context)->set_cursor (context, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_drag_context_cancel (GdkDragContext *context)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
|
||||
|
||||
g_signal_emit (context, signals[CANCEL], 0);
|
||||
}
|
||||
|
||||
GList *
|
||||
gdk_drag_context_list (void)
|
||||
{
|
||||
return contexts;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_drag_context_handle_source_event (GdkEvent *event)
|
||||
{
|
||||
GdkDragContext *context;
|
||||
GList *l;
|
||||
|
||||
for (l = contexts; l; l = l->next)
|
||||
{
|
||||
context = l->data;
|
||||
|
||||
if (!context->is_source)
|
||||
continue;
|
||||
|
||||
if (!GDK_DRAG_CONTEXT_GET_CLASS (context)->handle_event)
|
||||
continue;
|
||||
|
||||
if (GDK_DRAG_CONTEXT_GET_CLASS (context)->handle_event (context, event))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GdkCursor *
|
||||
gdk_drag_get_cursor (GdkDragAction action)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0 ; i < G_N_ELEMENTS (drag_cursors) - 1; i++)
|
||||
if (drag_cursors[i].action == action)
|
||||
break;
|
||||
|
||||
if (drag_cursors[i].cursor == NULL)
|
||||
drag_cursors[i].cursor = gdk_cursor_new_from_name (gdk_display_get_default (),
|
||||
drag_cursors[i].name);
|
||||
return drag_cursors[i].cursor;
|
||||
}
|
||||
|
@@ -190,6 +190,10 @@ void gdk_drag_context_set_hotspot (GdkDragContext *context,
|
||||
gint hot_x,
|
||||
gint hot_y);
|
||||
|
||||
GDK_AVAILABLE_IN_3_20
|
||||
gboolean gdk_drag_context_manage_dnd (GdkDragContext *context,
|
||||
GdkWindow *ipc_window,
|
||||
GdkDragAction actions);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_DND_H__ */
|
||||
|
@@ -68,6 +68,21 @@ struct _GdkDragContextClass {
|
||||
gint hot_y);
|
||||
void (*drop_done) (GdkDragContext *context,
|
||||
gboolean success);
|
||||
|
||||
gboolean (*manage_dnd) (GdkDragContext *context,
|
||||
GdkWindow *ipc_window,
|
||||
GdkDragAction actions);
|
||||
void (*set_cursor) (GdkDragContext *context,
|
||||
GdkCursor *cursor);
|
||||
void (*cancel) (GdkDragContext *context);
|
||||
void (*drop_performed) (GdkDragContext *context,
|
||||
guint32 time);
|
||||
void (*dnd_finished) (GdkDragContext *context);
|
||||
|
||||
gboolean (*handle_event) (GdkDragContext *context,
|
||||
const GdkEvent *event);
|
||||
void (*action_changed) (GdkDragContext *context,
|
||||
GdkDragAction action);
|
||||
};
|
||||
|
||||
struct _GdkDragContext {
|
||||
@@ -91,6 +106,14 @@ struct _GdkDragContext {
|
||||
GdkDevice *device;
|
||||
};
|
||||
|
||||
GList * gdk_drag_context_list (void);
|
||||
|
||||
void gdk_drag_context_set_cursor (GdkDragContext *context,
|
||||
GdkCursor *cursor);
|
||||
void gdk_drag_context_cancel (GdkDragContext *context);
|
||||
gboolean gdk_drag_context_handle_source_event (GdkEvent *event);
|
||||
GdkCursor * gdk_drag_get_cursor (GdkDragAction action);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "gdkinternals.h"
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkdndprivate.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
@@ -65,6 +66,9 @@ static GDestroyNotify _gdk_event_notify = NULL;
|
||||
void
|
||||
_gdk_event_emit (GdkEvent *event)
|
||||
{
|
||||
if (gdk_drag_context_handle_source_event (event))
|
||||
return;
|
||||
|
||||
if (_gdk_event_func)
|
||||
(*_gdk_event_func) (event, _gdk_event_data);
|
||||
}
|
||||
|
@@ -306,7 +306,7 @@ gdk_wayland_device_set_window_cursor (GdkDevice *device,
|
||||
if (device == wd->touch_master)
|
||||
return;
|
||||
|
||||
if (wd->pointer_grab_window)
|
||||
if (wd->grab_cursor)
|
||||
cursor = wd->grab_cursor;
|
||||
|
||||
/* Setting the cursor to NULL means that we should use
|
||||
@@ -883,16 +883,10 @@ data_device_drop (void *data,
|
||||
struct wl_data_device *data_device)
|
||||
{
|
||||
GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data;
|
||||
GdkWindow *local_dnd_owner;
|
||||
|
||||
GDK_NOTE (EVENTS,
|
||||
g_message ("data device drop, data device %p", data_device));
|
||||
|
||||
local_dnd_owner = gdk_selection_owner_get_for_display (device->display, gdk_drag_get_selection (device->drop_context));
|
||||
|
||||
if (local_dnd_owner)
|
||||
gdk_wayland_device_unset_grab (device->master_pointer);
|
||||
|
||||
_gdk_wayland_drag_context_emit_event (device->drop_context,
|
||||
GDK_DROP_START, GDK_CURRENT_TIME);
|
||||
}
|
||||
@@ -1078,6 +1072,8 @@ pointer_handle_enter (void *data,
|
||||
device->pointer_focus = wl_surface_get_user_data(surface);
|
||||
g_object_ref(device->pointer_focus);
|
||||
|
||||
device->button_modifiers = 0;
|
||||
|
||||
device->surface_x = wl_fixed_to_double (sx);
|
||||
device->surface_y = wl_fixed_to_double (sy);
|
||||
device->enter_serial = serial;
|
||||
@@ -2618,6 +2614,27 @@ gdk_wayland_seat_get_capabilities (GdkSeat *seat)
|
||||
return caps;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_seat_set_grab_window (GdkWaylandSeat *seat,
|
||||
GdkWindow *window)
|
||||
{
|
||||
if (seat->pointer_grab_window)
|
||||
{
|
||||
_gdk_wayland_window_set_grab_seat (seat->pointer_grab_window, NULL);
|
||||
g_object_remove_weak_pointer (G_OBJECT (seat->pointer_grab_window),
|
||||
(gpointer *) &seat->pointer_grab_window);
|
||||
seat->pointer_grab_window = NULL;
|
||||
}
|
||||
|
||||
if (window)
|
||||
{
|
||||
seat->pointer_grab_window = window;
|
||||
g_object_add_weak_pointer (G_OBJECT (window),
|
||||
(gpointer *) &seat->pointer_grab_window);
|
||||
_gdk_wayland_window_set_grab_seat (window, GDK_SEAT (seat));
|
||||
}
|
||||
}
|
||||
|
||||
static GdkGrabStatus
|
||||
gdk_wayland_seat_grab (GdkSeat *seat,
|
||||
GdkWindow *window,
|
||||
@@ -2650,16 +2667,15 @@ gdk_wayland_seat_grab (GdkSeat *seat,
|
||||
if (native == NULL || GDK_WINDOW_DESTROYED (native))
|
||||
return GDK_GRAB_NOT_VIEWABLE;
|
||||
|
||||
wayland_seat->pointer_grab_window = window;
|
||||
gdk_wayland_seat_set_grab_window (wayland_seat, window);
|
||||
wayland_seat->pointer_grab_time = evtime;
|
||||
_gdk_wayland_window_set_grab_seat (window, seat);
|
||||
|
||||
if (prepare_func)
|
||||
(prepare_func) (seat, window, prepare_func_data);
|
||||
|
||||
if (!gdk_window_is_visible (window))
|
||||
{
|
||||
_gdk_wayland_window_set_grab_seat (window, NULL);
|
||||
gdk_wayland_seat_set_grab_window (wayland_seat, NULL);
|
||||
g_critical ("Window %p has not been made visible in GdkSeatGrabPrepareFunc",
|
||||
window);
|
||||
return GDK_GRAB_NOT_VIEWABLE;
|
||||
@@ -2685,7 +2701,7 @@ gdk_wayland_seat_grab (GdkSeat *seat,
|
||||
evtime,
|
||||
FALSE);
|
||||
|
||||
g_set_object (&wayland_seat->grab_cursor, cursor);
|
||||
gdk_wayland_seat_set_global_cursor (seat, cursor);
|
||||
g_set_object (&wayland_seat->cursor, cursor);
|
||||
gdk_wayland_device_update_window_cursor (wayland_seat);
|
||||
}
|
||||
@@ -2744,12 +2760,7 @@ gdk_wayland_seat_ungrab (GdkSeat *seat)
|
||||
|
||||
g_clear_object (&wayland_seat->grab_cursor);
|
||||
|
||||
if (wayland_seat->pointer_grab_window)
|
||||
{
|
||||
_gdk_wayland_window_set_grab_seat (wayland_seat->pointer_grab_window,
|
||||
NULL);
|
||||
wayland_seat->pointer_grab_window = NULL;
|
||||
}
|
||||
gdk_wayland_seat_set_grab_window (wayland_seat, NULL);
|
||||
|
||||
if (wayland_seat->master_pointer)
|
||||
{
|
||||
@@ -3066,6 +3077,21 @@ gdk_wayland_device_unset_touch_grab (GdkDevice *gdk_device,
|
||||
_gdk_wayland_display_deliver_event (device->display, event);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_seat_set_global_cursor (GdkSeat *seat,
|
||||
GdkCursor *cursor)
|
||||
{
|
||||
GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
|
||||
GdkDevice *pointer;
|
||||
|
||||
pointer = gdk_seat_get_pointer (seat);
|
||||
|
||||
g_set_object (&wayland_seat->grab_cursor, cursor);
|
||||
gdk_wayland_device_set_window_cursor (pointer,
|
||||
gdk_wayland_device_get_focus (pointer),
|
||||
NULL);
|
||||
}
|
||||
|
||||
struct wl_data_device *
|
||||
gdk_wayland_device_get_data_device (GdkDevice *gdk_device)
|
||||
{
|
||||
@@ -3090,61 +3116,6 @@ gdk_wayland_device_set_selection (GdkDevice *gdk_device,
|
||||
_gdk_wayland_display_get_serial (display_wayland));
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_device_unset_grab (GdkDevice *gdk_device)
|
||||
{
|
||||
GdkWaylandDeviceData *device;
|
||||
GdkEventSequence *sequence;
|
||||
GdkModifierType state;
|
||||
GdkEvent *event;
|
||||
guint button;
|
||||
gdouble x, y;
|
||||
|
||||
device = GDK_WAYLAND_DEVICE (gdk_device)->device;
|
||||
_gdk_wayland_device_get_last_implicit_grab_serial (GDK_WAYLAND_DEVICE (gdk_device), &sequence);
|
||||
gdk_window_get_device_position_double (device->pointer_grab_window,
|
||||
gdk_device, &x, &y, &state);
|
||||
|
||||
if (sequence)
|
||||
{
|
||||
event = gdk_event_new (GDK_TOUCH_END);
|
||||
event->touch.window = g_object_ref (device->pointer_grab_window);
|
||||
event->touch.send_event = TRUE;
|
||||
event->touch.sequence = sequence;
|
||||
event->touch.time = GDK_CURRENT_TIME;
|
||||
event->touch.x = event->touch.x_root = x;
|
||||
event->touch.y = event->touch.y_root = y;
|
||||
}
|
||||
else if (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))
|
||||
{
|
||||
if (state & GDK_BUTTON1_MASK)
|
||||
button = 1;
|
||||
else if (state & GDK_BUTTON2_MASK)
|
||||
button = 2;
|
||||
else if (state & GDK_BUTTON3_MASK)
|
||||
button = 3;
|
||||
else
|
||||
return;
|
||||
|
||||
event = gdk_event_new (GDK_BUTTON_RELEASE);
|
||||
event->button.window = g_object_ref (device->pointer_grab_window);
|
||||
event->button.send_event = TRUE;
|
||||
event->button.button = button;
|
||||
event->button.time = GDK_CURRENT_TIME;
|
||||
event->button.x = event->button.x_root = x;
|
||||
event->button.y = event->button.y_root = y;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
device->button_modifiers = 0;
|
||||
gdk_event_set_device (event, gdk_device);
|
||||
gdk_event_set_source_device (event, gdk_device);
|
||||
gdk_event_set_seat (event, gdk_device_get_seat (gdk_device));
|
||||
|
||||
_gdk_wayland_display_deliver_event (gdk_device_get_display (gdk_device), event);
|
||||
}
|
||||
|
||||
struct wl_seat *
|
||||
gdk_wayland_seat_get_wl_seat (GdkSeat *seat)
|
||||
{
|
||||
@@ -3152,3 +3123,11 @@ gdk_wayland_seat_get_wl_seat (GdkSeat *seat)
|
||||
|
||||
return GDK_WAYLAND_SEAT (seat)->wl_seat;
|
||||
}
|
||||
|
||||
GdkDragContext *
|
||||
gdk_wayland_device_get_drop_context (GdkDevice *device)
|
||||
{
|
||||
GdkSeat *seat = gdk_device_get_seat (device);
|
||||
|
||||
return GDK_WAYLAND_SEAT (seat)->drop_context;
|
||||
}
|
||||
|
@@ -315,7 +315,7 @@ gdk_registry_handle_global (void *data,
|
||||
else if (strcmp (interface, "wl_data_device_manager") == 0)
|
||||
{
|
||||
display_wayland->data_device_manager =
|
||||
wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface, 1);
|
||||
wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface, 3);
|
||||
}
|
||||
else if (strcmp (interface, "wl_subcompositor") == 0)
|
||||
{
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "gdkproperty.h"
|
||||
#include "gdkprivate-wayland.h"
|
||||
#include "gdkdisplay-wayland.h"
|
||||
#include "gdkseat-wayland.h"
|
||||
|
||||
#include "gdkdeviceprivate.h"
|
||||
|
||||
@@ -45,6 +46,7 @@ struct _GdkWaylandDragContext
|
||||
GdkWindow *dnd_window;
|
||||
struct wl_surface *dnd_surface;
|
||||
struct wl_data_source *data_source;
|
||||
GdkDragAction selected_action;
|
||||
uint32_t serial;
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
@@ -82,6 +84,8 @@ gdk_wayland_drag_context_finalize (GObject *object)
|
||||
selection_owner = gdk_selection_owner_get_for_display (display, selection);
|
||||
if (selection_owner == context->source_window)
|
||||
gdk_wayland_selection_unset_data_source (display, selection);
|
||||
|
||||
gdk_drag_context_set_cursor (context, NULL);
|
||||
}
|
||||
|
||||
if (wayland_context->data_source)
|
||||
@@ -157,6 +161,21 @@ gdk_wayland_drag_context_find_window (GdkDragContext *context,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
gdk_to_wl_actions (GdkDragAction action)
|
||||
{
|
||||
uint32_t dnd_actions = 0;
|
||||
|
||||
if (action & (GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_PRIVATE))
|
||||
dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
if (action & GDK_ACTION_MOVE)
|
||||
dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||||
if (action & GDK_ACTION_ASK)
|
||||
dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
|
||||
return dnd_actions;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_drag_context_set_action (GdkDragContext *context,
|
||||
GdkDragAction action)
|
||||
@@ -208,6 +227,9 @@ gdk_wayland_drop_context_set_status (GdkDragContext *context,
|
||||
GdkDisplay *display;
|
||||
struct wl_data_offer *wl_offer;
|
||||
|
||||
if (!context->dest_window)
|
||||
return;
|
||||
|
||||
context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
|
||||
|
||||
display = gdk_device_get_display (gdk_drag_context_get_device (context));
|
||||
@@ -240,12 +262,33 @@ gdk_wayland_drop_context_set_status (GdkDragContext *context,
|
||||
wl_data_offer_accept (wl_offer, context_wayland->serial, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_drag_context_commit_status (GdkDragContext *context)
|
||||
{
|
||||
GdkWaylandDragContext *wayland_context;
|
||||
GdkDisplay *display;
|
||||
uint32_t dnd_actions;
|
||||
|
||||
wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
|
||||
display = gdk_device_get_display (gdk_drag_context_get_device (context));
|
||||
|
||||
dnd_actions = gdk_to_wl_actions (wayland_context->selected_action);
|
||||
gdk_wayland_selection_set_current_offer_actions (display, dnd_actions);
|
||||
|
||||
gdk_wayland_drop_context_set_status (context, wayland_context->selected_action != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_drag_context_drag_status (GdkDragContext *context,
|
||||
GdkDragAction action,
|
||||
guint32 time_)
|
||||
{
|
||||
gdk_wayland_drop_context_set_status (context, action != 0);
|
||||
GdkWaylandDragContext *wayland_context;
|
||||
|
||||
wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
|
||||
wayland_context->selected_action = action;
|
||||
|
||||
gdk_wayland_drag_context_commit_status (context);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -263,12 +306,20 @@ gdk_wayland_drag_context_drop_finish (GdkDragContext *context,
|
||||
guint32 time)
|
||||
{
|
||||
GdkDisplay *display = gdk_device_get_display (gdk_drag_context_get_device (context));
|
||||
GdkWaylandDragContext *wayland_context;
|
||||
struct wl_data_offer *wl_offer;
|
||||
GdkAtom selection;
|
||||
|
||||
wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
|
||||
selection = gdk_drag_get_selection (context);
|
||||
wl_offer = gdk_wayland_selection_get_offer (display, selection);
|
||||
|
||||
if (gdk_selection_owner_get_for_display (display, selection))
|
||||
gdk_wayland_selection_unset_data_source (display, selection);
|
||||
if (success && wayland_context->selected_action &&
|
||||
wayland_context->selected_action != GDK_ACTION_ASK)
|
||||
{
|
||||
gdk_wayland_drag_context_commit_status (context);
|
||||
wl_data_offer_finish (wl_offer);
|
||||
}
|
||||
|
||||
gdk_wayland_selection_set_offer (display, selection, NULL);
|
||||
}
|
||||
@@ -325,6 +376,67 @@ gdk_wayland_drag_context_set_hotspot (GdkDragContext *context,
|
||||
gdk_window_invalidate_rect (context_wayland->dnd_window, &damage_rect, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_wayland_drag_context_manage_dnd (GdkDragContext *context,
|
||||
GdkWindow *ipc_window,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
GdkWaylandDragContext *context_wayland;
|
||||
GdkWaylandDisplay *display_wayland;
|
||||
GdkDevice *device;
|
||||
GdkWindow *toplevel;
|
||||
|
||||
device = gdk_drag_context_get_device (context);
|
||||
display_wayland = GDK_WAYLAND_DISPLAY (gdk_device_get_display (device));
|
||||
toplevel = _gdk_device_window_at_position (device, NULL, NULL, NULL, TRUE);
|
||||
|
||||
context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
|
||||
wl_data_source_set_actions (context_wayland->data_source,
|
||||
gdk_to_wl_actions (actions));
|
||||
|
||||
wl_data_device_start_drag (gdk_wayland_device_get_data_device (device),
|
||||
context_wayland->data_source,
|
||||
gdk_wayland_window_get_wl_surface (toplevel),
|
||||
context_wayland->dnd_surface,
|
||||
_gdk_wayland_display_get_serial (display_wayland));
|
||||
|
||||
gdk_seat_ungrab (gdk_device_get_seat (device));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_drag_context_set_cursor (GdkDragContext *context,
|
||||
GdkCursor *cursor)
|
||||
{
|
||||
GdkDevice *device = gdk_drag_context_get_device (context);
|
||||
|
||||
gdk_wayland_seat_set_global_cursor (gdk_device_get_seat (device), cursor);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_drag_context_action_changed (GdkDragContext *context,
|
||||
GdkDragAction action)
|
||||
{
|
||||
GdkCursor *cursor;
|
||||
|
||||
cursor = gdk_drag_get_cursor (action);
|
||||
gdk_drag_context_set_cursor (context, cursor);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_drag_context_drop_performed (GdkDragContext *context,
|
||||
guint32 time_)
|
||||
{
|
||||
gdk_drag_context_set_cursor (context, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_drag_context_cancel (GdkDragContext *context)
|
||||
{
|
||||
gdk_drag_context_set_cursor (context, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass)
|
||||
{
|
||||
@@ -344,6 +456,11 @@ gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass)
|
||||
context_class->get_selection = gdk_wayland_drag_context_get_selection;
|
||||
context_class->get_drag_window = gdk_wayland_drag_context_get_drag_window;
|
||||
context_class->set_hotspot = gdk_wayland_drag_context_set_hotspot;
|
||||
context_class->manage_dnd = gdk_wayland_drag_context_manage_dnd;
|
||||
context_class->set_cursor = gdk_wayland_drag_context_set_cursor;
|
||||
context_class->action_changed = gdk_wayland_drag_context_action_changed;
|
||||
context_class->drop_performed = gdk_wayland_drag_context_drop_performed;
|
||||
context_class->cancel = gdk_wayland_drag_context_cancel;
|
||||
}
|
||||
|
||||
GdkDragProtocol
|
||||
@@ -383,13 +500,9 @@ _gdk_wayland_window_drag_begin (GdkWindow *window,
|
||||
gint y_root)
|
||||
{
|
||||
GdkWaylandDragContext *context_wayland;
|
||||
GdkWaylandDisplay *display_wayland;
|
||||
GdkDragContext *context;
|
||||
GdkWindow *toplevel;
|
||||
GList *l;
|
||||
|
||||
toplevel = _gdk_device_window_at_position (device, NULL, NULL, NULL, TRUE);
|
||||
|
||||
context_wayland = g_object_new (GDK_TYPE_WAYLAND_DRAG_CONTEXT, NULL);
|
||||
context = GDK_DRAG_CONTEXT (context_wayland);
|
||||
context->source_window = g_object_ref (window);
|
||||
@@ -397,7 +510,6 @@ _gdk_wayland_window_drag_begin (GdkWindow *window,
|
||||
context->targets = g_list_copy (targets);
|
||||
|
||||
gdk_drag_context_set_device (context, device);
|
||||
display_wayland = GDK_WAYLAND_DISPLAY (gdk_device_get_display (device));
|
||||
|
||||
context_wayland->dnd_window = create_dnd_window (gdk_window_get_screen (window));
|
||||
context_wayland->dnd_surface = gdk_wayland_window_get_wl_surface (context_wayland->dnd_window);
|
||||
@@ -413,12 +525,6 @@ _gdk_wayland_window_drag_begin (GdkWindow *window,
|
||||
g_free (mimetype);
|
||||
}
|
||||
|
||||
wl_data_device_start_drag (gdk_wayland_device_get_data_device (device),
|
||||
context_wayland->data_source,
|
||||
gdk_wayland_window_get_wl_surface (toplevel),
|
||||
context_wayland->dnd_surface,
|
||||
_gdk_wayland_display_get_serial (display_wayland));
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@@ -188,7 +188,7 @@ struct wl_data_device * gdk_wayland_device_get_data_device (GdkDevice *gdk_devic
|
||||
void gdk_wayland_device_set_selection (GdkDevice *gdk_device,
|
||||
struct wl_data_source *source);
|
||||
|
||||
void gdk_wayland_device_unset_grab (GdkDevice *device);
|
||||
GdkDragContext * gdk_wayland_device_get_drop_context (GdkDevice *gdk_device);
|
||||
|
||||
void gdk_wayland_device_unset_touch_grab (GdkDevice *device,
|
||||
GdkEventSequence *sequence);
|
||||
@@ -258,10 +258,15 @@ void gdk_wayland_selection_store (GdkWindow *window,
|
||||
struct wl_data_source * gdk_wayland_selection_get_data_source (GdkWindow *owner,
|
||||
GdkAtom selection);
|
||||
void gdk_wayland_selection_unset_data_source (GdkDisplay *display, GdkAtom selection);
|
||||
gboolean gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
|
||||
uint32_t actions);
|
||||
|
||||
EGLSurface gdk_wayland_window_get_egl_surface (GdkWindow *window,
|
||||
EGLConfig config);
|
||||
EGLSurface gdk_wayland_window_get_dummy_egl_surface (GdkWindow *window,
|
||||
EGLConfig config);
|
||||
|
||||
void gdk_wayland_seat_set_global_cursor (GdkSeat *seat,
|
||||
GdkCursor *cursor);
|
||||
|
||||
#endif /* __GDK_PRIVATE_WAYLAND_H__ */
|
||||
|
@@ -350,8 +350,69 @@ data_offer_offer (void *data,
|
||||
info->targets = g_list_prepend (info->targets, atom);
|
||||
}
|
||||
|
||||
static inline GdkDragAction
|
||||
_wl_to_gdk_actions (uint32_t dnd_actions)
|
||||
{
|
||||
GdkDragAction actions = 0;
|
||||
|
||||
if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
||||
actions |= GDK_ACTION_COPY;
|
||||
if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
||||
actions |= GDK_ACTION_MOVE;
|
||||
if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
|
||||
actions |= GDK_ACTION_ASK;
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
static void
|
||||
data_offer_source_actions (void *data,
|
||||
struct wl_data_offer *wl_data_offer,
|
||||
uint32_t source_actions)
|
||||
{
|
||||
GdkDragContext *drop_context;
|
||||
GdkDisplay *display;
|
||||
GdkDevice *device;
|
||||
GdkSeat *seat;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
seat = gdk_display_get_default_seat (display);
|
||||
device = gdk_seat_get_pointer (seat);
|
||||
drop_context = gdk_wayland_device_get_drop_context (device);
|
||||
|
||||
drop_context->actions = _wl_to_gdk_actions (source_actions);
|
||||
|
||||
if (gdk_drag_context_get_dest_window (drop_context))
|
||||
_gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
static void
|
||||
data_offer_action (void *data,
|
||||
struct wl_data_offer *wl_data_offer,
|
||||
uint32_t action)
|
||||
{
|
||||
GdkDragContext *drop_context;
|
||||
GdkDisplay *display;
|
||||
GdkDevice *device;
|
||||
GdkSeat *seat;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
seat = gdk_display_get_default_seat (display);
|
||||
device = gdk_seat_get_pointer (seat);
|
||||
drop_context = gdk_wayland_device_get_drop_context (device);
|
||||
|
||||
drop_context->action = _wl_to_gdk_actions (action);
|
||||
|
||||
if (gdk_drag_context_get_dest_window (drop_context))
|
||||
_gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_listener data_offer_listener = {
|
||||
data_offer_offer,
|
||||
data_offer_source_actions,
|
||||
data_offer_action
|
||||
};
|
||||
|
||||
DataOfferData *
|
||||
@@ -569,6 +630,9 @@ gdk_wayland_selection_store (GdkWindow *window,
|
||||
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
|
||||
GArray *array;
|
||||
|
||||
if (type == gdk_atom_intern_static_string ("NULL"))
|
||||
return;
|
||||
|
||||
array = g_array_new (TRUE, FALSE, sizeof (guchar));
|
||||
g_array_append_vals (array, data, len);
|
||||
|
||||
@@ -701,32 +765,16 @@ data_source_target (void *data,
|
||||
const char *mime_type)
|
||||
{
|
||||
GdkWaylandSelection *wayland_selection = data;
|
||||
GdkDragContext *context = NULL;
|
||||
GdkWindow *window = NULL;
|
||||
|
||||
g_debug (G_STRLOC ": %s source = %p, mime_type = %s",
|
||||
G_STRFUNC, source, mime_type);
|
||||
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (!mime_type)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
gdk_wayland_drag_context_set_action (context, 0);
|
||||
_gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
if (source == wayland_selection->dnd_source)
|
||||
{
|
||||
window = wayland_selection->dnd_owner;
|
||||
gdk_wayland_drag_context_set_action (context, GDK_ACTION_COPY);
|
||||
_gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
window = wayland_selection->dnd_owner;
|
||||
else if (source == wayland_selection->clipboard_source)
|
||||
window = wayland_selection->clipboard_owner;
|
||||
|
||||
@@ -745,7 +793,6 @@ data_source_send (void *data,
|
||||
int32_t fd)
|
||||
{
|
||||
GdkWaylandSelection *wayland_selection = data;
|
||||
GdkDragContext *context;
|
||||
GdkWindow *window;
|
||||
|
||||
g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d",
|
||||
@@ -757,8 +804,6 @@ data_source_send (void *data,
|
||||
return;
|
||||
}
|
||||
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (source == wayland_selection->dnd_source)
|
||||
window = wayland_selection->dnd_owner;
|
||||
else if (source == wayland_selection->clipboard_source)
|
||||
@@ -776,13 +821,6 @@ data_source_send (void *data,
|
||||
gdk_atom_intern (mime_type, FALSE),
|
||||
fd))
|
||||
gdk_wayland_selection_check_write (wayland_selection);
|
||||
|
||||
if (context)
|
||||
{
|
||||
_gdk_wayland_drag_context_emit_event (context, GDK_DROP_FINISHED,
|
||||
GDK_CURRENT_TIME);
|
||||
gdk_wayland_device_unset_grab (gdk_drag_context_get_device (context));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -806,22 +844,79 @@ data_source_cancelled (void *data,
|
||||
else
|
||||
return;
|
||||
|
||||
gdk_wayland_selection_unset_data_source (display, atom);
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (context)
|
||||
gdk_drag_context_cancel (context);
|
||||
|
||||
gdk_selection_owner_set (NULL, atom, GDK_CURRENT_TIME, TRUE);
|
||||
gdk_wayland_selection_unset_data_source (display, atom);
|
||||
}
|
||||
|
||||
if (source == wayland_selection->dnd_source)
|
||||
static void
|
||||
data_source_dnd_drop_performed (void *data,
|
||||
struct wl_data_source *source)
|
||||
{
|
||||
GdkDragContext *context;
|
||||
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
g_signal_emit_by_name (context, "drop-performed", GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_dnd_finished (void *data,
|
||||
struct wl_data_source *source)
|
||||
{
|
||||
GdkDisplay *display = gdk_display_get_default ();
|
||||
GdkDragContext *context;
|
||||
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (context->action == GDK_ACTION_MOVE)
|
||||
{
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (context)
|
||||
gdk_wayland_device_unset_grab (gdk_drag_context_get_device (context));
|
||||
gdk_wayland_selection_emit_request (context->source_window,
|
||||
atoms[ATOM_DND],
|
||||
gdk_atom_intern_static_string ("DELETE"));
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (context, "dnd-finished");
|
||||
gdk_selection_owner_set (NULL, atoms[ATOM_DND], GDK_CURRENT_TIME, TRUE);
|
||||
gdk_wayland_selection_unset_data_source (display, atoms[ATOM_DND]);
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_action (void *data,
|
||||
struct wl_data_source *source,
|
||||
uint32_t action)
|
||||
{
|
||||
GdkDragContext *context;
|
||||
|
||||
g_debug (G_STRLOC ": %s source = %p action=%x",
|
||||
G_STRFUNC, source, action);
|
||||
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->action = _wl_to_gdk_actions (action);
|
||||
g_signal_emit_by_name (context, "action-changed", context->action);
|
||||
}
|
||||
|
||||
static const struct wl_data_source_listener data_source_listener = {
|
||||
data_source_target,
|
||||
data_source_send,
|
||||
data_source_cancelled
|
||||
data_source_cancelled,
|
||||
data_source_dnd_drop_performed,
|
||||
data_source_dnd_finished,
|
||||
data_source_action,
|
||||
};
|
||||
|
||||
struct wl_data_source *
|
||||
@@ -1009,7 +1104,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
|
||||
offer = gdk_wayland_selection_get_offer (display, selection);
|
||||
target_list = gdk_wayland_selection_get_targets (display, selection);
|
||||
|
||||
if (!offer)
|
||||
if (!offer || target == gdk_atom_intern_static_string ("DELETE"))
|
||||
{
|
||||
GdkEvent *event;
|
||||
|
||||
@@ -1185,3 +1280,24 @@ gdk_wayland_selection_clear_targets (GdkDisplay *display,
|
||||
g_array_set_size (wayland_selection->source_targets, 0);
|
||||
gdk_wayland_selection_unset_data_source (display, selection);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
|
||||
uint32_t action)
|
||||
{
|
||||
struct wl_data_offer *offer;
|
||||
uint32_t all_actions = 0;
|
||||
|
||||
offer = gdk_wayland_selection_get_offer (display, atoms[ATOM_DND]);
|
||||
|
||||
if (!offer)
|
||||
return FALSE;
|
||||
|
||||
if (action != 0)
|
||||
all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
|
||||
wl_data_offer_set_actions (offer, all_actions, action);
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -89,6 +89,12 @@ struct _GdkX11DragContext
|
||||
|
||||
GdkWindow *drag_window;
|
||||
|
||||
GdkWindow *ipc_window;
|
||||
GdkCursor *cursor;
|
||||
GdkSeat *grab_seat;
|
||||
GdkDragAction actions;
|
||||
GdkDragAction current_action;
|
||||
|
||||
gint hot_x;
|
||||
gint hot_y;
|
||||
|
||||
@@ -106,6 +112,35 @@ struct _GdkX11DragContextClass
|
||||
GdkDragContextClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
gint keysym;
|
||||
gint modifiers;
|
||||
} GrabKey;
|
||||
|
||||
static GrabKey grab_keys[] = {
|
||||
{ XK_Escape, 0 },
|
||||
{ XK_space, 0 },
|
||||
{ XK_KP_Space, 0 },
|
||||
{ XK_Return, 0 },
|
||||
{ XK_KP_Enter, 0 },
|
||||
{ XK_Up, 0 },
|
||||
{ XK_Up, Mod1Mask },
|
||||
{ XK_Down, 0 },
|
||||
{ XK_Down, Mod1Mask },
|
||||
{ XK_Left, 0 },
|
||||
{ XK_Left, Mod1Mask },
|
||||
{ XK_Right, 0 },
|
||||
{ XK_Right, Mod1Mask },
|
||||
{ XK_KP_Up, 0 },
|
||||
{ XK_KP_Up, Mod1Mask },
|
||||
{ XK_KP_Down, 0 },
|
||||
{ XK_KP_Down, Mod1Mask },
|
||||
{ XK_KP_Left, 0 },
|
||||
{ XK_KP_Left, Mod1Mask },
|
||||
{ XK_KP_Right, 0 },
|
||||
{ XK_KP_Right, Mod1Mask }
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
|
||||
static GdkWindowCache *gdk_window_cache_get (GdkScreen *screen);
|
||||
@@ -135,6 +170,11 @@ static void xdnd_manage_source_filter (GdkDragContext *context,
|
||||
GdkWindow *window,
|
||||
gboolean add_filter);
|
||||
|
||||
gboolean gdk_x11_drag_context_handle_event (GdkDragContext *context,
|
||||
const GdkEvent *event);
|
||||
void gdk_x11_drag_context_action_changed (GdkDragContext *context,
|
||||
GdkDragAction action);
|
||||
|
||||
static GList *contexts;
|
||||
static GSList *window_caches;
|
||||
|
||||
@@ -195,6 +235,14 @@ static void gdk_x11_drag_context_set_hotspot (GdkDragContext *context,
|
||||
gint hot_y);
|
||||
static void gdk_x11_drag_context_drop_done (GdkDragContext *context,
|
||||
gboolean success);
|
||||
static gboolean gdk_x11_drag_context_manage_dnd (GdkDragContext *context,
|
||||
GdkWindow *window,
|
||||
GdkDragAction actions);
|
||||
static void gdk_x11_drag_context_set_cursor (GdkDragContext *context,
|
||||
GdkCursor *cursor);
|
||||
static void gdk_x11_drag_context_cancel (GdkDragContext *context);
|
||||
static void gdk_x11_drag_context_drop_performed (GdkDragContext *context,
|
||||
guint32 time);
|
||||
|
||||
static void
|
||||
gdk_x11_drag_context_class_init (GdkX11DragContextClass *klass)
|
||||
@@ -216,6 +264,12 @@ gdk_x11_drag_context_class_init (GdkX11DragContextClass *klass)
|
||||
context_class->get_drag_window = gdk_x11_drag_context_get_drag_window;
|
||||
context_class->set_hotspot = gdk_x11_drag_context_set_hotspot;
|
||||
context_class->drop_done = gdk_x11_drag_context_drop_done;
|
||||
context_class->manage_dnd = gdk_x11_drag_context_manage_dnd;
|
||||
context_class->set_cursor = gdk_x11_drag_context_set_cursor;
|
||||
context_class->cancel = gdk_x11_drag_context_cancel;
|
||||
context_class->drop_performed = gdk_x11_drag_context_drop_performed;
|
||||
context_class->handle_event = gdk_x11_drag_context_handle_event;
|
||||
context_class->action_changed = gdk_x11_drag_context_action_changed;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2592,3 +2646,489 @@ gdk_x11_drag_context_drop_done (GdkDragContext *context,
|
||||
gdk_drag_anim_timeout, anim,
|
||||
(GDestroyNotify) gdk_drag_anim_destroy);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_context_grab (GdkDragContext *context)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
GdkDevice *device = gdk_drag_context_get_device (context);
|
||||
GdkWindow *root;
|
||||
GdkSeat *seat;
|
||||
gint keycode, i;
|
||||
|
||||
if (!x11_context->ipc_window)
|
||||
return FALSE;
|
||||
|
||||
root = gdk_screen_get_root_window (gdk_window_get_screen (x11_context->ipc_window));
|
||||
seat = gdk_device_get_seat (gdk_drag_context_get_device (context));
|
||||
|
||||
if (gdk_seat_grab (seat, x11_context->ipc_window,
|
||||
GDK_SEAT_CAPABILITY_ALL, FALSE,
|
||||
x11_context->cursor, NULL, NULL, NULL) != GDK_GRAB_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
g_set_object (&x11_context->grab_seat, seat);
|
||||
|
||||
gdk_error_trap_push ();
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (grab_keys); ++i)
|
||||
{
|
||||
keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (x11_context->ipc_window),
|
||||
grab_keys[i].keysym);
|
||||
if (keycode == NoSymbol)
|
||||
continue;
|
||||
|
||||
#ifdef XINPUT_2
|
||||
if (GDK_IS_X11_DEVICE_XI2 (device))
|
||||
{
|
||||
gint deviceid = gdk_x11_device_get_id (gdk_seat_get_keyboard (seat));
|
||||
unsigned char mask[XIMaskLen(XI_LASTEVENT)];
|
||||
XIGrabModifiers mods;
|
||||
XIEventMask evmask;
|
||||
gint num_mods;
|
||||
|
||||
memset (mask, 0, sizeof (mask));
|
||||
XISetMask (mask, XI_KeyPress);
|
||||
XISetMask (mask, XI_KeyRelease);
|
||||
|
||||
evmask.deviceid = deviceid;
|
||||
evmask.mask_len = sizeof (mask);
|
||||
evmask.mask = mask;
|
||||
|
||||
num_mods = 1;
|
||||
mods.modifiers = grab_keys[i].modifiers;
|
||||
|
||||
XIGrabKeycode (GDK_WINDOW_XDISPLAY (x11_context->ipc_window),
|
||||
deviceid,
|
||||
keycode,
|
||||
GDK_WINDOW_XID (root),
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
False,
|
||||
&evmask,
|
||||
num_mods,
|
||||
&mods);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
XGrabKey (GDK_WINDOW_XDISPLAY (x11_context->ipc_window),
|
||||
keycode, grab_keys[i].modifiers,
|
||||
GDK_WINDOW_XID (root),
|
||||
FALSE,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_context_ungrab (GdkDragContext *context)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
GdkDevice *keyboard;
|
||||
GdkWindow *root;
|
||||
gint keycode, i;
|
||||
|
||||
if (!x11_context->grab_seat)
|
||||
return;
|
||||
|
||||
gdk_seat_ungrab (x11_context->grab_seat);
|
||||
|
||||
keyboard = gdk_seat_get_keyboard (x11_context->grab_seat);
|
||||
root = gdk_screen_get_root_window (gdk_window_get_screen (x11_context->ipc_window));
|
||||
g_clear_object (&x11_context->grab_seat);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (grab_keys); ++i)
|
||||
{
|
||||
keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (x11_context->ipc_window),
|
||||
grab_keys[i].keysym);
|
||||
if (keycode == NoSymbol)
|
||||
continue;
|
||||
|
||||
#ifdef XINPUT_2
|
||||
if (GDK_IS_X11_DEVICE_XI2 (keyboard))
|
||||
{
|
||||
XIGrabModifiers mods;
|
||||
gint num_mods;
|
||||
|
||||
num_mods = 1;
|
||||
mods.modifiers = grab_keys[i].modifiers;
|
||||
|
||||
XIUngrabKeycode (GDK_WINDOW_XDISPLAY (x11_context->ipc_window),
|
||||
gdk_x11_device_get_id (keyboard),
|
||||
keycode,
|
||||
GDK_WINDOW_XID (root),
|
||||
num_mods,
|
||||
&mods);
|
||||
}
|
||||
else
|
||||
#endif /* XINPUT_2 */
|
||||
{
|
||||
XUngrabKey (GDK_WINDOW_XDISPLAY (x11_context->ipc_window),
|
||||
keycode, grab_keys[i].modifiers,
|
||||
GDK_WINDOW_XID (root));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_x11_drag_context_manage_dnd (GdkDragContext *context,
|
||||
GdkWindow *ipc_window,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
|
||||
if (x11_context->ipc_window)
|
||||
return FALSE;
|
||||
|
||||
context->protocol = GDK_DRAG_PROTO_XDND;
|
||||
x11_context->ipc_window = g_object_ref (ipc_window);
|
||||
|
||||
if (drag_context_grab (context))
|
||||
{
|
||||
x11_context->actions = actions;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_object (&x11_context->ipc_window);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_drag_context_set_cursor (GdkDragContext *context,
|
||||
GdkCursor *cursor)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
|
||||
if (!g_set_object (&x11_context->cursor, cursor))
|
||||
return;
|
||||
|
||||
if (x11_context->grab_seat)
|
||||
{
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
|
||||
gdk_device_grab (gdk_seat_get_pointer (x11_context->grab_seat),
|
||||
x11_context->ipc_window,
|
||||
GDK_OWNERSHIP_APPLICATION, FALSE,
|
||||
GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
|
||||
cursor, GDK_CURRENT_TIME);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_drag_context_cancel (GdkDragContext *context)
|
||||
{
|
||||
drag_context_ungrab (context);
|
||||
gdk_drag_drop_done (context, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_drag_context_drop_performed (GdkDragContext *context,
|
||||
guint32 time_)
|
||||
{
|
||||
drag_context_ungrab (context);
|
||||
}
|
||||
|
||||
#define BIG_STEP 20
|
||||
#define SMALL_STEP 1
|
||||
|
||||
static void
|
||||
gdk_drag_get_current_actions (GdkModifierType state,
|
||||
gint button,
|
||||
GdkDragAction actions,
|
||||
GdkDragAction *suggested_action,
|
||||
GdkDragAction *possible_actions)
|
||||
{
|
||||
*suggested_action = 0;
|
||||
*possible_actions = 0;
|
||||
|
||||
if ((button == GDK_BUTTON_MIDDLE || button == GDK_BUTTON_SECONDARY) && (actions & GDK_ACTION_ASK))
|
||||
{
|
||||
*suggested_action = GDK_ACTION_ASK;
|
||||
*possible_actions = actions;
|
||||
}
|
||||
else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
|
||||
{
|
||||
if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
|
||||
{
|
||||
if (actions & GDK_ACTION_LINK)
|
||||
{
|
||||
*suggested_action = GDK_ACTION_LINK;
|
||||
*possible_actions = GDK_ACTION_LINK;
|
||||
}
|
||||
}
|
||||
else if (state & GDK_CONTROL_MASK)
|
||||
{
|
||||
if (actions & GDK_ACTION_COPY)
|
||||
{
|
||||
*suggested_action = GDK_ACTION_COPY;
|
||||
*possible_actions = GDK_ACTION_COPY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actions & GDK_ACTION_MOVE)
|
||||
{
|
||||
*suggested_action = GDK_ACTION_MOVE;
|
||||
*possible_actions = GDK_ACTION_MOVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*possible_actions = actions;
|
||||
|
||||
if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
|
||||
*suggested_action = GDK_ACTION_ASK;
|
||||
else if (actions & GDK_ACTION_COPY)
|
||||
*suggested_action = GDK_ACTION_COPY;
|
||||
else if (actions & GDK_ACTION_MOVE)
|
||||
*suggested_action = GDK_ACTION_MOVE;
|
||||
else if (actions & GDK_ACTION_LINK)
|
||||
*suggested_action = GDK_ACTION_LINK;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_drag_update (GdkDragContext *context,
|
||||
gdouble x_root,
|
||||
gdouble y_root,
|
||||
GdkModifierType mods,
|
||||
guint32 evtime)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
GdkDragAction action, possible_actions;
|
||||
GdkWindow *dest_window;
|
||||
GdkDragProtocol protocol;
|
||||
|
||||
gdk_drag_get_current_actions (mods, GDK_BUTTON_PRIMARY, x11_context->actions,
|
||||
&action, &possible_actions);
|
||||
|
||||
gdk_drag_find_window_for_screen (context,
|
||||
x11_context->drag_window,
|
||||
gdk_display_get_default_screen (gdk_display_get_default ()),
|
||||
x_root, y_root, &dest_window, &protocol);
|
||||
|
||||
gdk_drag_motion (context, dest_window, protocol, x_root, y_root,
|
||||
action, possible_actions, evtime);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_dnd_handle_motion_event (GdkDragContext *context,
|
||||
const GdkEventMotion *event)
|
||||
{
|
||||
GdkModifierType state;
|
||||
|
||||
if (!gdk_event_get_state ((GdkEvent *) event, &state))
|
||||
return FALSE;
|
||||
|
||||
gdk_drag_update (context, event->x_root, event->y_root, state,
|
||||
gdk_event_get_time ((GdkEvent *) event));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_dnd_handle_key_event (GdkDragContext *context,
|
||||
const GdkEventKey *event)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
GdkModifierType state;
|
||||
GdkWindow *root_window;
|
||||
GdkDevice *pointer;
|
||||
gint dx, dy;
|
||||
|
||||
dx = dy = 0;
|
||||
state = event->state;
|
||||
pointer = gdk_device_get_associated_device (gdk_event_get_device ((GdkEvent *) event));
|
||||
|
||||
if (event->type == GDK_KEY_PRESS)
|
||||
{
|
||||
switch (event->keyval)
|
||||
{
|
||||
case GDK_KEY_Escape:
|
||||
gdk_drag_context_cancel (context);
|
||||
return TRUE;
|
||||
|
||||
case GDK_KEY_space:
|
||||
case GDK_KEY_Return:
|
||||
case GDK_KEY_ISO_Enter:
|
||||
case GDK_KEY_KP_Enter:
|
||||
case GDK_KEY_KP_Space:
|
||||
if ((gdk_drag_context_get_selected_action (context) != 0) &&
|
||||
(gdk_drag_context_get_dest_window (context) != NULL))
|
||||
{
|
||||
g_signal_emit_by_name (context, "drop-performed",
|
||||
gdk_event_get_time ((GdkEvent *) event));
|
||||
}
|
||||
else
|
||||
gdk_drag_context_cancel (context);
|
||||
|
||||
return TRUE;
|
||||
|
||||
case GDK_KEY_Up:
|
||||
case GDK_KEY_KP_Up:
|
||||
dy = (state & GDK_MOD1_MASK) ? -BIG_STEP : -SMALL_STEP;
|
||||
break;
|
||||
|
||||
case GDK_KEY_Down:
|
||||
case GDK_KEY_KP_Down:
|
||||
dy = (state & GDK_MOD1_MASK) ? BIG_STEP : SMALL_STEP;
|
||||
break;
|
||||
|
||||
case GDK_KEY_Left:
|
||||
case GDK_KEY_KP_Left:
|
||||
dx = (state & GDK_MOD1_MASK) ? -BIG_STEP : -SMALL_STEP;
|
||||
break;
|
||||
|
||||
case GDK_KEY_Right:
|
||||
case GDK_KEY_KP_Right:
|
||||
dx = (state & GDK_MOD1_MASK) ? BIG_STEP : SMALL_STEP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The state is not yet updated in the event, so we need
|
||||
* to query it here. We could use XGetModifierMapping, but
|
||||
* that would be overkill.
|
||||
*/
|
||||
root_window = gdk_screen_get_root_window (gdk_window_get_screen (x11_context->ipc_window));
|
||||
gdk_window_get_device_position (root_window, pointer, NULL, NULL, &state);
|
||||
|
||||
if (dx != 0 || dy != 0)
|
||||
{
|
||||
x11_context->last_x += dx;
|
||||
x11_context->last_y += dy;
|
||||
gdk_device_warp (pointer,
|
||||
gdk_window_get_screen (x11_context->ipc_window),
|
||||
x11_context->last_x, x11_context->last_y);
|
||||
}
|
||||
|
||||
gdk_drag_update (context, x11_context->last_x, x11_context->last_y, state,
|
||||
gdk_event_get_time ((GdkEvent *) event));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_dnd_handle_grab_broken_event (GdkDragContext *context,
|
||||
const GdkEventGrabBroken *event)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
|
||||
/* Don't cancel if we break the implicit grab from the initial button_press.
|
||||
* Also, don't cancel if we re-grab on the widget or on our IPC window, for
|
||||
* example, when changing the drag cursor.
|
||||
*/
|
||||
if (event->implicit ||
|
||||
event->grab_window == x11_context->drag_window ||
|
||||
event->grab_window == x11_context->ipc_window)
|
||||
return FALSE;
|
||||
|
||||
gdk_drag_context_cancel (context);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_dnd_handle_button_event (GdkDragContext *context,
|
||||
const GdkEventButton *event)
|
||||
{
|
||||
#if 0
|
||||
/* FIXME: Check the button matches */
|
||||
if (event->button != x11_context->button)
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
if ((gdk_drag_context_get_selected_action (context) != 0) &&
|
||||
(gdk_drag_context_get_dest_window (context) != NULL))
|
||||
{
|
||||
g_signal_emit_by_name (context, "drop-performed",
|
||||
gdk_event_get_time ((GdkEvent *) event));
|
||||
}
|
||||
else
|
||||
gdk_drag_context_cancel (context);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_dnd_handle_drag_status (GdkDragContext *context,
|
||||
const GdkEventDND *event)
|
||||
{
|
||||
GdkX11DragContext *context_x11 = GDK_X11_DRAG_CONTEXT (context);
|
||||
GdkDragAction action;
|
||||
|
||||
if (context != event->context)
|
||||
return FALSE;
|
||||
|
||||
action = gdk_drag_context_get_selected_action (context);
|
||||
|
||||
if (action != context_x11->current_action)
|
||||
{
|
||||
context_x11->current_action = action;
|
||||
g_signal_emit_by_name (context, "action-changed", action);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_dnd_handle_drop_finished (GdkDragContext *context,
|
||||
const GdkEventDND *event)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
|
||||
if (context != event->context)
|
||||
return FALSE;
|
||||
|
||||
g_signal_emit_by_name (context, "dnd-finished");
|
||||
gdk_drag_drop_done (context, !x11_context->drop_failed);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_x11_drag_context_handle_event (GdkDragContext *context,
|
||||
const GdkEvent *event)
|
||||
{
|
||||
GdkX11DragContext *x11_context = GDK_X11_DRAG_CONTEXT (context);
|
||||
|
||||
if (!context->is_source)
|
||||
return FALSE;
|
||||
if (!x11_context->grab_seat && event->type != GDK_DROP_FINISHED)
|
||||
return FALSE;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
return gdk_dnd_handle_motion_event (context, &event->motion);
|
||||
case GDK_BUTTON_RELEASE:
|
||||
return gdk_dnd_handle_button_event (context, &event->button);
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
return gdk_dnd_handle_key_event (context, &event->key);
|
||||
case GDK_GRAB_BROKEN:
|
||||
return gdk_dnd_handle_grab_broken_event (context, &event->grab_broken);
|
||||
case GDK_DRAG_STATUS:
|
||||
return gdk_dnd_handle_drag_status (context, &event->dnd);
|
||||
case GDK_DROP_FINISHED:
|
||||
return gdk_dnd_handle_drop_finished (context, &event->dnd);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_x11_drag_context_action_changed (GdkDragContext *context,
|
||||
GdkDragAction action)
|
||||
{
|
||||
GdkCursor *cursor;
|
||||
|
||||
cursor = gdk_drag_get_cursor (action);
|
||||
gdk_drag_context_set_cursor (context, cursor);
|
||||
}
|
||||
|
191
gtk/gtkdnd.c
191
gtk/gtkdnd.c
@@ -42,6 +42,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#endif
|
||||
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgesturesingle.h"
|
||||
#include "gtkicontheme.h"
|
||||
@@ -55,6 +59,7 @@
|
||||
#include "gtkselectionprivate.h"
|
||||
#include "gtkwindowgroup.h"
|
||||
#include "gtkwindowprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
|
||||
/**
|
||||
@@ -234,6 +239,17 @@ static void gtk_drag_selection_get (GtkWidget *widget,
|
||||
gpointer data);
|
||||
static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
|
||||
static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info);
|
||||
|
||||
static void gtk_drag_context_drop_performed_cb (GdkDragContext *context,
|
||||
guint time,
|
||||
GtkDragSourceInfo *info);
|
||||
static void gtk_drag_context_cancel_cb (GdkDragContext *context,
|
||||
GtkDragSourceInfo *info);
|
||||
static void gtk_drag_context_action_cb (GdkDragContext *context,
|
||||
GdkDragAction action,
|
||||
GtkDragSourceInfo *info);
|
||||
static void gtk_drag_context_dnd_finished_cb (GdkDragContext *context,
|
||||
GtkDragSourceInfo *info);
|
||||
static void gtk_drag_add_update_idle (GtkDragSourceInfo *info);
|
||||
|
||||
static void gtk_drag_update (GtkDragSourceInfo *info,
|
||||
@@ -2159,6 +2175,17 @@ gtk_drag_begin_internal (GtkWidget *widget,
|
||||
GdkDevice *pointer, *keyboard;
|
||||
GdkWindow *ipc_window;
|
||||
gint start_x, start_y;
|
||||
GdkAtom selection;
|
||||
gboolean managed = FALSE;
|
||||
|
||||
managed =
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
GDK_IS_X11_DISPLAY (gtk_widget_get_display (widget)) ||
|
||||
#endif
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)) ||
|
||||
#endif
|
||||
FALSE;
|
||||
|
||||
pointer = keyboard = NULL;
|
||||
ipc_widget = gtk_drag_get_ipc_widget (widget);
|
||||
@@ -2201,24 +2228,27 @@ gtk_drag_begin_internal (GtkWidget *widget,
|
||||
|
||||
ipc_window = gtk_widget_get_window (ipc_widget);
|
||||
|
||||
if (gdk_device_grab (pointer, ipc_window,
|
||||
GDK_OWNERSHIP_APPLICATION, FALSE,
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK,
|
||||
cursor, time) != GDK_GRAB_SUCCESS)
|
||||
if (!managed)
|
||||
{
|
||||
gtk_drag_release_ipc_widget (ipc_widget);
|
||||
return NULL;
|
||||
if (gdk_device_grab (pointer, ipc_window,
|
||||
GDK_OWNERSHIP_APPLICATION, FALSE,
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK,
|
||||
cursor, time) != GDK_GRAB_SUCCESS)
|
||||
{
|
||||
gtk_drag_release_ipc_widget (ipc_widget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (keyboard)
|
||||
grab_dnd_keys (ipc_widget, keyboard, time);
|
||||
|
||||
/* We use a GTK grab here to override any grabs that the widget
|
||||
* we are dragging from might have held
|
||||
*/
|
||||
gtk_device_grab_add (ipc_widget, pointer, FALSE);
|
||||
}
|
||||
|
||||
if (keyboard)
|
||||
grab_dnd_keys (ipc_widget, keyboard, time);
|
||||
|
||||
/* We use a GTK grab here to override any grabs that the widget
|
||||
* we are dragging from might have held
|
||||
*/
|
||||
gtk_device_grab_add (ipc_widget, pointer, FALSE);
|
||||
|
||||
tmp_list = g_list_last (target_list->list);
|
||||
while (tmp_list)
|
||||
{
|
||||
@@ -2250,6 +2280,14 @@ gtk_drag_begin_internal (GtkWidget *widget,
|
||||
|
||||
gdk_drag_context_set_device (context, pointer);
|
||||
g_list_free (targets);
|
||||
|
||||
if (managed &&
|
||||
!gdk_drag_context_manage_dnd (context, ipc_window, actions))
|
||||
{
|
||||
gtk_drag_release_ipc_widget (ipc_widget);
|
||||
g_object_unref (context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = gtk_drag_get_source_info (context, TRUE);
|
||||
|
||||
@@ -2280,6 +2318,8 @@ gtk_drag_begin_internal (GtkWidget *widget,
|
||||
info->start_x = start_x;
|
||||
info->start_y = start_y;
|
||||
|
||||
gtk_widget_reset_controllers (widget);
|
||||
|
||||
g_signal_emit_by_name (widget, "drag-begin", info->context);
|
||||
|
||||
/* Ensure that we have an icon before we start the drag; the
|
||||
@@ -2300,26 +2340,45 @@ gtk_drag_begin_internal (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
info->cur_x = info->start_x;
|
||||
info->cur_y = info->start_y;
|
||||
if (managed)
|
||||
{
|
||||
g_signal_connect (context, "drop-performed",
|
||||
G_CALLBACK (gtk_drag_context_drop_performed_cb), info);
|
||||
g_signal_connect (context, "dnd-finished",
|
||||
G_CALLBACK (gtk_drag_context_dnd_finished_cb), info);
|
||||
g_signal_connect (context, "cancel",
|
||||
G_CALLBACK (gtk_drag_context_cancel_cb), info);
|
||||
g_signal_connect (context, "action-changed",
|
||||
G_CALLBACK (gtk_drag_context_action_cb), info);
|
||||
|
||||
if (event && event->type == GDK_MOTION_NOTIFY)
|
||||
gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
|
||||
selection = gdk_drag_get_selection (context);
|
||||
if (selection)
|
||||
gtk_drag_source_check_selection (info, selection, time);
|
||||
}
|
||||
else
|
||||
gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, event);
|
||||
{
|
||||
info->cur_x = info->start_x;
|
||||
info->cur_y = info->start_y;
|
||||
|
||||
if (event && event->type == GDK_MOTION_NOTIFY)
|
||||
gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
|
||||
else
|
||||
gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, event);
|
||||
|
||||
g_signal_connect (info->ipc_widget, "grab-broken-event",
|
||||
G_CALLBACK (gtk_drag_grab_broken_event_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "grab-notify",
|
||||
G_CALLBACK (gtk_drag_grab_notify_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "button-release-event",
|
||||
G_CALLBACK (gtk_drag_button_release_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "motion-notify-event",
|
||||
G_CALLBACK (gtk_drag_motion_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "key-press-event",
|
||||
G_CALLBACK (gtk_drag_key_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "key-release-event",
|
||||
G_CALLBACK (gtk_drag_key_cb), info);
|
||||
}
|
||||
|
||||
g_signal_connect (info->ipc_widget, "grab-broken-event",
|
||||
G_CALLBACK (gtk_drag_grab_broken_event_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "grab-notify",
|
||||
G_CALLBACK (gtk_drag_grab_notify_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "button-release-event",
|
||||
G_CALLBACK (gtk_drag_button_release_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "motion-notify-event",
|
||||
G_CALLBACK (gtk_drag_motion_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "key-press-event",
|
||||
G_CALLBACK (gtk_drag_key_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "key-release-event",
|
||||
G_CALLBACK (gtk_drag_key_cb), info);
|
||||
g_signal_connect (info->ipc_widget, "selection-get",
|
||||
G_CALLBACK (gtk_drag_selection_get), info);
|
||||
|
||||
@@ -3351,6 +3410,74 @@ gtk_drag_cancel_internal (GtkDragSourceInfo *info,
|
||||
gtk_drag_drop_finished (info, result, time);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_context_drop_performed_cb (GdkDragContext *context,
|
||||
guint32 time_,
|
||||
GtkDragSourceInfo *info)
|
||||
{
|
||||
gtk_drag_end (info, time_);
|
||||
gtk_drag_drop (info, time_);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_context_cancel_cb (GdkDragContext *context,
|
||||
GtkDragSourceInfo *info)
|
||||
{
|
||||
gtk_drag_cancel_internal (info, GTK_DRAG_RESULT_ERROR, GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_context_action_cb (GdkDragContext *context,
|
||||
GdkDragAction action,
|
||||
GtkDragSourceInfo *info)
|
||||
{
|
||||
if (info->proxy_dest)
|
||||
{
|
||||
if (info->proxy_dest->proxy_drop_wait)
|
||||
{
|
||||
gboolean result = gdk_drag_context_get_selected_action (context) != 0;
|
||||
|
||||
/* Aha - we can finally pass the DROP on... */
|
||||
gdk_drop_reply (info->proxy_dest->context, result, info->proxy_dest->proxy_drop_time);
|
||||
if (result)
|
||||
gdk_drag_drop (info->context, info->proxy_dest->proxy_drop_time);
|
||||
else
|
||||
gtk_drag_finish (info->proxy_dest->context, FALSE, FALSE, info->proxy_dest->proxy_drop_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_drag_status (info->proxy_dest->context,
|
||||
gdk_drag_context_get_selected_action (context),
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
g_signal_stop_emission_by_name (context, "action");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_context_dnd_finished_cb (GdkDragContext *context,
|
||||
GtkDragSourceInfo *info)
|
||||
{
|
||||
gtk_drag_source_release_selections (info, GDK_CURRENT_TIME);
|
||||
|
||||
if (info->proxy_dest)
|
||||
{
|
||||
/* The time from the event isn't reliable for Xdnd drags */
|
||||
gtk_drag_finish (info->proxy_dest->context, TRUE, FALSE,
|
||||
info->proxy_dest->proxy_drop_time);
|
||||
}
|
||||
|
||||
if (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE)
|
||||
{
|
||||
g_signal_emit_by_name (info->widget,
|
||||
"drag-data-delete",
|
||||
context);
|
||||
}
|
||||
|
||||
gtk_drag_source_info_destroy (info);
|
||||
}
|
||||
|
||||
/* “motion-notify-event” callback during drag. */
|
||||
static gboolean
|
||||
gtk_drag_motion_cb (GtkWidget *widget,
|
||||
|
@@ -13006,17 +13006,7 @@ gtk_widget_propagate_state (GtkWidget *widget,
|
||||
}
|
||||
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
{
|
||||
EventControllerData *controller_data;
|
||||
GList *l;
|
||||
|
||||
/* Reset all controllers */
|
||||
for (l = priv->event_controllers; l; l = l->next)
|
||||
{
|
||||
controller_data = l->data;
|
||||
gtk_event_controller_reset (controller_data->controller);
|
||||
}
|
||||
}
|
||||
gtk_widget_reset_controllers (widget);
|
||||
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
{
|
||||
@@ -17596,3 +17586,18 @@ _gtk_widget_consumes_motion (GtkWidget *widget,
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_widget_reset_controllers (GtkWidget *widget)
|
||||
{
|
||||
EventControllerData *controller_data;
|
||||
GtkWidgetPrivate *priv = widget->priv;
|
||||
GList *l;
|
||||
|
||||
/* Reset all controllers */
|
||||
for (l = priv->event_controllers; l; l = l->next)
|
||||
{
|
||||
controller_data = l->data;
|
||||
gtk_event_controller_reset (controller_data->controller);
|
||||
}
|
||||
}
|
||||
|
@@ -294,6 +294,8 @@ void gtk_widget_set_csd_input_shape (GtkWidget
|
||||
|
||||
gboolean gtk_widget_has_size_request (GtkWidget *widget);
|
||||
|
||||
void gtk_widget_reset_controllers (GtkWidget *widget);
|
||||
|
||||
/* inline getters */
|
||||
|
||||
static inline gboolean
|
||||
|
Reference in New Issue
Block a user