summaryrefslogtreecommitdiff
path: root/gdk/gdkdnd.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>1999-01-28 01:03:15 +0000
committerOwen Taylor <otaylor@src.gnome.org>1999-01-28 01:03:15 +0000
commit77e99440df31909f584f660de762783a467a14c4 (patch)
tree8be59e235d1d1f40ada467a830a603b54ebb48f1 /gdk/gdkdnd.c
parent4998934dcba802627c798b981ef271ec6cd29880 (diff)
downloadgtk+-77e99440df31909f584f660de762783a467a14c4.tar.gz
Change signatures for gdk_drag_begin() and gdk_drag_motion() so that the
Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com> * gdk/gdk.h gdk/gdkdnd.c: Change signatures for gdk_drag_begin() and gdk_drag_motion() so that the set of possible actions is passed on each motion, not just at the beginning of the drag. We do this so that we can restrict the set of possible drag events when the user presses a modifier key during a drag. * gdk/gdkdnd.c: Send a motif Operation-changed message when the set of possible actions change, as well as when the suggested action change. * gdk/gdkdnd.c: Change the XdndActionList whenever the set of actions change. * gdk/gdkdnd.c: Add a filter to catch changes to the XdndActionList property for the source widget. * gtk/gtkdnd.c: Change the set of possible actions when the user presses Control, Shift, or Control-Shift, to only include the corresponding action. * gtk/gtkdnd.c (gtk_drag_button_release_cb): Disconnect button signals before we possibly free info structure.
Diffstat (limited to 'gdk/gdkdnd.c')
-rw-r--r--gdk/gdkdnd.c230
1 files changed, 173 insertions, 57 deletions
diff --git a/gdk/gdkdnd.c b/gdk/gdkdnd.c
index 7c951e9869..a4244bd35c 100644
--- a/gdk/gdkdnd.c
+++ b/gdk/gdkdnd.c
@@ -56,11 +56,13 @@ struct _GdkDragContextPrivate {
guint16 last_x; /* Coordinates from last event */
guint16 last_y;
- GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_actions; /* The last actions we sent to the source */
+ GdkDragAction xdnd_actions; /* What is currently set in XdndActionList */
Window dest_xid;
guint xdnd_targets_set : 1; /* Whether we've already set XdndTypeList */
- guint xdnd_actions_set : 1; /* Whether we've already set XdndActionsList */
+ guint xdnd_actions_set : 1; /* Whether we've already set XdndActionList */
guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
guint motif_targets_set : 1; /* Whether we've already set motif initiator info */
guint drag_status : 4; /* current status of drag */
@@ -103,6 +105,10 @@ static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev,
GdkEvent *event,
gpointer data);
+static void xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter);
+
/* Drag Contexts */
static GList *contexts;
@@ -145,7 +151,13 @@ gdk_drag_context_unref (GdkDragContext *context)
g_list_free (context->targets);
if (context->source_window)
- gdk_window_unref (context->source_window);
+ {
+ if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+ !context->is_source)
+ xdnd_manage_source_filter (context, context->source_window, FALSE);
+
+ gdk_window_unref (context->source_window);
+ }
if (context->dest_window)
gdk_window_unref (context->dest_window);
@@ -1361,11 +1373,12 @@ motif_send_motion (GdkDragContext *context,
MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
MOTIF_XCLIENT_LONG (&xev, 1) = time;
- if (context->suggested_action != private->old_action)
+ if ((context->suggested_action != private->old_action) ||
+ (context->actions != private->old_actions))
{
MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
- private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+ /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
retval = TRUE;
}
else
@@ -1724,7 +1737,8 @@ motif_drag_status (GdkEvent *event,
if (context)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
- if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+ if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+ (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
private->drag_status = GDK_DRAG_STATUS_DRAG;
event->dnd.type = GDK_DRAG_STATUS;
@@ -2009,7 +2023,7 @@ xdnd_set_actions (GdkDragContext *context)
if (!xdnd_actions_initialized)
xdnd_initialize_actions();
-
+
actions = context->actions;
n_atoms = 0;
for (i=0; i<xdnd_n_actions; i++)
@@ -2042,6 +2056,7 @@ xdnd_set_actions (GdkDragContext *context)
(guchar *)atomlist, n_atoms);
private->xdnd_actions_set = 1;
+ private->xdnd_actions = context->actions;
}
static void
@@ -2082,9 +2097,6 @@ xdnd_send_enter (GdkDragContext *context)
}
}
- if (!private->xdnd_actions_set)
- xdnd_set_actions (context);
-
if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
FALSE, 0, &xev))
{
@@ -2256,6 +2268,133 @@ xdnd_check_dest (Window win)
/* Target side */
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+ Atom type;
+ int format;
+ gulong nitems, after;
+ Atom *data;
+
+ gint i;
+
+ gint old_warnings = gdk_error_warnings;
+
+ gdk_error_code = 0;
+ gdk_error_warnings = 0;
+
+ /* Get the XdndActionList, if set */
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (context->source_window),
+ GDK_WINDOW_XWINDOW (context->source_window),
+ gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
+ False, XA_ATOM, &type, &format, &nitems,
+ &after, (guchar **)&data);
+
+ if (!gdk_error_code && (format == 32) && (type == XA_ATOM))
+ {
+ context->actions = 0;
+
+ for (i=0; i<nitems; i++)
+ context->actions |= xdnd_action_from_atom (data[i]);
+
+ ((GdkDragContextPrivate *)context)->xdnd_have_actions = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+ if (gdk_debug_flags & GDK_DEBUG_DND)
+ {
+ GString *action_str = g_string_new (NULL);
+ if (context->actions & GDK_ACTION_MOVE)
+ g_string_append(action_str, "MOVE ");
+ if (context->actions & GDK_ACTION_COPY)
+ g_string_append(action_str, "COPY ");
+ if (context->actions & GDK_ACTION_LINK)
+ g_string_append(action_str, "LINK ");
+ if (context->actions & GDK_ACTION_ASK)
+ g_string_append(action_str, "ASK ");
+
+ g_message("Xdnd actions = %s", action_str->str);
+ g_string_free (action_str, TRUE);
+ }
+#endif /* G_ENABLE_DEBUG */
+
+ XFree(data);
+ }
+
+ gdk_error_warnings = old_warnings;
+ gdk_error_code = 0;
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn
+xdnd_source_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer cb_data)
+{
+ XEvent *xevent = (XEvent *)xev;
+ GdkDragContext *context = cb_data;
+
+ if ((xevent->xany.type == PropertyNotify) &&
+ (xevent->xproperty.atom == gdk_atom_intern ("XdndActionList", FALSE)))
+ {
+ xdnd_read_actions (context);
+
+ return GDK_FILTER_REMOVE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter)
+{
+ gint old_warnings = 0; /* quiet gcc */
+ GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+ gboolean is_foreign = (private->window_type == GDK_WINDOW_FOREIGN);
+
+ if (is_foreign)
+ {
+ old_warnings = gdk_error_warnings;
+ gdk_error_warnings = 0;
+ }
+
+ if (!private->destroyed)
+ {
+ if (add_filter)
+ {
+ gdk_window_set_events (window,
+ gdk_window_get_events (window) |
+ GDK_PROPERTY_CHANGE_MASK);
+ gdk_window_add_filter (window, xdnd_source_window_filter, context);
+
+ }
+ else
+ {
+ gdk_window_remove_filter (window,
+ xdnd_source_window_filter,
+ context);
+ /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+ * but we might want it for other reasons. (Like
+ * INCR selection transactions).
+ */
+ }
+ }
+
+ if (is_foreign)
+ {
+ gdk_flush();
+ gdk_error_warnings = old_warnings;
+ }
+}
+
static GdkFilterReturn
xdnd_enter_filter (GdkXEvent *xev,
GdkEvent *event,
@@ -2339,49 +2478,14 @@ xdnd_enter_filter (GdkXEvent *xev,
GUINT_TO_POINTER (xevent->xclient.data.l[2+i]));
}
- /* Get the XdndActionList, if set */
-
- XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window),
- source_window,
- gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
- False, XA_ATOM, &type, &format, &nitems,
- &after, (guchar **)&data);
-
- if ((format == 32) && (type == XA_ATOM))
- {
- new_context->actions = 0;
-
- for (i=0; i<nitems; i++)
- new_context->actions |= xdnd_action_from_atom (data[i]);
-
- ((GdkDragContextPrivate *)new_context)->xdnd_have_actions = TRUE;
-
-#ifdef G_ENABLE_DEBUG
- if (gdk_debug_flags & GDK_DEBUG_DND)
- {
- GString *action_str = g_string_new (NULL);
- if (new_context->actions & GDK_ACTION_MOVE)
- g_string_append(action_str, "MOVE ");
- if (new_context->actions & GDK_ACTION_COPY)
- g_string_append(action_str, "COPY ");
- if (new_context->actions & GDK_ACTION_LINK)
- g_string_append(action_str, "LINK ");
- if (new_context->actions & GDK_ACTION_ASK)
- g_string_append(action_str, "ASK ");
-
- g_message("\tactions = %s", action_str->str);
- g_string_free (action_str, TRUE);
- }
-#endif /* G_ENABLE_DEBUG */
-
- XFree(data);
- }
-
#ifdef G_ENABLE_DEBUG
if (gdk_debug_flags & GDK_DEBUG_DND)
print_target_list (new_context->targets);
#endif /* G_ENABLE_DEBUG */
+ xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+ xdnd_read_actions (new_context);
+
event->dnd.type = GDK_DRAG_ENTER;
event->dnd.context = new_context;
gdk_drag_context_ref (new_context);
@@ -2558,8 +2662,7 @@ gdk_drag_do_leave (GdkDragContext *context, guint32 time)
GdkDragContext *
gdk_drag_begin (GdkWindow *window,
- GList *targets,
- GdkDragAction actions)
+ GList *targets)
{
GList *tmp_list;
GdkDragContext *new_context;
@@ -2580,7 +2683,7 @@ gdk_drag_begin (GdkWindow *window,
tmp_list = tmp_list->prev;
}
- new_context->actions = actions;
+ new_context->actions = 0;
return new_context;
}
@@ -2717,13 +2820,25 @@ gdk_drag_motion (GdkDragContext *context,
GdkDragProtocol protocol,
gint x_root,
gint y_root,
- GdkDragAction action,
+ GdkDragAction suggested_action,
+ GdkDragAction possible_actions,
guint32 time)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
g_return_val_if_fail (context != NULL, FALSE);
+ /* When we have a Xdnd target, make sure our XdndActionList
+ * matches the current actions;
+ */
+ private->old_actions = context->actions;
+ context->actions = possible_actions;
+
+ if ((protocol == GDK_DRAG_PROTO_XDND) &&
+ (!private->xdnd_actions_set ||
+ private->xdnd_actions != possible_actions))
+ xdnd_set_actions (context);
+
if (context->dest_window != dest_window)
{
GdkEvent temp_event;
@@ -2754,8 +2869,9 @@ gdk_drag_motion (GdkDragContext *context,
case GDK_DRAG_PROTO_NONE:
break;
}
- private->old_action = action;
- context->suggested_action = action;
+ private->old_action = suggested_action;
+ context->suggested_action = suggested_action;
+ private->old_actions = possible_actions;
}
else
{
@@ -2782,7 +2898,7 @@ gdk_drag_motion (GdkDragContext *context,
else
{
private->old_action = context->suggested_action;
- context->suggested_action = action;
+ context->suggested_action = suggested_action;
}
/* Send a drag-motion event */
@@ -2797,11 +2913,11 @@ gdk_drag_motion (GdkDragContext *context,
switch (context->protocol)
{
case GDK_DRAG_PROTO_MOTIF:
- motif_send_motion (context, x_root, y_root, action, time);
+ motif_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_XDND:
- xdnd_send_motion (context, x_root, y_root, action, time);
+ xdnd_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_ROOTWIN: