changeset 92:ddb19cb18d2e

package dnd
author Frank Benoit <benoit@tionex.de>
date Fri, 18 Jan 2008 00:34:32 +0100
parents b58ec55ce70d
children c3d44df6708f
files dwt/dnd/ByteArrayTransfer.d dwt/dnd/Clipboard.d dwt/dnd/ClipboardProxy.d dwt/dnd/DND.d dwt/dnd/DNDEvent.d dwt/dnd/DNDListener.d dwt/dnd/DragSource.d dwt/dnd/DragSourceAdapter.d dwt/dnd/DragSourceEffect.d dwt/dnd/DragSourceEvent.d dwt/dnd/DragSourceListener.d dwt/dnd/DropTarget.d dwt/dnd/DropTargetAdapter.d dwt/dnd/DropTargetEffect.d dwt/dnd/DropTargetEvent.d dwt/dnd/DropTargetListener.d dwt/dnd/FileTransfer.d dwt/dnd/HTMLTransfer.d dwt/dnd/RTFTransfer.d dwt/dnd/TableDragSourceEffect.d dwt/dnd/TableDropTargetEffect.d dwt/dnd/TextTransfer.d dwt/dnd/Transfer.d dwt/dnd/TransferData.d dwt/dnd/TreeDragSourceEffect.d dwt/dnd/TreeDropTargetEffect.d dwt/dwthelper/System.d dwt/dwthelper/utils.d dwt/graphics/Image.d dwt/internal/gtk/OS.d
diffstat 30 files changed, 5384 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/ByteArrayTransfer.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.ByteArrayTransfer;
+
+import dwt.internal.gtk.OS;
+import dwt.dnd.Transfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+import dwt.dwthelper.utils;
+
+/**
+ * The class <code>ByteArrayTransfer</code> provides a platform specific
+ * mechanism for converting a java <code>byte[]</code> to a platform
+ * specific representation of the byte array and vice versa.  See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p><code>ByteArrayTransfer</code> is never used directly but is sub-classed
+ * by transfer agents that convert between data in a java format such as a
+ * <code>String</code> and a platform specific byte array.
+ *
+ * <p>If the data you are converting <b>does not</b> map to a
+ * <code>byte[]</code>, you should sub-class <code>Transfer</code> directly
+ * and do your own mapping to a platform data type.</p>
+ *
+ * <p>The following snippet shows a subclass of ByteArrayTransfer that transfers
+ * data defined by the class <code>MyType</code>.</p>
+ *
+ * <pre><code>
+ * public class MyType {
+ *  public String fileName;
+ *  public long fileLength;
+ *  public long lastModified;
+ * }
+ * </code></pre>
+ *
+ * <pre><code>
+ * public class MyTypeTransfer extends ByteArrayTransfer {
+ *
+ *  private static final String MYTYPENAME = "my_type_name";
+ *  private static final int MYTYPEID = registerType(MYTYPENAME);
+ *  private static MyTypeTransfer _instance = new MyTypeTransfer();
+ *
+ * private MyTypeTransfer() {}
+ *
+ * public static MyTypeTransfer getInstance () {
+ *  return _instance;
+ * }
+ * public void javaToNative (Object object, TransferData transferData) {
+ *  if (object is null || !(object instanceof MyType[])) return;
+ *
+ *  if (isSupportedType(transferData)) {
+ *      MyType[] myTypes = (MyType[]) object;
+ *      try {
+ *          // write data to a byte array and then ask super to convert to pMedium
+ *          ByteArrayOutputStream out = new ByteArrayOutputStream();
+ *          DataOutputStream writeOut = new DataOutputStream(out);
+ *          for (int i = 0, length = myTypes.length; i &lt; length;  i++){
+ *              byte[] buffer = myTypes[i].fileName.getBytes();
+ *              writeOut.writeInt(buffer.length);
+ *              writeOut.write(buffer);
+ *              writeOut.writeLong(myTypes[i].fileLength);
+ *              writeOut.writeLong(myTypes[i].lastModified);
+ *          }
+ *          byte[] buffer = out.toByteArray();
+ *          writeOut.close();
+ *
+ *          super.javaToNative(buffer, transferData);
+ *
+ *      } catch (IOException e) {
+ *      }
+ *  }
+ * }
+ * public Object nativeToJava(TransferData transferData){
+ *
+ *  if (isSupportedType(transferData)) {
+ *
+ *      byte[] buffer = (byte[])super.nativeToJava(transferData);
+ *      if (buffer is null) return null;
+ *
+ *      MyType[] myData = new MyType[0];
+ *      try {
+ *          ByteArrayInputStream in = new ByteArrayInputStream(buffer);
+ *          DataInputStream readIn = new DataInputStream(in);
+ *          while(readIn.available() > 20) {
+ *              MyType datum = new MyType();
+ *              int size = readIn.readInt();
+ *              byte[] name = new byte[size];
+ *              readIn.read(name);
+ *              datum.fileName = new String(name);
+ *              datum.fileLength = readIn.readLong();
+ *              datum.lastModified = readIn.readLong();
+ *              MyType[] newMyData = new MyType[myData.length + 1];
+ *              System.arraycopy(myData, 0, newMyData, 0, myData.length);
+ *              newMyData[myData.length] = datum;
+ *              myData = newMyData;
+ *          }
+ *          readIn.close();
+ *      } catch (IOException ex) {
+ *          return null;
+ *      }
+ *      return myData;
+ *  }
+ *
+ *  return null;
+ * }
+ * protected String[] getTypeNames(){
+ *  return new String[]{MYTYPENAME};
+ * }
+ * protected int[] getTypeIds(){
+ *  return new int[] {MYTYPEID};
+ * }
+ * }
+ * </code></pre>
+ */
+public abstract class ByteArrayTransfer : Transfer {
+
+public TransferData[] getSupportedTypes() {
+    int[] types = getTypeIds();
+    TransferData[] data = new TransferData[types.length];
+    for (int i = 0; i < types.length; i++) {
+        data[i] = new TransferData();
+        data[i].type = cast(void*)types[i];
+    }
+    return data;
+}
+
+public bool isSupportedType(TransferData transferData){
+    if (transferData is null) return false;
+    int[] types = getTypeIds();
+    for (int i = 0; i < types.length; i++) {
+        if (transferData.type is cast(void*)types[i]) return true;
+    }
+    return false;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a java
+ * <code>byte[]</code> to a platform specific representation.  For additional
+ * information see <code>Transfer#javaToNative</code>.
+ *
+ * @see Transfer#javaToNative
+ *
+ * @param object a java <code>byte[]</code> containing the data to be converted
+ * @param transferData an empty <code>TransferData</code> object; this
+ *  object will be filled in on return with the platform specific format of the data
+ */
+protected void javaToNative (Object object, TransferData transferData) {
+    transferData.result = 0;
+    if (!checkByteArray(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    byte[] buffer = (cast(ArrayWrapperByte)object).array;
+    if (buffer.length is 0) return;
+    byte* pValue = cast(byte*)OS.g_malloc(buffer.length);
+    if (pValue is null) return;
+    pValue[ 0 .. buffer.length ] = buffer;
+    transferData.length = buffer.length;
+    transferData.format = 8;
+    transferData.pValue = cast(char*)pValue;
+    transferData.result = 1;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a byte array to a java <code>byte[]</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @see Transfer#nativeToJava
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>byte[]</code> containing the converted data if the
+ * conversion was successful; otherwise null
+ */
+protected Object nativeToJava(TransferData transferData) {
+    if ( !isSupportedType(transferData) || transferData.pValue is null) return null;
+    int size = transferData.format * transferData.length / 8;
+    if (size is 0) return null;
+    byte* ptr = cast(byte*)transferData.pValue;
+    return new ArrayWrapperByte( ptr[ 0 .. size ].dup );
+}
+
+bool checkByteArray(Object object) {
+    if( object is null ) return false;
+    ArrayWrapperByte arr = cast(ArrayWrapperByte)object;
+    if( arr is null ) return false;
+    return arr.array.length > 0;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/Clipboard.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,623 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.Clipboard;
+
+
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.internal.Converter;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Display;
+import dwt.dnd.Transfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+import dwt.dnd.ClipboardProxy;
+
+import dwt.dwthelper.utils;
+
+import tango.core.Thread;
+static import tango.stdc.stringz;
+static import tango.stdc.string;
+
+/**
+ * The <code>Clipboard</code> provides a mechanism for transferring data from one
+ * application to another or within an application.
+ *
+ * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
+ */
+public class Clipboard {
+
+    private Display display;
+
+    static void* GTKCLIPBOARD;
+    static void* GTKPRIMARYCLIPBOARD;
+    private static void* TARGET;
+
+    static this(){
+        GTKCLIPBOARD = OS.gtk_clipboard_get( cast(void*)OS.GDK_NONE);
+        auto primary = OS.gdk_atom_intern("PRIMARY".ptr, false);
+        GTKPRIMARYCLIPBOARD = OS.gtk_clipboard_get(primary);
+        TARGET = OS.gdk_atom_intern("TARGETS".ptr, false);
+    }
+
+/**
+ * Constructs a new instance of this class.  Creating an instance of a Clipboard
+ * may cause system resources to be allocated depending on the platform.  It is therefore
+ * mandatory that the Clipboard instance be disposed when no longer required.
+ *
+ * @param display the display on which to allocate the clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see Clipboard#dispose
+ * @see Clipboard#checkSubclass
+ */
+public this(Display display) {
+    checkSubclass ();
+    if (display is null) {
+        display = Display.getCurrent();
+        if (display is null) {
+            display = Display.getDefault();
+        }
+    }
+    if (display.getThread() !is Thread.getThis()) {
+        DND.error(DWT.ERROR_THREAD_INVALID_ACCESS);
+    }
+    this.display = display;
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * <p>
+ * The DWT class library is intended to be subclassed
+ * only at specific, controlled points. This method enforces this
+ * rule unless it is overridden.
+ * </p><p>
+ * <em>IMPORTANT:</em> By providing an implementation of this
+ * method that allows a subclass of a class which does not
+ * normally allow subclassing to be created, the implementer
+ * agrees to be fully responsible for the fact that any such
+ * subclass will likely fail between DWT releases and will be
+ * strongly platform specific. No support is provided for
+ * user-written classes which are implemented in this fashion.
+ * </p><p>
+ * The ability to subclass outside of the allowed DWT classes
+ * is intended purely to enable those not on the DWT development
+ * team to implement patches in order to get around specific
+ * limitations in advance of when those limitations can be
+ * addressed by the team. Subclassing should not be attempted
+ * without an intimate and detailed understanding of the hierarchy.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ */
+protected void checkSubclass () {
+    char[] name = this.classinfo.name;
+    char[] validName = Clipboard.stringof;
+    if ( validName !=/*eq*/ name ) {
+        DND.error (DWT.ERROR_INVALID_SUBCLASS);
+    }
+}
+/**
+ * Throws an <code>DWTException</code> if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method <em>should</em> be called by
+ * widget implementors to enforce the standard DWT invariants.
+ * <p>
+ * Currently, it is an error to invoke any method (other than
+ * <code>isDisposed()</code>) on a widget that has had its
+ * <code>dispose()</code> method called. It is also an error
+ * to call widget methods from any thread that is different
+ * from the thread that created the widget.
+ * </p><p>
+ * In future releases of DWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+protected void checkWidget () {
+    Display display = this.display;
+    if (display is null) DND.error (DWT.ERROR_WIDGET_DISPOSED);
+    if (display.getThread() !is Thread.getThis ()) DND.error (DWT.ERROR_THREAD_INVALID_ACCESS);
+    if (display.isDisposed()) DND.error(DWT.ERROR_WIDGET_DISPOSED);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the system clipboard,
+ * clear the contents.  If this clipboard is not the owner, then nothing is done.
+ * Note that there are clipboard assistant applications that take ownership of
+ * data or make copies of data when it is placed on the clipboard.  In these
+ * cases, it may not be possible to clear the clipboard.
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void clearContents() {
+    clearContents(DND.CLIPBOARD);
+}
+
+/**
+ * If this clipboard is currently the owner of the data on the specified
+ * clipboard, clear the contents.  If this clipboard is not the owner, then
+ * nothing is done.
+ *
+ * <p>Note that there are clipboard assistant applications that take ownership
+ * of data or make copies of data when it is placed on the clipboard.  In these
+ * cases, it may not be possible to clear the clipboard.</p>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param clipboards to be cleared
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public void clearContents(int clipboards) {
+    checkWidget();
+    ClipboardProxy proxy = ClipboardProxy._getInstance(display);
+    proxy.clear(this, clipboards);
+}
+
+/**
+ * Disposes of the operating system resources associated with the clipboard.
+ * The data will still be available on the system clipboard after the dispose
+ * method is called.
+ *
+ * <p>NOTE: On some platforms the data will not be available once the application
+ * has exited or the display has been disposed.</p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ */
+public void dispose () {
+    if (isDisposed()) return;
+    if (display.getThread() !is Thread.getThis()) DND.error(DWT.ERROR_THREAD_INVALID_ACCESS);
+    display = null;
+}
+
+/**
+ * Retrieve the data of the specified type currently available on the system
+ * clipboard.  Refer to the specific subclass of <code>Transfer</code> to
+ * determine the type of object returned.
+ *
+ * <p>The following snippet shows text and RTF text being retrieved from the
+ * clipboard:</p>
+ *
+ *    <code><pre>
+ *    Clipboard clipboard = new Clipboard(display);
+ *    TextTransfer textTransfer = TextTransfer.getInstance();
+ *    String textData = (String)clipboard.getContents(textTransfer);
+ *    if (textData !is null) System.out.println("Text is "+textData);
+ *    RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *    String rtfData = (String)clipboard.getContents(rtfTransfer);
+ *    if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
+ *    clipboard.dispose();
+ *    </code></pre>
+ *
+ * @param transfer the transfer agent for the type of data being requested
+ * @return the data obtained from the clipboard or null if no data of this type is available
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
+ * </ul>
+ *
+ * @see Transfer
+ */
+public Object getContents(Transfer transfer) {
+    return getContents(transfer, DND.CLIPBOARD);
+}
+
+/**
+ * Retrieve the data of the specified type currently available on the specified
+ * clipboard.  Refer to the specific subclass of <code>Transfer</code> to
+ * determine the type of object returned.
+ *
+ * <p>The following snippet shows text and RTF text being retrieved from the
+ * clipboard:</p>
+ *
+ *    <code><pre>
+ *    Clipboard clipboard = new Clipboard(display);
+ *    TextTransfer textTransfer = TextTransfer.getInstance();
+ *    String textData = (String)clipboard.getContents(textTransfer);
+ *    if (textData !is null) System.out.println("Text is "+textData);
+ *    RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *    String rtfData = (String)clipboard.getContents(rtfTransfer, DND.CLIPBOARD);
+ *    if (rtfData !is null) System.out.println("RTF Text is "+rtfData);
+ *    clipboard.dispose();
+ *    </code></pre>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param transfer the transfer agent for the type of data being requested
+ * @param clipboards on which to look for data
+ *
+ * @return the data obtained from the clipboard or null if no data of this type is available
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if transfer is null</li>
+ * </ul>
+ *
+ * @see Transfer
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public Object getContents(Transfer transfer, int clipboards) {
+    checkWidget();
+    if (transfer is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
+    GtkSelectionData* selection_data;
+    auto typeIds = transfer.getTypeIds();
+    for (int i = 0; i < typeIds.length; i++) {
+        if ((clipboards & DND.CLIPBOARD) !is 0) {
+            selection_data = gtk_clipboard_wait_for_contents(GTKCLIPBOARD, cast(void*)typeIds[i]);
+        }
+        if (selection_data !is null) break;
+        if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) {
+            selection_data = gtk_clipboard_wait_for_contents(GTKPRIMARYCLIPBOARD, cast(void*)typeIds[i]);
+        }
+    }
+    if (selection_data is null) return null;
+    GtkSelectionData* gtkSelectionData = selection_data;
+    TransferData tdata = new TransferData();
+    tdata.type = gtkSelectionData.type;
+    tdata.pValue = gtkSelectionData.data;
+    tdata.length = gtkSelectionData.length;
+    tdata.format = gtkSelectionData.format;
+    Object result = transfer.nativeToJava(tdata);
+    OS.gtk_selection_data_free(selection_data);
+    return result;
+}
+
+/**
+ * Returns <code>true</code> if the clipboard has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the clipboard.
+ * When a clipboard has been disposed, it is an error to
+ * invoke any other method using the clipboard.
+ * </p>
+ *
+ * @return <code>true</code> when the widget is disposed and <code>false</code> otherwise
+ *
+ * @since 3.0
+ */
+public bool isDisposed () {
+    return (display is null);
+}
+
+/**
+ * Place data of the specified type on the system clipboard.  More than one type
+ * of data can be placed on the system clipboard at the same time.  Setting the
+ * data clears any previous data from the system clipboard, regardless of type.
+ *
+ * <p>NOTE: On some platforms, the data is immediately copied to the system
+ * clipboard but on other platforms it is provided upon request.  As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested.</p>
+ *
+ * <p>The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * </p>
+ *
+ * <code><pre>
+ *  Clipboard clipboard = new Clipboard(display);
+ *  String textData = "Hello World";
+ *  String rtfData = "{\\rtf1\\b\\i Hello World}";
+ *  TextTransfer textTransfer = TextTransfer.getInstance();
+ *  RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *  Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ *  Object[] data = new Object[]{textData, rtfData};
+ *  clipboard.setContents(data, transfers);
+ *  clipboard.dispose();
+ * </code></pre>
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
+ *          or the length of data is not the same as the length of dataTypes</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *  @exception DWTError <ul>
+ *    <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ */
+public void setContents(Object[] data, Transfer[] dataTypes) {
+    setContents(data, dataTypes, DND.CLIPBOARD);
+}
+
+/**
+ * Place data of the specified type on the specified clipboard.  More than one
+ * type of data can be placed on the specified clipboard at the same time.
+ * Setting the data clears any previous data from the specified
+ * clipboard, regardless of type.
+ *
+ * <p>NOTE: On some platforms, the data is immediately copied to the specified
+ * clipboard but on other platforms it is provided upon request.  As a result,
+ * if the application modifies the data object it has set on the clipboard, that
+ * modification may or may not be available when the data is subsequently
+ * requested.</p>
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * <p>The following snippet shows text and RTF text being set on the copy/paste
+ * clipboard:
+ * </p>
+ *
+ * <code><pre>
+ *  Clipboard clipboard = new Clipboard(display);
+ *  String textData = "Hello World";
+ *  String rtfData = "{\\rtf1\\b\\i Hello World}";
+ *  TextTransfer textTransfer = TextTransfer.getInstance();
+ *  RTFTransfer rtfTransfer = RTFTransfer.getInstance();
+ *  Transfer[] transfers = new Transfer[]{textTransfer, rtfTransfer};
+ *  Object[] data = new Object[]{textData, rtfData};
+ *  clipboard.setContents(data, transfers, DND.CLIPBOARD);
+ *  clipboard.dispose();
+ * </code></pre>
+ *
+ * @param data the data to be set in the clipboard
+ * @param dataTypes the transfer agents that will convert the data to its
+ * platform specific format; each entry in the data array must have a
+ * corresponding dataType
+ * @param clipboards on which to set the data
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if data is null or datatypes is null
+ *          or the length of data is not the same as the length of dataTypes</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *  @exception DWTError <ul>
+ *    <li>ERROR_CANNOT_SET_CLIPBOARD - if the clipboard is locked or otherwise unavailable</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_SET_CLIPBOARD should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public void setContents(Object[] data, Transfer[] dataTypes, int clipboards) {
+    checkWidget();
+    if (data is null || dataTypes is null || data.length !is dataTypes.length || data.length is 0) {
+        DND.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    for (int i = 0; i < data.length; i++) {
+        if (data[i] is null || dataTypes[i] is null || !dataTypes[i].validate(data[i])) {
+            DND.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+    }
+    ClipboardProxy proxy = ClipboardProxy._getInstance(display);
+    if (!proxy.setData(this, data, dataTypes, clipboards)) {
+        DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD);
+    }
+}
+
+/**
+ * Returns an array of the data types currently available on the system
+ * clipboard. Use with Transfer.isSupportedType.
+ *
+ * @return array of data types currently available on the system clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Transfer#isSupportedType
+ *
+ * @since 3.0
+ */
+public TransferData[] getAvailableTypes() {
+    return getAvailableTypes(DND.CLIPBOARD);
+}
+
+/**
+ * Returns an array of the data types currently available on the specified
+ * clipboard. Use with Transfer.isSupportedType.
+ *
+ * <p>The clipboards value is either one of the clipboard constants defined in
+ * class <code>DND</code>, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> clipboard constants.</p>
+ *
+ * @param clipboards from which to get the data types
+ * @return array of data types currently available on the specified clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Transfer#isSupportedType
+ * @see DND#CLIPBOARD
+ * @see DND#SELECTION_CLIPBOARD
+ *
+ * @since 3.1
+ */
+public TransferData[] getAvailableTypes(int clipboards) {
+    checkWidget();
+    TransferData[] result = null;
+    if ((clipboards & DND.CLIPBOARD) !is 0) {
+        auto types = getAvailableClipboardTypes();
+        result = new TransferData[types.length];
+        for (int i = 0; i < types.length; i++) {
+            result[i] = new TransferData();
+            result[i].type = types[i];
+        }
+    }
+    if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) {
+        auto types = getAvailablePrimaryTypes();
+        int offset = 0;
+        if (result !is null) {
+            TransferData[] newResult = new TransferData[result.length + types.length];
+            System.arraycopy(result,0, newResult, 0, result.length);
+            offset = result.length;
+            result = newResult;
+        } else {
+            result = new TransferData[types.length];
+        }
+        for (int i = 0; i < types.length; i++) {
+            result[offset+i] = new TransferData();
+            result[offset+i].type = types[i];
+        }
+    }
+    return result is null ? new TransferData[0] : result;
+}
+
+/**
+ * Returns a platform specific list of the data types currently available on the
+ * system clipboard.
+ *
+ * <p>Note: <code>getAvailableTypeNames</code> is a utility for writing a Transfer
+ * sub-class.  It should NOT be used within an application because it provides
+ * platform specific information.</p>
+ *
+ * @return a platform specific list of the data types currently available on the
+ * system clipboard
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public char[][] getAvailableTypeNames() {
+    checkWidget();
+    auto types1 = getAvailableClipboardTypes();
+    auto types2 = getAvailablePrimaryTypes();
+    char[][] result = new char[][types1.length + types2.length];
+    int count = 0;
+    for (int i = 0; i < types1.length; i++) {
+        auto pName = OS.gdk_atom_name(types1[i]);
+        if (pName is null) {
+            continue;
+        }
+        char[] buffer = tango.stdc.stringz.fromUtf8z( pName ).dup;
+        OS.g_free (pName);
+        result[count++] = "GTKCLIPBOARD "~buffer;
+    }
+    for (int i = 0; i < types2.length; i++) {
+        auto pName = OS.gdk_atom_name(types2[i]);
+        if (pName is null) {
+            continue;
+        }
+        char[] buffer = tango.stdc.stringz.fromUtf8z( pName ).dup;
+        OS.g_free (pName);
+        result[count++] = "GTKPRIMARYCLIPBOARD "~buffer;
+    }
+    if (count < result.length){
+        char[][] temp = new char[][count];
+        System.arraycopy(result, 0, temp, 0, count);
+        result = temp;
+    }
+    return result;
+}
+
+private  void*[] getAvailablePrimaryTypes() {
+    void*[] types;
+    auto selection_data = gtk_clipboard_wait_for_contents(GTKPRIMARYCLIPBOARD, TARGET);
+    if (selection_data !is null) {
+        try {
+            GtkSelectionData* gtkSelectionData = selection_data;
+            if (gtkSelectionData.length !is 0) {
+                types = cast(void*[])new int[gtkSelectionData.length * 8 / gtkSelectionData.format];
+                tango.stdc.string.memmove( cast(void*)types.ptr, gtkSelectionData.data, gtkSelectionData.length );
+            }
+        } finally {
+            OS.gtk_selection_data_free(selection_data);
+        }
+    }
+    return types;
+}
+private void*[] getAvailableClipboardTypes () {
+    void*[] types;
+    auto selection_data  = gtk_clipboard_wait_for_contents(GTKCLIPBOARD, TARGET);
+    if (selection_data !is null) {
+        try {
+            GtkSelectionData* gtkSelectionData = selection_data;
+            if (gtkSelectionData.length !is 0) {
+                types = cast(void*[])new int[gtkSelectionData.length * 8 / gtkSelectionData.format];
+                tango.stdc.string.memmove( cast(void*)types, gtkSelectionData.data, gtkSelectionData.length);
+            }
+        } finally {
+            OS.gtk_selection_data_free(selection_data);
+        }
+    }
+    return types;
+}
+
+GtkSelectionData* gtk_clipboard_wait_for_contents(void* clipboard, void* target) {
+    char[] key = "org.eclipse.swt.internal.gtk.dispatchEvent";
+    Display display = this.display;
+    ArrayWrapperInt arr = new ArrayWrapperInt( [ OS.GDK_PROPERTY_NOTIFY, OS.GDK_SELECTION_CLEAR, OS.GDK_SELECTION_REQUEST, OS.GDK_SELECTION_NOTIFY ] );
+    display.setData(key, arr );
+    GtkSelectionData* selection_data = OS.gtk_clipboard_wait_for_contents(clipboard, target);
+    display.setData(key, null);
+    return selection_data;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/ClipboardProxy.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.ClipboardProxy;
+
+
+
+import dwt.DWT;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.dnd.Transfer;
+import dwt.dnd.Clipboard;
+import dwt.dnd.DND;
+import dwt.dnd.TransferData;
+
+import dwt.dwthelper.System;
+static import tango.stdc.string;
+
+
+class ClipboardProxy {
+    /* Data is not flushed to the clipboard immediately.
+     * This class will remember the data and provide it when requested.
+     */
+    Object[] clipboardData;
+    Transfer[] clipboardDataTypes;
+    Object[] primaryClipboardData;
+    Transfer[] primaryClipboardDataTypes;
+
+    Display display;
+    Clipboard activeClipboard = null;
+    Clipboard activePrimaryClipboard = null;
+
+    static char[] ID = "CLIPBOARD PROXY OBJECT"; //$NON-NLS-1$
+
+static ClipboardProxy _getInstance(Display display) {
+    ClipboardProxy proxy = cast(ClipboardProxy) display.getData(ID);
+    if (proxy !is null) return proxy;
+    proxy = new ClipboardProxy(display);
+    display.setData(ID, proxy);
+    display.addListener(DWT.Dispose, new class( display ) Listener {
+        Display disp;
+        this( Display disp ){ this.disp = disp; }
+        public void handleEvent(Event event) {
+            ClipboardProxy clipbordProxy = cast(ClipboardProxy)disp.getData(ID);
+            if (clipbordProxy is null) return;
+            display.setData(ID, null);
+            clipbordProxy.dispose();
+        }
+    });
+    return proxy;
+}
+
+this(Display display) {
+    this.display = display;
+}
+
+void clear (Clipboard owner, int clipboards) {
+    if ((clipboards & DND.CLIPBOARD) !is 0 && activeClipboard is owner) {
+        OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD);
+    }
+    if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0 && activePrimaryClipboard is owner) {
+        OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD);
+    }
+}
+
+private static extern(C) void clearFuncFunc(GtkClipboard *clipboard, void* user_data_or_owner){
+    auto obj = cast(ClipboardProxy)user_data_or_owner;
+    obj.clearFunc( clipboard );
+}
+void clearFunc(GtkClipboard *clipboard ){
+    if (clipboard is Clipboard.GTKCLIPBOARD) {
+        activeClipboard = null;
+        clipboardData = null;
+        clipboardDataTypes = null;
+    }
+    if (clipboard is Clipboard.GTKPRIMARYCLIPBOARD) {
+        activePrimaryClipboard = null;
+        primaryClipboardData = null;
+        primaryClipboardDataTypes = null;
+    }
+}
+
+void dispose () {
+    if (display is null) return;
+    if (activeClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD);
+    if (activePrimaryClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD);
+    display = null;
+    clipboardData = null;
+    clipboardDataTypes = null;
+    primaryClipboardData = null;
+    primaryClipboardDataTypes = null;
+}
+
+private static extern(C) void getFuncFunc(
+    GtkClipboard *clipboard,
+    GtkSelectionData *selection_data,
+    uint info,
+    void* user_data_or_owner)
+{
+    auto obj = cast(ClipboardProxy)user_data_or_owner;
+    obj.getFunc( clipboard, selection_data, info );
+}
+/**
+ * This function provides the data to the clipboard on request.
+ * When this clipboard is disposed, the data will no longer be available.
+ */
+void getFunc(
+    GtkClipboard *clipboard,
+    GtkSelectionData *selectionData,
+    uint info)
+{
+    if (selectionData is null) return 0;
+    TransferData tdata = new TransferData();
+    tdata.type = selectionData.target;
+    Transfer[] types = (clipboard is Clipboard.GTKCLIPBOARD) ? clipboardDataTypes : primaryClipboardDataTypes;
+    int index = -1;
+    for (int i = 0; i < types.length; i++) {
+        if (types[i].isSupportedType(tdata)) {
+            index = i;
+            break;
+        }
+    }
+    if (index is -1) return 0;
+    Object[] data = (clipboard is Clipboard.GTKCLIPBOARD) ? clipboardData : primaryClipboardData;
+    types[index].javaToNative(data[index], tdata);
+    if (tdata.format < 8 || tdata.format % 8 !is 0) {
+        return 0;
+    }
+    OS.gtk_selection_data_set(selectionData, tdata.type, tdata.format, tdata.pValue, tdata.length);
+    OS.g_free(tdata.pValue);
+    return 1;
+}
+
+bool setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) {
+    GtkTargetEntry*[] entries;
+    GtkTargetEntry* pTargetsList;
+    try {
+        for (int i = 0; i < dataTypes.length; i++) {
+            Transfer transfer = dataTypes[i];
+            int[] typeIds = transfer.getTypeIds();
+            char[][] typeNames = transfer.getTypeNames();
+            for (int j = 0; j < typeIds.length; j++) {
+                GtkTargetEntry*  entry = new GtkTargetEntry();
+                entry.info = typeIds[j];
+                char* pName = cast(char*)OS.g_malloc(typeNames[j].length+1);
+                pName[ 0 .. typeNames[j].length ] = typeNames[j];
+                pName[ typeNames[j].length ] = '\0';
+                entry.target = pName;
+                GtkTargetEntry*[] tmp = new GtkTargetEntry*[entries.length + 1];
+                SimpleType!(GtkTargetEntry*).arraycopy(entries, 0, tmp, 0, entries.length);
+                tmp[entries.length] = entry;
+                entries = tmp;
+            }
+        }
+
+        pTargetsList = cast(GtkTargetEntry*)OS.g_malloc(GtkTargetEntry.sizeof * entries.length);
+        int offset = 0;
+        for (int i = 0; i < entries.length; i++) {
+            tango.stdc.string.memmove(pTargetsList + offset, entries[i], GtkTargetEntry.sizeof);
+            offset += GtkTargetEntry.sizeof;
+        }
+        if ((clipboards & DND.CLIPBOARD) !is 0) {
+            if (activeClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKCLIPBOARD);
+            clipboardData = data;
+            clipboardDataTypes = dataTypes;
+            if (!OS.gtk_clipboard_set_with_data(Clipboard.GTKCLIPBOARD, pTargetsList, entries.length, &getFuncFunc, &clearFuncFunc, cast(void*)this )) {
+                return false;
+            }
+            activeClipboard = owner;
+        }
+        if ((clipboards & DND.SELECTION_CLIPBOARD) !is 0) {
+            if (activePrimaryClipboard !is null) OS.gtk_clipboard_clear(Clipboard.GTKPRIMARYCLIPBOARD);
+            primaryClipboardData = data;
+            primaryClipboardDataTypes = dataTypes;
+            if (!OS.gtk_clipboard_set_with_data(Clipboard.GTKPRIMARYCLIPBOARD, pTargetsList, entries.length, &getFuncFunc, &clearFuncFunc, cast(void*)this )) {
+                return false;
+            }
+            activePrimaryClipboard = owner;
+        }
+        return true;
+    } finally {
+        for (int i = 0; i < entries.length; i++) {
+            GtkTargetEntry* entry = entries[i];
+            if( entry.target !is null) OS.g_free(entry.target);
+        }
+        if (pTargetsList !is null) OS.g_free(pTargetsList);
+    }
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DND.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DND;
+
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+
+import tango.util.Convert;
+
+/**
+ *
+ * Class DND contains all the constants used in defining a
+ * DragSource or a DropTarget.
+ *
+ */
+public class DND {
+
+    /**
+     * The transfer mechanism for data that is being cut
+     * and then pasted or copied and then pasted (value is 1).
+     *
+     * @see Clipboard
+     *
+     * @since 3.1
+     */
+    public const static int CLIPBOARD = 1 << 0;
+
+    /**
+     * The transfer mechanism for clients that use the selection
+     * mechanism (value is 2).
+     *
+     * @see Clipboard
+     *
+     * @since 3.1
+     */
+    public const static int SELECTION_CLIPBOARD = 1 << 1;
+
+    /**
+     * Drag and Drop Operation: no drag/drop operation performed
+     * (value is 0).
+     */
+    public const static int DROP_NONE = 0;
+
+    /**
+     * Drag and Drop Operation: a copy of the data in the drag source is
+     * added to the drop target (value is 1 &lt;&lt; 0).
+     */
+    public const static int DROP_COPY = 1 << 0;
+
+    /**
+     * Drag and Drop Operation: a copy of the data is added to the drop target and
+     * the original data is removed from the drag source (value is 1 &lt;&lt; 1).
+     */
+    public const static int DROP_MOVE = 1 << 1;
+
+    /**
+     * Drag and Drop Operation: the drop target makes a link to the data in
+     * the drag source (value is 1 &lt;&lt; 2).
+     */
+    public const static int DROP_LINK = 1 << 2;
+
+    /**
+     * Drag and Drop Operation: the drop target moves the data and the drag source removes
+     * any references to the data and updates its display.  This is not available on all platforms
+     * and is only used when a non-DWT application is the drop target.  In this case, the DWT
+     * drag source is informed in the dragFinished event that the drop target has moved the data.
+     * (value is 1 &lt;&lt; 3).
+     *
+     * @see DragSourceListener#dragFinished
+     */
+    public const static int DROP_TARGET_MOVE = 1 << 3;
+
+    /**
+     * Drag and Drop Operation: During a dragEnter event or a dragOperationChanged, if no modifier keys
+     * are pressed, the operation is set to DROP_DEFAULT.  The application can choose what the default
+     * operation should be by setting a new value in the operation field.  If no value is choosen, the
+     * default operation for the platform will be selected (value is 1 &lt;&lt; 4).
+     *
+     * @see DropTargetListener#dragEnter
+     * @see DropTargetListener#dragOperationChanged
+     * @since 2.0
+     */
+    public const static int DROP_DEFAULT = 1 << 4;
+
+    /**
+     * DragSource Event: the drop has successfully completed or has been terminated (such as hitting
+     * the ESC key); perform cleanup such as removing data on a move operation (value is 2000).
+     */
+    public static const int DragEnd     = 2000;
+
+    /**
+     * DragSource Event: the data to be dropped is required from the drag source (value is 2001).
+     */
+    public static const int DragSetData = 2001;
+
+    /**
+     * DropTarget Event: the cursor has entered the drop target boundaries (value is 2002).
+     */
+    public static const int DragEnter   = 2002;
+
+    /**
+     * DropTarget Event: the cursor has left the drop target boundaries OR the drop
+     * operation has been cancelled (such as by hitting ECS) OR the drop is about to
+     * happen (user has released the mous ebutotn over this target) (value is 2003).
+     */
+    public static const int DragLeave   = 2003;
+
+    /**
+     * DropTarget Event: the cursor is over the drop target (value is 2004).
+     */
+    public static const int DragOver    = 2004;
+
+    /**
+     * DropTarget Event: the operation being performed has changed usually due to the user
+     * changing the selected modifier keys while dragging (value is 2005).
+     */
+    public static const int DragOperationChanged = 2005;
+
+    /**
+     * DropTarget Event: the data has been dropped (value is 2006).
+     */
+    public static const int Drop = 2006;
+
+    /**
+     * DropTarget Event: the drop target is given a last chance to modify the drop (value is 2007).
+     */
+    public static const int DropAccept  = 2007;
+
+    /**
+     * DragSource Event: a drag is about to begin (value is 2008).
+     */
+    public static const int DragStart = 2008;
+
+    /**
+     * DropTarget drag under effect: No effect is shown (value is 0).
+     */
+    public static const int FEEDBACK_NONE = 0;
+
+    /**
+     * DropTarget drag under effect: The item under the cursor is selected; applies to tables
+     * and trees (value is 1).
+     */
+    public static const int FEEDBACK_SELECT = 1;
+
+    /**
+     * DropTarget drag under effect: An insertion mark is shown before the item under the cursor; applies to
+     * trees (value is 2).
+     */
+    public static const int FEEDBACK_INSERT_BEFORE = 2;
+
+    /**
+     * DropTarget drag under effect:An insertion mark is shown after the item under the cursor; applies to
+     * trees (value is 4).
+     */
+    public static const int FEEDBACK_INSERT_AFTER = 4;
+
+    /**
+     * DropTarget drag under effect: The widget is scrolled up or down to allow the user to drop on items that
+     * are not currently visible;  applies to tables and trees (value is 8).
+     */
+    public static const int FEEDBACK_SCROLL = 8;
+
+    /**
+     * DropTarget drag under effect: The item currently under the cursor is expanded to allow the user to
+     * select a drop target from a sub item; applies to trees (value is 16).
+     */
+    public static const int FEEDBACK_EXPAND = 16;
+
+    /**
+     * Error code: drag source can not be initialized (value is 2000).
+     */
+    public static const int ERROR_CANNOT_INIT_DRAG = 2000;
+
+    /**
+     * Error code: drop target cannot be initialized (value is 2001).
+     */
+    public static const int ERROR_CANNOT_INIT_DROP = 2001;
+
+    /**
+     * Error code: Data can not be set on system clipboard (value is 2002).
+     */
+    public static const int ERROR_CANNOT_SET_CLIPBOARD = 2002;
+
+    /**
+     * Error code: Data does not have correct format for type (value is 2003).
+     * @since 3.1
+     */
+    public static const int ERROR_INVALID_DATA = 2003;
+
+
+    static const char[] INIT_DRAG_MESSAGE = "Cannot initialize Drag"; //$NON-NLS-1$
+    static const char[] INIT_DROP_MESSAGE = "Cannot initialize Drop"; //$NON-NLS-1$
+    static const char[] CANNOT_SET_CLIPBOARD_MESSAGE = "Cannot set data in clipboard"; //$NON-NLS-1$
+    static const char[] INVALID_DATA_MESSAGE = "Data does not have correct format for type"; //$NON-NLS-1$
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ *
+ * @param code the DND error code
+ */
+public static void error (int code) {
+    error (code, 0);
+}
+
+/**
+ * Throws an appropriate exception based on the passed in error code.
+ * The <code>hresult</code> argument should be either 0, or the
+ * platform specific error code.
+ * <p>
+ * In DND, errors are reported by throwing one of three exceptions:
+ * <dl>
+ * <dd>java.lang.IllegalArgumentException</dd>
+ * <dt>thrown whenever one of the API methods is invoked with an illegal argument</dt>
+ * <dd>org.eclipse.swt.DWTException (extends java.lang.RuntimeException)</dd>
+ * <dt>thrown whenever a recoverable error happens internally in DWT</dt>
+ * <dd>org.eclipse.swt.DWTError (extends java.lang.Error)</dd>
+ * <dt>thrown whenever a <b>non-recoverable</b> error happens internally in DWT</dt>
+ * </dl>
+ * This method provides the logic which maps between error codes
+ * and one of the above exceptions.
+ * </p>
+ *
+ * @param code the DND error code.
+ * @param hresult the platform specific error code.
+ *
+ * @see DWTError
+ * @see DWTException
+ * @see IllegalArgumentException
+ */
+public static void error (int code, int hresult) {
+    switch (code) {
+        /* OS Failure/Limit (fatal, may occur only on some platforms) */
+        case DND.ERROR_CANNOT_INIT_DRAG:{
+            char[] msg = DND.INIT_DRAG_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTError (code, msg);
+        }
+        case DND.ERROR_CANNOT_INIT_DROP:{
+            char[] msg = DND.INIT_DROP_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTError (code, msg);
+        }
+        case DND.ERROR_CANNOT_SET_CLIPBOARD:{
+            char[] msg = DND.CANNOT_SET_CLIPBOARD_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTError (code, msg);
+        }
+        case DND.ERROR_INVALID_DATA:{
+            char[] msg = DND.INVALID_DATA_MESSAGE;
+            if (hresult !is 0) msg ~= " result = "~to!(char[])(hresult); //$NON-NLS-1$
+            throw new DWTException (code, msg);
+        }
+    }
+
+    /* Unknown/Undefined Error */
+    DWT.error(code);
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DNDEvent.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DNDEvent;
+
+
+
+import dwt.graphics.Image;
+import dwt.widgets.Event;
+import dwt.dnd.TransferData;
+
+class DNDEvent : Event {
+    public TransferData dataType;
+    public TransferData[] dataTypes;
+    public int operations;
+    public int feedback;
+    public Image image;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DNDListener.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DNDListener;
+
+
+import dwt.internal.DWTEventListener;
+import dwt.widgets.Event;
+import dwt.widgets.TypedListener;
+import dwt.widgets.Widget;
+import dwt.dnd.DND;
+import dwt.dnd.DNDEvent;
+import dwt.dnd.DragSourceEvent;
+import dwt.dnd.DragSourceEffect;
+import dwt.dnd.DragSource;
+import dwt.dnd.DragSourceListener;
+import dwt.dnd.DropTargetEvent;
+import dwt.dnd.DropTargetListener;
+import dwt.dnd.DropTargetEffect;
+import dwt.dnd.DropTarget;
+
+
+class DNDListener : TypedListener {
+    Widget dndWidget;
+/**
+ * DNDListener constructor comment.
+ * @param listener org.eclipse.swt.internal.DWTEventListener
+ */
+this(DWTEventListener listener) {
+    super(listener);
+}
+public void handleEvent (Event e) {
+    switch (e.type) {
+        case DND.DragStart: {
+            DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e);
+            DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect();
+            if (sourceEffect !is null) {
+                sourceEffect.dragStart (event);
+            }
+            (cast(DragSourceListener) eventListener).dragStart (event);
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragEnd: {
+            DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e);
+            DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect();
+            if (sourceEffect !is null) {
+                sourceEffect.dragFinished (event);
+            }
+            (cast(DragSourceListener) eventListener).dragFinished (event);
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragSetData: {
+            DragSourceEvent event = new DragSourceEvent(cast(DNDEvent)e);
+            DragSourceEffect sourceEffect = (cast(DragSource) dndWidget).getDragSourceEffect();
+            if (sourceEffect !is null) {
+                sourceEffect.dragSetData (event);
+            }
+            (cast(DragSourceListener) eventListener).dragSetData (event);
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragEnter: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragEnter (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragEnter (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragLeave: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragLeave (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragLeave (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragOver: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragOver (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragOver (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.Drop: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).drop (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.drop (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DropAccept: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dropAccept (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dropAccept (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+        case DND.DragOperationChanged: {
+            DropTargetEvent event = new DropTargetEvent(cast(DNDEvent)e);
+            (cast(DropTargetListener) eventListener).dragOperationChanged (event);
+            DropTargetEffect dropEffect = (cast(DropTarget) dndWidget).getDropTargetEffect();
+            if (dropEffect !is null) {
+                dropEffect.dragOperationChanged (event);
+            }
+            event.updateEvent(cast(DNDEvent)e);
+            break;
+        }
+
+    }
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSource.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,633 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DragSource;
+
+
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.graphics.Image;
+import dwt.graphics.ImageData;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Table;
+import dwt.widgets.Tree;
+import dwt.widgets.Widget;
+import dwt.dnd.Transfer;
+import dwt.dnd.DragSourceEffect;
+import dwt.dnd.DragSourceListener;
+import dwt.dnd.DND;
+import dwt.dnd.TreeDragSourceEffect;
+import dwt.dnd.TableDragSourceEffect;
+import dwt.dnd.DNDListener;
+import dwt.dnd.DNDEvent;
+import dwt.dnd.TransferData;
+
+import tango.core.Thread;
+
+/**
+ *
+ * <code>DragSource</code> defines the source object for a drag and drop transfer.
+ *
+ * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p>
+ *
+ * <p>A drag source is the object which originates a drag and drop operation. For the specified widget,
+ * it defines the type of data that is available for dragging and the set of operations that can
+ * be performed on that data.  The operations can be any bit-wise combination of DND.MOVE, DND.COPY or
+ * DND.LINK.  The type of data that can be transferred is specified by subclasses of Transfer such as
+ * TextTransfer or FileTransfer.  The type of data transferred can be a predefined system type or it
+ * can be a type defined by the application.  For instructions on how to define your own transfer type,
+ * refer to <code>ByteArrayTransfer</code>.</p>
+ *
+ * <p>You may have several DragSources in an application but you can only have one DragSource
+ * per Control.  Data dragged from this DragSource can be dropped on a site within this application
+ * or it can be dropped on another application such as an external Text editor.</p>
+ *
+ * <p>The application supplies the content of the data being transferred by implementing the
+ * <code>DragSourceListener</code> and associating it with the DragSource via DragSource#addDragListener.</p>
+ *
+ * <p>When a successful move operation occurs, the application is required to take the appropriate
+ * action to remove the data from its display and remove any associated operating system resources or
+ * internal references.  Typically in a move operation, the drop target makes a copy of the data
+ * and the drag source deletes the original.  However, sometimes copying the data can take a long
+ * time (such as copying a large file).  Therefore, on some platforms, the drop target may actually
+ * move the data in the operating system rather than make a copy.  This is usually only done in
+ * file transfers.  In this case, the drag source is informed in the DragEnd event that a
+ * DROP_TARGET_MOVE was performed.  It is the responsibility of the drag source at this point to clean
+ * up its displayed information.  No action needs to be taken on the operating system resources.</p>
+ *
+ * <p> The following example shows a Label widget that allows text to be dragged from it.</p>
+ *
+ * <code><pre>
+ *  // Enable a label as a Drag Source
+ *  Label label = new Label(shell, DWT.NONE);
+ *  // This example will allow text to be dragged
+ *  Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ *  // This example will allow the text to be copied or moved to the drop target
+ *  int operations = DND.DROP_MOVE | DND.DROP_COPY;
+ *
+ *  DragSource source = new DragSource(label, operations);
+ *  source.setTransfer(types);
+ *  source.addDragListener(new DragSourceListener() {
+ *      public void dragStart(DragSourceEvent e) {
+ *          // Only start the drag if there is actually text in the
+ *          // label - this text will be what is dropped on the target.
+ *          if (label.getText().length() is 0) {
+ *              event.doit = false;
+ *          }
+ *      };
+ *      public void dragSetData(DragSourceEvent event) {
+ *          // A drop has been performed, so provide the data of the
+ *          // requested type.
+ *          // (Checking the type of the requested data is only
+ *          // necessary if the drag source supports more than
+ *          // one data type but is shown here as an example).
+ *          if (TextTransfer.getInstance().isSupportedType(event.dataType)){
+ *              event.data = label.getText();
+ *          }
+ *      }
+ *      public void dragFinished(DragSourceEvent event) {
+ *          // A Move operation has been performed so remove the data
+ *          // from the source
+ *          if (event.detail is DND.DROP_MOVE)
+ *              label.setText("");
+ *      }
+ *  });
+ * </pre></code>
+ *
+ *
+ * <dl>
+ *  <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
+ *  <dt><b>Events</b></dt> <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd>
+ * </dl>
+ */
+public class DragSource : Widget {
+
+    // info for registering as a drag source
+    Control control;
+    Listener controlListener;
+    Transfer[] transferAgents;
+    DragSourceEffect dragEffect;
+
+    void* targetList;
+
+    //workaround - remember action performed for DragEnd
+    bool moveData = false;
+
+    static const char[] DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
+    static const char[] DRAGSOURCEID = "DragSource"; //$NON-NLS-1$
+
+//     static Callback DragGetData;
+//     static Callback DragEnd;
+//     static Callback DragDataDelete;
+//     static this() {
+//         DragGetData = new Callback(DragSource.class, "DragGetData", 5);  //$NON-NLS-1$
+//         if (DragGetData.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
+//         DragEnd = new Callback(DragSource.class, "DragEnd", 2); //$NON-NLS-1$
+//         if (DragEnd.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
+//         DragDataDelete = new Callback(DragSource.class, "DragDataDelete", 2); //$NON-NLS-1$
+//         if (DragDataDelete.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
+//     }
+
+/**
+ * Creates a new <code>DragSource</code> to handle dragging from the specified <code>Control</code>.
+ * Creating an instance of a DragSource may cause system resources to be allocated depending on the platform.
+ * It is therefore mandatory that the DragSource instance be disposed when no longer required.
+ *
+ * @param control the <code>Control</code> that the user clicks on to initiate the drag
+ * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
+ *                  DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ * @exception DWTError <ul>
+ *    <li>ERROR_CANNOT_INIT_DRAG - unable to initiate drag source; this will occur if more than one
+ *        drag source is created for a control or if the operating system will not allow the creation
+ *        of the drag source</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_INIT_DRAG should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see Widget#dispose
+ * @see DragSource#checkSubclass
+ * @see DND#DROP_NONE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_LINK
+ */
+public this(Control control, int style) {
+    super (control, checkStyle(style));
+    this.control = control;
+//     if (DragGetData is null || DragEnd is null || DragDataDelete is null) {
+//         DND.error(DND.ERROR_CANNOT_INIT_DRAG);
+//     }
+    if (control.getData(DRAGSOURCEID) !is null) {
+        DND.error(DND.ERROR_CANNOT_INIT_DRAG);
+    }
+    control.setData(DRAGSOURCEID, this);
+
+    OS.g_signal_connect(control.handle, OS.drag_data_get.ptr, cast(GCallback)&DragGetData, null);
+    OS.g_signal_connect(control.handle, OS.drag_end.ptr, cast(GCallback)&DragEnd, null);
+    OS.g_signal_connect(control.handle, OS.drag_data_delete.ptr, cast(GCallback)&DragDataDelete, null);
+
+    controlListener = new class() Listener {
+        public void handleEvent (Event event) {
+            if (event.type is DWT.Dispose) {
+                if (!this.outer.isDisposed()) {
+                    this.outer.dispose();
+                }
+            }
+            if (event.type is DWT.DragDetect) {
+                if (!this.outer.isDisposed()) {
+                    this.outer.drag(event);
+                }
+            }
+        }
+    };
+    control.addListener (DWT.Dispose, controlListener);
+    control.addListener (DWT.DragDetect, controlListener);
+
+    Object effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT);
+    if ( auto de = cast(DragSourceEffect)effect ) {
+        dragEffect = de;
+    } else if ( auto tree = cast(Tree)control) {
+        dragEffect = new TreeDragSourceEffect(tree);
+    } else if ( auto table = cast(Table)control ) {
+        dragEffect = new TableDragSourceEffect(table);
+    }
+
+    this.addListener(DWT.Dispose, new class() Listener {
+        public void handleEvent(Event e) {
+            onDispose();
+        }
+    });
+}
+
+static int checkStyle (int style) {
+    if (style is DWT.NONE) return DND.DROP_MOVE;
+    return style;
+}
+
+private static extern(C) void DragDataDelete(
+    GtkWidget      *widget,
+    GdkDragContext *drag_context,
+    void*           user_data )
+{
+    DragSource source = FindDragSource(widget);
+    if (source is null) return;
+    source.dragDataDelete(widget, drag_context);
+    return;
+}
+
+private static extern(C) void DragEnd (
+    GtkWidget      *widget,
+    GdkDragContext *drag_context,
+    void*           user_data)
+{
+    DragSource source = FindDragSource(widget);
+    if (source is null) return;
+    source.dragEnd(widget, drag_context);
+    return;
+}
+
+private static extern(C) void DragGetData(
+    GtkWidget        *widget,
+    GdkDragContext   *context,
+    GtkSelectionData *selection_data,
+    uint              info,
+    uint              time,
+    void*             user_data )
+{
+    DragSource source = FindDragSource(widget);
+    if (source is null) return;
+    source.dragGetData(widget, context, selection_data, cast(int)/*64*/info, cast(int)/*64*/time);
+    return;
+}
+
+static DragSource FindDragSource(GtkWidget* handle) {
+    Display display = Display.findDisplay(Thread.getThis());
+    if (display is null || display.isDisposed()) return null;
+    Widget widget = display.findWidget(handle);
+    if (widget is null) return null;
+    return cast(DragSource)widget.getData(DRAGSOURCEID);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when a drag and drop operation is in progress, by sending
+ * it one of the messages defined in the <code>DragSourceListener</code>
+ * interface.
+ *
+ * <p><ul>
+ * <li><code>dragStart</code> is called when the user has begun the actions required to drag the widget.
+ * This event gives the application the chance to decide if a drag should be started.
+ * <li><code>dragSetData</code> is called when the data is required from the drag source.
+ * <li><code>dragFinished</code> is called when the drop has successfully completed (mouse up
+ * over a valid target) or has been terminated (such as hitting the ESC key). Perform cleanup
+ * such as removing data from the source side on a successful move operation.
+ * </ul></p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DragSourceListener
+ * @see #removeDragListener
+ * @see DragSourceEvent
+ */
+public void addDragListener(DragSourceListener listener) {
+    if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
+    DNDListener typedListener = new DNDListener (listener);
+    typedListener.dndWidget = this;
+    addListener (DND.DragStart, typedListener);
+    addListener (DND.DragSetData, typedListener);
+    addListener (DND.DragEnd, typedListener);
+}
+
+protected void checkSubclass () {
+    char[] name = this.classinfo.name;
+    char[] validName = DragSource.stringof;
+    if ( validName !=/*eq*/ name ) {
+        DND.error (DWT.ERROR_INVALID_SUBCLASS);
+    }
+}
+
+void drag(Event dragEvent) {
+    moveData = false;
+    DNDEvent event = new DNDEvent();
+    event.widget = this;
+    event.x = dragEvent.x;
+    event.y = dragEvent.y;
+    event.time = dragEvent.time;
+    event.doit = true;
+    notifyListeners(DND.DragStart, event);
+    if (!event.doit || transferAgents is null || transferAgents.length is 0) return;
+    if (targetList is null) return;
+
+    int actions = opToOsOp(getStyle());
+    Image image = event.image;
+    auto context = OS.gtk_drag_begin(control.handle, targetList, actions, 1, null);
+    if (context !is null && image !is null) {
+        auto pixbuf = createPixbuf(image);
+        OS.gtk_drag_set_icon_pixbuf(context, pixbuf, 0, 0);
+        OS.g_object_unref(pixbuf);
+    }
+}
+
+void dragEnd(
+    GtkWidget      *widget,
+    GdkDragContext *context )
+{
+    /*
+     * Bug in GTK.  If a drag is initiated using gtk_drag_begin and the
+     * mouse is released immediately, the mouse and keyboard remain
+     * grabbed.  The fix is to release the grab on the mouse and keyboard
+     * whenever the drag is terminated.
+     *
+     * NOTE: We believe that it is never an error to ungrab when
+     * a drag is finished.
+     */
+    OS.gdk_pointer_ungrab(OS.GDK_CURRENT_TIME);
+    OS.gdk_keyboard_ungrab(OS.GDK_CURRENT_TIME);
+
+    int operation = DND.DROP_NONE;
+    if (context !is null) {
+        GdkDragContext* gdkDragContext = context;
+        if (gdkDragContext.dest_window !is null) { //NOTE: if dest_window is 0, drag was aborted
+            if (moveData) {
+                operation = DND.DROP_MOVE;
+            } else {
+                operation = osOpToOp(gdkDragContext.action);
+                if (operation is DND.DROP_MOVE) operation = DND.DROP_NONE;
+            }
+        }
+    }
+
+    DNDEvent event = new DNDEvent();
+    event.widget = this;
+    //event.time = ???
+    event.doit = operation !is 0;
+    event.detail = operation;
+    notifyListeners(DND.DragEnd, event);
+    moveData = false;
+}
+
+void dragGetData(
+    GtkWidget        *widget,
+    GdkDragContext   *context,
+    GtkSelectionData *gtkSelectionData,
+    uint              info,
+    uint              time )
+{
+    if (gtkSelectionData is null) return;
+    if (gtkSelectionData.target is null) return;
+
+    TransferData transferData = new TransferData();
+    transferData.type = gtkSelectionData.target;
+    transferData.pValue = gtkSelectionData.data;
+    transferData.length = gtkSelectionData.length;
+    transferData.format = gtkSelectionData.format;
+
+    DNDEvent event = new DNDEvent();
+    event.widget = this;
+    event.time = time;
+    event.dataType = transferData;
+    notifyListeners(DND.DragSetData, event);
+
+    Transfer transfer = null;
+    for (int i = 0; i < transferAgents.length; i++) {
+        Transfer transferAgent = transferAgents[i];
+        if (transferAgent !is null && transferAgent.isSupportedType(transferData)) {
+            transfer = transferAgent;
+            break;
+        }
+    }
+    if (transfer is null) return;
+    transfer.javaToNative(event.data, transferData);
+    if (transferData.result !is 1) return;
+    OS.gtk_selection_data_set(gtkSelectionData, transferData.type, transferData.format, transferData.pValue, transferData.length);
+    OS.g_free(transferData.pValue);
+    return;
+}
+
+void dragDataDelete(
+    GtkWidget      *widget,
+    GdkDragContext *drag_context)
+{
+    moveData = true;
+}
+
+/**
+ * Returns the Control which is registered for this DragSource.  This is the control that the
+ * user clicks in to initiate dragging.
+ *
+ * @return the Control which is registered for this DragSource
+ */
+public Control getControl () {
+    return control;
+}
+
+/**
+ * Returns the drag effect that is registered for this DragSource.  This drag
+ * effect will be used during a drag and drop operation.
+ *
+ * @return the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public DragSourceEffect getDragSourceEffect() {
+    return dragEffect;
+}
+
+/**
+ * Returns the list of data types that can be transferred by this DragSource.
+ *
+ * @return the list of data types that can be transferred by this DragSource
+ */
+public Transfer[] getTransfer(){
+    return transferAgents;
+}
+
+void onDispose() {
+    if (control is null) return;
+    if (targetList !is null) {
+        OS.gtk_target_list_unref(targetList);
+    }
+    targetList = null;
+    if (controlListener !is null) {
+        control.removeListener(DWT.Dispose, controlListener);
+        control.removeListener(DWT.DragDetect, controlListener);
+    }
+    controlListener = null;
+    control.setData(DRAGSOURCEID, null);
+    control = null;
+    transferAgents = null;
+}
+
+int opToOsOp(int operation){
+    int osOperation = 0;
+
+    if ((operation & DND.DROP_COPY) is DND.DROP_COPY)
+        osOperation |= OS.GDK_ACTION_COPY;
+    if ((operation & DND.DROP_MOVE) is DND.DROP_MOVE)
+        osOperation |= OS.GDK_ACTION_MOVE;
+    if ((operation & DND.DROP_LINK) is DND.DROP_LINK)
+        osOperation |= OS.GDK_ACTION_LINK;
+
+    return osOperation;
+}
+
+int osOpToOp(int osOperation){
+    int operation = DND.DROP_NONE;
+
+    if ((osOperation & OS.GDK_ACTION_COPY) is OS.GDK_ACTION_COPY)
+        operation |= DND.DROP_COPY;
+    if ((osOperation & OS.GDK_ACTION_MOVE) is OS.GDK_ACTION_MOVE)
+        operation |= DND.DROP_MOVE;
+    if ((osOperation & OS.GDK_ACTION_LINK) is OS.GDK_ACTION_LINK)
+        operation |= DND.DROP_LINK;
+
+    return operation;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag and drop operation is in progress.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DragSourceListener
+ * @see #addDragListener
+ */
+public void removeDragListener(DragSourceListener listener) {
+    if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
+    removeListener (DND.DragStart, listener);
+    removeListener (DND.DragSetData, listener);
+    removeListener (DND.DragEnd, listener);
+}
+
+/**
+ * Specifies the drag effect for this DragSource.  This drag effect will be
+ * used during a drag and drop operation.
+ *
+ * @param effect the drag effect that is registered for this DragSource
+ *
+ * @since 3.3
+ */
+public void setDragSourceEffect(DragSourceEffect effect) {
+    dragEffect = effect;
+}
+
+/**
+ * Specifies the list of data types that can be transferred by this DragSource.
+ * The application must be able to provide data to match each of these types when
+ * a successful drop has occurred.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ * dragged from this source
+ */
+public void setTransfer(Transfer[] transferAgents){
+    if (targetList !is null) {
+        OS.gtk_target_list_unref(targetList);
+        targetList = null;
+    }
+    this.transferAgents = transferAgents;
+    if (transferAgents is null || transferAgents.length is 0) return;
+
+    GtkTargetEntry*[] targets;
+    for (int i = 0; i < transferAgents.length; i++) {
+        Transfer transfer = transferAgents[i];
+        if (transfer !is null) {
+            int[] typeIds = transfer.getTypeIds();
+            char[][] typeNames = transfer.getTypeNames();
+            for (int j = 0; j < typeIds.length; j++) {
+                GtkTargetEntry* entry = new GtkTargetEntry();
+                char[] type = typeNames[j];
+                entry.target = cast(char*)OS.g_malloc(type.length+1);
+                entry.target[ 0 .. type.length ] = type[];
+                entry.target[ type.length ] = '\0';
+                entry.info = typeIds[j];
+                GtkTargetEntry*[] newTargets = new GtkTargetEntry*[targets.length + 1];
+                SimpleType!(GtkTargetEntry*).arraycopy(targets, 0, newTargets, 0, targets.length);
+                newTargets[targets.length] = entry;
+                targets = newTargets;
+            }
+        }
+    }
+
+    void* pTargets = OS.g_malloc(targets.length * GtkTargetEntry.sizeof);
+    for (int i = 0; i < targets.length; i++) {
+        tango.stdc.string.memmove(pTargets + i*GtkTargetEntry.sizeof, targets[i], GtkTargetEntry.sizeof);
+    }
+    targetList = OS.gtk_target_list_new(pTargets, targets.length);
+
+    for (int i = 0; i < targets.length; i++) {
+        OS.g_free(targets[i].target);
+    }
+}
+
+static GdkDrawable* createPixbuf(Image image) {
+    int w, h;
+    OS.gdk_drawable_get_size (image.pixmap, &w, &h);
+    auto colormap = OS.gdk_colormap_get_system ();
+    void* pixbuf;
+    bool hasMask = image.mask !is null && OS.gdk_drawable_get_depth (image.mask) is 1;
+    if (hasMask) {
+        pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, true, 8, w, h);
+        if (pixbuf is null) DWT.error (DWT.ERROR_NO_HANDLES);
+        OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w , h);
+        auto maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, w , h );
+        if (maskPixbuf is null) DWT.error (DWT.ERROR_NO_HANDLES);
+        OS.gdk_pixbuf_get_from_drawable(maskPixbuf, image.mask, null, 0, 0, 0, 0, w , h );
+        int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+        auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+        byte[] line = new byte[stride];
+        int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf);
+        auto maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf);
+        byte[] maskLine = new byte[maskStride];
+        for (int y=0; y<h; y++) {
+            auto offset = pixels + (y * stride);
+            tango.stdc.string.memmove(line.ptr, offset, stride);
+            auto maskOffset = maskPixels + (y * maskStride);
+            tango.stdc.string.memmove(maskLine.ptr, maskOffset, maskStride);
+            for (int x=0; x<w; x++) {
+                if (maskLine[x * 3] is 0) {
+                    line[x * 4 + 3] = 0;
+                }
+            }
+            tango.stdc.string.memmove(offset, line.ptr, stride);
+        }
+        OS.g_object_unref(maskPixbuf);
+    } else {
+        ImageData data = image.getImageData ();
+        bool hasAlpha = data.getTransparencyType () is DWT.TRANSPARENCY_ALPHA;
+        pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, hasAlpha, 8, w , h );
+        if (pixbuf is null) DWT.error (DWT.ERROR_NO_HANDLES);
+        OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w , h );
+        if (hasAlpha) {
+            byte [] alpha = data.alphaData;
+            int stride = OS.gdk_pixbuf_get_rowstride (pixbuf);
+            auto pixels = OS.gdk_pixbuf_get_pixels (pixbuf);
+            byte [] line = new byte [stride];
+            for (int y = 0; y < h ; y++) {
+                auto offset = pixels + (y * stride);
+                tango.stdc.string.memmove (line.ptr, offset, stride);
+                for (int x = 0; x < w ; x++) {
+                    line [x*4+3] = alpha [y*w +x];
+                }
+                tango.stdc.string.memmove (offset, line.ptr, stride);
+            }
+        }
+    }
+    return cast(GdkDrawable*)pixbuf;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceAdapter.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DragSourceAdapter;
+
+import dwt.dnd.DragSourceListener;
+import dwt.dnd.DragSourceEvent;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the <code>DragSourceListener</code> interface.
+ *
+ * <p>Classes that wish to deal with <code>DragSourceEvent</code>s can
+ * extend this class and override only the methods which they are
+ * interested in.</p>
+ *
+ * @see DragSourceListener
+ * @see DragSourceEvent
+ */
+public class DragSourceAdapter : DragSourceListener {
+    /**
+     * This implementation of <code>dragStart</code> permits the drag operation to start.
+     * For additional information see <code>DragSourceListener.dragStart</code>.
+     */
+    public void dragStart(DragSourceEvent event){}
+    /**
+     * This implementation of <code>dragFinished</code> does nothing.
+     * For additional information see <code>DragSourceListener.dragFinished</code>.
+     */
+    public void dragFinished(DragSourceEvent event){}
+    /**
+     * This implementation of <code>dragSetData</code> does nothing.
+     * For additional information see <code>DragSourceListener.dragSetData</code>.
+     */
+    public void dragSetData(DragSourceEvent event){}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceEffect.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DragSourceEffect;
+
+
+import dwt.DWT;
+import dwt.widgets.Control;
+import dwt.dnd.DragSourceAdapter;
+
+/**
+ * This class provides default implementations to display a drag source
+ * effect during a drag and drop operation. The current implementation
+ * does not provide any visual feedback.
+ *
+ * <p>The drag source effect has the same API as the
+ * <code>DragSourceAdapter</code> so that it can provide custom visual
+ * feedback when a <code>DragSourceEvent</code> occurs.
+ * </p>
+ *
+ * <p>Classes that wish to provide their own drag source effect such as
+ * displaying a default source image during a drag can extend the <code>DragSourceEffect</code>
+ * class, override the <code>DragSourceAdapter.dragStart</code> method and set
+ * the field <code>DragSourceEvent.image</code> with their own image.
+ * The image should be disposed when <code>DragSourceAdapter.dragFinished</code> is called.
+ * </p>
+ *
+ * @see DragSourceAdapter
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class DragSourceEffect : DragSourceAdapter {
+    Control control = null;
+
+    /**
+     * Creates a new <code>DragSourceEffect</code> to handle drag effect from the specified <code>Control</code>.
+     *
+     * @param control the <code>Control</code> that the user clicks on to initiate the drag
+     *
+     * @exception IllegalArgumentException <ul>
+     *    <li>ERROR_NULL_ARGUMENT - if the control is null</li>
+     * </ul>
+     */
+    public this(Control control) {
+        if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+        this.control = control;
+    }
+
+    /**
+     * Returns the Control which is registered for this DragSourceEffect.  This is the control that the
+     * user clicks in to initiate dragging.
+     *
+     * @return the Control which is registered for this DragSourceEffect
+     */
+    public Control getControl() {
+        return control;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceEvent.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DragSourceEvent;
+
+
+import dwt.events.TypedEvent;
+import dwt.widgets.Event;
+import dwt.graphics.Image;
+import dwt.dnd.TransferData;
+import dwt.dnd.DNDEvent;
+
+/**
+ * The DragSourceEvent contains the event information passed in the methods of the DragSourceListener.
+ *
+ * @see DragSourceListener
+ */
+public class DragSourceEvent : TypedEvent {
+    /**
+     * The operation that was performed.
+     * @see DND#DROP_NONE
+     * @see DND#DROP_MOVE
+     * @see DND#DROP_COPY
+     * @see DND#DROP_LINK
+     * @see DND#DROP_TARGET_MOVE
+     */
+    public int detail;
+
+    /**
+     * In dragStart, the doit field determines if the drag and drop operation
+     * should proceed; in dragFinished, the doit field indicates whether
+     * the operation was performed successfully.
+     * <p></p>
+     * In dragStart:
+     * <p>Flag to determine if the drag and drop operation should proceed.
+     * The application can set this value to false to prevent the drag from starting.
+     * Set to true by default.</p>
+     *
+     * <p>In dragFinished:</p>
+     * <p>Flag to indicate if the operation was performed successfully.
+     * True if the operation was performed successfully.</p>
+     */
+    public bool doit;
+
+    /**
+     * In dragStart, the x coordinate (relative to the control) of the
+     * position the mouse went down to start the drag.
+     * @since 3.2
+     */
+    public int x;
+    /**
+     * In dragStart, the y coordinate (relative to the control) of the
+     * position the mouse went down to start the drag .
+     * @since 3.2
+     */
+    public int y;
+
+    /**
+     * The type of data requested.
+     * Data provided in the data field must be of the same type.
+     */
+    public TransferData dataType;
+
+    /**
+     * The drag source image to be displayed during the drag.
+     * <p>A value of null indicates that no drag image will be displayed.</p>
+     * <p>The default value is null.</p>
+     *
+     * @since 3.3
+     */
+    public Image image;
+
+    static const long serialVersionUID = 3257002142513770808L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public this(DNDEvent e) {
+    super( cast(Event) e );
+    this.data = e.data;
+    this.detail = e.detail;
+    this.doit = e.doit;
+    this.dataType = e.dataType;
+    this.x = e.x;
+    this.y = e.y;
+    this.image = e.image;
+}
+void updateEvent(DNDEvent e) {
+    e.widget = this.widget;
+    e.time = this.time;
+    e.data = this.data;
+    e.detail = this.detail;
+    e.doit = this.doit;
+    e.dataType = this.dataType;
+    e.x = this.x;
+    e.y = this.y;
+    e.image = this.image;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DragSourceListener.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DragSourceListener;
+
+import dwt.internal.DWTEventListener;
+import dwt.dnd.DragSourceEvent;
+
+/**
+ * The <code>DragSourceListener</code> class provides event notification to the application for DragSource events.
+ *
+ * <p>When the user drops data on a <code>DropTarget</code>, the application which defines the <code>DragSource</code>
+ * must provide the dropped data by implementing <code>dragSetData</code>.  In the dragSetData, the application
+ * must support all the data types that were specified in the DragSource#setTransfer method.</p>
+ *
+ * <p>After the drop has completed successfully or has been aborted, the application which defines the
+ * <code>DragSource</code> is required to take the appropriate cleanup action.  In the case of a successful
+ * <b>move</b> operation, the application must remove the data that was transferred.</p>
+ *
+ */
+public interface DragSourceListener : DWTEventListener {
+
+/**
+ * The user has begun the actions required to drag the widget. This event gives the application
+ * the chance to decide if a drag should be started.
+ *
+ * <p>The following fields in the DragSourceEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in,out)doit
+ * </ul></p>
+ *
+ * @param event the information associated with the drag start event
+ *
+ * @see DragSourceEvent
+ */
+public void dragStart(DragSourceEvent event);
+
+/**
+ * The data is required from the drag source.
+ *
+ * <p>The following fields in the DragSourceEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)dataType - the type of data requested.
+ * <li>(out)data    - the application inserts the actual data here (must match the dataType)
+ * </ul></p>
+ *
+ * @param event the information associated with the drag set data event
+ *
+ * @see DragSourceEvent
+ */
+public void dragSetData(DragSourceEvent event);
+
+/**
+ * The drop has successfully completed(mouse up over a valid target) or has been terminated (such as hitting
+ * the ESC key). Perform cleanup such as removing data from the source side on a successful move operation.
+ *
+ * <p>The following fields in the DragSourceEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)doit
+ * <li>(in)detail
+ * </ul></p>
+ *
+ * @param event the information associated with the drag finished event
+ *
+ * @see DragSourceEvent
+ */
+public void dragFinished(DragSourceEvent event);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTarget.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,820 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DropTarget;
+
+
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.graphics.Point;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Table;
+import dwt.widgets.Tree;
+import dwt.widgets.Widget;
+import dwt.dnd.DND;
+import dwt.dnd.Transfer;
+import dwt.dnd.DropTargetEffect;
+import dwt.dnd.DNDEvent;
+import dwt.dnd.DNDListener;
+import dwt.dnd.TransferData;
+import dwt.dnd.DropTargetListener;
+import dwt.dnd.TableDropTargetEffect;
+import dwt.dnd.TreeDropTargetEffect;
+
+import dwt.dwthelper.Runnable;
+import tango.core.Thread;
+static import tango.stdc.string;
+
+/**
+ *
+ * Class <code>DropTarget</code> defines the target object for a drag and drop transfer.
+ *
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ *
+ * <p>This class identifies the <code>Control</code> over which the user must position the cursor
+ * in order to drop the data being transferred.  It also specifies what data types can be dropped on
+ * this control and what operations can be performed.  You may have several DropTragets in an
+ * application but there can only be a one to one mapping between a <code>Control</code> and a <code>DropTarget</code>.
+ * The DropTarget can receive data from within the same application or from other applications
+ * (such as text dragged from a text editor like Word).</p>
+ *
+ * <code><pre>
+ *  int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
+ *  Transfer[] types = new Transfer[] {TextTransfer.getInstance()};
+ *  DropTarget target = new DropTarget(label, operations);
+ *  target.setTransfer(types);
+ * </code></pre>
+ *
+ * <p>The application is notified of data being dragged over this control and of when a drop occurs by
+ * implementing the interface <code>DropTargetListener</code> which uses the class
+ * <code>DropTargetEvent</code>.  The application can modify the type of drag being performed
+ * on this Control at any stage of the drag by modifying the <code>event.detail</code> field or the
+ * <code>event.currentDataType</code> field.  When the data is dropped, it is the responsibility of
+ * the application to copy this data for its own purposes.
+ *
+ * <code><pre>
+ *  target.addDropListener (new DropTargetListener() {
+ *      public void dragEnter(DropTargetEvent event) {};
+ *      public void dragOver(DropTargetEvent event) {};
+ *      public void dragLeave(DropTargetEvent event) {};
+ *      public void dragOperationChanged(DropTargetEvent event) {};
+ *      public void dropAccept(DropTargetEvent event) {}
+ *      public void drop(DropTargetEvent event) {
+ *          // A drop has occurred, copy over the data
+ *          if (event.data is null) { // no data to copy, indicate failure in event.detail
+ *              event.detail = DND.DROP_NONE;
+ *              return;
+ *          }
+ *          label.setText ((String) event.data); // data copied to label text
+ *      }
+ *  });
+ * </pre></code>
+ *
+ * <dl>
+ *  <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd>
+ *  <dt><b>Events</b></dt> <dd>DND.DragEnter, DND.DragLeave, DND.DragOver, DND.DragOperationChanged,
+ *                             DND.DropAccept, DND.Drop </dd>
+ * </dl>
+ */
+public class DropTarget : Widget {
+
+    Control control;
+    Listener controlListener;
+    Transfer[] transferAgents;
+    DropTargetEffect dropEffect;
+
+    // Track application selections
+    TransferData selectedDataType;
+    int selectedOperation;
+
+    // workaround - There is no event for "operation changed" so track operation based on key state
+    int keyOperation = -1;
+
+    // workaround - Simulate events when the mouse is not moving
+    long dragOverStart;
+    Runnable dragOverHeartbeat;
+    DNDEvent dragOverEvent;
+
+    int drag_motion_handler;
+    int drag_leave_handler;
+    int drag_data_received_handler;
+    int drag_drop_handler;
+
+    static const char[] DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
+    static const char[] DROPTARGETID = "DropTarget"; //$NON-NLS-1$
+    static const int DRAGOVER_HYSTERESIS = 50;
+
+//     static Callback Drag_Motion;
+//     static Callback Drag_Leave;
+//     static Callback Drag_Data_Received;
+//     static Callback Drag_Drop;
+//
+//      static this(){
+//         Drag_Motion = new Callback(DropTarget.class, "Drag_Motion", 5); //$NON-NLS-1$
+//         if (Drag_Motion.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
+//         Drag_Leave = new Callback(DropTarget.class, "Drag_Leave", 3); //$NON-NLS-1$
+//         if (Drag_Leave.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
+//         Drag_Data_Received = new Callback(DropTarget.class, "Drag_Data_Received", 7); //$NON-NLS-1$
+//         if (Drag_Data_Received.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
+//         Drag_Drop = new Callback(DropTarget.class, "Drag_Drop", 5); //$NON-NLS-1$
+//         if (Drag_Drop.getAddress() is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
+//     }
+
+/**
+ * Creates a new <code>DropTarget</code> to allow data to be dropped on the specified
+ * <code>Control</code>.
+ * Creating an instance of a DropTarget may cause system resources to be allocated
+ * depending on the platform.  It is therefore mandatory that the DropTarget instance
+ * be disposed when no longer required.
+ *
+ * @param control the <code>Control</code> over which the user positions the cursor to drop the data
+ * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of
+ *         DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ * @exception DWTError <ul>
+ *    <li>ERROR_CANNOT_INIT_DROP - unable to initiate drop target; this will occur if more than one
+ *        drop target is created for a control or if the operating system will not allow the creation
+ *        of the drop target</li>
+ * </ul>
+ *
+ * <p>NOTE: ERROR_CANNOT_INIT_DROP should be an DWTException, since it is a
+ * recoverable error, but can not be changed due to backward compatibility.</p>
+ *
+ * @see Widget#dispose
+ * @see DropTarget#checkSubclass
+ * @see DND#DROP_NONE
+ * @see DND#DROP_COPY
+ * @see DND#DROP_MOVE
+ * @see DND#DROP_LINK
+ */
+public this(Control control, int style) {
+    super(control, checkStyle(style));
+    this.control = control;
+//     if (Drag_Motion is null || Drag_Leave is null || Drag_Data_Received is null || Drag_Drop is null) {
+//          DND.error(DND.ERROR_CANNOT_INIT_DROP);
+//     }
+    if (control.getData(DROPTARGETID) !is null) {
+        DND.error(DND.ERROR_CANNOT_INIT_DROP);
+    }
+    control.setData(DROPTARGETID, this);
+
+    drag_motion_handler = OS.g_signal_connect(control.handle, OS.drag_motion.ptr, cast(GCallback)&Drag_Motion, null);
+    drag_leave_handler = OS.g_signal_connect(control.handle, OS.drag_leave.ptr, cast(GCallback)&Drag_Leave, null);
+    drag_data_received_handler = OS.g_signal_connect(control.handle, OS.drag_data_received.ptr, cast(GCallback)&Drag_Data_Received, null);
+    drag_drop_handler = OS.g_signal_connect(control.handle, OS.drag_drop.ptr, cast(GCallback)&Drag_Drop, null);
+
+    // Dispose listeners
+    controlListener = new class() Listener{
+        public void handleEvent(Event event){
+            if (!this.outer.isDisposed()){
+                this.outer.dispose();
+            }
+        }
+    };
+    control.addListener(DWT.Dispose, controlListener);
+
+    this.addListener(DWT.Dispose, new class() Listener {
+        public void handleEvent(Event event){
+            onDispose();
+        }
+    });
+
+    Object effect = control.getData(DEFAULT_DROP_TARGET_EFFECT);
+    if ( auto de = cast(DropTargetEffect)effect ) {
+        dropEffect = de;
+    } else if ( auto table = cast(Table)control ) {
+        dropEffect = new TableDropTargetEffect(table);
+    } else if ( auto tree = cast(Tree) control ) {
+        dropEffect = new TreeDropTargetEffect(tree);
+    }
+
+    dragOverHeartbeat = new class() Runnable {
+        public void run() {
+            Control control = this.outer.control;
+            if (control is null || control.isDisposed() || dragOverStart is 0) return;
+            long time = System.currentTimeMillis();
+            int delay = DRAGOVER_HYSTERESIS;
+            if (time < dragOverStart) {
+                delay = cast(int)(dragOverStart - time);
+            } else {
+                dragOverEvent.time += DRAGOVER_HYSTERESIS;
+                int allowedOperations = dragOverEvent.operations;
+                TransferData[] allowedTypes = dragOverEvent.dataTypes;
+                //pass a copy of data types in to listeners in case application modifies it
+                TransferData[] dataTypes = new TransferData[allowedTypes.length];
+                System.arraycopy(allowedTypes, 0, dataTypes, 0, dataTypes.length);
+
+                DNDEvent event = new DNDEvent();
+                event.widget = dragOverEvent.widget;
+                event.x = dragOverEvent.x;
+                event.y = dragOverEvent.y;
+                event.time = dragOverEvent.time;
+                event.feedback = DND.FEEDBACK_SELECT;
+                event.dataTypes = dataTypes;
+                event.dataType = selectedDataType;
+                event.operations = dragOverEvent.operations;
+                event.detail  = selectedOperation;
+                if (dropEffect !is null) {
+                    event.item = dropEffect.getItem(dragOverEvent.x, dragOverEvent.y);
+                }
+                selectedDataType = null;
+                selectedOperation = DND.DROP_NONE;
+                notifyListeners(DND.DragOver, event);
+                if (event.dataType !is null) {
+                    for (int i = 0; i < allowedTypes.length; i++) {
+                        if (allowedTypes[i].type is event.dataType.type) {
+                            selectedDataType = event.dataType;
+                            break;
+                        }
+                    }
+                }
+                if (selectedDataType !is null && (event.detail & allowedOperations) !is 0) {
+                    selectedOperation = event.detail;
+                }
+            }
+            control = this.outer.control;
+            if (control is null || control.isDisposed()) return;
+            control.getDisplay().timerExec(delay, dragOverHeartbeat);
+        }
+    };
+}
+
+static int checkStyle (int style) {
+    if (style is DWT.NONE) return DND.DROP_MOVE;
+    return style;
+}
+
+private static extern(C) void Drag_Data_Received (
+    GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    GtkSelectionData *data,
+    uint info,
+    uint time,
+    void* user_data)
+{
+    DropTarget target = FindDropTarget(widget);
+    if (target is null) return;
+    target.drag_data_received (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, data, cast(int)/*64*/info, cast(int)/*64*/time);
+}
+
+private static extern(C) int Drag_Drop(
+    GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    uint time,
+    void* user_data)
+{
+    DropTarget target = FindDropTarget(widget);
+    if (target is null) return 0;
+    return target.drag_drop (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, cast(int)/*64*/time) ? 1 : 0;
+}
+
+private static extern(C) void Drag_Leave (
+    GtkWidget *widget,
+    GdkDragContext *context,
+    uint time,
+    void* user_data)
+{
+    DropTarget target = FindDropTarget(widget);
+    if (target is null) return;
+    target.drag_leave (widget, context, cast(int)/*64*/time);
+}
+
+private static extern(C) int Drag_Motion (
+    GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    uint time,
+    void* user_data)
+{
+    DropTarget target = FindDropTarget(widget);
+    if (target is null) return 0;
+    return target.drag_motion (widget, context, cast(int)/*64*/x, cast(int)/*64*/y, cast(int)/*64*/time) ? 1 : 0;
+}
+
+static DropTarget FindDropTarget(GtkWidget* handle) {
+    Display display = Display.findDisplay(Thread.getThis());
+    if (display is null || display.isDisposed()) return null;
+    Widget widget = display.findWidget(handle);
+    if (widget is null) return null;
+    return cast(DropTarget)widget.getData(DROPTARGETID);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when a drag and drop operation is in progress, by sending
+ * it one of the messages defined in the <code>DropTargetListener</code>
+ * interface.
+ *
+ * <p><ul>
+ * <li><code>dragEnter</code> is called when the cursor has entered the drop target boundaries
+ * <li><code>dragLeave</code> is called when the cursor has left the drop target boundaries and just before
+ * the drop occurs or is cancelled.
+ * <li><code>dragOperationChanged</code> is called when the operation being performed has changed
+ * (usually due to the user changing the selected modifier key(s) while dragging)
+ * <li><code>dragOver</code> is called when the cursor is moving over the drop target
+ * <li><code>dropAccept</code> is called just before the drop is performed.  The drop target is given
+ * the chance to change the nature of the drop or veto the drop by setting the <code>event.detail</code> field
+ * <li><code>drop</code> is called when the data is being dropped
+ * </ul></p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DropTargetListener
+ * @see #removeDropListener
+ * @see DropTargetEvent
+ */
+public void addDropListener(DropTargetListener listener) {
+    if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
+    DNDListener typedListener = new DNDListener (listener);
+    typedListener.dndWidget = this;
+    addListener (DND.DragEnter, typedListener);
+    addListener (DND.DragLeave, typedListener);
+    addListener (DND.DragOver, typedListener);
+    addListener (DND.DragOperationChanged, typedListener);
+    addListener (DND.Drop, typedListener);
+    addListener (DND.DropAccept, typedListener);
+}
+
+protected void checkSubclass () {
+    char[] name = this.classinfo.name;
+    char[] validName = DropTarget.stringof;
+    if ( validName !=/*eq*/ name ) {
+        DND.error (DWT.ERROR_INVALID_SUBCLASS);
+    }
+}
+
+void drag_data_received (
+    GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    GtkSelectionData *data,
+    uint info,
+    uint time )
+{
+    DNDEvent event = new DNDEvent();
+    if (data is null || !setEventData(context, x, y, time, event)) {
+        keyOperation = -1;
+        return;
+    }
+    keyOperation = -1;
+
+    int allowedOperations = event.operations;
+
+    // Get data in a Java format
+    Object object = null;
+    TransferData transferData = new TransferData();
+    if (data.data !is null) {
+        transferData.type = data.type;
+        transferData.length = data.length;
+        transferData.pValue = data.data;
+        transferData.format = data.format;
+        for (int i = 0; i < transferAgents.length; i++) {
+            Transfer transfer = transferAgents[i];
+            if (transfer !is null && transfer.isSupportedType(transferData)) {
+                object = transfer.nativeToJava(transferData);
+                break;
+            }
+        }
+    }
+    if (object is null) {
+        selectedOperation = DND.DROP_NONE;
+    }
+
+    event.detail = selectedOperation;
+    event.dataType = transferData;
+    event.data = object;
+    selectedOperation = DND.DROP_NONE;
+    notifyListeners(DND.Drop, event);
+    if ((allowedOperations & event.detail) is event.detail) {
+        selectedOperation = event.detail;
+    }
+    //stop native handler
+    OS.g_signal_stop_emission_by_name(widget, OS.drag_data_received.ptr);
+
+    //notify source of action taken
+    OS.gtk_drag_finish(context, selectedOperation !is DND.DROP_NONE, selectedOperation is DND.DROP_MOVE, time);
+    return;
+}
+
+bool drag_drop(
+    GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    uint time)
+{
+    DNDEvent event = new DNDEvent();
+    if (!setEventData(context, x, y, time, event)) {
+        keyOperation = -1;
+        return false;
+    }
+    keyOperation = -1;
+
+    int allowedOperations = event.operations;
+    TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+    System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+
+    event.dataType = selectedDataType;
+    event.detail = selectedOperation;
+    selectedDataType = null;
+    selectedOperation = DND.DROP_NONE;
+    notifyListeners(DND.DropAccept,event);
+    if (event.dataType !is null) {
+        for (int i = 0; i < allowedDataTypes.length; i++) {
+            if (allowedDataTypes[i].type is event.dataType.type) {
+                selectedDataType = allowedDataTypes[i];
+                break;
+            }
+        }
+    }
+    if (selectedDataType !is null && ((event.detail & allowedOperations) is event.detail)) {
+        selectedOperation = event.detail;
+    }
+    if (selectedOperation is DND.DROP_NONE) {
+        // this was not a successful drop
+        return false;
+    }
+    // ask drag source for dropped data
+    OS.gtk_drag_get_data(widget, context, selectedDataType.type, time);
+    return true;
+}
+
+void drag_leave(
+    GtkWidget *widget,
+    GdkDragContext *context,
+    uint time )
+{
+    updateDragOverHover(0, null);
+
+    if (keyOperation is -1) return;
+    keyOperation = -1;
+
+    DNDEvent event = new DNDEvent();
+    event.widget = this;
+    event.time = time;
+    event.detail = DND.DROP_NONE;
+    notifyListeners(DND.DragLeave, event);
+}
+
+bool drag_motion (
+    GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    uint time)
+{
+    int oldKeyOperation = keyOperation;
+
+    if (oldKeyOperation is -1) { //drag enter
+        selectedDataType = null;
+        selectedOperation = DND.DROP_NONE;
+    }
+
+    DNDEvent event = new DNDEvent();
+    if (!setEventData(context, x, y, time, event)) {
+        keyOperation = -1;
+        OS.gdk_drag_status(context, 0, time);
+        return false;
+    }
+
+    int allowedOperations = event.operations;
+    TransferData[] allowedDataTypes = new TransferData[event.dataTypes.length];
+    System.arraycopy(event.dataTypes, 0, allowedDataTypes, 0, allowedDataTypes.length);
+
+    if (oldKeyOperation is -1) {
+        event.type = DND.DragEnter;
+    } else {
+        if (keyOperation is oldKeyOperation) {
+            event.type = DND.DragOver;
+            event.dataType = selectedDataType;
+            event.detail = selectedOperation;
+        } else {
+            event.type = DND.DragOperationChanged;
+            event.dataType = selectedDataType;
+        }
+    }
+    updateDragOverHover(DRAGOVER_HYSTERESIS, event);
+    selectedDataType = null;
+    selectedOperation = DND.DROP_NONE;
+    notifyListeners(event.type, event);
+    if (event.detail is DND.DROP_DEFAULT) {
+        event.detail = (allowedOperations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+    }
+    if (event.dataType !is null) {
+        for (int i = 0; i < allowedDataTypes.length; i++) {
+            if (allowedDataTypes[i].type is event.dataType.type) {
+                selectedDataType = allowedDataTypes[i];
+                break;
+            }
+        }
+    }
+    if (selectedDataType !is null && (allowedOperations & event.detail) !is 0) {
+        selectedOperation = event.detail;
+    }
+
+    switch (selectedOperation) {
+        case DND.DROP_NONE:
+            OS.gdk_drag_status(context, 0, time);
+            break;
+        case DND.DROP_COPY:
+            OS.gdk_drag_status(context, OS.GDK_ACTION_COPY, time);
+            break;
+        case DND.DROP_MOVE:
+            OS.gdk_drag_status(context, OS.GDK_ACTION_MOVE, time);
+            break;
+        case DND.DROP_LINK:
+            OS.gdk_drag_status(context, OS.GDK_ACTION_LINK, time);
+            break;
+    }
+
+    if (oldKeyOperation is -1) {
+        dragOverHeartbeat.run();
+    }
+    return true;
+}
+
+/**
+ * Returns the Control which is registered for this DropTarget.  This is the control over which the
+ * user positions the cursor to drop the data.
+ *
+ * @return the Control which is registered for this DropTarget
+ */
+public Control getControl () {
+    return control;
+}
+
+/**
+ * Returns the drop effect for this DropTarget.  This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @return the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public DropTargetEffect getDropTargetEffect() {
+    return dropEffect;
+}
+
+int getOperationFromKeyState() {
+    int state;
+    OS.gdk_window_get_pointer(null, null, null, &state);
+    bool ctrl = (state & OS.GDK_CONTROL_MASK) !is 0;
+    bool shift = (state & OS.GDK_SHIFT_MASK) !is 0;
+    if (ctrl && shift) return DND.DROP_LINK;
+    if (ctrl)return DND.DROP_COPY;
+    if (shift)return DND.DROP_MOVE;
+    return DND.DROP_DEFAULT;
+}
+
+/**
+ * Returns a list of the data types that can be transferred to this DropTarget.
+ *
+ * @return a list of the data types that can be transferred to this DropTarget
+ */
+public Transfer[] getTransfer() {
+    return transferAgents;
+}
+
+void onDispose(){
+    if (control is null) return;
+    OS.g_signal_handler_disconnect(control.handle, drag_motion_handler);
+    OS.g_signal_handler_disconnect(control.handle, drag_leave_handler);
+    OS.g_signal_handler_disconnect(control.handle, drag_data_received_handler);
+    OS.g_signal_handler_disconnect(control.handle, drag_drop_handler);
+    if (transferAgents.length !is 0)
+        OS.gtk_drag_dest_unset(control.handle);
+    transferAgents = null;
+    if (controlListener !is null)
+        control.removeListener(DWT.Dispose, controlListener);
+    control.setData(DROPTARGETID, null);
+    control = null;
+    controlListener = null;
+}
+
+int opToOsOp(int operation){
+    int osOperation = 0;
+    if ((operation & DND.DROP_COPY) is DND.DROP_COPY)
+        osOperation |= OS.GDK_ACTION_COPY;
+    if ((operation & DND.DROP_MOVE) is DND.DROP_MOVE)
+        osOperation |= OS.GDK_ACTION_MOVE;
+    if ((operation & DND.DROP_LINK) is DND.DROP_LINK)
+        osOperation |= OS.GDK_ACTION_LINK;
+    return osOperation;
+}
+
+int osOpToOp(int osOperation){
+    int operation = DND.DROP_NONE;
+    if ((osOperation & OS.GDK_ACTION_COPY) is OS.GDK_ACTION_COPY)
+        operation |= DND.DROP_COPY;
+    if ((osOperation & OS.GDK_ACTION_MOVE) is OS.GDK_ACTION_MOVE)
+        operation |= DND.DROP_MOVE;
+    if ((osOperation & OS.GDK_ACTION_LINK) is OS.GDK_ACTION_LINK)
+        operation |= DND.DROP_LINK;
+    return operation;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a drag and drop operation is in progress.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see DropTargetListener
+ * @see #addDropListener
+ */
+public void removeDropListener(DropTargetListener listener) {
+    if (listener is null) DND.error (DWT.ERROR_NULL_ARGUMENT);
+    removeListener (DND.DragEnter, listener);
+    removeListener (DND.DragLeave, listener);
+    removeListener (DND.DragOver, listener);
+    removeListener (DND.DragOperationChanged, listener);
+    removeListener (DND.Drop, listener);
+    removeListener (DND.DropAccept, listener);
+}
+
+/**
+ * Specifies the data types that can be transferred to this DropTarget.  If data is
+ * being dragged that does not match one of these types, the drop target will be notified of
+ * the drag and drop operation but the currentDataType will be null and the operation
+ * will be DND.NONE.
+ *
+ * @param transferAgents a list of Transfer objects which define the types of data that can be
+ *                       dropped on this target
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if transferAgents is null</li>
+ * </ul>
+ */
+public void setTransfer(Transfer[] transferAgents){
+    if (transferAgents is null) DND.error(DWT.ERROR_NULL_ARGUMENT);
+
+    if (this.transferAgents.length !is 0) {
+        OS.gtk_drag_dest_unset(control.handle);
+    }
+    this.transferAgents = transferAgents;
+
+    GtkTargetEntry*[] targets;
+    for (int i = 0; i < transferAgents.length; i++) {
+        Transfer transfer = transferAgents[i];
+        if (transfer !is null) {
+            int[] typeIds = transfer.getTypeIds();
+            char[][] typeNames = transfer.getTypeNames();
+            for (int j = 0; j < typeIds.length; j++) {
+                GtkTargetEntry* entry = new GtkTargetEntry();
+                entry.target = cast(char*)OS.g_malloc(typeNames[j].length +1);
+                entry.target[ 0 .. typeNames[j].length ] = typeNames[j];
+                entry.target[ typeNames[j].length ] = '\0';
+                entry.info = typeIds[j];
+                GtkTargetEntry*[] newTargets = new GtkTargetEntry*[targets.length + 1];
+                SimpleType!(GtkTargetEntry*).arraycopy(targets, 0, newTargets, 0, targets.length);
+                newTargets[targets.length] = entry;
+                targets = newTargets;
+            }
+        }
+    }
+
+    auto pTargets = OS.g_malloc(targets.length * GtkTargetEntry.sizeof);
+    for (int i = 0; i < targets.length; i++) {
+        tango.stdc.string.memmove(pTargets + i*GtkTargetEntry.sizeof, targets[i], GtkTargetEntry.sizeof);
+    }
+
+    int actions = opToOsOp(getStyle());
+    OS.gtk_drag_dest_set(control.handle, 0, pTargets, targets.length, actions);
+
+    for (int i = 0; i < targets.length; i++) {
+        OS.g_free(targets[i].target);
+    }
+}
+
+/**
+ * Specifies the drop effect for this DropTarget.  This drop effect will be
+ * used during a drag and drop to display the drag under effect on the
+ * target widget.
+ *
+ * @param effect the drop effect that is registered for this DropTarget
+ *
+ * @since 3.3
+ */
+public void setDropTargetEffect(DropTargetEffect effect) {
+    dropEffect = effect;
+}
+
+bool setEventData(GdkDragContext* dragContext, int x, int y, int time, DNDEvent event) {
+    if (dragContext is null) return false;
+    if (dragContext.targets is null) return false;
+
+    // get allowed operations
+    int style = getStyle();
+    int operations = osOpToOp(dragContext.actions) & style;
+    if (operations is DND.DROP_NONE) return false;
+
+    // get current operation
+    int operation = getOperationFromKeyState();
+    keyOperation = operation;
+    if (operation is DND.DROP_DEFAULT) {
+        if ((style & DND.DROP_DEFAULT) is 0) {
+            operation = (operations & DND.DROP_MOVE) !is 0 ? DND.DROP_MOVE : DND.DROP_NONE;
+        }
+    } else {
+        if ((operation & operations) is 0) operation = DND.DROP_NONE;
+    }
+
+    // Get allowed transfer types
+    int length = OS.g_list_length(dragContext.targets);
+    TransferData[] dataTypes = new TransferData[0];
+    for (int i = 0; i < length; i++) {
+        auto pData = OS.g_list_nth(dragContext.targets, i);
+        GtkTargetPair* gtkTargetPair = cast(GtkTargetPair*)pData;
+        TransferData data = new TransferData();
+        data.type = gtkTargetPair.target;
+        for (int j = 0; j < transferAgents.length; j++) {
+            Transfer transfer = transferAgents[j];
+            if (transfer !is null && transfer.isSupportedType(data)) {
+                TransferData[] newDataTypes = new TransferData[dataTypes.length + 1];
+                System.arraycopy(dataTypes, 0, newDataTypes, 0, dataTypes.length);
+                newDataTypes[dataTypes.length] = data;
+                dataTypes = newDataTypes;
+                break;
+            }
+        }
+    }
+    if (dataTypes.length is 0) return false;
+
+    auto window = OS.GTK_WIDGET_WINDOW(control.handle);
+    int origin_x, origin_y;
+    OS.gdk_window_get_origin(window, &origin_x, &origin_y);
+    Point coordinates = new Point(origin_x + x, origin_y + y);
+
+    event.widget = this;
+    event.x = coordinates.x;
+    event.y = coordinates.y;
+    event.time = time;
+    event.feedback = DND.FEEDBACK_SELECT;
+    event.dataTypes = dataTypes;
+    event.dataType = dataTypes[0];
+    event.operations = operations;
+    event.detail = operation;
+    if (dropEffect !is null) {
+        event.item = dropEffect.getItem(coordinates.x, coordinates.y);
+    }
+    return true;
+}
+
+void updateDragOverHover(long delay, DNDEvent event) {
+    if (delay is 0) {
+        dragOverStart = 0;
+        dragOverEvent = null;
+        return;
+    }
+    dragOverStart = System.currentTimeMillis() + delay;
+    if (dragOverEvent is null) dragOverEvent = new DNDEvent();
+    dragOverEvent.x = event.x;
+    dragOverEvent.y = event.y;
+    TransferData[] dataTypes = new TransferData[ event.dataTypes.length];
+    System.arraycopy( event.dataTypes, 0, dataTypes, 0, dataTypes.length);
+    dragOverEvent.dataTypes  = dataTypes;
+    dragOverEvent.operations = event.operations;
+    dragOverEvent.time = event.time;
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetAdapter.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DropTargetAdapter;
+
+import dwt.dnd.DropTargetListener;
+import dwt.dnd.DropTargetEvent;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the <code>DropTargetListener</code> interface.
+ * <p>
+ * Classes that wish to deal with <code>DropTargetEvent</code>s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * </p>
+ *
+ * @see DropTargetListener
+ * @see DropTargetEvent
+ */
+public class DropTargetAdapter : DropTargetListener {
+
+/**
+ * This implementation of <code>dragEnter</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dragEnter</code>.
+ */
+public void dragEnter(DropTargetEvent event){}
+/**
+ * This implementation of <code>dragLeave</code> does nothing.
+ * For additional information see <code>DropTargetListener.dragOperationChanged</code>.
+ */
+public void dragLeave(DropTargetEvent event){}
+/**
+ * This implementation of <code>dragOperationChanged</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dragOperationChanged</code>.
+ */
+public void dragOperationChanged(DropTargetEvent event){}
+/**
+ * This implementation of <code>dragOver</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dragOver</code>.
+ */
+public void dragOver(DropTargetEvent event){}
+/**
+ * This implementation of <code>drop</code> does nothing.
+ * For additional information see <code>DropTargetListener.drop</code>.
+ */
+public void drop(DropTargetEvent event){}
+/**
+ * This implementation of <code>dropAccept</code> permits the default
+ * operation defined in <code>event.detail</code>to be performed on the current data type
+ * defined in <code>event.currentDataType</code>.
+ * For additional information see <code>DropTargetListener.dropAccept</code>.
+ */
+public void dropAccept(DropTargetEvent event){}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetEffect.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DropTargetEffect;
+
+
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Control;
+import dwt.widgets.Item;
+import dwt.widgets.Table;
+import dwt.widgets.Tree;
+import dwt.widgets.TreeItem;
+import dwt.widgets.Widget;
+import dwt.dnd.DropTargetAdapter;
+
+
+/**
+ * This class provides a default drag under effect during a drag and drop.
+ * The current implementation does not provide any visual feedback.
+ *
+ * <p>The drop target effect has the same API as the
+ * <code>DropTargetAdapter</code> so that it can provide custom visual
+ * feedback when a <code>DropTargetEvent</code> occurs.
+ * </p>
+ *
+ * <p>Classes that wish to provide their own drag under effect
+ * can extend the <code>DropTargetEffect</code> and override any applicable methods
+ * in <code>DropTargetAdapter</code> to display their own drag under effect.</p>
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_EXPAND, FEEDBACK_INSERT_AFTER, FEEDBACK_INSERT_BEFORE,
+ * FEEDBACK_NONE, FEEDBACK_SELECT, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class DropTargetEffect : DropTargetAdapter {
+    Control control;
+
+    /**
+     * Creates a new <code>DropTargetEffect</code> to handle the drag under effect on the specified
+     * <code>Control</code>.
+     *
+     * @param control the <code>Control</code> over which the user positions the cursor to drop the data
+     *
+     * @exception IllegalArgumentException <ul>
+     *    <li>ERROR_NULL_ARGUMENT - if the control is null</li>
+     * </ul>
+     */
+    public this(Control control) {
+        if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+        this.control = control;
+    }
+
+    /**
+     * Returns the Control which is registered for this DropTargetEffect.  This is the control over which the
+     * user positions the cursor to drop the data.
+     *
+     * @return the Control which is registered for this DropTargetEffect
+     */
+    public Control getControl() {
+        return control;
+    }
+
+    /**
+     * Returns the item at the given x-y coordinate in the receiver
+     * or null if no such item exists. The x-y coordinate is in the
+     * display relative coordinates.
+     *
+     * @param x the x coordinate used to locate the item
+     * @param y the y coordinate used to locate the item
+     * @return the item at the given x-y coordinate, or null if the coordinate is not in a selectable item
+     */
+    public Widget getItem(int x, int y) {
+        if ( auto table = cast(Table)control ) {
+            return getItem(table, x, y);
+        }
+        if ( auto tree = cast(Tree)control ) {
+            return getItem(tree, x, y);
+        }
+        return null;
+    }
+
+    Widget getItem(Table table, int x, int y) {
+        Point coordinates = new Point(x, y);
+        coordinates = table.toControl(coordinates);
+        Item item = table.getItem(coordinates);
+        if (item is null) {
+            Rectangle area = table.getClientArea();
+            if (area.contains(coordinates)) {
+                // Scan across the width of the table.
+                for (int x1 = area.x; x1 < area.x + area.width; x1++) {
+                    Point pt = new Point(x1, coordinates.y);
+                    item = table.getItem(pt);
+                    if (item !is null) {
+                        break;
+                    }
+                }
+            }
+        }
+        return item;
+    }
+
+    Widget getItem(Tree tree, int x, int y) {
+        Point coordinates = new Point(x, y);
+        coordinates = tree.toControl(coordinates);
+        Item item = tree.getItem(coordinates);
+        if (item is null) {
+            Rectangle area = tree.getClientArea();
+            if (area.contains(coordinates)) {
+                // Scan across the width of the tree.
+                for (int x1 = area.x; x1 < area.x + area.width; x1++) {
+                    Point pt = new Point(x1, coordinates.y);
+                    item = tree.getItem(pt);
+                    if (item !is null) {
+                        break;
+                    }
+                }
+            }
+        }
+        return item;
+    }
+
+    TreeItem nextItem(Tree tree, TreeItem item) {
+        if (item is null) return null;
+        if (item.getExpanded()) return item.getItem(0);
+        TreeItem childItem = item;
+        TreeItem parentItem = childItem.getParentItem();
+        int index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
+        int count = parentItem is null ? tree.getItemCount() : parentItem.getItemCount();
+        while (true) {
+            if (index + 1 < count) return parentItem is null ? tree.getItem(index + 1) : parentItem.getItem(index + 1);
+            if (parentItem is null) return null;
+            childItem = parentItem;
+            parentItem = childItem.getParentItem();
+            index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
+            count = parentItem is null ? tree.getItemCount() : parentItem.getItemCount();
+        }
+    }
+
+    TreeItem previousItem(Tree tree, TreeItem item) {
+        if (item is null) return null;
+        TreeItem childItem = item;
+        TreeItem parentItem = childItem.getParentItem();
+        int index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
+        if (index is 0) return parentItem;
+        TreeItem nextItem = parentItem is null ? tree.getItem(index-1) : parentItem.getItem(index-1);
+        int count = nextItem.getItemCount();
+        while (count > 0 && nextItem.getExpanded()) {
+            nextItem = nextItem.getItem(count - 1);
+            count = nextItem.getItemCount();
+        }
+        return nextItem;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetEvent.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DropTargetEvent;
+
+
+import dwt.events.TypedEvent;
+import dwt.widgets.Widget;
+import dwt.dnd.TransferData;
+import dwt.dnd.DNDEvent;
+import dwt.widgets.Event;
+
+/**
+ * The DropTargetEvent contains the event information passed in the methods of the DropTargetListener.
+ */
+public class DropTargetEvent : TypedEvent {
+    /**
+     * The x-cordinate of the cursor relative to the <code>Display</code>
+     */
+    public int x;
+
+    /**
+     * The y-cordinate of the cursor relative to the <code>Display</code>
+     */
+    public int y;
+
+    /**
+     * The operation being performed.
+     * @see DND#DROP_NONE
+     * @see DND#DROP_MOVE
+     * @see DND#DROP_COPY
+     * @see DND#DROP_LINK
+     */
+    public int detail;
+
+    /**
+     * A bitwise OR'ing of the operations that the DragSource can support
+     * (e.g. DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK).
+     * The detail value must be a member of this list or DND.DROP_NONE.
+     * @see DND#DROP_NONE
+     * @see DND#DROP_MOVE
+     * @see DND#DROP_COPY
+     * @see DND#DROP_LINK
+     */
+    public int operations;
+
+    /**
+     * A bitwise OR'ing of the drag under effect feedback to be displayed to the user
+     * (e.g. DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND).
+     * <p>A value of DND.FEEDBACK_NONE indicates that no drag under effect will be displayed.</p>
+     * <p>Feedback effects will only be applied if they are applicable.</p>
+     * <p>The default value is DND.FEEDBACK_SELECT.</p>
+     * @see DND#FEEDBACK_NONE
+     * @see DND#FEEDBACK_SELECT
+     * @see DND#FEEDBACK_INSERT_BEFORE
+     * @see DND#FEEDBACK_INSERT_AFTER
+     * @see DND#FEEDBACK_SCROLL
+     * @see DND#FEEDBACK_EXPAND
+     */
+    public int feedback;
+
+    /**
+     * If the associated control is a table or tree, this field contains the item located
+     * at the cursor coordinates.
+     */
+    public Widget item;
+
+    /**
+     * The type of data that will be dropped.
+     */
+    public TransferData currentDataType;
+
+    /**
+     * A list of the types of data that the DragSource is capable of providing.
+     * The currentDataType must be a member of this list.
+     */
+    public TransferData[] dataTypes;
+
+    static const long serialVersionUID = 3256727264573338678L;
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given untyped event.
+ *
+ * @param e the untyped event containing the information
+ */
+public this(DNDEvent e) {
+    super(cast(Event)e);
+    this.data = e.data;
+    this.x = e.x;
+    this.y = e.y;
+    this.detail = e.detail;
+    this.currentDataType = e.dataType;
+    this.dataTypes = e.dataTypes;
+    this.operations = e.operations;
+    this.feedback = e.feedback;
+    this.item = e.item;
+}
+void updateEvent(DNDEvent e) {
+    e.widget = this.widget;
+    e.time = this.time;
+    e.data = this.data;
+    e.x = this.x;
+    e.y = this.y;
+    e.detail = this.detail;
+    e.dataType = this.currentDataType;
+    e.dataTypes = this.dataTypes;
+    e.operations = this.operations;
+    e.feedback = this.feedback;
+    e.item = this.item;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/DropTargetListener.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.DropTargetListener;
+
+import dwt.internal.DWTEventListener;
+import dwt.dnd.DropTargetEvent;
+
+/**
+ * The <code>DropTargetListener</code> class provides event notification to the application
+ * for DropTarget events.
+ *
+ * <p>As the user moves the cursor into, over and out of a Control that has been designated
+ * as a DropTarget, events indicate what operation can be performed and what data can be
+ * transferred if a drop where to occur at that point.
+ * The application can respond to these events and change the type of data that will
+ * be dropped by modifying event.currentDataType, or change the operation that will be performed
+ * by modifying the event.detail field or stop any drop from happening on the current target
+ * by setting the event.detail field to DND_DROP_NONE.</p>
+ *
+ * <p>When the user causes a drop to happen by releasing the mouse over a valid drop target,
+ * the application has one last chance to change the data type of the drop through the
+ * DropAccept event.  If the drop is still allowed, the DropAccept event is immediately
+ * followed by the Drop event.  In the Drop event, the application can still change the
+ * operation that is performed but the data type is fixed.</p>
+ *
+ * @see DropTargetEvent
+ *
+ */
+public interface DropTargetListener : DWTEventListener {
+
+/**
+ * The cursor has entered the drop target boundaries.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * <li>(in,out)feedback
+ * </ul></p>
+ *
+ * <p>The <code>operation</code> value is determined by the modifier keys pressed by the user.
+ * If no keys are pressed the <code>event.detail</code> field is set to DND.DROP_DEFAULT.
+ * If the application does not set the <code>event.detail</code> to something other
+ * than <code>DND.DROP_DEFAULT</code> the operation will be set to the platform defined standard
+ * default.</p>
+ *
+ * <p>The <code>currentDataType</code> is determined by the first transfer agent specified in
+ * setTransfer() that matches a data type provided by the drag source.</p>
+ *
+ * <p>It is possible to get a DragEnter event when the drag source does not provide any matching data.
+ * In this case, the default operation is DND.DROP_NONE and the currentDataType is null.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the <code>operations</code>
+ * field or DND.DROP_NONE.</p>
+ *
+ * <p>The application can also change the type of data being requested by
+ * modifying the <code>currentDataTypes</code> field  but the value must be one of the values
+ * in the <code>dataTypes</code> list.</p>
+ *
+ * @param event  the information associated with the drag enter event
+ *
+ * @see DropTargetEvent
+ */
+public void dragEnter(DropTargetEvent event);
+
+/**
+ * The cursor has left the drop target boundaries OR the drop has been cancelled OR the data
+ * is about to be dropped.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in)currentDataType
+ * <li>(in)operations
+ * <li>(in)detail
+ * </ul></p>
+ *
+ * @param event  the information associated with the drag leave event
+ *
+ * @see DropTargetEvent
+ */
+public void dragLeave(DropTargetEvent event);
+
+/**
+ * The operation being performed has changed (usually due to the user changing the selected modifier key(s)
+ * while dragging).
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * <li>(in,out)feedback
+ * </ul></p>
+ *
+ * <p>The <code>operation</code> value is determined by the modifier keys pressed by the user.
+ * If no keys are pressed the <code>event.detail</code> field is set to DND.DROP_DEFAULT.
+ * If the application does not set the <code>event.detail</code> to something other than
+ * <code>DND.DROP_DEFAULT</code> the operation will be set to the platform defined standard default.</p>
+ *
+ * <p>The <code>currentDataType</code> value is determined by the value assigned to
+ * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the <code>operations</code>
+ * field.</p>
+ *
+ * <p>The application can also change the type of data being requested by modifying
+ * the <code>currentDataTypes</code> field  but the value must be one of the values in the
+ * <code>dataTypes</code> list.</p>
+ *
+ * @param event  the information associated with the drag operation changed event
+ *
+ * @see DropTargetEvent
+ */
+public void dragOperationChanged(DropTargetEvent event);
+
+/**
+ * The cursor is moving over the drop target.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * <li>(in,out)feedback
+ * </ul></p>
+ *
+ * <p>The <code>operation</code> value is determined by the value assigned to
+ * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p>
+ *
+ * <p>The <code>currentDataType</code> value is determined by the value assigned to
+ * <code>currentDataType</code> in previous dragEnter and dragOver calls.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the <code>operations</code>
+ * field.</p>
+ *
+ * <p>The application can also change the type of data being requested by modifying the
+ * <code>currentDataTypes</code> field  but the value must be one of the values in the
+ * <code>dataTypes</code> list.</p>
+ *
+ * <p>NOTE: At this point the <code>data</code> field is null.  On some platforms, it is possible
+ * to obtain the data being transferred before the transfer occurs but in most platforms this is
+ * not possible.  On those platforms where the data is available, the application can access the
+ * data as follows:</p>
+ *
+ * <pre><code>
+ * public void dragOver(DropTargetEvent event) {
+ *       TextTransfer textTransfer = TextTransfer.getInstance();
+ *       String data = (String)textTransfer.nativeToJava(event.currentDataType);
+ *       if (data !is null) {
+ *           System.out.println("Data to be dropped is (Text)"+data);
+ *       }
+ * };
+ * </code></pre>
+ *
+ * @param event  the information associated with the drag over event
+ *
+ * @see DropTargetEvent
+ */
+public void dragOver(DropTargetEvent event);
+
+/**
+ * The data is being dropped.  The data field contains java format of the data being dropped.
+ * To determine the type of the data object, refer to the documentation for the Transfer subclass
+ * specified in event.currentDataType.
+ *
+ * <p>The following fields in DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in,out)detail
+ * <li>(in)currentDataType
+ * <li>(in)data
+ * </ul></p>
+ *
+ * <p>The application can refuse to perform the drop operation by setting the detail
+ * field to DND.DROP_NONE.</p>
+ *
+ * @param event the information associated with the drop event
+ *
+ * @see DropTargetEvent
+ */
+public void drop(DropTargetEvent event);
+
+/**
+ * The drop is about to be performed.
+ * The drop target is given a last chance to change the nature of the drop.
+ *
+ * <p>The following fields in the DropTargetEvent apply:
+ * <ul>
+ * <li>(in)widget
+ * <li>(in)time
+ * <li>(in)x
+ * <li>(in)y
+ * <li>(in)dataTypes
+ * <li>(in,out)currentDataType
+ * <li>(in)operations
+ * <li>(in,out)detail
+ * </ul></p>
+ *
+ * <p>The application can veto the drop by setting the <code>event.detail</code> field to
+ * <code>DND.DROP_NONE</code>.</p>
+ *
+ * <p>The application can change the operation that will be performed by modifying the
+ * <code>detail</code> field but the choice must be one of the values in the
+ * <code>operations</code> field.</p>
+ *
+ * <p>The application can also change the type of data being requested by modifying the
+ * <code>currentDataTypes</code> field  but the value must be one of the values in the <
+ * code>dataTypes</code> list.</p>
+ *
+ * @param event  the information associated with the drop accept event
+ *
+ * @see DropTargetEvent
+ */
+public void dropAccept(DropTargetEvent event);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/FileTransfer.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.FileTransfer;
+
+import dwt.internal.gtk.OS;
+import dwt.dnd.ByteArrayTransfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+import dwt.dwthelper.utils;
+
+/**
+ * The class <code>FileTransfer</code> provides a platform specific mechanism
+ * for converting a list of files represented as a java <code>String[]</code> to a
+ * platform specific representation of the data and vice versa.
+ * Each <code>String</code> in the array contains the absolute path for a single
+ * file or directory.
+ * See <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String[]</code> containing a list of files is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     File file1 = new File("C:\temp\file1");
+ *     File file2 = new File("C:\temp\file2");
+ *     String[] fileData = new String[2];
+ *     fileData[0] = file1.getAbsolutePath();
+ *     fileData[1] = file2.getAbsolutePath();
+ * </code></pre>
+ */
+public class FileTransfer : ByteArrayTransfer {
+
+    private static FileTransfer _instance;
+    private static const char[] URI_LIST = "text/uri-list"; //$NON-NLS-1$
+    private static const int URI_LIST_ID;
+    private static const char[] separator = "\r\n";
+
+static this(){
+    URI_LIST_ID = registerType(URI_LIST);
+    _instance = new FileTransfer();
+}
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the FileTransfer class.
+ *
+ * @return the singleton instance of the FileTransfer class
+ */
+public static FileTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a list of file names
+ * represented by a java <code>String[]</code> to a platform specific representation.
+ * Each <code>String</code> in the array contains the absolute path for a single
+ * file or directory.  For additional information see
+ * <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String[]</code> containing the file names to be
+ * converted
+ * @param transferData an empty <code>TransferData</code> object; this
+ *  object will be filled in on return with the platform specific format of the data
+ */
+public void javaToNative(Object object, TransferData transferData) {
+    transferData.result = 0;
+    if (!checkFile(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    char[][] files = (cast(ArrayWrapperString2)object).array;
+    char[] buffer;
+    for (int i = 0; i < files.length; i++) {
+        char[] string = files[i];
+        if (string.ptr is null) continue;
+        if (string.length is 0) continue;
+        GError* error;
+        auto localePtr = OS.g_locale_from_utf8(string.ptr, -1, null, null, &error);
+        if (error !is null || localePtr is null) continue;
+        auto uriPtr = OS.g_filename_to_uri(localePtr, null, &error);
+        OS.g_free(localePtr);
+        if (error !is null || uriPtr is null) continue;
+        char[] temp = tango.stdc.stringz.fromUtf8z( uriPtr ).dup;
+        OS.g_free(uriPtr);
+        int newLength = (i > 0) ? buffer.length+separator.length+temp.length :  temp.length;
+        char[] newBuffer = new char[newLength];
+        int offset = 0;
+        if (i > 0) {
+            System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
+            offset +=  buffer.length;
+            System.arraycopy(separator, 0, newBuffer, offset, separator.length);
+            offset += separator.length;
+        }
+        System.arraycopy(temp, 0, newBuffer, offset, temp.length);
+        buffer = newBuffer;
+    }
+    if (buffer.length is 0) return;
+    char* ptr = cast(char*)OS.g_malloc(buffer.length+1);
+    ptr[ 0 .. buffer.length ] = buffer;
+    ptr[ buffer.length ] = '\0';
+    transferData.pValue = ptr;
+    transferData.length = buffer.length;
+    transferData.format = 8;
+    transferData.result = 1;
+}
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of a list of file names to a java <code>String[]</code>.
+ * Each String in the array contains the absolute path for a single file or directory.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String[]</code> containing a list of file names if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData) {
+    if ( !isSupportedType(transferData) ||  transferData.pValue is null ||  transferData.length <= 0 ) return null;
+    char[] temp = transferData.pValue[ 0 .. transferData.length ];
+    char*[] files;
+    int offset = 0;
+    for (int i = 0; i < temp.length - 1; i++) {
+        if (temp[i] is '\r' && temp[i+1] is '\n') {
+            int size =  i - offset;
+            char* file = cast(char*)OS.g_malloc(size + 1);
+            char[] fileBuffer = new char[size + 1];
+            System.arraycopy(temp, offset, fileBuffer, 0, size);
+            file[ 0 .. size + 1 ] = fileBuffer;
+            char*[] newFiles = new char*[files.length + 1];
+            SimpleType!(char*).arraycopy(files, 0, newFiles, 0, files.length);
+            newFiles[files.length] = file;
+            files = newFiles;
+            offset = i + 2;
+        }
+    }
+    if (offset < temp.length - 2) {
+        int size =  temp.length - offset;
+        char* file = cast(char*)OS.g_malloc(size + 1);
+        char[] fileBuffer = new char[size + 1];
+        System.arraycopy(temp, offset, fileBuffer, 0, size);
+        file[ 0 .. size+1 ] = fileBuffer;
+        char*[] newFiles = new char*[files.length + 1];
+        SimpleType!(char*).arraycopy(files, 0, newFiles, 0, files.length);
+        newFiles[files.length] = file;
+        files = newFiles;
+    }
+    char[][] fileNames;
+    for (int i = 0; i < files.length; i++) {
+        GError* error;
+        auto localePtr = OS.g_filename_from_uri(files[i], null, &error);
+        OS.g_free(files[i]);
+        if (error !is null || localePtr is null) continue;
+        auto utf8Ptr = OS.g_locale_to_utf8(localePtr, -1, null, null, &error);
+        OS.g_free(localePtr);
+        if (error !is null || utf8Ptr is null) continue;
+        char[] buffer = tango.stdc.stringz.fromUtf8z( utf8Ptr ).dup;
+        OS.g_free(utf8Ptr);
+        char[] name = buffer;
+        char[][] newFileNames = new char[][]( fileNames.length + 1 );
+        System.arraycopy(fileNames, 0, newFileNames, 0, fileNames.length);
+        newFileNames[fileNames.length] = name;
+        fileNames = newFileNames;
+    }
+    if (fileNames.length is 0) return null;
+    return new ArrayWrapperString2( fileNames );
+}
+
+protected int[] getTypeIds(){
+    return [URI_LIST_ID];
+}
+
+protected char[][] getTypeNames(){
+    return [URI_LIST];
+}
+
+bool checkFile(Object object) {
+    if( object is null ) return false;
+    ArrayWrapperString2 arr = cast(ArrayWrapperString2)object;
+    if( arr is null ) return false;
+    if( arr.array.length is 0 ) return false;
+
+    char[][] strings = arr.array;
+    for (int i = 0; i < strings.length; i++) {
+        if (strings[i] is null || strings[i].length is 0) return false;
+    }
+    return true;
+}
+
+protected bool validate(Object object) {
+    return checkFile(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/HTMLTransfer.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.HTMLTransfer;
+
+import dwt.internal.gtk.OS;
+import dwt.dnd.ByteArrayTransfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+import dwt.dwthelper.utils;
+
+static import tango.text.Util;
+
+/**
+ * The class <code>HTMLTransfer</code> provides a platform specific mechanism
+ * for converting text in HTML format represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa.  See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String</code> containing HTML text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String htmlData = "<p>This is a paragraph of text.</p>";
+ * </code></pre>
+ */
+public class HTMLTransfer : ByteArrayTransfer {
+
+    private static HTMLTransfer _instance;
+    private static const char[] TEXT_HTML = "text/html"; //$NON-NLS-1$
+    private static const int TEXT_HTML_ID;
+    private static const char[] TEXT_HTML2 = "TEXT/HTML"; //$NON-NLS-1$
+    private static const int TEXT_HTML2_ID;
+
+static this(){
+    _instance = new HTMLTransfer();
+    TEXT_HTML_ID = registerType(TEXT_HTML);
+    TEXT_HTML2_ID = registerType(TEXT_HTML2);
+}
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the HTMLTransfer class.
+ *
+ * @return the singleton instance of the HTMLTransfer class
+ */
+public static HTMLTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts HTML-formatted text
+ * represented by a java <code>String</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String</code> containing HTML text
+ * @param transferData an empty <code>TransferData</code> object; this
+ *  object will be filled in on return with the platform specific format of the data
+ */
+public void javaToNative (Object object, TransferData transferData){
+    transferData.result = 0;
+    if (!checkHTML(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    char[] string = (cast(ArrayWrapperString)object).array;
+    char* pValue = cast(char*)OS.g_malloc(string.length);
+    if (pValue is null) return;
+    pValue[0 .. string.length ] = string;
+    transferData.length = string.length;
+    transferData.format = 8;
+    transferData.pValue = pValue;
+    transferData.result = 1;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of HTML text to a java <code>String</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String</code> containing HTML text if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData){
+    if ( !isSupportedType(transferData) ||  transferData.pValue is null ) return null;
+    /* Ensure byteCount is a multiple of 2 bytes */
+    int size = (transferData.format * transferData.length / 8) / 2 * 2;
+    if (size <= 0) return null;
+    char[] chars = transferData.pValue[ 0 .. size ].dup;
+    return new ArrayWrapperString( chars[ 0 .. tango.text.Util.locate( chars, '\0' ) ] );
+}
+protected int[] getTypeIds() {
+    return [TEXT_HTML_ID, TEXT_HTML2_ID];
+}
+
+protected char[][] getTypeNames() {
+    return [TEXT_HTML, TEXT_HTML2];
+}
+
+bool checkHTML(Object object) {
+    if( object is null ) return false;
+    auto arr = cast(ArrayWrapperString)object;
+    if( arr is null ) return false;
+    if( arr.array.length is 0 ) return false;
+    return true;
+}
+
+protected bool validate(Object object) {
+    return checkHTML(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/RTFTransfer.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.RTFTransfer;
+
+import dwt.internal.Converter;
+import dwt.internal.gtk.OS;
+import dwt.dnd.ByteArrayTransfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+
+import dwt.dwthelper.utils;
+static import tango.text.Util;
+
+/**
+ * The class <code>RTFTransfer</code> provides a platform specific mechanism
+ * for converting text in RTF format represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa.  See
+ * <code>Transfer</code> for additional information.
+ *
+ * <p>An example of a java <code>String</code> containing RTF text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String rtfData = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i Hello World}";
+ * </code></pre>
+ */
+public class RTFTransfer : ByteArrayTransfer {
+
+    private static RTFTransfer _instance;
+    private static const char[] TEXT_RTF = "text/rtf"; //$NON-NLS-1$
+    private static const int TEXT_RTF_ID;
+    private static const char[] TEXT_RTF2 = "TEXT/RTF"; //$NON-NLS-1$
+    private static const int TEXT_RTF2_ID;
+    private static const char[] APPLICATION_RTF = "application/rtf"; //$NON-NLS-1$
+    private static const int APPLICATION_RTF_ID;
+
+static this(){
+    TEXT_RTF_ID = registerType(TEXT_RTF);
+    TEXT_RTF2_ID = registerType(TEXT_RTF2);
+    APPLICATION_RTF_ID = registerType(APPLICATION_RTF);
+    _instance = new RTFTransfer();
+}
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the RTFTransfer class.
+ *
+ * @return the singleton instance of the RTFTransfer class
+ */
+public static RTFTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts RTF-formatted text
+ * represented by a java <code>String</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>String</code> containing RTF text
+ * @param transferData an empty <code>TransferData</code> object; this
+ *  object will be filled in on return with the platform specific format of the data
+ */
+public void javaToNative (Object object, TransferData transferData){
+    transferData.result = 0;
+    if (!checkRTF(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    char[] string = (cast(ArrayWrapperString)object).array;
+    char* pValue = cast(char*)OS.g_malloc(string.length + 1);
+    if (pValue is null) return;
+    pValue[ 0 .. string.length ] = string;
+    pValue[ string.length ] = '\0';
+    transferData.length = string.length;
+    transferData.format = 8;
+    transferData.pValue = pValue;
+    transferData.result = 1;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of RTF text to a java <code>String</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * been converted
+ * @return a java <code>String</code> containing RTF text if the
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData){
+    if ( !isSupportedType(transferData) ||  transferData.pValue is null ) return null;
+    int size = transferData.format * transferData.length / 8;
+    if (size is 0) return null;
+    byte[] buffer = new byte[size];
+    char [] chars = transferData.pValue[ 0 .. size];
+    return new ArrayWrapperString( chars[ 0 .. tango.text.Util.locate( chars, '\0' ) ] );
+}
+
+protected int[] getTypeIds() {
+    return [TEXT_RTF_ID, TEXT_RTF2_ID, APPLICATION_RTF_ID];
+}
+
+protected char[][] getTypeNames() {
+    return [TEXT_RTF, TEXT_RTF2, APPLICATION_RTF];
+}
+
+bool checkRTF(Object object) {
+    if( object is null ) return false;
+    ArrayWrapperString astr = cast(ArrayWrapperString)object;
+    if( astr is null ) return false;
+    return astr.array.length > 0;
+}
+
+protected bool validate(Object object) {
+    return checkRTF(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TableDragSourceEffect.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.TableDragSourceEffect;
+
+
+import dwt.DWT;
+import dwt.graphics.Image;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Display;
+import dwt.widgets.Table;
+import dwt.dnd.DragSourceEffect;
+import dwt.dnd.DragSourceEvent;
+
+import Math = tango.math.Math;
+
+/**
+ * This class provides default implementations to display a source image
+ * when a drag is initiated from a <code>Table</code>.
+ *
+ * <p>Classes that wish to provide their own source image for a <code>Table</code> can
+ * extend the <code>TableDragSourceEffect</code> class, override the
+ * <code>TableDragSourceEffect.dragStart</code> method and set the field
+ * <code>DragSourceEvent.image</code> with their own image.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag source effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class TableDragSourceEffect : DragSourceEffect {
+    Image dragSourceImage = null;
+
+    /**
+     * Creates a new <code>TableDragSourceEffect</code> to handle drag effect
+     * from the specified <code>Table</code>.
+     *
+     * @param table the <code>Table</code> that the user clicks on to initiate the drag
+     */
+    public this(Table table) {
+        super(table);
+    }
+
+    /**
+     * This implementation of <code>dragFinished</code> disposes the image
+     * that was created in <code>TableDragSourceEffect.dragStart</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragFinished(event)</code>
+     * to dispose the image in the default implementation.
+     *
+     * @param event the information associated with the drag finished event
+     */
+    public void dragFinished(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+    }
+
+    /**
+     * This implementation of <code>dragStart</code> will create a default
+     * image that will be used during the drag. The image should be disposed
+     * when the drag is completed in the <code>TableDragSourceEffect.dragFinished</code>
+     * method.
+     *
+     * Subclasses that override this method should call <code>super.dragStart(event)</code>
+     * to use the image from the default implementation.
+     *
+     * @param event the information associated with the drag start event
+     */
+    public void dragStart(DragSourceEvent event) {
+        event.image = getDragSourceImage(event);
+    }
+
+    Image getDragSourceImage(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+
+        Table table = cast(Table) control;
+        if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) return null;
+        /*
+        * Bug in GTK.  gtk_tree_selection_get_selected_rows() segmentation faults
+        * in versions smaller than 2.2.4 if the model is NULL.  The fix is
+        * to give a valid pointer instead.
+        */
+        auto handle = table.handle;
+        auto selection = OS.gtk_tree_view_get_selection (handle);
+        int dummy;
+        void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null;
+        auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model);
+        if (list is null) return null;
+        int count = Math.min(10, OS.g_list_length (list));
+
+        Display display = table.getDisplay();
+        if (count is 1) {
+            auto path = OS.g_list_nth_data (list, 0);
+            auto pixmap = OS.gtk_tree_view_create_row_drag_icon(handle, path);
+            dragSourceImage =  Image.gtk_new(display, DWT.ICON, pixmap, null);
+        } else {
+            int width = 0, height = 0;
+            int w, h;
+            int[] yy, hh; yy.length = count; hh.length = count;
+            GdkDrawable*[] pixmaps; pixmaps.length = count;
+            GdkRectangle rect;
+            for (int i=0; i<count; i++) {
+                auto path = OS.g_list_nth_data (list, i);
+                OS.gtk_tree_view_get_cell_area (handle, path, null, &rect);
+                pixmaps[i] = OS.gtk_tree_view_create_row_drag_icon(handle, path);
+                OS.gdk_drawable_get_size(pixmaps[i], &w, &h);
+                width = Math.max(width, w);
+                height = rect.y + h - yy[0];
+                yy[i] = rect.y;
+                hh[i] = h;
+            }
+            auto source = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, -1);
+            auto gcSource = OS.gdk_gc_new(source);
+            auto mask = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, 1);
+            auto gcMask = OS.gdk_gc_new(mask);
+            GdkColor color;
+            color.pixel = 0;
+            OS.gdk_gc_set_foreground(gcMask, &color);
+            OS.gdk_draw_rectangle(mask, gcMask, 1, 0, 0, width, height);
+            color.pixel = 1;
+            OS.gdk_gc_set_foreground(gcMask, &color);
+            for (int i=0; i<count; i++) {
+                OS.gdk_draw_drawable(source, gcSource, pixmaps[i], 0, 0, 0, yy[i] - yy[0], -1, -1);
+                OS.gdk_draw_rectangle(mask, gcMask, 1, 0, yy[i] - yy[0], width, hh[i]);
+                OS.g_object_unref(pixmaps[i]);
+            }
+            OS.g_object_unref(gcSource);
+            OS.g_object_unref(gcMask);
+            dragSourceImage  = Image.gtk_new(display, DWT.ICON, source, mask);
+        }
+        OS.g_list_free (list);
+
+        return dragSourceImage;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TableDropTargetEffect.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.TableDropTargetEffect;
+
+
+import dwt.graphics.Point;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Table;
+import dwt.dnd.DropTargetEffect;
+import dwt.dnd.DropTargetEvent;
+import dwt.dnd.DND;
+
+import dwt.dwthelper.System;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert and scroll)
+ * when a drag occurs over a <code>Table</code>.
+ *
+ * <p>Classes that wish to provide their own drag under effect for a <code>Table</code>
+ * can extend the <code>TableDropTargetEffect</code> and override any applicable methods
+ * in <code>TableDropTargetEffect</code> to display their own drag under effect.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_SELECT, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class TableDropTargetEffect : DropTargetEffect {
+    static const int SCROLL_HYSTERESIS = 150; // milli seconds
+
+    int scrollIndex;
+    long scrollBeginTime;
+
+    /**
+     * Creates a new <code>TableDropTargetEffect</code> to handle the drag under effect on the specified
+     * <code>Table</code>.
+     *
+     * @param table the <code>Table</code> over which the user positions the cursor to drop the data
+     */
+    public this(Table table) {
+        super(table);
+    }
+
+    int checkEffect(int effect) {
+        // Some effects are mutually exclusive.  Make sure that only one of the mutually exclusive effects has been specified.
+        if ((effect & DND.FEEDBACK_SELECT) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+        if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+        return effect;
+    }
+
+    /**
+     * This implementation of <code>dragEnter</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragEnter</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragEnter(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag enter event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragEnter(DropTargetEvent event) {
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+    }
+
+    /**
+     * This implementation of <code>dragLeave</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragLeave</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragLeave(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag leave event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragLeave(DropTargetEvent event) {
+        Table table = cast(Table) control;
+        auto handle = table.handle;
+        OS.gtk_tree_view_unset_rows_drag_dest(handle);
+
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+    }
+
+    /**
+     * This implementation of <code>dragOver</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>. The class description
+     * lists the FEEDBACK constants that are applicable to the class.
+     *
+     * For additional information see <code>DropTargetAdapter.dragOver</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragOver(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag over event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     * @see DND#FEEDBACK_SELECT
+     * @see DND#FEEDBACK_SCROLL
+     */
+    public void dragOver(DropTargetEvent event) {
+        Table table = cast(Table) control;
+        auto handle = table.handle;
+        int effect = checkEffect(event.feedback);
+        Point coordinates = new Point(event.x, event.y);
+        coordinates = table.toControl(coordinates);
+        void* path;
+        OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null);
+        int index = -1;
+        if (path !is null) {
+            auto indices = OS.gtk_tree_path_get_indices (path);
+            if (indices !is null) {
+                index = indices[0];
+            }
+        }
+        if ((effect & DND.FEEDBACK_SCROLL) is 0) {
+            scrollBeginTime = 0;
+            scrollIndex = -1;
+        } else {
+            if (index !is -1 && scrollIndex is index && scrollBeginTime !is 0) {
+                if (System.currentTimeMillis() >= scrollBeginTime) {
+                    if (coordinates.y < table.getItemHeight()) {
+                        OS.gtk_tree_path_prev(path);
+                    } else {
+                        OS.gtk_tree_path_next(path);
+                    }
+                    if (path !is null) {
+                        OS.gtk_tree_view_scroll_to_cell(handle, path, null, false, 0, 0);
+                        OS.gtk_tree_path_free(path);
+                        path = null;
+                        OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null);
+                    }
+                    scrollBeginTime = 0;
+                    scrollIndex = -1;
+                }
+            } else {
+                scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+                scrollIndex = index;
+            }
+        }
+        if (path !is null) {
+            int position = 0;
+            if ((effect & DND.FEEDBACK_SELECT) !is 0) position = OS.GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
+            //if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) position = OS.GTK_TREE_VIEW_DROP_BEFORE;
+            //if ((effect & DND.FEEDBACK_INSERT_AFTER) !is 0) position = OS.GTK_TREE_VIEW_DROP_AFTER;
+            if (position !is 0) {
+                OS.gtk_tree_view_set_drag_dest_row(handle, path, OS.GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
+            } else {
+                OS.gtk_tree_view_unset_rows_drag_dest(handle);
+            }
+        } else {
+            OS.gtk_tree_view_unset_rows_drag_dest(handle);
+        }
+        if (path !is null) OS.gtk_tree_path_free (path );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TextTransfer.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.TextTransfer;
+
+import dwt.internal.Converter;
+import dwt.internal.gtk.OS;
+import dwt.dwthelper.utils;
+import dwt.dnd.ByteArrayTransfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+
+
+static import tango.stdc.stringz;
+
+/**
+ * The class <code>TextTransfer</code> provides a platform specific mechanism
+ * for converting plain text represented as a java <code>String</code>
+ * to a platform specific representation of the data and vice versa.
+ *
+ * <p>An example of a java <code>String</code> containing plain text is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String textData = "Hello World";
+ * </code></pre>
+ *
+ * @see Transfer
+ */
+public class TextTransfer : ByteArrayTransfer {
+
+    private static TextTransfer _instance;
+    private static const char[] COMPOUND_TEXT = "COMPOUND_TEXT"; //$NON-NLS-1$
+    private static const char[] UTF8_STRING = "UTF8_STRING"; //$NON-NLS-1$
+    private static const char[] STRING = "STRING"; //$NON-NLS-1$
+    private static const int COMPOUND_TEXT_ID;
+    private static const int UTF8_STRING_ID;
+    private static const int STRING_ID;
+
+static this(){
+    COMPOUND_TEXT_ID = registerType(COMPOUND_TEXT);
+    UTF8_STRING_ID = registerType(UTF8_STRING);
+    STRING_ID = registerType(STRING);
+    _instance = new TextTransfer();
+}
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the TextTransfer class.
+ *
+ * @return the singleton instance of the TextTransfer class
+ */
+public static TextTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts plain text
+ * represented by a java <code>String</code> to a platform specific representation.
+ *
+ * @param object a java <code>String</code> containing text
+ * @param transferData an empty <code>TransferData</code> object; this object
+ *  will be filled in on return with the platform specific format of the data
+ *
+ * @see Transfer#javaToNative
+ */
+public void javaToNative (Object object, TransferData transferData) {
+    transferData.result = 0;
+    if (!checkText(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    char[] string = (cast(ArrayWrapperString)object).array;
+    char* utf8 = tango.stdc.stringz.toStringz(string);
+    if  (transferData.type is cast(void*) COMPOUND_TEXT_ID) {
+        void* encoding;
+        int format;
+        char* ctext;
+        int length;
+        bool result = cast(bool) OS.gdk_utf8_to_compound_text(utf8, &encoding, &format, &ctext, &length);
+        if (!result) return;
+        transferData.type = encoding;
+        transferData.format = format;
+        transferData.length = length;
+        transferData.pValue = ctext;
+        transferData.result = 1;
+    }
+    if (transferData.type is cast(void*)UTF8_STRING_ID) {
+        char* pValue = cast(char*)OS.g_malloc(string.length+1);
+        if (pValue is  null) return;
+        pValue[ 0 .. string.length ] = string;
+        pValue[ string.length ] = '\0';
+        transferData.type = cast(void*)UTF8_STRING_ID;
+        transferData.format = 8;
+        transferData.length = string.length;
+        transferData.pValue = pValue;
+        transferData.result = 1;
+    }
+    if (transferData.type is cast(void*)STRING_ID) {
+        auto string_target = OS.gdk_utf8_to_string_target(utf8);
+        if (string_target is  null) return;
+        transferData.type = cast(void*)STRING_ID;
+        transferData.format = 8;
+        transferData.length = tango.stdc.string.strlen(string_target);
+        transferData.pValue = string_target;
+        transferData.result = 1;
+    }
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of plain text to a java <code>String</code>.
+ *
+ * @param transferData the platform specific representation of the data to be converted
+ * @return a java <code>String</code> containing text if the conversion was successful; otherwise null
+ *
+ * @see Transfer#nativeToJava
+ */
+public Object nativeToJava(TransferData transferData){
+    if (!isSupportedType(transferData) ||  transferData.pValue is null) return null;
+    char** list;
+    int count = OS.gdk_text_property_to_utf8_list(transferData.type, transferData.format, transferData.pValue, transferData.length, &list);
+    if (count is 0) return null;
+    char[] utf8 = tango.stdc.stringz.fromUtf8z( list[0] ).dup;
+    OS.g_strfreev(list);
+    return new ArrayWrapperString( utf8 );
+}
+
+protected int[] getTypeIds() {
+    return [UTF8_STRING_ID, COMPOUND_TEXT_ID, STRING_ID];
+}
+
+protected char[][] getTypeNames() {
+    return [UTF8_STRING, COMPOUND_TEXT, STRING];
+}
+
+bool checkText(Object object) {
+    if( object is null ) return false;
+    ArrayWrapperString astr = cast(ArrayWrapperString)object;
+    if( astr is null ) return false;
+    return astr.array.length > 0;
+}
+
+protected bool validate(Object object) {
+    return checkText(object);
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/Transfer.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.Transfer;
+
+
+import dwt.internal.Converter;
+import dwt.internal.gtk.OS;
+import dwt.dnd.TransferData;
+
+static import tango.stdc.stringz;
+
+/**
+ * <code>Transfer</code> provides a mechanism for converting between a java
+ * representation of data and a platform specific representation of data and
+ * vice versa.  It is used in data transfer operations such as drag and drop and
+ * clipboard copy/paste.
+ *
+ * <p>You should only need to become familiar with this class if you are
+ * implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class.</p>
+ *
+ * @see ByteArrayTransfer
+ */
+public abstract class Transfer {
+
+/**
+ * Returns a list of the platform specific data types that can be converted using
+ * this transfer agent.
+ *
+ * <p>Only the data type fields of the <code>TransferData</code> objects are filled
+ * in.</p>
+ *
+ * @return a list of the data types that can be converted using this transfer agent
+ */
+abstract public TransferData[] getSupportedTypes();
+
+/**
+ * Returns true if the <code>TransferData</code> data type can be converted
+ * using this transfer agent, or false otherwise (including if transferData is
+ * <code>null</code>).
+ *
+ * @param transferData a platform specific description of a data type; only the data
+ *  type fields of the <code>TransferData</code> object need to be filled in
+ *
+ * @return true if the transferData data type can be converted using this transfer
+ * agent
+ */
+abstract public bool isSupportedType(TransferData transferData);
+
+/**
+ * Returns the platform specific names of the  data types that can be converted
+ * using this transfer agent.
+ *
+ * @return the platform specific names of the data types that can be converted
+ * using this transfer agent.
+ */
+abstract public char[][] getTypeNames();
+
+/**
+ * Returns the platform specific ids of the  data types that can be converted using
+ * this transfer agent.
+ *
+ * @return the platform specific ids of the data types that can be converted using
+ * this transfer agent
+ */
+abstract public int[] getTypeIds();
+
+/**
+ * Converts a java representation of data to a platform specific representation of
+ * the data.
+ *
+ * <p>On a successful conversion, the transferData.result field will be set as follows:
+ * <ul>
+ * <li>Windows: COM.S_OK
+ * <li>Motif: 1
+ * <li>GTK: 1
+ * <li>Photon: 1
+ * </ul></p>
+ *
+ * <p>If this transfer agent is unable to perform the conversion, the transferData.result
+ * field will be set to a failure value as follows:
+ * <ul>
+ * <li>Windows: COM.DV_E_TYMED or COM.E_FAIL
+ * <li>Motif: 0
+ * <li>GTK: 0
+ * <li>Photon: 0
+ * </ul></p>
+ *
+ * @param object a java representation of the data to be converted; the type of
+ * Object that is passed in is dependent on the <code>Transfer</code> subclass.
+ *
+ * @param transferData an empty TransferData object; this object will be
+ * filled in on return with the platform specific representation of the data
+ *
+ * @exception dwt.DWTException <ul>
+ *    <li>ERROR_INVALID_DATA - if object does not contain data in a valid format or is <code>null</code></li>
+ * </ul>
+ */
+abstract public void javaToNative (Object object, TransferData transferData);
+
+/**
+ * Converts a platform specific representation of data to a java representation.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * converted
+ *
+ * @return a java representation of the converted data if the conversion was
+ * successful; otherwise null.  If transferData is <code>null</code> then
+ * <code>null</code> is returned.  The type of Object that is returned is
+ * dependent on the <code>Transfer</code> subclass.
+ */
+abstract public Object nativeToJava(TransferData transferData);
+
+/**
+ * Registers a name for a data type and returns the associated unique identifier.
+ *
+ * <p>You may register the same type more than once, the same unique identifier
+ * will be returned if the type has been previously registered.</p>
+ *
+ * <p>Note: On windows, do <b>not</b> call this method with pre-defined
+ * Clipboard Format types such as CF_TEXT or CF_BITMAP because the
+ * pre-defined identifier will not be returned</p>
+ *
+ * @param formatName the name of a data type
+ *
+ * @return the unique identifier associated with this data type
+ */
+public static int registerType(char[] formatName){
+    if (formatName is null) return OS.GDK_NONE;
+    char* buffer = tango.stdc.stringz.toStringz( formatName );
+    return cast(int)/*64*/OS.gdk_atom_intern(buffer, false);
+}
+
+/**
+ * Test that the object is of the correct format for this Transfer class.
+ *
+ * @param object a java representation of the data to be converted
+ *
+ * @return true if object is of the correct form for this transfer type
+ *
+ * @since 3.1
+ */
+public bool validate(Object object) {
+    return true;
+}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TransferData.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.TransferData;
+
+
+/**
+ * The <code>TransferData</code> class is a platform specific data structure for
+ * describing the type and the contents of data being converted by a transfer agent.
+ *
+ * <p>As an application writer, you do not need to know the specifics of
+ * TransferData.  TransferData instances are passed to a subclass of Transfer
+ * and the Transfer object manages the platform specific issues.
+ * You can ask a Transfer subclass if it can handle this data by calling
+ * Transfer.isSupportedType(transferData).</p>
+ *
+ * <p>You should only need to become familiar with the fields in this class if you
+ * are implementing a Transfer subclass and you are unable to subclass the
+ * ByteArrayTransfer class.</p>
+ */
+public class TransferData {
+    /**
+     * The type is a unique identifier of a system format or user defined format.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     */
+    public void* type;
+
+    /**
+     * Specifies the number of units in pValue.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     *
+     * @see TransferData#format for the size of one unit
+     */
+    public int length;
+
+    /**
+     * Specifies the size in bits of a single unit in pValue.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     *
+     * This is most commonly 8 bits.
+     */
+    public int format;
+
+    /**
+     * Pointer to the data being transferred.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     */
+    public char* pValue;
+
+    /**
+     * The result field contains the result of converting a
+     * java data type into a platform specific value.
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     * <p>The value of result is 1 if the conversion was successful.
+     * The value of result is 0 if the conversion failed.</p>
+     */
+    public int result;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TreeDragSourceEffect.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.TreeDragSourceEffect;
+
+
+import dwt.DWT;
+import dwt.graphics.Image;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Display;
+import dwt.widgets.Tree;
+import dwt.dnd.DragSourceEffect;
+import dwt.dnd.DragSourceEvent;
+
+import Math = tango.math.Math;
+
+/**
+ * This class provides default implementations to display a source image
+ * when a drag is initiated from a <code>Tree</code>.
+ *
+ * <p>Classes that wish to provide their own source image for a <code>Tree</code> can
+ * extend <code>TreeDragSourceEffect</code> class and override the <code>TreeDragSourceEffect.dragStart</code>
+ * method and set the field <code>DragSourceEvent.image</code> with their own image.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * @see DragSourceEffect
+ * @see DragSourceEvent
+ *
+ * @since 3.3
+ */
+public class TreeDragSourceEffect : DragSourceEffect {
+    Image dragSourceImage = null;
+
+    /**
+     * Creates a new <code>TreeDragSourceEffect</code> to handle drag effect
+     * from the specified <code>Tree</code>.
+     *
+     * @param tree the <code>Tree</code> that the user clicks on to initiate the drag
+     */
+    public this(Tree tree) {
+        super(tree);
+    }
+
+    /**
+     * This implementation of <code>dragFinished</code> disposes the image
+     * that was created in <code>TreeDragSourceEffect.dragStart</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragFinished(event)</code>
+     * to dispose the image in the default implementation.
+     *
+     * @param event the information associated with the drag finished event
+     */
+    public void dragFinished(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+    }
+
+    /**
+     * This implementation of <code>dragStart</code> will create a default
+     * image that will be used during the drag. The image should be disposed
+     * when the drag is completed in the <code>TreeDragSourceEffect.dragFinished</code>
+     * method.
+     *
+     * Subclasses that override this method should call <code>super.dragStart(event)</code>
+     * to use the image from the default implementation.
+     *
+     * @param event the information associated with the drag start event
+     */
+    public void dragStart(DragSourceEvent event) {
+        event.image = getDragSourceImage(event);
+    }
+
+    Image getDragSourceImage(DragSourceEvent event) {
+        if (dragSourceImage !is null) dragSourceImage.dispose();
+        dragSourceImage = null;
+
+        Tree tree = cast(Tree) control;
+        if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) return null;
+        /*
+        * Bug in GTK.  gtk_tree_selection_get_selected_rows() segmentation faults
+        * in versions smaller than 2.2.4 if the model is NULL.  The fix is
+        * to give a valid pointer instead.
+        */
+        auto handle = tree.handle;
+        auto selection = OS.gtk_tree_view_get_selection (handle);
+        int dummy;
+        void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null;
+        auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model);
+        if (list is null) return null;
+        int count = Math.min(10, OS.g_list_length (list));
+
+        Display display = tree.getDisplay();
+        if (count is 1) {
+            auto path = OS.g_list_nth_data (list, 0);
+            auto pixmap = OS.gtk_tree_view_create_row_drag_icon(handle, path);
+            dragSourceImage =  Image.gtk_new(display, DWT.ICON, pixmap, null);
+        } else {
+            int width = 0, height = 0;
+            int w , h;
+            int[] yy = new int[count], hh = new int[count];
+            GdkDrawable* [] pixmaps = new GdkDrawable*[count];
+            GdkRectangle rect;
+            for (int i=0; i<count; i++) {
+                auto path = OS.g_list_nth_data (list, i);
+                OS.gtk_tree_view_get_cell_area (handle, path, null, &rect);
+                pixmaps[i] = OS.gtk_tree_view_create_row_drag_icon(handle, path);
+                OS.gdk_drawable_get_size(pixmaps[i], &w, &h);
+                width = Math.max(width, w);
+                height = rect.y + h - yy[0];
+                yy[i] = rect.y;
+                hh[i] = h;
+            }
+            auto source = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, -1);
+            auto gcSource = OS.gdk_gc_new(source);
+            auto mask = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, 1);
+            auto gcMask = OS.gdk_gc_new(mask);
+            GdkColor color;
+            color.pixel = 0;
+            OS.gdk_gc_set_foreground(gcMask, &color);
+            OS.gdk_draw_rectangle(mask, gcMask, 1, 0, 0, width, height);
+            color.pixel = 1;
+            OS.gdk_gc_set_foreground(gcMask, &color);
+            for (int i=0; i<count; i++) {
+                OS.gdk_draw_drawable(source, gcSource, pixmaps[i], 0, 0, 0, yy[i] - yy[0], -1, -1);
+                OS.gdk_draw_rectangle(mask, gcMask, 1, 0, yy[i] - yy[0], width, hh[i]);
+                OS.g_object_unref(pixmaps[i]);
+            }
+            OS.g_object_unref(gcSource);
+            OS.g_object_unref(gcMask);
+            dragSourceImage  = Image.gtk_new(display, DWT.ICON, source, mask);
+        }
+        OS.g_list_free (list);
+
+        return dragSourceImage;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/TreeDropTargetEffect.d	Fri Jan 18 00:34:32 2008 +0100
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.dnd.TreeDropTargetEffect;
+
+
+import dwt.graphics.Point;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Tree;
+import dwt.dnd.DropTargetEffect;
+import dwt.dnd.DropTargetEvent;
+import dwt.dnd.DND;
+import dwt.dwthelper.System;
+
+/**
+ * This class provides a default drag under effect (eg. select, insert, scroll and expand)
+ * when a drag occurs over a <code>Tree</code>.
+ *
+ * <p>Classes that wish to provide their own drag under effect for a <code>Tree</code>
+ * can extend the <code>TreeDropTargetEffect</code> class and override any applicable methods
+ * in <code>TreeDropTargetEffect</code> to display their own drag under effect.</p>
+ *
+ * Subclasses that override any methods of this class must call the corresponding
+ * <code>super</code> method to get the default drag under effect implementation.
+ *
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DND</code> effect constants.
+ * </p>
+ * <p>
+ * <dl>
+ * <dt><b>Feedback:</b></dt>
+ * <dd>FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE, FEEDBACK_INSERT_AFTER, FEEDBACK_EXPAND, FEEDBACK_SCROLL</dd>
+ * </dl>
+ * </p><p>
+ * Note: Only one of the styles FEEDBACK_SELECT, FEEDBACK_INSERT_BEFORE or
+ * FEEDBACK_INSERT_AFTER may be specified.
+ * </p>
+ *
+ * @see DropTargetAdapter
+ * @see DropTargetEvent
+ *
+ * @since 3.3
+ */
+public class TreeDropTargetEffect : DropTargetEffect {
+    static const int SCROLL_HYSTERESIS = 150; // milli seconds
+    static const int EXPAND_HYSTERESIS = 1000; // milli seconds
+
+    int scrollIndex = -1;
+    long scrollBeginTime;
+
+    int expandIndex = -1;
+    long expandBeginTime;
+
+    /**
+     * Creates a new <code>TreeDropTargetEffect</code> to handle the drag under effect on the specified
+     * <code>Tree</code>.
+     *
+     * @param tree the <code>Tree</code> over which the user positions the cursor to drop the data
+     */
+    public this(Tree tree) {
+        super(tree);
+    }
+
+    int checkEffect(int effect) {
+        // Some effects are mutually exclusive.  Make sure that only one of the mutually exclusive effects has been specified.
+        if ((effect & DND.FEEDBACK_SELECT) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER & ~DND.FEEDBACK_INSERT_BEFORE;
+        if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) effect = effect & ~DND.FEEDBACK_INSERT_AFTER;
+        return effect;
+    }
+
+    /**
+     * This implementation of <code>dragEnter</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragEnter</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragEnter(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag enter event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragEnter(DropTargetEvent event) {
+        expandBeginTime = 0;
+        expandIndex = -1;
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+    }
+
+    /**
+     * This implementation of <code>dragLeave</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragLeave</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragLeave(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag leave event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     */
+    public void dragLeave(DropTargetEvent event) {
+        Tree tree = cast(Tree) control;
+        auto handle = tree.handle;
+        OS.gtk_tree_view_unset_rows_drag_dest(handle);
+
+        scrollBeginTime = 0;
+        scrollIndex = -1;
+        expandBeginTime = 0;
+        expandIndex = -1;
+    }
+
+    /**
+     * This implementation of <code>dragOver</code> provides a default drag under effect
+     * for the feedback specified in <code>event.feedback</code>.
+     *
+     * For additional information see <code>DropTargetAdapter.dragOver</code>.
+     *
+     * Subclasses that override this method should call <code>super.dragOver(event)</code>
+     * to get the default drag under effect implementation.
+     *
+     * @param event  the information associated with the drag over event
+     *
+     * @see DropTargetAdapter
+     * @see DropTargetEvent
+     * @see DND#FEEDBACK_SELECT
+     * @see DND#FEEDBACK_INSERT_BEFORE
+     * @see DND#FEEDBACK_INSERT_AFTER
+     * @see DND#FEEDBACK_SCROLL
+     */
+    public void dragOver(DropTargetEvent event) {
+        Tree tree = cast(Tree) control;
+        int effect = checkEffect(event.feedback);
+
+        auto handle = tree.handle;
+        Point coordinates = new Point(event.x, event.y);
+        coordinates = tree.toControl(coordinates);
+        void* path;
+        OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null);
+        int index = -1;
+        if (path !is null) {
+            auto indices = OS.gtk_tree_path_get_indices(path);
+            if (indices !is null) {
+                int depth = OS.gtk_tree_path_get_depth(path);
+                index = indices[depth - 1];
+            }
+        }
+        if ((effect & DND.FEEDBACK_SCROLL) is 0) {
+            scrollBeginTime = 0;
+            scrollIndex = -1;
+        } else {
+            if (index !is -1 && scrollIndex is index && scrollBeginTime !is 0) {
+                if (System.currentTimeMillis() >= scrollBeginTime) {
+                    GdkRectangle cellRect;
+                    OS.gtk_tree_view_get_cell_area (handle, path, null, &cellRect);
+                    if (cellRect.y < cellRect.height) {
+                        int tx, ty;
+                        OS.gtk_tree_view_widget_to_tree_coords(handle, cellRect.x, cellRect.y - cellRect.height, &tx, &ty);
+                        OS.gtk_tree_view_scroll_to_point (handle, -1, ty);
+                    } else {
+                        //scroll down
+                        OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y + cellRect.height, &path, null, null, null);
+                        if (path !is null) {
+                            OS.gtk_tree_view_scroll_to_cell(handle, path, null, false, 0, 0);
+                            OS.gtk_tree_path_free(path);
+                            path = null;
+                        }
+                        OS.gtk_tree_view_get_path_at_pos (handle, coordinates.x, coordinates.y, &path, null, null, null);
+                    }
+                    scrollBeginTime = 0;
+                    scrollIndex = -1;
+                }
+            } else {
+                scrollBeginTime = System.currentTimeMillis() + SCROLL_HYSTERESIS;
+                scrollIndex = index;
+            }
+        }
+        if ((effect & DND.FEEDBACK_EXPAND) is 0) {
+            expandBeginTime = 0;
+            expandIndex = -1;
+        } else {
+            if (index !is -1 && expandIndex is index && expandBeginTime !is 0) {
+                if (System.currentTimeMillis() >= expandBeginTime) {
+                    OS.gtk_tree_view_expand_row (handle, path, false);
+                    expandBeginTime = 0;
+                    expandIndex = -1;
+                }
+            } else {
+                expandBeginTime = System.currentTimeMillis() + EXPAND_HYSTERESIS;
+                expandIndex = index;
+            }
+        }
+        if (path !is null) {
+            int position = -1;
+            if ((effect & DND.FEEDBACK_SELECT) !is 0) position = OS.GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
+            if ((effect & DND.FEEDBACK_INSERT_BEFORE) !is 0) position = OS.GTK_TREE_VIEW_DROP_BEFORE;
+            if ((effect & DND.FEEDBACK_INSERT_AFTER) !is 0) position = OS.GTK_TREE_VIEW_DROP_AFTER;
+            if (position !is -1) {
+                OS.gtk_tree_view_set_drag_dest_row(handle, path, position);
+            } else {
+                OS.gtk_tree_view_unset_rows_drag_dest(handle);
+            }
+        } else {
+            OS.gtk_tree_view_unset_rows_drag_dest(handle);
+        }
+
+        if (path !is null) OS.gtk_tree_path_free (path );
+    }
+
+}
--- a/dwt/dwthelper/System.d	Thu Jan 17 15:44:59 2008 +0100
+++ b/dwt/dwthelper/System.d	Fri Jan 18 00:34:32 2008 +0100
@@ -115,5 +115,11 @@
     alias SimpleType!(Object[]).arraycopy arraycopy;
     alias SimpleType!(void*[]).arraycopy arraycopy;
     alias SimpleType!(void*[]).arraycopy arraycopy;
+
+    static long currentTimeMillis(){
+        //PORTING_FIXMe
+        return 0;
+    }
+
 }
 
--- a/dwt/dwthelper/utils.d	Thu Jan 17 15:44:59 2008 +0100
+++ b/dwt/dwthelper/utils.d	Fri Jan 18 00:34:32 2008 +0100
@@ -24,10 +24,11 @@
     }
 }
 
-alias ArrayWrapperT!(int)    ArrayWrapperInt;
-alias ArrayWrapperT!(Object) ArrayWrapperObject;
-alias ArrayWrapperT!(char)   ArrayWrapperString;
-alias ArrayWrapperT!(char[])   ArrayWrapperString2;
+alias ArrayWrapperT!(byte)    ArrayWrapperByte;
+alias ArrayWrapperT!(int)     ArrayWrapperInt;
+alias ArrayWrapperT!(Object)  ArrayWrapperObject;
+alias ArrayWrapperT!(char)    ArrayWrapperString;
+alias ArrayWrapperT!(char[])  ArrayWrapperString2;
 
 
 
--- a/dwt/graphics/Image.d	Thu Jan 17 15:44:59 2008 +0100
+++ b/dwt/graphics/Image.d	Fri Jan 18 00:34:32 2008 +0100
@@ -950,7 +950,7 @@
  *
  * @private
  */
-public static Image gtk_new(Device device, int type, int /*long*/ pixmap, int /*long*/ mask) {
+public static Image gtk_new(Device device, int type, GdkDrawable* pixmap, GdkDrawable* mask) {
     if (device is null) device = Device.getDevice();
     Image image = new Image();
     image.type = type;
--- a/dwt/internal/gtk/OS.d	Thu Jan 17 15:44:59 2008 +0100
+++ b/dwt/internal/gtk/OS.d	Fri Jan 18 00:34:32 2008 +0100
@@ -48,6 +48,7 @@
 public alias dwt.internal.c.glib_object.GTypeClass GTypeClass;
 public alias dwt.internal.c.glib_object.GInterfaceInfo GInterfaceInfo;
 public alias dwt.internal.c.glib_object.GTypeQuery GTypeQuery;
+public alias dwt.internal.c.glib_object.GError GError;
 
 public alias dwt.internal.c.gdk.GdkColor GdkColor;
 public alias dwt.internal.c.gdk.GdkRegion GdkRegion;
@@ -76,6 +77,7 @@
 public alias dwt.internal.c.gdk.GdkEventFocus GdkEventFocus;
 public alias dwt.internal.c.gdk.GdkWindowAttr GdkWindowAttr;
 public alias dwt.internal.c.gdk.GdkEventWindowState GdkEventWindowState;
+public alias dwt.internal.c.gdk.GdkDragContext GdkDragContext;
 
 public alias dwt.internal.c.pango.PangoFontDescription PangoFontDescription;
 public alias dwt.internal.c.pango.PangoTabArray PangoTabArray;
@@ -485,6 +487,7 @@
 public alias dwt.internal.c.gtk.GtkAccelKey GtkAccelKey;
 public alias dwt.internal.c.gtk.GtkAccelGroupClass GtkAccelGroupClass;
 public alias dwt.internal.c.gtk.GtkAccelGroup GtkAccelGroup;
+public alias dwt.internal.c.gtk.GtkClipboard GtkClipboard;
 
 public alias dwt.internal.c.gtk.GtkTreeModel GtkTreeModel;
 public alias dwt.internal.c.gtk.GtkTreePath GtkTreePath;
@@ -1278,7 +1281,7 @@
     mixin ForwardGtkOsCFunc!(.g_utf8_strlen);
     mixin ForwardGtkOsCFunc!(.g_utf8_to_utf16);
     mixin ForwardGtkOsCFunc!(.gdk_atom_intern);
-//    mixin ForwardGtkOsCFunc!(.gdk_atom_name);
+    mixin ForwardGtkOsCFunc!(.gdk_atom_name);
     mixin ForwardGtkOsCFunc!(.gdk_beep);
     mixin ForwardGtkOsCFunc!(.gdk_bitmap_create_from_data);
     mixin ForwardGtkOsCFunc!(.gdk_cairo_region);
@@ -1395,9 +1398,9 @@
     mixin ForwardGtkOsCFunc!(.gdk_screen_width);
     mixin ForwardGtkOsCFunc!(.gdk_screen_width_mm);
     mixin ForwardGtkOsCFunc!(.gdk_set_program_class);
-//    mixin ForwardGtkOsCFunc!(.gdk_utf8_to_compound_text);
-//   mixin ForwardGtkOsCFunc!(.gdk_utf8_to_string_target);
-//    mixin ForwardGtkOsCFunc!(.gdk_text_property_to_utf8_list  );
+    mixin ForwardGtkOsCFunc!(.gdk_utf8_to_compound_text);
+    mixin ForwardGtkOsCFunc!(.gdk_utf8_to_string_target);
+    mixin ForwardGtkOsCFunc!(.gdk_text_property_to_utf8_list  );
     mixin ForwardGtkOsCFunc!(.gdk_unicode_to_keyval);
     mixin ForwardGtkOsCFunc!(.gdk_visual_get_system);
     mixin ForwardGtkOsCFunc!(.gdk_window_at_pointer);