/* GDK - The GIMP Drawing Kit
* Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 1998-1999 Tor Lillqvist
+ * Copyright (C) 1998-2002 Tor Lillqvist
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
-#include "config.h"
-
#include <string.h>
/* #define OLE2_DND */
* this is used on both source and destination sides.
*/
struct _GdkDragContextPrivateWin32 {
- gint ref_count;
+ gint ref_count;
guint16 last_x; /* Coordinates from last event */
guint16 last_y;
- HWND dest_xid;
- guint drag_status; /* Current status of drag */
+ HWND dest_xid;
+ guint drag_status; /* Current status of drag */
};
-#define PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
+#define GDK_DRAG_CONTEXT_PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
GdkDragContext *current_dest_drag = NULL;
object_type = g_type_register_static (G_TYPE_OBJECT,
"GdkDragContext",
- &object_info);
+ &object_info, 0);
}
return object_type;
gdk_drag_context_finalize (GObject *object)
{
GdkDragContext *context = GDK_DRAG_CONTEXT (object);
- GdkDragContextPrivateWin32 *private = PRIVATE_DATA (context);
+ GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
g_list_free (context->targets);
{
g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
- g_object_ref (G_OBJECT (context));
+ GDK_NOTE (DND, g_print ("gdk_drag_context_ref: %p %d\n", context, G_OBJECT(context)->ref_count));
+
+ g_object_ref (context);
}
void
{
g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
- g_object_unref (G_OBJECT (context));
+ GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %p %d\n", context, G_OBJECT(context)->ref_count));
+ g_object_unref (context);
}
-#if 0
-
static GdkDragContext *
-gdk_drag_context_find (gboolean is_source,
- HWND source_xid,
- HWND dest_xid)
+gdk_drag_context_find (gboolean is_source,
+ GdkWindow *source,
+ GdkWindow *dest)
{
GList *tmp_list = contexts;
GdkDragContext *context;
+ GdkDragContextPrivateWin32 *private;
while (tmp_list)
{
context = (GdkDragContext *)tmp_list->data;
+ private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
if ((!context->is_source == !is_source) &&
- ((source_xid == None) || (context->source_window &&
- (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
- ((dest_xid == None) || (context->dest_window &&
- (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
+ ((source == NULL) || (context->source_window && (context->source_window == source))) &&
+ ((dest == NULL) || (context->dest_window && (context->dest_window == dest))))
return context;
tmp_list = tmp_list->next;
}
-
+
return NULL;
}
-#endif
typedef struct {
#ifdef OLE2_DND
idroptarget_addref (LPDROPTARGET This)
{
target_drag_context *ctx = (target_drag_context *) This;
- GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
+ GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
int ref_count = ++private->ref_count;
gdk_drag_context_ref (ctx->context);
idroptarget_release (LPDROPTARGET This)
{
target_drag_context *ctx = (target_drag_context *) This;
- GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
+ GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
int ref_count = --private->ref_count;
gdk_drag_context_unref (ctx->context);
idropsource_addref (LPDROPSOURCE This)
{
source_drag_context *ctx = (source_drag_context *) This;
- GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
+ GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
gdk_drag_context_ref (ctx->context);
GDK_NOTE (DND, g_print ("idropsource_addref %#x %d\n",
idropsource_release (LPDROPSOURCE This)
{
source_drag_context *ctx = (source_drag_context *) This;
- GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
+ GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
int ref_count = --private->ref_count;
gdk_drag_context_unref (ctx->context);
{
GdkDragContext *context;
GdkDragContextPrivateWin32 *private;
- static GdkAtom text_uri_list_atom = GDK_NONE;
GString *result;
MSG *msg = (MSG *) xev;
HANDLE hdrop;
gint nfiles, i;
guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
- if (text_uri_list_atom == GDK_NONE)
- text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
-
if (msg->message == WM_DROPFILES)
{
GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", (guint) msg->hwnd));
context = gdk_drag_context_new ();
- private = PRIVATE_DATA (context);
+ private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
context->is_source = FALSE;
- context->source_window = gdk_parent_root;
+ context->source_window = _gdk_parent_root;
+ gdk_drawable_ref (context->source_window);
context->dest_window = event->any.window;
gdk_drawable_ref (context->dest_window);
/* WM_DROPFILES drops are always file names */
context->targets =
- g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom));
+ g_list_append (NULL, GUINT_TO_POINTER (_text_uri_list));
current_dest_drag = context;
event->dnd.type = GDK_DROP_START;
event->dnd.context = current_dest_drag;
- gdk_drag_context_ref (current_dest_drag);
hdrop = (HANDLE) msg->wParam;
DragQueryPoint (hdrop, &pt);
event->dnd.x_root = pt.x;
event->dnd.y_root = pt.y;
- event->dnd.time = msg->time;
+ event->dnd.time = _gdk_win32_get_next_tick (msg->time);
nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
result = g_string_new (NULL);
for (i = 0; i < nfiles; i++)
{
- g_string_append (result, "file:");
+ gchar *uri;
+
DragQueryFile (hdrop, i, fileName, MAX_PATH);
/* Resolve shortcuts */
if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
{
- g_string_append (result, linkedFile);
- GDK_NOTE (DND, g_print ("...%s link to %s\n",
- fileName, linkedFile));
+ uri = g_filename_to_uri (linkedFile, NULL, NULL);
+ if (uri != NULL)
+ {
+ g_string_append (result, uri);
+ GDK_NOTE (DND, g_print ("...%s link to %s: %s\n",
+ fileName, linkedFile, uri));
+ g_free (uri);
+ }
}
else
{
- g_string_append (result, fileName);
- GDK_NOTE (DND, g_print ("...%s\n", fileName));
+ uri = g_filename_to_uri (fileName, NULL, NULL);
+ if (uri != NULL)
+ {
+ g_string_append (result, uri);
+ GDK_NOTE (DND, g_print ("...%s: %s\n", fileName, uri));
+ g_free (uri);
+ }
}
g_string_append (result, "\015\012");
}
- gdk_sel_prop_store (gdk_parent_root, text_uri_list_atom, 8,
- result->str, result->len + 1);
+ _gdk_dropfiles_store (result->str);
+ g_string_free (result, FALSE);
DragFinish (hdrop);
*************************************************************/
void
-gdk_dnd_init (void)
+_gdk_dnd_init (void)
{
#ifdef OLE2_DND
HRESULT hres;
}
void
-gdk_win32_dnd_exit (void)
+_gdk_win32_dnd_exit (void)
{
#ifdef OLE2_DND
OleUninitialize ();
/* Source side */
+static void
+local_send_leave (GdkDragContext *context,
+ guint32 time)
+{
+ GdkEvent tmp_event;
+
+ if ((current_dest_drag != NULL) &&
+ (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
+ (current_dest_drag->source_window == context->source_window))
+ {
+ tmp_event.dnd.type = GDK_DRAG_LEAVE;
+ tmp_event.dnd.window = context->dest_window;
+ /* Pass ownership of context to the event */
+ tmp_event.dnd.send_event = FALSE;
+ tmp_event.dnd.context = current_dest_drag;
+ tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+
+ current_dest_drag = NULL;
+
+ gdk_event_put (&tmp_event);
+ }
+}
+
+static void
+local_send_enter (GdkDragContext *context,
+ guint32 time)
+{
+ GdkEvent tmp_event;
+ GdkDragContextPrivateWin32 *private;
+ GdkDragContext *new_context;
+
+ private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+
+ if (current_dest_drag != NULL)
+ {
+ gdk_drag_context_unref (current_dest_drag);
+ current_dest_drag = NULL;
+ }
+
+ new_context = gdk_drag_context_new ();
+ new_context->protocol = GDK_DRAG_PROTO_LOCAL;
+ new_context->is_source = FALSE;
+
+ new_context->source_window = context->source_window;
+ gdk_window_ref (new_context->source_window);
+ new_context->dest_window = context->dest_window;
+ gdk_window_ref (new_context->dest_window);
+
+ new_context->targets = g_list_copy (context->targets);
+
+ gdk_window_set_events (new_context->source_window,
+ gdk_window_get_events (new_context->source_window) |
+ GDK_PROPERTY_CHANGE_MASK);
+ new_context->actions = context->actions;
+
+ tmp_event.dnd.type = GDK_DRAG_ENTER;
+ tmp_event.dnd.window = context->dest_window;
+ tmp_event.dnd.send_event = FALSE;
+ tmp_event.dnd.context = new_context;
+ tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+
+ current_dest_drag = new_context;
+
+ gdk_event_put (&tmp_event);
+}
+
+static void
+local_send_motion (GdkDragContext *context,
+ gint x_root,
+ gint y_root,
+ GdkDragAction action,
+ guint32 time)
+{
+ GdkEvent tmp_event;
+
+ if ((current_dest_drag != NULL) &&
+ (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
+ (current_dest_drag->source_window == context->source_window))
+ {
+ tmp_event.dnd.type = GDK_DRAG_MOTION;
+ tmp_event.dnd.window = current_dest_drag->dest_window;
+ tmp_event.dnd.send_event = FALSE;
+ tmp_event.dnd.context = current_dest_drag;
+ tmp_event.dnd.time = time;
+
+ current_dest_drag->suggested_action = action;
+ current_dest_drag->actions = current_dest_drag->suggested_action;
+
+ tmp_event.dnd.x_root = x_root;
+ tmp_event.dnd.y_root = y_root;
+
+ (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_x = x_root;
+ (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_y = y_root;
+
+ GDK_DRAG_CONTEXT_PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
+
+ gdk_event_put (&tmp_event);
+ }
+}
+
+static void
+local_send_drop (GdkDragContext *context,
+ guint32 time)
+{
+ GdkEvent tmp_event;
+
+ if ((current_dest_drag != NULL) &&
+ (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
+ (current_dest_drag->source_window == context->source_window))
+ {
+ GdkDragContextPrivateWin32 *private;
+ private = GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag);
+
+ tmp_event.dnd.type = GDK_DROP_START;
+ tmp_event.dnd.window = current_dest_drag->dest_window;
+ tmp_event.dnd.send_event = FALSE;
+ tmp_event.dnd.context = current_dest_drag;
+ tmp_event.dnd.time = GDK_CURRENT_TIME;
+
+ tmp_event.dnd.x_root = private->last_x;
+ tmp_event.dnd.y_root = private->last_y;
+
+ gdk_event_put (&tmp_event);
+ }
+
+}
+
static void
gdk_drag_do_leave (GdkDragContext *context,
guint32 time)
if (context->dest_window)
{
GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
+
+ switch (context->protocol)
+ {
+ case GDK_DRAG_PROTO_LOCAL:
+ local_send_leave (context, time);
+ break;
+ default:
+ break;
+ }
+
gdk_drawable_unref (context->dest_window);
context->dest_window = NULL;
}
gdk_drag_begin (GdkWindow *window,
GList *targets)
{
+#ifndef OLE2_DND
+ GList *tmp_list;
+ GdkDragContext *new_context;
+
+ g_return_val_if_fail (window != NULL, NULL);
+
+ new_context = gdk_drag_context_new ();
+ new_context->is_source = TRUE;
+ new_context->source_window = window;
+ gdk_window_ref (window);
+
+ tmp_list = g_list_last (targets);
+ new_context->targets = NULL;
+ while (tmp_list)
+ {
+ new_context->targets = g_list_prepend (new_context->targets,
+ tmp_list->data);
+ tmp_list = tmp_list->prev;
+ }
+
+ new_context->actions = 0;
+
+ return new_context;
+#else
source_drag_context *ctx;
-#ifdef OLE2_DND
GList *tmp_list;
data_object *dobj;
HRESULT hResult;
HGLOBAL global;
FORMATETC format;
STGMEDIUM medium;
-#endif
g_return_val_if_fail (window != NULL, NULL);
ctx->context->source_window = window;
gdk_drawable_ref (window);
-#ifdef OLE2_DND
tmp_list = g_list_last (targets);
ctx->context->targets = NULL;
while (tmp_list)
dobj->ido.lpVtbl->Release (&dobj->ido);
ctx->ids.lpVtbl->Release (&ctx->ids);
-#endif
+
return ctx->context;
+#endif
}
guint32
-gdk_drag_get_protocol (guint32 xid,
- GdkDragProtocol *protocol)
+gdk_drag_get_protocol_for_display (GdkDisplay *display,
+ guint32 xid,
+ GdkDragProtocol *protocol)
{
- /* This isn't used */
+ GdkWindow *window;
+
+ GDK_NOTE (DND, g_print ("gdk_drag_get_protocol\n"));
+
+ window = gdk_window_lookup (xid);
+
+ if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
+ {
+ *protocol = GDK_DRAG_PROTO_LOCAL;
+ return xid;
+ }
+
return 0;
}
void
-gdk_drag_find_window (GdkDragContext *context,
- GdkWindow *drag_window,
- gint x_root,
- gint y_root,
- GdkWindow **dest_window,
- GdkDragProtocol *protocol)
+gdk_drag_find_window_for_screen (GdkDragContext *context,
+ GdkWindow *drag_window,
+ GdkScreen *screen,
+ gint x_root,
+ gint y_root,
+ GdkWindow **dest_window,
+ GdkDragProtocol *protocol)
{
HWND recipient;
POINT pt;
- GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n",
- (drag_window ? (guint) GDK_WINDOW_HWND (drag_window) : 0),
- x_root, y_root));
-
pt.x = x_root;
pt.y = y_root;
recipient = WindowFromPoint (pt);
{
*dest_window = gdk_win32_handle_table_lookup (GPOINTER_TO_UINT(recipient));
if (*dest_window)
- gdk_drawable_ref (*dest_window);
- *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+ {
+ *dest_window = gdk_window_get_toplevel (*dest_window);
+ gdk_drawable_ref (*dest_window);
+ }
+
+ if (context->source_window)
+ *protocol = GDK_DRAG_PROTO_LOCAL;
+ else
+ *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
}
+
+ GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d Protocol: %d\n",
+ (drag_window ? (guint) GDK_WINDOW_HWND (drag_window) : 0),
+ x_root, y_root, *protocol));
}
gboolean
GdkDragAction possible_actions,
guint32 time)
{
+ GdkDragContextPrivateWin32 *private;
+
+ g_return_val_if_fail (context != NULL, FALSE);
+
GDK_NOTE (DND, g_print ("gdk_drag_motion\n"));
+ private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+
+ if (context->dest_window != dest_window)
+ {
+ GdkEvent temp_event;
+
+ /* Send a leave to the last destination */
+ gdk_drag_do_leave (context, time);
+ private->drag_status = GDK_DRAG_STATUS_DRAG;
+
+ /* Check if new destination accepts drags, and which protocol */
+ if (dest_window)
+ {
+ context->dest_window = dest_window;
+ gdk_window_ref (context->dest_window);
+ context->protocol = protocol;
+
+ switch (protocol)
+ {
+ case GDK_DRAG_PROTO_LOCAL:
+ local_send_enter (context, time);
+ break;
+
+ default:
+ break;
+ }
+ context->suggested_action = suggested_action;
+ }
+ else
+ {
+ context->dest_window = NULL;
+ context->action = 0;
+ }
+
+ /* Push a status event, to let the client know that
+ * the drag changed
+ */
+
+ temp_event.dnd.type = GDK_DRAG_STATUS;
+ temp_event.dnd.window = context->source_window;
+ /* We use this to signal a synthetic status. Perhaps
+ * we should use an extra field...
+ */
+ temp_event.dnd.send_event = TRUE;
+
+ temp_event.dnd.context = context;
+ temp_event.dnd.time = time;
+
+ gdk_event_put (&temp_event);
+ }
+ else
+ {
+ context->suggested_action = suggested_action;
+ }
+
+ /* Send a drag-motion event */
+
+ private->last_x = x_root;
+ private->last_y = y_root;
+
+ if (context->dest_window)
+ {
+ if (private->drag_status == GDK_DRAG_STATUS_DRAG)
+ {
+ switch (context->protocol)
+ {
+ case GDK_DRAG_PROTO_LOCAL:
+ local_send_motion (context, x_root, y_root, suggested_action, time);
+ break;
+
+ case GDK_DRAG_PROTO_NONE:
+ g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ return TRUE;
+ }
+
return FALSE;
}
g_return_if_fail (context != NULL);
GDK_NOTE (DND, g_print ("gdk_drag_drop\n"));
+
+ if (context->dest_window)
+ {
+ switch (context->protocol)
+ {
+ case GDK_DRAG_PROTO_LOCAL:
+ local_send_drop (context, time);
+ break;
+
+ case GDK_DRAG_PROTO_NONE:
+ g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
+ break;
+
+ default:
+ break;
+ }
+ }
}
void
GdkDragAction action,
guint32 time)
{
- GDK_NOTE (DND, g_print ("gdk_drag_status\n"));
+ GdkDragContextPrivateWin32 *private;
+ GdkDragContext *src_context;
+ GdkEvent tmp_event;
+
+ g_return_if_fail (context != NULL);
+
+ private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+
+ src_context = gdk_drag_context_find (TRUE,
+ context->source_window,
+ context->dest_window);
+
+ if (src_context)
+ {
+ GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (src_context);
+
+ if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+ private->drag_status = GDK_DRAG_STATUS_DRAG;
+
+ tmp_event.dnd.type = GDK_DRAG_STATUS;
+ tmp_event.dnd.window = context->source_window;
+ tmp_event.dnd.send_event = FALSE;
+ tmp_event.dnd.context = src_context;
+ tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+
+ if (action == GDK_ACTION_DEFAULT)
+ action = 0;
+
+ src_context->action = action;
+
+ gdk_event_put (&tmp_event);
+ }
}
void
gboolean ok,
guint32 time)
{
+ g_return_if_fail (context != NULL);
+
GDK_NOTE (DND, g_print ("gdk_drop_reply\n"));
+
+ if (context->dest_window)
+ {
+ switch (context->protocol)
+ {
+ case GDK_DRAG_PROTO_WIN32_DROPFILES:
+ _gdk_dropfiles_store (NULL);
+ break;
+
+ default:
+ break;
+ }
+ }
}
void
gboolean success,
guint32 time)
{
+ GdkDragContextPrivateWin32 *private;
+ GdkDragContext *src_context;
+ GdkEvent tmp_event;
+
+ g_return_if_fail (context != NULL);
+
GDK_NOTE (DND, g_print ("gdk_drop_finish\n"));
+
+ private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+
+ src_context = gdk_drag_context_find (TRUE,
+ context->source_window,
+ context->dest_window);
+ if (src_context)
+ {
+ tmp_event.dnd.type = GDK_DROP_FINISHED;
+ tmp_event.dnd.window = src_context->source_window;
+ tmp_event.dnd.send_event = FALSE;
+ tmp_event.dnd.context = src_context;
+
+ gdk_event_put (&tmp_event);
+ }
}
+#ifdef OLE2_DND
+
static GdkFilterReturn
gdk_destroy_filter (GdkXEvent *xev,
GdkEvent *event,
gpointer data)
{
-#ifdef OLE2_DND
MSG *msg = (MSG *) xev;
if (msg->message == WM_DESTROY)
RevokeDragDrop (msg->hwnd);
CoLockObjectExternal (idtp, FALSE, TRUE);
}
-#endif
return GDK_FILTER_CONTINUE;
}
+#endif
void
gdk_window_register_dnd (GdkWindow *window)
g_return_if_fail (window != NULL);
+ if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
+ return;
+
+ gdk_drawable_set_data (window, "gdk-dnd-registered", GINT_TO_POINTER(TRUE), NULL);
+
GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n",
(guint) GDK_WINDOW_HWND (window)));
GdkAtom
gdk_drag_get_selection (GdkDragContext *context)
{
- if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
- return gdk_win32_dropfiles_atom;
+ if (context->protocol == GDK_DRAG_PROTO_LOCAL)
+ return _local_dnd;
+ else if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
+ return _gdk_win32_dropfiles;
else if (context->protocol == GDK_DRAG_PROTO_OLE2)
- return gdk_ole2_dnd_atom;
+ return _gdk_ole2_dnd;
else
return GDK_NONE;
}