2008-08-05 Tor Lillqvist <tml@novell.com> Bug 544684 - Win64 issue, window handles are assumed to be 32-bit * gdk/gdkdnd.h * gdk/gdkdnd.c * gdk/win32/gdkdnd-win32.c * gdk/x11/gdkdnd-x11.c: Change return value and type of window id from guint32 to GdkNativeWindow for gdk_drag_get_protocol_for_display() and gdk_drag_get_protocol(). This is not an API break on existing platforms, as GdkNativeWindow has been guint32 for them already. svn path=/trunk/; revision=20988
		
			
				
	
	
		
			1742 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1742 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* GDK - The GIMP Drawing Kit
 | 
						|
 * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
 | 
						|
 * 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
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This library is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * Lesser General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General Public
 | 
						|
 * License along with this library; if not, write to the
 | 
						|
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
						|
 * Boston, MA 02111-1307, USA.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 | 
						|
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 | 
						|
 * files for a list of changes.  These files are distributed with
 | 
						|
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
/* #define OLE2_DND */
 | 
						|
 | 
						|
#define INITGUID
 | 
						|
 | 
						|
#include "gdkdnd.h"
 | 
						|
#include "gdkproperty.h"
 | 
						|
#include "gdkinternals.h"
 | 
						|
#include "gdkprivate-win32.h"
 | 
						|
 | 
						|
#ifdef OLE2_DND
 | 
						|
#include <ole2.h>
 | 
						|
#else
 | 
						|
#include <objbase.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <shlobj.h>
 | 
						|
#include <shlguid.h>
 | 
						|
 | 
						|
#include <gdk/gdk.h>
 | 
						|
 | 
						|
typedef struct _GdkDragContextPrivateWin32 GdkDragContextPrivateWin32;
 | 
						|
 | 
						|
typedef enum {
 | 
						|
  GDK_DRAG_STATUS_DRAG,
 | 
						|
  GDK_DRAG_STATUS_MOTION_WAIT,
 | 
						|
  GDK_DRAG_STATUS_ACTION_WAIT,
 | 
						|
  GDK_DRAG_STATUS_DROP
 | 
						|
} GtkDragStatus;
 | 
						|
 | 
						|
typedef enum {
 | 
						|
  GDK_DRAG_SOURCE,
 | 
						|
  GDK_DRAG_TARGET
 | 
						|
} GdkDragKind;
 | 
						|
 | 
						|
#ifdef OLE2_DND
 | 
						|
 | 
						|
#define PRINT_GUID(guid) \
 | 
						|
  g_print ("guid = %.08lx-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \
 | 
						|
	   ((gulong *)  guid)[0], \
 | 
						|
	   ((gushort *) guid)[2], \
 | 
						|
	   ((gushort *) guid)[3], \
 | 
						|
	   ((guchar *)  guid)[8], \
 | 
						|
	   ((guchar *)  guid)[9], \
 | 
						|
	   ((guchar *)  guid)[10], \
 | 
						|
	   ((guchar *)  guid)[11], \
 | 
						|
	   ((guchar *)  guid)[12], \
 | 
						|
	   ((guchar *)  guid)[13], \
 | 
						|
	   ((guchar *)  guid)[14], \
 | 
						|
	   ((guchar *)  guid)[15]);
 | 
						|
 | 
						|
 | 
						|
static FORMATETC *formats;
 | 
						|
static int nformats;
 | 
						|
 | 
						|
#endif /* OLE2_DND */
 | 
						|
 | 
						|
/* Structure that holds information about a drag in progress.
 | 
						|
 * this is used on both source and destination sides.
 | 
						|
 */
 | 
						|
struct _GdkDragContextPrivateWin32 {
 | 
						|
#ifdef OLE2_DND
 | 
						|
  gint    ref_count;
 | 
						|
#endif
 | 
						|
  guint16 last_x;		/* Coordinates from last event */
 | 
						|
  guint16 last_y;
 | 
						|
  HWND dest_xid;
 | 
						|
  guint drag_status : 4;	/* Current status of drag */
 | 
						|
  guint drop_failed : 1;	/* Whether the drop was unsuccessful */
 | 
						|
};
 | 
						|
 | 
						|
#define GDK_DRAG_CONTEXT_PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
 | 
						|
 | 
						|
static GdkDragContext *current_dest_drag = NULL;
 | 
						|
 | 
						|
static void gdk_drag_context_init       (GdkDragContext      *dragcontext);
 | 
						|
static void gdk_drag_context_class_init (GdkDragContextClass *klass);
 | 
						|
static void gdk_drag_context_finalize   (GObject              *object);
 | 
						|
 | 
						|
static gpointer parent_class = NULL;
 | 
						|
static GList *contexts;
 | 
						|
 | 
						|
GType
 | 
						|
gdk_drag_context_get_type (void)
 | 
						|
{
 | 
						|
  static GType object_type = 0;
 | 
						|
 | 
						|
  if (!object_type)
 | 
						|
    {
 | 
						|
      static const GTypeInfo object_info =
 | 
						|
      {
 | 
						|
        sizeof (GdkDragContextClass),
 | 
						|
        (GBaseInitFunc) NULL,
 | 
						|
        (GBaseFinalizeFunc) NULL,
 | 
						|
        (GClassInitFunc) gdk_drag_context_class_init,
 | 
						|
        NULL,           /* class_finalize */
 | 
						|
        NULL,           /* class_data */
 | 
						|
        sizeof (GdkDragContext),
 | 
						|
        0,              /* n_preallocs */
 | 
						|
        (GInstanceInitFunc) gdk_drag_context_init,
 | 
						|
      };
 | 
						|
      
 | 
						|
      object_type = g_type_register_static (G_TYPE_OBJECT,
 | 
						|
                                            "GdkDragContext",
 | 
						|
                                            &object_info, 0);
 | 
						|
    }
 | 
						|
  
 | 
						|
  return object_type;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_drag_context_init (GdkDragContext *dragcontext)
 | 
						|
{
 | 
						|
  GdkDragContextPrivateWin32 *private = g_new0 (GdkDragContextPrivateWin32, 1);
 | 
						|
 | 
						|
  dragcontext->windowing_data = private;
 | 
						|
#ifdef OLE2_DND
 | 
						|
  private->ref_count = 1;
 | 
						|
#endif
 | 
						|
 | 
						|
  contexts = g_list_prepend (contexts, dragcontext);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_drag_context_class_init (GdkDragContextClass *klass)
 | 
						|
{
 | 
						|
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
						|
 | 
						|
  parent_class = g_type_class_peek_parent (klass);
 | 
						|
 | 
						|
  object_class->finalize = gdk_drag_context_finalize;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_drag_context_finalize (GObject *object)
 | 
						|
{
 | 
						|
  GdkDragContext *context = GDK_DRAG_CONTEXT (object);
 | 
						|
  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
 | 
						|
 
 | 
						|
  GDK_NOTE (DND, g_print ("gdk_drag_context_finalize\n"));
 | 
						|
 
 | 
						|
  g_list_free (context->targets);
 | 
						|
 | 
						|
  if (context->source_window)
 | 
						|
    {
 | 
						|
      g_object_unref (context->source_window);
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (context->dest_window)
 | 
						|
    g_object_unref (context->dest_window);
 | 
						|
  
 | 
						|
  contexts = g_list_remove (contexts, context);
 | 
						|
 | 
						|
  if (context == current_dest_drag)
 | 
						|
    current_dest_drag = NULL;
 | 
						|
 | 
						|
  g_free (private);
 | 
						|
  
 | 
						|
  G_OBJECT_CLASS (parent_class)->finalize (object);
 | 
						|
}
 | 
						|
 | 
						|
/* Drag Contexts */
 | 
						|
 | 
						|
GdkDragContext *
 | 
						|
gdk_drag_context_new (void)
 | 
						|
{
 | 
						|
  return g_object_new (gdk_drag_context_get_type (), NULL);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gdk_drag_context_ref (GdkDragContext *context)
 | 
						|
{
 | 
						|
  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
 | 
						|
 | 
						|
  g_object_ref (context);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gdk_drag_context_unref (GdkDragContext *context)
 | 
						|
{
 | 
						|
  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
 | 
						|
 | 
						|
  g_object_unref (context);
 | 
						|
}
 | 
						|
 | 
						|
static GdkDragContext *
 | 
						|
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 == 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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
#ifdef OLE2_DND
 | 
						|
  IDropTarget idt;
 | 
						|
#endif
 | 
						|
  GdkDragContext *context;
 | 
						|
} target_drag_context;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
#ifdef OLE2_DND
 | 
						|
  IDropSource ids;
 | 
						|
#endif
 | 
						|
  GdkDragContext *context;
 | 
						|
} source_drag_context;
 | 
						|
 | 
						|
#ifdef OLE2_DND
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  IDataObject ido;
 | 
						|
  int ref_count;
 | 
						|
} data_object;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  IEnumFORMATETC ief;
 | 
						|
  int ref_count;
 | 
						|
  int ix;
 | 
						|
} enum_formats;
 | 
						|
 | 
						|
static enum_formats *enum_formats_new (void);
 | 
						|
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
idroptarget_addref (LPDROPTARGET This)
 | 
						|
{
 | 
						|
  target_drag_context *ctx = (target_drag_context *) This;
 | 
						|
  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
 | 
						|
  int ref_count = ++private->ref_count;
 | 
						|
 | 
						|
  gdk_drag_context_ref (ctx->context);
 | 
						|
  GDK_NOTE (DND, g_print ("idroptarget_addref %p %d\n", This, ref_count));
 | 
						|
  
 | 
						|
  return ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idroptarget_queryinterface (LPDROPTARGET This,
 | 
						|
			    REFIID       riid,
 | 
						|
			    LPVOID      *ppvObject)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idroptarget_queryinterface %p\n", This));
 | 
						|
 | 
						|
  *ppvObject = NULL;
 | 
						|
 | 
						|
  PRINT_GUID (riid);
 | 
						|
 | 
						|
  if (IsEqualGUID (riid, &IID_IUnknown))
 | 
						|
    {
 | 
						|
      g_print ("...IUnknown\n");
 | 
						|
      idroptarget_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else if (IsEqualGUID (riid, &IID_IDropTarget))
 | 
						|
    {
 | 
						|
      g_print ("...IDropTarget\n");
 | 
						|
      idroptarget_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      g_print ("...Huh?\n");
 | 
						|
      return E_NOINTERFACE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
idroptarget_release (LPDROPTARGET This)
 | 
						|
{
 | 
						|
  target_drag_context *ctx = (target_drag_context *) This;
 | 
						|
  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
 | 
						|
  int ref_count = --private->ref_count;
 | 
						|
 | 
						|
  gdk_drag_context_unref (ctx->context);
 | 
						|
  GDK_NOTE (DND, g_print ("idroptarget_release %p %d\n", This, ref_count));
 | 
						|
 | 
						|
  if (ref_count == 0)
 | 
						|
    g_free (This);
 | 
						|
 | 
						|
  return ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE 
 | 
						|
idroptarget_dragenter (LPDROPTARGET This,
 | 
						|
		       LPDATAOBJECT pDataObj,
 | 
						|
		       DWORD        grfKeyState,
 | 
						|
		       POINTL       pt,
 | 
						|
		       LPDWORD      pdwEffect)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idroptarget_dragenter %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idroptarget_dragover (LPDROPTARGET This,
 | 
						|
		      DWORD        grfKeyState,
 | 
						|
		      POINTL       pt,
 | 
						|
		      LPDWORD      pdwEffect)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idroptarget_dragover %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idroptarget_dragleave (LPDROPTARGET This)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idroptarget_dragleave %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idroptarget_drop (LPDROPTARGET This,
 | 
						|
		  LPDATAOBJECT pDataObj,
 | 
						|
		  DWORD        grfKeyState,
 | 
						|
		  POINTL       pt,
 | 
						|
		  LPDWORD      pdwEffect)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idroptarget_drop %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
idropsource_addref (LPDROPSOURCE This)
 | 
						|
{
 | 
						|
  source_drag_context *ctx = (source_drag_context *) This;
 | 
						|
  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
 | 
						|
 | 
						|
  gdk_drag_context_ref (ctx->context);
 | 
						|
  GDK_NOTE (DND, g_print ("idropsource_addref %p %d\n",
 | 
						|
			  This, private->ref_count));
 | 
						|
  
 | 
						|
  return private->ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idropsource_queryinterface (LPDROPSOURCE This,
 | 
						|
			    REFIID       riid,
 | 
						|
			    LPVOID      *ppvObject)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idropsource_queryinterface %p\n", This));
 | 
						|
 | 
						|
  *ppvObject = NULL;
 | 
						|
 | 
						|
  PRINT_GUID (riid);
 | 
						|
  if (IsEqualGUID (riid, &IID_IUnknown))
 | 
						|
    {
 | 
						|
      g_print ("...IUnknown\n");
 | 
						|
      idropsource_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else if (IsEqualGUID (riid, &IID_IDropSource))
 | 
						|
    {
 | 
						|
      g_print ("...IDropSource\n");
 | 
						|
      idropsource_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      g_print ("...Huh?\n");
 | 
						|
      return E_NOINTERFACE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
idropsource_release (LPDROPSOURCE This)
 | 
						|
{
 | 
						|
  source_drag_context *ctx = (source_drag_context *) This;
 | 
						|
  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
 | 
						|
  int ref_count = --private->ref_count;
 | 
						|
 | 
						|
  gdk_drag_context_unref (ctx->context);
 | 
						|
  GDK_NOTE (DND, g_print ("idropsource_release %p %d\n", This, ref_count));
 | 
						|
 | 
						|
  if (ref_count == 0)
 | 
						|
    g_free (This);
 | 
						|
 | 
						|
  return ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idropsource_querycontinuedrag (LPDROPSOURCE This,
 | 
						|
			       BOOL         fEscapePressed,
 | 
						|
			       DWORD        grfKeyState)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idropsource_givefeedback (LPDROPSOURCE This,
 | 
						|
			  DWORD        dwEffect)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idropsource_givefeedback %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
idataobject_addref (LPDATAOBJECT This)
 | 
						|
{
 | 
						|
  data_object *dobj = (data_object *) This;
 | 
						|
  int ref_count = ++dobj->ref_count;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_addref %p %d\n", This, ref_count));
 | 
						|
 | 
						|
  return ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_queryinterface (LPDATAOBJECT This,
 | 
						|
			    REFIID       riid,
 | 
						|
			    LPVOID      *ppvObject)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_queryinterface %p\n", This));
 | 
						|
 | 
						|
  *ppvObject = NULL;
 | 
						|
 | 
						|
  PRINT_GUID (riid);
 | 
						|
  if (IsEqualGUID (riid, &IID_IUnknown))
 | 
						|
    {
 | 
						|
      g_print ("...IUnknown\n");
 | 
						|
      idataobject_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else if (IsEqualGUID (riid, &IID_IDataObject))
 | 
						|
    {
 | 
						|
      g_print ("...IDataObject\n");
 | 
						|
      idataobject_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      g_print ("...Huh?\n");
 | 
						|
      return E_NOINTERFACE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
idataobject_release (LPDATAOBJECT This)
 | 
						|
{
 | 
						|
  data_object *dobj = (data_object *) This;
 | 
						|
  int ref_count = --dobj->ref_count;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_release %p %d\n", This, ref_count));
 | 
						|
 | 
						|
  if (ref_count == 0)
 | 
						|
    g_free (This);
 | 
						|
 | 
						|
  return ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_getdata (LPDATAOBJECT This,
 | 
						|
		     LPFORMATETC  pFormatEtc,
 | 
						|
		     LPSTGMEDIUM  pMedium)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_getdata %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_getdatahere (LPDATAOBJECT This,
 | 
						|
			 LPFORMATETC  pFormatEtc,
 | 
						|
			 LPSTGMEDIUM  pMedium)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_getdatahere %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_querygetdata (LPDATAOBJECT This,
 | 
						|
			  LPFORMATETC  pFormatEtc)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_querygetdata %p %#x", This, pFormatEtc->cfFormat));
 | 
						|
 | 
						|
  for (i = 0; i < nformats; i++)
 | 
						|
    if (pFormatEtc->cfFormat == formats[i].cfFormat)
 | 
						|
      {
 | 
						|
	GDK_NOTE (DND, g_print (" S_OK\n"));
 | 
						|
	return S_OK;
 | 
						|
      }
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print (" DV_E_FORMATETC\n"));
 | 
						|
  return DV_E_FORMATETC;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_getcanonicalformatetc (LPDATAOBJECT This,
 | 
						|
				   LPFORMATETC  pFormatEtcIn,
 | 
						|
				   LPFORMATETC  pFormatEtcOut)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %p\n", This));
 | 
						|
 | 
						|
  return E_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_setdata (LPDATAOBJECT This,
 | 
						|
		     LPFORMATETC  pFormatEtc,
 | 
						|
		     LPSTGMEDIUM  pMedium,
 | 
						|
		     BOOL         fRelease)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_setdata %p\n", This));
 | 
						|
 | 
						|
  return E_UNEXPECTED;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_enumformatetc (LPDATAOBJECT     This,
 | 
						|
			   DWORD            dwDirection,
 | 
						|
			   LPENUMFORMATETC *ppEnumFormatEtc)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_enumformatetc %p\n", This));
 | 
						|
 | 
						|
  if (dwDirection != DATADIR_GET)
 | 
						|
    return E_NOTIMPL;
 | 
						|
 | 
						|
  *ppEnumFormatEtc = &enum_formats_new ()->ief;
 | 
						|
  return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_dadvise (LPDATAOBJECT This,
 | 
						|
		     LPFORMATETC  pFormatetc,
 | 
						|
		     DWORD        advf,
 | 
						|
		     LPADVISESINK pAdvSink,
 | 
						|
		     DWORD       *pdwConnection)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_dadvise %p\n", This));
 | 
						|
 | 
						|
  return E_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_dunadvise (LPDATAOBJECT This,
 | 
						|
		       DWORD         dwConnection)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_dunadvise %p\n", This));
 | 
						|
 | 
						|
  return E_FAIL;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
idataobject_enumdadvise (LPDATAOBJECT    This,
 | 
						|
			 LPENUMSTATDATA *ppenumAdvise)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("idataobject_enumdadvise %p\n", This));
 | 
						|
 | 
						|
  return E_FAIL;
 | 
						|
}
 | 
						|
		
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
ienumformatetc_addref (LPENUMFORMATETC This)
 | 
						|
{
 | 
						|
  enum_formats *en = (enum_formats *) This;
 | 
						|
  int ref_count = ++en->ref_count;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("ienumformatetc_addref %p %d\n", This, ref_count));
 | 
						|
 | 
						|
  return ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
ienumformatetc_queryinterface (LPENUMFORMATETC This,
 | 
						|
			       REFIID          riid,
 | 
						|
			       LPVOID         *ppvObject)
 | 
						|
{
 | 
						|
  GDK_NOTE (DND, g_print ("ienumformatetc_queryinterface %p\n", This));
 | 
						|
 | 
						|
  *ppvObject = NULL;
 | 
						|
 | 
						|
  PRINT_GUID (riid);
 | 
						|
  if (IsEqualGUID (riid, &IID_IUnknown))
 | 
						|
    {
 | 
						|
      g_print ("...IUnknown\n");
 | 
						|
      ienumformatetc_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else if (IsEqualGUID (riid, &IID_IEnumFORMATETC))
 | 
						|
    {
 | 
						|
      g_print ("...IEnumFORMATETC\n");
 | 
						|
      ienumformatetc_addref (This);
 | 
						|
      *ppvObject = This;
 | 
						|
      return S_OK;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      g_print ("...Huh?\n");
 | 
						|
      return E_NOINTERFACE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static ULONG STDMETHODCALLTYPE
 | 
						|
ienumformatetc_release (LPENUMFORMATETC This)
 | 
						|
{
 | 
						|
  enum_formats *en = (enum_formats *) This;
 | 
						|
  int ref_count = --en->ref_count;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("ienumformatetc_release %p %d\n", This, ref_count));
 | 
						|
 | 
						|
  if (ref_count == 0)
 | 
						|
    g_free (This);
 | 
						|
 | 
						|
  return ref_count;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
ienumformatetc_next (LPENUMFORMATETC This,
 | 
						|
		     ULONG	     celt,
 | 
						|
		     LPFORMATETC     elts,
 | 
						|
		     ULONG	    *nelt)
 | 
						|
{
 | 
						|
  enum_formats *en = (enum_formats *) This;
 | 
						|
  int i, n;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("ienumformatetc_next %p %d %ld\n", This, en->ix, celt));
 | 
						|
 | 
						|
  n = 0;
 | 
						|
  for (i = 0; i < celt; i++)
 | 
						|
    {
 | 
						|
      if (en->ix >= nformats)
 | 
						|
	break;
 | 
						|
      elts[i] = formats[en->ix++];
 | 
						|
      n++;
 | 
						|
    }
 | 
						|
 | 
						|
  if (nelt != NULL)
 | 
						|
    *nelt = n;
 | 
						|
 | 
						|
  if (n == celt)
 | 
						|
    return S_OK;
 | 
						|
  else
 | 
						|
    return S_FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
ienumformatetc_skip (LPENUMFORMATETC This,
 | 
						|
		     ULONG	     celt)
 | 
						|
{
 | 
						|
  enum_formats *en = (enum_formats *) This;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("ienumformatetc_skip %p %d %ld\n", This, en->ix, celt));
 | 
						|
  en->ix += celt;
 | 
						|
 | 
						|
  return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
ienumformatetc_reset (LPENUMFORMATETC This)
 | 
						|
{
 | 
						|
  enum_formats *en = (enum_formats *) This;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("ienumformatetc_reset %p\n", This));
 | 
						|
 | 
						|
  en->ix = 0;
 | 
						|
 | 
						|
  return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
static HRESULT STDMETHODCALLTYPE
 | 
						|
ienumformatetc_clone (LPENUMFORMATETC  This,
 | 
						|
		      LPENUMFORMATETC *ppEnumFormatEtc)
 | 
						|
{
 | 
						|
  enum_formats *en = (enum_formats *) This;
 | 
						|
  enum_formats *new;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("ienumformatetc_clone %p\n", This));
 | 
						|
 | 
						|
  new = enum_formats_new ();
 | 
						|
 | 
						|
  new->ix = en->ix;
 | 
						|
 | 
						|
  *ppEnumFormatEtc = &new->ief;
 | 
						|
 | 
						|
  return S_OK;
 | 
						|
}
 | 
						|
 | 
						|
static IDropTargetVtbl idt_vtbl = {
 | 
						|
  idroptarget_queryinterface,
 | 
						|
  idroptarget_addref,
 | 
						|
  idroptarget_release,
 | 
						|
  idroptarget_dragenter,
 | 
						|
  idroptarget_dragover,
 | 
						|
  idroptarget_dragleave,
 | 
						|
  idroptarget_drop
 | 
						|
};
 | 
						|
 | 
						|
static IDropSourceVtbl ids_vtbl = {
 | 
						|
  idropsource_queryinterface,
 | 
						|
  idropsource_addref,
 | 
						|
  idropsource_release,
 | 
						|
  idropsource_querycontinuedrag,
 | 
						|
  idropsource_givefeedback
 | 
						|
};
 | 
						|
 | 
						|
static IDataObjectVtbl ido_vtbl = {
 | 
						|
  idataobject_queryinterface,
 | 
						|
  idataobject_addref,
 | 
						|
  idataobject_release,
 | 
						|
  idataobject_getdata,
 | 
						|
  idataobject_getdatahere,
 | 
						|
  idataobject_querygetdata,
 | 
						|
  idataobject_getcanonicalformatetc,
 | 
						|
  idataobject_setdata,
 | 
						|
  idataobject_enumformatetc,
 | 
						|
  idataobject_dadvise,
 | 
						|
  idataobject_dunadvise,
 | 
						|
  idataobject_enumdadvise
 | 
						|
};
 | 
						|
 | 
						|
static IEnumFORMATETCVtbl ief_vtbl = {
 | 
						|
  ienumformatetc_queryinterface,
 | 
						|
  ienumformatetc_addref,
 | 
						|
  ienumformatetc_release,
 | 
						|
  ienumformatetc_next,
 | 
						|
  ienumformatetc_skip,
 | 
						|
  ienumformatetc_reset,
 | 
						|
  ienumformatetc_clone
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static target_drag_context *
 | 
						|
target_context_new (void)
 | 
						|
{
 | 
						|
  target_drag_context *result;
 | 
						|
 | 
						|
  result = g_new0 (target_drag_context, 1);
 | 
						|
 | 
						|
  result->idt.lpVtbl = &idt_vtbl;
 | 
						|
 | 
						|
  result->context = gdk_drag_context_new ();
 | 
						|
  result->context->is_source = FALSE;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("target_context_new: %p\n", result));
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
static source_drag_context *
 | 
						|
source_context_new (void)
 | 
						|
{
 | 
						|
  source_drag_context *result;
 | 
						|
 | 
						|
  result = g_new0 (source_drag_context, 1);
 | 
						|
 | 
						|
  result->ids.lpVtbl = &ids_vtbl;
 | 
						|
 | 
						|
  result->context = gdk_drag_context_new ();
 | 
						|
  result->context->is_source = TRUE;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("source_context_new: %p\n", result));
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
static data_object *
 | 
						|
data_object_new (void)
 | 
						|
{
 | 
						|
  data_object *result;
 | 
						|
 | 
						|
  result = g_new0 (data_object, 1);
 | 
						|
 | 
						|
  result->ido.lpVtbl = &ido_vtbl;
 | 
						|
  result->ref_count = 1;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("data_object_new: %p\n", result));
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static enum_formats *
 | 
						|
enum_formats_new (void)
 | 
						|
{
 | 
						|
  enum_formats *result;
 | 
						|
 | 
						|
  result = g_new0 (enum_formats, 1);
 | 
						|
 | 
						|
  result->ief.lpVtbl = &ief_vtbl;
 | 
						|
  result->ref_count = 1;
 | 
						|
  result->ix = 0;
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("enum_formats_new: %p\n", result));
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
/* From MS Knowledge Base article Q130698 */
 | 
						|
 | 
						|
static gboolean
 | 
						|
resolve_link (HWND     hWnd,
 | 
						|
	      wchar_t *link,
 | 
						|
	      gchar  **lpszPath)
 | 
						|
{
 | 
						|
  WIN32_FILE_ATTRIBUTE_DATA wfad;
 | 
						|
  HRESULT hres;
 | 
						|
  IShellLinkW *pslW = NULL;
 | 
						|
  IPersistFile *ppf = NULL;
 | 
						|
 | 
						|
  /* Check if the file is empty first because IShellLink::Resolve for
 | 
						|
   * some reason succeeds with an empty file and returns an empty
 | 
						|
   * "link target". (#524151)
 | 
						|
   */
 | 
						|
    if (!GetFileAttributesExW (link, GetFileExInfoStandard, &wfad) ||
 | 
						|
	(wfad.nFileSizeHigh == 0 && wfad.nFileSizeLow == 0))
 | 
						|
      return FALSE;
 | 
						|
 | 
						|
  /* Assume failure to start with: */
 | 
						|
  *lpszPath = 0;
 | 
						|
 | 
						|
  /* Call CoCreateInstance to obtain the IShellLink interface
 | 
						|
   * pointer. This call fails if CoInitialize is not called, so it is
 | 
						|
   * assumed that CoInitialize has been called.
 | 
						|
   */
 | 
						|
 | 
						|
  hres = CoCreateInstance (&CLSID_ShellLink,
 | 
						|
			   NULL,
 | 
						|
			   CLSCTX_INPROC_SERVER,
 | 
						|
			   &IID_IShellLinkW,
 | 
						|
			   (LPVOID *)&pslW);
 | 
						|
 | 
						|
  if (SUCCEEDED (hres))
 | 
						|
   {
 | 
						|
     
 | 
						|
     /* The IShellLink interface supports the IPersistFile
 | 
						|
      * interface. Get an interface pointer to it.
 | 
						|
      */
 | 
						|
     hres = pslW->lpVtbl->QueryInterface (pslW,
 | 
						|
					  &IID_IPersistFile,
 | 
						|
					  (LPVOID *) &ppf);
 | 
						|
   }     
 | 
						|
 | 
						|
  if (SUCCEEDED (hres))
 | 
						|
    {
 | 
						|
      /* Load the file. */
 | 
						|
      hres = ppf->lpVtbl->Load (ppf, link, STGM_READ);
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (SUCCEEDED (hres))
 | 
						|
    {
 | 
						|
      /* Resolve the link by calling the Resolve()
 | 
						|
       * interface function.
 | 
						|
       */
 | 
						|
      hres = pslW->lpVtbl->Resolve (pslW, hWnd, SLR_ANY_MATCH | SLR_NO_UI);
 | 
						|
    }
 | 
						|
 | 
						|
  if (SUCCEEDED (hres))
 | 
						|
    {
 | 
						|
      wchar_t wtarget[MAX_PATH];
 | 
						|
 | 
						|
      hres = pslW->lpVtbl->GetPath (pslW, wtarget, MAX_PATH, NULL, 0);
 | 
						|
      if (SUCCEEDED (hres))
 | 
						|
	*lpszPath = g_utf16_to_utf8 (wtarget, -1, NULL, NULL, NULL);
 | 
						|
    }
 | 
						|
  
 | 
						|
  if (ppf)
 | 
						|
    ppf->lpVtbl->Release (ppf);
 | 
						|
 | 
						|
  if (pslW)
 | 
						|
    pslW->lpVtbl->Release (pslW);
 | 
						|
 | 
						|
  return SUCCEEDED (hres);
 | 
						|
}
 | 
						|
 | 
						|
static GdkFilterReturn
 | 
						|
gdk_dropfiles_filter (GdkXEvent *xev,
 | 
						|
		      GdkEvent  *event,
 | 
						|
		      gpointer   data)
 | 
						|
{
 | 
						|
  GdkDragContext *context;
 | 
						|
  GdkDragContextPrivateWin32 *private;
 | 
						|
  GString *result;
 | 
						|
  MSG *msg = (MSG *) xev;
 | 
						|
  HANDLE hdrop;
 | 
						|
  POINT pt;
 | 
						|
  gint nfiles, i;
 | 
						|
  gchar *fileName, *linkedFile;
 | 
						|
  
 | 
						|
  if (msg->message == WM_DROPFILES)
 | 
						|
    {
 | 
						|
      GDK_NOTE (DND, g_print ("WM_DROPFILES: %p\n", msg->hwnd));
 | 
						|
 | 
						|
      context = gdk_drag_context_new ();
 | 
						|
      private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
 | 
						|
      context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
 | 
						|
      context->is_source = FALSE;
 | 
						|
      context->source_window = _gdk_root;
 | 
						|
      g_object_ref (context->source_window);
 | 
						|
      context->dest_window = event->any.window;
 | 
						|
      g_object_ref (context->dest_window);
 | 
						|
      /* WM_DROPFILES drops are always file names */
 | 
						|
      context->targets =
 | 
						|
	g_list_append (NULL, GUINT_TO_POINTER (_text_uri_list));
 | 
						|
      context->actions = GDK_ACTION_COPY;
 | 
						|
      context->suggested_action = GDK_ACTION_COPY;
 | 
						|
      current_dest_drag = context;
 | 
						|
 | 
						|
      event->dnd.type = GDK_DROP_START;
 | 
						|
      event->dnd.context = current_dest_drag;
 | 
						|
      
 | 
						|
      hdrop = (HANDLE) msg->wParam;
 | 
						|
      DragQueryPoint (hdrop, &pt);
 | 
						|
      ClientToScreen (msg->hwnd, &pt);
 | 
						|
 | 
						|
      event->dnd.x_root = pt.x + _gdk_offset_x;
 | 
						|
      event->dnd.y_root = pt.y + _gdk_offset_y;
 | 
						|
      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++)
 | 
						|
	{
 | 
						|
	  gchar *uri;
 | 
						|
	  wchar_t wfn[MAX_PATH];
 | 
						|
 | 
						|
	  DragQueryFileW (hdrop, i, wfn, MAX_PATH);
 | 
						|
	  fileName = g_utf16_to_utf8 (wfn, -1, NULL, NULL, NULL);
 | 
						|
 | 
						|
	  /* Resolve shortcuts */
 | 
						|
	  if (resolve_link (msg->hwnd, wfn, &linkedFile))
 | 
						|
	    {
 | 
						|
	      uri = g_filename_to_uri (linkedFile, NULL, NULL);
 | 
						|
	      g_free (linkedFile);
 | 
						|
	      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
 | 
						|
	    {
 | 
						|
	      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_free (fileName);
 | 
						|
	  g_string_append (result, "\015\012");
 | 
						|
	}
 | 
						|
      _gdk_dropfiles_store (result->str);
 | 
						|
      g_string_free (result, FALSE);
 | 
						|
 | 
						|
      DragFinish (hdrop);
 | 
						|
      
 | 
						|
      return GDK_FILTER_TRANSLATE;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    return GDK_FILTER_CONTINUE;
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************
 | 
						|
 ************************** Public API ***********************
 | 
						|
 *************************************************************/
 | 
						|
 | 
						|
void
 | 
						|
_gdk_dnd_init (void)
 | 
						|
{
 | 
						|
#ifdef OLE2_DND
 | 
						|
  HRESULT hres;
 | 
						|
  hres = OleInitialize (NULL);
 | 
						|
 | 
						|
  if (! SUCCEEDED (hres))
 | 
						|
    g_error ("OleInitialize failed");
 | 
						|
 | 
						|
  nformats = 2;
 | 
						|
  formats = g_new (FORMATETC, nformats);
 | 
						|
 | 
						|
  formats[0].cfFormat = CF_TEXT;
 | 
						|
  formats[0].ptd = NULL;
 | 
						|
  formats[0].dwAspect = DVASPECT_CONTENT;
 | 
						|
  formats[0].lindex = -1;
 | 
						|
  formats[0].tymed = TYMED_HGLOBAL;
 | 
						|
  
 | 
						|
  formats[1].cfFormat = CF_GDIOBJFIRST;
 | 
						|
  formats[1].ptd = NULL;
 | 
						|
  formats[1].dwAspect = DVASPECT_CONTENT;
 | 
						|
  formats[1].lindex = -1;
 | 
						|
  formats[1].tymed = TYMED_HGLOBAL;
 | 
						|
#endif
 | 
						|
}      
 | 
						|
 | 
						|
void
 | 
						|
_gdk_win32_dnd_exit (void)
 | 
						|
{
 | 
						|
#ifdef OLE2_DND
 | 
						|
  OleUninitialize ();
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
  g_object_ref (new_context->source_window);
 | 
						|
  new_context->dest_window = context->dest_window;
 | 
						|
  g_object_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);
 | 
						|
 | 
						|
      /* Pass ownership of context to the event */
 | 
						|
      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;
 | 
						|
      
 | 
						|
      current_dest_drag = NULL;
 | 
						|
 | 
						|
      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;
 | 
						|
	}
 | 
						|
 | 
						|
      g_object_unref (context->dest_window);
 | 
						|
      context->dest_window = NULL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
GdkDragContext * 
 | 
						|
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;
 | 
						|
  g_object_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;
 | 
						|
  GList *tmp_list;
 | 
						|
  data_object *dobj;
 | 
						|
  HRESULT hResult;
 | 
						|
  DWORD dwEffect;
 | 
						|
  HGLOBAL global;
 | 
						|
  STGMEDIUM medium;
 | 
						|
 | 
						|
  g_return_val_if_fail (window != NULL, NULL);
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
 | 
						|
 | 
						|
  ctx = source_context_new ();
 | 
						|
  ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
 | 
						|
  ctx->context->source_window = window;
 | 
						|
  g_object_ref (window);
 | 
						|
 | 
						|
  tmp_list = g_list_last (targets);
 | 
						|
  ctx->context->targets = NULL;
 | 
						|
  while (tmp_list)
 | 
						|
    {
 | 
						|
      ctx->context->targets = g_list_prepend (ctx->context->targets,
 | 
						|
					      tmp_list->data);
 | 
						|
      tmp_list = tmp_list->prev;
 | 
						|
    }
 | 
						|
 | 
						|
  ctx->context->actions = 0;
 | 
						|
 | 
						|
  dobj = data_object_new ();
 | 
						|
 | 
						|
  global = GlobalAlloc (GMEM_FIXED, sizeof (ctx));
 | 
						|
 | 
						|
  memcpy (&global, ctx, sizeof (ctx));
 | 
						|
 | 
						|
  medium.tymed = TYMED_HGLOBAL;
 | 
						|
  medium.hGlobal = global;
 | 
						|
  medium.pUnkForRelease = NULL;
 | 
						|
 | 
						|
  dobj->ido.lpVtbl->SetData (&dobj->ido, &formats[1], &medium, TRUE);
 | 
						|
 | 
						|
  hResult = DoDragDrop (&dobj->ido, &ctx->ids, DROPEFFECT_MOVE|DROPEFFECT_COPY, &dwEffect);
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("DoDragDrop returned %s\n",
 | 
						|
			  (hResult == DRAGDROP_S_DROP ? "DRAGDROP_S_DROP" :
 | 
						|
			   (hResult == DRAGDROP_S_CANCEL ? "DRAGDROP_S_CANCEL" :
 | 
						|
			    (hResult == E_UNEXPECTED ? "E_UNEXPECTED" :
 | 
						|
			     g_strdup_printf ("%#.8lx", hResult))))));
 | 
						|
 | 
						|
  dobj->ido.lpVtbl->Release (&dobj->ido);
 | 
						|
  ctx->ids.lpVtbl->Release (&ctx->ids);
 | 
						|
 | 
						|
  return ctx->context;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
GdkNativeWindow
 | 
						|
gdk_drag_get_protocol_for_display (GdkDisplay      *display,
 | 
						|
				   GdkNativeWindow  xid,
 | 
						|
				   GdkDragProtocol *protocol)
 | 
						|
{
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  gint x;
 | 
						|
  gint y;
 | 
						|
  HWND ignore;
 | 
						|
  HWND result;
 | 
						|
} find_window_enum_arg;
 | 
						|
 | 
						|
static BOOL CALLBACK
 | 
						|
find_window_enum_proc (HWND   hwnd,
 | 
						|
		       LPARAM lparam)
 | 
						|
{
 | 
						|
  RECT rect;
 | 
						|
  POINT tl, br;
 | 
						|
  find_window_enum_arg *a = (find_window_enum_arg *) lparam;
 | 
						|
 | 
						|
  if (hwnd == a->ignore)
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  if (!IsWindowVisible (hwnd))
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  tl.x = tl.y = 0;
 | 
						|
  ClientToScreen (hwnd, &tl);
 | 
						|
  GetClientRect (hwnd, &rect);
 | 
						|
  br.x = rect.right;
 | 
						|
  br.y = rect.bottom;
 | 
						|
  ClientToScreen (hwnd, &br);
 | 
						|
 | 
						|
  if (a->x >= tl.x && a->y >= tl.y && a->x < br.x && a->y < br.y)
 | 
						|
    {
 | 
						|
      a->result = hwnd;
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gdk_drag_find_window_for_screen (GdkDragContext  *context,
 | 
						|
				 GdkWindow       *drag_window,
 | 
						|
				 GdkScreen       *screen,
 | 
						|
				 gint             x_root,
 | 
						|
				 gint             y_root,
 | 
						|
				 GdkWindow      **dest_window,
 | 
						|
				 GdkDragProtocol *protocol)
 | 
						|
{
 | 
						|
  find_window_enum_arg a;
 | 
						|
 | 
						|
  a.x = x_root - _gdk_offset_x;
 | 
						|
  a.y = y_root - _gdk_offset_y;
 | 
						|
  a.ignore = drag_window ? GDK_WINDOW_HWND (drag_window) : NULL;
 | 
						|
  a.result = NULL;
 | 
						|
 | 
						|
  EnumWindows (find_window_enum_proc, (LPARAM) &a);
 | 
						|
 | 
						|
  if (a.result == NULL)
 | 
						|
    *dest_window = NULL;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      *dest_window = gdk_win32_handle_table_lookup (a.result);
 | 
						|
      if (*dest_window)
 | 
						|
	{
 | 
						|
	  *dest_window = gdk_window_get_toplevel (*dest_window);
 | 
						|
	  g_object_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: %p %+d%+d: %p: %p %d\n",
 | 
						|
		     (drag_window ? GDK_WINDOW_HWND (drag_window) : NULL),
 | 
						|
		     x_root, y_root,
 | 
						|
		     a.result,
 | 
						|
		     (*dest_window ? GDK_WINDOW_HWND (*dest_window) : NULL),
 | 
						|
		     *protocol));
 | 
						|
}
 | 
						|
 | 
						|
gboolean
 | 
						|
gdk_drag_motion (GdkDragContext *context,
 | 
						|
		 GdkWindow      *dest_window,
 | 
						|
		 GdkDragProtocol protocol,
 | 
						|
		 gint            x_root, 
 | 
						|
		 gint            y_root,
 | 
						|
		 GdkDragAction   suggested_action,
 | 
						|
		 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;
 | 
						|
	  g_object_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;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
gdk_drag_drop (GdkDragContext *context,
 | 
						|
	       guint32         time)
 | 
						|
{
 | 
						|
  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
 | 
						|
gdk_drag_abort (GdkDragContext *context,
 | 
						|
		guint32         time)
 | 
						|
{
 | 
						|
  g_return_if_fail (context != NULL);
 | 
						|
 | 
						|
  GDK_NOTE (DND, g_print ("gdk_drag_abort\n"));
 | 
						|
 | 
						|
  gdk_drag_do_leave (context, time);
 | 
						|
}
 | 
						|
 | 
						|
/* Destination side */
 | 
						|
 | 
						|
void
 | 
						|
gdk_drag_status (GdkDragContext *context,
 | 
						|
		 GdkDragAction   action,
 | 
						|
		 guint32         time)
 | 
						|
{
 | 
						|
  GdkDragContextPrivateWin32 *private;
 | 
						|
  GdkDragContext *src_context;
 | 
						|
  GdkEvent tmp_event;
 | 
						|
 | 
						|
  g_return_if_fail (context != NULL);
 | 
						|
 | 
						|
  private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
 | 
						|
 | 
						|
  context->action = action;
 | 
						|
 | 
						|
  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 
 | 
						|
gdk_drop_reply (GdkDragContext *context,
 | 
						|
		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
 | 
						|
gdk_drop_finish (GdkDragContext *context,
 | 
						|
		 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"));
 | 
						|
 | 
						|
  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)
 | 
						|
{
 | 
						|
  MSG *msg = (MSG *) xev;
 | 
						|
 | 
						|
  if (msg->message == WM_DESTROY)
 | 
						|
    {
 | 
						|
      IDropTarget *idtp = (IDropTarget *) data;
 | 
						|
 | 
						|
      GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %p\n", msg->hwnd));
 | 
						|
#if 0
 | 
						|
      idtp->lpVtbl->Release (idtp);
 | 
						|
#endif
 | 
						|
      RevokeDragDrop (msg->hwnd);
 | 
						|
      CoLockObjectExternal (idtp, FALSE, TRUE);
 | 
						|
    }
 | 
						|
  return GDK_FILTER_CONTINUE;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
gdk_window_register_dnd (GdkWindow *window)
 | 
						|
{
 | 
						|
#ifdef OLE2_DND
 | 
						|
  target_drag_context *ctx;
 | 
						|
  HRESULT hres;
 | 
						|
#endif
 | 
						|
 | 
						|
  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: %p\n",
 | 
						|
			  GDK_WINDOW_HWND (window)));
 | 
						|
 | 
						|
  /* We always claim to accept dropped files, but in fact we might not,
 | 
						|
   * of course. This function is called in such a way that it cannot know
 | 
						|
   * whether the window (widget) in question actually accepts files
 | 
						|
   * (in gtk, data of type text/uri-list) or not.
 | 
						|
   */
 | 
						|
  gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
 | 
						|
  DragAcceptFiles (GDK_WINDOW_HWND (window), TRUE);
 | 
						|
 | 
						|
#ifdef OLE2_DND
 | 
						|
  /* Register for OLE2 d&d */
 | 
						|
  ctx = target_context_new ();
 | 
						|
  ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
 | 
						|
  hres = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
 | 
						|
  if (!SUCCEEDED (hres))
 | 
						|
    OTHER_API_FAILED ("CoLockObjectExternal");
 | 
						|
  else
 | 
						|
    {
 | 
						|
      hres = RegisterDragDrop (GDK_WINDOW_HWND (window), &ctx->idt);
 | 
						|
      if (hres == DRAGDROP_E_ALREADYREGISTERED)
 | 
						|
	{
 | 
						|
	  g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
 | 
						|
#if 0
 | 
						|
	  ctx->idt.lpVtbl->Release (&ctx->idt);
 | 
						|
#endif
 | 
						|
	  CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
 | 
						|
	}
 | 
						|
      else if (!SUCCEEDED (hres))
 | 
						|
	OTHER_API_FAILED ("RegisterDragDrop");
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  gdk_window_add_filter (window, gdk_destroy_filter, &ctx->idt);
 | 
						|
	}
 | 
						|
    }
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/*************************************************************
 | 
						|
 * gdk_drag_get_selection:
 | 
						|
 *     Returns the selection atom for the current source window
 | 
						|
 *   arguments:
 | 
						|
 *
 | 
						|
 *   results:
 | 
						|
 *************************************************************/
 | 
						|
 | 
						|
GdkAtom
 | 
						|
gdk_drag_get_selection (GdkDragContext *context)
 | 
						|
{
 | 
						|
  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;
 | 
						|
  else
 | 
						|
    return GDK_NONE;
 | 
						|
}
 | 
						|
 | 
						|
gboolean 
 | 
						|
gdk_drag_drop_succeeded (GdkDragContext *context)
 | 
						|
{
 | 
						|
  GdkDragContextPrivateWin32 *private;
 | 
						|
 | 
						|
  g_return_val_if_fail (context != NULL, FALSE);
 | 
						|
 | 
						|
  private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
 | 
						|
 | 
						|
  /* FIXME: Can we set drop_failed when the drop has failed? */
 | 
						|
  return !private->drop_failed;
 | 
						|
}
 |