[gtk+/wip/garnacho/dnd-grab: 211/222] gdk: Allow internal management of source-side DnD
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/garnacho/dnd-grab: 211/222] gdk: Allow internal management of source-side DnD
- Date: Mon, 18 Jan 2016 21:34:20 +0000 (UTC)
commit e873a71ea8ffb39c688ce4059d86b5909b800f32
Author: Carlos Garnacho <carlosg gnome org>
Date: Fri Jan 8 21:03:01 2016 +0100
gdk: Allow internal management of source-side DnD
We've traditionally left GTK+ to handle the input side of things,
letting GDK only manage the windowing-specific messaging. This
way of splitting responsibilities is not compatible however with
some backends, we must fold then input management at the DnD stage
into GDK (and backends) domain.
The gdk_drag_context_manage_dnd() call is meant to be the entry
point for this mode of operation, if the drag and drop operation
becomes managed, the caller (i.e. gtkdnd.c) doesn't need to perform
grabs, nor manage input events itself.
As a consequence of this, different aspects now belong to the
backend GdkDragContext implementation:
- Because the caller doesn't see keyboard events anymore,
keyboard navigation must be managed in GDK, so is the decision
of the current action based on modifiers/button pressed.
- Because the caller won't see input events in general, the lifetime
of the drag and drop operation is now communicated through the
::drop-performed, ::dnd-finished and ::cancel events
- Because the caller doesn't participate anymore on the action
being chosen, the pointer cursor must be set by the backend.
The caller is rather notified of the final action through the
::action signal.
The caller is still responsible of dealing with the corresponding
GdkSelection, ensuring its ownership and communicating the supported
mimetypes.
gdk/gdkdnd.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdk/gdkdnd.h | 4 +
gdk/gdkdndprivate.h | 22 ++++++
3 files changed, 211 insertions(+), 0 deletions(-)
---
diff --git a/gdk/gdkdnd.c b/gdk/gdkdnd.c
index 3009630..32b4528 100644
--- a/gdk/gdkdnd.c
+++ b/gdk/gdkdnd.c
@@ -27,7 +27,19 @@
#include "gdkdndprivate.h"
#include "gdkdisplay.h"
#include "gdkwindow.h"
+#include "gdkintl.h"
+#include "gdkenumtypes.h"
+enum {
+ CANCEL,
+ DROP_PERFORMED,
+ DND_FINISHED,
+ ACTION_CHANGED,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+static GList *contexts = NULL;
/**
* SECTION:dnd
@@ -217,6 +229,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 +237,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 +255,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 perfomed 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:
+ * @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);
}
/**
@@ -527,3 +625,90 @@ 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 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;
+}
diff --git a/gdk/gdkdnd.h b/gdk/gdkdnd.h
index 1aa5d07..65c8c87 100644
--- a/gdk/gdkdnd.h
+++ b/gdk/gdkdnd.h
@@ -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__ */
diff --git a/gdk/gdkdndprivate.h b/gdk/gdkdndprivate.h
index fe2a95d..2404293 100644
--- a/gdk/gdkdndprivate.h
+++ b/gdk/gdkdndprivate.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,13 @@ 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);
+
G_END_DECLS
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]