changeset 240:ce446666f5a2

Update to SWT 3.4M7
author Frank Benoit <benoit@tionex.de>
date Mon, 12 May 2008 19:13:01 +0200
parents 06a1f6829310
children 4653e99936cf
files dwt/DWT.d dwt/accessibility/AccessibleObject.d dwt/custom/CCombo.d dwt/custom/CLabel.d dwt/custom/CTabFolder.d dwt/custom/CTabItem.d dwt/custom/LineBackgroundEvent.d dwt/custom/LineStyleEvent.d dwt/custom/SashForm.d dwt/custom/ScrolledComposite.d dwt/custom/StyleRange.d dwt/custom/StyledText.d dwt/custom/StyledTextDropTargetEffect.d dwt/custom/StyledTextPrintOptions.d dwt/custom/StyledTextRenderer.d dwt/custom/TableCursor.d dwt/custom/TableTreeItem.d dwt/dnd/ClipboardProxy.d dwt/dnd/DND.d dwt/dnd/DragSource.d dwt/dnd/DropTarget.d dwt/dnd/DropTargetEffect.d dwt/dnd/FileTransfer.d dwt/dnd/ImageTransfer.d dwt/dnd/TableDragSourceEffect.d dwt/dnd/TableDropTargetEffect.d dwt/dnd/TransferData.d dwt/dnd/TreeDragSourceEffect.d dwt/dnd/TreeDropTargetEffect.d dwt/dnd/URLTransfer.d dwt/graphics/Color.d dwt/graphics/Cursor.d dwt/graphics/Device.d dwt/graphics/Font.d dwt/graphics/GC.d dwt/graphics/GCData.d dwt/graphics/Image.d dwt/graphics/ImageData.d dwt/graphics/Path.d dwt/graphics/Pattern.d dwt/graphics/Region.d dwt/graphics/Resource.d dwt/graphics/TextLayout.d dwt/graphics/TextStyle.d dwt/graphics/Transform.d dwt/internal/BidiUtil.d dwt/internal/Compatibility.d dwt/internal/DWTMessages.properties dwt/internal/LONG.d dwt/internal/Library.d dwt/internal/gtk/OS.d dwt/internal/image/FileFormat.d dwt/internal/image/GIFFileFormat.d dwt/internal/image/JPEGDecoder.d dwt/internal/image/JPEGFileFormat.d dwt/internal/image/LEDataInputStream.d dwt/internal/image/PNGFileFormat.d dwt/internal/image/PngDeflater.d dwt/internal/image/PngEncoder.d dwt/internal/image/PngHuffmanTable.d dwt/internal/image/PngPlteChunk.d dwt/internal/image/WinICOFileFormat.d dwt/layout/RowLayout.d dwt/printing/PrintDialog.d dwt/printing/Printer.d dwt/printing/PrinterData.d dwt/program/Program.d dwt/widgets/Button.d dwt/widgets/Canvas.d dwt/widgets/Caret.d dwt/widgets/ColorDialog.d dwt/widgets/Combo.d dwt/widgets/Composite.d dwt/widgets/Control.d dwt/widgets/CoolBar.d dwt/widgets/CoolItem.d dwt/widgets/DateTime.d dwt/widgets/Dialog.d dwt/widgets/DirectoryDialog.d dwt/widgets/Display.d dwt/widgets/Event.d dwt/widgets/EventTable.d dwt/widgets/ExpandItem.d dwt/widgets/FileDialog.d dwt/widgets/FontDialog.d dwt/widgets/IME.d dwt/widgets/Label.d dwt/widgets/Link.d dwt/widgets/Menu.d dwt/widgets/MenuItem.d dwt/widgets/MessageBox.d dwt/widgets/Monitor.d dwt/widgets/ProgressBar.d dwt/widgets/Sash.d dwt/widgets/ScrollBar.d dwt/widgets/Scrollable.d dwt/widgets/Shell.d dwt/widgets/Slider.d dwt/widgets/Spinner.d dwt/widgets/Synchronizer.d dwt/widgets/TabFolder.d dwt/widgets/TabItem.d dwt/widgets/Table.d dwt/widgets/TableItem.d dwt/widgets/Text.d dwt/widgets/ToolBar.d dwt/widgets/ToolItem.d dwt/widgets/ToolTip.d dwt/widgets/Tracker.d dwt/widgets/Tree.d dwt/widgets/TreeColumn.d dwt/widgets/TreeItem.d dwt/widgets/Widget.d
diffstat 113 files changed, 5947 insertions(+), 1715 deletions(-) [+]
line wrap: on
line diff
--- a/dwt/DWT.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/DWT.d	Mon May 12 19:13:01 2008 +0200
@@ -649,9 +649,76 @@
      */
     public static const int PaintItem = 42;
 
+    /**
+     * The IME composition event type (value is 43).
+     * <p>
+     * The IME composition event is sent to allow
+     * custom text editors to implement in-line
+     * editing of international text.
+     * </p>
+     *
+     * The detail field indicates the action to be taken:
+     * <p><ul>
+     * <li>{@link DWT#COMPOSITION_CHANGED}</li>
+     * <li>{@link DWT#COMPOSITION_OFFSET}</li>
+     * <li>{@link DWT#COMPOSITION_SELECTION}</li>
+     * </ul></p>
+     *
+     * @see dwt.widgets.Widget#addListener
+     * @see dwt.widgets.Display#addFilter
+     * @see dwt.widgets.Event
+     *
+     * @since 3.4
+     */
+    public static const int ImeComposition = 43;
+
     /* Event Details */
 
     /**
+     * The IME composition event detail that indicates
+     * a change in the IME composition. The text field
+     * of the event is the new composition text.
+     * The start and end indicate the offsets where the
+     * composition text should be inserted.
+     * The styles and ranges are stored in the IME
+     * object (value is 1).
+     *
+     * @see DWT#ImeComposition
+     *
+     * @since 3.4
+     */
+    public static const int COMPOSITION_CHANGED = 1;
+
+    /**
+     * The IME composition event detail that indicates
+     * that the IME needs the offset for a given location.
+     * The x and y fields of the event are used by the
+     * application to determine the offset.
+     *
+     * The index field of the event should be set to the
+     * text offset at that location. The count field should
+     * be set to indicate whether the location is closer to
+     * the leading edge (0) or the trailing edge (1) (value is 2).
+     *
+     * @see DWT#ImeComposition
+     * @see dwt.graphics.TextLayout#getOffset(int, int, int[])
+     *
+     * @since 3.4
+     */
+    public static const int COMPOSITION_OFFSET = 2;
+
+    /**
+     * The IME composition event detail that indicates
+     * that IME needs the selected text and its start
+     * and end offsets (value is 3).
+     *
+     * @see DWT#ImeComposition
+     *
+     * @since 3.4
+     */
+    public static const int COMPOSITION_SELECTION = 3;
+
+    /**
      * Indicates that a user-interface component is being dragged,
      * for example dragging the thumb of a scroll bar (value is 1).
      */
@@ -1144,6 +1211,23 @@
     public static const int V_SCROLL = 1 << 9;
 
     /**
+     * Style constant for no scrollbar behavior (value is 1&lt;&lt;4).
+     * <p>
+     * When neither H_SCROLL or V_SCROLL are specified, controls
+     * are free to create the default scroll bars for the control.
+     * Using NO_SCROLL overrides the default and forces the control
+     * to have no scroll bars.
+     *
+     * <b>Used By:</b><ul>
+     * <li><code>Tree</code></li>
+     * <li><code>Table</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int NO_SCROLL = 1 << 4;
+
+    /**
      * Style constant for bordered behavior (value is 1&lt;&lt;11).
      * <br>Note that this is a <em>HINT</em>.
      * <p><b>Used By:</b><ul>
@@ -1298,7 +1382,15 @@
 
     /**
      * Style constant for no focus from the mouse behavior (value is 1&lt;&lt;19).
+     * <p>
+     * Normally, when the user clicks on a control, focus is assigned to that
+     * control, providing the control has no children.  Some controls, such as
+     * tool bars and sashes, don't normally take focus when the mouse is clicked
+     * or accept focus when assigned from within the program.  This style allows
+     * Composites to implement "no focus" mouse behavior.
+     *
      * <br>Note that this is a <em>HINT</em>.
+     * </p>
      * <p><b>Used By:</b><ul>
      * <li><code>Composite</code></li>
      * </ul></p>
@@ -1313,6 +1405,8 @@
      * the DWT.Paint event is not sent. When it gets bigger, an DWT.Paint event is
      * sent with a GC clipped to only the new areas to be painted. Without this
      * style, the entire client area will be repainted.
+     *
+     * <br>Note that this is a <em>HINT</em>.
      * </p><p><b>Used By:</b><ul>
      * <li><code>Composite</code></li>
      * </ul></p>
@@ -1321,6 +1415,8 @@
 
     /**
      * Style constant for no paint event merging behavior (value is 1&lt;&lt;21).
+     *
+     * <br>Note that this is a <em>HINT</em>.
      * <p><b>Used By:</b><ul>
      * <li><code>Composite</code></li>
      * </ul></p>
@@ -1418,16 +1514,104 @@
     public static const int DOUBLE_BUFFERED = 1 << 29;
 
     /**
+     * Style constant for transparent behavior (value is 1&lt;&lt;30).
+     * <p>
+     * By default, before a widget paints, the client area is filled with the current background.
+     * When this style is specified, the background is not filled and widgets that are obscured
+     * will draw through.
+     * </p><p><b>Used By:</b><ul>
+     * <li><code>Composite</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     *
+     * WARNING: THIS API IS UNDER CONSTRUCTION AND SHOULD NOT BE USED
+     */
+    public static const int TRANSPARENT = 1 << 30;
+
+    /**
      * Style constant for align up behavior (value is 1&lt;&lt;7,
      * since align UP and align TOP are considered the same).
      * <p><b>Used By:</b><ul>
      * <li><code>Button</code> with <code>ARROW</code> style</li>
      * <li><code>Tracker</code></li>
+     * <li><code>Table</code></li>
+     * <li><code>Tree</code></li>
      * </ul></p>
      */
     public static const int UP = 1 << 7;
 
     /**
+     * Style constant to indicate single underline (value is 0).
+     * <p><b>Used By:</b><ul>
+     * <li><code>TextStyle</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int UNDERLINE_SINGLE = 0;
+
+    /**
+     * Style constant to indicate double underline (value is 1).
+     * <p><b>Used By:</b><ul>
+     * <li><code>TextStyle</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int UNDERLINE_DOUBLE = 1;
+
+    /**
+     * Style constant to indicate error underline (value is 2).
+     * <p><b>Used By:</b><ul>
+     * <li><code>TextStyle</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int UNDERLINE_ERROR = 2;
+
+    /**
+     * Style constant to indicate squiggle underline (value is 3).
+     * <p><b>Used By:</b><ul>
+     * <li><code>TextStyle</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int UNDERLINE_SQUIGGLE = 3;
+
+    /**
+     * Style constant to indicate solid border (value is 1).
+     * <p><b>Used By:</b><ul>
+     * <li><code>TextStyle</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int BORDER_SOLID = 1;
+
+    /**
+     * Style constant to indicate dashed border (value is 2).
+     * <p><b>Used By:</b><ul>
+     * <li><code>TextStyle</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int BORDER_DASH = 2;
+
+    /**
+     * Style constant to indicate dotted border (value is 4).
+     * <p><b>Used By:</b><ul>
+     * <li><code>TextStyle</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int BORDER_DOT = 4;
+
+    /**
      * Style constant for align top behavior (value is 1&lt;&lt;7,
      * since align UP and align TOP are considered the same).
      * <p><b>Used By:</b><ul>
@@ -1442,6 +1626,8 @@
      * <p><b>Used By:</b><ul>
      * <li><code>Button</code> with <code>ARROW</code> style</li>
      * <li><code>Tracker</code></li>
+     * <li><code>Table</code></li>
+     * <li><code>Tree</code></li>
      * </ul></p>
      */
     public static const int DOWN               = 1 << 10;
@@ -2979,8 +3165,32 @@
     public static const int IMAGE_GRAY = 2;
 
     /**
+     * Constant to indicate an error state (value is 1).
+     * <p><b>Used By:</b><ul>
+     * <li><code>ProgressBar</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int ERROR = 1;
+
+    /**
+     * Constant to a indicate a paused state (value is 4).
+     * <p><b>Used By:</b><ul>
+     * <li><code>ProgressBar</code></li>
+     * </ul></p>
+     *
+     * @since 3.4
+     */
+    public static const int PAUSED = 1 << 2;
+
+    /**
      * The font style constant indicating a normal weight, non-italic font
-     * (value is 0).
+     * (value is 0). This constant is also used with <code>ProgressBar</code>
+     * to indicate a normal state.
+     * <p><b>Used By:</b><ul>
+     * <li><code>ProgressBar</code></li>
+     * </ul></p>
      */
     public static const int NORMAL = 0;
 
--- a/dwt/accessibility/AccessibleObject.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/accessibility/AccessibleObject.d	Mon May 12 19:13:01 2008 +0200
@@ -472,8 +472,8 @@
                     case ACC.ROLE_SCROLLBAR: return ATK.ATK_ROLE_SCROLL_BAR;
                     case ACC.ROLE_SEPARATOR: return ATK.ATK_ROLE_SEPARATOR;
                     case ACC.ROLE_SLIDER: return ATK.ATK_ROLE_SLIDER;
-                    case ACC.ROLE_TABLE: return ATK.ATK_ROLE_TABLE;
-                    case ACC.ROLE_TABLECELL: return ATK.ATK_ROLE_TABLE_CELL;
+                    case ACC.ROLE_TABLE: return ATK.ATK_ROLE_LIST;
+                    case ACC.ROLE_TABLECELL: return ATK.ATK_ROLE_LIST_ITEM;
                     case ACC.ROLE_TABLECOLUMNHEADER: return ATK.ATK_ROLE_TABLE_COLUMN_HEADER;
                     case ACC.ROLE_TABLEROWHEADER: return ATK.ATK_ROLE_TABLE_ROW_HEADER;
                     case ACC.ROLE_TABFOLDER: return ATK.ATK_ROLE_PAGE_TAB_LIST;
--- a/dwt/custom/CCombo.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/CCombo.d	Mon May 12 19:13:01 2008 +0200
@@ -51,6 +51,7 @@
 static import tango.text.Unicode;
 static import tango.text.convert.Format;
 import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
 
 /**
  * The CCombo class represents a selectable user interface object
@@ -152,7 +153,12 @@
                 return;
             }
             if (getShell () is event.widget) {
-                handleFocus (DWT.FocusOut);
+                getDisplay().asyncExec(new class() Runnable {
+                    public void run() {
+                        if (isDisposed()) return;
+                        handleFocus (DWT.FocusOut);
+                    }
+                });
             }
         }
     };
@@ -165,13 +171,13 @@
         }
     };
 
-    int [] comboEvents = [DWT.Dispose, DWT.Move, DWT.Resize];
+    int [] comboEvents = [DWT.Dispose, DWT.FocusIn, DWT.Move, DWT.Resize];
     for (int i=0; i<comboEvents.length; i++) this.addListener (comboEvents [i], listener);
 
-    int [] textEvents = [DWT.KeyDown, DWT.KeyUp, DWT.MenuDetect, DWT.Modify, DWT.MouseDown, DWT.MouseUp, DWT.Traverse, DWT.FocusIn, DWT.Verify];
+    int [] textEvents = [DWT.DefaultSelection, DWT.KeyDown, DWT.KeyUp, DWT.MenuDetect, DWT.Modify, DWT.MouseDown, DWT.MouseUp, DWT.MouseDoubleClick, DWT.MouseWheel, DWT.Traverse, DWT.FocusIn, DWT.Verify];
     for (int i=0; i<textEvents.length; i++) text.addListener (textEvents [i], listener);
 
-    int [] arrowEvents = [DWT.Selection, DWT.FocusIn];
+    int [] arrowEvents = [DWT.MouseDown, DWT.MouseUp, DWT.Selection, DWT.FocusIn];
     for (int i=0; i<arrowEvents.length; i++) arrow.addListener (arrowEvents [i], listener);
 
     createPopup(null, -1);
@@ -179,7 +185,7 @@
 }
 static int checkStyle (int style) {
     int mask = DWT.BORDER | DWT.READ_ONLY | DWT.FLAT | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
-    return style & mask;
+    return DWT.NO_FOCUS | (style & mask);
 }
 /**
  * Adds the argument to the end of the receiver's list.
@@ -318,7 +324,30 @@
             handleFocus (DWT.FocusIn);
             break;
         }
+        case DWT.MouseDown: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseDown, mouseEvent);
+            event.doit = mouseEvent.doit;
+            break;
+        }
+        case DWT.MouseUp: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseUp, mouseEvent);
+            event.doit = mouseEvent.doit;
+            break;
+        }
         case DWT.Selection: {
+            text.setFocus();
             dropDown (!isDropped ());
             break;
         }
@@ -363,6 +392,15 @@
             list = null;
             arrow = null;
             break;
+        case DWT.FocusIn:
+            Control focusControl = getDisplay ().getFocusControl ();
+            if (focusControl is arrow || focusControl is list) return;
+            if (isDropped()) {
+                list.setFocus();
+            } else {
+                text.setFocus();
+            }
+            break;
         case DWT.Move:
             dropDown (false);
             break;
@@ -465,7 +503,12 @@
  */
 public void deselect (int index) {
     checkWidget ();
-    list.deselect (index);
+    if (0 <= index && index < list.getItemCount () &&
+            index is list.getSelectionIndex() &&
+            text.getText().equals(list.getItem(index))) {
+        text.setText("");  //$NON-NLS-1$
+        list.deselect (index);
+    }
 }
 /**
  * Deselects all selected items in the receiver's list.
@@ -483,13 +526,14 @@
  */
 public void deselectAll () {
     checkWidget ();
+    text.setText("");  //$NON-NLS-1$
     list.deselectAll ();
 }
 void dropDown (bool drop) {
     if (drop is isDropped ()) return;
     if (!drop) {
         popup.setVisible (false);
-        if (!isDisposed ()&& arrow.isFocusControl()) {
+        if (!isDisposed () && isFocusControl()) {
             text.setFocus();
         }
         return;
@@ -527,7 +571,7 @@
     if (x + width > displayRect.x + displayRect.width) x = displayRect.x + displayRect.width - listRect.width;
     popup.setBounds (x, y, width, height);
     popup.setVisible (true);
-    list.setFocus ();
+    if (isFocusControl()) list.setFocus ();
 }
 /*
  * Return the lowercase of the first non-'&' character following
@@ -655,6 +699,29 @@
     checkWidget ();
     return list.getItems ();
 }
+/**
+ * Returns <code>true</code> if the receiver's list is visible,
+ * and <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's list's visibility state
+ *
+ * @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.4
+ */
+public bool getListVisible () {
+    checkWidget ();
+    return isDropped();
+}
 public override Menu getMenu() {
     return text.getMenu();
 }
@@ -905,7 +972,7 @@
 
         public void getLocation (AccessibleControlEvent e) {
             Rectangle location = getBounds ();
-            Point pt = toDisplay (location.x, location.y);
+            Point pt = getParent().toDisplay (location.x, location.y);
             e.x = pt.x;
             e.y = pt.y;
             e.width = location.width;
@@ -1002,6 +1069,12 @@
                 case DWT.TRAVERSE_ARROW_NEXT:
                     event.doit = false;
                     break;
+                case DWT.TRAVERSE_TAB_NEXT:
+                case DWT.TRAVERSE_TAB_PREVIOUS:
+                    event.doit = text.traverse(event.detail);
+                    event.detail = DWT.TRAVERSE_NONE;
+                    if (event.doit) dropDown(false);
+                    return;
                 default:
             }
             Event e = new Event ();
@@ -1093,8 +1166,10 @@
              * we hide the popup in the deactivate event, the selection event will show
              * it again. To prevent the popup from showing again, we will let the selection
              * event of the arrow button hide the popup.
+             * In Windows, hiding the popup during the deactivate causes the deactivate
+             * to be called twice and the selection event to be disappear.
              */
-            if ("gtk".equals(DWT.getPlatform())) {
+            if (!"carbon".equals(DWT.getPlatform())) {
                 Point point = arrow.toControl(getDisplay().getCursorLocation());
                 Point size = arrow.getSize();
                 Rectangle rect = new Rectangle(0, 0, size.x, size.y);
@@ -1317,6 +1392,7 @@
 }
 public override bool setFocus () {
     checkWidget();
+    if (!isEnabled () || !isVisible ()) return false;
     if (isFocusControl ()) return true;
     return text.setFocus ();
 }
@@ -1394,6 +1470,28 @@
     checkWidget ();
     return;
 }
+/**
+ * Marks the receiver's list as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param visible the new visibility state
+ *
+ * @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.4
+ */
+public void setListVisible (bool visible) {
+    checkWidget ();
+    dropDown(visible);
+}
 public override void setMenu(Menu menu) {
     text.setMenu(menu);
 }
@@ -1526,6 +1624,14 @@
             handleFocus (DWT.FocusIn);
             break;
         }
+        case DWT.DefaultSelection: {
+            dropDown (false);
+            Event e = new Event ();
+            e.time = event.time;
+            e.stateMask = event.stateMask;
+            notifyListeners (DWT.DefaultSelection, e);
+            break;
+        }
         case DWT.KeyDown: {
             Event keyEvent = new Event ();
             keyEvent.time = event.time;
@@ -1536,16 +1642,6 @@
             if (isDisposed ()) break;
             event.doit = keyEvent.doit;
             if (!event.doit) break;
-
-            if (event.character is DWT.CR) {
-                dropDown (false);
-                Event selectionEvent = new Event ();
-                selectionEvent.time = event.time;
-                selectionEvent.stateMask = event.stateMask;
-                notifyListeners (DWT.DefaultSelection, selectionEvent);
-                if (isDisposed ()) break;
-            }
-
             if (event.keyCode is DWT.ARROW_UP || event.keyCode is DWT.ARROW_DOWN) {
                 event.doit = false;
                 if ((event.stateMask & DWT.ALT) !is 0) {
@@ -1599,6 +1695,16 @@
             break;
         }
         case DWT.MouseDown: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseDown, mouseEvent);
+            if (isDisposed ()) break;
+            event.doit = mouseEvent.doit;
+            if (!event.doit) break;
             if (event.button !is 1) return;
             if (text.getEditable ()) return;
             bool dropped = isDropped ();
@@ -1608,14 +1714,60 @@
             break;
         }
         case DWT.MouseUp: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseUp, mouseEvent);
+            if (isDisposed ()) break;
+            event.doit = mouseEvent.doit;
+            if (!event.doit) break;
             if (event.button !is 1) return;
             if (text.getEditable ()) return;
             text.selectAll ();
             break;
         }
+        case DWT.MouseDoubleClick: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseDoubleClick, mouseEvent);
+            break;
+        }
+        case DWT.MouseWheel: {
+            Event keyEvent = new Event ();
+            keyEvent.time = event.time;
+            keyEvent.keyCode = event.count > 0 ? DWT.ARROW_UP : DWT.ARROW_DOWN;
+            keyEvent.stateMask = event.stateMask;
+            notifyListeners (DWT.KeyDown, keyEvent);
+            if (isDisposed ()) break;
+            event.doit = keyEvent.doit;
+            if (!event.doit) break;
+            if (event.count !is 0) {
+                event.doit = false;
+                int oldIndex = getSelectionIndex ();
+                if (event.count > 0) {
+                    select (Math.max (oldIndex - 1, 0));
+                } else {
+                    select (Math.min (oldIndex + 1, getItemCount () - 1));
+                }
+                if (oldIndex !is getSelectionIndex ()) {
+                    Event e = new Event();
+                    e.time = event.time;
+                    e.stateMask = event.stateMask;
+                    notifyListeners (DWT.Selection, e);
+                }
+                if (isDisposed ()) break;
+            }
+            break;
+        }
         case DWT.Traverse: {
             switch (event.detail) {
-                case DWT.TRAVERSE_RETURN:
                 case DWT.TRAVERSE_ARROW_PREVIOUS:
                 case DWT.TRAVERSE_ARROW_NEXT:
                     // The enter causes default selection and
@@ -1623,9 +1775,12 @@
                     // do not use them for traversal.
                     event.doit = false;
                     break;
+                case DWT.TRAVERSE_TAB_PREVIOUS:
+                    event.doit = traverse(DWT.TRAVERSE_TAB_PREVIOUS);
+                    event.detail = DWT.TRAVERSE_NONE;
+                    return;
                 default:
             }
-
             Event e = new Event ();
             e.time = event.time;
             e.detail = event.detail;
--- a/dwt/custom/CLabel.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/CLabel.d	Mon May 12 19:13:01 2008 +0200
@@ -33,6 +33,7 @@
 import dwt.graphics.Image;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
+import dwt.graphics.TextLayout;
 import dwt.widgets.Canvas;
 import dwt.widgets.Composite;
 import dwt.widgets.Control;
@@ -797,25 +798,33 @@
     int min = 0;
     int mid = (max+min)/2 - 1;
     if (mid <= 0) return t;
+    TextLayout layout = new TextLayout (getDisplay());
+    layout.setText(t);
+    mid = validateOffset(layout, mid);
     while (min < mid && mid < max) {
         String s1 = t[0 .. mid].dup;
-        String s2 = t[l-mid .. l].dup;
+        String s2 = t.substring(validateOffset(layout, l-mid), l);
         int l1 = gc.textExtent(s1, DRAW_FLAGS).x;
         int l2 = gc.textExtent(s2, DRAW_FLAGS).x;
         if (l1+w+l2 > width) {
             max = mid;
-            mid = (max+min)/2;
+            mid = validateOffset(layout, (max+min)/2);
         } else if (l1+w+l2 < width) {
             min = mid;
-            mid = (max+min)/2;
+            mid = validateOffset(layout, (max+min)/2);
         } else {
             min = max;
         }
     }
-    if (mid is 0) return t;
-    return t[ 0 .. mid ] ~ ELLIPSIS ~ t[ l-mid .. l ];
+    String result = mid is 0 ? t : t.substring(0, mid) ~ ELLIPSIS ~ t.substring(validateOffset(layout, l-mid), l);
+    layout.dispose();
+    return result;
 }
-
+int validateOffset(TextLayout layout, int offset) {
+    int nextOffset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER);
+    if (nextOffset !is offset) return layout.getPreviousOffset(nextOffset, DWT.MOVEMENT_CLUSTER);
+    return offset;
+}
 private String[] splitString(String text) {
     String[] lines = new String[1];
     int start = 0, pos;
--- a/dwt/custom/CTabFolder.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/CTabFolder.d	Mon May 12 19:13:01 2008 +0200
@@ -1543,6 +1543,8 @@
     style &= ~(DWT.SINGLE | DWT.MULTI);
     style |= single ? DWT.SINGLE : DWT.MULTI;
     if (borderLeft !is 0) style |= DWT.BORDER;
+    style &= ~DWT.CLOSE;
+    if (showClose) style |= DWT.CLOSE;
     return style;
 }
 /**
@@ -1717,20 +1719,26 @@
 
         public void getLocation(AccessibleControlEvent e) {
             Rectangle location = null;
+            Point pt = null;
             int childID = e.childID;
             if (childID is ACC.CHILDID_SELF) {
                 location = getBounds();
-            } else if (childID >= 0 && childID < items.length) {
-                location = items[childID].getBounds();
-            } else if (showChevron && childID is items.length + CHEVRON_CHILD_ID) {
-                location = chevronRect;
-            } else if (showMin && childID is items.length + MINIMIZE_CHILD_ID) {
-                location = minRect;
-            } else if (showMax && childID is items.length + MAXIMIZE_CHILD_ID) {
-                location = maxRect;
+                pt = getParent().toDisplay(location.x, location.y);
+            } else {
+                if (childID >= 0 && childID < items.length && items[childID].isShowing()) {
+                    location = items[childID].getBounds();
+                } else if (showChevron && childID is items.length + CHEVRON_CHILD_ID) {
+                    location = chevronRect;
+                } else if (showMin && childID is items.length + MINIMIZE_CHILD_ID) {
+                    location = minRect;
+                } else if (showMax && childID is items.length + MAXIMIZE_CHILD_ID) {
+                    location = maxRect;
+                }
+                if (location !is null) {
+                    pt = toDisplay(location.x, location.y);
+                }
             }
-            if (location !is null) {
-                Point pt = toDisplay(location.x, location.y);
+            if (location !is null && pt !is null) {
                 e.x = pt.x;
                 e.y = pt.y;
                 e.width = location.width;
@@ -2243,8 +2251,8 @@
                         CTabFolderListener listener = tabListeners[j];
                         listener.itemClosed(e);
                     }
-                    if (e.doit) {
-                        item.dispose();
+                    if (e.doit) item.dispose();
+                    if (!isDisposed() && item.isDisposed()) {
                         Display display = getDisplay();
                         Point pt = display.getCursorLocation();
                         pt = display.map(null, this, pt.x, pt.y);
@@ -2782,7 +2790,7 @@
         topRight.setBounds(topRightRect);
     }
     if (oldX !is topRightRect.x || oldWidth !is topRightRect.width ||
-        oldY !is topRightRect.y || oldHeight !is topRightRect.height) {
+        oldY !is topRightRect.y || oldHeight !is topRightRect.height) { 
         int left = Math.min(oldX, topRightRect.x);
         int right = Math.max(oldX + oldWidth, topRightRect.x + topRightRect.width);
         int top = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
@@ -3287,22 +3295,25 @@
     selection.closeImageState = NORMAL;
     selection.showing = false;
 
-    Control control = selection.control;
-    if (control !is null && !control.isDisposed()) {
-        control.setBounds(getClientArea());
-        control.setVisible(true);
+    Control newControl = selection.control;
+    Control oldControl = null;
+    if (oldIndex !is -1) {
+        oldControl = items[oldIndex].control;
     }
 
-    if (oldIndex !is -1) {
-        control = items[oldIndex].control;
-        if (control !is null && !control.isDisposed()) {
-            control.setVisible(false);
+    if (newControl !is oldControl) {
+        if (newControl !is null && !newControl.isDisposed()) {
+            newControl.setBounds(getClientArea());
+            newControl.setVisible(true);
+        }
+        if (oldControl !is null && !oldControl.isDisposed()) {
+            oldControl.setVisible(false);
         }
     }
     showItem(selection);
     redraw();
 }
-void setSelection(int index, bool notify) {
+void setSelection(int index, bool notify) { 
     int oldSelectedIndex = selectedIndex;
     setSelection(index);
     if (notify && selectedIndex !is oldSelectedIndex && selectedIndex !is -1) {
@@ -4015,7 +4026,7 @@
 }
 bool updateTabHeight(bool force){
     int style = getStyle();
-    if (fixedTabHeight is 0 && (style & DWT.FLAT) !is 0 && (style & DWT.BORDER) is 0) highlight_header = 0;
+    if (fixedTabHeight is 0 && (style & DWT.FLAT) !is 0 && (style & DWT.BORDER) is 0) highlight_header = 0;     
     int oldHeight = tabHeight;
     if (fixedTabHeight !is DWT.DEFAULT) {
         tabHeight = fixedTabHeight is 0 ? 0 : fixedTabHeight + 1; // +1 for line drawn across top of tab
--- a/dwt/custom/CTabItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/CTabItem.d	Mon May 12 19:13:01 2008 +0200
@@ -25,6 +25,7 @@
 import dwt.graphics.Point;
 import dwt.graphics.RGB;
 import dwt.graphics.Rectangle;
+import dwt.graphics.TextLayout;
 import dwt.widgets.Control;
 import dwt.widgets.Display;
 import dwt.widgets.Item;
@@ -135,13 +136,10 @@
  */
 public this (CTabFolder parent, int style, int index) {
     closeRect = new Rectangle(0, 0, 0, 0);
-    super (parent, checkStyle(style));
+    super (parent, style);
     showClose = (style & DWT.CLOSE) !is 0;
     parent.createItem (this, index);
 }
-static int checkStyle(int style) {
-    return DWT.NONE;
-}
 
 /*
  * Return whether to use ellipses or just truncate labels
@@ -160,16 +158,19 @@
     if (gc.textExtent(text, FLAGS).x <= width) return text;
     int ellipseWidth = gc.textExtent(ellipses, FLAGS).x;
     int length = text.length;
-    int end = length - 1;
+    TextLayout layout = new TextLayout(getDisplay());
+    layout.setText(text);
+    int end = layout.getPreviousOffset(length, DWT.MOVEMENT_CLUSTER);
     while (end > 0) {
         text = text[ 0 .. end ];
         int l = gc.textExtent(text, FLAGS).x;
         if (l + ellipseWidth <= width) {
-            return text ~ ellipses;
+            break;
         }
-        end--;
+        end = layout.getPreviousOffset(end, DWT.MOVEMENT_CLUSTER);
     }
-    return text[ 0 .. 1 ];
+    layout.dispose();
+    return end is 0 ? text.substring(0, 1) : text ~ ellipses;
 }
 
 public override void dispose() {
@@ -768,6 +769,24 @@
     return parent;
 }
 /**
+ * Returns <code>true</code> to indicate that the receiver's close button should be shown.
+ * Otherwise return <code>false</code>. The initial value is defined by the style (DWT.CLOSE)
+ * that was used to create the receiver.
+ * 
+ * @return <code>true</code> if the close button should be shown
+ *
+ * @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.4
+ */
+public bool getShowClose() {
+    checkWidget();
+    return showClose;
+}
+/**
  * Returns the receiver's tool tip text, or null if it has
  * not been set.
  *
@@ -998,6 +1017,27 @@
         parent.redrawTabs();
     }
 }
+/**
+ * Sets to <code>true</code> to indicate that the receiver's close button should be shown.
+ * If the parent (CTabFolder) was created with DWT.CLOSE style, changing this value has
+ * no effect.
+ * 
+ * @param close the new state of the close button
+ *
+ * @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.4
+ */
+public void setShowClose(bool close) {
+    checkWidget();
+    if (showClose is close) return;
+    showClose = close;
+    parent.updateItems();
+    parent.redrawTabs();
+}
 public override void setText (String string) {
     checkWidget();
     if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
@@ -1025,4 +1065,5 @@
     checkWidget();
     toolTipText = string;
 }
+
 }
--- a/dwt/custom/LineBackgroundEvent.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/LineBackgroundEvent.d	Mon May 12 19:13:01 2008 +0200
@@ -45,6 +45,7 @@
     super(cast(Object)e);
     lineOffset = e.detail;
     lineText = e.text;
+    lineBackground = e.lineBackground;
 }
 }
 
--- a/dwt/custom/LineStyleEvent.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/LineStyleEvent.d	Mon May 12 19:13:01 2008 +0200
@@ -89,6 +89,8 @@
 
 public this(StyledTextEvent e) {
     super(cast(Object)e);
+    styles = e.styles;
+    ranges = e.ranges;
     lineOffset = e.detail;
     lineText = e.text;
     alignment = e.alignment;
--- a/dwt/custom/SashForm.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/SashForm.d	Mon May 12 19:13:01 2008 +0200
@@ -111,6 +111,23 @@
     //checkWidget();
     return (sashStyle & DWT.VERTICAL) !is 0 ? DWT.HORIZONTAL : DWT.VERTICAL;
 }
+/**
+ * Returns the width of the sashes when the controls in the SashForm are 
+ * laid out.
+ * 
+ * @return the width of the sashes
+ * 
+ * @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.4
+ */
+public int getSashWidth() {
+    checkWidget();
+    return SASH_WIDTH;
+}
 public override int getStyle() {
     int style = super.getStyle();
     style |= getOrientation() is DWT.VERTICAL ? DWT.VERTICAL : DWT.HORIZONTAL;
@@ -360,6 +377,25 @@
 }
 
 /**
+ * Specify the width of the sashes when the controls in the SashForm are 
+ * laid out.
+ * 
+ * @param width the width of the sashes
+ * 
+ * @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.4
+ */
+public void setSashWidth(int width) {
+    checkWidget();
+    if (SASH_WIDTH is width) return;
+    SASH_WIDTH = width;
+    layout(false);
+}
+/**
  * Specify the relative weight of each child in the SashForm.  This will determine
  * what percent of the total width (if SashForm has Horizontal orientation) or
  * total height (if SashForm has Vertical orientation) each control will occupy.
--- a/dwt/custom/ScrolledComposite.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/ScrolledComposite.d	Mon May 12 19:13:01 2008 +0200
@@ -17,14 +17,18 @@
 
 import dwt.DWT;
 import dwt.DWTException;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
 import dwt.widgets.Composite;
 import dwt.widgets.Control;
+import dwt.widgets.Display;
 import dwt.widgets.Event;
 import dwt.widgets.Layout;
 import dwt.widgets.Listener;
 import dwt.widgets.ScrollBar;
+import dwt.widgets.Shell;
 import dwt.custom.ScrolledCompositeLayout;
 
 /**
@@ -114,12 +118,14 @@
 
     Control content;
     Listener contentListener;
+    Listener filter;
 
     int minHeight = 0;
     int minWidth = 0;
     bool expandHorizontal = false;
     bool expandVertical = false;
     bool alwaysShowScroll = false;
+    bool showFocusedControl = false;
 
 /**
  * Constructs a new instance of this class given its parent
@@ -177,6 +183,20 @@
             layout(false);
         }
     };
+
+    filter = new class() Listener {
+        public void handleEvent(Event event) {
+            if (auto control = cast(Control)event.widget ) {
+                if (contains(control)) showControl(control);
+            }
+        }
+    };
+
+    addDisposeListener(new class() DisposeListener {
+        public void widgetDisposed(DisposeEvent e) {
+            getDisplay().removeFilter(DWT.FocusIn, filter);
+        }
+    });
 }
 
 static int checkStyle (int style) {
@@ -184,6 +204,17 @@
     return style & mask;
 }
 
+bool contains(Control control) {
+    if (control is null || control.isDisposed()) return false;
+
+    Composite parent = control.getParent();
+    while (parent !is null && !( null !is cast(Shell)parent )) {
+        if (this is parent) return true;
+        parent = parent.getParent();
+    }
+    return false;
+}
+
 /**
  * Returns the Always Show Scrollbars flag.  True if the scrollbars are
  * always shown even if they are not required.  False if the scrollbars are only
@@ -278,6 +309,22 @@
     return content;
 }
 
+/**
+ * Returns <code>true</code> if the receiver automatically scrolls to a focused child control
+ * to make it visible. Otherwise, returns <code>false</code>.
+ *
+ * @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.4
+ */
+public bool getShowFocusedControl() {
+    checkWidget();
+    return showFocusedControl;
+}
+
 void hScroll() {
     if (content is null) return;
     Point location = content.getLocation ();
@@ -587,6 +634,66 @@
     setMinSize(width, minHeight);
 }
 
+/**
+ * Configure the receiver to automatically scroll to a focused child control
+ * to make it visible.
+ *
+ * If show is <code>false</code>, show a focused control is off.
+ * By default, show a focused control is off.
+ *
+ * @param show <code>true</code> to show a focused control.
+ *
+ * @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.4
+ */
+public void setShowFocusedControl(bool show) {
+    checkWidget();
+    if (showFocusedControl is show) return;
+    Display display = getDisplay();
+    display.removeFilter(DWT.FocusIn, filter);
+    showFocusedControl = show;
+    if (!showFocusedControl) return;
+    display.addFilter(DWT.FocusIn, filter);
+    Control control = display.getFocusControl();
+    if (contains(control)) showControl(control);
+}
+
+/**
+ * Scrolls the content of the receiver so that the control is visible.
+ *
+ * @param control the control to be shown
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the control is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</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>
+ *
+ * @since 3.4
+ */
+public void showControl(Control control) {
+    checkWidget ();
+    if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (control.isDisposed ()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    if (!contains(control)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+
+    Rectangle itemRect = getDisplay().map(control.getParent(), this, control.getBounds());
+    Rectangle area = getClientArea();
+    Point origin = getOrigin();
+    if (itemRect.x < 0) origin.x = Math.max(0, origin.x + itemRect.x);
+    if (itemRect.y < 0) origin.y = Math.max(0, origin.y + itemRect.y);
+    if (area.width < itemRect.x + itemRect.width) origin.x = Math.max(0, origin.x + itemRect.x + itemRect.width - area.width);
+    if (area.height < itemRect.y + itemRect.height) origin.y = Math.max(0, origin.y + itemRect.y + itemRect.height - area.height);
+    setOrigin(origin);
+}
+
 void vScroll() {
     if (content is null) return;
     Point location = content.getLocation ();
--- a/dwt/custom/StyleRange.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/StyleRange.d	Mon May 12 19:13:01 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * 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
@@ -47,6 +47,13 @@
      */
     public int fontStyle = DWT.NORMAL;
 
+/**
+ * Create a new style range with no styles
+ *
+ * @since 3.2
+ */
+public this() {
+}
 /++
  + DWT extension for clone implementation
  +/
@@ -58,12 +65,14 @@
 }
 
 /**
- * Create a new style range with no styles
+ * Create a new style range from an existing text style.
+ *
+ *@param style the text style to copy
  *
- * @since 3.2
+ *@since 3.4
  */
-public this() {
-    super(null, null, null);
+public this(TextStyle style) {
+    super(style);
 }
 
 /**
@@ -145,6 +154,7 @@
     if (fontStyle !is DWT.NORMAL) return false;
     if (underline) return false;
     if (strikeout) return false;
+    if (borderStyle !is DWT.NONE) return false;
     return true;
 }
 
--- a/dwt/custom/StyledText.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/StyledText.d	Mon May 12 19:13:01 2008 +0200
@@ -56,6 +56,7 @@
 import dwt.widgets.Control;
 import dwt.widgets.Display;
 import dwt.widgets.Event;
+import dwt.widgets.IME;
 import dwt.widgets.Label;
 import dwt.widgets.Listener;
 import dwt.widgets.ScrollBar;
@@ -195,8 +196,8 @@
     Point doubleClickSelection;         // selection after last mouse double click
     bool editable = true;
     bool wordWrap = false;
-    bool doubleClickEnabled = true;  // see getDoubleClickEnabled
-    bool overwrite = false;          // insert/overwrite edit mode
+    bool doubleClickEnabled = true; // see getDoubleClickEnabled
+    bool overwrite = false;         // insert/overwrite edit mode
     int textLimit = -1;                 // limits the number of characters the user can type in the widget. Unlimited by default.
     int[int] keyActionMap;
     Color background = null;            // workaround for bug 4791
@@ -212,14 +213,16 @@
     int lastTextChangeReplaceCharCount;
     int lastLineBottom;                 // the bottom pixel of the last line been replaced
     bool isMirrored_;
-    bool bidiColoring = false;       // apply the BIDI algorithm on text segments of the same color
+    bool bidiColoring = false;      // apply the BIDI algorithm on text segments of the same color
     Image leftCaretBitmap = null;
     Image rightCaretBitmap = null;
     int caretDirection = DWT.NULL;
+    int caretWidth = 0;
     Caret defaultCaret = null;
     bool updateCaretDirection = true;
     bool fixedLineHeight;
     bool dragDetect_ = true;
+    IME ime;
 
     int alignment;
     bool justify;
@@ -259,9 +262,9 @@
         int endPage;                                    // last page to print
         int startLine;                                  // first (wrapped) line to print
         int endLine;                                    // last (wrapped) line to print
-        bool singleLine;                             // widget single line mode
+        bool singleLine;                                // widget single line mode
         Point selection = null;                 // selected text
-        bool mirrored;                       // indicates the printing gc should be mirrored
+        bool mirrored;                      // indicates the printing gc should be mirrored
         int lineSpacing;
         int printMargin;
 
@@ -525,11 +528,24 @@
             printLayout.setFont(printerFont);
         }
         if (printOptions.printLineNumbers) {
+            int numberingWidth = 0;
             int count = endLine - startLine + 1;
-            StringBuffer buffer = new StringBuffer("0");
-            while ((count /= 10) > 0) buffer.append("0");
-            printLayout.setText(buffer.toString());
-            int numberingWidth = printLayout.getBounds().width + printMargin;
+            String[] lineLabels = printOptions.lineLabels;
+            if (lineLabels !is null) {
+                for (int i = startLine; i < Math.min(count, lineLabels.length); i++) {
+                    if (lineLabels[i] !is null) {
+                        printLayout.setText(lineLabels[i]);
+                        int lineWidth = printLayout.getBounds().width;
+                        numberingWidth = Math.max(numberingWidth, lineWidth);
+                    }
+                }
+            } else {
+                StringBuffer buffer = new StringBuffer("0");
+                while ((count /= 10) > 0) buffer.append("0");
+                printLayout.setText(buffer.toString());
+                numberingWidth = printLayout.getBounds().width;
+            }
+            numberingWidth += printMargin;
             if (numberingWidth > width) numberingWidth = width;
             paintX += numberingWidth;
             width -= numberingWidth;
@@ -567,8 +583,9 @@
                 } else {
                     //draw paragraph top in the current page and paragraph bottom in the next
                     int height = paragraphBottom - paintY;
-                    gc.setClipping(paintX, paintY, width, height);
+                    gc.setClipping(clientArea.x, paintY, clientArea.width, height);
                     printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
+                    gc.setClipping(cast(Rectangle)null);
                     printDecoration(page, false, printLayout);
                     printer.endPage();
                     page++;
@@ -577,16 +594,16 @@
                         printDecoration(page, true, printLayout);
                         paintY = clientArea.y - height;
                         int layoutHeight = layout.getBounds().height;
-                        gc.setClipping(paintX, clientArea.y, width, layoutHeight - height);
+                        gc.setClipping(clientArea.x, clientArea.y, clientArea.width, layoutHeight - height);
                         printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
+                        gc.setClipping(cast(Rectangle)null);
                         paintY += layoutHeight;
                     }
-                    gc.setClipping(cast(Rectangle)null);
                 }
             }
             printerRenderer.disposeTextLayout(layout);
         }
-        if (paintY > clientArea.y) {
+        if (page <= endPage && paintY > clientArea.y) {
             // close partial page
             printDecoration(page, false, printLayout);
             printer.endPage();
@@ -673,9 +690,18 @@
         }
         if (printOptions.printLineNumbers) {
             FontMetrics metrics = layout.getLineMetrics(0);
-            printLayout.setAscent(metrics.getAscent() + metrics.getDescent());
+            printLayout.setAscent(metrics.getAscent() + metrics.getLeading());
             printLayout.setDescent(metrics.getDescent());
-            printLayout.setText( to!(String)(index) );
+            String[] lineLabels = printOptions.lineLabels;
+            if (lineLabels !is null) {
+                if (0 <= index && index < lineLabels.length && lineLabels[index] !is null) {
+                    printLayout.setText(lineLabels[index]);
+                } else {
+                    printLayout.setText("");
+                }
+            } else {
+                printLayout.setText(to!(String)(index));
+            }
             int paintX = x - printMargin - printLayout.getBounds().width;
             printLayout.draw(gc, paintX, y);
             printLayout.setAscent(-1);
@@ -1311,7 +1337,8 @@
     renderer = new StyledTextRenderer(getDisplay(), this);
     renderer.setContent(content);
     renderer.setFont(getFont(), tabLength);
-    defaultCaret = new Caret(this, DWT.NULL);
+    ime = new IME(this, DWT.NONE);
+    defaultCaret = new Caret(this, DWT.NONE);
     if ((style & DWT.WRAP) !is 0) {
         setWordWrap(true);
     }
@@ -1326,7 +1353,7 @@
                 setCaretLocation(newCaretPos, direction);
             }
         };
-        BidiUtil.addLanguageListener(handle, runnable);
+        BidiUtil.addLanguageListener(this, runnable);
     }
     setCaret(defaultCaret);
     calculateScrollBars();
@@ -1750,10 +1777,12 @@
         int maxHeight = display.getClientArea().height;
         for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) {
             TextLayout layout = renderer.getTextLayout(lineIndex);
+            int wrapWidth = layout.getWidth();
             if (wordWrap) layout.setWidth(wHint is 0 ? 1 : wHint);
             Rectangle rect = layout.getBounds();
             height += rect.height;
             width = Math.max(width, rect.width);
+            layout.setWidth(wrapWidth);
             renderer.disposeTextLayout(layout);
             if (isFixedLineHeight() && height > maxHeight) break;
         }
@@ -1940,8 +1969,8 @@
         if (event.button !is 1) return false;
     }
     if (selection.x is selection.y) return false;
-    int offset = getOffsetAtPoint(event.x, event.y);
-    if (offset > selection.x && offset < selection.y) {
+    int offset = getOffsetAtPoint(event.x, event.y, null, true);
+    if (selection.x <= offset && offset < selection.y) {
         return dragDetect(event);
     }
     return false;
@@ -2233,10 +2262,6 @@
  * @param key the character typed by the user
  */
 void doContent(dchar key) {
-    if (textLimit > 0 &&
-        content.getCharCount() - (selection.y - selection.x) >= textLimit) {
-        return;
-    }
     Event event = new Event();
     event.start = selection.x;
     event.end = selection.y;
@@ -2263,6 +2288,9 @@
         event.text = dcharToString( key );
     }
     if (event.text !is null) {
+        if (textLimit > 0 && content.getCharCount() - (event.end - event.start) >= textLimit) {
+            return;
+        }
         sendKeyEvent(event);
     }
 }
@@ -2527,8 +2555,7 @@
     int oldCaretAlignment = caretAlignment;
     int newCaretOffset = getOffsetAtPoint(x, y);
 
-    if (clickCount > 1) {
-        // double click word select the previous/next word. fixes bug 15610
+    if (doubleClickEnabled && clickCount > 1) {
         newCaretOffset = doMouseWordSelect(x, newCaretOffset, line);
     }
 
@@ -3244,21 +3271,27 @@
 }
 Rectangle getBoundsAtOffset(int offset) {
     int lineIndex = content.getLineAtOffset(offset);
+    int lineOffset = content.getOffsetAtLine(lineIndex);
     String line = content.getLine(lineIndex);
     Rectangle bounds;
     if (line.length !is 0) {
-        int offsetInLine = offset - content.getOffsetAtLine(lineIndex);
+        int offsetInLine = offset - lineOffset;
         TextLayout layout = renderer.getTextLayout(lineIndex);
         bounds = layout.getBounds(offsetInLine, offsetInLine);
         renderer.disposeTextLayout(layout);
     } else {
         bounds = new Rectangle (0, 0, 0, renderer.getLineHeight());
     }
+    if (offset is caretOffset) {
+        int lineEnd = lineOffset + line.length;
+        if (offset is lineEnd && caretAlignment is PREVIOUS_OFFSET_TRAILING) {
+            bounds.width += getCaretWidth();
+        }
+    }
     bounds.x += leftMargin - horizontalScrollOffset;
     bounds.y += getLinePixel(lineIndex);
     return bounds;
 }
-
 /**
  * Returns the caret position relative to the start of the text.
  *
@@ -3305,11 +3338,11 @@
     return offset;
 }
 /**
- * Returns the content implementation that is used for text storage
- * or null if no user defined content implementation has been set.
- *
- * @return content implementation that is used for text storage or null
- * if no user defined content implementation has been set.
+ * Returns the content implementation that is used for text storage.
+ *
+ * @return content the user defined content implementation that is used for
+ * text storage or the default content implementation if no user defined
+ * content implementation has been set.
  * @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>
@@ -3466,6 +3499,32 @@
     return content.getCharCount();
 }
 /**
+ * Returns the line at the given line index without delimiters.
+ * Index 0 is the first line of the content. When there are not
+ * any lines, getLine(0) is a valid call that answers an empty string.
+ * <p>
+ *
+ * @param lineIndex index of the line to return.
+ * @return the line text without delimiters
+ *
+ * @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_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li>
+ * </ul>
+ * @since 3.4
+ */
+public String getLine(int lineIndex) {
+    checkWidget();
+    if (lineIndex < 0 ||
+        (lineIndex > 0 && lineIndex >= content.getLineCount())) {
+        DWT.error(DWT.ERROR_INVALID_RANGE);
+    }
+    return content.getLine(lineIndex);
+}
+/**
  * Returns the alignment of the line at the given index.
  *
  * @param index the index of the line
@@ -3857,7 +3916,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
+ *   <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li>
  * </ul>
  * @since 2.0
  */
@@ -3897,32 +3956,12 @@
     if (point is null) {
         DWT.error(DWT.ERROR_NULL_ARGUMENT);
     }
-    // is y above first line or is x before first column?
-    if (point.y + getVerticalScrollOffset() < 0 || point.x + horizontalScrollOffset < 0) {
-        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    }
-    int bottomIndex = getLineIndex(clientAreaHeight);
-    int height = getLinePixel(bottomIndex) + renderer.getLineHeight(bottomIndex);
-    if (point.y > height) {
+    int[] trailing = new int[1];
+    int offset = getOffsetAtPoint(point.x, point.y, trailing, true);
+    if (offset is -1) {
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
-    int lineIndex = getLineIndex(point.y);
-    int lineOffset = content.getOffsetAtLine(lineIndex);
-    TextLayout layout = renderer.getTextLayout(lineIndex);
-    int[] trailing = new int[1];
-    int x = point.x + horizontalScrollOffset - leftMargin ;
-    int y = point.y - getLinePixel(lineIndex);
-    int offsetInLine = layout.getOffset(x, y, trailing);
-    String line = content.getLine(lineIndex);
-    if (offsetInLine !is line.length - 1) {
-        offsetInLine = Math.min(line.length, offsetInLine + trailing[0]);
-    }
-    Rectangle rect = layout.getLineBounds(layout.getLineIndex(offsetInLine));
-    renderer.disposeTextLayout(layout);
-    if (x > rect.x + rect.width) {
-        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    }
-    return lineOffset + offsetInLine;
+    return offset + trailing[0];
 }
 int getOffsetAtPoint(int x, int y) {
     int lineIndex = getLineIndex(y);
@@ -3945,7 +3984,6 @@
     caretAlignment = OFFSET_LEADING;
     if (trailing[0] !is 0) {
         int lineInParagraph = layout.getLineIndex(offsetInLine + trailing[0]);
-        //TODO handle bidi text
         int lineStart = layout.getLineOffsets()[lineInParagraph];
         if (offsetInLine + trailing[0] is lineStart) {
             offsetInLine += trailing[0];
@@ -3972,6 +4010,28 @@
     renderer.disposeTextLayout(layout);
     return offsetInLine + content.getOffsetAtLine(lineIndex);
 }
+int getOffsetAtPoint(int x, int y, int[] trailing, bool inTextOnly) {
+    if (inTextOnly && y + getVerticalScrollOffset() < 0 || x + horizontalScrollOffset < 0) {
+        return -1;
+    }
+    int bottomIndex = getPartialBottomIndex();
+    int height = getLinePixel(bottomIndex + 1);
+    if (inTextOnly && y > height) {
+        return -1;
+    }
+    int lineIndex = getLineIndex(y);
+    int lineOffset = content.getOffsetAtLine(lineIndex);
+    TextLayout layout = renderer.getTextLayout(lineIndex);
+    x += horizontalScrollOffset - leftMargin ;
+    y -= getLinePixel(lineIndex);
+    int offset = layout.getOffset(x, y, trailing);
+    Rectangle rect = layout.getLineBounds(layout.getLineIndex(offset));
+    renderer.disposeTextLayout(layout);
+    if (inTextOnly && !(rect.x  <= x && x <=  rect.x + rect.width)) {
+        return -1;
+    }
+    return offset + lineOffset;
+}
 /**
  * Returns the orientation of the receiver.
  *
@@ -3997,7 +4057,7 @@
     if (isFixedLineHeight()) {
         int lineHeight = renderer.getLineHeight();
         int partialLineCount = Compatibility.ceil(clientAreaHeight, lineHeight);
-        return Math.min(content.getLineCount(), topIndex + partialLineCount) - 1;
+        return Math.max(0, Math.min(content.getLineCount(), topIndex + partialLineCount) - 1);
     }
     return getLineIndex(clientAreaHeight - bottomMargin);
 }
@@ -4594,12 +4654,15 @@
     for (int i = lineStart; i <= lineEnd; i++) {
         int lineOffset = content.getOffsetAtLine(i);
         TextLayout layout = renderer.getTextLayout(i);
-        if (layout.getText().length > 0) {
-            if (i is lineStart && i is lineEnd) {
-                rect = layout.getBounds(start - lineOffset, end - lineOffset);
-            } else if (i is lineStart) {
-                String line = content.getLine(i);
-                rect = layout.getBounds(start - lineOffset, line.length);
+        int length = layout.getText().length;
+        if (length > 0) {
+            if (i is lineStart) {
+                if (i is lineEnd) {
+                    rect = layout.getBounds(start - lineOffset, end - lineOffset);
+                } else {
+                    rect = layout.getBounds(start - lineOffset, length);
+                }
+                y += rect.y;
             } else if (i is lineEnd) {
                 rect = layout.getBounds(0, end - lineOffset);
             } else {
@@ -4724,6 +4787,7 @@
 }
 int getCaretDirection() {
     if (!isBidiCaret()) return DWT.DEFAULT;
+    if (ime.getCompositionOffset() !is -1) return DWT.DEFAULT;
     if (!updateCaretDirection && caretDirection !is DWT.NULL) return caretDirection;
     updateCaretDirection = false;
     int caretLine = getCaretLine();
@@ -4751,7 +4815,7 @@
 }
 int getWrapWidth () {
     if (wordWrap && !isSingleLine()) {
-        int width = clientAreaWidth - leftMargin - rightMargin;
+        int width = clientAreaWidth - leftMargin - rightMargin - getCaretWidth();
         return width > 0 ? width : 1;
     }
     return -1;
@@ -4932,6 +4996,15 @@
     addListener(DWT.Paint, listener);
     addListener(DWT.Resize, listener);
     addListener(DWT.Traverse, listener);
+    ime.addListener(DWT.ImeComposition, new class() Listener {
+        public void handleEvent(Event event) {
+            switch (event.detail) {
+                case DWT.COMPOSITION_SELECTION: handleCompositionSelection(event); break;
+                case DWT.COMPOSITION_CHANGED: handleCompositionChanged(event); break;
+                case DWT.COMPOSITION_OFFSET: handleCompositionOffset(event); break;
+            }
+        }
+    });
     if (verticalBar !is null) {
         verticalBar.addListener(DWT.Selection, new class() Listener {
             public void handleEvent(Event event) {
@@ -5035,6 +5108,39 @@
         super.redraw(leftMargin, y, clientAreaWidth - rightMargin - leftMargin, endRect.y - y, false);
     }
 }
+void handleCompositionOffset (Event event) {
+    int[] trailing = new int [1];
+    event.index = getOffsetAtPoint(event.x, event.y, trailing, true);
+    event.count = trailing[0];
+}
+void handleCompositionSelection (Event event) {
+    event.start = selection.x;
+    event.end = selection.y;
+    event.text = getSelectionText();
+}
+void handleCompositionChanged(Event event) {
+    String text = event.text;
+    int start = event.start;
+    int end = event.end;
+    int length = text.length;
+    if (length is ime.getCommitCount()) {
+        content.replaceTextRange(start, end - start, "");
+        caretOffset = start;
+        caretWidth = 0;
+        caretDirection = DWT.NULL;
+    } else {
+        content.replaceTextRange(start, end - start, text);
+        caretOffset = ime.getCaretOffset();
+        if (ime.getWideCaret()) {
+            int lineIndex = getCaretLine();
+            int lineOffset = content.getOffsetAtLine(lineIndex);
+            TextLayout layout = renderer.getTextLayout(lineIndex);
+            caretWidth = layout.getBounds(start - lineOffset, start + length - 1 - lineOffset).width;
+            renderer.disposeTextLayout(layout);
+        }
+    }
+    showCaret();
+}
 /**
  * Frees resources.
  */
@@ -5065,7 +5171,7 @@
         rightCaretBitmap = null;
     }
     if (isBidiCaret()) {
-        BidiUtil.removeLanguageListener(handle);
+        BidiUtil.removeLanguageListener(this);
     }
     selectionBackground = null;
     selectionForeground = null;
@@ -5247,8 +5353,8 @@
                 start = lineOffset;
                 end = lineEnd;
             }
-            selection.x = selection.y = start;
-            selectionAnchor = -1;
+            caretOffset = start;
+            resetSelection();
             caretOffset = end;
             showCaret();
             doMouseSelection();
@@ -5393,6 +5499,10 @@
  * the content change.
  */
 void handleTextChanged(TextChangedEvent event) {
+    int offset = ime.getCompositionOffset();
+    if (offset !is -1 && lastTextChangeStart < offset) {
+        ime.setCompositionOffset(offset + lastTextChangeNewCharCount - lastTextChangeReplaceCharCount);
+    }
     int firstLine = content.getLineAtOffset(lastTextChangeStart);
     resetCache(firstLine, 0);
     if (!isFixedLineHeight() && topIndex > firstLine) {
@@ -5783,7 +5893,7 @@
  * Temporary until DWT provides this
  */
 bool isBidi() {
-    return IS_GTK || BidiUtil.isBidiPlatform() || isMirrored_;
+    return IS_GTK || IS_CARBON || BidiUtil.isBidiPlatform() || isMirrored_;
 }
 bool isBidiCaret() {
     return BidiUtil.isBidiPlatform();
@@ -6510,9 +6620,7 @@
         }
     }
     horizontalScrollOffset += pixels;
-    int oldColumnX = columnX;
     setCaretLocation();
-    columnX = oldColumnX;
     return true;
 }
 /**
@@ -6565,9 +6673,7 @@
         calculateTopIndex(pixels);
         super.redraw();
     }
-    int oldColumnX = columnX;
     setCaretLocation();
-    columnX = oldColumnX;
     return true;
 }
 void scrollText(int srcY, int destY) {
@@ -6702,6 +6808,10 @@
 /**
  * Sets the alignment of the widget. The argument should be one of <code>DWT.LEFT</code>,
  * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>. The alignment applies for all lines.
+ * </p><p>
+ * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set
+ * in order to stabilize the right edge before setting alignment.
+ * </p>
  *
  * @param alignment the new alignment
  *
@@ -6729,6 +6839,7 @@
 public override void setBackground(Color color) {
     checkWidget();
     background = color;
+    super.setBackground(color);
     super.redraw();
 }
 /**
@@ -6798,7 +6909,7 @@
             location.x -= (caret.getSize().x - 1);
         }
         if (isDefaultCaret) {
-            caret.setBounds(location.x, location.y, 0, caretHeight);
+            caret.setBounds(location.x, location.y, caretWidth, caretHeight);
         } else {
             caret.setLocation(location);
         }
@@ -6852,6 +6963,7 @@
             }
             caretOffset = offset;
         }
+        caretAlignment = PREVIOUS_OFFSET_TRAILING;
         // clear the selection if the caret is moved.
         // don't notify listeners about the selection change.
         clearSelection(false);
@@ -7181,7 +7293,10 @@
 /**
  * Sets the alignment of the specified lines. The argument should be one of <code>DWT.LEFT</code>,
  * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>.
- * <p>
+ * <p><p>
+ * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set
+ * in order to stabilize the right edge before setting alignment.
+ * </p>
  * Should not be called if a LineStyleListener has been set since the listener
  * maintains the line attributes.
  * </p><p>
@@ -7487,7 +7602,7 @@
     if ((orientation & DWT.LEFT_TO_RIGHT) !is 0 && !isMirrored()) {
         return;
     }
-    if (!BidiUtil.setOrientation(handle, orientation)) {
+    if (!BidiUtil.setOrientation(this, orientation)) {
         return;
     }
     isMirrored_ = (orientation & DWT.RIGHT_TO_LEFT) !is 0;
@@ -7705,6 +7820,7 @@
             selectionAnchor = selection.x = start;
             caretOffset = selection.y = end;
         }
+        caretAlignment = PREVIOUS_OFFSET_TRAILING;
         internalRedrawRange(selection.x, selection.y - selection.x);
     }
 }
@@ -8004,12 +8120,8 @@
     checkWidget();
     tabLength = tabs;
     renderer.setFont(null, tabs);
-    if (caretOffset > 0) {
-        caretOffset = 0;
-        showCaret();
-        clearSelection(false);
-    }
     resetCache(0, content.getLineCount());
+    setCaretLocation();
     super.redraw();
 }
 /**
--- a/dwt/custom/StyledTextDropTargetEffect.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/StyledTextDropTargetEffect.d	Mon May 12 19:13:01 2008 +0200
@@ -18,6 +18,8 @@
 import dwt.dnd.DropTargetAdapter;
 import dwt.dnd.DropTargetEffect;
 import dwt.dnd.DropTargetEvent;
+import dwt.graphics.FontMetrics;
+import dwt.graphics.GC;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
 import dwt.widgets.Event;
@@ -30,7 +32,7 @@
 
 /**
  * This adapter class provides a default drag under effect (eg. select and scroll)
- * when a drag occurs over a <code>Table</code>.
+ * when a drag occurs over a <code>StyledText</code>.
  *
  * <p>Classes that wish to provide their own drag under effect for a <code>StyledText</code>
  * can extend this class, override the <code>StyledTextDropTargetEffect.dragOver</code>
@@ -171,37 +173,27 @@
                      pt.y >= scrollY && pt.y <= (scrollY + SCROLL_TOLERANCE))) {
                     if (System.currentTimeMillis() >= scrollBeginTime) {
                         Rectangle area = text.getClientArea();
-                        Rectangle bounds = text.getTextBounds(0, 0);
-                        int charWidth = bounds.width;
+                        GC gc = new GC(text);
+                        FontMetrics fm = gc.getFontMetrics();
+                        gc.dispose();
+                        int charWidth = fm.getAverageCharWidth();
                         int scrollAmount = 10*charWidth;
                         if (pt.x < area.x + 3*charWidth) {
                             int leftPixel = text.getHorizontalPixel();
                             text.setHorizontalPixel(leftPixel - scrollAmount);
-                            if (text.getHorizontalPixel() !is leftPixel) {
-                                text.redraw();
-                            }
                         }
                         if (pt.x > area.width - 3*charWidth) {
                             int leftPixel = text.getHorizontalPixel();
                             text.setHorizontalPixel(leftPixel + scrollAmount);
-                            if (text.getHorizontalPixel() !is leftPixel) {
-                                text.redraw();
-                            }
                         }
-                        int lineHeight = bounds.height;
+                        int lineHeight = text.getLineHeight();
                         if (pt.y < area.y + lineHeight) {
                             int topPixel = text.getTopPixel();
                             text.setTopPixel(topPixel - lineHeight);
-                            if (text.getTopPixel() !is topPixel) {
-                                text.redraw();
-                            }
                         }
                         if (pt.y > area.height - lineHeight) {
                             int topPixel = text.getTopPixel();
                             text.setTopPixel(topPixel + lineHeight);
-                            if (text.getTopPixel() !is topPixel) {
-                                text.redraw();
-                            }
                         }
                         scrollBeginTime = 0;
                         scrollX = scrollY = -1;
@@ -215,53 +207,10 @@
         }
 
         if ((effect & DND.FEEDBACK_SELECT) !is 0) {
-            StyledTextContent content = text.getContent();
-            int newOffset = -1;
-            try {
-                newOffset = text.getOffsetAtLocation(pt);
-            } catch ( tango.core.Exception.IllegalArgumentException ex1) {
-                int maxOffset = content.getCharCount();
-                Point maxLocation = text.getLocationAtOffset(maxOffset);
-                if (pt.y >= maxLocation.y) {
-                    try {
-                        newOffset = text.getOffsetAtLocation(new Point(pt.x, maxLocation.y));
-                    } catch (tango.core.Exception.IllegalArgumentException ex2) {
-                        newOffset = maxOffset;
-                    }
-                } else {
-                    try {
-                        int startOffset = text.getOffsetAtLocation(new Point(0, pt.y));
-                        int endOffset = maxOffset;
-                        int line = content.getLineAtOffset(startOffset);
-                        int lineCount = content.getLineCount();
-                        if (line + 1 < lineCount) {
-                            endOffset = content.getOffsetAtLine(line + 1)  - 1;
-                        }
-                        int lineHeight = text.getLineHeight(startOffset);
-                        for (int i = endOffset; i >= startOffset; i--) {
-                            Point p = text.getLocationAtOffset(i);
-                            if (p.x < pt.x && p.y < pt.y && p.y + lineHeight > pt.y) {
-                                newOffset = i;
-                                break;
-                            }
-                        }
-                    } catch (tango.core.Exception.IllegalArgumentException ex2) {
-                        newOffset = -1;
-                    }
-                }
-            }
-            if (newOffset !is -1 && newOffset !is currentOffset) {
-                // check if offset is line delimiter
-                // see StyledText.isLineDelimiter()
-                int line = content.getLineAtOffset(newOffset);
-                int lineOffset = content.getOffsetAtLine(line);
-                int offsetInLine = newOffset - lineOffset;
-                // offsetInLine will be greater than line length if the line
-                // delimiter is longer than one character and the offset is set
-                // in between parts of the line delimiter.
-                if (offsetInLine > content.getLine(line).length) {
-                    newOffset = Math.max(0, newOffset - 1);
-                }
+            int[] trailing = new int [1];
+            int newOffset = text.getOffsetAtPoint(pt.x, pt.y, trailing, false);
+            newOffset += trailing [0];
+            if (newOffset !is currentOffset) {
                 refreshCaret(text, currentOffset, newOffset);
                 currentOffset = newOffset;
             }
--- a/dwt/custom/StyledTextPrintOptions.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/StyledTextPrintOptions.d	Mon May 12 19:13:01 2008 +0200
@@ -95,5 +95,11 @@
      */
     public bool printLineNumbers = false;
 
+    /**
+     * Labels used for printing line numbers.
+     * 
+     * @since 3.4
+     */
+    public String[] lineLabels = null;
 
 }
--- a/dwt/custom/StyledTextRenderer.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/StyledTextRenderer.d	Mon May 12 19:13:01 2008 +0200
@@ -27,6 +27,7 @@
 import dwt.graphics.TextLayout;
 import dwt.graphics.TextStyle;
 import dwt.widgets.Display;
+import dwt.widgets.IME;
 import dwt.widgets.ScrollBar;
 import dwt.custom.StyledText;
 import dwt.custom.Bullet;
@@ -391,16 +392,19 @@
     int selectionStart = selection.x - lineOffset;
     int selectionEnd = selection.y - lineOffset;
     Rectangle client = styledText.getClientArea();
-    Color lineBackground = getLineBackground(lineIndex, widgetBackground);
+    Color lineBackground = getLineBackground(lineIndex, null);
     StyledTextEvent event = styledText.getLineBackgroundData(lineOffset, line);
     if (event !is null && event.lineBackground !is null) lineBackground = event.lineBackground;
 
     int height = layout.getBounds().height;
-    gc.setBackground(lineBackground);
-    styledText.drawBackground(gc, client.x, paintY, client.width, height);
-
+    if (lineBackground !is null) {
+        gc.setBackground(lineBackground);
+        gc.fillRectangle(client.x, paintY, client.width, height);
+    } else {
+        gc.setBackground(widgetBackground);
+        styledText.drawBackground(gc, client.x, paintY, client.width, height);
+    }
     gc.setForeground(widgetForeground);
-    gc.setBackground(lineBackground);
     if (selectionStart is selectionEnd || (selectionEnd <= 0 && selectionStart > lineLength - 1)) {
         layout.draw(gc, paintX, paintY);
     } else {
@@ -663,8 +667,14 @@
     }
     style = newStyles[newStyles.length - 1];
     if (end < style.start + style.length - 1) {
-        if (!includeRanges || ranges is null) newStyles[newStyles.length - 1] = style = cast(StyleRange)style.clone();
-        style.length = end - style.start + 1;
+        if (end < style.start) {
+            StyleRange[] tmp = new StyleRange[newStyles.length - 1];
+            System.arraycopy(newStyles, 0, tmp, 0, newStyles.length - 1);
+            newStyles = tmp;
+        } else {
+            if (!includeRanges || ranges is null) newStyles[newStyles.length - 1] = style = cast(StyleRange)style.clone();
+            style.length = end - style.start + 1;
+        }
     }
     return newStyles;
 }
@@ -868,6 +878,58 @@
         }
     }
     if (lastOffset < length) layout.setStyle(null, lastOffset, length);
+    if (styledText !is null && styledText.ime !is null) {
+        IME ime = styledText.ime;
+        int compositionOffset = ime.getCompositionOffset();
+        if (compositionOffset !is -1) {
+            int commitCount = ime.getCommitCount();
+            int compositionLength = ime.getText().length;
+            if (compositionLength !is commitCount) {
+                int compositionLine = content.getLineAtOffset(compositionOffset);
+                if (compositionLine is lineIndex) {
+                    int[] imeRanges = ime.getRanges();
+                    TextStyle[] imeStyles = ime.getStyles();
+                    if (imeRanges.length > 0) {
+                        for (int i = 0; i < imeStyles.length; i++) {
+                            int start = imeRanges[i*2] - lineOffset;
+                            int end = imeRanges[i*2+1] - lineOffset;
+                            TextStyle imeStyle = imeStyles[i], userStyle;
+                            for (int j = start; j <= end; j++) {
+                                userStyle = layout.getStyle(j);
+                                if (userStyle is null && j > 0) userStyle = layout.getStyle(j - 1);
+                                if (userStyle is null && j + 1 < length) userStyle = layout.getStyle(j + 1);
+                                if (userStyle is null) {
+                                    layout.setStyle(imeStyle, j, j);
+                                } else {
+                                    TextStyle newStyle = new TextStyle(imeStyle);
+                                    if (newStyle.font is null) newStyle.font = userStyle.font;
+                                    if (newStyle.foreground is null) newStyle.foreground = userStyle.foreground;
+                                    if (newStyle.background is null) newStyle.background = userStyle.background;
+                                    layout.setStyle(newStyle, j, j);
+                                }
+                            }
+                        }
+                    } else {
+                        int start = compositionOffset - lineOffset;
+                        int end = start + compositionLength - 1;
+                        TextStyle userStyle = layout.getStyle(start);
+                        if (userStyle is null) {
+                            if (start > 0) userStyle = layout.getStyle(start - 1);
+                            if (userStyle is null && end + 1 < length) userStyle = layout.getStyle(end + 1);
+                            if (userStyle !is null) {
+                                TextStyle newStyle = new TextStyle();
+                                newStyle.font = userStyle.font;
+                                newStyle.foreground = userStyle.foreground;
+                                newStyle.background = userStyle.background;
+                                layout.setStyle(newStyle, start, end);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     if (styledText !is null && styledText.isFixedLineHeight()) {
         int index = -1;
         int lineCount = layout.getLineCount();
--- a/dwt/custom/TableCursor.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/TableCursor.d	Mon May 12 19:13:01 2008 +0200
@@ -161,6 +161,9 @@
     TableColumn column = null;
     Listener tableListener, resizeListener, disposeItemListener, disposeColumnListener;
 
+    Color background = null;
+    Color foreground = null;
+
     // By default, invert the list selection colors
     static final int BACKGROUND = DWT.COLOR_LIST_SELECTION_TEXT;
     static final int FOREGROUND = DWT.COLOR_LIST_SELECTION;
@@ -254,6 +257,7 @@
 
     disposeItemListener = new class() Listener {
         public void handleEvent(Event event) {
+            unhookRowColumnListeners();
             row = null;
             column = null;
             _resize();
@@ -261,6 +265,7 @@
     };
     disposeColumnListener = new class() Listener {
         public void handleEvent(Event event) {
+            unhookRowColumnListeners();
             row = null;
             column = null;
             _resize();
@@ -320,16 +325,7 @@
 void dispose(Event event) {
     table.removeListener(DWT.FocusIn, tableListener);
     table.removeListener(DWT.MouseDown, tableListener);
-    if (column !is null) {
-        column.removeListener(DWT.Dispose, disposeColumnListener);
-        column.removeListener(DWT.Move, resizeListener);
-        column.removeListener(DWT.Resize, resizeListener);
-        column = null;
-    }
-    if (row !is null) {
-        row.removeListener(DWT.Dispose, disposeItemListener);
-        row = null;
-    }
+    unhookRowColumnListeners();
     ScrollBar hBar = table.getHorizontalBar();
     if (hBar !is null) {
         hBar.removeListener(DWT.Selection, resizeListener);
@@ -493,10 +489,11 @@
 }
 
 void tableFocusIn(Event event) {
-    if (isDisposed())
-        return;
-    if (isVisible())
+    if (isDisposed()) return;
+    if (isVisible()) {
+        if (row is null && column is null) return;
         setFocus();
+    }
 }
 
 void tableMouseDown(Event event) {
@@ -523,7 +520,14 @@
     }
     TableColumn newColumn = null;
     int columnCount = table.getColumnCount();
-    if (columnCount > 0) {
+    if (columnCount is 0) {
+        if ((table.getStyle() & DWT.FULL_SELECTION) is 0) {
+            Rectangle rect = item.getBounds(0);
+            rect.width += lineWidth;
+            rect.height += lineWidth;
+            if (!rect.contains(pt)) return;
+        }
+    } else {
         for (int i = 0; i < columnCount; i++) {
             Rectangle rect = item.getBounds(i);
             rect.width += lineWidth;
@@ -534,6 +538,7 @@
             }
         }
         if (newColumn is null) {
+            if ((table.getStyle() & DWT.FULL_SELECTION) is 0) return;
             newColumn = table.getColumn(0);
         }
     }
@@ -639,6 +644,30 @@
     return column is null ? 0 : table.indexOf(column);
 }
 /**
+ * Returns the background color that the receiver will use to draw.
+ *
+ * @return the receiver's background color
+ */
+public Color getBackground() {
+    checkWidget();
+    if (background is null) {
+        return getDisplay().getSystemColor(BACKGROUND);
+    }
+    return background;
+}
+/**
+ * Returns the foreground color that the receiver will use to draw.
+ *
+ * @return the receiver's foreground color
+ */
+public Color getForeground() {
+    checkWidget();
+    if (foreground is null) {
+        return getDisplay().getSystemColor(FOREGROUND);
+    }
+    return foreground;
+}
+/**
  * Returns the row over which the TableCursor is positioned.
  *
  * @return the item for the current position
@@ -652,14 +681,49 @@
     checkWidget();
     return row;
 }
+/**
+ * Sets the receiver's background color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform.
+ * For example, on Windows the background of a Button cannot be changed.
+ * </p>
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</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>
+ */
 public override void setBackground (Color color) {
-    if (color is null) color = getDisplay().getSystemColor(BACKGROUND);
-    super.setBackground(color);
+    background = color;
+    super.setBackground(getBackground());
     redraw();
 }
+/**
+ * Sets the receiver's foreground color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ * <p>
+ * Note: This operation is a hint and may be overridden by the platform.
+ * </p>
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</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>
+ */
 public override void setForeground (Color color) {
-    if (color is null) color = getDisplay().getSystemColor(FOREGROUND);
-    super.setForeground(color);
+    foreground = color;
+    super.setForeground(getForeground());
     redraw();
 }
 /**
@@ -708,4 +772,16 @@
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     setRowColumn(table.indexOf(row), column, false);
 }
+void unhookRowColumnListeners() {
+    if (column !is null) {
+        column.removeListener(DWT.Dispose, disposeColumnListener);
+        column.removeListener(DWT.Move, resizeListener);
+        column.removeListener(DWT.Resize, resizeListener);
+        column = null;
+    }
+    if (row !is null) {
+        row.removeListener(DWT.Dispose, disposeItemListener);
+        row = null;
+    }
 }
+}
--- a/dwt/custom/TableTreeItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/custom/TableTreeItem.d	Mon May 12 19:13:01 2008 +0200
@@ -206,7 +206,7 @@
         */
         if (parent.sizeImage is null) {
             int itemHeight = parent.getItemHeight();
-            parent.sizeImage = new Image(null, itemHeight, itemHeight);
+            parent.sizeImage = new Image(parent.getDisplay(), itemHeight, itemHeight);
             GC gc = new GC (parent.sizeImage);
             gc.setBackground(parent.getBackground());
             gc.fillRectangle(0, 0, itemHeight, itemHeight);
--- a/dwt/dnd/ClipboardProxy.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/ClipboardProxy.d	Mon May 12 19:13:01 2008 +0200
@@ -144,7 +144,7 @@
     return 1;
 }
 
-bool setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) {
+bool setData(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) { 
     GtkTargetEntry*[] entries;
     GtkTargetEntry* pTargetsList;
     try {
--- a/dwt/dnd/DND.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/DND.d	Mon May 12 19:13:01 2008 +0200
@@ -115,7 +115,7 @@
     /**
      * 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).
+     * happen (user has released the mouse button over this target) (value is 2003).
      */
     public static const int DragLeave   = 2003;
 
@@ -201,6 +201,25 @@
      */
     public static const int ERROR_INVALID_DATA = 2003;
 
+    /**
+     * DropTarget Key: The string constant for looking up the drop target 
+     * for a control using <code>getData(String)</code>. When a drop target 
+     * is created for a control, it is stored as a property in the control 
+     * using <code>setData(String, Object)</code>.
+     * 
+     * @since 3.4
+     */
+    public static final String DROP_TARGET_KEY = "DropTarget"; //$NON-NLS-1$
+    
+    /**
+     * DragSource Key: The string constant for looking up the drag source 
+     * for a control using <code>getData(String)</code>. When a drag source 
+     * is created for a control, it is stored as a property in the control 
+     * using <code>setData(String, Object)</code>.
+     * 
+     * @since 3.4
+     */
+    public static final String DRAG_SOURCE_KEY = "DragSource"; //$NON-NLS-1$
 
     static const String INIT_DRAG_MESSAGE = "Cannot initialize Drag"; //$NON-NLS-1$
     static const String INIT_DROP_MESSAGE = "Cannot initialize Drop"; //$NON-NLS-1$
--- a/dwt/dnd/DragSource.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/DragSource.d	Mon May 12 19:13:01 2008 +0200
@@ -130,7 +130,6 @@
     bool moveData = false;
 
     static const String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$
-    static const String DRAGSOURCEID = "DragSource"; //$NON-NLS-1$
 
 //     static Callback DragGetData;
 //     static Callback DragEnd;
@@ -179,10 +178,10 @@
 //     if (DragGetData is null || DragEnd is null || DragDataDelete is null) {
 //         DND.error(DND.ERROR_CANNOT_INIT_DRAG);
 //     }
-    if (control.getData(DRAGSOURCEID) !is null) {
+    if (control.getData(DND.DRAG_SOURCE_KEY) !is null) {
         DND.error(DND.ERROR_CANNOT_INIT_DRAG);
     }
-    control.setData(DRAGSOURCEID, this);
+    control.setData(DND.DRAG_SOURCE_KEY, 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);
@@ -267,7 +266,7 @@
     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);
+    return cast(DragSource)widget.getData(DND.DRAG_SOURCE_KEY);
 }
 
 /**
@@ -432,6 +431,41 @@
 }
 
 /**
+ * Returns an array 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.
+ *
+ * @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
+ * @see #removeDragListener
+ * @see DragSourceEvent
+ *
+ * @since 3.4
+ */
+public DragSourceListener[] getDragListeners() {
+    Listener[] listeners = getListeners(DND.DragStart);
+    int length = listeners.length;
+    DragSourceListener[] dragListeners = new DragSourceListener[length];
+    int count = 0;
+    for (int i = 0; i < length; i++) {
+        Listener listener = listeners[i];
+        if ( auto l = cast(DNDListener)listener ) {
+            dragListeners[count] = cast(DragSourceListener) (l.getEventListener());
+            count++;
+        }
+    }
+    if (count is length) return dragListeners;
+    DragSourceListener[] result = new DragSourceListener[count];
+    SimpleType!(DragSourceListener).arraycopy(dragListeners, 0, result, 0, count);
+    return result;
+}
+
+/**
  * Returns the drag effect that is registered for this DragSource.  This drag
  * effect will be used during a drag and drop operation.
  *
@@ -463,7 +497,7 @@
         control.removeListener(DWT.DragDetect, controlListener);
     }
     controlListener = null;
-    control.setData(DRAGSOURCEID, null);
+    control.setData(DND.DRAG_SOURCE_KEY, null);
     control = null;
     transferAgents = null;
 }
--- a/dwt/dnd/DropTarget.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/DropTarget.d	Mon May 12 19:13:01 2008 +0200
@@ -19,6 +19,7 @@
 import dwt.DWTException;
 import dwt.graphics.Point;
 import dwt.internal.gtk.OS;
+import dwt.widgets.Combo;
 import dwt.widgets.Control;
 import dwt.widgets.Display;
 import dwt.widgets.Event;
@@ -117,7 +118,6 @@
     int drag_drop_handler;
 
     static const String DEFAULT_DROP_TARGET_EFFECT = "DEFAULT_DROP_TARGET_EFFECT"; //$NON-NLS-1$
-    static const String DROPTARGETID = "DropTarget"; //$NON-NLS-1$
     static const int DRAGOVER_HYSTERESIS = 50;
 
 //     static Callback Drag_Motion;
@@ -173,10 +173,10 @@
 //     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) {
+    if (control.getData(DND.DROP_TARGET_KEY) !is null) {
         DND.error(DND.ERROR_CANNOT_INIT_DROP);
     }
-    control.setData(DROPTARGETID, this);
+    control.setData(DND.DROP_TARGET_KEY, 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);
@@ -321,7 +321,7 @@
     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);
+    return cast(DropTarget)widget.getData(DND.DROP_TARGET_KEY);
 }
 
 /**
@@ -579,6 +579,41 @@
 }
 
 /**
+ * Returns an array 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.
+ *
+ * @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
+ * @see #removeDropListener
+ * @see DropTargetEvent
+ *
+ * @since 3.4
+ */
+public DropTargetListener[] getDropListeners() {
+    Listener[] listeners = getListeners(DND.DragEnter);
+    int length = listeners.length;
+    DropTargetListener[] dropListeners = new DropTargetListener[length];
+    int count = 0;
+    for (int i = 0; i < length; i++) {
+        Listener listener = listeners[i];
+        if ( auto l = cast(DNDListener)listener ) {
+            dropListeners[count] = cast(DropTargetListener) (l.getEventListener());
+            count++;
+        }
+    }
+    if (count is length) return dropListeners;
+    DropTargetListener[] result = new DropTargetListener[count];
+    SimpleType!(DropTargetListener).arraycopy(dropListeners, 0, result, 0, count);
+    return result;
+}
+
+/**
  * 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.
@@ -622,7 +657,7 @@
     transferAgents = null;
     if (controlListener !is null)
         control.removeListener(DWT.Dispose, controlListener);
-    control.setData(DROPTARGETID, null);
+    control.setData(DND.DROP_TARGET_KEY, null);
     control = null;
     controlListener = null;
 }
@@ -723,6 +758,14 @@
     }
 
     int actions = opToOsOp(getStyle());
+    if ( auto c = cast(Combo)control ) {
+        if ((control.getStyle() & DWT.READ_ONLY) is 0) {
+            auto entryHandle = OS.gtk_bin_get_child (control.handle);
+            if (entryHandle !is null) {
+                OS.gtk_drag_dest_unset(entryHandle);
+            }
+        }
+    }
     OS.gtk_drag_dest_set(control.handle, 0, pTargets, targets.length, actions);
 
     for (int i = 0; i < targets.length; i++) {
--- a/dwt/dnd/DropTargetEffect.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/DropTargetEffect.d	Mon May 12 19:13:01 2008 +0200
@@ -17,8 +17,8 @@
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
 import dwt.widgets.Control;
-import dwt.widgets.Item;
 import dwt.widgets.Table;
+import dwt.widgets.TableItem;
 import dwt.widgets.Tree;
 import dwt.widgets.TreeItem;
 import dwt.widgets.Widget;
@@ -107,38 +107,39 @@
     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;
-                    }
-                }
-            }
+        TableItem item = table.getItem(coordinates);
+        if (item !is null) return item;
+        Rectangle area = table.getClientArea();
+        int tableBottom = area.y + area.height;
+        int itemCount = table.getItemCount();
+        for (int i=table.getTopIndex(); i<itemCount; i++) {
+            item = table.getItem(i);
+            Rectangle rect = item.getBounds();
+            rect.x = area.x;
+            rect.width = area.width;
+            if (rect.contains(coordinates)) return item;
+            if (rect.y > tableBottom) break;
         }
-        return item;
+        return null;
     }
 
     Widget getItem(Tree tree, int x, int y) {
-        Point coordinates = new Point(x, y);
-        coordinates = tree.toControl(coordinates);
-        Item item = tree.getItem(coordinates);
+        Point point = new Point(x, y);
+        point = tree.toControl(point);
+        TreeItem item = tree.getItem(point);
         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;
-                    }
+            if (area.contains(point)) {
+                int treeBottom = area.y + area.height;
+                item = tree.getTopItem();
+                while (item !is null) {
+                    Rectangle rect = item.getBounds();
+                    int itemBottom = rect.y + rect.height;
+                    if (rect.y <= point.y && point.y < itemBottom) return item;
+                    if (itemBottom > treeBottom) break;
+                    item = nextItem(tree, item);
                 }
+                return null;
             }
         }
         return item;
@@ -146,7 +147,7 @@
 
     TreeItem nextItem(Tree tree, TreeItem item) {
         if (item is null) return null;
-        if (item.getExpanded()) return item.getItem(0);
+        if (item.getExpanded() && item.getItemCount() > 0) return item.getItem(0);
         TreeItem childItem = item;
         TreeItem parentItem = childItem.getParentItem();
         int index = parentItem is null ? tree.indexOf(childItem) : parentItem.indexOf(childItem);
--- a/dwt/dnd/FileTransfer.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/FileTransfer.d	Mon May 12 19:13:01 2008 +0200
@@ -84,7 +84,7 @@
         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);
+        auto localePtr = OS.g_filename_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);
@@ -159,7 +159,7 @@
         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);
+        auto utf8Ptr = OS.g_filename_to_utf8(localePtr, -1, null, null, &error);
         OS.g_free(localePtr);
         if (error !is null || utf8Ptr is null) continue;
         String buffer = tango.stdc.stringz.fromStringz( utf8Ptr ).dup;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/ImageTransfer.d	Mon May 12 19:13:01 2008 +0200
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * 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.ImageTransfer;
+
+import dwt.DWT;
+import dwt.graphics.Image;
+import dwt.graphics.ImageData;
+import dwt.internal.Converter;
+import dwt.internal.gtk.OS;
+import dwt.widgets.Display;
+import dwt.dnd.ByteArrayTransfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+
+import dwt.dwthelper.utils;
+
+/**
+ * The class <code>ImageTransfer</code> provides a platform specific mechanism
+ * for converting a Image represented as a java <code>ImageData</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>ImageData</code> is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     Image image = new Image("C:\temp\img1.gif");
+ *     ImageData imgData = image.getImageData();
+ * </code></pre>
+ */
+public class ImageTransfer : ByteArrayTransfer {
+
+    private static ImageTransfer _instance;
+
+    private static const String JPEG = "image/jpge"; //$NON-NLS-1$
+    private static int JPEG_ID;
+    private static const String PNG = "image/png"; //$NON-NLS-1$
+    private static int PNG_ID;
+    private static const String BMP = "image/bmp"; //$NON-NLS-1$
+    private static int BMP_ID;
+    private static const String EPS = "image/eps"; //$NON-NLS-1$
+    private static int EPS_ID;
+    private static const String PCX = "image/pcx"; //$NON-NLS-1$
+    private static int PCX_ID;
+    private static const String PPM = "image/ppm"; //$NON-NLS-1$
+    private static int PPM_ID;
+    private static const String RGB = "image/ppm"; //$NON-NLS-1$
+    private static int RGB_ID;
+    private static const String TGA = "image/tga"; //$NON-NLS-1$
+    private static int TGA_ID;
+    private static const String XBM = "image/xbm"; //$NON-NLS-1$
+    private static int XBM_ID;
+    private static const String XPM = "image/xpm"; //$NON-NLS-1$
+    private static int XPM_ID;
+    private static const String XV = "image/xv"; //$NON-NLS-1$
+    private static int XV_ID;
+
+static this(){
+    JPEG_ID = registerType(JPEG);
+    PNG_ID = registerType(PNG);
+    BMP_ID = registerType(BMP);
+    EPS_ID = registerType(EPS);
+    PCX_ID = registerType(PCX);
+    PPM_ID = registerType(PPM);
+    RGB_ID = registerType(RGB);
+    TGA_ID = registerType(TGA);
+    XBM_ID = registerType(XBM);
+    XPM_ID = registerType(XPM);
+    XV_ID = registerType(XV);
+    _instance = new ImageTransfer();
+}
+
+private this() {
+}
+
+/**
+ * Returns the singleton instance of the ImageTransfer class.
+ *
+ * @return the singleton instance of the ImageTransfer class
+ */
+public static ImageTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts an ImageData object represented
+ * by java <code>ImageData</code> to a platform specific representation.
+ * For additional information see <code>Transfer#javaToNative</code>.
+ *
+ * @param object a java <code>ImageData</code> containing the ImageData 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) {
+    if (!checkImage(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    if (OS.GTK_VERSION < OS.buildVERSION (2, 4, 0)) return;
+
+    ImageData imgData = cast(ImageData)object;
+    if (imgData is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    Image image = new Image(Display.getCurrent(), imgData);
+    auto pixmap = image.pixmap;
+    int width = imgData.width;
+    int height = imgData.height;
+    auto pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, true, 8, width, height);
+    if (pixbuf is null) DWT.error(DWT.ERROR_NO_HANDLES);
+    auto colormap = OS.gdk_colormap_get_system();
+    OS.gdk_pixbuf_get_from_drawable(pixbuf, pixmap, colormap, 0, 0, 0, 0, width, height);
+
+    String typeStr = "";
+    if (transferData.type is  cast(void*)JPEG_ID) typeStr = "jpeg";
+    if (transferData.type is  cast(void*)PNG_ID) typeStr = "png";
+    if (transferData.type is  cast(void*)BMP_ID) typeStr = "bmp";
+    if (transferData.type is  cast(void*)EPS_ID) typeStr = "eps";
+    if (transferData.type is  cast(void*)PCX_ID) typeStr = "pcx";
+    if (transferData.type is  cast(void*)PPM_ID) typeStr = "ppm";
+    if (transferData.type is  cast(void*)RGB_ID) typeStr = "rgb";
+    if (transferData.type is  cast(void*)TGA_ID) typeStr = "tga";
+    if (transferData.type is  cast(void*)XBM_ID) typeStr = "xbm";
+    if (transferData.type is  cast(void*)XPM_ID) typeStr = "xpm";
+    if (transferData.type is  cast(void*)XV_ID) typeStr = "xv";
+    char* type = typeStr.ptr;
+    char* buffer;
+    uint len;
+    if (type is null) return;
+    OS.gdk_pixbuf_save_to_buffer0(pixbuf, &buffer, &len, type, null);
+    OS.g_object_unref(pixbuf);
+    image.dispose();
+    transferData.pValue = buffer;
+    transferData.length = (len + 3) / 4 * 4;
+    transferData.result = 1;
+    transferData.format = 32;
+}
+
+/**
+ * This implementation of <code>nativeToJava</code> converts a platform specific
+ * representation of an <code>ImageData</code> to java.
+ * 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>ImageData</code> the imageData of the image if
+ * conversion was successful; otherwise null
+ */
+public Object nativeToJava(TransferData transferData) {
+    ImageData imgData = null;
+    if (transferData.length > 0)
+    {
+        auto loader = OS.gdk_pixbuf_loader_new();
+        OS.gdk_pixbuf_loader_write(loader, transferData.pValue, transferData.length, null);
+        OS.gdk_pixbuf_loader_close(loader, null);
+        auto pixbuf = OS.gdk_pixbuf_loader_get_pixbuf(loader);
+        if (pixbuf !is null) {
+            OS.g_object_ref(pixbuf);
+            GdkPixmap* pixmap_return;
+            OS.gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap_return, null, 0);
+            auto handle = pixmap_return;
+            if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
+            OS.g_object_unref(loader);
+            Image img = Image.gtk_new(Display.getCurrent(), DWT.BITMAP, handle, null);
+            imgData = img.getImageData();
+            img.dispose();
+        }
+    }
+    return imgData;
+}
+
+protected int[] getTypeIds(){
+    return [JPEG_ID, PNG_ID, BMP_ID, EPS_ID, PCX_ID, PPM_ID, RGB_ID, TGA_ID, XBM_ID, XPM_ID, XV_ID];
+}
+
+protected String[] getTypeNames(){
+    return [JPEG, PNG, BMP, EPS, PCX, PPM, RGB, TGA, XBM, XPM, XV];
+}
+
+bool checkImage(Object object) {
+    if (object is null || !( null !is cast(ImageData)object )) return false;
+    return true;
+}
+
+protected bool validate(Object object) {
+    return checkImage(object);
+}
+}
--- a/dwt/dnd/TableDragSourceEffect.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/TableDragSourceEffect.d	Mon May 12 19:13:01 2008 +0200
@@ -88,6 +88,8 @@
 
         Table table = cast(Table) control;
         if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) return null;
+        //TEMPORARY CODE
+        if (table.isListening(DWT.EraseItem) || table.isListening (DWT.PaintItem)) 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
--- a/dwt/dnd/TableDropTargetEffect.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/TableDropTargetEffect.d	Mon May 12 19:13:01 2008 +0200
@@ -110,7 +110,7 @@
     public override void dragLeave(DropTargetEvent event) {
         Table table = cast(Table) control;
         auto handle = table.handle;
-        OS.gtk_tree_view_unset_rows_drag_dest(handle);
+        OS.gtk_tree_view_set_drag_dest_row(handle, null, OS.GTK_TREE_VIEW_DROP_BEFORE);
 
         scrollBeginTime = 0;
         scrollIndex = -1;
@@ -181,10 +181,10 @@
             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);
+                OS.gtk_tree_view_set_drag_dest_row(handle, null, OS.GTK_TREE_VIEW_DROP_BEFORE);
             }
         } else {
-            OS.gtk_tree_view_unset_rows_drag_dest(handle);
+            OS.gtk_tree_view_set_drag_dest_row(handle, null, OS.GTK_TREE_VIEW_DROP_BEFORE);
         }
         if (path !is null) OS.gtk_tree_path_free (path );
     }
--- a/dwt/dnd/TransferData.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/TransferData.d	Mon May 12 19:13:01 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * 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
--- a/dwt/dnd/TreeDragSourceEffect.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/TreeDragSourceEffect.d	Mon May 12 19:13:01 2008 +0200
@@ -87,6 +87,8 @@
 
         Tree tree = cast(Tree) control;
         if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) return null;
+        //TEMPORARY CODE
+        if (tree.isListening(DWT.EraseItem) || tree.isListening (DWT.PaintItem)) 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
--- a/dwt/dnd/TreeDropTargetEffect.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/dnd/TreeDropTargetEffect.d	Mon May 12 19:13:01 2008 +0200
@@ -118,7 +118,7 @@
     public override void dragLeave(DropTargetEvent event) {
         Tree tree = cast(Tree) control;
         auto handle = tree.handle;
-        OS.gtk_tree_view_unset_rows_drag_dest(handle);
+        OS.gtk_tree_view_set_drag_dest_row(handle, null, OS.GTK_TREE_VIEW_DROP_BEFORE);
 
         scrollBeginTime = 0;
         scrollIndex = -1;
@@ -214,10 +214,10 @@
             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);
+                OS.gtk_tree_view_set_drag_dest_row(handle, null, OS.GTK_TREE_VIEW_DROP_BEFORE);
             }
         } else {
-            OS.gtk_tree_view_unset_rows_drag_dest(handle);
+            OS.gtk_tree_view_set_drag_dest_row(handle, null, OS.GTK_TREE_VIEW_DROP_BEFORE);
         }
 
         if (path !is null) OS.gtk_tree_path_free (path );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/dnd/URLTransfer.d	Mon May 12 19:13:01 2008 +0200
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * 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.URLTransfer;
+
+import dwt.internal.gtk.OS;
+
+import dwt.dnd.ByteArrayTransfer;
+import dwt.dnd.TransferData;
+import dwt.dnd.DND;
+
+import dwt.dwthelper.utils;
+
+/**
+ * The class <code>URLTransfer</code> provides a platform specific mechanism
+ * for converting text in URL 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. The string
+ * must be a fully specified url.
+ *
+ * <p>An example of a java <code>String[]</code> containing a URL is shown
+ * below:</p>
+ *
+ * <code><pre>
+ *     String urlData = "http://www.eclipse.org";
+ * </code></pre>
+ */
+public class URLTransfer : ByteArrayTransfer {
+
+    static URLTransfer _instance;
+    private static const String TEXT_UNICODE = "text/unicode"; //$NON-NLS-1$
+    private static const String TEXT_XMOZURL = "text/x-moz-url"; //$NON-NLS-1$
+    private static int TEXT_UNICODE_ID;
+    private static int TEXT_XMOZURL_ID;
+
+static this(){
+    TEXT_UNICODE_ID = registerType(TEXT_UNICODE);
+    TEXT_XMOZURL_ID = registerType(TEXT_XMOZURL);
+    _instance = new URLTransfer();
+}
+
+private this() {}
+
+/**
+ * Returns the singleton instance of the URLTransfer class.
+ *
+ * @return the singleton instance of the URLTransfer class
+ */
+public static URLTransfer getInstance () {
+    return _instance;
+}
+
+/**
+ * This implementation of <code>javaToNative</code> converts a URL
+ * 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 a URL
+ * @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 (!checkURL(object) || !isSupportedType(transferData)) {
+        DND.error(DND.ERROR_INVALID_DATA);
+    }
+    String 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 a URL <code>String</code>.
+ * For additional information see <code>Transfer#nativeToJava</code>.
+ *
+ * @param transferData the platform specific representation of the data to be
+ * converted
+ * @return a java <code>String</code> containing a URL 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 <= 0) return null;
+    String string = tango.stdc.stringz.fromStringz(cast(char*)transferData.pValue).dup;
+    int end = string.indexOf('\0');
+    return new ArrayWrapperString((end is -1) ? string : string.substring(0, end));
+}
+
+protected int[] getTypeIds(){
+    return [TEXT_XMOZURL_ID, TEXT_UNICODE_ID];
+}
+
+protected String[] getTypeNames(){
+    return [TEXT_XMOZURL, TEXT_UNICODE];
+}
+
+bool checkURL(Object object) {
+    return object !is null && (null !is cast(ArrayWrapperString)object) && (cast(ArrayWrapperString)object).array.length > 0;
+}
+
+protected bool validate(Object object) {
+    return checkURL(object);
+}
+}
--- a/dwt/graphics/Color.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Color.d	Mon May 12 19:13:01 2008 +0200
@@ -39,6 +39,7 @@
  * @see Device#getSystemColor
  */
 public final class Color : Resource {
+    alias Resource.init_ init_;
     /**
      * the handle to the OS color resource
      * (Warning: This field is platform dependent)
@@ -51,7 +52,8 @@
      */
     public GdkColor* handle;
 
-this() {
+this(Device device) {
+    super(device);
 }
 
 /**
@@ -79,10 +81,9 @@
  * @see #dispose
  */
 public this(Device device, int red, int green, int blue) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, red, green, blue);
-    if (device.tracking) device.new_Object(this);
+    super(device);
+    init_(red, green, blue);
+    init_();
 }
 
 /**
@@ -108,21 +109,13 @@
  * @see #dispose
  */
 public this(Device device, RGB rgb) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (rgb is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, rgb.red, rgb.green, rgb.blue);
-    if (device.tracking) device.new_Object(this);
+    init_(rgb.red, rgb.green, rgb.blue);
+    init_();
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the color. Applications must dispose of all colors which
- * they allocate.
- */
-public override void dispose() {
-    if (handle is null) return;
-    if (device.isDisposed()) return;
+void destroy() {
     int pixel = handle.pixel;
     if (device.colorRefCount !is null) {
         /* If this was the last reference, remove the color from the list */
@@ -133,8 +126,6 @@
     auto colormap = OS.gdk_colormap_get_system();
     OS.gdk_colormap_free_colors(colormap, handle, 1);
     handle = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
 }
 
 /**
@@ -245,15 +236,12 @@
  * @private
  */
 public static Color gtk_new(Device device, GdkColor* gdkColor) {
-    if (device is null) device = Device.getDevice();
-    Color color = new Color();
+    Color color = new Color(device);
     color.handle = gdkColor;
-    color.device = device;
     return color;
 }
 
-void init_(Device device, int red, int green, int blue) {
-    this.device = device;
+void init_(int red, int green, int blue) {
     if ((red > 255) || (red < 0) ||
         (green > 255) || (green < 0) ||
         (blue > 255) || (blue < 0)) {
--- a/dwt/graphics/Cursor.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Cursor.d	Mon May 12 19:13:01 2008 +0200
@@ -90,7 +90,8 @@
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
 
-this () {
+this (Device device) {
+    super(device);
 }
 
 /**
@@ -135,9 +136,7 @@
  * @see DWT#CURSOR_HAND
  */
 public this(Device device, int style) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
+    super(device);
     int shape = 0;
     switch (style) {
         case DWT.CURSOR_APPSTARTING:    break;
@@ -171,7 +170,7 @@
         handle = OS.gdk_cursor_new(shape);
     }
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
 /**
@@ -206,9 +205,7 @@
  * </ul>
  */
 public this(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
+    super(device);
     if (source is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (mask is null) {
         if (!(source.getTransparencyType() is DWT.TRANSPARENCY_MASK)) DWT.error(DWT.ERROR_NULL_ARGUMENT);
@@ -260,7 +257,7 @@
     maskData = ImageData.convertPad(maskData, mask.width, mask.height, mask.depth, mask.scanlinePad, 1);
     handle = createCursor(maskData, sourceData, source.width, source.height, hotspotX, hotspotY, true);
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
 /**
@@ -291,9 +288,7 @@
  * @since 3.0
  */
 public this(Device device, ImageData source, int hotspotX, int hotspotY) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
+    super(device);
     if (source is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (hotspotX >= source.width || hotspotX < 0 ||
         hotspotY >= source.height || hotspotY < 0) {
@@ -438,7 +433,7 @@
         handle = createCursor(sourceData, maskData, source.width, source.height, hotspotX, hotspotY, false);
     }
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
 GdkCursor* createCursor(byte[] sourceData, byte[] maskData, int width, int height, int hotspotX, int hotspotY, bool reverse) {
@@ -457,18 +452,9 @@
     return cursor;
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the cursor. Applications must dispose of all cursors which
- * they allocate.
- */
-public override void dispose() {
-    if (handle is null) return;
-    if (device.isDisposed()) return;
+void destroy() {
     OS.gdk_cursor_destroy(handle);
     handle = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
 }
 
 /**
@@ -505,10 +491,8 @@
  * @private
  */
 public static Cursor gtk_new(Device device, GdkCursor* handle) {
-    if (device is null) device = Device.getDevice();
-    Cursor cursor = new Cursor();
+    Cursor cursor = new Cursor(device);
     cursor.handle = handle;
-    cursor.device = device;
     return cursor;
 }
 
--- a/dwt/graphics/Device.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Device.d	Mon May 12 19:13:01 2008 +0200
@@ -57,6 +57,7 @@
     bool tracking;
     Exception [] errors;
     Object [] objects;
+    Object trackingLock;
 
     /* Colormap and reference count */
     GdkColor *[] gdkColors;
@@ -99,8 +100,6 @@
 
     static bool CAIRO_LOADED;
 
-//    static Object CREATE_LOCK;
-
     /*
     * TEMPORARY CODE. When a graphics object is
     * created and the device parameter is null,
@@ -157,7 +156,6 @@
  * @see #init
  * @see DeviceData
  */
-
 public this(DeviceData data) {
     handler_ids = new int [log_domains.length];
     debugging = DEBUG;
@@ -171,13 +169,11 @@
         if (tracking) {
             errors = new Exception [128];
             objects = new Object [128];
+            trackingLock = new Object ();
         }
         create (data);
         init_ ();
         register (this);
-
-        /* Initialize the system font slot */
-        systemFont = getSystemFont ();
     }
 }
 
@@ -236,25 +232,32 @@
  * @see #checkDevice
  */
 public void dispose () {
-    if (isDisposed()) return;
-    checkDevice ();
-    release ();
-    destroy ();
-    deregister (this);
-    xDisplay = null;
-    disposed = true;
-    if (tracking) {
-        objects = null;
-        errors = null;
+    synchronized (Device.classinfo) {
+        if (isDisposed()) return;
+        checkDevice ();
+        release ();
+        destroy ();
+        deregister (this);
+        xDisplay = null;
+        disposed = true;
+        if (tracking) {
+            synchronized (trackingLock) {
+                objects = null;
+                errors = null;
+                trackingLock = null;
+            }
+        }
     }
 }
 
 void dispose_Object (Object object) {
-    for (int i=0; i<objects.length; i++) {
-        if (objects [i] is object) {
-            objects [i] = null;
-            errors [i] = null;
-            return;
+    synchronized (trackingLock) {
+        for (int i=0; i<objects.length; i++) {
+            if (objects [i] is object) {
+                objects [i] = null;
+                errors [i] = null;
+                return;
+            }
         }
     }
 }
@@ -324,20 +327,26 @@
     DeviceData data = new DeviceData ();
     data.debugging = debugging;
     data.tracking = tracking;
-    int count = 0, length = 0;
-    if (tracking) length = objects.length;
-    for (int i=0; i<length; i++) {
-        if (objects [i] !is null) count++;
-    }
-    int index = 0;
-    data.objects = new Object [count];
-    data.errors = new Exception [count];
-    for (int i=0; i<length; i++) {
-        if (objects [i] !is null) {
-            data.objects [index] = objects [i];
-            data.errors [index] = errors [i];
-            index++;
+    if (tracking) {
+        synchronized (trackingLock) {
+            int count = 0, length = objects.length;
+            for (int i=0; i<length; i++) {
+                if (objects [i] !is null) count++;
+            }
+            int index = 0;
+            data.objects = new Object [count];
+            data.errors = new Exception [count];
+            for (int i=0; i<length; i++) {
+                if (objects [i] !is null) {
+                    data.objects [index] = objects [i];
+                    data.errors [index] = errors [i];
+                    index++;
+                }
+            }
         }
+    } else {
+        data.objects = null;
+        data.errors = null;
     }
     return data;
 }
@@ -611,6 +620,9 @@
     shellHandle = OS.gtk_window_new(OS.GTK_WINDOW_TOPLEVEL);
     if (shellHandle is null) DWT.error(DWT.ERROR_NO_HANDLES);
     OS.gtk_widget_realize(shellHandle);
+
+    /* Initialize the system font slot */
+    systemFont = getSystemFont ();
 }
 
 /**
@@ -654,7 +666,9 @@
  * @return <code>true</code> when the device is disposed and <code>false</code> otherwise
  */
 public bool isDisposed () {
-    return disposed;
+    synchronized (Device.classinfo) {
+        return disposed;
+    }
 }
 
 /**
@@ -693,21 +707,23 @@
 }
 
 void new_Object (Object object) {
-    for (int i=0; i<objects.length; i++) {
-        if (objects [i] is null) {
-            objects [i] = object;
-            errors [i] = new Exception ("");
-            return;
+    synchronized (trackingLock) {
+        for (int i=0; i<objects.length; i++) {
+            if (objects [i] is null) {
+                objects [i] = object;
+                errors [i] = new Exception ("");
+                return;
+            }
         }
+        Object [] newObjects = new Object [objects.length + 128];
+        System.arraycopy (objects, 0, newObjects, 0, objects.length);
+        newObjects [objects.length] = object;
+        objects = newObjects;
+        Exception [] newErrors = new Exception [errors.length + 128];
+        System.arraycopy (errors, 0, newErrors, 0, errors.length);
+        newErrors [errors.length] = new Exception ("");
+        errors = newErrors;
     }
-    Object [] newObjects = new Object [objects.length + 128];
-    System.arraycopy (objects, 0, newObjects, 0, objects.length);
-    newObjects [objects.length] = object;
-    objects = newObjects;
-    Exception [] newErrors = new Exception [errors.length + 128];
-    System.arraycopy (errors, 0, newErrors, 0, errors.length);
-    newErrors [errors.length] = new Exception ("");
-    errors = newErrors;
 }
 
 static synchronized void register (Device device) {
--- a/dwt/graphics/Font.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Font.d	Mon May 12 19:13:01 2008 +0200
@@ -39,6 +39,8 @@
  * @see FontData
  */
 public final class Font : Resource {
+
+    alias Resource.init_ init_;
     /**
      * the handle to the OS font resource
      * (Warning: This field is platform dependent)
@@ -51,7 +53,8 @@
      */
     public PangoFontDescription* handle;
 
-this() {
+this(Device device) {
+    super(device);
 }
 
 /**
@@ -73,11 +76,10 @@
  * </ul>
  */
 public this(Device device, FontData fd) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (fd is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, fd.getName(), fd.getHeightF(), fd.getStyle(), fd.str);
-    if (device.tracking) device.new_Object(this);
+    init_(fd.getName(), fd.getHeightF(), fd.getStyle(), fd.str);
+    init_();
 }
 
 /**
@@ -104,16 +106,15 @@
  * @since 2.1
  */
 public this(Device device, FontData[] fds) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (fds is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (fds.length is 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     for (int i=0; i<fds.length; i++) {
         if (fds[i] is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
     FontData fd = fds[0];
-    init_(device,fd.getName(), fd.getHeightF(), fd.getStyle(), fd.str);
-    if (device.tracking) device.new_Object(this);
+    init_(fd.getName(), fd.getHeightF(), fd.getStyle(), fd.str);
+    init_();
 }
 
 /**
@@ -139,31 +140,20 @@
  * </ul>
  */
 public this(Device device, String name, int height, int style) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, name, height, style, null);
-    if (device.tracking) device.new_Object(this);
+    super(device);
+    init_(name, height, style, null);
+    init_();
 }
 
 /*public*/ this(Device device, String name, float height, int style) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, name, height, style, null);
-    if (device.tracking) device.new_Object(this);
+    super(device);
+    init_(name, height, style, null);
+    init_();
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the font. Applications must dispose of all fonts which
- * they allocate.
- */
-public override void dispose() {
-    if (handle is null ) return;
-    if (device.isDisposed()) return;
+void destroy() {
     OS.pango_font_description_free(handle);
     handle = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
 }
 
 /**
@@ -233,10 +223,8 @@
  * @private
  */
 public static Font gtk_new(Device device, PangoFontDescription* handle) {
-    if (device is null) device = Device.getDevice();
-    Font font = new Font();
+    Font font = new Font(device);
     font.handle = handle;
-    font.device = device;
     return font;
 }
 
@@ -254,10 +242,9 @@
     return cast(hash_t)/*64*/handle;
 }
 
-void init_(Device device, String name, float height, int style, String fontString) {
+void init_(String name, float height, int style, char[] fontString) {
     if (name is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (height < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    this.device = device;
     if (fontString !is null) {
         handle = OS.pango_font_description_from_string (toStringz(fontString));
         if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
@@ -266,7 +253,9 @@
         if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
         //byte[] buffer = Converter.wcsToMbcs(null, name, true);
         OS.pango_font_description_set_family(handle, toStringz(name) );
-        OS.pango_font_description_set_size(handle, cast(int)(0.5f + height * OS.PANGO_SCALE));
+        if (height > 0) {
+            OS.pango_font_description_set_size(handle, cast(int)(0.5f + height * OS.PANGO_SCALE));
+        }
         OS.pango_font_description_set_stretch(handle, OS.PANGO_STRETCH_NORMAL);
         int pangoStyle = OS.PANGO_STYLE_NORMAL;
         int pangoWeight = OS.PANGO_WEIGHT_NORMAL;
--- a/dwt/graphics/GC.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/GC.d	Mon May 12 19:13:01 2008 +0200
@@ -78,6 +78,9 @@
  * @see dwt.events.PaintEvent
  */
 public final class GC : Resource {
+
+    alias Resource.init_ init_;
+
     /**
      * the handle to the OS device context
      * (Warning: This field is platform dependent)
@@ -180,8 +183,8 @@
     if (device is null) device = Device.getDevice();
     if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     this.device = data.device = device;
-    init(drawable, data, gdkGC);
-    if (device.tracking) device.new_Object(this);
+    init_(drawable, data, gdkGC);
+    init_();
 }
 
 static void addCairoString(cairo_t* cairo, String str, float x, float y, Font font) {
@@ -191,7 +194,11 @@
         if (layout is null) DWT.error(DWT.ERROR_NO_HANDLES);
         OS.pango_layout_set_text(layout, buffer, -1);
         OS.pango_layout_set_font_description(layout, font.handle);
-        Cairo.cairo_move_to(cairo, x, y);
+        double currentX, currentY;
+        Cairo.cairo_get_current_point(cairo, &currentX, &currentY);
+        if (currentX !is x || currentY !is y) {
+            Cairo.cairo_move_to(cairo, x, y);
+        }
         OS.pango_cairo_layout_path(cairo, layout);
         OS.g_object_unref(layout);
     } else {
@@ -209,11 +216,18 @@
     return style & (DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT);
 }
 
+public static GC gtk_new(GdkGC* handle, GCData data) {
+    GC gc = new GC();
+    gc.device = data.device;
+    gc.init_(null, data, handle);
+    return gc;
+}
+
 public static GC gtk_new(Drawable drawable, GCData data) {
     GC gc = new GC();
     auto gdkGC = drawable.internal_new_GC(data);
     gc.device = data.device;
-    gc.init(drawable, data, gdkGC);
+    gc.init_(drawable, data, gdkGC);
     return gc;
 }
 
@@ -237,14 +251,25 @@
                 data.state &= ~FOREGROUND;
             }
             if  (pattern !is null) {
-                Cairo.cairo_set_source(cairo, pattern.handle);
+                if ((data.style & DWT.MIRRORED) !is 0 && pattern.surface !is null) {
+                    auto newPattern = Cairo.cairo_pattern_create_for_surface(pattern.surface);
+                    if (newPattern is null) DWT.error(DWT.ERROR_NO_HANDLES);
+                    Cairo.cairo_pattern_set_extend(newPattern, Cairo.CAIRO_EXTEND_REPEAT);
+                    double[6] matrix; matrix[0] = -1; matrix[1] = 0; matrix[2] = 0; matrix[3] = 1; matrix[4] = 0; matrix[5] = 0;
+                    Cairo.cairo_pattern_set_matrix(newPattern, cast(cairo_matrix_t*) matrix.ptr);
+                    Cairo.cairo_set_source(cairo, newPattern);
+                    Cairo.cairo_pattern_destroy(newPattern);
+                } else {
+                    Cairo.cairo_set_source(cairo, pattern.handle);
+                }
             } else {
                 Cairo.cairo_set_source_rgba(cairo, (color.red & 0xFFFF) / cast(float)0xFFFF, (color.green & 0xFFFF) / cast(float)0xFFFF, (color.blue & 0xFFFF) / cast(float)0xFFFF, data.alpha / cast(float)0xFF);
             }
         }
         if ((state & FONT) !is 0) {
             if (data.layout !is null) {
-                OS.pango_layout_set_font_description(data.layout, data.font);
+                Font font = data.font;
+                OS.pango_layout_set_font_description(data.layout, font.handle);
             }
             if (OS.GTK_VERSION < OS.buildVERSION(2, 8, 0)) {
                 setCairoFont(cairo, data.font);
@@ -312,13 +337,16 @@
             data.cairoXoffset = data.cairoYoffset = 0;
             double[] matrix = new double[6];
             Cairo.cairo_get_matrix(cairo,cast(cairo_matrix_t*) matrix.ptr);
-            double scaling = matrix[0];
+            double dx = 1;
+            double dy = 1;
+            Cairo.cairo_user_to_device_distance(cairo, &dx, &dy);
+            double scaling = dx;
             if (scaling < 0) scaling = -scaling;
             double strokeWidth = data.lineWidth * scaling;
             if (strokeWidth is 0 || (cast(int)strokeWidth % 2) is 1) {
                 data.cairoXoffset = 0.5 / scaling;
             }
-            scaling = matrix[3];
+            scaling = dy;
             if (scaling < 0) scaling = -scaling;
             strokeWidth = data.lineWidth * scaling;
             if (strokeWidth is 0 || (cast(int)strokeWidth % 2) is 1) {
@@ -344,7 +372,8 @@
     }
     if ((state & FONT) !is 0) {
         if (data.layout !is null) {
-            OS.pango_layout_set_font_description(data.layout, data.font);
+            Font font = data.font;
+            OS.pango_layout_set_font_description(data.layout, font.handle);
         }
     }
     if ((state & (LINE_CAP | LINE_JOIN | LINE_STYLE | LINE_WIDTH)) !is 0) {
@@ -544,7 +573,7 @@
     if (layout is null) DWT.error(DWT.ERROR_NO_HANDLES);
     data.layout = layout;
     OS.pango_context_set_language(context, OS.gtk_get_default_language());
-    OS.pango_context_set_base_dir(context, OS.PANGO_DIRECTION_LTR);
+    OS.pango_context_set_base_dir(context, (data.style & DWT.MIRRORED) !is 0 ? OS.PANGO_DIRECTION_RTL : OS.PANGO_DIRECTION_LTR);
     OS.gdk_pango_context_set_colormap(context, OS.gdk_colormap_get_system());
     if (OS.GTK_VERSION >= OS.buildVERSION(2, 4, 0)) {
         OS.pango_layout_set_auto_dir(layout, false);
@@ -559,19 +588,7 @@
     data.context = null;
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the graphics context. Applications must dispose of all GCs
- * which they allocate.
- *
- * @exception DWTError <ul>
- *    <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
- * </ul>
- */
-public override void dispose() {
-    if (handle is null) return;
-    if (data.device.isDisposed()) return;
-
+void destroy() {
     if (data.disposeCairo) {
         auto cairo = data.cairo;
         if (cairo !is null) Cairo.cairo_destroy(cairo);
@@ -590,17 +607,15 @@
     disposeLayout();
 
     /* Dispose the GC */
-    Device device = data.device;
-    drawable.internal_dispose_GC(handle, data);
-
+    if (drawable !is null) {
+        drawable.internal_dispose_GC(handle, data);
+    }
     data.drawable = null;
     data.clipRgn = null;
     drawable = null;
     handle = null;
     data.image = null;
     data.str = null;
-    if (device.tracking) device.dispose_Object(this);
-    data.device = null;
     data = null;
 }
 
@@ -808,6 +823,10 @@
         if (data.alpha !is 0) {
             srcImage.createSurface();
             Cairo.cairo_save(cairo);
+            if ((data.style & DWT.MIRRORED) !is 0) {
+                Cairo.cairo_scale(cairo, -1f,  1);
+                Cairo.cairo_translate(cairo, - 2 * destX - destWidth, 0);
+            }
             Cairo.cairo_rectangle(cairo, destX , destY, destWidth, destHeight);
             Cairo.cairo_clip(cairo);
             Cairo.cairo_translate(cairo, destX - srcX, destY - srcY);
@@ -1054,7 +1073,7 @@
 void drawImageXRender(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple, int imgWidth, int imgHeight, GdkDrawable* maskPixmap, int maskType) {
     int translateX = 0, translateY = 0;
     auto drawable = data.drawable;
-    if (data.image is null) {
+    if (data.image is null && !data.realDrawable) {
         int x, y;
         GdkDrawable* real_drawable;
         OS.gdk_window_get_internal_paint_info(cast(GdkWindow*)drawable, &real_drawable, &x, &y);
@@ -1448,21 +1467,25 @@
     if (nah < 0) nah = 0 - nah;
     auto cairo = data.cairo;
     if (cairo !is null) {
-        float naw2 = naw / 2f;
-        float nah2 = nah / 2f;
-        float fw = nw / naw2;
-        float fh = nh / nah2;
-        Cairo.cairo_save(cairo);
         double xOffset = data.cairoXoffset, yOffset = data.cairoYoffset;
-        Cairo.cairo_translate(cairo, nx + xOffset, ny + yOffset);
-        Cairo.cairo_scale(cairo, naw2, nah2);
-        Cairo.cairo_move_to(cairo, fw - 1, 0);
-        Cairo.cairo_arc(cairo, fw - 1, 1, 1, Compatibility.PI + Compatibility.PI/2.0, Compatibility.PI*2.0);
-        Cairo.cairo_arc(cairo, fw - 1, fh - 1, 1, 0, Compatibility.PI/2.0);
-        Cairo.cairo_arc(cairo, 1, fh - 1, 1, Compatibility.PI/2, Compatibility.PI);
-        Cairo.cairo_arc(cairo, 1, 1, 1, Compatibility.PI, 270.0*Compatibility.PI/180.0);
-        Cairo.cairo_close_path(cairo);
-        Cairo.cairo_restore(cairo);
+        if (naw is 0 || nah is 0) {
+            Cairo.cairo_rectangle(cairo, x + xOffset, y + yOffset, width, height);
+        } else {
+            float naw2 = naw / 2f;
+            float nah2 = nah / 2f;
+            float fw = nw / naw2;
+            float fh = nh / nah2;
+            Cairo.cairo_save(cairo);
+            Cairo.cairo_translate(cairo, nx + xOffset, ny + yOffset);
+            Cairo.cairo_scale(cairo, naw2, nah2);
+            Cairo.cairo_move_to(cairo, fw - 1, 0);
+            Cairo.cairo_arc(cairo, fw - 1, 1, 1, Compatibility.PI + Compatibility.PI/2.0, Compatibility.PI*2.0);
+            Cairo.cairo_arc(cairo, fw - 1, fh - 1, 1, 0, Compatibility.PI/2.0);
+            Cairo.cairo_arc(cairo, 1, fh - 1, 1, Compatibility.PI/2, Compatibility.PI);
+            Cairo.cairo_arc(cairo, 1, 1, 1, Compatibility.PI, 270.0*Compatibility.PI/180.0);
+            Cairo.cairo_close_path(cairo);
+            Cairo.cairo_restore(cairo);
+        }
         Cairo.cairo_stroke(cairo);
         return;
     }
@@ -1653,8 +1676,19 @@
             Cairo.cairo_fill(cairo);
         }
         checkGC(FOREGROUND | FONT);
+        if ((data.style & DWT.MIRRORED) !is 0) {
+            Cairo.cairo_save(cairo);
+            int width, height;
+            OS.pango_layout_get_size(data.layout, &width, &height);
+            Cairo.cairo_scale(cairo, -1f,  1);
+            Cairo.cairo_translate(cairo, -2 * x - OS.PANGO_PIXELS(width), 0);
+        }
         Cairo.cairo_move_to(cairo, x, y);
         OS.pango_cairo_show_layout(cairo, data.layout);
+        if ((data.style & DWT.MIRRORED) !is 0) {
+            Cairo.cairo_restore(cairo);
+        }
+        Cairo.cairo_new_path(cairo);
         return;
     }
     checkGC(FOREGROUND | FONT | BACKGROUND_BG);
@@ -2055,20 +2089,24 @@
     if (nah < 0) nah = 0 - nah;
     auto cairo = data.cairo;
     if (cairo !is null) {
-        float naw2 = naw / 2f;
-        float nah2 = nah / 2f;
-        float fw = nw / naw2;
-        float fh = nh / nah2;
-        Cairo.cairo_save(cairo);
-        Cairo.cairo_translate(cairo, nx, ny);
-        Cairo.cairo_scale(cairo, naw2, nah2);
-        Cairo.cairo_move_to(cairo, fw - 1, 0);
-        Cairo.cairo_arc(cairo, fw - 1, 1, 1, Compatibility.PI + Compatibility.PI/2.0, Compatibility.PI*2.0);
-        Cairo.cairo_arc(cairo, fw - 1, fh - 1, 1, 0, Compatibility.PI/2.0);
-        Cairo.cairo_arc(cairo, 1, fh - 1, 1, Compatibility.PI/2, Compatibility.PI);
-        Cairo.cairo_arc(cairo, 1, 1, 1, Compatibility.PI, 270.0*Compatibility.PI/180.0);
-        Cairo.cairo_close_path(cairo);
-        Cairo.cairo_restore(cairo);
+        if (naw is 0 || nah is 0) {
+            Cairo.cairo_rectangle(cairo, x, y, width, height);
+        } else {
+            float naw2 = naw / 2f;
+            float nah2 = nah / 2f;
+            float fw = nw / naw2;
+            float fh = nh / nah2;
+            Cairo.cairo_save(cairo);
+            Cairo.cairo_translate(cairo, nx, ny);
+            Cairo.cairo_scale(cairo, naw2, nah2);
+            Cairo.cairo_move_to(cairo, fw - 1, 0);
+            Cairo.cairo_arc(cairo, fw - 1, 1, 1, Compatibility.PI + Compatibility.PI/2.0, Compatibility.PI*2.0);
+            Cairo.cairo_arc(cairo, fw - 1, fh - 1, 1, 0, Compatibility.PI/2.0);
+            Cairo.cairo_arc(cairo, 1, fh - 1, 1, Compatibility.PI/2, Compatibility.PI);
+            Cairo.cairo_arc(cairo, 1, 1, 1, Compatibility.PI, 270.0*Compatibility.PI/180.0);
+            Cairo.cairo_close_path(cairo);
+            Cairo.cairo_restore(cairo);
+        }
         Cairo.cairo_fill(cairo);
         return;
     }
@@ -2283,10 +2321,15 @@
     if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
     /* Calculate visible bounds in device space */
     int x = 0, y = 0, width = 0, height = 0;
-    int w, h;
-    OS.gdk_drawable_get_size(data.drawable, &w, &h);
-    width = w;
-    height = h;
+    if (data.width !is -1 && data.height !is -1) {
+        width = data.width;
+        height = data.height;
+    } else {
+        int w, h;
+        OS.gdk_drawable_get_size(data.drawable, &w, &h);
+        width = w;
+        height = h;
+    }
     /* Intersect visible bounds with clipping in device space and then convert then to user space */
     auto cairo = data.cairo;
     auto clipRgn = data.clipRgn;
@@ -2353,11 +2396,16 @@
     auto cairo = data.cairo;
     auto clipRgn = data.clipRgn;
     if (clipRgn is null) {
-        int width,height;
-        OS.gdk_drawable_get_size(data.drawable, &width, &height);
         GdkRectangle rect;
-        rect.width = width;
-        rect.height = height;
+        if (data.width !is -1 && data.height !is -1) {
+            rect.width = data.width;
+            rect.height = data.height;
+        } else {
+            int width, height;
+            OS.gdk_drawable_get_size(data.drawable, &width, &height);
+            rect.width = width;
+            rect.height = height;
+        }
         OS.gdk_region_union_with_rect(clipping, &rect);
     } else {
         /* Convert clipping to device space if needed */
@@ -2415,7 +2463,7 @@
  */
 public Font getFont() {
     if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
-    return Font.gtk_new(data.device, data.font);
+    return data.font;
 }
 
 /**
@@ -2433,9 +2481,10 @@
     if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
     if (data.context is null) createLayout();
     checkGC(FONT);
+    Font font = data.font;
     auto context = data.context;
     auto lang = OS.pango_context_get_language(context);
-    auto metrics = OS.pango_context_get_metrics(context, data.font, lang);
+    auto metrics = OS.pango_context_get_metrics(context, font.handle, lang);
     FontMetrics fm = new FontMetrics();
     fm.ascent = OS.PANGO_PIXELS(OS.pango_font_metrics_get_ascent(metrics));
     fm.descent = OS.PANGO_PIXELS(OS.pango_font_metrics_get_descent(metrics));
@@ -2723,6 +2772,9 @@
     auto cairo = data.cairo;
     if (cairo !is null) {
         Cairo.cairo_get_matrix(cairo, cast(cairo_matrix_t*)transform.handle.ptr);
+        double[] identity = identity();
+        Cairo.cairo_matrix_invert(cast(cairo_matrix_t*)identity.ptr);
+        Cairo.cairo_matrix_multiply(cast(cairo_matrix_t*)transform.handle.ptr, cast(cairo_matrix_t*)transform.handle.ptr, cast(cairo_matrix_t*)identity.ptr);
     } else {
         transform.setElements(1, 0, 0, 1, 0, 0);
     }
@@ -2765,7 +2817,19 @@
     return cast(hash_t)/*64*/handle;
 }
 
-void init(Drawable drawable, GCData data, GdkGC* gdkGC) {
+double[] identity() {
+    double[] identity = new double[6];
+    if ((data.style & DWT.MIRRORED) !is 0) {
+        int w, h;
+        OS.gdk_drawable_get_size(data.drawable, &w, &h);
+        Cairo.cairo_matrix_init(cast(cairo_matrix_t*)identity.ptr, -1, 0, 0, 1, w, 0);
+    } else {
+        Cairo.cairo_matrix_init_identity(cast(cairo_matrix_t*)identity.ptr);
+    }
+    return identity;
+}
+
+void init_(Drawable drawable, GCData data, GdkGC* gdkGC) {
     if (data.foreground !is null) data.state &= ~FOREGROUND;
     if (data.background !is null) data.state &= ~(BACKGROUND | BACKGROUND_BG);
     if (data.font !is null) data.state &= ~FONT;
@@ -2783,6 +2847,11 @@
     this.drawable = drawable;
     this.data = data;
     handle = gdkGC;
+    if ((data.style & DWT.MIRRORED) !is 0) {
+      initCairo();
+      auto cairo = data.cairo;
+      Cairo.cairo_set_matrix(cairo, cast(cairo_matrix_t*) identity().ptr);
+    }
 }
 
 void initCairo() {
@@ -2797,12 +2866,14 @@
     if (data.image !is null) {
         xDrawable = OS.GDK_PIXMAP_XID(drawable);
     } else {
-        int x, y;
-        GdkDrawable* real_drawable;
-        OS.gdk_window_get_internal_paint_info(cast(GdkWindow*)drawable, &real_drawable, &x, &y);
-        xDrawable = OS.gdk_x11_drawable_get_xid(real_drawable);
-        translateX = -x;
-        translateY = -y;
+        if (!data.realDrawable) {
+            int x, y;
+            GdkDrawable* real_drawable;
+            OS.gdk_window_get_internal_paint_info(cast(GdkWindow*)drawable, &real_drawable, &x, &y);
+            xDrawable = OS.gdk_x11_drawable_get_xid(real_drawable);
+            translateX = -x;
+            translateY = -y;
+        }
     }
     int w, h;
     OS.gdk_drawable_get_size(drawable, &w, &h);
@@ -2901,6 +2972,19 @@
  */
 public void setAdvanced(bool advanced) {
     if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if ((data.style & DWT.MIRRORED) !is 0) {
+        if (!advanced) {
+            setAlpha(0xFF);
+            setAntialias(DWT.DEFAULT);
+            setBackgroundPattern(null);
+            setClipping(cast(GdkRegion*)null);
+            setForegroundPattern(null);
+            setInterpolation(DWT.DEFAULT);
+            setTextAntialias(DWT.DEFAULT);
+            setTransform(null);
+        }
+        return;
+    }
     if (advanced && data.cairo !is null) return;
     if (advanced) {
         try {
@@ -3268,9 +3352,8 @@
  */
 public void setFont(Font font) {
     if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
-    if (font is null) font = data.device.systemFont;
-    if (font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    data.font = font.handle;
+    if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    data.font = font !is null ? font : data.device.systemFont;
     data.state &= ~FONT;
     data.stringWidth = data.stringHeight = -1;
 }
@@ -3469,7 +3552,7 @@
                 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
         }
     }
-    int cap = attributes.join;
+    int cap = attributes.cap;
     if (cap !is data.lineCap) {
         mask |= LINE_CAP;
         switch (cap) {
@@ -3810,11 +3893,11 @@
     if (data.cairo is null && transform is null) return;
     initCairo();
     auto cairo = data.cairo;
+    double[] identity = identity();
     if (transform !is null) {
-        Cairo.cairo_set_matrix(cairo,cast(cairo_matrix_t*) transform.handle.ptr);
-    } else {
-        Cairo.cairo_identity_matrix(cairo);
+        Cairo.cairo_matrix_multiply(cast(cairo_matrix_t*)identity.ptr, cast(cairo_matrix_t*)transform.handle.ptr, cast(cairo_matrix_t*)identity.ptr);
     }
+    Cairo.cairo_set_matrix(cairo, cast(cairo_matrix_t*)identity.ptr);
     data.state &= ~DRAW_OFFSET;
 }
 
--- a/dwt/graphics/GCData.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/GCData.d	Mon May 12 19:13:01 2008 +0200
@@ -19,6 +19,7 @@
 import dwt.graphics.Device;
 import dwt.graphics.Pattern;
 import dwt.graphics.Image;
+import dwt.graphics.Font;
 
 /**
  * Instances of this class are descriptions of GCs in terms
@@ -35,7 +36,7 @@
     public int style, state = -1;
     public GdkColor* foreground;
     public GdkColor* background;
-    public PangoFontDescription* font;
+    public Font font;
     public Pattern foregroundPattern;
     public Pattern backgroundPattern;
     public GdkRegion* clipRgn;
@@ -63,5 +64,7 @@
     public int stringWidth = -1;
     public int stringHeight = -1;
     public int drawFlags;
+    public bool realDrawable;
+    public int width = -1, height = -1;
 }
 
--- a/dwt/graphics/Image.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Image.d	Mon May 12 19:13:01 2008 +0200
@@ -83,7 +83,7 @@
  * @see ImageLoader
  */
 public final class Image : Resource, Drawable {
-
+    alias Resource.init_ init_;
     /**
      * specifies whether the receiver is a bitmap or an icon
      * (one of <code>DWT.BITMAP</code>, <code>DWT.ICON</code>)
@@ -158,7 +158,8 @@
      */
     static const int DEFAULT_SCANLINE_PAD = 4;
 
-this() {
+this(Device device) {
+    super(device);
 }
 
 /**
@@ -192,10 +193,9 @@
  * </ul>
  */
 public this(Device device, int width, int height) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, width, height);
-    if (device.tracking) device.new_Object(this);
+    super(device);
+    init_(width, height);
+    init_();
 }
 
 /**
@@ -230,8 +230,7 @@
  * </ul>
  */
 public this(Device device, Image srcImage, int flag) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (srcImage is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (srcImage.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     switch (flag) {
@@ -242,7 +241,7 @@
         default:
             DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
-    this.device = device;
+    device = this.device;
     this.type = srcImage.type;
 
     /* Get source image size */
@@ -286,80 +285,79 @@
     if (flag is DWT.IMAGE_COPY) {
         OS.gdk_draw_drawable(pixmap, gdkGC, srcImage.pixmap, 0, 0, 0, 0, width, height);
         OS.g_object_unref(gdkGC);
-        if (device.tracking) device.new_Object(this);
-        return;
-    }
+    } else {
 
-    /* Retrieve the source pixmap data */
-    auto pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, width, height);
-    if (pixbuf is null) DWT.error(DWT.ERROR_NO_HANDLES);
-    auto colormap = OS.gdk_colormap_get_system();
-    OS.gdk_pixbuf_get_from_drawable(pixbuf, srcImage.pixmap, colormap, 0, 0, 0, 0, width, height);
-    int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
-    auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+        /* Retrieve the source pixmap data */
+        auto pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, width, height);
+        if (pixbuf is null) DWT.error(DWT.ERROR_NO_HANDLES);
+        auto colormap = OS.gdk_colormap_get_system();
+        OS.gdk_pixbuf_get_from_drawable(pixbuf, srcImage.pixmap, colormap, 0, 0, 0, 0, width, height);
+        int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+        auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
 
-    /* Apply transformation */
-    switch (flag) {
-        case DWT.IMAGE_DISABLE: {
-            Color zeroColor = device.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
-            RGB zeroRGB = zeroColor.getRGB();
-            byte zeroRed = cast(byte)zeroRGB.red;
-            byte zeroGreen = cast(byte)zeroRGB.green;
-            byte zeroBlue = cast(byte)zeroRGB.blue;
-            Color oneColor = device.getSystemColor(DWT.COLOR_WIDGET_BACKGROUND);
-            RGB oneRGB = oneColor.getRGB();
-            byte oneRed = cast(byte)oneRGB.red;
-            byte oneGreen = cast(byte)oneRGB.green;
-            byte oneBlue = cast(byte)oneRGB.blue;
-            byte[] line = new byte[stride];
-            for (int y=0; y<height; y++) {
+        /* Apply transformation */
+        switch (flag) {
+            case DWT.IMAGE_DISABLE: {
+                Color zeroColor = device.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
+                RGB zeroRGB = zeroColor.getRGB();
+                byte zeroRed = cast(byte)zeroRGB.red;
+                byte zeroGreen = cast(byte)zeroRGB.green;
+                byte zeroBlue = cast(byte)zeroRGB.blue;
+                Color oneColor = device.getSystemColor(DWT.COLOR_WIDGET_BACKGROUND);
+                RGB oneRGB = oneColor.getRGB();
+                byte oneRed = cast(byte)oneRGB.red;
+                byte oneGreen = cast(byte)oneRGB.green;
+                byte oneBlue = cast(byte)oneRGB.blue;
+                byte[] line = new byte[stride];
+                for (int y=0; y<height; y++) {
+                    memmove(line.ptr, pixels + (y * stride), stride);
+                    for (int x=0; x<width; x++) {
+                        int offset = x*3;
+                        int red = line[offset] & 0xFF;
+                        int green = line[offset+1] & 0xFF;
+                        int blue = line[offset+2] & 0xFF;
+                        int intensity = red * red + green * green + blue * blue;
+                        if (intensity < 98304) {
+                            line[offset] = zeroRed;
+                            line[offset+1] = zeroGreen;
+                            line[offset+2] = zeroBlue;
+                        } else {
+                            line[offset] = oneRed;
+                            line[offset+1] = oneGreen;
+                            line[offset+2] = oneBlue;
+                        }
+                    }
+                    memmove(pixels + (y * stride), line.ptr, stride);
+                }
+                break;
+            }
+            case DWT.IMAGE_GRAY: {
+                byte[] line = new byte[stride];
+                for (int y=0; y<height; y++) {
                 memmove(line.ptr, pixels + (y * stride), stride);
-                for (int x=0; x<width; x++) {
-                    int offset = x*3;
-                    int red = line[offset] & 0xFF;
-                    int green = line[offset+1] & 0xFF;
-                    int blue = line[offset+2] & 0xFF;
-                    int intensity = red * red + green * green + blue * blue;
-                    if (intensity < 98304) {
-                        line[offset] = zeroRed;
-                        line[offset+1] = zeroGreen;
-                        line[offset+2] = zeroBlue;
-                    } else {
-                        line[offset] = oneRed;
-                        line[offset+1] = oneGreen;
-                        line[offset+2] = oneBlue;
+                    for (int x=0; x<width; x++) {
+                        int offset = x*3;
+                        int red = line[offset] & 0xFF;
+                        int green = line[offset+1] & 0xFF;
+                        int blue = line[offset+2] & 0xFF;
+                        byte intensity = cast(byte)((red+red+green+green+green+green+green+blue) >> 3);
+                        line[offset] = line[offset+1] = line[offset+2] = intensity;
                     }
+                    memmove(pixels + (y * stride), line.ptr, stride);
                 }
-                memmove(pixels + (y * stride), line.ptr, stride);
+                break;
             }
-            break;
+        default:
         }
-        case DWT.IMAGE_GRAY: {
-            byte[] line = new byte[stride];
-            for (int y=0; y<height; y++) {
-                memmove(line.ptr, pixels + (y * stride), stride);
-                for (int x=0; x<width; x++) {
-                    int offset = x*3;
-                    int red = line[offset] & 0xFF;
-                    int green = line[offset+1] & 0xFF;
-                    int blue = line[offset+2] & 0xFF;
-                    byte intensity = cast(byte)((red+red+green+green+green+green+green+blue) >> 3);
-                    line[offset] = line[offset+1] = line[offset+2] = intensity;
-                }
-                memmove(pixels + (y * stride), line.ptr, stride);
-            }
-            break;
-        }
-        default:
+
+        /* Copy data back to destination pixmap */
+        OS.gdk_pixbuf_render_to_drawable(pixbuf, pixmap, gdkGC, 0, 0, 0, 0, width, height, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
+
+        /* Free resources */
+        OS.g_object_unref(pixbuf);
+        OS.g_object_unref(gdkGC);
     }
-
-    /* Copy data back to destination pixmap */
-    OS.gdk_pixbuf_render_to_drawable(pixbuf, pixmap, gdkGC, 0, 0, 0, 0, width, height, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
-
-    /* Free resources */
-    OS.g_object_unref(pixbuf);
-    OS.g_object_unref(gdkGC);
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
 /**
@@ -393,11 +391,10 @@
  * </ul>
  */
 public this(Device device, Rectangle bounds) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (bounds is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, bounds.width, bounds.height);
-    if (device.tracking) device.new_Object(this);
+    init_(bounds.width, bounds.height);
+    init_();
 }
 
 /**
@@ -419,10 +416,9 @@
  * </ul>
  */
 public this(Device device, ImageData data) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, data);
-    if (device.tracking) device.new_Object(this);
+    super(device);
+    init_(data);
+    init_();
 }
 
 /**
@@ -451,8 +447,7 @@
  * </ul>
  */
 public this(Device device, ImageData source, ImageData mask) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (source is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (mask is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (source.width !is mask.width || source.height !is mask.height) {
@@ -462,8 +457,8 @@
     ImageData image = new ImageData(source.width, source.height, source.depth, source.palette, source.scanlinePad, source.data);
     image.maskPad = mask.scanlinePad;
     image.maskData = mask.data;
-    init_(device, image);
-    if (device.tracking) device.new_Object(this);
+    init_(image);
+    init_();
 }
 
 /**
@@ -515,10 +510,9 @@
  * </ul>
  */
 public this(Device device, InputStream stream) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    init_(device, new ImageData(stream));
-    if (device.tracking) device.new_Object(this);
+    super(device);
+    init_(new ImageData(stream));
+    init_();
 }
 
 /**
@@ -549,10 +543,8 @@
  * </ul>
  */
 public this(Device device, String filename) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (filename is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
     try {
         int length = filename.length;
         auto pixbuf = OS.gdk_pixbuf_new_from_file(toStringz(filename), null);
@@ -591,8 +583,8 @@
             return;
         }
     } catch (DWTException e) {}
-    init_(device, new ImageData(filename));
-    if (device.tracking) device.new_Object(this);
+    init_(new ImageData(filename));
+    init_();
 }
 
 void createAlphaMask (int width, int height) {
@@ -767,14 +759,7 @@
     mask = null;
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the image. Applications must dispose of all images which
- * they allocate.
- */
-public override void dispose () {
-    if (pixmap is null) return;
-    if (device.isDisposed()) return;
+void destroy() {
     if (memGC !is null) memGC.dispose();
     if (pixmap !is null) OS.g_object_unref(pixmap);
     if (mask !is null) OS.g_object_unref(mask);
@@ -785,8 +770,6 @@
     pixmap = null;
     mask = null;
     memGC = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
 }
 
 /**
@@ -944,12 +927,10 @@
  * @private
  */
 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 image = new Image(device);
     image.type = type;
     image.pixmap = cast(GdkDrawable*)pixmap;
     image.mask = cast(GdkDrawable*)mask;
-    image.device = device;
     return image;
 }
 
@@ -967,11 +948,10 @@
     return cast(hash_t)/*64*/pixmap;
 }
 
-void init_(Device device, int width, int height) {
+void init_(int width, int height) {
     if (width <= 0 || height <= 0) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
-    this.device = device;
     this.type = DWT.BITMAP;
 
     /* Create the pixmap */
@@ -991,9 +971,8 @@
     OS.gdk_colormap_free_colors(colormap, white, 1);
 }
 
-void init_(Device device, ImageData image) {
+void init_(ImageData image) {
     if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
     int width = image.width;
     int height = image.height;
     PaletteData palette = image.palette;
@@ -1101,12 +1080,16 @@
         int mask = DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
         if ((data.style & mask) is 0) {
             data.style |= DWT.LEFT_TO_RIGHT;
+        } else {
+            if ((data.style & DWT.RIGHT_TO_LEFT) !is 0) {
+                data.style |= DWT.MIRRORED;
+            }
         }
         data.device = device;
         data.drawable = pixmap;
         data.background = device.COLOR_WHITE.handle;
         data.foreground = device.COLOR_BLACK.handle;
-        data.font = device.systemFont.handle;
+        data.font = device.systemFont;
         data.image = this;
     }
     return gdkGC;
--- a/dwt/graphics/ImageData.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/ImageData.d	Mon May 12 19:13:01 2008 +0200
@@ -289,7 +289,7 @@
  *
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
- *          one of 1, 2, 4, 8, 16, 24 or 32</li>
+ *          one of 1, 2, 4, 8, 16, 24 or 32, or the data array is too small to contain the image data</li>
  *    <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li>
  *    <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li>
  * </ul>
@@ -444,6 +444,17 @@
 
     int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1))
         / scanlinePad * scanlinePad;
+    
+    /*
+     * When the image is being loaded from a PNG, we need to use the theoretical minimum
+     * number of bytes per line to check whether there is enough data, because the actual
+     * number of bytes per line is calculated based on the given depth, which may be larger
+     * than the actual depth of the PNG.
+     */
+    int minBytesPerLine = type is DWT.IMAGE_PNG ? ((((width + 7) / 8) + 3) / 4) * 4 : bytesPerLine;
+    if (data !is null && data.length < minBytesPerLine * height) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
     setAllFields(
         width,
         height,
--- a/dwt/graphics/Path.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Path.d	Mon May 12 19:13:01 2008 +0200
@@ -44,7 +44,7 @@
  * @since 3.1
  */
 public class Path : Resource {
-
+    alias Resource.init_ init_;
     /**
      * the OS resource for the Path
      * (Warning: This field is platform dependent)
@@ -82,16 +82,48 @@
  * @see #dispose()
  */
 public this (Device device) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
-    device.checkCairo();
+    super(device);
+    this.device.checkCairo();
+    auto surface = Cairo.cairo_image_surface_create(Cairo.CAIRO_FORMAT_ARGB32, 1, 1);
+    if (surface is null) DWT.error(DWT.ERROR_NO_HANDLES);
+    handle = Cairo.cairo_create(surface);
+    Cairo.cairo_surface_destroy(surface);
+    if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
+    init_();
+}
+
+public this (Device device, Path path, float flatness) {
+    super(device);
+    if (path is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (path.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     auto surface = Cairo.cairo_image_surface_create(Cairo.CAIRO_FORMAT_ARGB32, 1, 1);
     if (surface is null) DWT.error(DWT.ERROR_NO_HANDLES);
     handle = Cairo.cairo_create(surface);
     Cairo.cairo_surface_destroy(surface);
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
-    if (device.tracking) device.new_Object(this);
+    cairo_path_t* copy;
+    flatness = Math.max(0, flatness);
+    if (flatness is 0) {
+        copy = Cairo.cairo_copy_path(path.handle);
+    } else {
+        double tolerance = Cairo.cairo_get_tolerance(path.handle);
+        Cairo.cairo_set_tolerance(path.handle, flatness);
+        copy = Cairo.cairo_copy_path_flat(path.handle);
+        Cairo.cairo_set_tolerance(path.handle, tolerance);
+    }
+    if (copy is null) {
+        Cairo.cairo_destroy(handle);
+        DWT.error(DWT.ERROR_NO_HANDLES);
+    }
+    Cairo.cairo_append_path(handle, copy);
+    Cairo.cairo_path_destroy(copy);
+    init_();
+}
+
+public this (Device device, PathData data) {
+    this(device);
+    if (data is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    init_(data);
 }
 
 /**
@@ -552,17 +584,36 @@
     closed = false;
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the Path. Applications must dispose of all Paths that
- * they allocate.
- */
-public override void dispose() {
-    if (handle is null) return;
+void destroy() {
     Cairo.cairo_destroy(handle);
     handle = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
+}
+
+void init_(PathData data) {
+    byte[] types = data.types;
+    float[] points = data.points;
+    for (int i = 0, j = 0; i < types.length; i++) {
+        switch (types[i]) {
+            case DWT.PATH_MOVE_TO:
+                moveTo(points[j++], points[j++]);
+                break;
+            case DWT.PATH_LINE_TO:
+                lineTo(points[j++], points[j++]);
+                break;
+            case DWT.PATH_CUBIC_TO:
+                cubicTo(points[j++], points[j++], points[j++], points[j++], points[j++], points[j++]);
+                break;
+            case DWT.PATH_QUAD_TO:
+                quadTo(points[j++], points[j++], points[j++], points[j++]);
+                break;
+            case DWT.PATH_CLOSE:
+                close();
+                break;
+            default:
+                dispose();
+                DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+    }
 }
 
 /**
--- a/dwt/graphics/Pattern.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Pattern.d	Mon May 12 19:13:01 2008 +0200
@@ -54,6 +54,8 @@
      */
     public cairo_pattern_t* handle;
 
+    cairo_surface_t * surface;
+
 /**
  * Constructs a new Pattern given an image. Drawing with the resulting
  * pattern will cause the image to be tiled over the resulting area.
@@ -80,17 +82,16 @@
  * @see #dispose()
  */
 public this(Device device, Image image) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    this.device = device;
-    device.checkCairo();
+    this.device.checkCairo();
     image.createSurface();
     handle = Cairo.cairo_pattern_create_for_surface(image.surface);
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
     Cairo.cairo_pattern_set_extend(handle, Cairo.CAIRO_EXTEND_REPEAT);
-    if (device.tracking) device.new_Object(this);
+    surface = image.surface;
+    init_();
 }
 
 /**
@@ -165,34 +166,24 @@
  * @since 3.2
  */
 public this(Device device, float x1, float y1, float x2, float y2, Color color1, int alpha1, Color color2, int alpha2) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    super(device);
     if (color1 is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (color1.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (color2 is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (color2.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    this.device = device;
-    device.checkCairo();
+    this.device.checkCairo();
     handle = Cairo.cairo_pattern_create_linear(x1, y1, x2, y2);
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
     GC.setCairoPatternColor(handle, 0, color1, alpha1);
     GC.setCairoPatternColor(handle, 1, color2, alpha2);
     Cairo.cairo_pattern_set_extend(handle, Cairo.CAIRO_EXTEND_REPEAT);
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the Pattern. Applications must dispose of all Patterns that
- * they allocate.
- */
-public override void dispose() {
-    if (handle is null) return;
-    if (device.isDisposed()) return;
+void destroy() {
     Cairo.cairo_pattern_destroy(handle);
     handle = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
+    surface = null;
 }
 
 /**
--- a/dwt/graphics/Region.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Region.d	Mon May 12 19:13:01 2008 +0200
@@ -78,16 +78,14 @@
  * @since 3.0
  */
 public this(Device device) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
+    super(device);
     handle = OS.gdk_region_new();
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
 this(Device device, GdkRegion* handle) {
-    this.device = device;
+    super(device);
     this.handle = handle;
 }
 
@@ -110,7 +108,12 @@
 public void add (int[] pointArray) {
     if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
     if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-//PORTING_FIXME: shall the pointArray be changed to be GdkPoint[] ?
+    /*
+    * Bug in GTK. If gdk_region_polygon() is called with one point,
+    * it segment faults. The fix is to make sure that it is called
+    * with enough points for a polygon.
+    */
+    if (pointArray.length < 6) return;
     auto polyRgn = OS.gdk_region_polygon(cast(GdkPoint*)pointArray.ptr, pointArray.length / 2, OS.GDK_EVEN_ODD_RULE);
     OS.gdk_region_union(handle, polyRgn);
     OS.gdk_region_destroy(polyRgn);
@@ -225,18 +228,9 @@
     return contains(pt.x, pt.y);
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the region. Applications must dispose of all regions which
- * they allocate.
- */
-public override void dispose() {
-    if (handle is null) return;
-    if (device.isDisposed()) return;
+void destroy() {
     OS.gdk_region_destroy(handle);
     handle = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
 }
 
 /**
@@ -468,6 +462,12 @@
 public void subtract (int[] pointArray) {
     if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
     if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    /*
+    * Bug in GTK. If gdk_region_polygon() is called with one point,
+    * it segment faults. The fix is to make sure that it is called
+    * with enough points for a polygon.
+    */
+    if (pointArray.length < 6) return;
     auto polyRgn = OS.gdk_region_polygon( cast(GdkPoint*)pointArray.ptr, pointArray.length / 2, OS.GDK_EVEN_ODD_RULE);
     OS.gdk_region_subtract(handle, polyRgn);
     OS.gdk_region_destroy(polyRgn);
--- a/dwt/graphics/Resource.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Resource.d	Mon May 12 19:13:01 2008 +0200
@@ -46,12 +46,30 @@
      */
     Device device;
 
+this() {
+}
+
+this(Device device) {
+    if (device is null) device = Device.getDevice();
+    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    this.device = device;
+}
+
+void destroy() {
+}
+
 /**
  * Disposes of the operating system resources associated with
  * this resource. Applications must dispose of all resources
  * which they allocate.
  */
-public abstract void dispose();
+public void dispose() {
+    if (device is null) return;
+    if (device.isDisposed()) return;
+    destroy();
+    if (device.tracking) device.dispose_Object(this);
+    device = null;
+}
 
 /**
  * Returns the <code>Device</code> where this resource was
@@ -67,6 +85,10 @@
     return device;
 }
 
+void init_() {
+    if (device.tracking) device.new_Object(this);
+}
+
 /**
  * Returns <code>true</code> if the resource has been disposed,
  * and <code>false</code> otherwise.
--- a/dwt/graphics/TextLayout.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/TextLayout.d	Mon May 12 19:13:01 2008 +0200
@@ -12,6 +12,7 @@
  *******************************************************************************/
 module dwt.graphics.TextLayout;
 
+import dwt.internal.Compatibility;
 import dwt.internal.cairo.Cairo;
 import dwt.internal.gtk.OS;
 import dwt.internal.Converter;
@@ -94,9 +95,7 @@
  * @see #dispose()
  */
 public this (Device device) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
+    super(device);
     context = OS.gdk_pango_context_get();
     if (context is null) DWT.error(DWT.ERROR_NO_HANDLES);
     OS.pango_context_set_language(context, OS.gtk_get_default_language());
@@ -104,8 +103,9 @@
     OS.gdk_pango_context_set_colormap(context, OS.gdk_colormap_get_system());
     layout = OS.pango_layout_new(context);
     if (layout is null) DWT.error(DWT.ERROR_NO_HANDLES);
+    OS.pango_layout_set_font_description(layout, device.systemFont.handle);
     OS.pango_layout_set_wrap(layout, OS.PANGO_WRAP_WORD_CHAR);
-    OS.pango_layout_set_tabs(layout, device.emptyTab);
+    OS.pango_layout_set_tabs(layout, this.device.emptyTab);
     if (OS.GTK_VERSION >= OS.buildVERSION(2, 4, 0)) {
         OS.pango_layout_set_auto_dir(layout, false);
     }
@@ -114,7 +114,7 @@
     styles = new StyleItem[2];
     styles[0] = new StyleItem();
     styles[1] = new StyleItem();
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
 void checkLayout() {
@@ -132,18 +132,17 @@
     char[] chars = null;
     int segementsLength = segmentsText.length;
     if ((ascent !is -1  || descent !is -1) && segementsLength > 0) {
-        auto iter = OS.pango_layout_get_iter(layout);
-        if (iter is null) DWT.error(DWT.ERROR_NO_HANDLES);
         PangoRectangle rect;
         if (ascent !is -1) rect.y =  -(ascent  * OS.PANGO_SCALE);
         rect.height = (Math.max(0, ascent) + Math.max(0, descent)) * OS.PANGO_SCALE;
         int lineCount = OS.pango_layout_get_line_count(layout);
         chars = new char[segementsLength + lineCount * 6/*2*/];
-        int oldPos = 0, count = 0;
-        do {
-            int bytePos = OS.pango_layout_iter_get_index(iter);
+        int oldPos = 0, lineIndex = 0;
+        while (lineIndex < lineCount) {
+            auto line = OS.pango_layout_get_line(layout, lineIndex);
+            int bytePos = line.start_index;
             /* Note: The length in bytes of ZWS and ZWNBS are both equals to 3 */
-            int offset = count * 6;
+            int offset = lineIndex * 6;
             PangoAttribute* attr = OS.pango_attr_shape_new (&rect, &rect);
             attr.start_index = bytePos + offset;
             attr.end_index = bytePos + offset + 3;
@@ -153,15 +152,15 @@
             attr.end_index = bytePos + offset + 6;
             OS.pango_attr_list_insert(attrList, attr);
             int pos = bytePos;//OS.g_utf8_pointer_to_offset(ptr, ptr + bytePos);
-            chars[pos + count * 6 +0 .. pos + count * 6 + 3] = STR_ZWS;
-            chars[pos + count * 6 +3 .. pos + count * 6 + 6] = STR_ZWNBS;
-            chars[ oldPos + count*6 .. oldPos + count*6 + pos - oldPos ] =
+            chars[pos + lineIndex * 6 +0 .. pos + lineIndex * 6 + 3] = STR_ZWS;
+            chars[pos + lineIndex * 6 +3 .. pos + lineIndex * 6 + 6] = STR_ZWNBS;
+            chars[ oldPos + lineIndex*6 .. oldPos + lineIndex*6 + pos - oldPos ] =
                 segmentsText[ oldPos .. pos ];
             oldPos = pos;
-            count++;
-        } while (OS.pango_layout_iter_next_line(iter));
-        OS.pango_layout_iter_free (iter);
-        chars[ oldPos + count*6 .. oldPos + count*6 + segementsLength - oldPos ] =
+            lineIndex++;
+        }
+        segmentsText.getChars(oldPos, segementsLength, chars,  oldPos + lineIndex * 2);
+        chars[ oldPos + lineIndex*6 .. oldPos + lineIndex*6 + segementsLength - oldPos ] =
             segmentsText[ oldPos .. segementsLength ];
         String buffer = chars;// Converter.wcsToMbcs(null, chars, false);
 
@@ -216,12 +215,29 @@
             OS.pango_attr_list_insert(attrList, attr);
         }
         if (style.underline) {
-            auto attr = OS.pango_attr_underline_new(OS.PANGO_UNDERLINE_SINGLE);
-            attr.start_index = byteStart;
-            attr.end_index = byteEnd;
-            OS.pango_attr_list_insert(attrList, attr);
+            int underlineStyle = OS.PANGO_UNDERLINE_NONE;
+            switch (style.underlineStyle) {
+                case DWT.UNDERLINE_SINGLE:
+                    underlineStyle = OS.PANGO_UNDERLINE_SINGLE;
+                    break;
+                case DWT.UNDERLINE_DOUBLE:
+                    underlineStyle = OS.PANGO_UNDERLINE_DOUBLE;
+                    break;
+                case DWT.UNDERLINE_SQUIGGLE:
+                case DWT.UNDERLINE_ERROR:
+                    if (OS.GTK_VERSION >= OS.buildVERSION(2, 4, 0)) {
+                        underlineStyle = OS.PANGO_UNDERLINE_ERROR;
+                    }
+                    break;
+            }
+            if (underlineStyle !is OS.PANGO_UNDERLINE_NONE && style.underlineColor is null) {
+                auto attr = OS.pango_attr_underline_new(underlineStyle);
+                attr.start_index = byteStart;
+                attr.end_index = byteEnd;
+                OS.pango_attr_list_insert(attrList, attr);
+            }
         }
-        if (style.strikeout) {
+        if (style.strikeout && style.strikeoutColor is null) {
             auto attr = OS.pango_attr_strikethrough_new(true);
             attr.start_index = byteStart;
             attr.end_index = byteEnd;
@@ -265,12 +281,30 @@
     OS.pango_layout_set_attributes(layout, attrList);
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the text layout. Applications must dispose of all allocated text layouts.
- */
-public override void dispose() {
-    if (layout is null) return;
+int[] computePolyline(int left, int top, int right, int bottom) {
+    int height = bottom - top; // can be any number
+    int width = 2 * height; // must be even
+    int peaks = Compatibility.ceil(right - left, width);
+    if (peaks is 0 && right - left > 2) {
+        peaks = 1;
+    }
+    int length_ = ((2 * peaks) + 1) * 2;
+    if (length_ < 0) return new int[0];
+
+    int[] coordinates = new int[length_];
+    for (int i = 0; i < peaks; i++) {
+        int index = 4 * i;
+        coordinates[index] = left + (width * i);
+        coordinates[index+1] = bottom;
+        coordinates[index+2] = coordinates[index] + width / 2;
+        coordinates[index+3] = top;
+    }
+    coordinates[length_-2] = left + (width * peaks);
+    coordinates[length_-1] = bottom;
+    return coordinates;
+}
+
+void destroy() {
     font = null;
     text = null;
     styles = null;
@@ -279,8 +313,6 @@
     layout = null;
     if (context !is null) OS.g_object_unref(context);
     context = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
 }
 
 /**
@@ -360,7 +392,7 @@
     if (selectionForeground !is null && selectionForeground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (selectionBackground !is null && selectionBackground.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     gc.checkGC(GC.FOREGROUND);
-    int length = text.length;
+    int length_ = text.length;
     bool hasSelection = selectionStart <= selectionEnd && selectionStart !is -1 && selectionEnd !is -1;
     GCData data = gc.data;
     auto cairo = data.cairo;
@@ -429,29 +461,48 @@
             OS.gdk_gc_set_foreground(gc.handle, data.foreground);
         }
     }
-    if (length is 0) return;
+    if (length_ is 0) return;
     if (!hasSelection) {
         if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+            if ((data.style & DWT.MIRRORED) !is 0) {
+                Cairo.cairo_save(cairo);
+                Cairo.cairo_scale(cairo, -1,  1);
+                Cairo.cairo_translate(cairo, -2 * x - width(), 0);
+            }
             Cairo.cairo_move_to(cairo, x, y);
             OS.pango_cairo_show_layout(cairo, layout);
+            drawBorder(gc, x, y, null);
+            if ((data.style & DWT.MIRRORED) !is 0) {
+                Cairo.cairo_restore(cairo);
+            }
         } else {
             OS.gdk_draw_layout(data.drawable, gc.handle, x, y, layout);
+            drawBorder(gc, x, y, null);
         }
     } else {
-        selectionStart = Math.min(Math.max(0, selectionStart), length - 1);
-        selectionEnd = Math.min(Math.max(0, selectionEnd), length - 1);
-        length = OS.g_utf8_strlen(OS.pango_layout_get_text(layout), -1);
+        selectionStart = Math.min(Math.max(0, selectionStart), length_ - 1);
+        selectionEnd = Math.min(Math.max(0, selectionEnd), length_ - 1);
+        length_ = OS.g_utf8_strlen(OS.pango_layout_get_text(layout), -1);
         selectionStart = translateOffset(selectionStart);
         selectionEnd = translateOffset(selectionEnd);
         if (selectionForeground is null) selectionForeground = device.getSystemColor(DWT.COLOR_LIST_SELECTION_TEXT);
         if (selectionBackground is null) selectionBackground = device.getSystemColor(DWT.COLOR_LIST_SELECTION);
-        bool fullSelection = selectionStart is 0 && selectionEnd is length - 1;
+        bool fullSelection = selectionStart is 0 && selectionEnd is length_ - 1;
         if (fullSelection) {
             if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
                 auto ptr = OS.pango_layout_get_text(layout);
-                drawWithCairo(cairo, x, y, 0, strlen(ptr), fullSelection, selectionBackground.handle, selectionForeground.handle);
+                if ((data.style & DWT.MIRRORED) !is 0) {
+                    Cairo.cairo_save(cairo);
+                    Cairo.cairo_scale(cairo, -1,  1);
+                    Cairo.cairo_translate(cairo, -2 * x - width(), 0);
+                }
+                drawWithCairo(gc, x, y, 0, OS.strlen(ptr), fullSelection, selectionForeground.handle, selectionBackground.handle);
+                if ((data.style & DWT.MIRRORED) !is 0) {
+                    Cairo.cairo_restore(cairo);
+                }
             } else {
                 OS.gdk_draw_layout_with_colors(data.drawable, gc.handle, x, y, layout, selectionForeground.handle, selectionBackground.handle);
+                drawBorder(gc, x, y, selectionForeground.handle);
             }
         } else {
             auto ptr = OS.pango_layout_get_text(layout);
@@ -461,11 +512,20 @@
             byteSelStart = Math.min(byteSelStart, slen);
             byteSelEnd = Math.min(byteSelEnd, slen);
             if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
-                drawWithCairo(cairo, x, y, byteSelStart, byteSelEnd, fullSelection, selectionBackground.handle, selectionForeground.handle);
+                if ((data.style & DWT.MIRRORED) !is 0) {
+                    Cairo.cairo_save(cairo);
+                    Cairo.cairo_scale(cairo, -1,  1);
+                    Cairo.cairo_translate(cairo, -2 * x - width(), 0);
+                }
+                drawWithCairo(gc, x, y, byteSelStart, byteSelEnd, fullSelection, selectionForeground.handle, selectionBackground.handle);
+                if ((data.style & DWT.MIRRORED) !is 0) {
+                    Cairo.cairo_restore(cairo);
+                }
             } else {
                 Region clipping = new Region();
                 gc.getClipping(clipping);
                 OS.gdk_draw_layout(data.drawable, gc.handle, x, y, layout);
+                drawBorder(gc, x, y, null);
                 int[] ranges = [byteSelStart, byteSelEnd];
                 auto rgn = OS.gdk_pango_layout_get_clip_region(layout, x, y, ranges.ptr, ranges.length / 2);
                 if (rgn !is null) {
@@ -473,6 +533,7 @@
                     OS.gdk_region_destroy(rgn);
                 }
                 OS.gdk_draw_layout_with_colors(data.drawable, gc.handle, x, y, layout, selectionForeground.handle, selectionBackground.handle);
+                drawBorder(gc, x, y, selectionForeground.handle);
                 gc.setClipping(clipping);
                 clipping.dispose();
             }
@@ -480,27 +541,294 @@
     }
 }
 
-void drawWithCairo(cairo_t* cairo, int x, int y, int byteSelStart, int byteSelEnd, bool fullSelection, GdkColor* selectionBackground, GdkColor* selectionForeground) {
+void drawWithCairo(GC gc, int x, int y, int start, int end, bool fullSelection, GdkColor* fg, GdkColor* bg) {
+    GCData data = gc.data;
+    cairo_t* cairo = data.cairo;
     Cairo.cairo_save(cairo);
     if (!fullSelection) {
         Cairo.cairo_move_to(cairo, x, y);
         OS.pango_cairo_show_layout(cairo, layout);
+        drawBorder(gc, x, y, null);
     }
-    int[] ranges = [byteSelStart, byteSelEnd];
+    int[] ranges = [start, end];
     auto rgn = OS.gdk_pango_layout_get_clip_region(layout, x, y, ranges.ptr, ranges.length / 2);
     if (rgn !is null) {
         OS.gdk_cairo_region(cairo, rgn);
         Cairo.cairo_clip(cairo);
-        OS.gdk_cairo_set_source_color(cairo, selectionBackground);
+        Cairo.cairo_set_source_rgba(cairo, (bg.red & 0xFFFF) / cast(float)0xFFFF, (bg.green & 0xFFFF) / cast(float)0xFFFF, (bg.blue & 0xFFFF) / cast(float)0xFFFF, data.alpha / cast(float)0xFF);
         Cairo.cairo_paint(cairo);
         OS.gdk_region_destroy(rgn);
     }
-    OS.gdk_cairo_set_source_color(cairo, selectionForeground);
+    Cairo.cairo_set_source_rgba(cairo, (fg.red & 0xFFFF) / cast(float)0xFFFF, (fg.green & 0xFFFF) / cast(float)0xFFFF, (fg.blue & 0xFFFF) / cast(float)0xFFFF, data.alpha / cast(float)0xFF);
     Cairo.cairo_move_to(cairo, x, y);
     OS.pango_cairo_show_layout(cairo, layout);
+    drawBorder(gc, x, y, fg);
     Cairo.cairo_restore(cairo);
 }
 
+void drawBorder(GC gc, int x, int y, GdkColor* selectionColor) {
+    GCData data = gc.data;
+    auto cairo = data.cairo;
+    auto gdkGC = gc.handle;
+    auto ptr = OS.pango_layout_get_text(layout);
+    GdkGCValues* gcValues = null;
+    if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+        Cairo.cairo_save(cairo);
+    }
+    for (int i = 0; i < styles.length - 1; i++) {
+        TextStyle style = styles[i].style;
+        if (style is null) continue;
+
+        bool drawBorder = style.borderStyle !is DWT.NONE;
+        if (drawBorder && !style.isAdherentBorder(styles[i+1].style)) {
+            int start = styles[i].start;
+            for (int j = i; j > 0 && style.isAdherentBorder(styles[j-1].style); j--) {
+                start = styles[j - 1].start;
+            }
+            start = translateOffset(start);
+            int end = translateOffset(styles[i+1].start - 1);
+            int byteStart = cast(int)/*64*/(OS.g_utf8_offset_to_pointer(ptr, start) - ptr);
+            int byteEnd = cast(int)/*64*/(OS.g_utf8_offset_to_pointer(ptr, end + 1) - ptr);
+            int[] ranges = [byteStart, byteEnd];
+            auto rgn = OS.gdk_pango_layout_get_clip_region(layout, x, y, ranges.ptr, ranges.length / 2);
+            if (rgn !is null) {
+                int nRects;
+                GdkRectangle* rects;
+                OS.gdk_region_get_rectangles(rgn, &rects, &nRects);
+                GdkRectangle rect;
+                GdkColor* color = null;
+                if (color is null && style.borderColor !is null) color = style.borderColor.handle;
+                if (color is null && selectionColor !is null) color = selectionColor;
+                if (color is null && style.foreground !is null) color = style.foreground.handle;
+                if (color is null) color = data.foreground;
+                int width = 1;
+                float[] dashes = null;
+                switch (style.borderStyle) {
+                    case DWT.BORDER_SOLID: break;
+                    case DWT.BORDER_DASH: dashes = width !is 0 ? GC.LINE_DASH : GC.LINE_DASH_ZERO; break;
+                    case DWT.BORDER_DOT: dashes = width !is 0 ? GC.LINE_DOT : GC.LINE_DOT_ZERO; break;
+                }
+                if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+                    Cairo.cairo_set_source_rgba(cairo, (color.red & 0xFFFF) / cast(float)0xFFFF, (color.green & 0xFFFF) / cast(float)0xFFFF, (color.blue & 0xFFFF) / cast(float)0xFFFF, data.alpha / cast(float)0xFF);
+                    Cairo.cairo_set_line_width(cairo, width);
+                    if (dashes !is null) {
+                        double[] cairoDashes = new double[dashes.length];
+                        for (int j = 0; j < cairoDashes.length; j++) {
+                            cairoDashes[j] = width is 0 || data.lineStyle is DWT.LINE_CUSTOM ? dashes[j] : dashes[j] * width;
+                        }
+                        Cairo.cairo_set_dash(cairo, cairoDashes.ptr, cairoDashes.length, 0);
+                    } else {
+                        Cairo.cairo_set_dash(cairo, null, 0, 0);
+                    }
+                    for (int j=0; j<nRects; j++) {
+                        rect = rects[j];
+                        Cairo.cairo_rectangle(cairo, rect.x + 0.5, rect.y + 0.5, rect.width - 1, rect.height - 1);
+                    }
+                    Cairo.cairo_stroke(cairo);
+                } else {
+                    if (gcValues is null) {
+                        gcValues = new GdkGCValues();
+                        OS.gdk_gc_get_values(gdkGC, gcValues);
+                    }
+                    OS.gdk_gc_set_foreground(gdkGC, color);
+                    int cap_style = OS.GDK_CAP_BUTT;
+                    int join_style = OS.GDK_JOIN_MITER;
+                    int line_style = 0;
+                    if (dashes !is null) {
+                        byte[] dash_list = new byte[dashes.length];
+                        for (int j = 0; j < dash_list.length; j++) {
+                            dash_list[j] = cast(byte)(width is 0 || data.lineStyle is DWT.LINE_CUSTOM ? dashes[j] : dashes[j] * width);
+                        }
+                        OS.gdk_gc_set_dashes(gdkGC, 0, cast(char*)dash_list.ptr, dash_list.length);
+                        line_style = OS.GDK_LINE_ON_OFF_DASH;
+                    } else {
+                        line_style = OS.GDK_LINE_SOLID;
+                    }
+                    OS.gdk_gc_set_line_attributes(gdkGC, width, line_style, cap_style, join_style);
+                    for (int j=0; j<nRects; j++) {
+                        rect = rects[j];
+                        OS.gdk_draw_rectangle(data.drawable, gdkGC, 0, rect.x, rect.y, rect.width - 1, rect.height - 1);
+                    }
+                }
+                if (rects !is null) OS.g_free(rects);
+                OS.gdk_region_destroy(rgn);
+            }
+        }
+
+        bool drawUnderline = false;
+        if (style.underline && style.underlineColor !is null) drawUnderline = true;
+        if (style.underline && (style.underlineStyle is DWT.UNDERLINE_ERROR || style.underlineStyle is DWT.UNDERLINE_SQUIGGLE)&& OS.GTK_VERSION < OS.buildVERSION(2, 4, 0)) drawUnderline = true;
+        if (drawUnderline && !style.isAdherentUnderline(styles[i+1].style)) {
+            int start = styles[i].start;
+            for (int j = i; j > 0 && style.isAdherentUnderline(styles[j-1].style); j--) {
+                start = styles[j - 1].start;
+            }
+            start = translateOffset(start);
+            int end = translateOffset(styles[i+1].start - 1);
+            int byteStart = cast(int)/*64*/(OS.g_utf8_offset_to_pointer(ptr, start) - ptr);
+            int byteEnd = cast(int)/*64*/(OS.g_utf8_offset_to_pointer(ptr, end + 1) - ptr);
+            int[] ranges = [byteStart, byteEnd];
+            auto rgn = OS.gdk_pango_layout_get_clip_region(layout, x, y, ranges.ptr, ranges.length / 2);
+            if (rgn !is null) {
+                int nRects;
+                GdkRectangle* rects;
+                OS.gdk_region_get_rectangles(rgn, &rects, &nRects);
+                GdkRectangle rect;
+                GdkColor* color = null;
+                if (color is null && style.underlineColor !is null) color = style.underlineColor.handle;
+                if (color is null && selectionColor !is null) color = selectionColor;
+                if (color is null && style.foreground !is null) color = style.foreground.handle;
+                if (color is null) color = data.foreground;
+                if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+                    Cairo.cairo_set_source_rgba(cairo, (color.red & 0xFFFF) / cast(float)0xFFFF, (color.green & 0xFFFF) / cast(float)0xFFFF, (color.blue & 0xFFFF) / cast(float)0xFFFF, data.alpha / cast(float)0xFF);
+                } else {
+                    if (gcValues is null) {
+                        gcValues = new GdkGCValues();
+                        OS.gdk_gc_get_values(gdkGC, gcValues);
+                    }
+                    OS.gdk_gc_set_foreground(gdkGC, color);
+                }
+                int underlinePosition = -1;
+                int underlineThickness = 1;
+                if (OS.GTK_VERSION >= OS.buildVERSION(2, 6, 0)) {
+                    Font font = style.font;
+                    if (font is null) font = this.font;
+                    if (font is null) font = device.systemFont;
+                    auto lang = OS.pango_context_get_language(context);
+                    auto metrics = OS.pango_context_get_metrics(context, font.handle, lang);
+                    underlinePosition = OS.PANGO_PIXELS(OS.pango_font_metrics_get_underline_position(metrics));
+                    underlineThickness = OS.PANGO_PIXELS(OS.pango_font_metrics_get_underline_thickness(metrics));
+                    OS.pango_font_metrics_unref(metrics);
+                }
+                for (int j=0; j<nRects; j++) {
+                    rect = rects[j];
+                    int offset = getOffset(rect.x - x, rect.y - y, null);
+                    int lineIndex = getLineIndex(offset);
+                    FontMetrics metrics = getLineMetrics(lineIndex);
+                    int underlineY = rect.y + metrics.ascent - underlinePosition - style.rise;
+                    switch (style.underlineStyle) {
+                        case DWT.UNDERLINE_SQUIGGLE:
+                        case DWT.UNDERLINE_ERROR: {
+                            int squigglyThickness = underlineThickness;
+                            int squigglyHeight = 2 * squigglyThickness;
+                            int squigglyY = Math.min(underlineY, rect.y + rect.height - squigglyHeight - 1);
+                            int[] points = computePolyline(rect.x, squigglyY, rect.x + rect.width, squigglyY + squigglyHeight);
+                            if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+                                Cairo.cairo_set_line_width(cairo, squigglyThickness);
+                                Cairo.cairo_set_line_cap(cairo, Cairo.CAIRO_LINE_CAP_BUTT);
+                                Cairo.cairo_set_line_join(cairo, Cairo.CAIRO_LINE_JOIN_MITER);
+                                if (points.length > 0) {
+                                    double xOffset = 0.5, yOffset = 0.5;
+                                    Cairo.cairo_move_to(cairo, points[0] + xOffset, points[1] + yOffset);
+                                    for (int k = 2; k < points.length; k += 2) {
+                                        Cairo.cairo_line_to(cairo, points[k] + xOffset, points[k + 1] + yOffset);
+                                    }
+                                    Cairo.cairo_stroke(cairo);
+                                }
+                            } else {
+                                OS.gdk_gc_set_line_attributes(gdkGC, squigglyThickness, OS.GDK_LINE_SOLID, OS.GDK_CAP_BUTT, OS.GDK_JOIN_MITER);
+                                OS.gdk_draw_lines(data.drawable, gdkGC, cast(GdkPoint*)points.ptr, points.length / 2);
+                            }
+                            break;
+                        }
+                        case DWT.UNDERLINE_DOUBLE:
+                            if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+                                Cairo.cairo_rectangle(cairo, rect.x, underlineY + underlineThickness * 2, rect.width, underlineThickness);
+                                Cairo.cairo_fill(cairo);
+                            } else {
+                                OS.gdk_draw_rectangle(data.drawable, gdkGC, 1, rect.x, underlineY + underlineThickness * 2, rect.width, underlineThickness);
+                            }
+                            //FALLTHROUGH
+                        case DWT.UNDERLINE_SINGLE:
+                            if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+                                Cairo.cairo_rectangle(cairo, rect.x, underlineY, rect.width, underlineThickness);
+                                Cairo.cairo_fill(cairo);
+                            } else {
+                                OS.gdk_draw_rectangle(data.drawable, gdkGC, 1, rect.x, underlineY, rect.width, underlineThickness);
+                            }
+                            break;
+                    }
+                }
+                if (rects !is null) OS.g_free(rects);
+                OS.gdk_region_destroy(rgn);
+            }
+        }
+
+        bool drawStrikeout = false;
+        if (style.strikeout && style.strikeoutColor !is null) drawStrikeout = true;
+        if (drawStrikeout && !style.isAdherentStrikeout(styles[i+1].style)) {
+            int start = styles[i].start;
+            for (int j = i; j > 0 && style.isAdherentStrikeout(styles[j-1].style); j--) {
+                start = styles[j - 1].start;
+            }
+            start = translateOffset(start);
+            int end = translateOffset(styles[i+1].start - 1);
+            int byteStart = cast(int)/*64*/(OS.g_utf8_offset_to_pointer(ptr, start) - ptr);
+            int byteEnd = cast(int)/*64*/(OS.g_utf8_offset_to_pointer(ptr, end + 1) - ptr);
+            int[] ranges = [byteStart, byteEnd];
+            auto rgn = OS.gdk_pango_layout_get_clip_region(layout, x, y, ranges.ptr, ranges.length / 2);
+            if (rgn !is null) {
+                int nRects;
+                GdkRectangle* rects;
+                OS.gdk_region_get_rectangles(rgn, &rects, &nRects);
+                GdkRectangle rect;
+                GdkColor* color = null;
+                if (color is null && style.strikeoutColor !is null) color = style.strikeoutColor.handle;
+                if (color is null && selectionColor !is null) color = selectionColor;
+                if (color is null && style.foreground !is null) color = style.foreground.handle;
+                if (color is null) color = data.foreground;
+                if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+                    Cairo.cairo_set_source_rgba(cairo, (color.red & 0xFFFF) / cast(float)0xFFFF, (color.green & 0xFFFF) / cast(float)0xFFFF, (color.blue & 0xFFFF) / cast(float)0xFFFF, data.alpha / cast(float)0xFF);
+                } else {
+                    if (gcValues is null) {
+                        gcValues = new GdkGCValues();
+                        OS.gdk_gc_get_values(gdkGC, gcValues);
+                    }
+                    OS.gdk_gc_set_foreground(gdkGC, color);
+                }
+                int strikeoutPosition = -1;
+                int strikeoutThickness = 1;
+                if (OS.GTK_VERSION >= OS.buildVERSION(2, 6, 0)) {
+                    Font font = style.font;
+                    if (font is null) font = this.font;
+                    if (font is null) font = device.systemFont;
+                    auto lang = OS.pango_context_get_language(context);
+                    auto metrics = OS.pango_context_get_metrics(context, font.handle, lang);
+                    strikeoutPosition = OS.PANGO_PIXELS(OS.pango_font_metrics_get_strikethrough_position(metrics));
+                    strikeoutThickness = OS.PANGO_PIXELS(OS.pango_font_metrics_get_strikethrough_thickness(metrics));
+                    OS.pango_font_metrics_unref(metrics);
+                }
+                for (int j=0; j<nRects; j++) {
+                    rect = rects[j];
+                    int strikeoutY = rect.y + rect.height / 2 - style.rise;
+                    if (OS.GTK_VERSION >= OS.buildVERSION(2, 6, 0)) {
+                        int offset = getOffset(rect.x - x, rect.y - y, null);
+                        int lineIndex = getLineIndex(offset);
+                        FontMetrics metrics = getLineMetrics(lineIndex);
+                        strikeoutY = rect.y + metrics.ascent - strikeoutPosition - style.rise;
+                    }
+                    if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+                        Cairo.cairo_rectangle(cairo, rect.x, strikeoutY, rect.width, strikeoutThickness);
+                        Cairo.cairo_fill(cairo);
+                    } else {
+                        OS.gdk_draw_rectangle(data.drawable, gdkGC, 1, rect.x, strikeoutY, rect.width, strikeoutThickness);
+                    }
+                }
+                if (rects !is null) OS.g_free(rects);
+                OS.gdk_region_destroy(rgn);
+            }
+        }
+    }
+    if (gcValues !is null) {
+        int mask = OS.GDK_GC_FOREGROUND | OS.GDK_GC_LINE_WIDTH | OS.GDK_GC_LINE_STYLE | OS.GDK_GC_CAP_STYLE | OS.GDK_GC_JOIN_STYLE;
+        OS.gdk_gc_set_values(gdkGC, gcValues, mask);
+        data.state &= ~GC.LINE_STYLE;
+    }
+    if (cairo !is null && OS.GTK_VERSION >= OS.buildVERSION(2, 8, 0)) {
+        Cairo.cairo_restore(cairo);
+    }
+}
+
 void freeRuns() {
     if (attrList is null) return;
     OS.pango_layout_set_attributes(layout, null );
@@ -523,12 +851,13 @@
 public int getAlignment() {
     checkLayout();
     auto alignment = OS.pango_layout_get_alignment(layout);
+    bool rtl = OS.pango_context_get_base_dir(context) is OS.PANGO_DIRECTION_RTL;
     switch ( cast(int)alignment) {
-        case OS.PANGO_ALIGN_CENTER: return DWT.CENTER;
-        case OS.PANGO_ALIGN_RIGHT: return DWT.RIGHT;
+        case OS.PANGO_ALIGN_LEFT: return rtl ? DWT.RIGHT : DWT.LEFT;
+        case OS.PANGO_ALIGN_RIGHT: return rtl ? DWT.LEFT : DWT.RIGHT;
         default:
     }
-    return DWT.LEFT;
+    return DWT.CENTER;
 }
 
 /**
@@ -565,7 +894,8 @@
     int w, h;
     OS.pango_layout_get_size(layout, &w, &h);
     int wrapWidth = OS.pango_layout_get_width(layout);
-    int width = OS.PANGO_PIXELS(wrapWidth !is -1 ? wrapWidth : w);
+    w = wrapWidth !is -1 ? wrapWidth : w + OS.pango_layout_get_indent(layout);
+    int width = OS.PANGO_PIXELS(w);
     int height = OS.PANGO_PIXELS(h);
     if (ascent !is -1 && descent !is -1) {
         height = Math.max (height, ascent + descent);
@@ -590,11 +920,11 @@
 public Rectangle getBounds(int start, int end) {
     checkLayout();
     computeRuns();
-    int length = text.length;
-    if (length is 0) return new Rectangle(0, 0, 0, 0);
+    int length_ = text.length;
+    if (length_ is 0) return new Rectangle(0, 0, 0, 0);
     if (start > end) return new Rectangle(0, 0, 0, 0);
-    start = Math.min(Math.max(0, start), length - 1);
-    end = Math.min(Math.max(0, end), length - 1);
+    start = Math.min(Math.max(0, start), length_ - 1);
+    end = Math.min(Math.max(0, end), length_ - 1);
     start = translateOffset(start);
     end = translateOffset(end);
     auto ptr = OS.pango_layout_get_text(layout);
@@ -646,6 +976,9 @@
 
     OS.gdk_region_get_clipbox(clipRegion, &rect);
     OS.gdk_region_destroy(clipRegion);
+    if (OS.pango_context_get_base_dir(context) is OS.PANGO_DIRECTION_RTL) {
+        rect.x = width() - rect.x - rect.width;
+    }
     return new Rectangle(rect.x, rect.y, rect.width, rect.height);
 }
 
@@ -732,8 +1065,8 @@
 public int getLevel(int offset) {
     checkLayout();
     computeRuns();
-    int length = text.length;
-    if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+    int length_ = text.length;
+    if (!(0 <= offset && offset <= length_)) DWT.error(DWT.ERROR_INVALID_RANGE);
     offset = translateOffset(offset);
     auto iter = OS.pango_layout_get_iter(layout);
     if (iter is null) DWT.error(DWT.ERROR_NO_HANDLES);
@@ -785,12 +1118,15 @@
     OS.pango_layout_iter_free(iter);
     int x = OS.PANGO_PIXELS(rect.x);
     int y = OS.PANGO_PIXELS(rect.y);
-    int width = OS.PANGO_PIXELS(rect.width);
+    int width_ = OS.PANGO_PIXELS(rect.width);
     int height = OS.PANGO_PIXELS(rect.height);
     if (ascent !is -1 && descent !is -1) {
         height = Math.max (height, ascent + descent);
     }
-    return new Rectangle(x, y, width, height);
+    if (OS.pango_context_get_base_dir(context) is OS.PANGO_DIRECTION_RTL) {
+        x = width() - x - width_;
+    }
+    return new Rectangle(x, y, width_, height);
 }
 
 /**
@@ -826,8 +1162,8 @@
 public int getLineIndex(int offset) {
     checkLayout ();
     computeRuns();
-    int length = text.length;
-    if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    int length_ = text.length;
+    if (!(0 <= offset && offset <= length_)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     offset = translateOffset(offset);
     int line = 0;
     auto ptr = OS.pango_layout_get_text(layout);
@@ -900,15 +1236,11 @@
     int lineCount = OS.pango_layout_get_line_count(layout);
     int[] offsets = new int [lineCount + 1];
     auto ptr = OS.pango_layout_get_text(layout);
-    auto iter = OS.pango_layout_get_iter(layout);
-    if (iter is null) DWT.error(DWT.ERROR_NO_HANDLES);
-    int i = 0;
-    do {
-        int bytePos = OS.pango_layout_iter_get_index(iter);
-        int pos = bytePos;//OS.g_utf8_pointer_to_offset(ptr, ptr + bytePos);
-        offsets[i++] = untranslateOffset(pos);
-    } while (OS.pango_layout_iter_next_line(iter));
-    OS.pango_layout_iter_free(iter);
+    for (int i = 0; i < lineCount; i++) {
+        auto line = OS.pango_layout_get_line(layout, i);
+        int pos = cast(int)/*64*/OS.g_utf8_pointer_to_offset(ptr, ptr + line.start_index);
+        offsets[i] = untranslateOffset(pos);
+    }
     offsets[lineCount] = text.length;
     return offsets;
 }
@@ -932,8 +1264,8 @@
 public Point getLocation(int offset, bool trailing) {
     checkLayout();
     computeRuns();
-    int length = text.length;
-    if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+    int length_ = text.length;
+    if (!(0 <= offset && offset <= length_)) DWT.error(DWT.ERROR_INVALID_RANGE);
     offset = translateOffset(offset);
     auto ptr = OS.pango_layout_get_text(layout);
     auto cont = fromStringz(ptr);
@@ -946,7 +1278,11 @@
     OS.pango_layout_index_to_pos(layout, byteOffset, pos);
     int x = trailing ? pos.x + pos.width : pos.x;
     int y = pos.y;
-    return new Point(OS.PANGO_PIXELS(x), OS.PANGO_PIXELS(y));
+    x = OS.PANGO_PIXELS(x);
+    if (OS.pango_context_get_base_dir(context) is OS.PANGO_DIRECTION_RTL) {
+        x = width() - x;
+    }
+    return new Point(x, OS.PANGO_PIXELS(y));
 }
 
 /**
@@ -975,10 +1311,10 @@
 int _getOffset (int offset, int movement, bool forward) {
     checkLayout();
     computeRuns();
-    int length = text.length;
-    if (!(0 <= offset && offset <= length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+    int length_ = text.length;
+    if (!(0 <= offset && offset <= length_)) DWT.error(DWT.ERROR_INVALID_RANGE);
     if (forward) {
-        if (offset is length) return length;
+        if (offset is length_) return length_;
     } else {
         if (offset is 0) return 0;
     }
@@ -997,12 +1333,12 @@
     int nAttrs;
     OS.pango_layout_get_log_attrs(layout, &attrs, &nAttrs);
     if (attrs is null) return offset + step;
-    length = OS.g_utf8_strlen(cont, -1);
+    length_ = OS.g_utf8_strlen(cont, -1);
     offset = translateOffset(offset);
     offset = dcont.utf8AdjustOffset( offset );
     PangoLogAttr* logAttr = new PangoLogAttr();
     offset = validateOffset( dcont, offset, step);
-    while (0 < offset && offset < length) {
+    while (0 < offset && offset < length_) {
         *logAttr = attrs[ offset ];
         if (((movement & DWT.MOVEMENT_CLUSTER) !is 0) && ( logAttr.bitfield0 & (1<<4/*is_cursor_position*/))) break;
         if ((movement & DWT.MOVEMENT_WORD) !is 0) {
@@ -1080,6 +1416,9 @@
     checkLayout();
     computeRuns();
     if (trailing !is null && trailing.length < 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    if (OS.pango_context_get_base_dir(context) is OS.PANGO_DIRECTION_RTL) {
+        x = width() - x;
+    }
 
     /*
     * Feature in GTK.  pango_layout_xy_to_index() returns the
@@ -1257,8 +1596,8 @@
  */
 public TextStyle getStyle (int offset) {
     checkLayout();
-    int length = text.length;
-    if (!(0 <= offset && offset < length)) DWT.error(DWT.ERROR_INVALID_RANGE);
+    int length_ = text.length;
+    if (!(0 <= offset && offset < length_)) DWT.error(DWT.ERROR_INVALID_RANGE);
     for (int i=1; i<styles.length; i++) {
         StyleItem item = styles[i];
         if (item.start > offset) {
@@ -1382,13 +1721,17 @@
     if (alignment is 0) return;
     if ((alignment & DWT.LEFT) !is 0) alignment = DWT.LEFT;
     if ((alignment & DWT.RIGHT) !is 0) alignment = DWT.RIGHT;
-    int al = OS.PANGO_ALIGN_LEFT;
+    bool rtl = OS.pango_context_get_base_dir(context) is OS.PANGO_DIRECTION_RTL;
+    int align_ = OS.PANGO_ALIGN_CENTER;
     switch (alignment) {
-        case DWT.CENTER: al = OS.PANGO_ALIGN_CENTER; break;
-        case DWT.RIGHT: al = OS.PANGO_ALIGN_RIGHT; break;
-        default:
+        case DWT.LEFT:
+            align_ = rtl ? OS.PANGO_ALIGN_RIGHT : OS.PANGO_ALIGN_LEFT;
+            break;
+        case DWT.RIGHT:
+            align_ = rtl ? OS.PANGO_ALIGN_LEFT : OS.PANGO_ALIGN_RIGHT;
+            break;
     }
-    OS.pango_layout_set_alignment(layout, al);
+    OS.pango_layout_set_alignment(layout, align_);
 }
 
 /**
@@ -1462,13 +1805,13 @@
 public void setFont (Font font) {
     checkLayout ();
     if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    if (this.font is font) return;
-    if (font !is null && font.opEquals(this.font)) return;
+    Font oldFont = this.font;
+    if (oldFont is font) return;
     this.font = font;
-    OS.pango_layout_set_font_description(layout, font !is null ? font.handle : null);
+    if (oldFont !is null && oldFont.opEquals(font)) return;
+    OS.pango_layout_set_font_description(layout, font !is null ? font.handle : device.systemFont.handle);
 }
 
-
 /**
  * Sets the indent of the receiver. This indent it applied of the first line of
  * each paragraph.
@@ -1524,6 +1867,11 @@
     if (OS.pango_context_get_base_dir(context) is baseDir) return;
     OS.pango_context_set_base_dir(context, baseDir);
     OS.pango_layout_context_changed(layout);
+    int align_ = OS.pango_layout_get_alignment(layout);
+    if (align_ !is OS.PANGO_ALIGN_CENTER) {
+        align_ = align_ is OS.PANGO_ALIGN_LEFT ? OS.PANGO_ALIGN_RIGHT : OS.PANGO_ALIGN_LEFT;
+        OS.pango_layout_set_alignment(layout, align_);
+    }
 }
 
 /**
@@ -1594,11 +1942,11 @@
  */
 public void setStyle (TextStyle style, int start, int end) {
     checkLayout();
-    int length = text.length;
-    if (length is 0) return;
+    int length_ = text.length;
+    if (length_ is 0) return;
     if (start > end) return;
-    start = Math.min(Math.max(0, start), length - 1);
-    end = Math.min(Math.max(0, end), length - 1);
+    start = Math.min(Math.max(0, start), length_ - 1);
+    end = Math.min(Math.max(0, end), length_ - 1);
     start = text.utf8AdjustOffset( start );
     end = text.utf8AdjustOffset( end );
 
@@ -1614,7 +1962,7 @@
     if ((start > 0 ) && isAlef(text[ start .. $ ].firstCodePoint()) && isLam(text.getRelativeCodePoint( start, -1, relIndex ))) {
         start += relIndex;
     }
-    if ((end < length - 1) && isLam(text[ end .. $ ].firstCodePoint()) && isAlef(text.getRelativeCodePoint(end, 1,relIndex))) {
+    if ((end < length_ - 1) && isLam(text[ end .. $ ].firstCodePoint()) && isAlef(text.getRelativeCodePoint(end, 1,relIndex))) {
         end += relIndex;
     }
 
@@ -1766,7 +2114,13 @@
     checkLayout ();
     if (width < -1 || width is 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     freeRuns();
-    OS.pango_layout_set_width(layout, width is -1 ? -1 : width * OS.PANGO_SCALE);
+    if (width is -1) {
+        OS.pango_layout_set_width(layout, -1);
+        bool rtl = OS.pango_context_get_base_dir(context) is OS.PANGO_DIRECTION_RTL;
+        OS.pango_layout_set_alignment(layout, rtl ? OS.PANGO_ALIGN_RIGHT : OS.PANGO_ALIGN_LEFT);
+    } else {
+        OS.pango_layout_set_width(layout, width * OS.PANGO_SCALE);
+    }
 }
 
 static final bool isLam(int ch) {
@@ -1806,8 +2160,8 @@
  *  Translate a client offset to an internal offset
  */
 int translateOffset(int offset) {
-    int length = text.length;
-    if (length is 0) return offset;
+    int length_ = text.length;
+    if (length_ is 0) return offset;
     if (invalidOffsets is null) return offset;
     for (int i = 0; i < invalidOffsets.length; i++) {
         if (offset < invalidOffsets[i]) break;
@@ -1820,8 +2174,8 @@
  *  Translate an internal offset to a client offset
  */
 int untranslateOffset(int offset) {
-    int length = text.length;
-    if (length is 0) return offset;
+    int length_ = text.length;
+    if (length_ is 0) return offset;
     if (invalidOffsets is null) return offset;
     for (int i = 0; i < invalidOffsets.length; i++) {
         if (offset is invalidOffsets[i]) {
@@ -1853,4 +2207,12 @@
     return offset;
 }
 
+int width () {
+    int wrapWidth = OS.pango_layout_get_width(layout);
+    if (wrapWidth !is -1) return OS.PANGO_PIXELS(wrapWidth);
+    int w, h;
+    OS.pango_layout_get_size(layout, &w, &h);
+    return OS.PANGO_PIXELS(w + OS.pango_layout_get_indent(layout));
 }
+
+}
--- a/dwt/graphics/TextStyle.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/TextStyle.d	Mon May 12 19:13:01 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * 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
@@ -59,13 +59,40 @@
     public Color background;
 
     /**
-     * the underline flag of the style
+     * the underline flag of the style. The default underline
+     * style is <code>DWT.UNDERLINE_SINGLE</code>.
+     *
      *
      * @since 3.1
      */
     public bool underline;
 
     /**
+     * the underline color of the style
+     *
+     * @since 3.4
+     */
+    public Color underlineColor;
+
+    /**
+     * the underline style. This style is ignored when
+     * <code>underline</code> is false.
+     * <p>
+     * This value should be one of <code>DWT.UNDERLINE_SINGLE</code>,
+     * <code>DWT.UNDERLINE_DOUBLE</code>, <code>DWT.UNDERLINE_ERROR</code>,
+     * or <code>DWT.UNDERLINE_SQUIGGLE</code>.
+     * </p>
+     *
+     * @see DWT#UNDERLINE_SINGLE
+     * @see DWT#UNDERLINE_DOUBLE
+     * @see DWT#UNDERLINE_ERROR
+     * @see DWT#UNDERLINE_SQUIGGLE
+     *
+     * @since 3.4
+     */
+    public int underlineStyle;
+
+    /**
      * the strikeout flag of the style
      *
      * @since 3.1
@@ -73,6 +100,37 @@
     public bool strikeout;
 
     /**
+     * the strikeout color of the style
+     *
+     * @since 3.4
+     */
+    public Color strikeoutColor;
+
+    /**
+     * the border style. The default border style is <code>DWT.NONE</code>.
+     * <p>
+     * This value should be one of <code>DWT.BORDER_SOLID</code>,
+     * <code>DWT.BORDER_DASH</code>,<code>DWT.BORDER_DOT</code> or
+     * <code>DWT.NONE</code>.
+     * </p>
+     *
+     * @see DWT#BORDER_SOLID
+     * @see DWT#BORDER_DASH
+     * @see DWT#BORDER_DOT
+     * @see DWT#NONE
+     *
+     * @since 3.4
+     */
+    public int borderStyle;
+
+    /**
+     * the border color of the style
+     *
+     * @since 3.4
+     */
+    public Color borderColor;
+
+    /**
      * the GlyphMetrics of the style
      *
      * @since 3.2
@@ -86,17 +144,12 @@
      */
     public int rise;
 
-/++
- + DWT extension for clone implementation
- +/
-protected this( TextStyle other ){
-    font = other.font;
-    foreground = other.foreground;
-    background = other.background;
-    underline = other.underline;
-    strikeout = other.strikeout;
-    metrics = other.metrics;
-    rise = other.rise;
+/**
+ * Create an empty text style.
+ *
+ * @since 3.4
+ */
+public this () {
 }
 
 /**
@@ -116,6 +169,30 @@
     this.background = background;
 }
 
+
+/**
+ * Create a new text style from an existing text style.
+ *
+ *@param style the style to copy
+ *
+ * @since 3.4
+ */
+public this (TextStyle style) {
+    if (style is null) DWT.error (DWT.ERROR_INVALID_ARGUMENT);
+    font = style.font;
+    foreground = style.foreground;
+    background = style.background;
+    underline = style.underline;
+    underlineColor = style.underlineColor;
+    underlineStyle = style.underlineStyle;
+    strikeout = style.strikeout;
+    strikeoutColor = style.strikeoutColor;
+    borderStyle = style.borderStyle;
+    borderColor = style.borderColor;
+    metrics = style.metrics;
+    rise = style.rise;
+}
+
 /**
  * Compares the argument to the receiver, and returns true
  * if they represent the <em>same</em> object using a class
@@ -142,8 +219,20 @@
     } else if (style.font !is null) return false;
     if (metrics !is null || style.metrics !is null) return false;
     if (underline !is style.underline) return false;
+    if (underlineStyle !is style.underlineStyle) return false;
+    if (borderStyle !is style.borderStyle) return false;
     if (strikeout !is style.strikeout) return false;
     if (rise !is style.rise) return false;
+    if (underlineColor !is null) {
+        if (!underlineColor.opEquals(style.underlineColor)) return false;
+    } else if (style.underlineColor !is null) return false;
+    if (strikeoutColor !is null) {
+        if (!strikeoutColor.opEquals(style.strikeoutColor)) return false;
+    } else if (style.strikeoutColor !is null) return false;
+    if (underlineStyle !is style.underlineStyle) return false;
+    if (borderColor !is null) {
+        if (!borderColor.opEquals(style.borderColor)) return false;
+    } else if (style.borderColor !is null) return false;
     return true;
 }
 
@@ -166,9 +255,44 @@
     if (underline) hash ^= hash;
     if (strikeout) hash ^= hash;
     hash ^= rise;
+    if (underlineColor !is null) hash ^= underlineColor.toHash();
+    if (strikeoutColor !is null) hash ^= strikeoutColor.toHash();
+    if (borderColor !is null) hash ^= borderColor.toHash();
+    hash ^= underlineStyle;
     return hash;
 }
 
+bool isAdherentBorder(TextStyle style) {
+    if (this is style) return true;
+    if (style is null) return false;
+    if (borderStyle !is style.borderStyle) return false;
+    if (borderColor !is null) {
+        if (!borderColor.opEquals(style.borderColor)) return false;
+    } else if (style.borderColor !is null) return false;
+    return true;
+}
+
+bool isAdherentUnderline(TextStyle style) {
+    if (this is style) return true;
+    if (style is null) return false;
+    if (underline !is style.underline) return false;
+    if (underlineStyle !is style.underlineStyle) return false;
+    if (underlineColor !is null) {
+        if (!underlineColor.opEquals(style.underlineColor)) return false;
+    } else if (style.underlineColor !is null) return false;
+    return true;
+}
+
+bool isAdherentStrikeout(TextStyle style) {
+    if (this is style) return true;
+    if (style is null) return false;
+    if (strikeout !is style.strikeout) return false;
+    if (strikeoutColor !is null) {
+        if (!strikeoutColor.opEquals(style.strikeoutColor)) return false;
+    } else if (style.strikeoutColor !is null) return false;
+    return true;
+}
+
 /**
  * Returns a string containing a concise, human-readable
  * description of the receiver.
--- a/dwt/graphics/Transform.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/graphics/Transform.d	Mon May 12 19:13:01 2008 +0200
@@ -135,14 +135,12 @@
  * @see #dispose()
  */
 public this (Device device, float m11, float m12, float m21, float m22, float dx, float dy) {
-    if (device is null) device = Device.getDevice();
-    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    this.device = device;
-    device.checkCairo();
+    super(device);
+    this.device.checkCairo();
     handle = new double[6];
     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
     Cairo.cairo_matrix_init( cast(cairo_matrix_t*)handle.ptr, m11, m12, m21, m22, dx, dy);
-    if (device.tracking) device.new_Object(this);
+    init_();
 }
 
 static float[] checkTransform(float[] elements) {
@@ -151,17 +149,8 @@
     return elements;
 }
 
-/**
- * Disposes of the operating system resources associated with
- * the Transform. Applications must dispose of all Transforms that
- * they allocate.
- */
-public override void dispose() {
-    if (handle is null) return;
-    if (device.isDisposed()) return;
+void destroy() {
     handle = null;
-    if (device.tracking) device.dispose_Object(this);
-    device = null;
 }
 
 /**
@@ -190,6 +179,11 @@
     elements[5] = cast(float)handle[5];
 }
 
+public void identity() {
+    if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    Cairo.cairo_matrix_init(cast(cairo_matrix_t*)handle.ptr, 1, 0, 0, 1, 0, 0);
+}
+
 /**
  * Modifies the receiver such that the matrix it represents becomes the
  * the mathematical inverse of the matrix it previously represented.
@@ -309,6 +303,12 @@
     Cairo.cairo_matrix_init(cast(cairo_matrix_t*)handle.ptr, m11, m12, m21, m22, dx, dy);
 }
 
+public void shear(float shearX, float shearY) {
+    if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    double[] matrix = [ 1.0, shearX, shearY, 1, 0, 0];
+    Cairo.cairo_matrix_multiply(cast(cairo_matrix_t*)handle.ptr, cast(cairo_matrix_t*)matrix.ptr, cast(cairo_matrix_t*)handle.ptr);
+}
+
 /**
  * Given an array containing points described by alternating x and y values,
  * modify that array such that each point has been replaced with the result of
--- a/dwt/internal/BidiUtil.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/BidiUtil.d	Mon May 12 19:13:01 2008 +0200
@@ -15,8 +15,9 @@
 import dwt.dwthelper.utils;
 
 import dwt.graphics.GC;
+import dwt.widgets.Control;
+import dwt.dwthelper.Runnable;
 import dwt.internal.gtk.OS;
-import dwt.dwthelper.Runnable;
 
 /*
  * This class is supplied so that the StyledText code that supports bidi text (supported
@@ -49,6 +50,8 @@
  */
 public static void addLanguageListener(GtkWidget* hwnd, Runnable runnable) {
 }
+public static void addLanguageListener (Control control, Runnable runnable) {
+}
 /*
  * Not implemented.
  *
@@ -98,6 +101,8 @@
  */
 public static void removeLanguageListener(GtkWidget* hwnd) {
 }
+public static void removeLanguageListener (Control control) {
+}
 /*
  * Not implemented.
  */
@@ -109,4 +114,7 @@
 public static bool setOrientation(GtkWidget* hwnd, int orientation) {
     return false;
 }
+public static bool setOrientation (Control control, int orientation) {
+    return false;
 }
+}
--- a/dwt/internal/Compatibility.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/Compatibility.d	Mon May 12 19:13:01 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * 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
@@ -13,12 +13,12 @@
 module dwt.internal.Compatibility;
 
 import dwt.dwthelper.utils;
-
 /+
-import java.io.*;
+import java.io.File;
 import java.text.MessageFormat;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
+import java.util.zip.DeflaterOutputStream;
 import java.util.zip.InflaterInputStream;
 +/
 
@@ -26,6 +26,7 @@
 public import dwt.dwthelper.FileInputStream;
 public import dwt.dwthelper.FileOutputStream;
 public import dwt.dwthelper.InflaterInputStream;
+import dwt.dwthelper.BufferedInputStream;
 
 import Math = tango.math.Math;
 import Unicode = tango.text.Unicode;
@@ -110,6 +111,17 @@
 }
 
 /**
+ * Answers whether the indicated file exists or not.
+ *
+ * @param parent the file's parent directory
+ * @param child the file's name
+ * @return true if the file exists
+ */
+public static bool fileExists(String parent, String child) {
+    return (new File (parent, child)).exists();
+}
+
+/**
  * Answers the most positive (i.e. closest to positive infinity)
  * integer value which is less than the number obtained by dividing
  * the first argument p by the second argument q.
@@ -159,6 +171,21 @@
 }
 
 /**
+ * Create an DeflaterOutputStream if such things are supported.
+ *
+ * @param stream the output stream
+ * @return a deflater stream or <code>null</code>
+ * @exception IOException
+ *
+ * @since 3.4
+ */
+public static OutputStream newDeflaterOutputStream(OutputStream stream) {
+    implMissing(__FILE__,__LINE__);
+    return null;
+    //DWT_TODO return new DeflaterOutputStream(stream);
+}
+
+/**
  * Open a file if such things are supported.
  *
  * @param filename the name of the file to open
--- a/dwt/internal/DWTMessages.properties	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/DWTMessages.properties	Mon May 12 19:13:01 2008 +0200
@@ -71,3 +71,5 @@
 SWT_Download_Location=Saving {0} from {1}
 SWT_Download_Started=Downloading...
 SWT_Download_Status=Download: {0,number,integer} KB of {1,number,integer} KB
+SWT_Authentication_Required=Authentication Required
+SWT_Enter_Username_and_Password=Enter user name and password for {0} at {1}
--- a/dwt/internal/LONG.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/LONG.d	Mon May 12 19:13:01 2008 +0200
@@ -12,24 +12,6 @@
  *******************************************************************************/
 module dwt.internal.LONG;
 
-public class LONG {
-    public int /*long*/ value;
-
-    public this (int /*long*/ value) {
-        this.value = value;
-    }
+import dwt.dwthelper.utils;
 
-    public override int opEquals (Object object) {
-        if (object is this){
-            return true;
-        }
-        if ( auto obj = cast(LONG)object ) {
-            return obj.value == this.value;
-        }
-        return false;
-    }
-
-    public override hash_t toHash () {
-        return /*64*/value;
-    }
-}
+alias Integer LONG;
--- a/dwt/internal/Library.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/Library.d	Mon May 12 19:13:01 2008 +0200
@@ -35,7 +35,7 @@
     /**
      * DWT Minor version number (must be in the range 0..999)
      */
-    static const int MINOR_VERSION = 349;
+    static const int MINOR_VERSION = 442;
 
     /**
      * DWT revision number (must be >= 0)
@@ -179,6 +179,20 @@
  * @param mapName true if the name should be mapped, false otherwise
  */
 public static void loadLibrary (String name, boolean mapName) {
+    String prop = System.getProperty ("sun.arch.data.model"); //$NON-NLS-1$
+    if (prop is null) prop = System.getProperty ("com.ibm.vm.bitmode"); //$NON-NLS-1$
+    if (prop !is null) {
+        if ("32".equals (prop)) { //$NON-NLS-1$
+             if (0x1FFFFFFFFL is (int /*long*/)0x1FFFFFFFFL) {
+                throw new UnsatisfiedLinkError ("Cannot load 64-bit DWT libraries on 32-bit JVM"); //$NON-NLS-1$
+             }
+        }
+        if ("64".equals (prop)) { //$NON-NLS-1$
+            if (0x1FFFFFFFFL !is (int /*long*/)0x1FFFFFFFFL) {
+                throw new UnsatisfiedLinkError ("Cannot load 32-bit DWT libraries on 64-bit JVM"); //$NON-NLS-1$
+            }       
+        }
+    }
 
     /* Compute the library name and mapped name */
     String libName1, libName2, mappedName1, mappedName2;
--- a/dwt/internal/gtk/OS.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/gtk/OS.d	Mon May 12 19:13:01 2008 +0200
@@ -36,6 +36,7 @@
         dwt.internal.c.Xrender,
         dwt.internal.c.glib_object;
 
+static import tango.stdc.string;
 //version=GTK_DYN_LINK;
 
 public alias dwt.internal.c.glib_object.GPollFD GPollFD;
@@ -52,6 +53,9 @@
 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.glib_object.GSignalEmissionHook GSignalEmissionHook;
+public alias dwt.internal.c.glib_object.GSignalInvocationHint GSignalInvocationHint;
+public alias dwt.internal.c.glib_object.GValue GValue;
 
 public alias dwt.internal.c.gdk.GdkColor GdkColor;
 public alias dwt.internal.c.gdk.GdkRegion GdkRegion;
@@ -82,19 +86,21 @@
 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;
+public alias dwt.internal.c.pango.PangoAttrColor PangoAttrColor;
+public alias dwt.internal.c.pango.PangoAttribute PangoAttribute;
+public alias dwt.internal.c.pango.PangoAttrList PangoAttrList;
+public alias dwt.internal.c.pango.PangoAttrInt PangoAttrInt;
 public alias dwt.internal.c.pango.PangoContext PangoContext;
-public alias dwt.internal.c.pango.PangoLayout PangoLayout;
-public alias dwt.internal.c.pango.PangoAttrList PangoAttrList;
-public alias dwt.internal.c.pango.PangoFontFamily PangoFontFamily;
+public alias dwt.internal.c.pango.PangoFontDescription PangoFontDescription;
 public alias dwt.internal.c.pango.PangoFontFace PangoFontFace;
-public alias dwt.internal.c.pango.PangoRectangle PangoRectangle;
-public alias dwt.internal.c.pango.PangoAttribute PangoAttribute;
+public alias dwt.internal.c.pango.PangoFontFamily PangoFontFamily;
+public alias dwt.internal.c.pango.PangoItem PangoItem;
 public alias dwt.internal.c.pango.PangoLogAttr PangoLogAttr;
-public alias dwt.internal.c.pango.PangoItem PangoItem;
+public alias dwt.internal.c.pango.PangoLayout PangoLayout;
+public alias dwt.internal.c.pango.PangoLayoutLine PangoLayoutLine;
 public alias dwt.internal.c.pango.PangoLayoutRun PangoLayoutRun;
-public alias dwt.internal.c.pango.PangoLayoutLine PangoLayoutLine;
+public alias dwt.internal.c.pango.PangoRectangle PangoRectangle;
+public alias dwt.internal.c.pango.PangoTabArray PangoTabArray;
 
 public alias dwt.internal.c.cairo.cairo_t cairo_t;
 public alias dwt.internal.c.cairo.cairo_pattern_t cairo_pattern_t;
@@ -280,6 +286,7 @@
 public alias dwt.internal.c.gtk.GtkFileChooserButtonClass GtkFileChooserButtonClass;
 public alias dwt.internal.c.gtk.GtkFileChooserButton GtkFileChooserButton;
 public alias dwt.internal.c.gtk.GtkFileFilterInfo GtkFileFilterInfo;
+public alias dwt.internal.c.gtk.GtkFileFilter GtkFileFilter;
 public alias dwt.internal.c.gtk.GtkFixedChild GtkFixedChild;
 public alias dwt.internal.c.gtk.GtkFixedClass GtkFixedClass;
 public alias dwt.internal.c.gtk.GtkFixed GtkFixed;
@@ -497,6 +504,7 @@
 public alias dwt.internal.c.gtk.GtkEditable GtkEditable;
 public alias dwt.internal.c.gtk.GtkCallback GtkCallback;
 public alias dwt.internal.c.gtk.GtkAllocation GtkAllocation;
+public alias dwt.internal.c.gtk.GtkPageSetup GtkPageSetup;
 
 
 public alias dwt.internal.c.gtk_unix_print_2_0.GtkPrinter GtkPrinter;
@@ -552,6 +560,11 @@
     g_signal_emit_by_name( instance, detailed_signal, value1, value2, value3 );
 }
 
+private void gdk_pixbuf_save_to_buffer0(GdkPixbuf *pixbuf, char **buffer, uint *buffer_size,
+   char *type, GError **error ){
+    gdk_pixbuf_save_to_buffer( pixbuf, buffer, buffer_size, type, error );
+}
+
 private void gtk_list_store_set1(void* store , void* iter, int column, void* value ){
     gtk_list_store_set( cast(GtkListStore *)store, cast(GtkTreeIter *)iter, column, value, -1 );
 }
@@ -737,9 +750,14 @@
     public static const int GDK_FLEUR = 0x34;
     public static const int GDK_FOCUS_CHANGE = 0xc;
     public static const int GDK_FOCUS_CHANGE_MASK = 0x4000;
+    public static const int GDK_GC_FOREGROUND = 0x1;
     public static const int GDK_GC_CLIP_MASK = 0x80;
     public static const int GDK_GC_CLIP_X_ORIGIN = 0x800;
     public static const int GDK_GC_CLIP_Y_ORIGIN = 0x1000;
+    public static const int GDK_GC_LINE_WIDTH = 0x4000;
+    public static const int GDK_GC_LINE_STYLE = 0x8000;
+    public static const int GDK_GC_CAP_STYLE = 0x10000;
+    public static const int GDK_GC_JOIN_STYLE = 0x20000;
     public static const int GDK_GRAB_SUCCESS = 0x0;
     public static const int GDK_HAND2 = 0x3c;
     public static const int GDK_Help = 0xFF6A;
@@ -849,6 +867,7 @@
     public static const int GDK_WINDOW_CHILD = 2;
     public static const int GDK_WINDOW_STATE_ICONIFIED  = 1 << 1;
     public static const int GDK_WINDOW_STATE_MAXIMIZED  = 1 << 2;
+    public static const int GDK_WINDOW_STATE_FULLSCREEN  = 1 << 4;
     public static const int GTK_ACCEL_VISIBLE = 0x1;
     public static const int GTK_ARROW_DOWN = 0x1;
     public static const int GTK_ARROW_LEFT = 0x2;
@@ -913,6 +932,7 @@
     public static const int GTK_PROGRESS_LEFT_TO_RIGHT = 0x0;
     public static const int GTK_PROGRESS_BOTTOM_TO_TOP = 0x2;
     public static const int GTK_REALIZED  = 1 << 6;
+    public static const int GTK_RECEIVES_DEFAULT = 1 << 20;
     public static const int GTK_RELIEF_NONE = 0x2;
     public static const int GTK_RELIEF_NORMAL = 0;
     public static const int GTK_RC_BG = 1 << 1;
@@ -981,6 +1001,7 @@
     public static const int GDK_WINDOW_TYPE_HINT_DIALOG = 1;
     public static const int GTK_WRAP_NONE = 0;
     public static const int GTK_WRAP_WORD = 2;
+    public static const int GTK_WRAP_WORD_CHAR = 3;
     public static const int G_LOG_FLAG_FATAL = 0x2;
     public static const int G_LOG_FLAG_RECURSION = 0x1;
     public static const int G_LOG_LEVEL_MASK = 0xfffffffc;
@@ -988,6 +1009,10 @@
     public static const int PANGO_ALIGN_LEFT = 0;
     public static const int PANGO_ALIGN_CENTER = 1;
     public static const int PANGO_ALIGN_RIGHT = 2;
+    public static const int PANGO_ATTR_FOREGROUND = 9;
+    public static const int PANGO_ATTR_BACKGROUND = 10;
+    public static const int PANGO_ATTR_UNDERLINE = 11;
+    public static final int PANGO_ATTR_UNDERLINE_COLOR = 18;
     public static const int PANGO_DIRECTION_LTR = 0;
     public static const int PANGO_DIRECTION_RTL = 1;
     public static const int PANGO_SCALE = 1024;
@@ -996,8 +1021,11 @@
     public static const int PANGO_STYLE_NORMAL = 0x0;
     public static const int PANGO_STYLE_OBLIQUE = 0x1;
     public static const int PANGO_TAB_LEFT = 0;
+    public static const int PANGO_UNDERLINE_NONE = 0;
+    public static const int PANGO_UNDERLINE_SINGLE = 1;
+    public static const int PANGO_UNDERLINE_DOUBLE = 2;
     public static const int PANGO_UNDERLINE_LOW = 3;
-    public static const int PANGO_UNDERLINE_SINGLE = 1;
+    public static const int PANGO_UNDERLINE_ERROR = 4;
     public static const int PANGO_WEIGHT_BOLD = 0x2bc;
     public static const int PANGO_WEIGHT_NORMAL = 0x190;
     public static const int PANGO_WRAP_WORD = 0;
@@ -1050,6 +1078,7 @@
     public static const char[] move_focus = "move-focus";
     public static const char[] output = "output";
     public static const char[] popup_menu = "popup-menu";
+    public static final char[] populate_popup = "populate-popup";
     public static const char[] preedit_changed = "preedit-changed";
     public static const char[] realize = "realize";
     public static const char[] row_activated = "row-activated";
@@ -1186,6 +1215,7 @@
     mixin ForwardGtkOsCFunc!(.XFree);
     mixin ForwardGtkOsCFunc!(.XGetSelectionOwner);
     mixin ForwardGtkOsCFunc!(.XInternAtom);
+    mixin ForwardGtkOsCFunc!(.XQueryPointer);
     mixin ForwardGtkOsCFunc!(.XQueryTree);
     mixin ForwardGtkOsCFunc!(.XKeysymToKeycode);
     mixin ForwardGtkOsCFunc!(.XListProperties);
@@ -1225,6 +1255,8 @@
     mixin ForwardGtkOsCFunc!(.XRenderFindStandardFormat);
     mixin ForwardGtkOsCFunc!(.XRenderFindVisualFormat);
 
+    mixin ForwardGtkOsCFunc!(.g_signal_add_emission_hook);
+    mixin ForwardGtkOsCFunc!(.g_signal_remove_emission_hook);
     mixin ForwardGtkOsCFunc!(.g_cclosure_new);
     mixin ForwardGtkOsCFunc!(.g_closure_ref);
     mixin ForwardGtkOsCFunc!(.g_closure_unref);
@@ -1305,6 +1337,7 @@
     mixin ForwardGtkOsCFunc!(.g_utf8_pointer_to_offset);
     mixin ForwardGtkOsCFunc!(.g_utf8_strlen);
     mixin ForwardGtkOsCFunc!(.g_utf8_to_utf16);
+    mixin ForwardGtkOsCFunc!(.g_value_peek_pointer);
     mixin ForwardGtkOsCFunc!(.gdk_atom_intern);
     mixin ForwardGtkOsCFunc!(.gdk_atom_name);
     mixin ForwardGtkOsCFunc!(.gdk_beep);
@@ -1347,6 +1380,7 @@
     mixin ForwardGtkOsCFunc!(.gdk_event_get_state);
     mixin ForwardGtkOsCFunc!(.gdk_event_get_time);
     mixin ForwardGtkOsCFunc!(.gdk_event_handler_set);
+    mixin ForwardGtkOsCFunc!(.gdk_event_new);
     mixin ForwardGtkOsCFunc!(.gdk_event_peek);
     mixin ForwardGtkOsCFunc!(.gdk_event_put);
     mixin ForwardGtkOsCFunc!(.gdk_error_trap_push);
@@ -1386,11 +1420,16 @@
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_get_pixels);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_get_rowstride);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_get_width);
+    mixin ForwardGtkOsCFunc!(.gdk_pixbuf_loader_new);
+    mixin ForwardGtkOsCFunc!(.gdk_pixbuf_loader_close);
+    mixin ForwardGtkOsCFunc!(.gdk_pixbuf_loader_get_pixbuf);
+    mixin ForwardGtkOsCFunc!(.gdk_pixbuf_loader_write);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_new);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_new_from_file);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_render_to_drawable);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_render_to_drawable_alpha);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_render_pixmap_and_mask);
+    mixin ForwardGtkOsCFunc!(.gdk_pixbuf_save_to_buffer0);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_scale);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_scale_simple);
     mixin ForwardGtkOsCFunc!(.gdk_pixmap_new);
@@ -1425,7 +1464,8 @@
     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_text_property_to_utf8_list);
+    mixin ForwardGtkOsCFunc!(.gtk_tooltip_trigger_tooltip_query);
     mixin ForwardGtkOsCFunc!(.gdk_unicode_to_keyval);
     mixin ForwardGtkOsCFunc!(.gdk_visual_get_system);
     mixin ForwardGtkOsCFunc!(.gdk_window_at_pointer);
@@ -1447,6 +1487,7 @@
     mixin ForwardGtkOsCFunc!(.gdk_window_hide);
     mixin ForwardGtkOsCFunc!(.gdk_window_invalidate_rect);
     mixin ForwardGtkOsCFunc!(.gdk_window_invalidate_region);
+    mixin ForwardGtkOsCFunc!(.gdk_window_is_visible);
     mixin ForwardGtkOsCFunc!(.gdk_window_move);
     mixin ForwardGtkOsCFunc!(.gdk_window_new);
     mixin ForwardGtkOsCFunc!(.gdk_window_lower);
@@ -1515,6 +1556,7 @@
     mixin ForwardGtkOsCFunc!(.gtk_combo_disable_activate);
     mixin ForwardGtkOsCFunc!(.gtk_combo_new);
     mixin ForwardGtkOsCFunc!(.gtk_combo_set_case_sensitive);
+    mixin ForwardGtkOsCFunc!(.gtk_combo_box_set_focus_on_click);
     mixin ForwardGtkOsCFunc!(.gtk_combo_set_popdown_strings);
     mixin ForwardGtkOsCFunc!(.gtk_combo_box_entry_new_text);
     mixin ForwardGtkOsCFunc!(.gtk_combo_box_new_text);
@@ -1585,13 +1627,17 @@
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_get_current_folder);
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_get_filename);
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_get_filenames);
+    mixin ForwardGtkOsCFunc!(.gtk_file_chooser_get_filter);
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_set_current_folder);
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_set_current_name);
+    mixin ForwardGtkOsCFunc!(.gtk_file_chooser_set_do_overwrite_confirmation);
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_set_extra_widget);
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_set_filename);
+    mixin ForwardGtkOsCFunc!(.gtk_file_chooser_set_filter);
     mixin ForwardGtkOsCFunc!(.gtk_file_chooser_set_select_multiple);
     mixin ForwardGtkOsCFunc!(.gtk_file_filter_add_pattern);
     mixin ForwardGtkOsCFunc!(.gtk_file_filter_new);
+    mixin ForwardGtkOsCFunc!(.gtk_file_filter_get_name);
     mixin ForwardGtkOsCFunc!(.gtk_file_filter_set_name);
     mixin ForwardGtkOsCFunc!(.gtk_file_selection_get_filename);
     mixin ForwardGtkOsCFunc!(.gtk_file_selection_get_selections);
@@ -1652,6 +1698,7 @@
     mixin ForwardGtkOsCFunc!(.gtk_label_set_attributes);
     mixin ForwardGtkOsCFunc!(.gtk_label_set_justify);
     mixin ForwardGtkOsCFunc!(.gtk_label_set_line_wrap);
+    mixin ForwardGtkOsCFunc!(.gtk_label_set_line_wrap_mode);
     mixin ForwardGtkOsCFunc!(.gtk_label_set_text);
     mixin ForwardGtkOsCFunc!(.gtk_label_set_text_with_mnemonic);
     mixin ForwardGtkOsCFunc!(.gtk_list_append_items);
@@ -1673,6 +1720,7 @@
     mixin ForwardGtkOsCFunc!(.gtk_main_do_event);
     mixin ForwardGtkOsCFunc!(.gtk_menu_bar_new);
     mixin ForwardGtkOsCFunc!(.gtk_menu_item_remove_submenu);
+    mixin ForwardGtkOsCFunc!(.gtk_menu_item_get_submenu);
     mixin ForwardGtkOsCFunc!(.gtk_menu_item_set_submenu);
     mixin ForwardGtkOsCFunc!(.gtk_menu_new);
     mixin ForwardGtkOsCFunc!(.gtk_menu_popdown);
@@ -1893,7 +1941,9 @@
     mixin ForwardGtkOsCFunc!(.gtk_timeout_remove);
     mixin ForwardGtkOsCFunc!(.gtk_toggle_button_get_active);
     mixin ForwardGtkOsCFunc!(.gtk_toggle_button_new);
+    mixin ForwardGtkOsCFunc!(.gtk_toggle_button_get_inconsistent);
     mixin ForwardGtkOsCFunc!(.gtk_toggle_button_set_active);
+    mixin ForwardGtkOsCFunc!(.gtk_toggle_button_set_inconsistent);
     mixin ForwardGtkOsCFunc!(.gtk_toggle_button_set_mode);
     mixin ForwardGtkOsCFunc!(.gtk_toolbar_insert_widget);
     mixin ForwardGtkOsCFunc!(.gtk_toolbar_new);
@@ -2029,6 +2079,7 @@
     mixin ForwardGtkOsCFunc!(.gtk_widget_get_toplevel );
     mixin ForwardGtkOsCFunc!(.gtk_widget_grab_focus);
     mixin ForwardGtkOsCFunc!(.gtk_widget_hide);
+    mixin ForwardGtkOsCFunc!(.gtk_widget_is_composited);
     mixin ForwardGtkOsCFunc!(.gtk_widget_is_focus);
     mixin ForwardGtkOsCFunc!(.gtk_widget_map);
     mixin ForwardGtkOsCFunc!(.gtk_widget_mnemonic_activate);
@@ -2042,6 +2093,7 @@
     mixin ForwardGtkOsCFunc!(.gtk_widget_realize);
     mixin ForwardGtkOsCFunc!(.gtk_widget_remove_accelerator);
     mixin ForwardGtkOsCFunc!(.gtk_widget_reparent);
+    mixin ForwardGtkOsCFunc!(.gtk_widget_send_expose);
     mixin ForwardGtkOsCFunc!(.gtk_widget_set_app_paintable);
     mixin ForwardGtkOsCFunc!(.gtk_widget_set_default_direction);
     mixin ForwardGtkOsCFunc!(.gtk_widget_set_direction);
@@ -2064,13 +2116,21 @@
     mixin ForwardGtkOsCFunc!(.gtk_window_add_accel_group);
     mixin ForwardGtkOsCFunc!(.gtk_window_deiconify);
     mixin ForwardGtkOsCFunc!(.gtk_window_get_focus);
+    mixin ForwardGtkOsCFunc!(.gtk_window_get_group);
     mixin ForwardGtkOsCFunc!(.gtk_window_get_icon_list);
     mixin ForwardGtkOsCFunc!(.gtk_window_get_modal);
     mixin ForwardGtkOsCFunc!(.gtk_window_get_mnemonic_modifier);
+    mixin ForwardGtkOsCFunc!(.gtk_window_get_opacity);
     mixin ForwardGtkOsCFunc!(.gtk_window_get_position);
     mixin ForwardGtkOsCFunc!(.gtk_window_get_size);
+    mixin ForwardGtkOsCFunc!(.gtk_window_group_add_window);
+    mixin ForwardGtkOsCFunc!(.gtk_window_group_remove_window);
+    mixin ForwardGtkOsCFunc!(.gtk_window_group_new);
     mixin ForwardGtkOsCFunc!(.gtk_window_iconify);
+    mixin ForwardGtkOsCFunc!(.gtk_window_list_toplevels);
     mixin ForwardGtkOsCFunc!(.gtk_window_maximize);
+    mixin ForwardGtkOsCFunc!(.gtk_window_fullscreen);
+    mixin ForwardGtkOsCFunc!(.gtk_window_unfullscreen);
     mixin ForwardGtkOsCFunc!(.gtk_window_move);
     mixin ForwardGtkOsCFunc!(.gtk_window_new);
     mixin ForwardGtkOsCFunc!(.gtk_window_present);
@@ -2078,9 +2138,12 @@
     mixin ForwardGtkOsCFunc!(.gtk_window_resize);
     mixin ForwardGtkOsCFunc!(.gtk_window_set_default);
     mixin ForwardGtkOsCFunc!(.gtk_window_set_destroy_with_parent);
+    mixin ForwardGtkOsCFunc!(.gtk_window_set_keep_below);
     mixin ForwardGtkOsCFunc!(.gtk_window_set_geometry_hints);
     mixin ForwardGtkOsCFunc!(.gtk_window_set_icon_list);
     mixin ForwardGtkOsCFunc!(.gtk_window_set_modal);
+    mixin ForwardGtkOsCFunc!(.gtk_window_set_opacity);
+    mixin ForwardGtkOsCFunc!(.gtk_widget_set_tooltip_text);
     mixin ForwardGtkOsCFunc!(.gtk_widget_set_parent_window);
     mixin ForwardGtkOsCFunc!(.gtk_window_set_resizable);
     mixin ForwardGtkOsCFunc!(.gtk_window_set_title);
@@ -2095,9 +2158,17 @@
     mixin ForwardGtkOsCFunc!(.pango_attr_shape_new);
     mixin ForwardGtkOsCFunc!(.pango_attr_list_insert);
     mixin ForwardGtkOsCFunc!(.pango_attr_list_change);
+    mixin ForwardGtkOsCFunc!(.pango_attr_list_get_iterator);
+    mixin ForwardGtkOsCFunc!(.pango_attr_iterator_next);
+    mixin ForwardGtkOsCFunc!(.pango_attr_iterator_range);
+    mixin ForwardGtkOsCFunc!(.pango_attr_iterator_get);
+    mixin ForwardGtkOsCFunc!(.pango_attr_iterator_get_attrs);
+    mixin ForwardGtkOsCFunc!(.pango_attr_iterator_destroy);
     mixin ForwardGtkOsCFunc!(.pango_attr_list_new);
     mixin ForwardGtkOsCFunc!(.pango_attr_list_unref);
+    mixin ForwardGtkOsCFunc!(.pango_attr_strikethrough_color_new);
     mixin ForwardGtkOsCFunc!(.pango_attr_strikethrough_new);
+    mixin ForwardGtkOsCFunc!(.pango_attr_underline_color_new);
     mixin ForwardGtkOsCFunc!(.pango_attr_underline_new);
     mixin ForwardGtkOsCFunc!(.pango_attr_weight_new);
 //    mixin ForwardGtkOsCFunc!(.pango_cairo_font_map_get_default);
@@ -2136,6 +2207,10 @@
     mixin ForwardGtkOsCFunc!(.pango_font_metrics_get_approximate_char_width);
     mixin ForwardGtkOsCFunc!(.pango_font_metrics_get_ascent);
     mixin ForwardGtkOsCFunc!(.pango_font_metrics_get_descent);
+    mixin ForwardGtkOsCFunc!(.pango_font_metrics_get_underline_thickness);
+    mixin ForwardGtkOsCFunc!(.pango_font_metrics_get_underline_position);
+    mixin ForwardGtkOsCFunc!(.pango_font_metrics_get_strikethrough_thickness);
+    mixin ForwardGtkOsCFunc!(.pango_font_metrics_get_strikethrough_position);
     mixin ForwardGtkOsCFunc!(.pango_font_metrics_unref);
     mixin ForwardGtkOsCFunc!(.pango_language_from_string);
     mixin ForwardGtkOsCFunc!(.pango_layout_context_changed);
@@ -2453,6 +2528,13 @@
         return cast(bool)g_type_check_instance_is_a( cast(GTypeInstance*)arg0, gtk_image_menu_item_get_type ());
     }
 
+    static bool GTK_IS_MENU_ITEM( void* arg0 )
+    {
+        lock.lock();
+        scope(exit) lock.unlock();
+        return cast(bool)g_type_check_instance_is_a( cast(GTypeInstance*)arg0, gtk_menu_item_get_type ());
+    }
+
     static bool GTK_IS_PLUG( void* arg0 )
     {
         lock.lock();
@@ -2873,6 +2955,9 @@
         *arg1 = arg0.white_gc;
     }
 
+    static int strlen( char* ptr ){
+        return tango.stdc.string.strlen( ptr );
+    }
     //localeconv_decimal_point() localeconv()->decimal_point
 }
 
--- a/dwt/internal/image/FileFormat.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/FileFormat.d	Mon May 12 19:13:01 2008 +0200
@@ -82,7 +82,7 @@
 public static ImageData[] load(InputStream istr, ImageLoader loader) {
     FileFormat fileFormat = null;
     LEDataInputStream stream = new LEDataInputStream(istr);
-    bool isSupported = false;
+    bool isSupported = false;   
     foreach( TFormat; TFormats ){
         try{
             fileFormat = new TFormat();
--- a/dwt/internal/image/GIFFileFormat.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/GIFFileFormat.d	Mon May 12 19:13:01 2008 +0200
@@ -24,8 +24,6 @@
 import tango.core.Exception;
 import dwt.dwthelper.utils;
 
-///FORTING_TYPE
-class Image{}
 
 final class GIFFileFormat : FileFormat {
     String signature;
@@ -64,7 +62,7 @@
             byte[3] signature;
             stream.read(signature);
             stream.unread(signature);
-            return cast(String)signature == "GIF"; //$NON-NLS-1$
+            return signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F';
         } catch (Exception e) {
             return false;
         }
@@ -75,13 +73,12 @@
      * Return an array of ImageData representing the image(s).
      */
     override ImageData[] loadFromByteStream() {
-        byte[3] signatureBytes;
+        byte[3] signature;
         byte[3] versionBytes;
         byte[7] block;
         try {
-            inputStream.read(signatureBytes);
-            signature = cast(String)signatureBytes.dup;
-            if (signature != "GIF") //$NON-NLS-1$
+            inputStream.read(signature);
+            if (!(signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F'))
                 DWT.error(DWT.ERROR_INVALID_IMAGE);
 
             inputStream.read(versionBytes);
@@ -315,13 +312,11 @@
             // Read size of block = 0x0B.
             inputStream.read();
             // Read application identifier.
-            byte[] applicationBytes = new byte[8];
-            inputStream.read(applicationBytes);
-            String application = cast(String)(applicationBytes.dup);
+            byte[] application = new byte[8];
+            inputStream.read(application);
             // Read authentication code.
-            byte[] authenticationBytes = new byte[3];
-            inputStream.read(authenticationBytes);
-            String authentication = cast(String)(authenticationBytes.dup);
+            byte[] authentication = new byte[3];
+            inputStream.read(authentication);
             // Read application data.
             byte[] data = new byte[0];
             byte[] block = new byte[255];
@@ -335,7 +330,20 @@
                 size = inputStream.read();
             }
             // Look for the NETSCAPE 'repeat count' field for an animated GIF.
-            if (application=="NETSCAPE" && authentication=="2.0" && data[0] is 01) { //$NON-NLS-1$ //$NON-NLS-2$
+            bool netscape =
+                application[0] is 'N' &&
+                application[1] is 'E' &&
+                application[2] is 'T' &&
+                application[3] is 'S' &&
+                application[4] is 'C' &&
+                application[5] is 'A' &&
+                application[6] is 'P' &&
+                application[7] is 'E';
+            bool authentic =
+                authentication[0] is '2' &&
+                authentication[1] is '.' &&
+                authentication[2] is '0';
+            if (netscape && authentic && data[0] is 01) { //$NON-NLS-1$ //$NON-NLS-2$
                 repeatCount = (data[1] & 0xFF) | ((data[2] & 0xFF) << 8);
                 loader.repeatCount = repeatCount;
             }
--- a/dwt/internal/image/JPEGDecoder.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/JPEGDecoder.d	Mon May 12 19:13:01 2008 +0200
@@ -979,7 +979,7 @@
                         r = s >> 4;
                         s &= 15;
                         if (s !is 0) {
-                            if (s !is 1) {       /* size of new coef should always be 1 */
+                            if (s !is 1) {      /* size of new coef should always be 1 */
 //                              WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
                             }
 //                          CHECK_BIT_BUFFER(br_state, 1, goto undoit);
@@ -1242,7 +1242,7 @@
                                 k += 15;        /* skip 15 zeroes in band */
                             } else {        /* EOBr, run length is 2^r + appended bits */
                                 EOBRUN = 1 << r;
-                                if (r !is 0) {       /* EOBr, r > 0 */
+                                if (r !is 0) {      /* EOBr, r > 0 */
 //                                  CHECK_BIT_BUFFER(br_state, r, return FALSE);
                                     {
                                     if (bits_left < (r)) {
@@ -1280,7 +1280,7 @@
             return true;
         }
 
-        bool decode_mcu_DC_first (jpeg_decompress_struct cinfo, short[][] MCU_data) {
+        bool decode_mcu_DC_first (jpeg_decompress_struct cinfo, short[][] MCU_data) {    
             phuff_entropy_decoder entropy = this;
             int Al = cinfo.Al;
             int s = 0, r;
@@ -1644,7 +1644,7 @@
 
         /* Variables for Floyd-Steinberg dithering */
 //          FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */
-        bool on_odd_row;
+        bool on_odd_row;    
 
         void start_pass (jpeg_decompress_struct cinfo, bool is_pre_scan) {
             error();
@@ -4448,7 +4448,7 @@
 
         length -= count;
 
-        if ((index & 0x10) !is 0) {      /* AC table definition */
+        if ((index & 0x10) !is 0) {     /* AC table definition */
             index -= 0x10;
             htblptr = cinfo.ac_huff_tbl_ptrs[index] = new JHUFF_TBL();
         } else {            /* DC table definition */
@@ -5237,7 +5237,7 @@
 //               GETJOCTET(data[12]), GETJOCTET(data[13]));
         }
         totallen -= APP0_DATA_LEN;
-        if (totallen !is ((data[12] & 0xFF) * (data[13] & 0xFF) * 3)) {
+        if (totallen !is    ((data[12] & 0xFF) * (data[13] & 0xFF) * 3)) {
 //          TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, cast(int) totallen);
         }
     } else if (datalen >= 6 &&
--- a/dwt/internal/image/JPEGFileFormat.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/JPEGFileFormat.d	Mon May 12 19:13:01 2008 +0200
@@ -152,7 +152,7 @@
         RCbTable, GCbTable, BCbTable, RCrTable, GCrTable, BCrTable, NBitsTable;
     //public static void static_this() {
     static this() {
-        initialize();
+
         RGB16 = [
             new RGB(0,0,0),
             new RGB(0x80,0,0),
@@ -171,6 +171,65 @@
             new RGB(0,0xFF,0xFF),
             new RGB(0xFF,0xFF,0xFF)
         ];
+        int [] rYTable = new int[256];
+        int [] gYTable = new int[256];
+        int [] bYTable = new int[256];
+        int [] rCbTable = new int[256];
+        int [] gCbTable = new int[256];
+        int [] bCbTable = new int[256];
+        int [] rCrTable = new int[256];
+        int [] gCrTable = new int[256];
+        int [] bCrTable = new int[256];
+        for (int i = 0; i < 256; i++) {
+            rYTable[i] = i * 19595;
+            gYTable[i] = i * 38470;
+            bYTable[i] = i * 7471 + 32768;
+            rCbTable[i] = i * -11059;
+            gCbTable[i] = i * -21709;
+            bCbTable[i] = i * 32768 + 8388608;
+            gCrTable[i] = i * -27439;
+            bCrTable[i] = i * -5329;
+        }
+        RYTable = rYTable;
+        GYTable = gYTable;
+        BYTable = bYTable;
+        RCbTable = rCbTable;
+        GCbTable = gCbTable;
+        BCbTable = bCbTable;
+        RCrTable = bCbTable;
+        GCrTable = gCrTable;
+        BCrTable = bCrTable;
+
+        /* Initialize YCbCr-RGB Tables */
+        int [] crRTable = new int[256];
+        int [] cbBTable = new int[256];
+        int [] crGTable = new int[256];
+        int [] cbGTable = new int[256];
+        for (int i = 0; i < 256; i++) {
+            int x2 = 2 * i - 255;
+            crRTable[i] = (45941 * x2 + 32768) >> 16;
+            cbBTable[i] = (58065 * x2 + 32768) >> 16;
+            crGTable[i] = -23401 * x2;
+            cbGTable[i] = -11277 * x2 + 32768;
+        }
+        CrRTable = crRTable;
+        CbBTable = cbBTable;
+        CrGTable = crGTable;
+        CbGTable = cbGTable;
+
+        /* Initialize BitCount Table */
+        int nBits = 1;
+        int power2 = 2;
+        int [] nBitsTable = new int[2048];
+        nBitsTable[0] = 0;
+        for (int i = 1; i < nBitsTable.length; i++) {
+            if (!(i < power2)) {
+                nBits++;
+                power2 *= 2;
+            }
+            nBitsTable[i] = nBits;
+        }
+        NBitsTable = nBitsTable;
     }
 void compress(ImageData image, byte[] dataYComp, byte[] dataCbComp, byte[] dataCrComp) {
     int srcWidth = image.width;
@@ -229,15 +288,15 @@
             int delta = componentWidth - compressedWidth;
             for (int yPos = 0; yPos < compressedHeight; yPos++) {
                 int dstOfs = ((yPos + 1) * componentWidth - delta);
-                int dataValue = imageComponent[dstOfs - 1] & 0xFF;
+                int dataValue = imageComponent[(dstOfs > 0) ? dstOfs - 1 : 0] & 0xFF;
                 for (int i = 0; i < delta; i++) {
                     imageComponent[dstOfs + i] = cast(byte)dataValue;
                 }
             }
         }
         if (compressedHeight < componentHeight) {
-            int srcOfs = (compressedHeight - 1) * componentWidth;
-            for (int yPos = compressedHeight; yPos <= componentHeight; yPos++) {
+            int srcOfs = (compressedHeight > 0) ? (compressedHeight - 1) * componentWidth : 1;
+            for (int yPos = (compressedHeight > 0) ? compressedHeight : 1; yPos <= componentHeight; yPos++) {
                 int dstOfs = (yPos - 1) * componentWidth;
                 System.arraycopy(imageComponent, srcOfs, imageComponent, dstOfs, componentWidth);
             }
@@ -1160,58 +1219,6 @@
     }
     restartInterval = dri.getRestartInterval();
 }
-static void initialize() {
-    initializeRGBYCbCrTables();
-    initializeYCbCrRGBTables();
-    initializeBitCountTable();
-}
-static void initializeBitCountTable() {
-    int nBits = 1;
-    int power2 = 2;
-    NBitsTable = new int[2048];
-    NBitsTable[0] = 0;
-    for (int i = 1; i < NBitsTable.length; i++) {
-        if (!(i < power2)) {
-            nBits++;
-            power2 *= 2;
-        }
-        NBitsTable[i] = nBits;
-    }
-}
-static void initializeRGBYCbCrTables() {
-    RYTable = new int[256];
-    GYTable = new int[256];
-    BYTable = new int[256];
-    RCbTable = new int[256];
-    GCbTable = new int[256];
-    BCbTable = new int[256];
-    RCrTable = BCbTable;
-    GCrTable = new int[256];
-    BCrTable = new int[256];
-    for (int i = 0; i < 256; i++) {
-        RYTable[i] = i * 19595;
-        GYTable[i] = i * 38470;
-        BYTable[i] = i * 7471 + 32768;
-        RCbTable[i] = i * -11059;
-        GCbTable[i] = i * -21709;
-        BCbTable[i] = i * 32768 + 8388608;
-        GCrTable[i] = i * -27439;
-        BCrTable[i] = i * -5329;
-    }
-}
-static void initializeYCbCrRGBTables() {
-    CrRTable = new int[256];
-    CbBTable = new int[256];
-    CrGTable = new int[256];
-    CbGTable = new int[256];
-    for (int i = 0; i < 256; i++) {
-        int x2 = 2 * i - 255;
-        CrRTable[i] = (45941 * x2 + 32768) >> 16;
-        CbBTable[i] = (58065 * x2 + 32768) >> 16;
-        CrGTable[i] = -23401 * x2;
-        CbGTable[i] = -11277 * x2 + 32768;
-    }
-}
 void inverseDCT(int[] dataUnit) {
     for (int row = 0; row < 8; row++) {
         int rIndex = row * DCTSIZE;
--- a/dwt/internal/image/LEDataInputStream.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/LEDataInputStream.d	Mon May 12 19:13:01 2008 +0200
@@ -156,9 +156,9 @@
     public int readInt() {
         byte[4] buf = void;
         read(buf);
-        return ((((((buf[3] & 0xFF) << 24) |
-            (buf[2] & 0xFF)) << 16) |
-            (buf[1] & 0xFF)) << 8) |
+        return ((buf[3] & 0xFF) << 24) | 
+            ((buf[2] & 0xFF) << 16) | 
+            ((buf[1] & 0xFF) << 8) | 
             (buf[0] & 0xFF);
     }
 
--- a/dwt/internal/image/PNGFileFormat.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/PNGFileFormat.d	Mon May 12 19:13:01 2008 +0200
@@ -176,7 +176,7 @@
         if ((signature[4] & 0xFF) !is 13) return false; //<RETURN>
         if ((signature[5] & 0xFF) !is 10) return false; //<LINEFEED>
         if ((signature[6] & 0xFF) !is 26) return false; //<CTRL/Z>
-        if ((signature[7] & 0xFF) !is 10) return false; //<LINEFEED>
+        if ((signature[7] & 0xFF) !is 10) return false; //<LINEFEED>        
         return true;
     } catch (Exception e) {
         return false;
@@ -314,7 +314,7 @@
     bool use3_2 = true;//System.getProperty("dwt.internal.image.PNGFileFormat_3.2") !is null;
     InputStream inflaterStream = use3_2 ? null : Compatibility.newInflaterInputStream(stream);
     if (inflaterStream !is null) {
-        stream = new BufferedInputStream(inflaterStream);
+        stream = inflaterStream;
     } else {
         stream = new PngDecodingDataStream(stream);
     }
--- a/dwt/internal/image/PngDeflater.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/PngDeflater.d	Mon May 12 19:13:01 2008 +0200
@@ -55,7 +55,7 @@
 
 }
 
-class Match {
+static class Match {
 
     int length, distance;
 
--- a/dwt/internal/image/PngEncoder.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/PngEncoder.d	Mon May 12 19:13:01 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * 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
@@ -15,10 +15,12 @@
 import dwt.internal.image.LEDataOutputStream;
 import dwt.internal.image.PngDeflater;
 import dwt.dwthelper.ByteArrayOutputStream;
+import dwt.dwthelper.OutputStream;
 import dwt.DWT;
 import dwt.graphics.ImageData;
 import dwt.graphics.ImageLoader;
 import dwt.graphics.RGB;
+import dwt.internal.Compatibility;
 import dwt.internal.image.PngChunk;
 
 import tango.core.Exception;
@@ -236,21 +238,23 @@
 void writeImageData() {
 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+    OutputStream os = Compatibility.newDeflaterOutputStream(baos);
+    if (os is null) os = baos;
 
     if (colorType is 3) {
 
-        int[] lineData = new int[width];
+        byte[] lineData = new byte[width];
 
         for (int y = 0; y < height; y++) {
 
-            byte filter[] = [0];
-            baos.write(filter, 0, 1);
+            int filter = 0;
+            os.write(filter);
 
             data.getPixels(0, y, width, lineData, 0);
 
             for (int x = 0; x < lineData.length; x++) {
 
-                baos.write(cast(byte) lineData[x]);
+                os.write(lineData[x]);
 
             }
 
@@ -261,7 +265,10 @@
     else {
 
         int[] lineData = new int[width];
-        byte[] alphaData = new byte[width];
+        byte[] alphaData = null;
+        if (colorType is 6) {
+            alphaData = new byte[width];
+        }
 
         int redMask = data.palette.redMask;
         int redShift = data.palette.redShift;
@@ -272,8 +279,8 @@
 
         for (int y = 0; y < height; y++) {
 
-            byte filter[] = [0];
-            baos.write(filter, 0, 1);
+            int filter = 0;
+            os.write(filter);
 
             data.getPixels(0, y, width, lineData, 0);
 
@@ -292,14 +299,12 @@
                 int b = pixel & blueMask;
                 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;
 
-                byte pixels[] = [cast(byte) r, cast(byte) g, cast(byte) b];
-                baos.write(pixels, 0, 3);
+                os.write(r);
+                os.write(g);
+                os.write(b);
 
                 if (colorType is 6) {
-
-                    byte alpha[] = [alphaData[x]];
-                    baos.write(alpha, 0, 1);
-
+                    os.write(alphaData[x]);
                 }
 
             }
@@ -308,8 +313,14 @@
 
     }
 
-    PngDeflater deflater = new PngDeflater();
-    byte[] compressed = deflater.deflate(baos.toByteArray());
+    os.flush();
+    os.close();
+
+    byte[] compressed = baos.toByteArray();
+    if (os is baos) {
+        PngDeflater deflater = new PngDeflater();
+        compressed = deflater.deflate(compressed);
+    }
 
     writeChunk(TAG_IDAT, compressed);
 
--- a/dwt/internal/image/PngHuffmanTable.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/PngHuffmanTable.d	Mon May 12 19:13:01 2008 +0200
@@ -116,7 +116,7 @@
     return codeValues[index];
 }
 
-class CodeLengthInfo {
+static class CodeLengthInfo {
     int length;
     int max;
     int min;
--- a/dwt/internal/image/PngPlteChunk.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/PngPlteChunk.d	Mon May 12 19:13:01 2008 +0200
@@ -112,7 +112,7 @@
 
     // Palette chunks' data fields must be event multiples
     // of 3. Each 3-byte group represents an RGB value.
-    if (getLength() % 3 !is 0) DWT.error(DWT.ERROR_INVALID_IMAGE);
+    if (getLength() % 3 !is 0) DWT.error(DWT.ERROR_INVALID_IMAGE);  
 
     // Palettes cannot have more entries than 2^bitDepth
     // where bitDepth is the bit depth of the image given
--- a/dwt/internal/image/WinICOFileFormat.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/internal/image/WinICOFileFormat.d	Mon May 12 19:13:01 2008 +0200
@@ -20,7 +20,7 @@
 
 import tango.core.Exception;
 
-final class WinICOFileFormat : FileFormat {
+public final class WinICOFileFormat : FileFormat {
 
 byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
     // Destructively bit invert data in the given byte array.
--- a/dwt/layout/RowLayout.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/layout/RowLayout.d	Mon May 12 19:13:01 2008 +0200
@@ -138,6 +138,17 @@
     public bool fill = false;
 
     /**
+     * center specifies whether the controls in a row should be
+     * centered vertically in each cell for horizontal layouts,
+     * or centered horizontally in each cell for vertical layouts.
+     *
+     * The default value is false.
+     * 
+     * @since 3.4
+     */
+    public bool center = false;
+    
+    /**
      * justify specifies whether the controls in a row should be
      * fully justified, with any extra space placed between the controls.
      *
@@ -268,7 +279,7 @@
     int [] wraps = null;
     bool wrapped = false;
     Rectangle [] bounds = null;
-    if (move && (justify || fill)) {
+    if (move && (justify || fill || center)) {
         bounds = new Rectangle [count];
         wraps = new int [count];
     }
@@ -282,17 +293,17 @@
         }
         if (wrap && (i !is 0) && (x + childWidth > width)) {
             wrapped = true;
-            if (move && (justify || fill)) wraps [i - 1] = maxHeight;
+            if (move && (justify || fill || center)) wraps [i - 1] = maxHeight;
             x = marginLeft + marginWidth;
             y += spacing + maxHeight;
             if (pack) maxHeight = 0;
         }
-        if (pack || fill) {
+        if (pack || fill || center) {
             maxHeight = Math.max (maxHeight, childHeight);
         }
         if (move) {
             int childX = x + clientX, childY = y + clientY;
-            if (justify || fill) {
+            if (justify || fill || center) {
                 bounds [i] = new Rectangle (childX, childY, childWidth, childHeight);
             } else {
                 child.setBounds (childX, childY, childWidth, childHeight);
@@ -303,13 +314,13 @@
     }
     maxX = Math.max (clientX + marginLeft + marginWidth, maxX - spacing);
     if (!wrapped) maxX += marginRight + marginWidth;
-    if (move && (justify || fill)) {
+    if (move && (justify || fill || center)) {
         int space = 0, margin = 0;
         if (!wrapped) {
             space = Math.max (0, (width - maxX) / (count + 1));
             margin = Math.max (0, ((width - maxX) % (count + 1)) / 2);
         } else {
-            if (fill || justify) {
+            if (fill || justify || center) {
                 int last = 0;
                 if (count > 0) wraps [count - 1] = maxHeight;
                 for (int i=0; i<count; i++) {
@@ -325,7 +336,13 @@
                         }
                         for (int j=last; j<=i; j++) {
                             if (justify) bounds [j].x += (space * (j - last + 1)) + margin;
-                            if (fill) bounds [j].height = wraps [i];
+                            if (fill) {
+                                bounds [j].height = wraps [i];
+                            } else {
+                                if (center) {
+                                    bounds [j].y += Math.max (0, (wraps [i] - bounds [j].height) / 2);
+                                }
+                            }
                         }
                         last = i + 1;
                     }
@@ -335,7 +352,13 @@
         for (int i=0; i<count; i++) {
             if (!wrapped) {
                 if (justify) bounds [i].x += (space * (i + 1)) + margin;
-                if (fill) bounds [i].height = maxHeight;
+                if (fill) {
+                    bounds [i].height = maxHeight;
+                } else {
+                    if (center) {
+                        bounds [i].y += Math.max (0, (maxHeight - bounds [i].height) / 2);
+                    }
+                }
             }
             children [i].setBounds (bounds [i]);
         }
@@ -375,7 +398,7 @@
     int [] wraps = null;
     bool wrapped = false;
     Rectangle [] bounds = null;
-    if (move && (justify || fill)) {
+    if (move && (justify || fill || center)) {
         bounds = new Rectangle [count];
         wraps = new int [count];
     }
@@ -389,17 +412,17 @@
         }
         if (wrap && (i !is 0) && (y + childHeight > height)) {
             wrapped = true;
-            if (move && (justify || fill)) wraps [i - 1] = maxWidth;
+            if (move && (justify || fill || center)) wraps [i - 1] = maxWidth;
             x += spacing + maxWidth;
             y = marginTop + marginHeight;
             if (pack) maxWidth = 0;
         }
-        if (pack || fill) {
+        if (pack || fill || center) {
             maxWidth = Math.max (maxWidth, childWidth);
         }
         if (move) {
             int childX = x + clientX, childY = y + clientY;
-            if (justify || fill) {
+            if (justify || fill || center) {
                 bounds [i] = new Rectangle (childX, childY, childWidth, childHeight);
             } else {
                 child.setBounds (childX, childY, childWidth, childHeight);
@@ -410,13 +433,13 @@
     }
     maxY = Math.max (clientY + marginTop + marginHeight, maxY - spacing);
     if (!wrapped) maxY += marginBottom + marginHeight;
-    if (move && (justify || fill)) {
+    if (move && (justify || fill || center)) {
         int space = 0, margin = 0;
         if (!wrapped) {
             space = Math.max (0, (height - maxY) / (count + 1));
             margin = Math.max (0, ((height - maxY) % (count + 1)) / 2);
         } else {
-            if (fill || justify) {
+            if (fill || justify || center) {
                 int last = 0;
                 if (count > 0) wraps [count - 1] = maxWidth;
                 for (int i=0; i<count; i++) {
@@ -432,7 +455,13 @@
                         }
                         for (int j=last; j<=i; j++) {
                             if (justify) bounds [j].y += (space * (j - last + 1)) + margin;
-                            if (fill) bounds [j].width = wraps [i];
+                            if (fill) {
+                                bounds [j].width = wraps [i];
+                            } else {
+                                if (center) {
+                                    bounds [j].x += Math.max (0, (wraps [i] - bounds [j].width) / 2);
+                                }
+                            }
                         }
                         last = i + 1;
                     }
@@ -442,7 +471,14 @@
         for (int i=0; i<count; i++) {
             if (!wrapped) {
                 if (justify) bounds [i].y += (space * (i + 1)) + margin;
-                if (fill) bounds [i].width = maxWidth;
+                if (fill) {
+                    bounds [i].width = maxWidth;
+                } else {
+                    if (center) {
+                        bounds [i].x += Math.max (0, (maxWidth - bounds [i].width) / 2);
+                    }
+                }
+
             }
             children [i].setBounds (bounds [i]);
         }
--- a/dwt/printing/PrintDialog.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/printing/PrintDialog.d	Mon May 12 19:13:01 2008 +0200
@@ -16,6 +16,7 @@
 
 import dwt.DWT;
 import dwt.DWTException;
+import dwt.internal.LONG;
 import dwt.internal.gtk.OS;
 import dwt.widgets.Dialog;
 import dwt.widgets.Display;
@@ -39,6 +40,7 @@
  * </p>
  */
 public class PrintDialog : Dialog {
+    PrinterData printerData;
     int scope_ = PrinterData.ALL_PAGES;
     int startPage = 1, endPage = 1;
     bool printToFile = false;
@@ -47,9 +49,11 @@
     int index;
     char [] settingsData;
 
-    static const String ADD_IDLE_PROC_KEY = "org.eclipse.swt.internal.gtk2.addIdleProc";
-    static const String REMOVE_IDLE_PROC_KEY = "org.eclipse.swt.internal.gtk2.removeIdleProc";
-
+    static const String GET_MODAL_DIALOG = "dwt.internal.gtk.getModalDialog";
+    static const String SET_MODAL_DIALOG = "dwt.internal.gtk.setModalDialog";
+    static const String ADD_IDLE_PROC_KEY = "dwt.internal.gtk.addIdleProc";
+    static const String REMOVE_IDLE_PROC_KEY = "dwt.internal.gtk.removeIdleProc";
+    static const String GET_EMISSION_PROC_KEY = "dwt.internal.gtk.getEmissionProc";
 /**
  * Constructs a new instance of this class given only its parent.
  *
@@ -100,11 +104,55 @@
  * @see Widget#getStyle
  */
 public this (Shell parent, int style) {
-    super (parent, style);
+    super (parent, parent is null? style : checkStyleBit (parent, style));
     checkSubclass ();
 }
 
-protected override void checkSubclass() {
+/**
+ * Sets the printer data that will be used when the dialog
+ * is opened.
+ *
+ * @param data the data that will be used when the dialog is opened
+ *
+ * @since 3.4
+ */
+public void setPrinterData(PrinterData data) {
+    this.printerData = data;
+}
+
+/**
+ * Returns the printer data that will be used when the dialog
+ * is opened.
+ *
+ * @return the data that will be used when the dialog is opened
+ *
+ * @since 3.4
+ */
+public PrinterData getPrinterData() {
+    return printerData;
+}
+
+static int checkBits (int style, int int0, int int1, int int2, int int3, int int4, int int5) {
+    int mask = int0 | int1 | int2 | int3 | int4 | int5;
+    if ((style & mask) is 0) style |= int0;
+    if ((style & int0) !is 0) style = (style & ~mask) | int0;
+    if ((style & int1) !is 0) style = (style & ~mask) | int1;
+    if ((style & int2) !is 0) style = (style & ~mask) | int2;
+    if ((style & int3) !is 0) style = (style & ~mask) | int3;
+    if ((style & int4) !is 0) style = (style & ~mask) | int4;
+    if ((style & int5) !is 0) style = (style & ~mask) | int5;
+    return style;
+}
+
+static int checkStyleBit (Shell parent, int style) {
+    style &= ~DWT.MIRRORED;
+    if ((style & (DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT)) is 0) {
+        if (parent !is null) {
+            if ((parent.getStyle () & DWT.LEFT_TO_RIGHT) !is 0) style |= DWT.LEFT_TO_RIGHT;
+            if ((parent.getStyle () & DWT.RIGHT_TO_LEFT) !is 0) style |= DWT.RIGHT_TO_LEFT;
+        }
+    }
+    return checkBits (style, DWT.LEFT_TO_RIGHT, DWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
 }
 
 /**
@@ -252,7 +300,28 @@
         /* Set state into print dialog settings. */
         auto settings = OS.gtk_print_settings_new();
         auto page_setup = OS.gtk_page_setup_new();
+
+        if (printerData !is null) {
+            if (printerData.otherData !is null) {
+                Printer.restore(printerData.otherData, settings, page_setup);
+            }
+            /* Set values of settings from PrinterData. */
+            Printer.setScope(settings, printerData.scope_, printerData.startPage, printerData.endPage);
+            //TODO: Should we look at printToFile, or driver/name for "Print to File", or both? (see gtk bug 345590)
+            if (printerData.printToFile) {
+                char* buffer = tango.stdc.stringz.toStringz(printerData.fileName);
+                OS.gtk_print_settings_set(settings, OS.GTK_PRINT_SETTINGS_OUTPUT_URI.ptr, buffer);
+            }
+            if (printerData.driver.equals("GtkPrintBackendFile") && printerData.name.equals("Print to File")) { //$NON-NLS-1$ //$NON-NLS-2$
+                char* buffer = tango.stdc.stringz.toStringz(printerData.fileName);
+                OS.gtk_print_settings_set(settings, OS.GTK_PRINT_SETTINGS_OUTPUT_URI.ptr, buffer);
+            }
+            OS.gtk_print_settings_set_n_copies(settings, printerData.copyCount);
+            OS.gtk_print_settings_set_collate(settings, printerData.collate);
+        }
+
         Printer.setScope(settings, scope_, startPage, endPage);
+
         if (printToFile) {
             char* buffer = tango.stdc.stringz.toStringz( "Print to File" ); //$NON-NLS-1$
             OS.gtk_print_settings_set_printer(settings, buffer);
@@ -265,10 +334,30 @@
         PrinterData data = null;
         //TODO: Handle 'Print Preview' (GTK_RESPONSE_APPLY).
         Display display = getParent() !is null ? getParent().getDisplay (): Display.getCurrent ();
+
+        int signalId = 0;
+        int /*long*/ hookId = 0;
+        if ((getStyle () & DWT.RIGHT_TO_LEFT) !is 0) {
+            signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+            hookId = OS.g_signal_add_emission_hook (signalId, 0, cast(GSignalEmissionHook)cast(void*)(cast(LONG) display.getData (GET_EMISSION_PROC_KEY)).value, handle, null);
+        }
         display.setData (ADD_IDLE_PROC_KEY, null);
-        if (OS.gtk_dialog_run (handle) is OS.GTK_RESPONSE_OK) {
+        Object oldModal = null;
+        if (OS.gtk_window_get_modal (handle)) {
+            oldModal = display.getData (GET_MODAL_DIALOG);
+            display.setData (SET_MODAL_DIALOG, this);
+        }
+        int response = OS.gtk_dialog_run (handle);
+        if (OS.gtk_window_get_modal (handle)) {
+            display.setData (SET_MODAL_DIALOG, oldModal);
+        }
+        if ((getStyle () & DWT.RIGHT_TO_LEFT) !is 0) {
+            OS.g_signal_remove_emission_hook (signalId, hookId);
+        }
+        if (response is OS.GTK_RESPONSE_OK) {
             auto printer = OS.gtk_print_unix_dialog_get_selected_printer(handle);
             if (printer !is null) {
+
                 /* Get state from print dialog. */
                 settings = OS.gtk_print_unix_dialog_get_settings(handle); // must unref
                 page_setup = OS.gtk_print_unix_dialog_get_page_setup(handle); // do not unref
--- a/dwt/printing/Printer.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/printing/Printer.d	Mon May 12 19:13:01 2008 +0200
@@ -29,7 +29,7 @@
 import dwt.dwthelper.utils;
 
 static import tango.stdc.stringz;
-static import tango.io.Stdout;
+import tango.io.Stdout;
 import tango.util.Convert;
 
 
@@ -70,8 +70,8 @@
     bool isGCCreated = false;
     Font systemFont;
 
-    String settingsData;
-    int start, end;
+    static String settingsData;
+    static int start, end;
 
     static const String GTK_LPR_BACKEND = "GtkPrintBackendLpr"; //$NON-NLS-1$
 
@@ -88,6 +88,14 @@
     if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0) || disablePrinting) {
         return printerList;
     }
+    if (!OS.g_thread_supported ()) {
+        OS.g_thread_init (null);
+    }
+    OS.gtk_set_locale();
+    int argc = 0;
+    if (!OS.gtk_init_check ( &argc, null)) {
+        DWT.error (DWT.ERROR_NO_HANDLES, null, " [gtk_init_check() failed]");
+    }
     OS.gtk_enumerate_printers(&GtkPrinterFunc_List, null, null, true);
     return printerList;
 }
@@ -124,6 +132,14 @@
     if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0) || disablePrinting) {
         return null;
     }
+    if (!OS.g_thread_supported ()) {
+        OS.g_thread_init (null);
+    }
+    OS.gtk_set_locale();
+    int argc = 0;
+    if (!OS.gtk_init_check (&argc, null)) {
+        DWT.error (DWT.ERROR_NO_HANDLES, null, " [gtk_init_check() failed]");
+    }
     OS.gtk_enumerate_printers(&GtkPrinterFunc_Default, null, null, true);
     return printerList[0];
 }
@@ -132,6 +148,8 @@
     if (OS.gtk_printer_is_default(printer)) {
         printerList[0] = printerDataFromGtkPrinter(printer);
         return 1;
+    } else if (OS.GTK_VERSION < OS.buildVERSION(2, 10, 12) && printerDataFromGtkPrinter(printer).driver.equals (GTK_LPR_BACKEND)) {
+        return 1;
     }
     return 0;
 }
@@ -151,6 +169,8 @@
         this.printer = printer;
         OS.g_object_ref(printer);
         return 1;
+    } else if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 12) && pd.driver.equals(GTK_LPR_BACKEND)) {
+        return 1;
     }
     return 0;
 }
@@ -166,6 +186,56 @@
     return new PrinterData (backendType, name);
 }
 
+/*
+* Restore printer settings and page_setup data from data.
+*/
+static void restore(char[] data, GtkPrintSettings* settings, GtkPageSetup* page_setup) {
+    settingsData = data;
+    start = end = 0;
+    while (end < settingsData.length && settingsData[end] !is 0) {
+        start = end;
+        while (end < settingsData.length && settingsData[end] !is 0) end++;
+        end++;
+        char [] keyBuffer = new char [end - start];
+        System.arraycopy (settingsData, start, keyBuffer, 0, keyBuffer.length);
+        start = end;
+        while (end < settingsData.length && settingsData[end] !is 0) end++;
+        end++;
+        char [] valueBuffer = new char [end - start];
+        System.arraycopy (settingsData, start, valueBuffer, 0, valueBuffer.length);
+        OS.gtk_print_settings_set(settings, keyBuffer.ptr, valueBuffer.ptr);
+        if (DEBUG) Stdout.formatln("{}: {}", keyBuffer, valueBuffer );
+    }
+    end++; // skip extra null terminator
+
+    /* Retrieve stored page_setup data.
+     * Note that page_setup properties must be stored (in PrintDialog) and restored (here) in the same order.
+     */
+    OS.gtk_page_setup_set_orientation(page_setup, restoreInt("orientation")); //$NON-NLS-1$
+    OS.gtk_page_setup_set_top_margin(page_setup, restoreDouble("top_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
+    OS.gtk_page_setup_set_bottom_margin(page_setup, restoreDouble("bottom_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
+    OS.gtk_page_setup_set_left_margin(page_setup, restoreDouble("left_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
+    OS.gtk_page_setup_set_right_margin(page_setup, restoreDouble("right_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
+    char [] name = restoreBytes("paper_size_name", true); //$NON-NLS-1$
+    char [] display_name = restoreBytes("paper_size_display_name", true); //$NON-NLS-1$
+    char [] ppd_name = restoreBytes("paper_size_ppd_name", true); //$NON-NLS-1$
+    double width = restoreDouble("paper_size_width"); //$NON-NLS-1$
+    double height = restoreDouble("paper_size_height"); //$NON-NLS-1$
+    bool custom = restoreBoolean("paper_size_is_custom"); //$NON-NLS-1$
+    GtkPaperSize* paper_size = null;
+    if (custom) {
+        if (ppd_name.length > 0) {
+            paper_size = OS.gtk_paper_size_new_from_ppd(ppd_name.ptr, display_name.ptr, width, height);
+        } else {
+            paper_size = OS.gtk_paper_size_new_custom(name.ptr, display_name.ptr, width, height, OS.GTK_UNIT_MM);
+        }
+    } else {
+        paper_size = OS.gtk_paper_size_new(name.ptr);
+    }
+    OS.gtk_page_setup_set_paper_size(page_setup, paper_size);
+    OS.gtk_paper_size_free(paper_size);
+}
+
 static void setScope(GtkPrintSettings* settings, int scope_, int startPage, int endPage) {
     switch (scope_) {
     case PrinterData.ALL_PAGES:
@@ -235,22 +305,22 @@
     super(checkNull(data));
 }
 
-int restoreInt(String key) {
+static int restoreInt(String key) {
     char [] value = restoreBytes(key, false);
     return to!(int)( value );
 }
 
-double restoreDouble(String key) {
+static double restoreDouble(String key) {
     char [] value = restoreBytes(key, false);
     return to!(double)( value );
 }
 
-bool restoreBoolean(String key) {
+static bool restoreBoolean(String key) {
     char [] value = restoreBytes(key, false);
     return to!(bool)( value );
 }
 
-String restoreBytes(String key, bool nullTerminate) {
+static String restoreBytes(String key, bool nullTerminate) {
     //get key
     start = end;
     while (end < settingsData.length && settingsData[end] !is 0) end++;
@@ -328,7 +398,10 @@
         data.drawable = drawable;
         data.background = getSystemColor (DWT.COLOR_WHITE).handle;
         data.foreground = getSystemColor (DWT.COLOR_BLACK).handle;
-        data.font = getSystemFont ().handle;
+        data.font = getSystemFont ();
+        //TODO: We are supposed to return this in pixels, but GTK_UNIT_PIXELS is currently not implemented (gtk bug 346245)
+        data.width = cast(int)OS.gtk_page_setup_get_paper_width (pageSetup, OS.GTK_UNIT_POINTS);
+        data.height = cast(int)OS.gtk_page_setup_get_paper_height (pageSetup, OS.GTK_UNIT_POINTS);
         if (cairo is null) DWT.error(DWT.ERROR_NO_HANDLES);
         data.cairo = cairo;
         isGCCreated = true;
@@ -656,51 +729,7 @@
     settings = OS.gtk_print_settings_new();
     pageSetup = OS.gtk_page_setup_new();
     if (data.otherData !is null) {
-        /* Retreive stored printer_settings data. */
-        settingsData = data.otherData;
-        start = end = 0;
-        while (end < settingsData.length && settingsData[end] !is 0) {
-            start = end;
-            while (end < settingsData.length && settingsData[end] !is 0) end++;
-            end++;
-            char [] keyBuffer = new char [end - start];
-            System.arraycopy (settingsData, start, keyBuffer, 0, keyBuffer.length);
-            start = end;
-            while (end < settingsData.length && settingsData[end] !is 0) end++;
-            end++;
-            char [] valueBuffer = new char [end - start];
-            System.arraycopy (settingsData, start, valueBuffer, 0, valueBuffer.length);
-            OS.gtk_print_settings_set(settings, keyBuffer.ptr, valueBuffer.ptr);
-            if (DEBUG) tango.io.Stdout.Stdout.formatln("{}: {}", keyBuffer, valueBuffer);
-        }
-        end++; // skip extra null terminator
-
-        /* Retreive stored page_setup data.
-         * Note that page_setup properties must be stored (in PrintDialog) and restored (here) in the same order.
-         */
-        OS.gtk_page_setup_set_orientation(pageSetup, restoreInt("orientation")); //$NON-NLS-1$
-        OS.gtk_page_setup_set_top_margin(pageSetup, restoreDouble("top_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
-        OS.gtk_page_setup_set_bottom_margin(pageSetup, restoreDouble("bottom_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
-        OS.gtk_page_setup_set_left_margin(pageSetup, restoreDouble("left_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
-        OS.gtk_page_setup_set_right_margin(pageSetup, restoreDouble("right_margin"), OS.GTK_UNIT_MM); //$NON-NLS-1$
-        char [] name = restoreBytes("paper_size_name", true); //$NON-NLS-1$
-        char [] display_name = restoreBytes("paper_size_display_name", true); //$NON-NLS-1$
-        char [] ppd_name = restoreBytes("paper_size_ppd_name", true); //$NON-NLS-1$
-        double width = restoreDouble("paper_size_width"); //$NON-NLS-1$
-        double height = restoreDouble("paper_size_height"); //$NON-NLS-1$
-        bool custom = restoreBoolean("paper_size_is_custom"); //$NON-NLS-1$
-        GtkPaperSize* paper_size;
-        if (custom) {
-            if (ppd_name.length > 0) {
-                paper_size = OS.gtk_paper_size_new_from_ppd(ppd_name.ptr, display_name.ptr, width, height);
-            } else {
-                paper_size = OS.gtk_paper_size_new_custom(name.ptr, display_name.ptr, width, height, OS.GTK_UNIT_MM);
-            }
-        } else {
-            paper_size = OS.gtk_paper_size_new(name.ptr);
-        }
-        OS.gtk_page_setup_set_paper_size(pageSetup, paper_size);
-        OS.gtk_paper_size_free(paper_size);
+        restore(data.otherData, settings, pageSetup);
     }
 
     /* Set values of settings from PrinterData. */
--- a/dwt/printing/PrinterData.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/printing/PrinterData.d	Mon May 12 19:13:01 2008 +0200
@@ -132,6 +132,10 @@
      * private, platform-specific data
      * On Windows, this contains a copy of the DEVMODE struct
      * returned from the <code>PrintDialog</code>.
+     * On GTK, this contains a copy of the print_settings and page_setup
+     * returned from the <code>PrintDialog</code>.
+     * On OS X Carbon, this contains a copy of the PrintSettings and PageFormat
+     * returned from the <code>PrintDialog</code>.
      * This field is not currently used on the X/Window System.
      */
     char [] otherData;
--- a/dwt/program/Program.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/program/Program.d	Mon May 12 19:13:01 2008 +0200
@@ -194,6 +194,8 @@
     static const String[] CDE_MASK_EXT = [ ".m_m.bm"[], ".l_m.bm", ".s_m.bm", ".t_m.bm" ];
     static const String DESKTOP_DATA = "Program_DESKTOP";
     static const String ICON_THEME_DATA = "Program_GNOME_ICON_THEME";
+    static const String PREFIX_HTTP = "http://"; //$NON-NLS-1$
+    static const String PREFIX_HTTPS = "https://"; //$NON-NLS-1$
     static const int DESKTOP_UNKNOWN = 0;
     static const int DESKTOP_GNOME = 1;
     static const int DESKTOP_GNOME_24 = 2;
@@ -855,18 +857,26 @@
  *  API: When support for multiple displays is added, this method will
  *       become public and the original method above can be deprecated.
  */
-static bool launch(Display display, String fileName) {
+static bool launch (Display display, String fileName) {
     if (fileName is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
-    switch(getDesktop(display)) {
+    switch (getDesktop (display)) {
         case DESKTOP_GNOME_24:
             if (gnome_24_launch (fileName)) return true;
         default:
-            int index = fileName.lastIndexOf('.');
+            int index = fileName.lastIndexOf ('.');
             if (index !is -1) {
                 String extension = fileName.substring (index);
                 Program program = Program.findProgram (display, extension);
                 if (program !is null && program.execute (fileName)) return true;
             }
+            String lowercaseName = fileName.toLowerCase ();
+            if (lowercaseName.startsWith (PREFIX_HTTP) || lowercaseName.startsWith (PREFIX_HTTPS)) {
+                Program program = Program.findProgram (display, ".html"); //$NON-NLS-1$
+                if (program is null) {
+                    program = Program.findProgram (display, ".htm"); //$NON-NLS-1$
+                }
+                if (program !is null && program.execute (fileName)) return true;
+            }
             break;
     }
     try {
--- a/dwt/widgets/Button.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Button.d	Mon May 12 19:13:01 2008 +0200
@@ -61,7 +61,7 @@
     alias Control.setForegroundColor setForegroundColor;
 
     GtkWidget* boxHandle, labelHandle, imageHandle, arrowHandle, groupHandle;
-    bool selected;
+    bool selected, grayed;
     ImageList imageList;
     Image image;
     String text;
@@ -193,7 +193,7 @@
 
 override void createHandle (int index) {
     state |= HANDLE;
-    if ((style & DWT.PUSH) is 0) state |= THEME_BACKGROUND;
+    if ((style & (DWT.PUSH | DWT.TOGGLE)) is 0) state |= THEME_BACKGROUND;  
     int bits = DWT.ARROW | DWT.TOGGLE | DWT.CHECK | DWT.RADIO | DWT.PUSH;
     fixedHandle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null);
     if (fixedHandle is null) error (DWT.ERROR_NO_HANDLES);
@@ -312,6 +312,12 @@
     return DWT.LEFT;
 }
 
+public bool getGrayed () {
+    checkWidget();
+    if ((style & DWT.CHECK) is 0) return false;
+    return grayed;
+}
+
 /**
  * Returns the receiver's image if it has one, or null
  * if it does not.
@@ -386,6 +392,16 @@
         } else {
             selectRadio ();
         }
+    } else {
+        if ((style & DWT.CHECK) !is 0) {
+            if (grayed) {
+                if (OS.gtk_toggle_button_get_active (handle)) {
+                    OS.gtk_toggle_button_set_inconsistent (handle, true);
+                } else {
+                    OS.gtk_toggle_button_set_inconsistent (handle, false);
+                }
+            }
+        }
     }
     postEvent (DWT.Selection);
     return 0;
@@ -643,6 +659,17 @@
     if (imageHandle !is null) setForegroundColor (imageHandle, color);
 }
 
+public void setGrayed (bool grayed) {
+    checkWidget();
+    if ((style & DWT.CHECK) is 0) return;
+    this.grayed = grayed;
+    if (grayed && OS.gtk_toggle_button_get_active (handle)) {
+        OS.gtk_toggle_button_set_inconsistent (handle, true);
+    } else {
+        OS.gtk_toggle_button_set_inconsistent (handle, false);
+    }
+}
+
 /**
  * Sets the receiver's image to the argument, which may be
  * <code>null</code> indicating that no image should be displayed.
@@ -687,6 +714,7 @@
 override void setOrientation () {
     super.setOrientation ();
     if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        if (boxHandle !is null) OS.gtk_widget_set_direction (boxHandle, OS.GTK_TEXT_DIR_RTL);
         if (labelHandle !is null) OS.gtk_widget_set_direction (labelHandle, OS.GTK_TEXT_DIR_RTL);
         if (imageHandle !is null) OS.gtk_widget_set_direction (imageHandle, OS.GTK_TEXT_DIR_RTL);
         if (arrowHandle !is null) {
@@ -720,6 +748,13 @@
     if ((style & (DWT.CHECK | DWT.RADIO | DWT.TOGGLE)) is 0) return;
     OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCLICKED);
     OS.gtk_toggle_button_set_active (cast(GtkToggleButton*)handle, selected);
+    if ((style & DWT.CHECK) !is 0) {
+        if (selected && grayed) {
+            OS.gtk_toggle_button_set_inconsistent (handle, true);
+        } else {
+            OS.gtk_toggle_button_set_inconsistent (handle, false);
+        }
+    }
     if ((style & DWT.RADIO) !is 0) OS.gtk_toggle_button_set_active (cast(GtkToggleButton*)groupHandle, !selected);
     OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCLICKED);
 }
@@ -776,6 +811,7 @@
 
 override int traversalCode (int key, GdkEventKey* event) {
     int code = super.traversalCode (key, event);
+    if ((style & DWT.ARROW) !is 0) code &= ~(DWT.TRAVERSE_TAB_NEXT | DWT.TRAVERSE_TAB_PREVIOUS);
     if ((style & DWT.RADIO) !is 0) code |= DWT.TRAVERSE_ARROW_NEXT | DWT.TRAVERSE_ARROW_PREVIOUS;
     return code;
 }
--- a/dwt/widgets/Canvas.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Canvas.d	Mon May 12 19:13:01 2008 +0200
@@ -19,6 +19,7 @@
 import dwt.widgets.Composite;
 import dwt.widgets.Caret;
 import dwt.widgets.Control;
+import dwt.widgets.IME;
 import dwt.graphics.GC;
 import dwt.graphics.Rectangle;
 import dwt.graphics.Font;
@@ -47,6 +48,7 @@
     alias Composite.setBounds setBounds;
 
     Caret caret;
+    IME ime;
 
 this () {}
 
@@ -78,7 +80,7 @@
  * @see Widget#getStyle
  */
 public this (Composite parent, int style) {
-    super (parent, style);
+    super (parent, checkStyle (style));
 }
 
 /**
@@ -137,6 +139,27 @@
     return new Point (caret.x, caret.y);
 }
 
+public IME getIME () {
+    checkWidget ();
+    return ime;
+}
+
+override int /*long*/ gtk_button_press_event (GtkWidget* widget, GdkEventButton* event) {
+    if (ime !is null) {
+        auto result = ime.gtk_button_press_event (widget, event);
+        if (result !is 0) return result;
+    }
+    return  super.gtk_button_press_event (widget, event);
+}
+
+override int /*long*/ gtk_commit (GtkIMContext* imcontext, char* text) {
+    if (ime !is null) {
+        auto result = ime.gtk_commit (imcontext, text);
+        if (result !is 0) return result;
+    }
+    return super.gtk_commit (imcontext, text);
+}
+
 override int /*long*/ gtk_expose_event (GtkWidget* widget, GdkEventExpose* event) {
     if ((state & OBSCURED) !is 0) return 0;
     bool isFocus = caret !is null && caret.isFocusCaret ();
@@ -158,6 +181,14 @@
     return result;
 }
 
+override int /*long*/ gtk_preedit_changed (GtkIMContext* imcontext) {
+    if (ime !is null) {
+        auto result = ime.gtk_preedit_changed (imcontext);
+        if (result !is 0) return result;
+    }
+    return super.gtk_preedit_changed (imcontext);
+}
+
 override void redrawWidget (int x, int y, int width, int height, bool redrawAll, bool all, bool trim) {
     bool isFocus = caret !is null && caret.isFocusCaret ();
     if (isFocus) caret.killFocus ();
@@ -170,6 +201,10 @@
         caret.release (false);
         caret = null;
     }
+    if (ime !is null) {
+        ime.release (false);
+        ime = null;
+    }
     super.releaseChildren (destroy);
 }
 
@@ -198,6 +233,11 @@
 public void scroll (int destX, int destY, int x, int y, int width, int height, bool all) {
     checkWidget();
     if (width <= 0 || height <= 0) return;
+    if ((style & DWT.MIRRORED) !is 0) {
+        int clientWidth = getClientWidth ();
+        x = clientWidth - width - x;
+        destX = clientWidth - width - destX;
+    }
     int deltaX = destX - x, deltaY = destY - y;
     if (deltaX is 0 && deltaY is 0) return;
     if (!isVisible ()) return;
@@ -329,6 +369,12 @@
     super.setFont (font);
 }
 
+public void setIME (IME ime) {
+    checkWidget ();
+    if (ime !is null && ime.isDisposed()) error(DWT.ERROR_INVALID_ARGUMENT);
+    this.ime = ime;
+}
+
 void updateCaret () {
     auto imHandle = imHandle ();
     if (imHandle is null) return;
--- a/dwt/widgets/Caret.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Caret.d	Mon May 12 19:13:01 2008 +0200
@@ -43,6 +43,8 @@
     Image image;
     Font font;
 
+    static final int DEFAULT_WIDTH = 1;
+
 /**
  * Constructs a new instance of this class given its parent
  * and a style value describing its behavior and appearance.
@@ -109,11 +111,15 @@
     if (image !is null && !image.isDisposed() && image.mask is null) {
         int width; int height;
         OS.gdk_drawable_get_size(image.pixmap, &width, &height);
+        int nX = x;
+        if ((parent.style & DWT.MIRRORED) !is 0) nX = parent.getClientWidth () - width - nX;
         OS.gdk_draw_drawable(window, gc, image.pixmap, 0, 0, x, y, width, height);
     } else {
         int nWidth = width, nHeight = height;
-        if (nWidth <= 0) nWidth = 1;
-        OS.gdk_draw_rectangle (window, gc, 1, x, y, nWidth, nHeight);
+        if (nWidth <= 0) nWidth = DEFAULT_WIDTH;
+        int nX = x;
+        if ((parent.style & DWT.MIRRORED) !is 0) nX = parent.getClientWidth () - nWidth - nX;
+        OS.gdk_draw_rectangle (window, gc, 1, nX, y, nWidth, nHeight);
     }
     OS.g_object_unref (gc);
     OS.gdk_colormap_free_colors (colormap, color, 1);
@@ -136,6 +142,10 @@
     if (image !is null) {
         Rectangle rect = image.getBounds ();
         return new Rectangle (x, y, rect.width, rect.height);
+    } else {
+        if (width is 0) {
+            return new Rectangle (x, y, DEFAULT_WIDTH, height);
+        }
     }
     return new Rectangle (x, y, width, height);
 }
@@ -217,6 +227,10 @@
     if (image !is null) {
         Rectangle rect = image.getBounds ();
         return new Point (rect.width, rect.height);
+    } else {
+        if (width is 0) {
+            return new Point (DEFAULT_WIDTH, height);
+        }
     }
     return new Point (width, height);
 }
--- a/dwt/widgets/ColorDialog.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/ColorDialog.d	Mon May 12 19:13:01 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * 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
@@ -59,7 +59,7 @@
  * @see Widget#getStyle
  */
 public this (Shell parent) {
-    this (parent, DWT.NONE);
+    this (parent, DWT.APPLICATION_MODAL);
 }
 /**
  * Constructs a new instance of this class given its parent
@@ -90,7 +90,7 @@
  * @see Widget#getStyle
  */
 public this (Shell parent, int style) {
-    super (parent, style);
+    super (parent, checkStyle (parent, style));
     checkSubclass ();
 }
 
@@ -120,6 +120,7 @@
 public RGB open () {
     char* buffer = toStringz(title);
     auto handle = cast(GtkWidget*)OS.gtk_color_selection_dialog_new (buffer);
+    Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     if (parent !is null) {
         auto shellHandle = parent.topHandle ();
         OS.gtk_window_set_transient_for (handle, shellHandle);
@@ -138,9 +139,28 @@
         OS.gtk_color_selection_set_current_color (dialog.colorsel, &color);
     }
     OS.gtk_color_selection_set_has_palette (dialog.colorsel, true);
-    Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     display.addIdleProc ();
+    Dialog oldModal = null;
+    if (OS.gtk_window_get_modal (handle)) {
+        oldModal = display.getModalDialog ();
+        display.setModalDialog (this);
+    }
+    int signalId = 0;
+    int /*long*/ hookId = 0;
+    CallbackData emissionData;
+    emissionData.display = display;
+    emissionData.data = handle;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+        hookId = OS.g_signal_add_emission_hook (signalId, 0, &Display.emissionFunc, &emissionData, null);
+    }
     int response = OS.gtk_dialog_run (handle);
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.g_signal_remove_emission_hook (signalId, hookId);
+    }
+    if (OS.gtk_window_get_modal (handle)) {
+        display.setModalDialog (oldModal);
+    }
     bool success = response is OS.GTK_RESPONSE_OK;
     if (success) {
         OS.gtk_color_selection_get_current_color (dialog.colorsel, &color);
--- a/dwt/widgets/Combo.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Combo.d	Mon May 12 19:13:01 2008 +0200
@@ -75,7 +75,7 @@
     alias Composite.setToolTipText setToolTipText;
     alias Composite.translateTraversal translateTraversal;
 
-    GtkWidget* buttonHandle, entryHandle, listHandle, textRenderer;
+    GtkWidget* buttonHandle, entryHandle, listHandle, textRenderer, cellHandle, popupHandle;
     int lastEventTime, visibleCount = 5;
     GdkEventKey* gdkEventKey;
     int fixStart = -1, fixEnd = -1;
@@ -191,6 +191,9 @@
     char* buffer = toStringz(string);
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
         OS.gtk_combo_box_insert_text (handle, index, buffer);
+        if ((style & DWT.RIGHT_TO_LEFT) !is 0 && popupHandle !is null) {
+            display.doSetDirectionProc( popupHandle, OS.GTK_TEXT_DIR_RTL);
+        }
     } else {
         /*
         * Feature in GTK. When the list is empty and the first item
@@ -438,15 +441,19 @@
     if (fixedHandle is null) error (DWT.ERROR_NO_HANDLES);
     OS.gtk_fixed_set_has_window (fixedHandle, true);
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
+        auto oldList = OS.gtk_window_list_toplevels ();
         if ((style & DWT.READ_ONLY) !is 0) {
             handle = OS.gtk_combo_box_new_text ();
             if (handle is null) error (DWT.ERROR_NO_HANDLES);
+            cellHandle = OS.gtk_bin_get_child (handle);
+            if (cellHandle is null) error (DWT.ERROR_NO_HANDLES);
         } else {
             handle = OS.gtk_combo_box_entry_new_text ();
             if (handle is null) error (DWT.ERROR_NO_HANDLES);
             entryHandle = OS.gtk_bin_get_child (handle);
             if (entryHandle is null) error (DWT.ERROR_NO_HANDLES);
         }
+        popupHandle = findPopupHandle (oldList);
         OS.gtk_container_add (fixedHandle, handle);
         textRenderer = cast(GtkWidget*)OS.gtk_cell_renderer_text_new ();
         if (textRenderer is null) error (DWT.ERROR_NO_HANDLES);
@@ -492,6 +499,15 @@
             OS.g_list_free (display.allChildren);
             display.allChildren = null;
         }
+        /*
+        * Feature in GTK. By default, read only combo boxes
+        * process the RETURN key rather than allowing the
+        * default button to process the key. The fix is to
+        * clear the GTK_RECEIVES_DEFAULT flag.
+        */
+        if ((style & DWT.READ_ONLY) !is 0 && buttonHandle !is null) {
+            OS.GTK_WIDGET_UNSET_FLAGS (buttonHandle, OS.GTK_RECEIVES_DEFAULT);
+        }
     } else {
         handle = OS.gtk_combo_new ();
         if (handle is null) error (DWT.ERROR_NO_HANDLES);
@@ -500,6 +516,20 @@
         entryHandle = combo.entry;
         listHandle = combo.list;
 
+        if (OS.GTK_VERSION < OS.buildVERSION (2, 4, 0)) {
+            GtkWidget* parentHandle = null;
+            auto temp = listHandle;
+            while ((temp = OS.gtk_widget_get_parent(temp)) !is null) {
+                parentHandle = temp;
+            }
+            popupHandle = parentHandle;
+            if (popupHandle !is null) {
+                GtkWidget* modalGroup = getShell().modalGroup;
+                if (modalGroup !is null) {
+                    OS.gtk_window_group_add_window (modalGroup, popupHandle);
+                }
+            }
+        }
         /*
         * Feature in GTK.  There is no API to query the arrow
         * handle from a combo box although it is possible to
@@ -569,6 +599,47 @@
     return false;
 }
 
+GtkWidget* findPopupHandle (GList* oldList) {
+    GtkWidget* hdl = null;
+    GList* currentList = OS.gtk_window_list_toplevels();
+    GList* oldFromList = oldList;
+    GList* newFromList = currentList;
+    bool isFound;
+    while (newFromList !is null) {
+        void* newToplevel = OS.g_list_data(newFromList);
+        isFound = false;
+        oldFromList = oldList;
+        while (oldFromList !is null) {
+            void* oldToplevel = OS.g_list_data(oldFromList);
+            if (newToplevel is oldToplevel) {
+                isFound = true;
+                break;
+            }
+            oldFromList = OS.g_list_next(oldFromList);
+        }
+        if (!isFound) {
+            hdl = cast(GtkWidget*)newToplevel;
+            break;
+        }
+        newFromList = OS.g_list_next(newFromList);
+    }
+    OS.g_list_free(oldList);
+    OS.g_list_free(currentList);
+    return hdl;
+}
+
+override void fixModal (GtkWidget* group, GtkWidget* modalGroup) {
+    if (popupHandle !is null) {
+        if (group !is null) {
+            OS.gtk_window_group_add_window (group, popupHandle);
+        } else {
+            if (modalGroup !is null) {
+                OS.gtk_window_group_remove_window (modalGroup, popupHandle);
+            }
+        }
+    }
+}
+
 void fixIM () {
     /*
     *  The IM filter has to be called one time for each key press event.
@@ -620,6 +691,7 @@
         OS.g_signal_connect_closure (entryHandle, OS.insert_text.ptr, display.closures [INSERT_TEXT], false);
         OS.g_signal_connect_closure (entryHandle, OS.delete_text.ptr, display.closures [DELETE_TEXT], false);
         OS.g_signal_connect_closure (entryHandle, OS.activate.ptr, display.closures [ACTIVATE], false);
+        OS.g_signal_connect_closure (entryHandle, OS.populate_popup.ptr, display.closures [POPULATE_POPUP], false);
     }
     int eventMask = OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_PRESS_MASK |
         OS.GDK_BUTTON_RELEASE_MASK;
@@ -836,6 +908,18 @@
     return result;
 }
 
+public bool getListVisible () {
+    checkWidget ();
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
+        return popupHandle !is null && OS.GTK_WIDGET_VISIBLE (popupHandle);
+    }
+    return false;
+}
+
+String getNameText () {
+    return getText ();
+}
+
 /**
  * Returns the orientation of the receiver.
  *
@@ -1023,6 +1107,18 @@
     return 0;
 }
 
+override int /*long*/ gtk_button_press_event (GtkWidget* widget, GdkEventButton* event) {
+    /*
+    * Feature in GTK. Depending on where the user clicks, GTK prevents
+    * the left mouse button event from being propagated. The fix is to
+    * send the mouse event from the event_after handler.
+    */
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
+        if (event.type is OS.GDK_BUTTON_PRESS) return 0;
+    }
+    return super.gtk_button_press_event (widget, event);
+}
+
 override int gtk_changed (GtkWidget* widget) {
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
         if (widget is handle) {
@@ -1143,6 +1239,54 @@
     return 0;
 }
 
+override int /*long*/ gtk_event_after (GtkWidget* widget, GdkEvent* event) {
+    /*
+    * Feature in GTK. Depending on where the user clicks, GTK prevents
+    * the left mouse button event from being propagated. The fix is to
+    * send the mouse event from the event_after handler.
+    *
+    * Feature in GTK. When the user clicks anywhere in an editable
+    * combo box, a single focus event should be issued, despite the
+    * fact that focus might switch between the drop down button and
+    * the text field. The fix is to use gtk_combo_box_set_focus_on_click ()
+    * to eat all focus events while focus is in the combo box. When the
+    * user clicks on the drop down button focus is assigned to the text
+    * field.
+    */
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
+        switch (event.type) {
+            case OS.GDK_BUTTON_PRESS: {
+                GdkEventButton* gdkEventButton = cast(GdkEventButton*)event;
+                if (gdkEventButton.button is 1) {
+                    if (!sendMouseEvent (DWT.MouseDown, gdkEventButton.button, display.clickCount, 0, false, gdkEventButton.time, gdkEventButton.x_root, gdkEventButton.y_root, false, gdkEventButton.state)) {
+                        return 1;
+                    }
+                    if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 0)) {
+                        if ((style & DWT.READ_ONLY) is 0 && widget is buttonHandle) {
+                            OS.gtk_widget_grab_focus (entryHandle);
+                        }
+                    }
+                }
+                break;
+            }
+            case OS.GDK_FOCUS_CHANGE: {
+                if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 0)) {
+                    if ((style & DWT.READ_ONLY) is 0) {
+                        GdkEventFocus* gdkEventFocus = cast(GdkEventFocus*)event;
+                        if (gdkEventFocus.in_ !is 0) {
+                            OS.gtk_combo_box_set_focus_on_click (handle, false);
+                        } else {
+                            OS.gtk_combo_box_set_focus_on_click (handle, true);
+                        }
+                    }
+                }
+                break;
+            }
+        }
+    }
+    return super.gtk_event_after(widget, event);
+}
+
 override int gtk_focus_out_event (GtkWidget* widget, GdkEventFocus* event) {
     fixIM ();
     return super.gtk_focus_out_event (widget, event);
@@ -1196,9 +1340,57 @@
     if (result !is 0) fixIM ();
     if (gdkEventKey is cast(GdkEventKey*)-1) result = 1;
     gdkEventKey = null;
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0) && (style & DWT.READ_ONLY) is 0) {
+        GdkEventKey* keyEvent = cast(GdkEventKey*)event;
+        int oldIndex = OS.gtk_combo_box_get_active (handle);
+        int newIndex = oldIndex;
+        int key = keyEvent.keyval;
+        switch (key) {
+            case OS.GDK_Down:
+            case OS.GDK_KP_Down:
+                 if (oldIndex !is (items.length - 1)) {
+                    newIndex = oldIndex + 1;
+                 }
+                 break;
+            case OS.GDK_Up:
+            case OS.GDK_KP_Up:
+                if (oldIndex !is -1 && oldIndex !is 0) {
+                    newIndex = oldIndex - 1;
+                }
+                break;
+            /*
+            * Feature in GTK. In gtk_combo_box, the PageUp and PageDown keys
+            * go the first and last items in the list rather than scrolling
+            * a page at a time. The fix is to emulate this behavior for
+            * gtk_combo_box_entry.
+            */
+            case OS.GDK_Page_Up:
+            case OS.GDK_KP_Page_Up:
+                newIndex = 0;
+                break;
+            case OS.GDK_Page_Down:
+            case OS.GDK_KP_Page_Down:
+                newIndex = items.length - 1;
+                break;
+        }
+        if (newIndex !is oldIndex) {
+            OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+            OS.gtk_combo_box_set_active (handle, newIndex);
+            OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+            return 1;
+        }
+    }
     return result;
 }
 
+override int /*long*/ gtk_populate_popup (GtkWidget* widget, GtkWidget* menu) {
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.gtk_widget_set_direction (menu, OS.GTK_TEXT_DIR_RTL);
+        display.doSetDirectionProc(menu, OS.GTK_TEXT_DIR_RTL);
+    }
+    return 0;
+}
+
 /**
  * Searches the receiver's list starting at the first item
  * (index 0) until an item is found that is equal to the
@@ -1250,6 +1442,14 @@
     return -1;
 }
 
+override bool isFocusHandle(GtkWidget* widget) {
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
+        if (buttonHandle !is null && widget is buttonHandle) return true;
+        if (entryHandle !is null && widget is entryHandle) return true;
+    }
+    return super.isFocusHandle (widget);
+}
+
 override GdkDrawable* paintWindow () {
     auto childHandle =  entryHandle !is null ? entryHandle : handle;
     OS.gtk_widget_realize (childHandle);
@@ -1546,6 +1746,14 @@
         OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
         OS.gtk_combo_box_set_active (handle, index);
         OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+        if ((style & DWT.READ_ONLY) !is 0) {
+            /*
+            * Feature in GTK. Read Only combo boxes do not get a chance to send out a
+            * Modify event in the gtk_changed callback. The fix is to send a Modify event
+            * here.
+            */
+            sendEvent (DWT.Modify);
+        }
     } else {
         ignoreSelect = true;
         OS.gtk_list_select_item (listHandle, index);
@@ -1565,7 +1773,8 @@
 }
 
 override int setBounds (int x, int y, int width, int height, bool move, bool resize) {
-    int newHeight = resize ? getTextHeight () : height;
+    int newHeight = height;
+    if (resize) newHeight = Math.max (getTextHeight (), height);
     return super.setBounds (x, y, width, newHeight, move, resize);
 }
 
@@ -1652,6 +1861,9 @@
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
         OS.gtk_combo_box_remove_text (handle, index);
         OS.gtk_combo_box_insert_text (handle, index, buffer);
+        if ((style & DWT.RIGHT_TO_LEFT) !is 0 && popupHandle !is null) {
+            display.doSetDirectionProc(popupHandle, OS.GTK_TEXT_DIR_RTL);
+        }
     } else {
         ignoreSelect = true;
         auto children = OS.gtk_container_get_children (listHandle);
@@ -1695,6 +1907,9 @@
             String string = items [i];
             char* buffer = toStringz(string);
             OS.gtk_combo_box_insert_text (handle, i, buffer);
+            if ((style & DWT.RIGHT_TO_LEFT) !is 0 && popupHandle !is null) {
+                display.doSetDirectionProc(popupHandle, OS.GTK_TEXT_DIR_RTL);
+            }
         }
     } else {
         lockText = ignoreSelect = true;
@@ -1720,7 +1935,7 @@
     }
 }
 
-/*public*/ void setListVisible (bool visible) {
+public void setListVisible (bool visible) {
     checkWidget ();
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
         if (visible) {
@@ -1736,6 +1951,7 @@
     if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
         if (listHandle !is null) OS.gtk_widget_set_direction (listHandle, OS.GTK_TEXT_DIR_RTL);
         if (entryHandle !is null) OS.gtk_widget_set_direction (entryHandle, OS.GTK_TEXT_DIR_RTL);
+        if (cellHandle !is null) OS.gtk_widget_set_direction (cellHandle, OS.GTK_TEXT_DIR_RTL);
     }
 }
 
@@ -1754,26 +1970,30 @@
  * @since 2.1.2
  */
 public void setOrientation (int orientation) {
-    checkWidget();
-    int flags = DWT.RIGHT_TO_LEFT | DWT.LEFT_TO_RIGHT;
-    if ((orientation & flags) is 0 || (orientation & flags) is flags) return;
-    style &= ~flags;
-    style |= orientation & flags;
-    int dir = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? OS.GTK_TEXT_DIR_RTL : OS.GTK_TEXT_DIR_LTR;
-    OS.gtk_widget_set_direction (fixedHandle, dir);
-    OS.gtk_widget_set_direction (handle, dir);
-    if (entryHandle !is null) OS.gtk_widget_set_direction (entryHandle, dir);
-    if (listHandle !is null) {
-        OS.gtk_widget_set_direction (listHandle, dir);
-        auto itemsList = OS.gtk_container_get_children (listHandle);
-        if (itemsList !is null) {
-            int count = OS.g_list_length (itemsList);
-            for (int i=count - 1; i>=0; i--) {
-                auto widget = OS.gtk_bin_get_child (OS.g_list_nth_data (itemsList, i));
-                OS.gtk_widget_set_direction (widget, dir);
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
+        checkWidget();
+        int flags = DWT.RIGHT_TO_LEFT | DWT.LEFT_TO_RIGHT;
+        if ((orientation & flags) is 0 || (orientation & flags) is flags) return;
+        style &= ~flags;
+        style |= orientation & flags;
+        int dir = (orientation & DWT.RIGHT_TO_LEFT) !is 0 ? OS.GTK_TEXT_DIR_RTL : OS.GTK_TEXT_DIR_LTR;
+        OS.gtk_widget_set_direction (fixedHandle, dir);
+        OS.gtk_widget_set_direction (handle, dir);
+    	if (entryHandle !is null) OS.gtk_widget_set_direction (entryHandle, dir);
+    	if (listHandle !is null) {
+            OS.gtk_widget_set_direction (listHandle, dir);
+            auto itemsList = OS.gtk_container_get_children (listHandle);
+            if (itemsList !is null) {
+                int count = OS.g_list_length (itemsList);
+                for (int i=count - 1; i>=0; i--) {
+                    auto widget = OS.gtk_bin_get_child (OS.g_list_nth_data (itemsList, i));
+                    OS.gtk_widget_set_direction (widget, dir);
+                }
+                OS.g_list_free (itemsList);
             }
-            OS.g_list_free (itemsList);
         }
+        if (cellHandle !is null) OS.gtk_widget_set_direction (cellHandle, dir);
+        if (popupHandle !is null) display.doSetDirectionProc (popupHandle, dir);
     }
 }
 
@@ -1834,6 +2054,12 @@
             OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
             OS.gtk_combo_box_set_active (handle, index);
             OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+            /*
+            * Feature in GTK. Read Only combo boxes do not get a chance to send out a
+            * Modify event in the gtk_changed callback. The fix is to send a Modify event
+            * here.
+            */
+            sendEvent (DWT.Modify);
             return;
         }
     }
--- a/dwt/widgets/Composite.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Composite.d	Mon May 12 19:13:01 2008 +0200
@@ -27,6 +27,7 @@
 import dwt.internal.gtk.OS;
 import dwt.graphics.GC;
 import dwt.DWT;
+import dwt.graphics.Region;
 import dwt.internal.cairo.Cairo;
 import dwt.internal.gtk.OS;
 import dwt.graphics.Rectangle;
@@ -118,7 +119,12 @@
  * @see Widget#getStyle
  */
 public this (Composite parent, int style) {
-    super (parent, style);
+    super (parent, checkStyle (style));
+}
+
+static int checkStyle (int style) {
+    style &= ~DWT.TRANSPARENT;
+    return style;
 }
 
 Control [] _getChildren () {
@@ -296,7 +302,7 @@
     OS.gtk_fixed_set_has_window (cast(GtkFixed*)handle, true);
     OS.GTK_WIDGET_SET_FLAGS(handle, OS.GTK_CAN_FOCUS);
     if ((style & DWT.EMBEDDED) is 0) {
-        if ((state & CANVAS) !is 0 && (style & DWT.NO_FOCUS) is 0) {
+        if ((state & CANVAS) !is 0) {
             /* Prevent an input method context from being created for the Browser widget */
             if (display.getData (NO_INPUT_METHOD) is null) {
                 imHandle_ = OS.gtk_im_multicontext_new ();
@@ -328,7 +334,7 @@
         if (socketHandle is null) DWT.error (DWT.ERROR_NO_HANDLES);
         OS.gtk_container_add (cast(GtkContainer*)handle, cast(GtkWidget*)socketHandle);
     }
-    if ((style & DWT.NO_REDRAW_RESIZE) !is 0) {
+    if ((style & DWT.NO_REDRAW_RESIZE) !is 0 && (style & DWT.RIGHT_TO_LEFT) is 0) {
         OS.gtk_widget_set_redraw_on_allocate (handle, false);
     }
     /*
@@ -373,6 +379,10 @@
                 auto pattern = Cairo.cairo_pattern_create_for_surface (surface);
                 if (pattern is null) error (DWT.ERROR_NO_HANDLES);
                 Cairo.cairo_pattern_set_extend (pattern, Cairo.CAIRO_EXTEND_REPEAT);
+                if ((data.style & DWT.MIRRORED) !is 0) {
+                    double[] matrix = [-1.0, 0, 0, 1, 0, 0 ];
+                    Cairo.cairo_pattern_set_matrix(pattern, cast(cairo_matrix_t*)matrix.ptr);
+                }
                 Cairo.cairo_set_source (cairo, pattern);
                 Cairo.cairo_surface_destroy (surface);
                 Cairo.cairo_pattern_destroy (pattern);
@@ -442,6 +452,13 @@
     }
 }
 
+void fixModal(GtkWidget* group, GtkWidget* modalGroup)  {
+    Control[] controls = _getChildren ();
+    for (int i = 0; i < controls.length; i++) {
+        controls[i].fixModal (group, modalGroup);
+    }
+}
+
 override void fixStyle () {
     super.fixStyle ();
     if (scrolledHandle is null) fixStyle (handle);
@@ -583,6 +600,10 @@
     return super.getClientArea();
 }
 
+int getClientWidth() {
+    return (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (clientHandle ());
+}
+
 /**
  * Returns layout which is associated with the receiver, or
  * null if one has not been set.
@@ -684,6 +705,7 @@
         event.y = rectangles[i].y;
         event.width = rectangles[i].width;
         event.height = rectangles[i].height;
+        if ((style & DWT.MIRRORED) !is 0) event.x = getClientWidth () - event.width - event.x;
         auto damageRgn = OS.gdk_region_new ();
         OS.gdk_region_union_with_rect (damageRgn, rectangles + i );
         GCData data = new GCData ();
@@ -1085,6 +1107,41 @@
     parentHandle = cast(GtkWidget*)fixed;
 }
 
+void moveChildren(int oldWidth) {
+    Control[] children = _getChildren ();
+    for (int i = 0; i < children.length; i++) {
+        Control child = children[i];
+        auto topHandle = child.topHandle ();
+        int x = OS.GTK_WIDGET_X (topHandle);
+        int y = OS.GTK_WIDGET_Y (topHandle);
+        int controlWidth = (child.state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle);
+        x = oldWidth - controlWidth - x;
+        int clientWidth = getClientWidth ();
+        x = clientWidth - controlWidth - x;
+        if (child.enableWindow !is null) {
+            OS.gdk_window_move (child.enableWindow, x, y);
+        }
+        child.moveHandle (x, y);
+        /*
+        * Cause a size allocation this widget's topHandle.  Note that
+        * all calls to gtk_widget_size_allocate() must be preceded by
+        * a call to gtk_widget_size_request().
+        */
+        GtkRequisition requisition;
+        gtk_widget_size_request (topHandle, &requisition);
+        GtkAllocation allocation;
+        allocation.x = x;
+        allocation.y = y;
+        allocation.width = OS.GTK_WIDGET_WIDTH (topHandle);
+        allocation.height = OS.GTK_WIDGET_HEIGHT (topHandle);
+        OS.gtk_widget_size_allocate (topHandle, &allocation);
+        Control control = child.findBackgroundControl ();
+        if (control !is null && control.backgroundImage !is null) {
+            if (child.isVisible ()) child.redrawWidget (0, 0, 0, 0, true, true, true);
+        }
+    }
+}
+
 Point minimumSize (int wHint, int hHint, bool changed) {
     Control [] children = _getChildren ();
     int width = 0, height = 0;
@@ -1101,6 +1158,34 @@
     return fixedHandle !is null ? fixedHandle : handle;
 }
 
+override void printWidget (GC gc, GdkDrawable* drawable, int depth, int x, int y) {
+    Region oldClip = new Region (gc.getDevice ());
+    Region newClip = new Region (gc.getDevice ());
+    gc.getClipping (oldClip);
+    Rectangle rect = getBounds ();
+    newClip.add (oldClip);
+    newClip.intersect (x, y, rect.width, rect.height);
+    gc.setClipping (newClip);
+    super.printWidget (gc, drawable, depth, x, y);
+    Rectangle clientRect = getClientArea ();
+    Point pt = display.map (this, parent, clientRect.x, clientRect.y);
+    clientRect.x = x + pt.x - rect.x;
+    clientRect.y = y + pt.y - rect.y;
+    newClip.intersect (clientRect);
+    gc.setClipping (newClip);
+    Control [] children = _getChildren ();
+    for (int i=children.length-1; i>=0; --i) {
+        Control child = children [i];
+        if (child.getVisible ()) {
+            Point location = child.getLocation ();
+            child.printWidget (gc, drawable, depth, x + location.x, y + location.y);
+        }
+    }
+    gc.setClipping (oldClip);
+    oldClip.dispose ();
+    newClip.dispose ();
+}
+
 override void redrawChildren () {
     super.redrawChildren ();
     Control [] children = _getChildren ();
--- a/dwt/widgets/Control.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Control.d	Mon May 12 19:13:01 2008 +0200
@@ -39,6 +39,7 @@
 import dwt.graphics.Image;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
+import dwt.graphics.Region;
 import dwt.internal.Converter;
 import dwt.internal.DWTEventListener;
 import dwt.internal.accessibility.gtk.ATK;
@@ -96,6 +97,7 @@
     Menu menu;
     Image backgroundImage;
     Font font;
+    Region region;
     String toolTipText;
     Object layoutData;
     Accessible accessible;
@@ -137,8 +139,8 @@
     createWidget (0);
 }
 
-PangoFontDescription* defaultFont () {
-    return display.getSystemFont ().handle;
+Font defaultFont () {
+    return display.getSystemFont ();
 }
 
 override void deregister () {
@@ -153,6 +155,7 @@
     auto window = OS.GTK_WIDGET_WINDOW (paintHandle);
     if (window is null) return false;
     int orientation = vertical ? OS.GTK_ORIENTATION_HORIZONTAL : OS.GTK_ORIENTATION_VERTICAL;
+    if ((style & DWT.MIRRORED) !is 0) x = getClientWidth () - width - x;
     char dummy;
     OS.gtk_paint_handle (OS.gtk_widget_get_style (paintHandle), window, OS.GTK_STATE_NORMAL, OS.GTK_SHADOW_OUT, null, paintHandle, &dummy, x, y, width, height, orientation);
     return true;
@@ -241,8 +244,7 @@
 
     /* Connect the mouse signals */
     auto eventHandle = eventHandle ();
-    int eventMask = OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_PRESS_MASK |
-        OS.GDK_BUTTON_RELEASE_MASK;
+    int eventMask = OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK;
     OS.gtk_widget_add_events (eventHandle, eventMask);
     OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [BUTTON_PRESS_EVENT], 0, display.closures [BUTTON_PRESS_EVENT], false);
     OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [BUTTON_RELEASE_EVENT], 0, display.closures [BUTTON_RELEASE_EVENT], false);
@@ -296,8 +298,8 @@
 
     OS.g_signal_connect_closure_by_id (paintHandle, display.signalIds [STYLE_SET], 0, display.closures [STYLE_SET], false);
 
-    auto topHandle = topHandle ();
-    OS.g_signal_connect_closure_by_id (topHandle, display.signalIds [MAP], 0, display.closures [MAP], true);
+    auto topHandle_ = topHandle ();
+    OS.g_signal_connect_closure_by_id (topHandle_, display.signalIds [MAP], 0, display.closures [MAP], true);
 }
 
 override int /*long*/ hoverProc (GtkWidget* widget) {
@@ -315,9 +317,9 @@
 }
 
 GtkWidget* paintHandle () {
-    auto topHandle = topHandle ();
+    auto topHandle_ = topHandle ();
     auto paintHandle = handle;
-    while (paintHandle !is topHandle) {
+    while (paintHandle !is topHandle_) {
         if ((OS.GTK_WIDGET_FLAGS (paintHandle) & OS.GTK_NO_WINDOW) is 0) break;
         paintHandle = OS.gtk_widget_get_parent (paintHandle);
     }
@@ -330,6 +332,91 @@
     return OS.GTK_WIDGET_WINDOW (paintHandle);
 }
 
+public bool print (GC gc) {
+    checkWidget ();
+    if (gc is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (gc.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT);
+    auto topHandle_ = topHandle ();
+    OS.gtk_widget_realize (topHandle_);
+    auto window = OS.GTK_WIDGET_WINDOW (topHandle_);
+    GCData data = gc.getGCData ();
+    OS.gdk_window_process_updates (window, cast(int)true);
+    printWidget (gc, data.drawable, OS.gdk_drawable_get_depth (data.drawable), 0, 0);
+    return true;
+}
+
+void printWidget (GC gc, GdkDrawable* drawable, int depth, int x, int y) {
+    bool obscured = (state & OBSCURED) !is 0;
+    state &= ~OBSCURED;
+    auto topHandle_ = topHandle ();
+    auto window = OS.GTK_WIDGET_WINDOW (topHandle_);
+    printWindow (true, this, gc.handle, drawable, depth, window, x, y);
+    if (obscured) state |= OBSCURED;
+}
+
+void printWindow (bool first, Control control, GdkGC* gc, GdkDrawable* drawable, int depth, GdkDrawable* window, int x, int y) {
+    if (OS.gdk_drawable_get_depth (window) !is depth) return;
+    GdkRectangle rect;
+    int width, height;
+    OS.gdk_drawable_get_size (window, &width, &height);
+    rect.width = width;
+    rect.height = height;
+    OS.gdk_window_begin_paint_rect (window, &rect);
+    GdkDrawable* real_drawable;
+    int x_offset, y_offset;
+    OS.gdk_window_get_internal_paint_info (window, &real_drawable, &x_offset, &y_offset);
+    void* userData;
+    OS.gdk_window_get_user_data (window, &userData);
+    if (userData !is null) {
+        GdkEventExpose* event = cast(GdkEventExpose*) OS.gdk_event_new (OS.GDK_EXPOSE);
+        event.type = OS.GDK_EXPOSE;
+        event.window = cast(GdkDrawable*)OS.g_object_ref (window);
+        event.area.width = rect.width;
+        event.area.height = rect.height;
+        event.region = OS.gdk_region_rectangle (&rect);
+        OS.gtk_widget_send_expose (userData, cast(GdkEvent*)event);
+        OS.gdk_event_free (cast(GdkEvent*)event);
+    }
+    int srcX = x_offset, srcY = y_offset;
+    int destX = x, destY = y, destWidth = width, destHeight = height;
+    if (!first) {
+        int cX, cY;
+        OS.gdk_window_get_position (window, &cX, &cY);
+        auto parentWindow = OS.gdk_window_get_parent (window);
+        int pW, pH;
+        OS.gdk_drawable_get_size (parentWindow, &pW, &pH);
+        srcX = x_offset - cX;
+        srcY = y_offset - cY;
+        destX = x - cX;
+        destY = y - cY;
+        destWidth = Math.min (cX + width, pW);
+        destHeight = Math.min (cY + height, pH);
+    }
+    OS.gdk_draw_drawable (drawable, gc, real_drawable, srcX, srcY, destX, destY, destWidth, destHeight);
+    OS.gdk_window_end_paint (window);
+    auto children = OS.gdk_window_get_children (window);
+    if (children !is null) {
+        auto windows = children;
+        while (windows !is null) {
+            auto child = cast(GdkDrawable*) OS.g_list_data (windows);
+            if (OS.gdk_window_is_visible (child)) {
+                void* data;
+                OS.gdk_window_get_user_data (child, &data);
+                if (data !is null) {
+                    Widget widget = display.findWidget ( cast(GtkWidget*) data);
+                    if (widget is null || widget is control) {
+                        int x_pos, y_pos;
+                        OS.gdk_window_get_position (child, &x_pos, &y_pos);
+                        printWindow (false, control, gc, drawable, depth, child, x + x_pos, y + y_pos);
+                    }
+                }
+            }
+            windows = OS.g_list_next (windows);
+        }
+        OS.g_list_free (children);
+    }
+}
+
 /**
  * Returns the preferred size of the receiver.
  * <p>
@@ -423,6 +510,10 @@
     if (getBorderWidth () is 0) style &= ~DWT.BORDER;
 }
 
+void checkMirrored () {
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) style |= DWT.MIRRORED;
+}
+
 GtkStyle* childStyle () {
     return parent.childStyle ();
 }
@@ -438,6 +529,7 @@
     setInitialBounds ();
     setZOrder (null, false, false);
     setRelations ();
+    checkMirrored ();
     checkBorder ();
 }
 
@@ -508,15 +600,15 @@
     * topHandle.  Note that all calls to gtk_widget_size_allocate()
     * must be preceded by a call to gtk_widget_size_request().
     */
-    auto topHandle = topHandle ();
+    auto topHandle_ = topHandle ();
     GtkRequisition requisition;
-    gtk_widget_size_request (topHandle, &requisition);
+    gtk_widget_size_request (topHandle_, &requisition);
     GtkAllocation allocation;
-    allocation.x = OS.GTK_WIDGET_X (topHandle);
-    allocation.y = OS.GTK_WIDGET_Y (topHandle);
-    allocation.width = OS.GTK_WIDGET_WIDTH (topHandle);
-    allocation.height = OS.GTK_WIDGET_HEIGHT (topHandle);
-    OS.gtk_widget_size_allocate (topHandle, &allocation);
+    allocation.x = OS.GTK_WIDGET_X (topHandle_);
+    allocation.y = OS.GTK_WIDGET_Y (topHandle_);
+    allocation.width = OS.GTK_WIDGET_WIDTH (topHandle_);
+    allocation.height = OS.GTK_WIDGET_HEIGHT (topHandle_);
+    OS.gtk_widget_size_allocate (topHandle_, &allocation);
 }
 
 /**
@@ -559,11 +651,12 @@
  */
 public Rectangle getBounds () {
     checkWidget();
-    auto topHandle = topHandle ();
-    int x = OS.GTK_WIDGET_X (topHandle);
-    int y = OS.GTK_WIDGET_Y (topHandle);
-    int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle);
-    int height = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (topHandle);
+    auto topHandle_ = topHandle ();
+    int x = OS.GTK_WIDGET_X (topHandle_);
+    int y = OS.GTK_WIDGET_Y (topHandle_);
+    int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle_);
+    int height = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (topHandle_);
+    if ((parent.style & DWT.MIRRORED) !is 0) x = parent.getClientWidth () - width - x;
     return new Rectangle (x, y, width, height);
 }
 
@@ -623,8 +716,18 @@
     /* Do nothing */
 }
 
+override void modifyStyle (GtkWidget* handle, GtkRcStyle* style) {
+    super.modifyStyle(handle, style);
+    /*
+    * Bug in GTK.  When changing the style of a control that
+    * has had a region set on it, the region is lost.  The
+    * fix is to set the region again.
+    */
+    if (region !is null) OS.gdk_window_shape_combine_region (OS.GTK_WIDGET_WINDOW (topHandle ()), region.handle, 0, 0);
+}
+
 void moveHandle (int x, int y) {
-    auto topHandle = topHandle ();
+    auto topHandle_ = topHandle ();
     auto parentHandle = parent.parentingHandle ();
     /*
     * Feature in GTK.  Calling gtk_fixed_move() to move a child causes
@@ -636,24 +739,38 @@
     */
     int flags = OS.GTK_WIDGET_FLAGS (parentHandle);
     OS.GTK_WIDGET_UNSET_FLAGS (parentHandle, OS.GTK_VISIBLE);
-    OS.gtk_fixed_move (cast(GtkFixed*)parentHandle, topHandle, x, y);
+    OS.gtk_fixed_move (cast(GtkFixed*)parentHandle, topHandle_, x, y);
     if ((flags & OS.GTK_VISIBLE) !is 0) {
         OS.GTK_WIDGET_SET_FLAGS (parentHandle, OS.GTK_VISIBLE);
     }
 }
 
 void resizeHandle (int width, int height) {
-    auto topHandle = topHandle ();
-    OS.gtk_widget_set_size_request (topHandle, width, height);
-    if (topHandle !is handle) OS.gtk_widget_set_size_request (handle, width, height);
+    auto topHandle_ = topHandle ();
+    OS.gtk_widget_set_size_request (topHandle_, width, height);
+    if (topHandle_ !is handle) OS.gtk_widget_set_size_request (handle, width, height);
 }
 
 int setBounds (int x, int y, int width, int height, bool move, bool resize) {
-    auto topHandle = topHandle ();
+    auto topHandle_ = topHandle ();
+    bool sendMove = move;
+    if ((parent.style & DWT.MIRRORED) !is 0) {
+        int clientWidth = parent.getClientWidth ();
+        int oldWidth = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle_);
+        int oldX = clientWidth - oldWidth - OS.GTK_WIDGET_X (topHandle_);
+        if (move) {
+            sendMove &= x !is oldX;
+            x = clientWidth - (resize ? width : oldWidth) - x;
+        } else {
+            move = true;
+            x = clientWidth - (resize ? width : oldWidth) - oldX;
+            y = OS.GTK_WIDGET_Y (topHandle_);
+        }
+    }
     bool sameOrigin = true, sameExtent = true;
     if (move) {
-        int oldX = OS.GTK_WIDGET_X (topHandle);
-        int oldY = OS.GTK_WIDGET_Y (topHandle);
+        int oldX = OS.GTK_WIDGET_X (topHandle_);
+        int oldY = OS.GTK_WIDGET_Y (topHandle_);
         sameOrigin = x is oldX && y is oldY;
         if (!sameOrigin) {
             if (enableWindow !is null) {
@@ -662,10 +779,12 @@
             moveHandle (x, y);
         }
     }
+    int clientWidth = 0;
     if (resize) {
-        int oldWidth = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle);
-        int oldHeight = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (topHandle);
+        int oldWidth = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle_);
+        int oldHeight = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (topHandle_);
         sameExtent = width is oldWidth && height is oldHeight;
+        if (!sameExtent && (style & DWT.MIRRORED) !is 0) clientWidth = getClientWidth ();
         if (!sameExtent && !(width is 0 && height is 0)) {
             int newWidth = Math.max (1, width);
             int newHeight = Math.max (1, height);
@@ -685,23 +804,23 @@
         * a call to gtk_widget_size_request().
         */
         GtkRequisition requisition;
-        gtk_widget_size_request (topHandle, &requisition);
+        gtk_widget_size_request (topHandle_, &requisition);
         GtkAllocation allocation;
         if (move) {
             allocation.x = x;
             allocation.y = y;
         } else {
-            allocation.x = OS.GTK_WIDGET_X (topHandle);
-            allocation.y = OS.GTK_WIDGET_Y (topHandle);
+            allocation.x = OS.GTK_WIDGET_X (topHandle_);
+            allocation.y = OS.GTK_WIDGET_Y (topHandle_);
         }
         if (resize) {
             allocation.width = width;
             allocation.height = height;
         } else {
-            allocation.width = OS.GTK_WIDGET_WIDTH (topHandle);
-            allocation.height = OS.GTK_WIDGET_HEIGHT (topHandle);
+            allocation.width = OS.GTK_WIDGET_WIDTH (topHandle_);
+            allocation.height = OS.GTK_WIDGET_HEIGHT (topHandle_);
         }
-        OS.gtk_widget_size_allocate (topHandle, &allocation);
+        OS.gtk_widget_size_allocate (topHandle_, &allocation);
     }
     /*
     * Bug in GTK.  Widgets cannot be sized smaller than 1x1.
@@ -715,15 +834,16 @@
             if (enableWindow !is null) {
                 OS.gdk_window_hide (enableWindow);
             }
-            OS.gtk_widget_hide (topHandle);
+            OS.gtk_widget_hide (topHandle_);
         } else {
             if ((state & HIDDEN) is 0) {
                 if (enableWindow !is null) {
                     OS.gdk_window_show_unraised (enableWindow);
                 }
-                OS.gtk_widget_show (topHandle);
+                OS.gtk_widget_show (topHandle_);
             }
         }
+        if ((style & DWT.MIRRORED) !is 0) moveChildren (clientWidth);
     }
     int result = 0;
     if (move && !sameOrigin) {
@@ -731,7 +851,7 @@
         if (control !is null && control.backgroundImage !is null) {
             if (isVisible ()) redrawWidget (0, 0, 0, 0, true, true, true);
         }
-        sendEvent (DWT.Move);
+        if (sendMove) sendEvent (DWT.Move);
         result |= MOVED;
     }
     if (resize && !sameExtent) {
@@ -756,9 +876,13 @@
  */
 public Point getLocation () {
     checkWidget();
-    auto topHandle = topHandle ();
-    int x = OS.GTK_WIDGET_X (topHandle);
-    int y = OS.GTK_WIDGET_Y (topHandle);
+    auto topHandle_ = topHandle ();
+    int x = OS.GTK_WIDGET_X (topHandle_);
+    int y = OS.GTK_WIDGET_Y (topHandle_);
+    if ((parent.style & DWT.MIRRORED) !is 0) {
+        int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle_);
+        x = parent.getClientWidth () - width - x;
+    }
     return new Point (x, y);
 }
 
@@ -817,9 +941,9 @@
  */
 public Point getSize () {
     checkWidget();
-    auto topHandle = topHandle ();
-    int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle);
-    int height = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (topHandle);
+    auto topHandle_ = topHandle ();
+    int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle_);
+    int height = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (topHandle_);
     return new Point (width, height);
 }
 
@@ -847,6 +971,16 @@
     setBounds (0, 0, Math.max (0, size.x), Math.max (0, size.y), false, true);
 }
 
+public void setRegion (Region region) {
+    checkWidget ();
+    if ((style & DWT.NO_TRIM) is 0) return;
+    if (region !is null && region.isDisposed()) error (DWT.ERROR_INVALID_ARGUMENT);
+    auto window = OS.GTK_WIDGET_WINDOW (topHandle ());
+    auto shape_region = (region is null) ? null : region.handle;
+    OS.gdk_window_shape_combine_region (window, shape_region, 0, 0);
+    this.region = region;
+}
+
 void setRelations () {
     auto parentHandle = parent.parentingHandle ();
     auto list = OS.gtk_container_get_children (cast(GtkContainer*)parentHandle);
@@ -899,6 +1033,10 @@
     return true;
 }
 
+bool isFocusHandle (GtkWidget* widget) {
+    return widget is focusHandle ();
+}
+
 /**
  * Moves the receiver above the specified control in the
  * drawing order. If the argument is null, then the receiver
@@ -957,6 +1095,9 @@
     setZOrder (control, false, true);
 }
 
+void moveChildren (int oldWidth) {
+}
+
 /**
  * Causes the receiver to be resized to its preferred size.
  * For a composite, this involves computing the preferred size
@@ -1034,7 +1175,10 @@
     auto window = eventWindow ();
     int origin_x, origin_y;
     OS.gdk_window_get_origin (window, &origin_x, &origin_y);
-    return new Point (x - origin_x , y - origin_y );
+    x -= origin_x ;
+    y -= origin_y ;
+    if ((style & DWT.MIRRORED) !is 0) x = getClientWidth () - x;
+    return new Point (x, y);
 }
 
 /**
@@ -1080,7 +1224,10 @@
     auto window = eventWindow ();
     int origin_x, origin_y;
     OS.gdk_window_get_origin (window, &origin_x, &origin_y);
-    return new Point (origin_x + x, origin_y + y);
+    if ((style & DWT.MIRRORED) !is 0) x = getClientWidth () - x;
+    x += origin_x ;
+    y += origin_y ;
+    return new Point (x, y);
 }
 
 /**
@@ -1939,6 +2086,9 @@
     return 0;
 }
 
+void fixModal(GtkWidget* group, GtkWidget* modalGroup) {
+}
+
 /**
  * Forces the receiver to have the <em>keyboard focus</em>, causing
  * all keyboard events to be delivered to it.
@@ -2051,6 +2201,10 @@
     return 0;
 }
 
+int getClientWidth () {
+    return 0;
+}
+
 /**
  * Returns the receiver's cursor, or null if it has not been set.
  * <p>
@@ -2120,8 +2274,7 @@
  */
 public Font getFont () {
     checkWidget();
-    if (font !is null) return font;
-    return Font.gtk_new (display, defaultFont ());
+    return font !is null ? font : defaultFont ();
 }
 
 PangoFontDescription* getFontDescription () {
@@ -2278,6 +2431,11 @@
     return result;
 }
 
+public Region getRegion () {
+    checkWidget ();
+    return region;
+}
+
 /**
  * Returns the receiver's shell. For all controls other than
  * shells, this simply returns the control's nearest ancestor
@@ -2341,6 +2499,7 @@
 
 override int /*long*/ gtk_button_press_event (GtkWidget* widget, GdkEventButton* gdkEvent) {
     if (gdkEvent.type is OS.GDK_3BUTTON_PRESS) return 0;
+
     /*
     * When a shell is created with DWT.ON_TOP and DWT.NO_FOCUS,
     * do not activate the shell when the user clicks on the
@@ -2427,6 +2586,21 @@
 }
 
 override int /*long*/ gtk_enter_notify_event (GtkWidget*  widget, GdkEventCrossing* gdkEvent) {
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
+        /*
+         * Feature in GTK. Children of a shell will inherit and display the shell's
+         * tooltip if they do not have a tooltip of their own. The fix is to use the
+         * new tooltip API in GTK 2.12 to null the shell's tooltip when the control
+         * being entered does not have any tooltip text set.
+         */
+        char* buffer = null;
+        if (toolTipText !is null && toolTipText.length !is 0) {
+            char [] chars = fixMnemonic (toolTipText, false);
+            buffer = tango.stdc.stringz.toStringz(chars);
+        }
+        auto toolHandle = getShell().handle;
+        OS.gtk_widget_set_tooltip_text (toolHandle, buffer);
+    }
     if (display.currentControl is this) return 0;
     if (gdkEvent.mode !is OS.GDK_CROSSING_NORMAL && gdkEvent.mode !is OS.GDK_CROSSING_UNGRAB) return 0;
     if ((gdkEvent.state & (OS.GDK_BUTTON1_MASK | OS.GDK_BUTTON2_MASK | OS.GDK_BUTTON3_MASK)) !is 0) return 0;
@@ -2459,7 +2633,7 @@
             break;
         }
         case OS.GDK_FOCUS_CHANGE: {
-            if (widget !is focusHandle ()) break;
+            if (!isFocusHandle (widget)) break;
             GdkEventFocus* gdkEventFocus = cast(GdkEventFocus*)gdkEvent;
 
             /*
@@ -2503,6 +2677,7 @@
     event.y = gdkEvent.area.y;
     event.width = gdkEvent.area.width;
     event.height = gdkEvent.area.height;
+    if ((style & DWT.MIRRORED) !is 0) event.x = getClientWidth () - event.width - event.x;
     GCData data = new GCData ();
     data.damageRgn = gdkEvent.region;
     GC gc = event.gc = GC.gtk_new (this, data);
@@ -2733,6 +2908,10 @@
         int mask = DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
         if ((data.style & mask) is 0) {
             data.style |= style & (mask | DWT.MIRRORED);
+        } else {
+            if ((data.style & DWT.RIGHT_TO_LEFT) !is 0) {
+                data.style |= DWT.MIRRORED;
+            }
         }
         data.drawable = cast(GdkDrawable*)window;
         data.device = display;
@@ -2740,7 +2919,7 @@
         Control control = findBackgroundControl ();
         if (control is null) control = this;
         data.background = control.getBackgroundColor ();
-        data.font = font !is null ? font.handle : defaultFont ();
+        data.font = font !is null ? font : defaultFont ();
     }
     return gdkGC;
 }
@@ -2969,6 +3148,7 @@
 public void redraw (int x, int y, int width, int height, bool all) {
     checkWidget();
     if (!OS.GTK_WIDGET_VISIBLE (topHandle ())) return;
+    if ((style & DWT.MIRRORED) !is 0) x = getClientWidth () - width - x;
     redrawWidget (x, y, width, height, false, all, false);
 }
 
@@ -3046,6 +3226,7 @@
     toolTipText = null;
     layoutData = null;
     accessible = null;
+    region = null;
 }
 
 bool sendDragEvent (int button, int stateMask, int x, int y, bool isStateMask) {
@@ -3053,6 +3234,7 @@
     event.button = button;
     event.x = x;
     event.y = y;
+    if ((style & DWT.MIRRORED) !is 0) event.x = getClientWidth () - event.x;
     if (isStateMask) {
         event.stateMask = stateMask;
     } else {
@@ -3129,6 +3311,7 @@
         event.x = cast(int)x - origin_x;
         event.y = cast(int)y - origin_y;
     }
+    if ((style & DWT.MIRRORED) !is 0) event.x = getClientWidth () - event.x;
     setInputState (event, state);
     if (send) {
         sendEvent (type, event);
@@ -3207,7 +3390,7 @@
     int flags = OS.gtk_rc_style_get_color_flags (style, index);
     flags = (color is null) ? flags & ~OS.GTK_RC_BG : flags | OS.GTK_RC_BG;
     OS.gtk_rc_style_set_color_flags (style, index, flags);
-    OS.gtk_widget_modify_style (handle, style);
+    modifyStyle (handle, style);
 }
 
 void setBackgroundColor (GdkColor* color) {
@@ -3379,8 +3562,8 @@
         }
     } else {
         OS.gtk_widget_realize (handle);
-        auto parentHandle = parent.parentingHandle ();
-        auto window = OS.GTK_WIDGET_WINDOW (parentHandle);
+        auto parentHandle = parent.eventHandle ();
+        auto window = parent.eventWindow();
         Rectangle rect = getBounds ();
         GdkWindowAttr attributes;
         attributes.x = rect.x;
@@ -3392,12 +3575,12 @@
         attributes.window_type = OS.GDK_WINDOW_CHILD;
         enableWindow = OS.gdk_window_new (window, &attributes, OS.GDK_WA_X | OS.GDK_WA_Y);
         if (enableWindow !is null) {
-            auto topHandle = topHandle ();
+            auto topHandle_ = topHandle ();
             OS.gdk_window_set_user_data (enableWindow, parentHandle);
             if (!OS.GDK_WINDOWING_X11 ()) {
                 OS.gdk_window_raise (enableWindow);
             } else {
-                auto topWindow = OS.GTK_WIDGET_WINDOW (topHandle);
+                auto topWindow = OS.GTK_WIDGET_WINDOW (topHandle_);
                 auto xDisplay = OS.gdk_x11_drawable_get_xdisplay (cast(GdkDrawable*)topWindow);
                 auto xWindow = OS.gdk_x11_drawable_get_xid (cast(GdkDrawable*)enableWindow);
                 int xScreen = OS.XDefaultScreen (xDisplay);
@@ -3407,7 +3590,7 @@
                 changes.stack_mode = OS.Above;
                 OS.XReconfigureWMWindow (xDisplay, xWindow, xScreen, flags, &changes);
             }
-            if (OS.GTK_WIDGET_VISIBLE (topHandle)) OS.gdk_window_show_unraised (enableWindow);
+            if (OS.GTK_WIDGET_VISIBLE (topHandle_)) OS.gdk_window_show_unraised (enableWindow);
         }
     }
     if (fixFocus_) fixFocus (control);
@@ -3454,7 +3637,7 @@
     this.font = font;
     PangoFontDescription* fontDesc;
     if (font is null) {
-        fontDesc = defaultFont ();
+        fontDesc = defaultFont ().handle;
     } else {
         if (font.isDisposed ()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
         fontDesc = font.handle;
@@ -3526,9 +3709,13 @@
         * first sized.  The fix is to set the value to (0, 0) as
         * expected by DWT.
         */
-        auto topHandle = topHandle ();
-        OS.GTK_WIDGET_SET_X (topHandle, 0);
-        OS.GTK_WIDGET_SET_Y (topHandle, 0);
+        auto topHandle_ = topHandle ();
+        if ((parent.style & DWT.MIRRORED) !is 0) {
+            OS.GTK_WIDGET_SET_X (topHandle_, parent.getClientWidth ());
+        } else {
+            OS.GTK_WIDGET_SET_X (topHandle_, 0);
+        }
+        OS.GTK_WIDGET_SET_Y (topHandle_, 0);
     } else {
         resizeHandle (1, 1);
         forceResize ();
@@ -3603,6 +3790,16 @@
     if (parent.isDisposed()) DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     if (this.parent is parent) return true;
     if (!isReparentable ()) return false;
+    auto topHandle_ = topHandle ();
+    int x = OS.GTK_WIDGET_X (topHandle_);
+    int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (topHandle_);
+    if ((this.parent.style & DWT.MIRRORED) !is 0) {
+        x =  this.parent.getClientWidth () - width - x;
+    }
+    if ((parent.style & DWT.MIRRORED) !is 0) {
+        x = parent.getClientWidth () - width - x;
+    }
+    int y = OS.GTK_WIDGET_Y (topHandle_);
     releaseParent ();
     Shell newShell = parent.getShell (), oldShell = getShell ();
     Decorations newDecorations = parent.menuShell (), oldDecorations = menuShell ();
@@ -3612,12 +3809,9 @@
         newDecorations.fixAccelGroup ();
         oldDecorations.fixAccelGroup ();
     }
-    auto topHandle = topHandle ();
     auto newParent = parent.parentingHandle();
-    int x = OS.GTK_WIDGET_X (topHandle);
-    int y = OS.GTK_WIDGET_Y (topHandle);
-    OS.gtk_widget_reparent (topHandle, newParent);
-    OS.gtk_fixed_move (cast(GtkFixed*)newParent, topHandle, x, y);
+    OS.gtk_widget_reparent (topHandle_, newParent);
+    OS.gtk_fixed_move (cast(GtkFixed*)newParent, topHandle_, x, y);
     this.parent = parent;
     setZOrder (null, false, true);
     return true;
@@ -3723,7 +3917,25 @@
 }
 
 void setToolTipText (Shell shell, String newString) {
-    shell.setToolTipText (eventHandle (), newString);
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
+        /*
+        * Feature in GTK.  In order to prevent children widgets
+        * from inheriting their parent's tooltip, the tooltip is
+        * a set on a shell only. In order to force the shell tooltip
+        * to update when a new tip string is set, the existing string
+        * in the tooltip is set to null, followed by running a query.
+        * The real tip text can then be set.
+        *
+        * Note that this will only run if the control for which the
+        * tooltip is being set is the current control (i.e. the control
+        * under the pointer).
+        */
+        if (display.currentControl is this) {
+            shell.setToolTipText (shell.handle, eventHandle (), newString);
+        }
+    } else {
+        shell.setToolTipText (eventHandle (), newString);
+    }
 }
 
 /**
@@ -3745,7 +3957,7 @@
 public void setVisible (bool visible) {
     checkWidget();
     if (((state & HIDDEN) is 0) is visible) return;
-    auto topHandle = topHandle();
+    auto topHandle_ = topHandle();
     if (visible) {
         /*
         * It is possible (but unlikely), that application
@@ -3757,7 +3969,7 @@
         state &= ~HIDDEN;
         if ((state & (ZERO_WIDTH | ZERO_HEIGHT)) is 0) {
             if (enableWindow !is null) OS.gdk_window_show_unraised (enableWindow);
-            OS.gtk_widget_show (topHandle);
+            OS.gtk_widget_show (topHandle_);
         }
     } else {
         /*
@@ -3777,12 +3989,12 @@
         }
         state |= HIDDEN;
         if (fixFocus_) {
-            OS.GTK_WIDGET_UNSET_FLAGS (topHandle, OS.GTK_VISIBLE);
+            OS.GTK_WIDGET_UNSET_FLAGS (topHandle_, OS.GTK_VISIBLE);
             fixFocus (control);
             if (isDisposed ()) return;
-            OS.GTK_WIDGET_SET_FLAGS (topHandle, OS.GTK_VISIBLE);
+            OS.GTK_WIDGET_SET_FLAGS (topHandle_, OS.GTK_VISIBLE);
         }
-        OS.gtk_widget_hide (topHandle);
+        OS.gtk_widget_hide (topHandle_);
         if (isDisposed ()) return;
         if (enableWindow !is null) OS.gdk_window_hide (enableWindow);
         sendEvent (DWT.Hide);
@@ -3826,9 +4038,9 @@
         }
     }
 
-    auto topHandle = topHandle ();
+    auto topHandle_ = topHandle ();
     auto siblingHandle = sibling !is null ? sibling.topHandle () : null;
-    auto window = OS.GTK_WIDGET_WINDOW (topHandle);
+    auto window = OS.GTK_WIDGET_WINDOW (topHandle_);
     if (window !is null) {
         GdkWindow* siblingWindow;
         if (sibling !is null) {
@@ -3877,9 +4089,9 @@
     }
     if (fixChildren) {
         if (above) {
-            parent.moveAbove (topHandle, siblingHandle);
+            parent.moveAbove (topHandle_, siblingHandle);
         } else {
-            parent.moveBelow (topHandle, siblingHandle);
+            parent.moveBelow (topHandle_, siblingHandle);
         }
     }
     /*  Make sure that the parent internal windows are on the bottom of the stack   */
@@ -3922,10 +4134,10 @@
 void setWidgetBackground  () {
     if (fixedHandle !is null) {
         auto style = OS.gtk_widget_get_modifier_style (fixedHandle);
-        OS.gtk_widget_modify_style (fixedHandle, style);
+        modifyStyle (fixedHandle, style);
     }
     auto style = OS.gtk_widget_get_modifier_style (handle);
-    OS.gtk_widget_modify_style (handle, style);
+    modifyStyle (handle, style);
 }
 
 bool showMenu (int x, int y) {
@@ -3950,11 +4162,11 @@
 void showWidget () {
     // Comment this line to disable zero-sized widgets
     state |= ZERO_WIDTH | ZERO_HEIGHT;
-    auto topHandle = topHandle ();
+    auto topHandle_ = topHandle ();
     auto parentHandle = parent.parentingHandle ();
-    parent.setParentWindow (topHandle);
-    OS.gtk_container_add (cast(GtkContainer*)parentHandle, topHandle);
-    if (handle !is null && handle !is topHandle) OS.gtk_widget_show (handle);
+    parent.setParentWindow (topHandle_);
+    OS.gtk_container_add (cast(GtkContainer*)parentHandle, topHandle_);
+    if (handle !is null && handle !is topHandle_) OS.gtk_widget_show (handle);
     if ((state & (ZERO_WIDTH | ZERO_HEIGHT)) is 0) {
         if (fixedHandle !is null) OS.gtk_widget_show (fixedHandle);
     }
@@ -4057,6 +4269,9 @@
         case OS.GDK_Down:
         case OS.GDK_Right: {
             bool next = key is OS.GDK_Down || key is OS.GDK_Right;
+            if (parent !is null && (parent.style & DWT.MIRRORED) !is 0) {
+                if (key is OS.GDK_Left || key is OS.GDK_Right) next = !next;
+            }
             detail = next ? DWT.TRAVERSE_ARROW_NEXT : DWT.TRAVERSE_ARROW_PREVIOUS;
             break;
         }
--- a/dwt/widgets/CoolBar.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/CoolBar.d	Mon May 12 19:13:01 2008 +0200
@@ -135,7 +135,7 @@
         addListener(events[i], listener);
     }
 }
-private static int checkStyle (int style) {
+static int checkStyle (int style) {
     style |= DWT.NO_FOCUS;
     return (style | DWT.NO_REDRAW_RESIZE) & ~(DWT.V_SCROLL | DWT.H_SCROLL);
 }
@@ -323,7 +323,7 @@
 void insertItemIntoRow(CoolItem item, int rowIndex, int x_root) {
     int barWidth = getWidth();
     int rowY = items[rowIndex][0].internalGetBounds().y;
-    int x = Math.max(0, x_root - toDisplay(new Point(0, 0)).x);
+    int x = Math.max(0, Math.abs(x_root - toDisplay(new Point(0, 0)).x));
 
     /* Find the insertion index and add the item. */
     int index;
@@ -623,7 +623,7 @@
     fixEvent(event);
     CoolItem grabbed = getGrabbedItem(event.x, event.y);
     if (dragging !is null) {
-        int left_root = toDisplay(new Point(event.x, event.y)).x - itemXOffset;
+        int left_root = toDisplay(new Point(event.x - itemXOffset, event.y)).x;
         Rectangle bounds = dragging.internalGetBounds();
         if (event.y < bounds.y) {
             moveUp(dragging, left_root);
--- a/dwt/widgets/CoolItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/CoolItem.d	Mon May 12 19:13:01 2008 +0200
@@ -276,7 +276,7 @@
     imageData.transparentPixel = 1;
     Image image = new Image (display, imageData);
 
-    GC gc = new GC (image);
+    GC gc = new GC (image, parent.getStyle() & DWT.RIGHT_TO_LEFT);
     gc.setBackground (background);
     gc.fillRectangle (0, 0, width, height);
     gc.setForeground (black);
--- a/dwt/widgets/DateTime.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/DateTime.d	Mon May 12 19:13:01 2008 +0200
@@ -190,7 +190,11 @@
         default: assert( false, Format( "no matching switch case for field {}.", field ));
         }
     }
-
+    void set( int year, int month, int day ){
+        this.year = year;
+        this.month = month;
+        this.dayofmonth = day;
+    }
     void set(int field, int value){
         switch( field ){
         case YEAR:
@@ -433,6 +437,8 @@
         formatSymbols = new DateFormatSymbols();
 
         text = new Text(this, DWT.SINGLE);
+        /* disable the native drag and drop for the date/time text field */
+        OS.gtk_drag_dest_unset(text.handle);
         if ((this.style & DWT.DATE) !is 0) {
             setFormat((this.style & DWT.SHORT) !is 0 ? DEFAULT_SHORT_DATE_FORMAT : (this.style & DWT.LONG) !is 0 ? DEFAULT_LONG_DATE_FORMAT : DEFAULT_MEDIUM_DATE_FORMAT);
         } else { // DWT.TIME
@@ -639,8 +645,8 @@
         int m = calendar.get(Calendar.MINUTE);
         int s = calendar.get(Calendar.SECOND);
         int a = calendar.get(Calendar.AM_PM);
-        if ((style & DWT.SHORT) !is 0) return "" ~ (h < 10 ? " " : "") ~ to!(String)(h) ~ ":" ~ (m < 10 ? " " : "") ~ to!(String)(m) ~ " " ~ ampm[a];
-        return "" ~ (h < 10 ? " " : "") ~ to!(String)(h) ~ ":" ~ (m < 10 ? " " : "") ~ to!(String)(m) ~ ":" ~ (s < 10 ? " " : "") ~ to!(String)(s) ~ " " ~ ampm[a];
+        if ((style & DWT.SHORT) !is 0) return "" ~ (h < 10 ? " " : "") ~ to!(String)(h) ~ ":" ~ (m < 10 ? "0" : "") ~ to!(String)(m) ~ " " ~ ampm[a];
+        return "" ~ (h < 10 ? " " : "") ~ to!(String)(h) ~ ":" ~ (m < 10 ? "0" : "") ~ to!(String)(m) ~ ":" ~ (s < 10 ? "0" : "") ~ to!(String)(s) ~ " " ~ ampm[a];
     }
     /* DWT.DATE */
     int y = calendar.get(Calendar.YEAR);
@@ -750,6 +756,15 @@
     }
 }
 
+String getNameText() {
+    if((style & DWT.TIME) !is 0){
+        return Format( "{}:{}:{}", getHours(), getMinutes(), getSeconds() );
+    }
+    else{
+        return Format( "{}/{}/{}", (getMonth() + 1), getDay(), getYear() );
+    }
+}
+
 /**
  * Returns the receiver's seconds.
  * <p>
@@ -827,6 +842,12 @@
     return value >= min && value <= max;
 }
 
+bool isValid(int year, int month, int day) {
+    Calendar valid = Calendar.getInstance();
+    valid.set(year, month, day);
+    return valid.get(Calendar.YEAR) is year && valid.get(Calendar.MONTH) is month && valid.get(Calendar.DAY_OF_MONTH) is day;
+}
+
 void incrementField(int amount) {
     int fieldName = fieldNames[currentField];
     int value = calendar.get(fieldName);
@@ -1111,7 +1132,7 @@
         calendar.roll(Calendar.HOUR_OF_DAY, 12); // TODO: needs more work for setFormat and locale
     }
     calendar.set(fieldName, value);
-    notifyListeners(DWT.Selection, new Event());
+    postEvent(DWT.Selection);
 }
 
 void setTextField(int fieldName, int value, bool commit, bool adjust) {
@@ -1138,7 +1159,15 @@
     /* Convert leading 0's into spaces. */
     int prependCount = end - start - buffer.length();
     for (int i = 0; i < prependCount; i++) {
-        buffer.prepend(' ');
+        switch (fieldName) {
+        case Calendar.MINUTE:
+        case Calendar.SECOND:
+            buffer.prepend('0');
+        break;
+        default:
+            buffer.prepend(' ');
+        break;
+        }
     }
     newValue = buffer.toString();
     ignoreVerify = true;
@@ -1149,6 +1178,41 @@
 }
 
 /**
+ * Sets the receiver's year, month, and day in a single operation.
+ * <p>
+ * This is the recommended way to set the date, because setting the year,
+ * month, and day separately may result in invalid intermediate dates.
+ * </p>
+ *
+ * @param year an integer between 1752 and 9999
+ * @param month an integer between 0 and 11
+ * @param day a positive integer beginning with 1
+ *
+ * @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.4
+ */
+public void setDate (int year, int month, int day) {
+    checkWidget ();
+    if (!isValid(year, month, day)) return;
+    if ((style & DWT.CALENDAR) !is 0) {
+        this.year = year;
+        this.month = month;
+        this.day = day;
+        OS.gtk_calendar_select_month(handle, month, year);
+        OS.gtk_calendar_select_day(handle, day);
+    } else {
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, month);
+        calendar.set(Calendar.DAY_OF_MONTH, day);
+        updateControl();
+    }
+}
+
+/**
  * Sets the receiver's date, or day of the month, to the specified day.
  * <p>
  * The first day of the month is 1, and the last day depends on the month and year.
@@ -1271,6 +1335,37 @@
 }
 
 /**
+ * Sets the receiver's hours, minutes, and seconds in a single operation.
+ *
+ * @param hours an integer between 0 and 23
+ * @param minutes an integer between 0 and 59
+ * @param seconds an integer between 0 and 59
+ *
+ * @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.4
+ */
+public void setTime (int hours, int minutes, int seconds) {
+    checkWidget ();
+    if (!isValid(Calendar.HOUR_OF_DAY, hours)) return;
+    if (!isValid(Calendar.MINUTE, minutes)) return;
+    if (!isValid(Calendar.SECOND, seconds)) return;
+    if ((style & DWT.CALENDAR) !is 0) {
+        this.hours = hours;
+        this.minutes = minutes;
+        this.seconds = seconds;
+    } else {
+        calendar.set(Calendar.HOUR_OF_DAY, hours);
+        calendar.set(Calendar.MINUTE, minutes);
+        calendar.set(Calendar.SECOND, seconds);
+        updateControl();
+    }
+}
+
+/**
  * Sets the receiver's year.
  * <p>
  * The first year is 1752 and the last year is 9999.
--- a/dwt/widgets/Dialog.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Dialog.d	Mon May 12 19:13:01 2008 +0200
@@ -19,6 +19,7 @@
 import dwt.DWTException;
 import dwt.widgets.Shell;
 import dwt.widgets.Display;
+import dwt.widgets.Widget;
 
 /**
  * This class is the abstract superclass of the classes
@@ -171,6 +172,20 @@
     parent.checkWidget ();
 }
 
+static int checkStyle (Shell parent, int style) {
+    if ((style & (DWT.PRIMARY_MODAL | DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL)) is 0) {
+        style |= DWT.APPLICATION_MODAL;
+    }
+    style &= ~DWT.MIRRORED;
+    if ((style & (DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT)) is 0) {
+        if (parent !is null) {
+            if ((parent.style & DWT.LEFT_TO_RIGHT) !is 0) style |= DWT.LEFT_TO_RIGHT;
+            if ((parent.style & DWT.RIGHT_TO_LEFT) !is 0) style |= DWT.RIGHT_TO_LEFT;
+        }
+    }
+    return Widget.checkBits (style, DWT.LEFT_TO_RIGHT, DWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
+}
+
 /**
  * Does whatever dialog specific cleanup is required, and then
  * uses the code in <code>DWTError.error</code> to handle the error.
--- a/dwt/widgets/DirectoryDialog.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/DirectoryDialog.d	Mon May 12 19:13:01 2008 +0200
@@ -59,7 +59,7 @@
  * </ul>
  */
 public this (Shell parent) {
-    this (parent, DWT.PRIMARY_MODAL);
+    this (parent, DWT.APPLICATION_MODAL);
 }
 /**
  * Constructs a new instance of this class given its parent
@@ -86,7 +86,7 @@
  * </ul>
  */
 public this (Shell parent, int style) {
-    super (parent, style);
+    super (parent, checkStyle (parent, style));
     checkSubclass ();
 }
 /**
@@ -154,7 +154,17 @@
         else{
             p = filterPath;
         }
-        OS.gtk_file_chooser_set_current_folder (handle, tango.stdc.stringz.toStringz(p));
+        char* buffer = tango.stdc.stringz.toStringz(p);
+        /*
+        * Bug in GTK. GtkFileChooser may crash on GTK versions 2.4.10 to 2.6
+        * when setting a file name that is not a true canonical path.
+        * The fix is to use the canonical path.
+        */
+        char* ptr = OS.realpath (buffer, null);
+        if (ptr !is null) {
+            OS.gtk_file_chooser_set_current_folder (handle, ptr);
+            OS.g_free (ptr);
+        }
     }
     if (message.length > 0) {
         char* buffer = tango.stdc.stringz.toStringz(message);
@@ -171,7 +181,27 @@
     String answer = null;
     Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     display.addIdleProc ();
+    Dialog oldModal = null;
+    if (OS.gtk_window_get_modal (handle)) {
+        oldModal = display.getModalDialog ();
+        display.setModalDialog (this);
+    }
+    int signalId = 0;
+    int /*long*/ hookId = 0;
+    CallbackData emissionData;
+    emissionData.display = display;
+    emissionData.data = handle;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+        hookId = OS.g_signal_add_emission_hook (signalId, 0, &Display.emissionFunc, &emissionData, null);
+    }
     int response = OS.gtk_dialog_run (handle);
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.g_signal_remove_emission_hook (signalId, hookId);
+    }
+    if (OS.gtk_window_get_modal (handle)) {
+        display.setModalDialog (oldModal);
+    }
     if (response is OS.GTK_RESPONSE_OK) {
         auto path = OS.gtk_file_chooser_get_filename (handle);
         if (path !is null) {
@@ -180,7 +210,7 @@
             OS.g_free (path);
             if (utf8Ptr !is null) {
                 answer = utf8Ptr[ 0 .. items_written ].dup;
-                filterPath = answer[ tango.text.Util.locatePatternPrior( answer, SEPARATOR ) + 1 .. $ ];
+                filterPath = answer;
                 OS.g_free (utf8Ptr);
             }
         }
@@ -227,7 +257,27 @@
     }
     Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     display.addIdleProc ();
+    Dialog oldModal = null;
+    if (OS.gtk_window_get_modal (handle)) {
+        oldModal = display.getModalDialog ();
+        display.setModalDialog (this);
+    }
+    int signalId = 0;
+    int /*long*/ hookId = 0;
+    CallbackData emissionData;
+    emissionData.display = display;
+    emissionData.data = handle;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+        hookId = OS.g_signal_add_emission_hook (signalId, 0, &Display.emissionFunc, &emissionData, null);
+    }
     int response = OS.gtk_dialog_run (handle);
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.g_signal_remove_emission_hook (signalId, hookId);
+    }
+    if (OS.gtk_window_get_modal (handle)) {
+        display.setModalDialog (oldModal);
+    }
     if (response is OS.GTK_RESPONSE_OK) {
         char* fileNamePtr = OS.gtk_file_selection_get_filename (handle);
         uint items_written;
--- a/dwt/widgets/Display.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Display.d	Mon May 12 19:13:01 2008 +0200
@@ -32,6 +32,7 @@
 import dwt.internal.gtk.OS;
 import dwt.widgets.Caret;
 import dwt.widgets.Control;
+import dwt.widgets.Dialog;
 import dwt.widgets.Event;
 import dwt.widgets.EventTable;
 import dwt.widgets.Listener;
@@ -144,7 +145,7 @@
 
     CallbackData  filterProcCallbackData;
     EventTable eventTable, filterTable;
-    static String APP_NAME = "DWT";
+    static String APP_NAME = "DWT"; //$NON-NLS-1$
     static const String DISPATCH_EVENT_KEY = "dwt.internal.gtk.dispatchEvent";
     static const String ADD_WIDGET_KEY = "dwt.internal.addWidget";
     GClosure*[] closures;
@@ -161,6 +162,12 @@
     static int SWT_OBJECT_INDEX1;
     static int SWT_OBJECT_INDEX2;
 
+    /* Modality */
+    Shell [] modalShells;
+    Dialog modalDialog;
+    static final String GET_MODAL_DIALOG = "dwt.internal.gtk.getModalDialog"; //$NON-NLS-1$
+    static final String SET_MODAL_DIALOG = "dwt.internal.gtk.setModalDialog"; //$NON-NLS-1$
+
     /* Focus */
     int focusEvent;
     Control focusControl;
@@ -212,9 +219,8 @@
     /* Idle proc callback */
     CallbackData idleProcCallbackData;
     int idleHandle;
-    static const String ADD_IDLE_PROC_KEY = "dwt.internal.gtk2.addIdleProc";
-    static const String REMOVE_IDLE_PROC_KEY = "dwt.internal.gtk2.removeIdleProc";
-
+    static const String ADD_IDLE_PROC_KEY = "dwt.internal.gtk.addIdleProc";
+    static const String REMOVE_IDLE_PROC_KEY = "dwt.internal.gtk.removeIdleProc";
     Object idleLock;
     bool idleNeeded;
 
@@ -224,6 +230,11 @@
 
     /* Set direction callback */
     CallbackData setDirectionProcCallbackData;
+    static const String GET_DIRECTION_PROC_KEY = "dwt.internal.gtk.getDirectionProc"; //$NON-NLS-1$
+
+    /* Set emissionProc callback */
+    CallbackData emissionProcCallbackData;
+    static const String GET_EMISSION_PROC_KEY = "dwt.internal.gtk.getEmissionProc"; //$NON-NLS-1$
 
     /* Get all children callback */
     CallbackData allChildrenProcCallbackData;
@@ -279,6 +290,8 @@
     /* Fixed Subclass */
     static int /*long*/ fixed_type;
     static int /*long*/ fixed_info_ptr;
+    static extern(C) void function(GtkWidget* handle, GtkAllocation* allocation) oldFixedSizeAllocateProc;
+
 
     /* Renderer Subclass */
     static int /*long*/ text_renderer_type, pixbuf_renderer_type, toggle_renderer_type;
@@ -391,18 +404,12 @@
 //      PACKAGE_NAME = name.substring (0, index + 1);
 //  }
 
-    /*
-    * In order to support CLDC, .class cannot be used because
-    * it does not compile on some Java compilers when they are
-    * targeted for CLDC.  Use Class.forName() instead.
-    */
-    //synchronized static void static_this() {
     static this() {
-            Displays = new Display [4];
-            initDeviceFinder();
-            SWT_OBJECT_INDEX = OS.g_quark_from_string ("SWT_OBJECT_INDEX");
-            SWT_OBJECT_INDEX1 = OS.g_quark_from_string ("SWT_OBJECT_INDEX1");
-            SWT_OBJECT_INDEX2 = OS.g_quark_from_string ("SWT_OBJECT_INDEX2");
+        Displays = new Display [4];
+        initDeviceFinder();
+        SWT_OBJECT_INDEX = OS.g_quark_from_string ("SWT_OBJECT_INDEX");
+        SWT_OBJECT_INDEX1 = OS.g_quark_from_string ("SWT_OBJECT_INDEX1");
+        SWT_OBJECT_INDEX2 = OS.g_quark_from_string ("SWT_OBJECT_INDEX2");
     }
 
     /* GTK Version */
@@ -694,14 +701,16 @@
  * @see #syncExec
  */
 public void asyncExec (Runnable runnable) {
-    if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
-    synchronized (idleLock) {
-        if (idleNeeded && idleHandle is 0) {
-            //NOTE: calling unlocked function in OS
-            idleHandle = OS.g_idle_add (&idleProcFunc, cast(void*) this);
+    synchronized (Device.classinfo) {
+        if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
+        synchronized (idleLock) {
+            if (idleNeeded && idleHandle is 0) {
+                //NOTE: calling unlocked function in OS
+                idleHandle = OS.g_idle_add (&idleProcFunc, cast(void*) this);
+            }
         }
+        synchronizer.asyncExec (runnable);
     }
-    synchronizer.asyncExec (runnable);
 }
 
 /**
@@ -760,11 +769,13 @@
     if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
 }
 
-static synchronized void checkDisplay (Thread thread, bool multiple) {
-    for (int i=0; i<Displays.length; i++) {
-        if (Displays [i] !is null) {
-            if (!multiple) DWT.error (DWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]");
-            if (Displays [i].thread is thread) DWT.error (DWT.ERROR_THREAD_INVALID_ACCESS);
+static void checkDisplay (Thread thread, bool multiple) {
+    synchronized (Device.classinfo) {
+        for (int i=0; i<Displays.length; i++) {
+            if (Displays [i] !is null) {
+                if (!multiple) DWT.error (DWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]"); //$NON-NLS-1$
+                if (Displays [i].thread is thread) DWT.error (DWT.ERROR_THREAD_INVALID_ACCESS);
+            }
         }
     }
 }
@@ -848,6 +859,22 @@
 //PORTING_TODO  if (!isValidClass (getClass ())) error (DWT.ERROR_INVALID_SUBCLASS);
 }
 
+void clearModal (Shell shell) {
+    if (modalShells is null) return;
+    int index = 0, length_ = modalShells.length;
+    while (index < length_) {
+        if (modalShells [index] is shell) break;
+        if (modalShells [index] is null) return;
+        index++;
+    }
+    if (index is length_) return;
+    System.arraycopy (modalShells, index + 1, modalShells, index, --length_ - index);
+    modalShells [length_] = null;
+    if (index is 0 && modalShells [0] is null) modalShells = null;
+    Shell [] shells = getShells ();
+    for (int i=0; i<shells.length; i++) shells [i].updateModal ();
+}
+
 /**
  * Requests that the connection between DWT and the underlying
  * operating system be closed.
@@ -884,7 +911,7 @@
     checkSubclass ();
     checkDisplay(thread = Thread.getThis (), false);
     createDisplay (data);
-    register ();
+    register (this);
     if (Default is null) Default = this;
 }
 
@@ -895,7 +922,7 @@
     return 0;
 }
 
-synchronized void createDisplay (DeviceData data) {
+void createDisplay (DeviceData data) {
     /* Required for g_main_context_wakeup */
     if (!OS.g_thread_supported ()) {
         OS.g_thread_init (null);
@@ -905,7 +932,6 @@
     char*[] args = [ "name".ptr, "--sync".ptr, null ];
     char** a = args.ptr;
     if (!OS.gtk_init_check (&cnt, &a )) {
-        DWT.error (DWT.ERROR_NO_HANDLES, null, " [gtk_init_check() failed]");
     }
     assert( cnt is 1 );
     if (OS.GDK_WINDOWING_X11 ()) xDisplay = cast(void*) OS.GDK_DISPLAY ();
@@ -1077,9 +1103,11 @@
     return pixbuf;
 }
 
-synchronized void deregister () {
-    for (int i=0; i<Displays.length; i++) {
-        if (this is Displays [i]) Displays [i] = null;
+static void deregister (Display display) {
+    synchronized (Device.classinfo) {
+        for (int i=0; i<Displays.length; i++) {
+            if (display is Displays [i]) Displays [i] = null;
+        }
     }
 }
 
@@ -1095,13 +1123,25 @@
  */
 protected override void destroy () {
     if (this is Default) Default = null;
-    deregister ();
+    deregister (this);
     destroyDisplay ();
 }
 
 void destroyDisplay () {
 }
 
+static extern(C) int /*long*/ emissionFunc (GSignalInvocationHint* ihint, uint n_param_values, GValue* param_values, void* data) {
+    auto cb = cast(CallbackData*)data;
+    return cb.display.emissionProc( ihint, n_param_values, param_values, cb.data );
+}
+
+int /*long*/ emissionProc (GSignalInvocationHint* ihint, uint n_param_values, GValue* param_values, void* data) {
+    if (OS.gtk_widget_get_toplevel (OS.g_value_peek_pointer(param_values)) is data) {
+        OS.gtk_widget_set_direction (OS.g_value_peek_pointer(param_values), OS.GTK_TEXT_DIR_RTL);
+    }
+    return 1;
+}
+
 /**
  * Returns the display which the given thread is the
  * user-interface thread for, or null if the given thread
@@ -1112,14 +1152,16 @@
  * @param thread the user-interface thread
  * @return the display for the given thread
  */
-public static synchronized Display findDisplay (Thread thread) {
-    for (int i=0; i<Displays.length; i++) {
-        Display display = Displays [i];
-        if (display !is null && display.thread is thread) {
-            return display;
+public static Display findDisplay (Thread thread) {
+    synchronized (Device.classinfo) {
+        for (int i=0; i<Displays.length; i++) {
+            Display display = Displays [i];
+            if (display !is null && display.thread is thread) {
+                return display;
+            }
         }
+        return null;
     }
-    return null;
 }
 
 /**
@@ -1200,61 +1242,8 @@
         addGdkEvent (OS.gdk_event_copy (event));
         return 0;
     }
-    /*
-    * Feature in GTK.  GTK implements modality by adding a grab
-    * to the GTK top level window.  Normally, all mouse and
-    * keyboard events are delivered to child widgets and the
-    * shell when the grab is active.  When an override redirect
-    * shell is created as a child of a dialog, then events are
-    * grabbed by the dialog instead of the override redirect
-    * shell.  The fix is to add a temporary grab to the override
-    * redirect window when there is not already a grab in a
-    * child widget of the override redirect shell (for example,
-    * in a scroll bar).
-    */
-    Shell shell = null;
-    Control control = null;
-    auto grabHandle = OS.gtk_grab_get_current ();
-    if (grabHandle !is null && OS.GTK_IS_WINDOW (cast(GTypeInstance*)grabHandle) && OS.gtk_window_get_modal (cast(GtkWindow*)grabHandle)) {
-        switch (eventType) {
-            case OS.GDK_KEY_PRESS:
-            case OS.GDK_KEY_RELEASE:
-            case OS.GDK_ENTER_NOTIFY:
-            case OS.GDK_LEAVE_NOTIFY:
-            case OS.GDK_BUTTON_PRESS:
-            case OS.GDK_2BUTTON_PRESS:
-            case OS.GDK_3BUTTON_PRESS:
-            case OS.GDK_BUTTON_RELEASE:
-            case OS.GDK_MOTION_NOTIFY:  {
-                auto window = OS.GDK_EVENT_WINDOW (cast(GdkEventAny*)event);
-                do {
-                    GtkWidget* handle;
-                    OS.gdk_window_get_user_data (window, cast(void**) &handle);
-                    if (handle !is null) {
-                        Widget widget = getWidget (handle);
-                        if (widget !is null && (null !is cast(Control)widget)) {
-                            control = cast(Control) widget;
-                            break;
-                        }
-                    }
-                } while ((window = OS.gdk_window_get_parent (window)) !is null);
-            default:
-            }
-        }
-        if (control !is null) {
-            shell = control.getShell ();
-            if ((shell.style & DWT.ON_TOP) !is 0) {
-                OS.gtk_grab_add (shell.shellHandle);
-            }
-        }
-    }
     OS.gtk_main_do_event (event);
     if (dispatchEvents is null) putGdkEvents ();
-    if (control !is null) {
-        if (shell !is null && !shell.isDisposed () && (shell.style & DWT.ON_TOP) !is 0) {
-            OS.gtk_grab_remove (shell.shellHandle);
-        }
-    }
     return 0;
 }
 
@@ -1325,7 +1314,7 @@
  *
  * @since 3.3
  */
-public Widget findWidget (Widget widget, int id) {
+public Widget findWidget (Widget widget, int /*long*/ id) {
     checkDevice ();
     return null;
 }
@@ -1334,6 +1323,8 @@
     version(LOG) Stderr.formatln( "Display {}:", __LINE__ ).flush;
     GtkWidgetClass* klass = cast(GtkWidgetClass*)g_class;
     klass.map = &fixedMapProcFunc;
+    oldFixedSizeAllocateProc = klass.size_allocate;
+    klass.size_allocate = &fixedSizeAllocateProc;
 }
 
 private static extern(C)  void fixedMapProcFunc (GtkWidget * handle) {
@@ -1343,11 +1334,19 @@
     if (widget !is null) widget.fixedMapProc (handle);
 }
 
+private static extern(C) static void fixedSizeAllocateProc (GtkWidget* handle, GtkAllocation* allocation) {
+    Display display = getCurrent ();
+    Widget widget = display.getWidget (handle);
+    if (widget !is null) return widget.fixedSizeAllocateProc (handle, allocation);
+    return oldFixedSizeAllocateProc(handle, allocation);
+}
+
 private static extern(C) void rendererClassInitProcFunc (void* g_class, void* class_data) {
     version(LOG) Stderr.formatln( "Display {}:", __LINE__ ).flush;
     GtkCellRendererClass* klass = cast(GtkCellRendererClass*)g_class;
     klass.render = &rendererRenderProcFunc;
     klass.get_size = &rendererGetSizeProcFunc;
+
 }
 private static extern(C) void rendererGetSizeProcFunc(
     GtkCellRenderer      *cell,
@@ -1423,13 +1422,8 @@
  *
  * @return the current display
  */
-public static synchronized Display getCurrent () {
-    Thread current = Thread.getThis ();
-    for (int i=0; i<Displays.length; i++) {
-        Display display = Displays [i];
-        if (display !is null && display.thread is current) return display;
-    }
-    return null;
+public static Display getCurrent () {
+    return findDisplay (Thread.getThis ());
 }
 
 int getCaretBlinkTime () {
@@ -1464,10 +1458,41 @@
 public Control getCursorControl () {
     checkDevice();
     int x, y;
+    GtkWidget* handle;
+    GtkWidget* user_data;
     auto window = OS.gdk_window_at_pointer (&x, &y);
-    if (window is null) return null;
-    GtkWidget* handle;
-    OS.gdk_window_get_user_data (window, cast(void**)&handle);
+    if (window !is null) {
+        OS.gdk_window_get_user_data (window, cast(void**)&user_data);
+        handle = user_data;
+    } else {
+        /*
+        * Feature in GTK. gdk_window_at_pointer() will not return a window
+        * if the pointer is over a foreign embedded window. The fix is to use
+        * XQueryPointer to find the containing GDK window.
+        */
+        if (!OS.GDK_WINDOWING_X11 ()) return null;
+        OS.gdk_error_trap_push ();
+        int unusedInt;
+        uint unusedUInt;
+        uint unusedPtr;
+        uint buffer;
+        uint xWindow, xParent = OS.XDefaultRootWindow (xDisplay);
+        do {
+            if (OS.XQueryPointer (xDisplay, xParent, &unusedPtr, &buffer, &unusedInt, &unusedInt, &unusedInt, &unusedInt, &unusedUInt) is 0) {
+                handle = null;
+                break;
+            }
+            if ((xWindow = buffer) !is 0) {
+                xParent = xWindow;
+                auto gdkWindow = OS.gdk_window_lookup (xWindow);
+                if (gdkWindow !is null)    {
+                    OS.gdk_window_get_user_data (gdkWindow, cast(void**)&user_data);
+                    if (user_data !is null) handle = user_data;
+                }
+            }
+        } while (xWindow !is 0);
+        OS.gdk_error_trap_pop ();
+    }
     if (handle is null) return null;
     do {
         Widget widget = getWidget (handle);
@@ -1587,12 +1612,21 @@
 public Object getData (String key) {
     checkDevice ();
     if (key is null) error (DWT.ERROR_NULL_ARGUMENT);
-    if (key ==/*eq*/ DISPATCH_EVENT_KEY) {
+    if (key.equals (DISPATCH_EVENT_KEY)) {
         return new ArrayWrapperInt(dispatchEvents);
     }
+    if (key.equals (GET_MODAL_DIALOG)) {
+        return modalDialog;
+    }
+    if (key.equals (GET_DIRECTION_PROC_KEY)) {
+        return new LONG (cast(int) &setDirectionProcFunc);
+    }
+    if (key.equals (GET_EMISSION_PROC_KEY)) {
+        return new LONG (cast(int) &emissionFunc);
+    }
     if (keys is null) return null;
     for (int i=0; i<keys.length; i++) {
-        if (keys [i] ==/*eq*/ key) return values [i];
+        if (keys [i].equals(key)) return values [i];
     }
     return null;
 }
@@ -1667,9 +1701,11 @@
  *
  * @return the default display
  */
-public static synchronized Display getDefault () {
-    if (Default is null) Default = new Display ();
-    return Default;
+public static Display getDefault () {
+    synchronized (Device.classinfo) {
+        if (Default is null) Default = new Display ();
+        return Default;
+    }
 }
 
 // /+static bool isValidClass (Class clazz) {
@@ -1826,6 +1862,10 @@
     return synchronizer.getMessageCount ();
 }
 
+Dialog getModalDialog () {
+    return modalDialog;
+}
+
 /**
  * Returns the work area, an EWMH property to store the size
  * and position of the screen not covered by dock and panel
@@ -1972,6 +2012,23 @@
 }
 
 /**
+ * Gets the synchronizer used by the display.
+ *
+ * @return the receiver's synchronizer
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public Synchronizer getSynchronizer () {
+    checkDevice ();
+    return synchronizer;
+}
+
+/**
  * Returns the thread that has invoked <code>syncExec</code>
  * or null if no such runnable is currently being invoked by
  * the user-interface thread.
@@ -1987,8 +2044,10 @@
  * </ul>
  */
 public Thread getSyncThread () {
-    if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
-    return synchronizer.syncThread;
+    synchronized (Device.classinfo) {
+        if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
+        return synchronizer.syncThread;
+    }
 }
 
 /**
@@ -2122,23 +2181,23 @@
     switch (id) {
         case DWT.ICON_ERROR:
             if (errorImage is null) {
-                errorImage = createImage ("gtk-dialog-error");
+                errorImage = createImage ("gtk-dialog-error"); //$NON-NLS-1$
             }
             return errorImage;
         case DWT.ICON_INFORMATION:
         case DWT.ICON_WORKING:
             if (infoImage is null) {
-                infoImage = createImage ("gtk-dialog-info");
+                infoImage = createImage ("gtk-dialog-info"); //$NON-NLS-1$
             }
             return infoImage;
         case DWT.ICON_QUESTION:
             if (questionImage is null) {
-                questionImage = createImage ("gtk-dialog-question");
+                questionImage = createImage ("gtk-dialog-question"); //$NON-NLS-1$
             }
             return questionImage;
         case DWT.ICON_WARNING:
             if (warningImage is null) {
-                warningImage = createImage ("gtk-dialog-warning");
+                warningImage = createImage ("gtk-dialog-warning"); //$NON-NLS-1$
             }
             return warningImage;
         default:
@@ -2279,8 +2338,10 @@
  * </ul>
  */
 public Thread getThread () {
-    if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
-    return thread;
+    synchronized (Device.classinfo) {
+        if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
+        return thread;
+    }
 }
 
 Widget getWidget (GtkWidget* handle) {
@@ -2419,6 +2480,7 @@
     closures [Widget.MOTION_NOTIFY_EVENT] = do_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT, 0);
     closures [Widget.MOTION_NOTIFY_EVENT_INVERSE] = do_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT_INVERSE, 0);
     closures [Widget.MOVE_FOCUS] = do_cclosure_new (windowProc3, Widget.MOVE_FOCUS, 0);
+    closures [Widget.POPULATE_POPUP] = do_cclosure_new (windowProc3, Widget.POPULATE_POPUP, 0);
     closures [Widget.SCROLL_EVENT] = do_cclosure_new (windowProc3, Widget.SCROLL_EVENT, 0);
     closures [Widget.SHOW_HELP] = do_cclosure_new (windowProc3, Widget.SHOW_HELP, 0);
     closures [Widget.SIZE_ALLOCATE] = do_cclosure_new (windowProc3, Widget.SIZE_ALLOCATE, 0);
@@ -2454,6 +2516,7 @@
 
 void* getWindowProcUserData( int value ){
     return windowProcCallbackDatas[ value ];
+
 }
 
 void initializeSystemSettings () {
@@ -2487,7 +2550,7 @@
 
 void initializeWindowManager () {
     /* Get the window manager name */
-    windowManager = "";
+    windowManager = ""; //$NON-NLS-1$
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 0)) {
         auto screen = OS.gdk_screen_get_default ();
         if (screen !is null) {
@@ -2549,7 +2612,7 @@
         data.drawable = root;
         data.background = getSystemColor (DWT.COLOR_WHITE).handle;
         data.foreground = getSystemColor (DWT.COLOR_BLACK).handle;
-        data.font = getSystemFont ().handle;
+        data.font = getSystemFont ();
     }
     return gdkGC;
     return null;
@@ -2647,6 +2710,7 @@
         auto window = from.eventWindow ();
         int origin_x, origin_y;
         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
+        if ((from.style & DWT.MIRRORED) !is 0) point.x = from.getClientWidth () - point.x;
         point.x += origin_x;
         point.y += origin_y;
     }
@@ -2656,6 +2720,7 @@
         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
         point.x -= origin_x;
         point.y -= origin_y;
+        if ((to.style & DWT.MIRRORED) !is 0) point.x = to.getClientWidth () - point.x;
     }
     return point;
 }
@@ -2788,10 +2853,13 @@
     if (to !is null && to.isDisposed()) error (DWT.ERROR_INVALID_ARGUMENT);
     Rectangle rect = new Rectangle (x, y, width, height);
     if (from is to) return rect;
+    bool fromRTL = false, toRTL = false;
     if (from !is null) {
         auto window = from.eventWindow ();
         int origin_x, origin_y;
         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
+        fromRTL = (from.style & DWT.MIRRORED) !is 0;
+        if (fromRTL) rect.x = from.getClientWidth() - rect.x;
         rect.x += origin_x;
         rect.y += origin_y;
     }
@@ -2801,7 +2869,10 @@
         OS.gdk_window_get_origin (window, &origin_x, &origin_y);
         rect.x -= origin_x;
         rect.y -= origin_y;
+        toRTL = (to.style & DWT.MIRRORED) !is 0;
+        if (toRTL) rect.x = to.getClientWidth () - rect.x;
     }
+    if (fromRTL !is toRTL) rect.x -= rect.width;
     return rect;
 }
 
@@ -2870,67 +2941,69 @@
  *
  */
 public bool post (Event event) {
-    if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
-    if (event is null) error (DWT.ERROR_NULL_ARGUMENT);
-    if (!OS.GDK_WINDOWING_X11()) return false;
-    auto xDisplay = OS.GDK_DISPLAY ();
-    int type = event.type;
-    switch (type) {
-        case DWT.KeyDown:
-        case DWT.KeyUp: {
-            int keyCode = 0;
-            auto keysym = untranslateKey (event.keyCode);
-            if (keysym !is 0) keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
-            if (keyCode is 0) {
-                char key = event.character;
-                switch (key) {
-                    case DWT.BS: keysym = OS.GDK_BackSpace; break;
-                    case DWT.CR: keysym = OS.GDK_Return; break;
-                    case DWT.DEL: keysym = OS.GDK_Delete; break;
-                    case DWT.ESC: keysym = OS.GDK_Escape; break;
-                    case DWT.TAB: keysym = OS.GDK_Tab; break;
-                    case DWT.LF: keysym = OS.GDK_Linefeed; break;
-                    default:
-                        keysym = wcsToMbcs (key);
+    synchronized (Device.classinfo) {
+        if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
+        if (event is null) error (DWT.ERROR_NULL_ARGUMENT);
+        if (!OS.GDK_WINDOWING_X11()) return false;
+        auto xDisplay = OS.GDK_DISPLAY ();
+        int type = event.type;
+        switch (type) {
+            case DWT.KeyDown:
+            case DWT.KeyUp: {
+                int keyCode = 0;
+                auto keysym = untranslateKey (event.keyCode);
+                if (keysym !is 0) keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
+                if (keyCode is 0) {
+                    char key = event.character;
+                    switch (key) {
+                        case DWT.BS: keysym = OS.GDK_BackSpace; break;
+                        case DWT.CR: keysym = OS.GDK_Return; break;
+                        case DWT.DEL: keysym = OS.GDK_Delete; break;
+                        case DWT.ESC: keysym = OS.GDK_Escape; break;
+                        case DWT.TAB: keysym = OS.GDK_Tab; break;
+                        case DWT.LF: keysym = OS.GDK_Linefeed; break;
+                        default:
+                            keysym = key;
+                    }
+                    keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
+                    if (keyCode is 0) return false;
                 }
-                keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
-                if (keyCode is 0) return false;
+                OS.XTestFakeKeyEvent (xDisplay, keyCode, type is DWT.KeyDown, 0);
+                return true;
             }
-            OS.XTestFakeKeyEvent (xDisplay, keyCode, type is DWT.KeyDown, 0);
-            return true;
+            case DWT.MouseDown:
+            case DWT.MouseMove:
+            case DWT.MouseUp: {
+                if (type is DWT.MouseMove) {
+                    OS.XTestFakeMotionEvent (xDisplay, -1, event.x, event.y, 0);
+                } else {
+                    int button = event.button;
+                    switch (button) {
+                        case 1:
+                        case 2:
+                        case 3: break;
+                        case 4: button = 6; break;
+                        case 5: button = 7; break;
+                        default: return false;
+                    }
+                    OS.XTestFakeButtonEvent (xDisplay, button, type is DWT.MouseDown, 0);
+                }
+                return true;
+        default:
+            }
+            /*
+            * This code is intentionally commented. After posting a
+            * mouse wheel event the system may respond unpredictably
+            * to subsequent mouse actions.
+            */
+//          case DWT.MouseWheel: {
+//              if (event.count is 0) return false;
+//              int button = event.count < 0 ? 5 : 4;
+//              OS.XTestFakeButtonEvent (xDisplay, button, type is DWT.MouseWheel, 0);
+//          }
         }
-        case DWT.MouseDown:
-        case DWT.MouseMove:
-        case DWT.MouseUp: {
-            if (type is DWT.MouseMove) {
-                OS.XTestFakeMotionEvent (xDisplay, -1, event.x, event.y, 0);
-            } else {
-                int button = event.button;
-                switch (button) {
-                    case 1:
-                    case 2:
-                    case 3: break;
-                    case 4: button = 6; break;
-                    case 5: button = 7; break;
-                    default: return false;
-                }
-                OS.XTestFakeButtonEvent (xDisplay, button, type is DWT.MouseDown, 0);
-            }
-            return true;
-        default:
-        }
-        /*
-        * This code is intentionally commented. After posting a
-        * mouse wheel event the system may respond unpredictably
-        * to subsequent mouse actions.
-        */
-//      case DWT.MouseWheel: {
-//          if (event.count is 0) return false;
-//          int button = event.count < 0 ? 5 : 4;
-//          OS.XTestFakeButtonEvent (xDisplay, button, type is DWT.MouseWheel, 0);
-//      }
+        return false;
     }
-    return false;
 }
 
 void postEvent (Event event) {
@@ -3008,17 +3081,19 @@
     return runAsyncMessages (false);
 }
 
-synchronized void register () {
-    for (int i=0; i<Displays.length; i++) {
-        if (Displays [i] is null) {
-            Displays [i] = this;
-            return;
+static void register (Display display) {
+    synchronized (Device.classinfo) {
+        for (int i=0; i<Displays.length; i++) {
+            if (Displays [i] is null) {
+                Displays [i] = display;
+                return;
+            }
         }
+        Display [] newDisplays = new Display [Displays.length + 4];
+        System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
+        newDisplays [Displays.length] = display;
+        Displays = newDisplays;
     }
-    Display [] newDisplays = new Display [Displays.length + 4];
-    System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
-    newDisplays [Displays.length] = this;
-    Displays = newDisplays;
 }
 
 /**
@@ -3070,6 +3145,7 @@
 void releaseDisplay () {
 
     /* Dispose xfilter callback */
+    OS.gdk_window_remove_filter(null, &filterProcFunc, null);
 
     /* Dispose checkIfEvent callback */
 
@@ -3091,6 +3167,8 @@
 
     /* Dispose the set direction callback */
 
+    /* Dispose the emission proc callback */
+
     /* Dispose the set direction callback */
 
     /* Dispose the caret callback */
@@ -3146,6 +3224,8 @@
     COLOR_WIDGET_DARK_SHADOW = COLOR_WIDGET_NORMAL_SHADOW = COLOR_WIDGET_LIGHT_SHADOW =
     COLOR_WIDGET_HIGHLIGHT_SHADOW = COLOR_WIDGET_BACKGROUND = COLOR_WIDGET_BORDER =
     COLOR_LIST_FOREGROUND = COLOR_LIST_BACKGROUND = COLOR_LIST_SELECTION = COLOR_LIST_SELECTION_TEXT =
+    COLOR_WIDGET_FOREGROUND = COLOR_TITLE_FOREGROUND = COLOR_TITLE_BACKGROUND = COLOR_TITLE_BACKGROUND_GRADIENT =
+    COLOR_TITLE_INACTIVE_FOREGROUND = COLOR_TITLE_INACTIVE_BACKGROUND = COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT =
     COLOR_INFO_BACKGROUND = COLOR_INFO_FOREGROUND = null;
 
     /* Dispose the event callback */
@@ -3166,10 +3246,21 @@
     /* Release references */
     popups = null;
     thread = null;
-    activeShell = null;
-    lastWidget = null;
-    indexTable = null;
-    widgetTable = null;
+    lastWidget = activeShell = null;
+    //flushData = null;
+    closures = null;
+    indexTable = signalIds = treeSelection = null;
+    widgetTable = modalShells = null;
+    data = null;
+    values = null;
+    keys = null;
+    windowManager = null;
+    eventTable = filterTable = null;
+    modalDialog = null;
+    flushRect = null;
+    exposeEvent = null;
+    visibilityEvent = null;
+    idleLock = null;
 }
 
 /**
@@ -3219,7 +3310,7 @@
 }
 
 void removeIdleProc () {
-    synchronized(idleLock) {
+    synchronized (idleLock) {
         if (idleHandle !is 0) OS.g_source_remove (idleHandle);
         idleNeeded = false;
         idleHandle = 0;
@@ -3455,8 +3546,12 @@
             return;
         }
     }
-
-    if (key==/*eq*/ ADD_WIDGET_KEY) {
+    if (key.equals (SET_MODAL_DIALOG)) {
+        setModalDialog (cast(Dialog) data);
+        return;
+    }
+
+    if (key.equals (ADD_WIDGET_KEY)) {
         auto wrap = cast(ArrayWrapperObject) value;
         if( wrap is null ) DWT.error(DWT.ERROR_INVALID_ARGUMENT, null, " []");
         Object [] data = wrap.array;
@@ -3564,12 +3659,43 @@
 }
 int /*long*/ setDirectionProc (GtkWidget* widget, int /*long*/ direction) {
     OS.gtk_widget_set_direction (widget,  direction);
+    if (OS.GTK_IS_MENU_ITEM (widget)) {
+        auto submenu = OS.gtk_menu_item_get_submenu (widget);
+        if (submenu !is null) {
+            OS.gtk_widget_set_direction (submenu, cast(int)/*64*/ direction);
+            OS.gtk_container_forall (cast(GtkContainer*)submenu, cast(GtkCallback)&setDirectionProcFunc, cast(void*)direction);
+        }
+    }
     if (OS.GTK_IS_CONTAINER (cast(GTypeInstance*)widget)) {
         OS.gtk_container_forall (cast(GtkContainer*)widget, cast(GtkCallback)&setDirectionProcFunc, cast(void*)direction);
     }
     return 0;
 }
 
+void setModalDialog (Dialog modalDailog) {
+    this.modalDialog = modalDailog;
+    Shell [] shells = getShells ();
+    for (int i=0; i<shells.length; i++) shells [i].updateModal ();
+}
+
+void setModalShell (Shell shell) {
+    if (modalShells is null) modalShells = new Shell [4];
+    int index = 0, length = modalShells.length;
+    while (index < length) {
+        if (modalShells [index] is shell) return;
+        if (modalShells [index] is null) break;
+        index++;
+    }
+    if (index is length) {
+        Shell [] newModalShells = new Shell [length + 4];
+        System.arraycopy (modalShells, 0, newModalShells, 0, length);
+        modalShells = newModalShells;
+    }
+    modalShells [index] = shell;
+    Shell [] shells = getShells ();
+    for (int i=0; i<shells.length; i++) shells [i].updateModal ();
+}
+
 /**
  * Sets the synchronizer used by the display to be
  * the argument, which can not be null.
@@ -3588,10 +3714,15 @@
 public void setSynchronizer (Synchronizer synchronizer) {
     checkDevice ();
     if (synchronizer is null) error (DWT.ERROR_NULL_ARGUMENT);
-    if (this.synchronizer !is null) {
-        this.synchronizer.runAsyncMessages(true);
+    if (synchronizer is this.synchronizer) return;
+    Synchronizer oldSynchronizer;
+    synchronized (Device.classinfo) {
+        oldSynchronizer = this.synchronizer;
+        this.synchronizer = synchronizer;
     }
-    this.synchronizer = synchronizer;
+    if (oldSynchronizer !is null) {
+        oldSynchronizer.runAsyncMessages(true);
+    }
 }
 
 void showIMWindow (Control control) {
@@ -3965,14 +4096,18 @@
  * @see #asyncExec
  */
 public void syncExec (Runnable runnable) {
-    if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
-    synchronized (idleLock) {
-        if (idleNeeded && idleHandle is 0) {
-            //NOTE: calling unlocked function in OS
+    Synchronizer synchronizer;
+    synchronized (Device.classinfo) {
+        if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
+        synchronizer = this.synchronizer;
+        synchronized (idleLock) {
+            if (idleNeeded && idleHandle is 0) {
+                //NOTE: calling unlocked function in OS
             idleProcCallbackData.display = this;
             idleProcCallbackData.data = cast(void*)0;
             //PORTING_TODO: was _g_idle_add, calling directly
             idleHandle = OS.g_idle_add (&idleProcFunc, &idleProcCallbackData);
+            }
         }
     }
     synchronizer.syncExec (runnable);
@@ -4021,9 +4156,11 @@
  * @see #sleep
  */
 public void wake () {
-    if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
-    if (thread is Thread.getThis ()) return;
-    wakeThread ();
+    synchronized (Device.classinfo) {
+        if (isDisposed ()) error (DWT.ERROR_DEVICE_DISPOSED);
+        if (thread is Thread.getThis ()) return;
+        wakeThread ();
+    }
 }
 
 void wakeThread () {
--- a/dwt/widgets/Event.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Event.d	Mon May 12 19:13:01 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * 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
--- a/dwt/widgets/EventTable.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/EventTable.d	Mon May 12 19:13:01 2008 +0200
@@ -32,10 +32,28 @@
     int [] types;
     Listener [] listeners;
     int level;
+    static final int GROW_SIZE = 4;
+    
+public Listener [] getListeners (int eventType) {
+    if (types is null) return new Listener [0];
+    int count = 0;
+    for (int i=0; i<types.length; i++) {
+        if (types [i] is eventType) count++;
+    }
+    if (count is 0) return new Listener [0];
+    Listener [] result = new Listener [count];
+    count = 0;
+    for (int i=0; i<types.length; i++) {
+        if (types [i] is eventType) {
+            result [count++] = listeners [i];
+        }
+    }
+    return result;
+}
 
 public void hook (int eventType, Listener listener) {
-    if (types is null) types = new int [4];
-    if (listeners is null) listeners = new Listener [4];
+    if (types is null) types = new int [GROW_SIZE];
+    if (listeners is null) listeners = new Listener [GROW_SIZE];
     int length = types.length, index = length - 1;
     while (index >= 0) {
         if (types [index] !is 0) break;
@@ -43,10 +61,10 @@
     }
     index++;
     if (index is length) {
-        int [] newTypes = new int [length + 4];
+        int [] newTypes = new int [length + GROW_SIZE];
         System.arraycopy (types, 0, newTypes, 0, length);
         types = newTypes;
-        Listener [] newListeners = new Listener [length + 4];
+        Listener [] newListeners = new Listener [length + GROW_SIZE];
         SimpleType!(Listener).arraycopy (listeners, 0, newListeners, 0, length);
         listeners = newListeners;
     }
--- a/dwt/widgets/ExpandItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/ExpandItem.d	Mon May 12 19:13:01 2008 +0200
@@ -290,8 +290,7 @@
 public int getHeaderHeight () {
     checkWidget ();
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
-        auto widget = OS.gtk_expander_get_label_widget (handle);
-        return OS.GTK_WIDGET_HEIGHT (widget);
+        return OS.GTK_WIDGET_HEIGHT (handle) - (expanded ? height : 0);
     }
     return Math.max (parent.getBandHeight (), imageHeight);
 }
@@ -596,6 +595,14 @@
     }
 }
 
+void setOrientation() {
+    super.setOrientation ();
+    if ((parent.style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.gtk_widget_set_direction (handle, OS.GTK_TEXT_DIR_RTL);
+        display.doSetDirectionProc(handle, OS.GTK_TEXT_DIR_RTL);
+    }
+}
+
 public override void setText (String string) {
     super.setText (string);
     if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
--- a/dwt/widgets/FileDialog.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/FileDialog.d	Mon May 12 19:13:01 2008 +0200
@@ -49,6 +49,8 @@
     String fileName = "";
     String[] fileNames;
     String fullPath = "";
+    int filterIndex = -1;
+    bool overwrite = false;
     GtkWidget* handle;
     static final char SEPARATOR = tango.io.FileConst.FileConst.PathSeparatorChar;
     static final char EXTENSION_SEPARATOR = ';';
@@ -67,7 +69,7 @@
  * </ul>
  */
 public this (Shell parent) {
-    this (parent, DWT.PRIMARY_MODAL);
+    this (parent, DWT.APPLICATION_MODAL);
 }
 /**
  * Constructs a new instance of this class given its parent
@@ -94,7 +96,7 @@
  * </ul>
  */
 public this (Shell parent, int style) {
-    super (parent, style);
+    super (parent, checkStyle (parent, style));
     checkSubclass ();
 }
 String computeResultChooserDialog () {
@@ -142,6 +144,28 @@
             }
         }
     }
+    filterIndex = -1;
+    auto filter = OS.gtk_file_chooser_get_filter (handle);
+    if (filter !is null) {
+        auto filterNamePtr = OS.gtk_file_filter_get_name (filter);
+        if (filterNamePtr !is null) {
+            String filterName = tango.stdc.stringz.fromStringz(filterNamePtr).dup;
+            //OS.g_free (filterNamePtr); //GTK owns this pointer - do not free
+            for (int i = 0; i < filterExtensions.length; i++) {
+                if (filterNames.length > 0) {
+                    if (filterNames[i].equals(filterName)) {
+                        filterIndex = i;
+                        break;
+                    }
+                } else {
+                    if (filterExtensions[i].equals(filterName)) {
+                        filterIndex = i;
+                        break;
+                    }
+                }
+            }
+        }
+    }
     if (fullPath !is null) {
         int separatorIndex = tango.text.Util.locatePrior( fullPath, SEPARATOR);
         if( separatorIndex is fullPath.length ) separatorIndex = -1;
@@ -151,6 +175,7 @@
     return fullPath;
 }
 String computeResultClassicDialog () {
+    filterIndex = -1;
     GtkFileSelection* selection = cast(GtkFileSelection*)handle;
     auto entry = selection.selection_entry;
     auto entryText = OS.gtk_entry_get_text (entry);
@@ -248,6 +273,25 @@
     return filterExtensions;
 }
 /**
+ * Get the 0-based index of the file extension filter
+ * which was selected by the user, or -1 if no filter
+ * was selected.
+ * <p>
+ * This is an index into the FilterExtensions array and
+ * the FilterNames array.
+ * </p>
+ *
+ * @return index the file extension filter index
+ *
+ * @see #getFilterExtensions
+ * @see #getFilterNames
+ *
+ * @since 3.4
+ */
+public int getFilterIndex () {
+    return filterIndex;
+}
+/**
  * Returns the names that describe the filter extensions
  * which the dialog will use to filter the files it shows.
  *
@@ -269,6 +313,18 @@
     return filterPath;
 }
 /**
+ * Returns the flag that the dialog will use to
+ * determine whether to prompt the user for file
+ * overwrite if the selected file already exists.
+ *
+ * @return true if the dialog will prompt for file overwrite, false otherwise
+ *
+ * @since 3.4
+ */
+public bool getOverwrite () {
+    return overwrite;
+}
+/**
  * Makes the dialog visible and brings it to the front
  * of the display.
  *
@@ -309,7 +365,28 @@
     Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     display.addIdleProc ();
     String answer = null;
-    if (OS.gtk_dialog_run (handle) is OS.GTK_RESPONSE_OK) {
+    Dialog oldModal = null;
+    if (OS.gtk_window_get_modal (handle)) {
+        oldModal = display.getModalDialog ();
+        display.setModalDialog (this);
+    }
+    uint signalId = 0;
+    uint /*long*/ hookId = 0;
+    CallbackData emissionData;
+    emissionData.display = display;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+        emissionData.data = handle;
+        hookId = OS.g_signal_add_emission_hook (signalId, 0, &Display.emissionFunc, &emissionData, null);
+    }
+    int response = OS.gtk_dialog_run (handle);
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.g_signal_remove_emission_hook (signalId, hookId);
+    }
+    if (OS.gtk_window_get_modal (handle)) {
+        display.setModalDialog (oldModal);
+    }
+    if (response is OS.GTK_RESPONSE_OK) {
         answer = computeResultChooserDialog ();
     }
     display.removeIdleProc ();
@@ -332,7 +409,28 @@
     Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     display.addIdleProc ();
     String answer = null;
-    if (OS.gtk_dialog_run (handle) is OS.GTK_RESPONSE_OK) {
+    Dialog oldModal = null;
+    if (OS.gtk_window_get_modal (handle)) {
+        oldModal = display.getModalDialog ();
+        display.setModalDialog (this);
+    }
+    int signalId = 0;
+    int /*long*/ hookId = 0;
+    CallbackData emissionData;
+    emissionData.display = display;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+        emissionData.data = handle;
+        hookId = OS.g_signal_add_emission_hook (signalId, 0, &Display.emissionFunc, &emissionData, null);
+    }
+    int response = OS.gtk_dialog_run (handle);
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.g_signal_remove_emission_hook (signalId, hookId);
+    }
+    if (OS.gtk_window_get_modal (handle)) {
+        display.setModalDialog (oldModal);
+    }
+    if (response is OS.GTK_RESPONSE_OK) {
         answer = computeResultClassicDialog ();
     }
     display.removeIdleProc ();
@@ -353,30 +451,40 @@
             stringBuffer.append (SEPARATOR);
         }
         stringBuffer.append (filterPath);
-        if (filterPath[filterPath.length - 1 ] !is SEPARATOR) {
-            stringBuffer.append (SEPARATOR);
-        }
-        if (fileName.length > 0) {
+        if (fileName.length > 0 && (style & DWT.SAVE) is 0) {
+            if (filterPath[filterPath.length - 1 ] !is SEPARATOR) {
+                stringBuffer.append (SEPARATOR);
+            }
             stringBuffer.append (fileName);
-        } else {
-            /* go into the specified directory */
-            stringBuffer.append ('.');
-        }
         char* buffer = tango.stdc.stringz.toStringz( stringBuffer.toString ());
-        /*
-        * Bug in GTK. GtkFileChooser may crash on GTK versions 2.4.10 to 2.6
-        * when setting a file name that is not a true canonical path.
-        * The fix is to use the canonical path.
-        */
+            /*
+            * Bug in GTK. GtkFileChooser may crash on GTK versions 2.4.10 to 2.6
+            * when setting a file name that is not a true canonical path.
+            * The fix is to use the canonical path.
+            */
         auto ptr = OS.realpath (buffer, null);
         if (ptr !is null) {
-            OS.gtk_file_chooser_set_filename (handle, ptr);
-            OS.g_free (ptr);
+                OS.gtk_file_chooser_set_filename (handle, ptr);
+                OS.g_free (ptr);
+            }
+        } else {
+            char* buffer = tango.stdc.stringz.toStringz( stringBuffer.toString () );
+            /*
+            * Bug in GTK. GtkFileChooser may crash on GTK versions 2.4.10 to 2.6
+            * when setting a file name that is not a true canonical path.
+            * The fix is to use the canonical path.
+            */
+            auto ptr = OS.realpath (buffer, null);
+            if (ptr !is null) {
+                OS.gtk_file_chooser_set_current_folder (handle, ptr);
+                OS.g_free (ptr);
+            }
         }
     } else {
         if (fileName.length > 0) {
             if (fileName[0] is SEPARATOR) {
                 char* buffer = tango.stdc.stringz.toStringz(fileName);
+
                 /*
                 * Bug in GTK. GtkFileChooser may crash on GTK versions 2.4.10 to 2.6
                 * when setting a file name that is not a true canonical path.
@@ -394,10 +502,16 @@
         char* buffer = tango.stdc.stringz.toStringz(fileName);
         OS.gtk_file_chooser_set_current_name (handle, buffer);
     }
+    if ((style & DWT.SAVE) !is 0) {
+        if (OS.GTK_VERSION >= OS.buildVERSION (2, 8, 0)) {
+            OS.gtk_file_chooser_set_do_overwrite_confirmation (handle, overwrite);
+        }
+    }
 
     /* Set the extension filters */
     if (filterNames is null) filterNames = null;
     if (filterExtensions is null) filterExtensions = null;
+    GtkFileFilter* initialFilter = null;
     for (int i = 0; i < filterExtensions.length; i++) {
         if (filterExtensions [i] !is null) {
             auto filter = OS.gtk_file_filter_new ();
@@ -421,8 +535,14 @@
             char* filterString = tango.stdc.stringz.toStringz(current);
             OS.gtk_file_filter_add_pattern (filter, filterString);
             OS.gtk_file_chooser_add_filter (handle, filter);
+            if (i is filterIndex) {
+                initialFilter = filter;
+            }
         }
     }
+    if (initialFilter !is null) {
+        OS.gtk_file_chooser_set_filter(handle, initialFilter);
+    }
     fullPath = null;
     fileNames = null;
 }
@@ -486,6 +606,25 @@
     filterExtensions = extensions;
 }
 /**
+ * Set the 0-based index of the file extension filter
+ * which the dialog will use initially to filter the files
+ * it shows to the argument.
+ * <p>
+ * This is an index into the FilterExtensions array and
+ * the FilterNames array.
+ * </p>
+ *
+ * @param index the file extension filter index
+ *
+ * @see #setFilterExtensions
+ * @see #setFilterNames
+ *
+ * @since 3.4
+ */
+public void setFilterIndex (int index) {
+    filterIndex = index;
+}
+/**
  * Sets the the names that describe the filter extensions
  * which the dialog will use to filter the files it shows
  * to the argument, which may be null.
@@ -522,4 +661,17 @@
 public void setFilterPath (String string) {
     filterPath = string;
 }
+
+/**
+ * Sets the flag that the dialog will use to
+ * determine whether to prompt the user for file
+ * overwrite if the selected file already exists.
+ *
+ * @param overwrite true if the dialog will prompt for file overwrite, false otherwise
+ *
+ * @since 3.4
+ */
+public void setOverwrite (bool overwrite) {
+    this.overwrite = overwrite;
 }
+}
--- a/dwt/widgets/FontDialog.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/FontDialog.d	Mon May 12 19:13:01 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * 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
@@ -58,7 +58,7 @@
  * </ul>
  */
 public this (Shell parent) {
-    this (parent, DWT.PRIMARY_MODAL);
+    this (parent, DWT.APPLICATION_MODAL);
 }
 /**
  * Constructs a new instance of this class given its parent
@@ -85,7 +85,7 @@
  * </ul>
  */
 public this (Shell parent, int style) {
-    super (parent, style);
+    super (parent, checkStyle (parent, style));
     checkSubclass ();
 }
 
@@ -144,6 +144,7 @@
     GtkWidget* handle;
     char* titleBytes;
     titleBytes = tango.stdc.stringz.toStringz(title);
+    Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     handle = OS.gtk_font_selection_dialog_new (titleBytes);
     if (parent !is null) {
         auto shellHandle = parent.topHandle ();
@@ -155,16 +156,34 @@
         }
     }
     if (fontData !is null) {
-        Display display = parent !is null ? parent.display : Display.getCurrent ();
         Font font = new Font (display, fontData);
         auto fontName = OS.pango_font_description_to_string (font.handle);
         font.dispose();
         OS.gtk_font_selection_dialog_set_font_name (handle, fontName);
         OS.g_free (fontName);
     }
-    Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     display.addIdleProc ();
-    int response = OS.gtk_dialog_run(handle);
+    Dialog oldModal = null;
+    if (OS.gtk_window_get_modal (handle)) {
+        oldModal = display.getModalDialog ();
+        display.setModalDialog (this);
+    }
+    int signalId = 0;
+    int /*long*/ hookId = 0;
+    CallbackData emissionData;
+    emissionData.display = display;
+    emissionData.data = handle;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+        hookId = OS.g_signal_add_emission_hook (signalId, 0, &Display.emissionFunc, &emissionData, null);
+    }
+    int response = OS.gtk_dialog_run (handle);
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.g_signal_remove_emission_hook (signalId, hookId);
+    }
+    if (OS.gtk_window_get_modal (handle)) {
+        display.setModalDialog (oldModal);
+    }
     bool success = response is OS.GTK_RESPONSE_OK;
     if (success) {
         auto fontName = OS.gtk_font_selection_dialog_get_font_name (handle);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/widgets/IME.d	Mon May 12 19:13:01 2008 +0200
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * 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.widgets.IME;
+
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.graphics.TextStyle;
+import dwt.internal.Converter;
+import dwt.internal.gtk.OS;
+
+import dwt.widgets.Widget;
+import dwt.widgets.Canvas;
+import dwt.widgets.Event;
+
+import dwt.dwthelper.utils;
+
+public class IME : Widget {
+    Canvas parent;
+    int caretOffset;
+    int startOffset;
+    int commitCount;
+    String text;
+    int [] ranges;
+    TextStyle [] styles;
+    bool inComposition;
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+this () {
+}
+
+/**
+ *
+ * @see DWT
+ */
+public this (Canvas parent, int style) {
+    super (parent, style);
+    this.parent = parent;
+    createWidget ();
+}
+
+void createWidget () {
+    text = "";
+    startOffset = -1;
+    if (parent.getIME () is null) {
+        parent.setIME (this);
+    }
+}
+
+public int getCaretOffset () {
+    checkWidget ();
+    return startOffset + caretOffset;
+}
+
+public int getCommitCount () {
+    checkWidget ();
+    return commitCount;
+}
+
+public int getCompositionOffset () {
+    checkWidget ();
+    return startOffset;
+}
+
+public int [] getRanges () {
+    checkWidget ();
+    if (ranges is null) return new int [0];
+    int [] result = new int [ranges.length];
+    for (int i = 0; i < result.length; i++) {
+        result [i] = ranges [i] + startOffset;
+    }
+    return result;
+}
+
+public TextStyle [] getStyles () {
+    checkWidget ();
+    if (styles is null) return new TextStyle [0];
+    TextStyle [] result = new TextStyle [styles.length];
+    System.arraycopy (styles, 0, result, 0, styles.length);
+    return result;
+}
+
+public String getText () {
+    checkWidget ();
+    return text;
+}
+
+public bool getWideCaret () {
+    checkWidget ();
+    return false;
+}
+
+override int /*long*/ gtk_button_press_event (GtkWidget* widget, GdkEventButton* event) {
+    if (!isInlineEnabled ()) return 0;
+    auto imHandle_ = imHandle ();
+    if (imHandle_ !is null) OS.gtk_im_context_reset (imHandle_);
+    return 0;
+}
+
+override int /*long*/ gtk_commit (GtkIMContext* imcontext, char* textPtr) {
+    if (!isInlineEnabled ()) return 0;
+    bool doit = true;
+    ranges = null;
+    styles = null;
+    caretOffset = commitCount = 0;
+    if (textPtr !is null && inComposition) {
+        int length = OS.strlen (textPtr);
+        if (length !is 0) {
+            char [] chars = tango.stdc.stringz.fromStringz(textPtr).dup;
+            Event event = new Event();
+            event.detail = DWT.COMPOSITION_CHANGED;
+            event.start = startOffset;
+            event.end = startOffset + text.length;
+            event.text = text = chars !is null ? chars : "";
+            commitCount = text.length;
+            sendEvent (DWT.ImeComposition, event);
+            doit = event.doit;
+            text = "";
+            startOffset = -1;
+            commitCount = 0;
+        }
+    }
+    inComposition = false;
+    return doit ? 0 : 1;
+}
+
+override int /*long*/ gtk_preedit_changed (GtkIMContext* imcontext) {
+    if (!isInlineEnabled ()) return 0;
+    ranges = null;
+    styles = null;
+    commitCount = 0;
+    auto imHandle_ = imHandle ();
+    char* preeditString;
+    void* pangoAttrs;
+    int cursorPos;
+    OS.gtk_im_context_get_preedit_string (imHandle_, &preeditString, &pangoAttrs, &cursorPos);
+    caretOffset = cursorPos ;
+    char [] chars = null;
+    if (preeditString !is null) {
+        int length = OS.strlen (preeditString);
+        chars = tango.stdc.stringz.fromStringz(preeditString).dup;
+        if (pangoAttrs !is null) {
+            int count = 0;
+            auto iterator = OS.pango_attr_list_get_iterator (pangoAttrs );
+            while (OS.pango_attr_iterator_next (iterator)) count++;
+            OS.pango_attr_iterator_destroy (iterator);
+            ranges = new int [count * 2];
+            styles = new TextStyle [count];
+            iterator = OS.pango_attr_list_get_iterator (pangoAttrs );
+            PangoAttrColor* attrColor;
+            PangoAttrInt* attrInt;
+            int start;
+            int end;
+            for (int i = 0; i < count; i++) {
+                OS.pango_attr_iterator_range (iterator, &start, &end);
+                ranges [i * 2] = cast(int)/*64*/OS.g_utf8_pointer_to_offset (preeditString, preeditString + start);
+                ranges [i * 2 + 1] = cast(int)/*64*/OS.g_utf8_pointer_to_offset (preeditString, preeditString + end) - 1;
+                styles [i] = new TextStyle (null, null, null);
+                auto attr = OS.pango_attr_iterator_get (iterator, OS.PANGO_ATTR_FOREGROUND);
+                if (attr !is null) {
+                    attrColor = cast(PangoAttrColor*) attr;
+                    GdkColor* color = new GdkColor ();
+                    color.red = attrColor.color.red;
+                    color.green = attrColor.color.green;
+                    color.blue = attrColor.color.blue;
+                    styles [i].foreground = Color.gtk_new (display, color);
+                }
+                attr = OS.pango_attr_iterator_get (iterator, OS.PANGO_ATTR_BACKGROUND);
+                if (attr !is null) {
+                    attrColor = cast(PangoAttrColor*) attr;
+                    GdkColor* color = new GdkColor ();
+                    color.red = attrColor.color.red;
+                    color.green = attrColor.color.green;
+                    color.blue = attrColor.color.blue;
+                    styles [i].background = Color.gtk_new (display, color);
+                }
+                attr = OS.pango_attr_iterator_get (iterator, OS.PANGO_ATTR_UNDERLINE);
+                if (attr !is null) {
+                    attrInt = cast(PangoAttrInt*) attr;
+                    styles [i].underline = attrInt.value !is OS.PANGO_UNDERLINE_NONE;;
+                    styles [i].underlineStyle = DWT.UNDERLINE_SINGLE;
+                    switch (attrInt.value) {
+                        case OS.PANGO_UNDERLINE_DOUBLE:
+                            styles [i].underlineStyle = DWT.UNDERLINE_DOUBLE;
+                            break;
+                        case OS.PANGO_UNDERLINE_ERROR:
+                            styles [i].underlineStyle = DWT.UNDERLINE_ERROR;
+                            break;
+                    }
+                    if (styles [i].underline) {
+                        attr = OS.pango_attr_iterator_get(iterator, OS.PANGO_ATTR_UNDERLINE_COLOR);
+                        if (attr !is null) {
+                            attrColor = cast(PangoAttrColor*) attr;
+                            GdkColor* color = new GdkColor;
+                            color.red = attrColor.color.red;
+                            color.green = attrColor.color.green;
+                            color.blue = attrColor.color.blue;
+                            styles [i].underlineColor = Color.gtk_new (display, color);
+                        }
+                    }
+                }
+                OS.pango_attr_iterator_next (iterator);
+            }
+            OS.pango_attr_iterator_destroy (iterator);
+            OS.pango_attr_list_unref (pangoAttrs);
+        }
+        OS.g_free (preeditString);
+    }
+    if (chars !is null) {
+        if (text.length is 0) startOffset = -1;
+        int end = startOffset + text.length;
+        if (startOffset is -1) {
+            Event event = new Event ();
+            event.detail = DWT.COMPOSITION_SELECTION;
+            sendEvent (DWT.ImeComposition, event);
+            startOffset = event.start;
+            end = event.end;
+        }
+        inComposition = true;
+        Event event = new Event ();
+        event.detail = DWT.COMPOSITION_CHANGED;
+        event.start = startOffset;
+        event.end = end;
+        event.text = text = chars !is null ? chars : "";
+        sendEvent (DWT.ImeComposition, event);
+    }
+    return 1;
+}
+
+GtkIMContext* imHandle () {
+    return parent.imHandle ();
+}
+
+bool isInlineEnabled () {
+    return hooks (DWT.ImeComposition);
+}
+
+void releaseParent () {
+    super.releaseParent ();
+    if (this is parent.getIME ()) parent.setIME (null);
+}
+
+void releaseWidget () {
+    super.releaseWidget ();
+    parent = null;
+    text = null;
+    styles = null;
+    ranges = null;
+}
+
+public void setCompositionOffset (int offset) {
+    checkWidget ();
+    if (offset < 0) return;
+    if (startOffset !is -1) {
+        startOffset = offset;
+    }
+}
+
+}
--- a/dwt/widgets/Label.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Label.d	Mon May 12 19:13:01 2008 +0200
@@ -214,7 +214,12 @@
         OS.gtk_container_add (cast(GtkContainer*)fixedHandle, handle);
     }
     if ((style & DWT.SEPARATOR) !is 0) return;
-    if ((style & DWT.WRAP) !is 0) OS.gtk_label_set_line_wrap (cast(GtkLabel*)labelHandle, true);
+    if ((style & DWT.WRAP) !is 0) {
+        OS.gtk_label_set_line_wrap (labelHandle, true);
+        if (OS.GTK_VERSION >= OS.buildVERSION (2, 10, 0)) {
+            OS.gtk_label_set_line_wrap_mode (labelHandle, OS.PANGO_WRAP_WORD_CHAR);
+        }
+    }
     if ((style & DWT.LEFT) !is 0) {
         OS.gtk_misc_set_alignment (cast(GtkMisc*)labelHandle, 0.0f, 0.0f);
         OS.gtk_label_set_justify (cast(GtkLabel*)labelHandle, OS.GTK_JUSTIFY_LEFT);
--- a/dwt/widgets/Link.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Link.d	Mon May 12 19:13:01 2008 +0200
@@ -188,6 +188,7 @@
     OS.gtk_fixed_set_has_window (handle, true);
     OS.GTK_WIDGET_SET_FLAGS (handle, OS.GTK_CAN_FOCUS);
     layout = new TextLayout (display);
+    layout.setOrientation((style & DWT.RIGHT_TO_LEFT) !is 0? DWT.RIGHT_TO_LEFT : DWT.LEFT_TO_RIGHT);
     linkColor = new Color (display, LINK_FOREGROUND);
     disabledColor = new Color (display, LINK_DISABLED_FOREGROUND);
     offsets = null;
@@ -415,6 +416,7 @@
         event.y = gdkEvent.area.y;
         event.width = gdkEvent.area.width;
         event.height = gdkEvent.area.height;
+        if ((style & DWT.MIRRORED) !is 0) event.x = getClientWidth () - event.width - event.x;
         event.gc = gc;
         sendEvent (DWT.Paint, event);
         event.gc = null;
@@ -488,9 +490,9 @@
 
 override void releaseWidget () {
     super.releaseWidget ();
-    if (layout !is null) layout.dispose ();
+    if (layout !is null)    layout.dispose ();
     layout = null;
-    if (linkColor !is null)  linkColor.dispose ();
+    if (linkColor !is null) linkColor.dispose ();
     linkColor = null;
     if (disabledColor !is null) disabledColor.dispose ();
     disabledColor = null;
@@ -638,7 +640,7 @@
     }
     if (start < length_) {
         int tmp = parseMnemonics (buffer, start, tagStart, result);
-        int mnemonic = parseMnemonics (buffer, linkStart, index, result);
+        int mnemonic = parseMnemonics (buffer, Math.max (tagStart, linkStart), length_, result);
         if (mnemonic is -1) mnemonic = tmp;
         mnemonics [linkIndex] = mnemonic;
     } else {
@@ -725,10 +727,14 @@
     bool enabled = (state & DISABLED) is 0;
     TextStyle linkStyle = new TextStyle (null, enabled ? linkColor : disabledColor, null);
     linkStyle.underline = true;
+    int [] bidiSegments = new int [offsets.length*2];
     for (int i = 0; i < offsets.length; i++) {
         Point point = offsets [i];
         layout.setStyle (linkStyle, point.x, point.y);
+        bidiSegments[i*2] = point.x;
+        bidiSegments[i*2+1] = point.y+1;
     }
+    layout.setSegments (bidiSegments);
     TextStyle mnemonicStyle = new TextStyle (null, null, null);
     mnemonicStyle.underline = true;
     for (int i = 0; i < mnemonics.length; i++) {
--- a/dwt/widgets/Menu.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Menu.d	Mon May 12 19:13:01 2008 +0200
@@ -190,7 +190,15 @@
         sendEvent (DWT.Show);
         if (getItemCount () !is 0) {
             if ((OS.GTK_VERSION >=  OS.buildVERSION (2, 8, 0))) {
-                OS.gtk_menu_shell_set_take_focus (cast(GtkMenuShell*)handle, false);
+                /*
+                * Feature in GTK. ON_TOP shells will send out 
+                * DWT.Deactivate whenever a context menu is shown.
+                * The fix is to prevent the menu from taking focus
+                * when it is being shown in an ON_TOP shell.
+                */
+                if ((parent._getShell ().style & DWT.ON_TOP) !is 0) {
+                    OS.gtk_menu_shell_set_take_focus (cast(GtkMenuShell*)handle, false);
+                }
             }
             /*
             * Bug in GTK.  The timestamp passed into gtk_menu_popup is used
@@ -710,9 +718,9 @@
     OS.gtk_widget_size_request (cast(GtkWidget*)menu, &requisition);
     int screenHeight = OS.gdk_screen_height ();
     int reqy = this.y;
-    if (reqy + requisition.height > screenHeight && reqy - requisition.height >= 0) {
-        reqy -= requisition.height;
-    }
+    if (reqy + requisition.height > screenHeight) {
+        reqy = Math.max (0, reqy - requisition.height);
+    } 
     int screenWidth = OS.gdk_screen_width ();
     int reqx = this.x;
     if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
--- a/dwt/widgets/MenuItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/MenuItem.d	Mon May 12 19:13:01 2008 +0200
@@ -373,6 +373,11 @@
     return menu;
 }
 
+String getNameText () {
+    if ((style & DWT.SEPARATOR) !is 0) return "|";
+    return super.getNameText ();
+}
+
 /**
  * Returns the receiver's parent, which must be a <code>Menu</code>.
  *
@@ -842,7 +847,8 @@
     String accelString = "";
     int index = string.indexOf ('\t');
     if (index !is -1) {
-        accelString = string.substring (index, string.length);
+        bool isRTL = (parent.style & DWT.RIGHT_TO_LEFT) !is 0;
+        accelString = (isRTL? "" : "  ") ~ string.substring (index+1, string.length) ~ (isRTL? "  " : "");
         string = string.substring (0, index);
     }
     char [] chars = fixMnemonic (string);
@@ -861,6 +867,7 @@
 
 void updateAccelerator (GtkAccelGroup* accelGroup, bool add) {
     if (accelerator is 0 || !getEnabled ()) return;
+    if ((accelerator & DWT.COMMAND) !is 0) return;
     int mask = 0;
     if ((accelerator & DWT.ALT) !is 0) mask |= OS.GDK_MOD1_MASK;
     if ((accelerator & DWT.SHIFT) !is 0) mask |= OS.GDK_SHIFT_MASK;
--- a/dwt/widgets/MessageBox.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/MessageBox.d	Mon May 12 19:13:01 2008 +0200
@@ -47,6 +47,8 @@
  */
 public class MessageBox : Dialog {
 
+    alias Dialog.checkStyle checkStyle;
+
     String message = "";
     GtkWidget* handle;
     private bool allowNullParent = false;
@@ -91,7 +93,7 @@
  * </ul>
  */
 public this (Shell parent, int style) {
-    super(parent, checkStyle(style));
+    super (parent, checkStyle (parent, checkStyle (style)));
     checkSubclass ();
 }
 
@@ -100,7 +102,7 @@
  +/
 public this (int style) {
     allowNullParent = true;
-    super (parent, checkStyle (style));
+    super (parent, checkStyle (parent, checkStyle (style)));
     checkSubclass ();
 }
 // PORT
@@ -176,10 +178,30 @@
     OS.gtk_window_set_title(handle,buffer);
     Display display = parent !is null ? parent.getDisplay (): Display.getCurrent ();
     display.addIdleProc ();
-    int result = OS.gtk_dialog_run (handle);
+    Dialog oldModal = null;
+    if (OS.gtk_window_get_modal (handle)) {
+        oldModal = display.getModalDialog ();
+        display.setModalDialog (this);
+    }
+    int signalId = 0;
+    int /*long*/ hookId = 0;
+    CallbackData emissionData;
+    emissionData.display = display;
+    emissionData.data = handle;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        signalId = OS.g_signal_lookup (OS.map.ptr, OS.GTK_TYPE_WIDGET());
+        hookId = OS.g_signal_add_emission_hook (signalId, 0, &Display.emissionFunc, &emissionData, null);
+    }
+    int response = OS.gtk_dialog_run (handle);
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.g_signal_remove_emission_hook (signalId, hookId);
+    }
+    if (OS.gtk_window_get_modal (handle)) {
+        display.setModalDialog (oldModal);
+    }
     display.removeIdleProc ();
     OS.gtk_widget_destroy (handle);
-    return result;
+    return response;
 }
 
 private void createButtons() {
--- a/dwt/widgets/Monitor.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Monitor.d	Mon May 12 19:13:01 2008 +0200
@@ -22,7 +22,7 @@
  * @since 3.0
  */
 public final class Monitor {
-    int handle;
+    int /*long*/ handle;
     int x, y, width, height;
     int clientX, clientY, clientWidth, clientHeight;
 
@@ -52,7 +52,8 @@
 
 /**
  * Returns a rectangle describing the receiver's size and location
- * relative to its device.
+ * relative to its device. Note that on multi-monitor systems the
+ * origin can be negative.
  *
  * @return the receiver's bounding rectangle
  */
--- a/dwt/widgets/ProgressBar.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/ProgressBar.d	Mon May 12 19:13:01 2008 +0200
@@ -146,6 +146,11 @@
     return selection;
 }
 
+public int getState () {
+    checkWidget ();
+    return DWT.NORMAL;
+}
+
 override int gtk_realize (GtkWidget* widget) {
     int result = super.gtk_realize (widget);
     if (result !is 0) return result;
@@ -234,6 +239,11 @@
     updateBar (selection, minimum, maximum);
 }
 
+public void setState (int state) {
+    checkWidget ();
+    //NOT IMPLEMENTED
+}
+
 override int /*long*/ timerProc (GtkWidget* widget) {
     if (isVisible ()) OS.gtk_progress_bar_pulse (handle);
     return 1;
--- a/dwt/widgets/Sash.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Sash.d	Mon May 12 19:13:01 2008 +0200
@@ -201,14 +201,16 @@
     if ((style & DWT.SMOOTH) is 0) {
         event.detail = DWT.DRAG;
     }
+    if ((parent.style & DWT.MIRRORED) !is 0) event.x = parent.getClientWidth () - width  - event.x;
     sendEvent (DWT.Selection, event);
     if (isDisposed ()) return 0;
     if (event.doit) {
         dragging = true;
         lastX = event.x;
         lastY = event.y;
+        if ((parent.style & DWT.MIRRORED) !is 0) lastX = parent.getClientWidth () - width  - lastX;
         parent.update (true, (style & DWT.SMOOTH) is 0);
-        drawBand (event.x, event.y, width, height);
+        drawBand (lastX, event.y, width, height);
         if ((style & DWT.SMOOTH) !is 0) {
             setBounds (event.x, event.y, width, height);
             // widget could be disposed at this point
@@ -233,6 +235,7 @@
     event.width = width;
     event.height = height;
     drawBand (lastX, lastY, width, height);
+    if ((parent.style & DWT.MIRRORED) !is 0) event.x = parent.getClientWidth () - width  - event.x;
     sendEvent (DWT.Selection, event);
     if (isDisposed ()) return result;
     if (event.doit) {
@@ -301,6 +304,7 @@
             event.y = newY;
             event.width = width;
             event.height = height;
+            if ((parent.style & DWT.MIRRORED) !is 0) event.x = parent.getClientWidth () - width  - event.x;
             sendEvent (DWT.Selection, event);
             if (ptrGrabResult is OS.GDK_GRAB_SUCCESS) OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME);
             if (isDisposed ()) break;
@@ -308,6 +312,7 @@
             if (event.doit) {
                 lastX = event.x;
                 lastY = event.y;
+                if ((parent.style & DWT.MIRRORED) !is 0) lastX = parent.getClientWidth () - width  - lastX;
                 if ((style & DWT.SMOOTH) !is 0) {
                     setBounds (event.x, event.y, width, height);
                     if (isDisposed ()) break;
@@ -371,16 +376,18 @@
     if ((style & DWT.SMOOTH) is 0) {
         event.detail = DWT.DRAG;
     }
+    if ((parent.style & DWT.MIRRORED) !is 0) event.x = parent.getClientWidth() - width  - event.x;
     sendEvent (DWT.Selection, event);
     if (isDisposed ()) return 0;
     if (event.doit) {
         lastX = event.x;
         lastY = event.y;
+        if ((parent.style & DWT.MIRRORED) !is 0) lastX = parent.getClientWidth () - width  - lastX;
     }
     parent.update (true, (style & DWT.SMOOTH) is 0);
     drawBand (lastX, lastY, width, height);
     if ((style & DWT.SMOOTH) !is 0) {
-        setBounds (lastX, lastY, width, height);
+        setBounds (event.x, lastY, width, height);
         // widget could be disposed at this point
     }
     return result;
--- a/dwt/widgets/ScrollBar.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/ScrollBar.d	Mon May 12 19:13:01 2008 +0200
@@ -156,6 +156,16 @@
     if (adjustmentHandle !is null) display.removeWidget (cast(GtkWidget*)adjustmentHandle);
 }
 
+void destroyHandle () {
+    super.destroyWidget ();
+}
+
+void destroyWidget () {
+    parent.destroyScrollBar (this);
+    releaseHandle ();
+    //parent.sendEvent (DWT.Resize);
+}
+
 /**
  * Returns <code>true</code> if the receiver is enabled, and
  * <code>false</code> otherwise. A disabled control is typically
@@ -456,6 +466,11 @@
     if (adjustmentHandle !is null) display.addWidget (cast(GtkWidget*)adjustmentHandle, this);
 }
 
+void releaseHandle () {
+    super.releaseHandle ();
+    parent = null;
+}
+
 override void releaseParent () {
     super.releaseParent ();
     if (parent.horizontalBar is this) parent.horizontalBar = null;
@@ -464,7 +479,7 @@
 
 override void releaseWidget () {
     super.releaseWidget ();
-    parent = null;
+    //parent = null;
 }
 
 /**
@@ -583,6 +598,17 @@
     OS.g_signal_handlers_unblock_matched (adjustmentHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udVALUE_CHANGED);
 }
 
+void setOrientation () {
+    super.setOrientation ();
+    if ((parent.style & DWT.MIRRORED) !is 0) {
+        if ((parent.state & CANVAS) !is 0) {
+            if ((style & DWT.HORIZONTAL) !is 0) {
+                OS.gtk_range_set_inverted (handle, true);
+            }
+        }
+    }
+}
+
 /**
  * Sets the amount that the receiver's value will be
  * modified by when the page increment/decrement areas
@@ -709,7 +735,10 @@
  */
 public void setVisible (bool visible) {
     checkWidget ();
-    parent.setScrollBarVisible (this, visible);
+    if (parent.setScrollBarVisible (this, visible)) {
+        sendEvent (visible ? DWT.Show : DWT.Hide);
+        parent.sendEvent (DWT.Resize);
+    }
 }
 
 }
--- a/dwt/widgets/Scrollable.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Scrollable.d	Mon May 12 19:13:01 2008 +0200
@@ -149,6 +149,7 @@
         bar.handle = OS.GTK_SCROLLED_WINDOW_VSCROLLBAR (cast(GtkScrolledWindow*)scrolledHandle);
         bar.adjustmentHandle = OS.gtk_scrolled_window_get_vadjustment (cast(GtkScrolledWindow*)scrolledHandle);
     }
+    bar.setOrientation();
     bar.hookEvents ();
     bar.register ();
     return bar;
@@ -165,6 +166,12 @@
     if (scrolledHandle !is null) display.removeWidget (cast(GtkWidget*)scrolledHandle);
 }
 
+void destroyScrollBar (ScrollBar bar) {
+    setScrollBarVisible (bar, false);
+    //This code is intentionally commented
+    //bar.destroyHandle ();
+}
+
 public override int getBorderWidth () {
     checkWidget();
     int border = 0;
@@ -301,8 +308,6 @@
         vsp = policy;
     }
     OS.gtk_scrolled_window_set_policy (cast(GtkScrolledWindow*)scrolledHandle, hsp, vsp);
-    bar.sendEvent (visible ? DWT.Show : DWT.Hide);
-    sendEvent (DWT.Resize);
     return true;
 }
 
--- a/dwt/widgets/Shell.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Shell.d	Mon May 12 19:13:01 2008 +0200
@@ -22,6 +22,7 @@
 import dwt.internal.gtk.OS;
 import dwt.events.ShellListener;
 import dwt.graphics.Cursor;
+import dwt.graphics.GC;
 import dwt.graphics.Image;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
@@ -149,17 +150,17 @@
     alias Decorations.setToolTipText setToolTipText;
     alias Decorations.setZOrder setZOrder;
 
-    GtkWidget* shellHandle, tooltipsHandle, tooltipWindow;
-    bool mapped, moved, resized, opened;
+    GtkWidget* shellHandle, tooltipsHandle, tooltipWindow, group, modalGroup;
+    bool mapped, moved, resized, opened, fullScreen, showWithParent;
+
     int oldX, oldY, oldWidth, oldHeight;
     int minWidth, minHeight;
     Control lastActive;
-    Region region;
     CallbackData filterProcCallbackData;
     CallbackData sizeAllocateProcCallbackData;
     CallbackData sizeRequestProcCallbackData;
 
-    static final int MAXIMUM_TRIM = 128;
+    static const int MAXIMUM_TRIM = 128;
 
 /**
  * Constructs a new instance of this class. This is equivalent
@@ -393,6 +394,7 @@
 
 static int checkStyle (int style) {
     style = Decorations.checkStyle (style);
+    style &= ~DWT.TRANSPARENT;
     if ((style & DWT.ON_TOP) !is 0) style &= ~DWT.SHELL_TRIM;
     int mask = DWT.SYSTEM_MODAL | DWT.APPLICATION_MODAL | DWT.PRIMARY_MODAL;
     int bits = style & ~mask;
@@ -649,11 +651,6 @@
             OS.gtk_style_get_black (OS.gtk_widget_get_style (shellHandle), color);
             OS.gtk_widget_modify_bg (shellHandle,  OS.GTK_STATE_NORMAL, color);
         }
-        int bits = DWT.PRIMARY_MODAL | DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL;
-        bool modal = (style & bits) !is 0;
-        //TEMPORARY CODE
-        if ((style & DWT.ON_TOP) is 0) modal |= (parent !is null && (parent.style & bits) !is 0);
-        OS.gtk_window_set_modal (cast(GtkWindow*)shellHandle, modal);
     } else {
         vboxHandle = OS.gtk_bin_get_child (cast(GtkBin*)shellHandle);
         if (vboxHandle is null) error (DWT.ERROR_NO_HANDLES);
@@ -666,6 +663,8 @@
         handle = OS.gtk_bin_get_child (cast(GtkBin*)scrolledHandle);
         if (handle is null) error (DWT.ERROR_NO_HANDLES);
     }
+    group = cast(GtkWidget*) OS.gtk_window_group_new ();
+    if (group is null) error (DWT.ERROR_NO_HANDLES);
     /*
     * Feature in GTK.  Realizing the shell triggers a size allocate event,
     * which may be confused for a resize event from the window manager if
@@ -734,8 +733,6 @@
 override void hookEvents () {
     super.hookEvents ();
     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [KEY_PRESS_EVENT], 0, display.closures [KEY_PRESS_EVENT], false);
-    OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [MAP_EVENT], 0, display.closures [MAP_EVENT], false);
-    OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [UNMAP_EVENT], 0, display.closures [UNMAP_EVENT], false);
     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [WINDOW_STATE_EVENT], 0, display.closures [WINDOW_STATE_EVENT], false);
     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [SIZE_ALLOCATE], 0, display.closures [SIZE_ALLOCATE], false);
     OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [CONFIGURE_EVENT], 0, display.closures [CONFIGURE_EVENT], false);
@@ -804,6 +801,13 @@
     }
 }
 
+override void fixedSizeAllocateProc(GtkWidget* widget, GtkAllocation* allocationPtr) {
+    int clientWidth = 0;
+    if ((style & DWT.MIRRORED) !is 0) clientWidth = getClientWidth ();
+    super.fixedSizeAllocateProc (widget, allocationPtr);
+    if ((style & DWT.MIRRORED) !is 0) moveChildren (clientWidth);
+}
+
 override void fixStyle (GtkWidget* handle) {
 }
 
@@ -823,6 +827,21 @@
     OS.gtk_widget_size_allocate (cast(GtkWidget*)vboxHandle, &allocation);
 }
 
+public int getAlpha () {
+    checkWidget ();
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
+        if (OS.gtk_widget_is_composited (shellHandle)) {
+            return cast(int) (OS.gtk_window_get_opacity (shellHandle) * 255);
+        }
+    }
+    return 255;
+}
+
+public bool getFullScreen () {
+    checkWidget();
+    return fullScreen;
+}
+
 override public Point getLocation () {
     checkWidget ();
     int x, y;
@@ -830,6 +849,11 @@
     return new Point (x, y);
 }
 
+public bool getMaximized () {
+    checkWidget();
+    return !fullScreen && super.getMaximized ();
+}
+
 /**
  * Returns a point describing the minimum receiver's size. The
  * x coordinate of the result is the minimum width of the receiver.
@@ -852,6 +876,34 @@
     return new Point (width, height);
 }
 
+Shell getModalShell () {
+    Shell shell = null;
+    Shell [] modalShells = display.modalShells;
+    if (modalShells !is null) {
+        int bits = DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL;
+        int index = modalShells.length;
+        while (--index >= 0) {
+            Shell modal = modalShells [index];
+            if (modal !is null) {
+                if ((modal.style & bits) !is 0) {
+                    Control control = this;
+                    while (control !is null) {
+                        if (control is modal) break;
+                        control = control.parent;
+                    }
+                    if (control !is modal) return modal;
+                    break;
+                }
+                if ((modal.style & DWT.PRIMARY_MODAL) !is 0) {
+                    if (shell is null) shell = getShell ();
+                    if (modal.parent is shell) return modal;
+                }
+            }
+        }
+    }
+    return null;
+}
+
 override public Point getSize () {
     checkWidget ();
     int width = OS.GTK_WIDGET_WIDTH (vboxHandle);
@@ -883,6 +935,7 @@
  *
  */
 public Region getRegion () {
+    /* This method is needed for @since 3.0 Javadoc */
     checkWidget ();
     return region;
 }
@@ -1009,12 +1062,6 @@
     return super.gtk_key_press_event (widget, event);
 }
 
-override int /*long*/ gtk_map_event (GtkWidget* widget, int /*long*/ event) {
-    minimized = false;
-    sendEvent (DWT.Deiconify);
-    return 0;
-}
-
 override int /*long*/ gtk_size_allocate (GtkWidget* widget, int /*long*/ allocation) {
     int width = OS.GTK_WIDGET_WIDTH (shellHandle);
     int height = OS.GTK_WIDGET_HEIGHT (shellHandle);
@@ -1054,15 +1101,18 @@
     return result;
 }
 
-override int /*long*/ gtk_unmap_event (GtkWidget* widget, int /*long*/ event) {
-    minimized = true;
-    sendEvent (DWT.Iconify);
-    return 0;
-}
-
 override int /*long*/ gtk_window_state_event (GtkWidget* widget, GdkEventWindowState* event) {
     minimized = (event.new_window_state & OS.GDK_WINDOW_STATE_ICONIFIED) !is 0;
     maximized = (event.new_window_state & OS.GDK_WINDOW_STATE_MAXIMIZED) !is 0;
+    fullScreen = (event.new_window_state & OS.GDK_WINDOW_STATE_FULLSCREEN) !is 0;
+    if ((event.changed_mask & OS.GDK_WINDOW_STATE_ICONIFIED) !is 0) {
+        if (minimized) {
+            sendEvent (DWT.Iconify);
+        } else {
+            sendEvent (DWT.Deiconify);
+        }
+        updateMinimized (minimized);
+    }
     return 0;
 }
 
@@ -1095,6 +1145,13 @@
     if (!restoreFocus () && !traverseGroup (true)) setFocus ();
 }
 
+public bool print (GC gc) {
+    checkWidget ();
+    if (gc is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (gc.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT);
+    return false;
+}
+
 /**
  * Removes the listener from the collection of listeners who will
  * be notified when operations are performed on the receiver.
@@ -1186,6 +1243,16 @@
     }
 }
 
+public void setAlpha (int alpha) {
+    checkWidget ();
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
+        if (OS.gtk_widget_is_composited (shellHandle)) {
+            alpha &= 0xFF;
+            OS.gtk_window_set_opacity (shellHandle, alpha / 255f);
+        }
+    }
+}
+
 void resizeBounds (int width, int height, bool notify) {
     if (redrawWindow !is null) {
         OS.gdk_window_resize (redrawWindow, width, height);
@@ -1210,6 +1277,7 @@
 }
 
 override int setBounds (int x, int y, int width, int height, bool move, bool resize) {
+    if (fullScreen) setFullScreen (false);
     /*
     * Bug in GTK.  When either of the location or size of
     * a shell is changed while the shell is maximized, the
@@ -1323,6 +1391,19 @@
     }
 }
 
+public void setFullScreen (bool fullScreen) {
+    checkWidget();
+    if (fullScreen) {
+        OS.gtk_window_fullscreen (shellHandle);
+    } else {
+        OS.gtk_window_unfullscreen (shellHandle);
+        if (maximized) {
+            setMaximized (true);
+        }
+    }
+    this.fullScreen = fullScreen;
+}
+
 /**
  * Sets the input method editor mode to the argument which
  * should be the result of bitwise OR'ing together one or more
@@ -1471,11 +1552,7 @@
 public void setRegion (Region region) {
     checkWidget ();
     if ((style & DWT.NO_TRIM) is 0) return;
-    if (region !is null && region.isDisposed()) error (DWT.ERROR_INVALID_ARGUMENT);
-    auto window = OS.GTK_WIDGET_WINDOW (shellHandle);
-    auto shape_region = (region is null) ? null : region.handle;
-    OS.gdk_window_shape_combine_region (window, shape_region, 0, 0);
-    this.region = region;
+    super.setRegion (region);
 }
 
 /*
@@ -1503,6 +1580,19 @@
 
 public override void setVisible (bool visible) {
     checkWidget();
+    int mask = DWT.PRIMARY_MODAL | DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL;
+    if ((style & mask) !is 0) {
+        if (visible) {
+            display.setModalShell (this);
+            OS.gtk_window_set_modal (shellHandle, true);
+        } else {
+            display.clearModal (this);
+            OS.gtk_window_set_modal (shellHandle, false);
+        }
+    } else {
+        updateModal ();
+    }
+    showWithParent = visible;
     if ((OS.GTK_WIDGET_MAPPED (shellHandle) is visible)) return;
     if (visible) {
         sendEvent (DWT.Show);
@@ -1520,6 +1610,7 @@
         * unminimized or shown on the desktop.
         */
         OS.gtk_widget_show (shellHandle);
+        if (enableWindow !is null) OS.gdk_window_raise (enableWindow);
         if (!OS.GTK_IS_PLUG (cast(GTypeInstance*)shellHandle)) {
             mapped = false;
             if (isDisposed ()) return;
@@ -1550,7 +1641,6 @@
         }
         mapped = true;
 
-        int mask = DWT.PRIMARY_MODAL | DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL;
         if ((style & mask) !is 0) {
             OS.gdk_pointer_ungrab (OS.GDK_CURRENT_TIME);
         }
@@ -1644,6 +1734,7 @@
 }
 int trimHeight () {
     if ((style & DWT.NO_TRIM) !is 0) return 0;
+    if (fullScreen) return 0;
     bool hasTitle = false, hasResize = false, hasBorder = false;
     hasTitle = (style & (DWT.MIN | DWT.MAX | DWT.TITLE | DWT.MENU)) !is 0;
     hasResize = (style & DWT.RESIZE) !is 0;
@@ -1660,6 +1751,7 @@
 
 int trimWidth () {
     if ((style & DWT.NO_TRIM) !is 0) return 0;
+    if (fullScreen) return 0;
     bool hasTitle = false, hasResize = false, hasBorder = false;
     hasTitle = (style & (DWT.MIN | DWT.MAX | DWT.TITLE | DWT.MENU)) !is 0;
     hasResize = (style & DWT.RESIZE) !is 0;
@@ -1674,6 +1766,72 @@
     return 0;
 }
 
+void updateModal () {
+    GtkWidget* group = null;
+    if (display.getModalDialog () is null) {
+        Shell modal = getModalShell ();
+        int mask = DWT.PRIMARY_MODAL | DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL;
+        Composite shell = null;
+        if (modal is null) {
+            if ((style & mask) !is 0) shell = this;
+        } else {
+            shell = modal;
+        }
+        while (shell !is null) {
+            if ((shell.style & mask) is 0) {
+                group = shell.getShell ().group;
+                break;
+            }
+            shell = shell.parent;
+        }
+    }
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 10, 0) && group is null) {
+        /*
+        * Feature in GTK. Starting with GTK version 2.10, GTK
+        * doesn't assign windows to a default group. The fix is to
+        * get the handle of the default group and add windows to the
+        * group.
+        */
+        group = cast(GtkWidget*)OS.gtk_window_get_group(null);
+    }
+    if (group !is null) {
+        OS.gtk_window_group_add_window (group, shellHandle);
+    } else {
+        if (modalGroup !is null) {
+            OS.gtk_window_group_remove_window (modalGroup, shellHandle);
+        }
+    }
+    if (OS.GTK_VERSION < OS.buildVERSION (2, 4, 0)) {
+        fixModal (group, modalGroup);
+    }
+    modalGroup = group;
+}
+
+void updateMinimized (bool minimized) {
+    Shell[] shells = getShells ();
+    for (int i = 0; i < shells.length; i++) {
+        bool update = false;
+        Shell shell = shells[i];
+        while (shell !is null && shell !is this && !shell.isUndecorated ()) {
+            shell = cast(Shell) shell.getParent ();
+        }
+        if (shell !is null && shell !is this) update = true;
+        if (update) {
+            if (minimized) {
+                if (shells[i].isVisible ()) {
+                    shells[i].showWithParent = true;
+                    OS.gtk_widget_hide(shells[i].shellHandle);
+                }
+            } else {
+                if (shells[i].showWithParent) {
+                    shells[i].showWithParent = false;
+                    OS.gtk_widget_show(shells[i].shellHandle);
+                }
+            }
+        }
+    }
+}
+
 override void deregister () {
     super.deregister ();
     display.removeWidget (shellHandle);
@@ -1748,76 +1906,129 @@
 override void releaseWidget () {
     super.releaseWidget ();
     destroyAccelGroup ();
+    display.clearModal (this);
     if (display.activeShell is this) display.activeShell = null;
     if (tooltipsHandle !is null) OS.g_object_unref (tooltipsHandle);
     tooltipsHandle = null;
+    if (group !is null) OS.g_object_unref (group);
+    group = modalGroup = null;
     auto window = OS.GTK_WIDGET_WINDOW (shellHandle);
     display.doWindowRemoveFilter( &filterProcCallbackData, window, shellHandle );
-    region = null;
+
     lastActive = null;
 }
 
-void setToolTipText (GtkWidget* widget, String string) {
-    char* buffer = toStringz( string );
-    if (tooltipsHandle is null) {
-        tooltipsHandle = cast(GtkWidget*)OS.gtk_tooltips_new ();
-        if (tooltipsHandle is null) error (DWT.ERROR_NO_HANDLES);
-        OS.g_object_ref (tooltipsHandle);
-        OS.gtk_object_sink (cast(GtkObject*)tooltipsHandle);
-    }
-
-    /*
-    * Feature in GTK.  There is no API to position a tooltip.
-    * The fix is to connect to the size_allocate signal for
-    * the tooltip window and position it before it is mapped.
-    *
-    * Bug in Solaris-GTK.  Invoking gtk_tooltips_force_window()
-    * can cause a crash in older versions of GTK.  The fix is
-    * to avoid this call if the GTK version is older than 2.2.x.
-    */
-    if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 1)) {
-        OS.gtk_tooltips_force_window (cast(GtkTooltips*)tooltipsHandle);
-    }
-    auto tipWindow = OS.GTK_TOOLTIPS_TIP_WINDOW (cast(GtkTooltips*)tooltipsHandle);
-    if (tipWindow !is null && tipWindow !is tooltipWindow) {
-        display.doSizeAllocateConnect( &sizeAllocateProcCallbackData, tipWindow, shellHandle );
-        tooltipWindow = tipWindow;
-    }
+void setToolTipText (GtkWidget* tipWidget, String string) {
+    setToolTipText (tipWidget, tipWidget, string);
+}
 
-    /*
-    * Bug in GTK.  If the cursor is inside the window when a new
-    * tooltip is set and the old tooltip is hidden, the new tooltip
-    * is not displayed until the mouse re-enters the window.  The
-    * fix is force the new tooltip to be active.
-    */
-    bool set = true;
-    if (tipWindow !is null) {
-        if ((OS.GTK_WIDGET_FLAGS (widget) & (OS.GTK_REALIZED | OS.GTK_VISIBLE)) !is 0) {
-            int  x, y;
+void setToolTipText (GtkWidget* rootWidget, GtkWidget* tipWidget, String string) {
+    if (OS.GTK_VERSION >= OS.buildVERSION (2, 12, 0)) {
+        char * buffer = null;
+        if (string !is null && string.length > 0) {
+            char [] chars = fixMnemonic (string, false);
+            buffer = tango.stdc.stringz.toStringz( chars );
+        }
+        OS.gtk_widget_set_tooltip_text (rootWidget, null);
+        /*
+        * Bug in GTK. In GTK 2.12, due to a miscalculation of window
+        * coordinates, using gtk_tooltip_trigger_tooltip_query ()
+        * to update an existing a tooltip will result in the tooltip
+        * being displayed at a wrong position. The fix is to send out
+        * 2 fake GDK_MOTION_NOTIFY events (to mimic the GTK call) which
+        * contain the proper x and y coordinates.
+        */
+        GdkEvent* eventPtr = null;
+        auto tipWindow = OS.GTK_WIDGET_WINDOW (rootWidget);
+        if (tipWindow !is null) {
+            int x, y;
             auto window = OS.gdk_window_at_pointer (&x, &y);
-            if (window !is null) {
-                GtkWidget* user_data;
-                OS.gdk_window_get_user_data (window, cast(void**)&user_data);
-                if (widget is user_data) {
-                    /*
-                    * Feature in GTK.  Calling gtk_tooltips_set_tip() positions and
-                    * shows the tooltip.  If the tooltip is already visible, moving
-                    * it to a new location in the size_allocate signal causes flashing.
-                    * The fix is to hide the tip window in the size_request signal
-                    * and before the new tooltip is forced to be active.
-                    */
-                    set = false;
-                    int handler_id = display.doSizeRequestConnect( &sizeRequestProcCallbackData, tipWindow, shellHandle );
-                    OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, widget, buffer, null);
-                    OS.gtk_widget_hide (tipWindow);
-                    auto data = OS.gtk_tooltips_data_get (widget);
-                    OS.GTK_TOOLTIPS_SET_ACTIVE (cast(GtkTooltips*)tooltipsHandle, cast(GtkTooltipsData*)data);
-                    OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, widget, buffer, null);
-                    if (handler_id !is 0) OS.g_signal_handler_disconnect (tipWindow, handler_id);
+            void* user_data;
+            OS.gdk_window_get_user_data (window, &user_data);
+            if (tipWidget is user_data ) {
+                eventPtr = OS.gdk_event_new (OS.GDK_MOTION_NOTIFY);
+                eventPtr.type = OS.GDK_MOTION_NOTIFY;
+                eventPtr.motion.window = cast(GdkDrawable*)OS.g_object_ref (tipWindow);
+                eventPtr.motion.x = x;
+                eventPtr.motion.y = y;
+                OS.gdk_window_get_origin (window, &x, &y);
+                eventPtr.motion.x_root = eventPtr.motion.x + x;
+                eventPtr.motion.y_root = eventPtr.motion.y + y;
+                OS.gtk_main_do_event (eventPtr);
+            }
+        }
+        OS.gtk_widget_set_tooltip_text (rootWidget, buffer);
+        if (eventPtr !is null) {
+            OS.gtk_main_do_event (eventPtr);
+            OS.gdk_event_free (eventPtr);
+        }
+    } else {
+        char* buffer = null;
+        if (string !is null && string.length > 0) {
+            char [] chars = fixMnemonic (string, false);
+            buffer = tango.stdc.stringz.toStringz( chars );
+        }
+        if (tooltipsHandle is null) {
+            tooltipsHandle = cast(GtkWidget*)OS.gtk_tooltips_new ();
+            if (tooltipsHandle is null) error (DWT.ERROR_NO_HANDLES);
+            OS.g_object_ref (tooltipsHandle);
+            OS.gtk_object_sink (cast(GtkObject*)tooltipsHandle);
+        }
+
+        /*
+        * Feature in GTK.  There is no API to position a tooltip.
+        * The fix is to connect to the size_allocate signal for
+        * the tooltip window and position it before it is mapped.
+        *
+        * Bug in Solaris-GTK.  Invoking gtk_tooltips_force_window()
+        * can cause a crash in older versions of GTK.  The fix is
+        * to avoid this call if the GTK version is older than 2.2.x.
+        */
+        if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 1)) {
+            OS.gtk_tooltips_force_window (cast(GtkTooltips*)tooltipsHandle);
+        }
+        auto tipWindow = OS.GTK_TOOLTIPS_TIP_WINDOW (cast(GtkTooltips*)tooltipsHandle);
+        if (tipWindow !is null && tipWindow !is tooltipWindow) {
+            display.doSizeAllocateConnect( &sizeAllocateProcCallbackData, tipWindow, shellHandle );
+            tooltipWindow = tipWindow;
+        }
+
+        /*
+        * Bug in GTK.  If the cursor is inside the window when a new
+        * tooltip is set and the old tooltip is hidden, the new tooltip
+        * is not displayed until the mouse re-enters the window.  The
+        * fix is force the new tooltip to be active.
+        */
+        bool set = true;
+        if (tipWindow !is null) {
+            if ((OS.GTK_WIDGET_FLAGS (tipWidget) & (OS.GTK_REALIZED | OS.GTK_VISIBLE)) !is 0) {
+                int  x, y;
+                auto window = OS.gdk_window_at_pointer (&x, &y);
+                if (window !is null) {
+                    GtkWidget* user_data;
+                    OS.gdk_window_get_user_data (window, cast(void**)&user_data);
+                    if (tipWidget is user_data) {
+                        /*
+                        * Feature in GTK.  Calling gtk_tooltips_set_tip() positions and
+                        * shows the tooltip.  If the tooltip is already visible, moving
+                        * it to a new location in the size_allocate signal causes flashing.
+                        * The fix is to hide the tip window in the size_request signal
+                        * and before the new tooltip is forced to be active.
+                        */
+                        set = false;
+                        int handler_id = display.doSizeRequestConnect( &sizeRequestProcCallbackData, tipWindow, shellHandle );
+                        OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null);
+                        OS.gtk_widget_hide (tipWindow);
+                        auto data = OS.gtk_tooltips_data_get (tipWidget);
+                        OS.GTK_TOOLTIPS_SET_ACTIVE (cast(GtkTooltips*)tooltipsHandle, cast(GtkTooltipsData*)data);
+                        OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null);
+                        if (handler_id !is 0) OS.g_signal_handler_disconnect (tipWindow, handler_id);
+                    }
                 }
             }
         }
+        if (set) OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, tipWidget, buffer, null);
     }
-    if (set) OS.gtk_tooltips_set_tip (cast(GtkTooltips*)tooltipsHandle, widget, buffer, null);
+
 }
 }
--- a/dwt/widgets/Slider.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Slider.d	Mon May 12 19:13:01 2008 +0200
@@ -166,7 +166,17 @@
         handle = cast(GtkWidget*)OS.gtk_vscrollbar_new (hAdjustment);
     }
     if (handle is null) error (DWT.ERROR_NO_HANDLES);
-    OS.GTK_WIDGET_SET_FLAGS (handle, OS.GTK_CAN_FOCUS);
+    /*
+    * Bug in GTK. In GTK 2.10, the buttons on either end of
+    * a horizontal slider are created taller then the slider bar
+    * when the GTK_CAN_FOCUS flag is set. The fix is not to set
+    * the flag for horizontal bars in all versions of 2.10. Note
+    * that a bug has been logged with GTK about this issue.
+    * (http://bugzilla.gnome.org/show_bug.cgi?id=475909)
+    */
+    if (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0) || (style & DWT.VERTICAL) !is 0) {
+        OS.GTK_WIDGET_SET_FLAGS (handle, OS.GTK_CAN_FOCUS);
+    }
     OS.gtk_container_add (fixedHandle, handle);
 }
 
--- a/dwt/widgets/Spinner.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Spinner.d	Mon May 12 19:13:01 2008 +0200
@@ -64,6 +64,16 @@
     GdkEventKey* gdkEventKey;
     int fixStart = -1, fixEnd = -1;
 
+    /**
+    * The maximum number of characters that can be entered
+    * into a text widget.
+    * <p>
+    * Note that this value is platform dependent, based upon
+    * the native widget implementation.
+    * </p>
+    */
+    public const static int LIMIT = 0x7FFFFFFF;
+
 /**
  * Constructs a new instance of this class given its parent
  * and a style value describing its behavior and appearance.
@@ -390,7 +400,7 @@
     int digits = OS.gtk_spin_button_get_digits (cast(GtkSpinButton*)handle);
     auto value = adjustment.step_increment;
     for (int i = 0; i < digits; i++) value *= 10;
-    return cast(int) (value + 0.5);
+    return cast(int) (value > 0 ? value + 0.5 : value - 0.5);
 }
 
 /**
@@ -409,7 +419,7 @@
     int digits = OS.gtk_spin_button_get_digits (cast(GtkSpinButton*)handle);
     auto value = adjustment.upper;
     for (int i = 0; i < digits; i++) value *= 10;
-    return cast(int) (value + 0.5);
+    return cast(int) (value > 0 ? value + 0.5 : value - 0.5);
 }
 
 /**
@@ -428,7 +438,7 @@
     int digits = OS.gtk_spin_button_get_digits (cast(GtkSpinButton*)handle);
     auto value = adjustment.lower;
     for (int i = 0; i < digits; i++) value *= 10;
-    return cast(int) (value + 0.5);
+    return cast(int) (value > 0 ? value + 0.5 : value - 0.5);
 }
 
 /**
@@ -448,7 +458,7 @@
     int digits = OS.gtk_spin_button_get_digits (cast(GtkSpinButton*)handle);
     auto value = adjustment.page_increment;
     for (int i = 0; i < digits; i++) value *= 10;
-    return cast(int) (value + 0.5);
+    return cast(int) (value > 0 ? value + 0.5 : value - 0.5);
 }
 
 /**
@@ -467,7 +477,19 @@
     int digits = OS.gtk_spin_button_get_digits (cast(GtkSpinButton*)handle);
     auto value = adjustment.value;
     for (int i = 0; i < digits; i++) value *= 10;
-    return cast(int) (value + 0.5);
+    return cast(int) (value > 0 ? value + 0.5 : value - 0.5);
+}
+
+public String getText () {
+    checkWidget ();
+    auto str = OS.gtk_entry_get_text (handle);
+    return tango.stdc.stringz.fromStringz(str).dup;
+}
+
+public int getTextLimit () {
+    checkWidget ();
+    int limit = OS.gtk_entry_get_max_length (handle);
+    return limit is 0 ? 0xFFFF : limit;
 }
 
 /**
@@ -646,6 +668,14 @@
     return result;
 }
 
+override int /*long*/ gtk_populate_popup (GtkWidget* widget, GtkWidget* menu) {
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.gtk_widget_set_direction (menu, OS.GTK_TEXT_DIR_RTL);
+        display.doSetDirectionProc( menu, OS.GTK_TEXT_DIR_RTL);
+    }
+    return 0;
+}
+
 override int /*long*/ gtk_value_changed (int  adjustment) {
     postEvent (DWT.Selection);
     return 0;
@@ -658,6 +688,7 @@
     OS.g_signal_connect_closure (handle, OS.delete_text.ptr, display.closures [DELETE_TEXT], false);
     OS.g_signal_connect_closure (handle, OS.value_changed.ptr, display.closures [VALUE_CHANGED], false);
     OS.g_signal_connect_closure (handle, OS.activate.ptr, display.closures [ACTIVATE], false);
+    OS.g_signal_connect_closure (handle, OS.populate_popup.ptr, display.closures [POPULATE_POPUP], false);
     auto imContext = imContext ();
     if (imContext !is null) {
         OS.g_signal_connect_closure (imContext, OS.commit.ptr, display.closures [COMMIT], false);
@@ -835,7 +866,6 @@
  */
 public void setMaximum (int value) {
     checkWidget ();
-    if (value < 0) return;
     auto adjustment = OS.gtk_spin_button_get_adjustment (cast(GtkSpinButton*)handle);
     double newValue = value;
     int digits = OS.gtk_spin_button_get_digits (cast(GtkSpinButton*)handle);
@@ -861,7 +891,6 @@
  */
 public void setMinimum (int value) {
     checkWidget ();
-    if (value < 0) return;
     auto adjustment = OS.gtk_spin_button_get_adjustment (cast(GtkSpinButton*)handle);
     double newValue = value;
     int digits = OS.gtk_spin_button_get_digits (cast(GtkSpinButton*)handle);
@@ -919,6 +948,12 @@
     OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udVALUE_CHANGED);
 }
 
+public void setTextLimit (int limit) {
+    checkWidget ();
+    if (limit is 0) error (DWT.ERROR_CANNOT_BE_ZERO);
+    OS.gtk_entry_set_max_length (handle, limit);
+}
+
 /**
  * Sets the number of decimal places used by the receiver.
  * <p>
@@ -989,7 +1024,6 @@
  */
 public void setValues (int selection, int minimum, int maximum, int digits, int increment, int pageIncrement) {
     checkWidget ();
-    if (minimum < 0) return;
     if (maximum <= minimum) return;
     if (digits < 0) return;
     if (increment < 1) return;
@@ -1052,6 +1086,10 @@
         }
         index = 0;
     }
+    if (string.length  > 0) {
+        auto adjustment = OS.gtk_spin_button_get_adjustment (handle);
+        if (adjustment.lower < 0 && string.charAt (0) is '-') index++;
+    }
     while (index < string.length) {
         if (!CharacterIsDigit (string.charAt(index))) break;
         index++;
--- a/dwt/widgets/Synchronizer.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Synchronizer.d	Mon May 12 19:13:01 2008 +0200
@@ -20,6 +20,7 @@
 
 import dwt.DWT;
 import tango.core.Thread;
+import dwt.graphics.Device;
 import tango.core.Exception;
 
 /**
@@ -45,6 +46,8 @@
     RunnableLock [] messages;
     Object messageLock;
     Thread syncThread;
+    static final int GROW_SIZE = 4;
+    static final int MESSAGE_LIMIT = 64;
 
 /**
  * Constructs a new instance of this class.
@@ -59,9 +62,9 @@
 void addLast (RunnableLock lock) {
     bool wake = false;
     synchronized (messageLock) {
-        if (messages is null) messages = new RunnableLock [4];
+        if (messages is null) messages = new RunnableLock [GROW_SIZE];
         if (messageCount is messages.length) {
-            RunnableLock[] newMessages = new RunnableLock [messageCount + 4];
+            RunnableLock[] newMessages = new RunnableLock [messageCount + GROW_SIZE];
             System.arraycopy (messages, 0, newMessages, 0, messageCount);
             messages = newMessages;
         }
@@ -110,7 +113,7 @@
         System.arraycopy (messages, 1, messages, 0, --messageCount);
         messages [messageCount] = null;
         if (messageCount is 0) {
-            if (messages.length > 64) messages = null;
+            if (messages.length > MESSAGE_LIMIT) messages = null;
         }
         return lock;
     }
@@ -157,21 +160,27 @@
  * @see #asyncExec
  */
 public void syncExec (Runnable runnable) {
-    if (display.isValidThread ()) {
+    RunnableLock lock = null;
+    synchronized (Device.classinfo) {
+        if (display is null || display.isDisposed ()) DWT.error (DWT.ERROR_DEVICE_DISPOSED);
+        if (!display.isValidThread ()) {
+            if (runnable is null) {
+                display.wake ();
+                return;
+            }
+            lock = new RunnableLock (runnable);
+            /*
+             * Only remember the syncThread for syncExec.
+             */
+            lock.thread = Thread.getThis();
+            addLast (lock);
+        }
+    }
+    if (lock is null) {
         if (runnable !is null) runnable.run ();
         return;
     }
-    if (runnable is null) {
-        display.wake ();
-        return;
-    }
-    RunnableLock lock = new RunnableLock (runnable);
-    /*
-     * Only remember the syncThread for syncExec.
-     */
-    lock.thread = Thread.getThis();
     synchronized (lock) {
-        addLast (lock);
         bool interrupted = false;
         while (!lock.done ()) {
             try {
--- a/dwt/widgets/TabFolder.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/TabFolder.d	Mon May 12 19:13:01 2008 +0200
@@ -298,7 +298,7 @@
 }
 
 override GtkWidget* eventHandle () {
-    return fixedHandle;
+    return handle;
 }
 
 /**
@@ -327,6 +327,21 @@
     return items [index];
 }
 
+public TabItem getItem(Point point) {
+    checkWidget();
+    if (point is null) error (DWT.ERROR_NULL_ARGUMENT);
+    auto list = OS.gtk_container_get_children (handle);
+    if (list is null) return null;
+    int itemCount = OS.g_list_length (list);
+    OS.g_list_free (list);
+    for (int i = 0; i < itemCount; i++) {
+        TabItem item = items[i];
+        Rectangle rect = item.getBounds();
+        if (rect.contains(point)) return item;
+    }
+    return null;
+}
+
 /**
  * Returns the number of items contained in the receiver.
  *
--- a/dwt/widgets/TabItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/TabItem.d	Mon May 12 19:13:01 2008 +0200
@@ -19,6 +19,7 @@
 import dwt.DWT;
 import dwt.DWTException;
 import dwt.graphics.Image;
+import dwt.graphics.Rectangle;
 import dwt.internal.gtk.OS;
 import dwt.widgets.Item;
 import dwt.widgets.Control;
@@ -145,6 +146,16 @@
     releaseHandle ();
 }
 
+public Rectangle getBounds () {
+    checkWidget();
+    int x = OS.GTK_WIDGET_X (handle);
+    int y = OS.GTK_WIDGET_Y (handle);
+    int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (handle);
+    int height = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (handle);
+    if ((parent.style & DWT.MIRRORED) !is 0) x = parent.getClientWidth () - width - x;
+    return new Rectangle (x, y, width, height);
+}
+
 /**
  * Returns the control that is used to fill the client area of
  * the tab folder when the user selects the tab item.  If no
--- a/dwt/widgets/Table.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Table.d	Mon May 12 19:13:01 2008 +0200
@@ -184,11 +184,17 @@
 
 static int checkStyle (int style) {
     /*
-    * To be compatible with Windows, force the H_SCROLL
-    * and V_SCROLL style bits.  On Windows, it is not
-    * possible to create a table without scroll bars.
+    * Feature in Windows.  Even when WS_HSCROLL or
+    * WS_VSCROLL is not specified, Windows creates
+    * trees and tables with scroll bars.  The fix
+    * is to set H_SCROLL and V_SCROLL.
+    *
+    * NOTE: This code appears on all platforms so that
+    * applications have consistent scroll bar behavior.
     */
-    style |= DWT.H_SCROLL | DWT.V_SCROLL;
+    if ((style & DWT.NO_SCROLL) is 0) {
+        style |= DWT.H_SCROLL | DWT.V_SCROLL;
+    }
     /* GTK is always FULL_SELECTION */
     style |= DWT.FULL_SELECTION;
     return checkBits (style, DWT.SINGLE, DWT.MULTI, 0, 0, 0, 0);
@@ -1153,6 +1159,13 @@
     return new Rectangle (fixedX - binX, fixedY - binY, width, height);
 }
 
+int getClientWidth () {
+    int w, h;
+    OS.gtk_widget_realize (handle);
+    OS.gdk_drawable_get_size(OS.gtk_tree_view_get_bin_window(handle), &w, &h);
+    return w;
+}
+
 /**
  * Returns the column at the given, zero-relative index in the
  * receiver. Throws an exception if the index is out of range.
@@ -2362,22 +2375,9 @@
     }
     items = new TableItem [4];
     itemCount = 0;
-
-    /*
-    * Bug in GTK.  In version 2.3.2, when the property fixed-height-mode
-    * is set and there are items in the list, OS.gtk_list_store_clear()
-    * segment faults.  The fix is to create a new empty model instead.
-    */
     auto selection = OS.gtk_tree_view_get_selection (handle);
     OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
-//  OS.gtk_list_store_clear (modelHandle);
-    auto oldModel = modelHandle;
-    auto types = getColumnTypes (Math.max (1,columnCount));
-    auto newModel = OS.gtk_list_store_newv (types.length, types.ptr);
-    if (newModel is null) error (DWT.ERROR_NO_HANDLES);
-    OS.gtk_tree_view_set_model (handle, newModel);
-    OS.g_object_unref (oldModel);
-    modelHandle = cast(GtkWidget*)newModel;
+    OS.gtk_list_store_clear (modelHandle);
     OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
 
     resetCustomDraw ();
@@ -2485,7 +2485,7 @@
                 sendEvent (DWT.MeasureItem, event);
                 gc.dispose ();
                 contentWidth = event.width - imageWidth;
-                contentHeight = event.height;
+                if (contentHeight < event.height) contentHeight = event.height;
                 if (width !is null) *width = contentWidth;
                 if (height !is null) *height = contentHeight;
             }
@@ -2562,6 +2562,7 @@
                     gc.setForeground (item.getForeground (columnIndex));
                 }
                 gc.setFont (item.getFont (columnIndex));
+                if ((style & DWT.MIRRORED) !is 0) rect.x = getClientWidth () - rect.width - rect.x;
                 gc.setClipping (rect.x, rect.y, rect.width, rect.height);
                 Event event = new Event ();
                 event.item = item;
@@ -2634,6 +2635,7 @@
                     gc.setForeground (foreground);
                 }
                 gc.setFont (item.getFont (columnIndex));
+                if ((style & DWT.MIRRORED) !is 0) rect.x = getClientWidth () - rect.width - rect.x;
                 gc.setClipping (rect.x, rect.y, rect.width, rect.height);
                 Event event = new Event ();
                 event.item = item;
--- a/dwt/widgets/TableItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/TableItem.d	Mon May 12 19:13:01 2008 +0200
@@ -136,6 +136,79 @@
     return control;
 }
 
+Color _getBackground () {
+    void* ptr;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.BACKGROUND_COLUMN, &ptr);
+    if (ptr is null) return parent.getBackground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+Color _getBackground (int index) {
+    int count = Math.max (1, parent.columnCount);
+    if (0 > index || index > count - 1) return _getBackground ();
+    void* ptr;
+    int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_BACKGROUND, &ptr);
+    if (ptr is null) return _getBackground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+bool _getChecked () {
+    void* ptr;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.CHECKED_COLUMN, &ptr);
+    return ptr !is null;
+}
+
+Color _getForeground () {
+    void* ptr;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.FOREGROUND_COLUMN, &ptr);
+    if (ptr is null) return parent.getForeground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+Color _getForeground (int index) {
+    int count = Math.max (1, parent.columnCount);
+    if (0 > index || index > count - 1) return _getForeground ();
+    void* ptr;
+    int modelIndex =  parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_FOREGROUND, &ptr);
+    if (ptr is null) return _getForeground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+Image _getImage (int index) {
+    int count = Math.max (1, parent.getColumnCount ());
+    if (0 > index || index > count - 1) return null;
+    void* ptr;
+    int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_PIXBUF, &ptr);
+    if (ptr is null) return null;
+    ImageList imageList = parent.imageList;
+    int imageIndex = imageList.indexOf (ptr);
+    if (imageIndex is -1) return null;
+    return imageList.get (imageIndex);
+}
+
+String _getText (int index) {
+    int count = Math.max (1, parent.getColumnCount ());
+    if (0 > index || index > count - 1) return "";
+    void* ptr;
+    int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_TEXT, &ptr);
+    if (ptr is null) return "";
+    char[] buffer = tango.stdc.stringz.fromStringz( cast(char*)ptr).dup;
+    OS.g_free (ptr);
+    return buffer;
+}
+
 protected override void checkSubclass () {
     if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS);
 }
@@ -183,11 +256,7 @@
 public Color getBackground () {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    void* ptr;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.BACKGROUND_COLUMN, &ptr);
-    if (ptr is null) return parent.getBackground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getBackground ();
 }
 
 /**
@@ -225,6 +294,7 @@
     GdkRectangle rect;
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
     OS.gtk_tree_path_free (path);
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
     int right = rect.x + rect.width;
 
     int x, w;
@@ -257,7 +327,8 @@
             rect.width = Math.max (0, right - rect.x);
         }
     }
-    return new Rectangle (rect.x, rect.y, rect.width + 1, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 /**
@@ -276,14 +347,7 @@
 public Color getBackground (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.columnCount);
-    if (0 > index || index > count - 1) return getBackground ();
-    void* ptr;
-    int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_BACKGROUND, &ptr);
-    if (ptr is null) return getBackground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getBackground (index);
 }
 
 /**
@@ -314,6 +378,7 @@
     GdkRectangle rect;
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
     OS.gtk_tree_path_free (path);
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
 
     if (index is 0 && (parent.style & DWT.CHECK) !is 0) {
         if (OS.GTK_VERSION >= OS.buildVERSION (2, 1, 3)) {
@@ -330,7 +395,8 @@
             rect.width -= w + buffer;
         }
     }
-    return new Rectangle (rect.x, rect.y, rect.width + 1, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 /**
@@ -349,9 +415,7 @@
     checkWidget();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
     if ((parent.style & DWT.CHECK) is 0) return false;
-    void* ptr;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.CHECKED_COLUMN, &ptr);
-    return ptr !is null;
+    return _getChecked ();
 }
 
 /**
@@ -410,11 +474,7 @@
 public Color getForeground () {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    void* ptr;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.FOREGROUND_COLUMN, &ptr);
-    if (ptr is null) return parent.getForeground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getForeground ();
 }
 
 /**
@@ -434,14 +494,7 @@
 public Color getForeground (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.columnCount);
-    if (0 > index || index > count - 1) return getForeground ();
-    void* ptr;
-    int modelIndex =  parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_FOREGROUND, &ptr);
-    if (ptr is null) return getForeground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getForeground (index);
 }
 
 /**
@@ -484,16 +537,7 @@
 public Image getImage (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.getColumnCount ());
-    if (0 > index || index > count - 1) return null;
-    void* ptr;
-    int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_PIXBUF, &ptr);
-    if (ptr is null) return null;
-    ImageList imageList = parent.imageList;
-    int imageIndex = imageList.indexOf (ptr);
-    if (imageIndex is -1) return null;
-    return imageList.get (imageIndex);
+    return _getImage (index);
 }
 
 /**
@@ -528,7 +572,7 @@
     OS.gtk_widget_realize (parentHandle);
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
     OS.gtk_tree_path_free (path);
-
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
     /*
     * The OS call gtk_cell_renderer_get_size() provides the width of image to be drawn
     * by the cell renderer.  If there is no image in the cell, the width is zero.  If the table contains
@@ -549,7 +593,8 @@
         OS.gtk_cell_renderer_get_size (pixbufRenderer, parentHandle, null, null, null, &w, null);
         rect.width = w;
     }
-    return new Rectangle (rect.x, rect.y, rect.width, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 /**
@@ -612,15 +657,7 @@
 public String getText (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.getColumnCount ());
-    if (0 > index || index > count - 1) return "";
-    char* ptr;
-    int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_TEXT, cast(void**) &ptr);
-    if (ptr is null) return "";
-    String res = tango.stdc.stringz.fromStringz( ptr ).dup;
-    OS.g_free (ptr);
-    return res;
+    return _getText (index);
 }
 
 /**
@@ -668,6 +705,7 @@
     GdkRectangle rect;
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
     OS.gtk_tree_path_free (path);
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
     int right = rect.x + rect.width;
 
     int x, w;
@@ -699,7 +737,8 @@
             rect.width = Math.max (0, right - rect.x);
         }
     }
-    return new Rectangle (rect.x, rect.y, rect.width + 1, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 void redraw () {
@@ -753,6 +792,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getBackground ().opEquals (color)) return;
     GdkColor* gdkColor = color !is null ? color.handle : null;
     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.BACKGROUND_COLUMN, gdkColor);
     /*
@@ -791,6 +831,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getBackground (index).opEquals (color)) return;
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
@@ -848,6 +889,7 @@
 public void setChecked (bool checked) {
     checkWidget();
     if ((parent.style & DWT.CHECK) is 0) return;
+    if (_getChecked () is checked) return;
     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.CHECKED_COLUMN, cast(void*)cast(int)checked);
     /*
     * GTK+'s "inconsistent" state does not match DWT's concept of grayed.  To
@@ -880,9 +922,10 @@
     if (font !is null && font.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
-    if (this.font is font) return;
-    if (this.font !is null && this.font ==/*eq*/font ) return;
+    Font oldFont = this.font;
+    if (oldFont is font) return;
     this.font = font;
+    if (oldFont !is null && oldFont.opEquals (font)) return;
     auto fontHandle = font !is null ? font.handle : null;
     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.FONT_COLUMN, fontHandle);
     /*
@@ -925,11 +968,13 @@
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     if (cellFont is null) {
+        if (font is null) return;
         cellFont = new Font [count];
     }
-    if (cellFont [index] is font) return;
-    if (cellFont [index] !is null && cellFont [index] ==/*eq*/ font) return;
+    Font oldFont = cellFont [index];
+    if (oldFont is font) return;
     cellFont [index] = font;
+    if (oldFont !is null && oldFont.opEquals (font)) return;
 
     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
     auto fontHandle  = font !is null ? font.handle : null;
@@ -994,6 +1039,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getForeground ().opEquals (color)) return;
     GdkColor* gdkColor = color !is null ? color.handle : null;
     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.FOREGROUND_COLUMN, gdkColor);
     /*
@@ -1032,6 +1078,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getForeground (index).opEquals (color)) return;
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
@@ -1089,6 +1136,7 @@
 public void setGrayed (bool grayed) {
     checkWidget();
     if ((parent.style & DWT.CHECK) is 0) return;
+    if (this.grayed is grayed) return;
     this.grayed = grayed;
     /*
     * GTK+'s "inconsistent" state does not match DWT's concept of grayed.
@@ -1119,6 +1167,9 @@
     if (image !is null && image.isDisposed ()) {
         error(DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (image !is null && image.type is DWT.ICON) {
+        if (image.opEquals (_getImage (index))) return;
+    }
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     void* pixbuf;
@@ -1161,7 +1212,7 @@
                     * the style.
                     */
                     auto style = OS.gtk_widget_get_modifier_style (parentHandle);
-                    OS.gtk_widget_modify_style (parentHandle, style);
+                    parent.modifyStyle (parentHandle, style);
                 }
             }
         }
@@ -1233,6 +1284,7 @@
 public void setText (int index, String string) {
     checkWidget ();
     if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (_getText (index).equals (string)) return;
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     char* buffer = tango.stdc.stringz.toStringz( string );
--- a/dwt/widgets/Text.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Text.d	Mon May 12 19:13:01 2008 +0200
@@ -177,7 +177,7 @@
         OS.gtk_container_add (cast(GtkContainer*)fixedHandle, scrolledHandle);
         OS.gtk_container_add (cast(GtkContainer*)scrolledHandle, handle);
         OS.gtk_text_view_set_editable (cast(GtkTextView*)handle, (style & DWT.READ_ONLY) is 0);
-        if ((style & DWT.WRAP) !is 0) OS.gtk_text_view_set_wrap_mode (cast(GtkTextView*)handle, OS.GTK_WRAP_WORD);
+        if ((style & DWT.WRAP) !is 0) OS.gtk_text_view_set_wrap_mode (cast(GtkTextView*)handle, OS.GTK_WRAP_WORD_CHAR);
         int hsp = (style & DWT.H_SCROLL) !is 0 ? OS.GTK_POLICY_ALWAYS : OS.GTK_POLICY_NEVER;
         int vsp = (style & DWT.V_SCROLL) !is 0 ? OS.GTK_POLICY_ALWAYS : OS.GTK_POLICY_NEVER;
         OS.gtk_scrolled_window_set_policy (cast(GtkScrolledWindow*)scrolledHandle, hsp, vsp);
@@ -1323,6 +1323,14 @@
     return result;
 }
 
+override int /*long*/ gtk_populate_popup (GtkWidget* widget, GtkWidget* menu) {
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) {
+        OS.gtk_widget_set_direction (menu, OS.GTK_TEXT_DIR_RTL);
+        display.doSetDirectionProc (menu, OS.GTK_TEXT_DIR_RTL);
+    }
+    return 0;
+}
+
 override int /*long*/ gtk_text_buffer_insert_text (GtkTextBuffer *widget, GtkTextIter *iter, char *text, int len) {
     if (!hooks (DWT.Verify) && !filters (DWT.Verify)) return 0;
     GtkTextIter position = *iter;
@@ -1356,10 +1364,12 @@
         OS.g_signal_connect_closure (handle, OS.delete_text.ptr, display.closures [DELETE_TEXT], false);
         OS.g_signal_connect_closure (handle, OS.activate.ptr, display.closures [ACTIVATE], false);
         OS.g_signal_connect_closure (handle, OS.grab_focus.ptr, display.closures [GRAB_FOCUS], false);
+        OS.g_signal_connect_closure (handle, OS.populate_popup.ptr, display.closures [POPULATE_POPUP], false);
     } else {
         OS.g_signal_connect_closure (bufferHandle, OS.changed.ptr, display.closures [CHANGED], false);
         OS.g_signal_connect_closure (bufferHandle, OS.insert_text.ptr, display.closures [TEXT_BUFFER_INSERT_TEXT], false);
         OS.g_signal_connect_closure (bufferHandle, OS.delete_range.ptr, display.closures [DELETE_RANGE], false);
+        OS.g_signal_connect_closure (handle, OS.populate_popup.ptr, display.closures [POPULATE_POPUP], false);
     }
     auto imContext = imContext ();
     if (imContext !is null) {
@@ -1371,7 +1381,10 @@
 }
 
 GtkIMContext* imContext () {
-    return (style & DWT.SINGLE) !is 0 ? OS.GTK_ENTRY_IM_CONTEXT (cast(GtkEntry*)handle) : OS.GTK_TEXTVIEW_IM_CONTEXT (cast(GtkTextView*)handle);
+    if ((style & DWT.SINGLE) !is 0) {
+        return OS.gtk_editable_get_editable (handle) ? OS.GTK_ENTRY_IM_CONTEXT (handle) : null;
+    }
+    return OS.GTK_TEXTVIEW_IM_CONTEXT (cast(GtkTextView*)handle);
 }
 
 /**
--- a/dwt/widgets/ToolBar.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/ToolBar.d	Mon May 12 19:13:01 2008 +0200
@@ -333,6 +333,7 @@
                     auto topHandle = item.topHandle ();
                     event.x = OS.GTK_WIDGET_X (topHandle);
                     event.y = OS.GTK_WIDGET_Y (topHandle) + OS.GTK_WIDGET_HEIGHT (topHandle);
+                    if ((style & DWT.MIRRORED) !is 0) event.x = getClientWidth() - OS.GTK_WIDGET_WIDTH(topHandle) - event.x;
                     item.postEvent (DWT.Selection, event);
                     return result;
                 }
@@ -342,6 +343,7 @@
         case OS.GDK_Right: next = true; break;
         default: return result;
     }
+    if ((style & DWT.MIRRORED) !is 0) next= !next;
     int start = index, offset = next ? 1 : -1;
     while ((index = (index + offset + length) % length) !is start) {
         ToolItem item = items [index];
--- a/dwt/widgets/ToolItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/ToolItem.d	Mon May 12 19:13:01 2008 +0200
@@ -339,6 +339,8 @@
         width = OS.GTK_WIDGET_WIDTH (topHandle);
         height = OS.GTK_WIDGET_HEIGHT (topHandle);
     }
+    if ((parent.style & DWT.MIRRORED) !is 0) x = parent.getClientWidth () - width - x;
+    if ((style & DWT.SEPARATOR) !is 0 && control !is null) height = Math.max (height, 23);
     return new Rectangle (x, y, width, height);
 }
 
@@ -525,11 +527,12 @@
                     OS.gdk_event_get_coords (eventPtr, &x_win, &y_win);
                     int x = OS.GTK_WIDGET_X (arrowHandle) - OS.GTK_WIDGET_X (handle);
                     int width = OS.GTK_WIDGET_WIDTH (arrowHandle);
-                    if ((((state & DWT.RIGHT_TO_LEFT) is 0) && x <= cast(int)x_win)
-                        || (((state & DWT.RIGHT_TO_LEFT) !is 0) && cast(int)x_win <= x + width)) {
+                    if ((((parent.style & DWT.RIGHT_TO_LEFT) is 0) && x <= cast(int)x_win)
+                        || (((parent.style & DWT.RIGHT_TO_LEFT) !is 0) && cast(int)x_win <= x + width)) {
                         event.detail = DWT.ARROW;
                         auto topHandle = topHandle ();
                         event.x = OS.GTK_WIDGET_X (topHandle);
+                        if ((parent.style & DWT.MIRRORED) !is 0) event.x = parent.getClientWidth () - OS.GTK_WIDGET_WIDTH (topHandle) - event.x;
                         event.y = OS.GTK_WIDGET_Y (topHandle) + OS.GTK_WIDGET_HEIGHT (topHandle);
                     }
                     break;
@@ -725,6 +728,7 @@
         */
         Rectangle itemRect = getBounds ();
         control.setSize (itemRect.width, itemRect.height);
+        OS.gtk_widget_set_size_request (handle, itemRect.width, itemRect.height);
         Rectangle rect = control.getBounds ();
         rect.x = itemRect.x + (itemRect.width - rect.width) / 2;
         rect.y = itemRect.y + (itemRect.height - rect.height) / 2;
@@ -1034,7 +1038,9 @@
     checkWidget();
     if ((style & DWT.SEPARATOR) is 0) return;
     if (width < 0) return;
-    OS.gtk_widget_set_size_request (handle, width, -1);
+    bool isVertical = (parent.style & DWT.VERTICAL) !is 0;
+    OS.gtk_widget_set_size_request (separatorHandle, width, isVertical ? 6 : 15);
+    OS.gtk_widget_set_size_request (handle, width, isVertical ? 6 : 15);
     parent.relayout ();
 }
 
--- a/dwt/widgets/ToolTip.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/ToolTip.d	Mon May 12 19:13:01 2008 +0200
@@ -173,6 +173,14 @@
                 w-1, h-6+t, w-2, h-5+t, w-2, h-4+t, w-4, h-2+t, w-5, h-2+t, w-6, h-1+t,
                 5, h-1+t, 4, h-2+t, 3, h-2+t, 1, h-4+t, 1, h-5+t, 0, h-6+t,
                 0, 5+t];
+            if ((parent.style & DWT.MIRRORED) !is 0) {
+                x -= w - 36;
+                polyline[12] = w-36; 
+                polyline[14] = w-16; 
+                polyline[16] = w-15; 
+                borderPolygon[12] = w-35;
+                borderPolygon[14] = borderPolygon[16]  = w-16;
+            }
             OS.gtk_window_move (cast(GtkWindow*)handle, Math.max(0, x - 17), y);
         } else {
             polyline = [
@@ -189,6 +197,13 @@
                 35, h-1, 17, h+TIP_HEIGHT-2, 17, h-1,
                 5, h-1, 4, h-2, 3, h-2, 1, h-4, 1, h-5, 0, h-6,
                 0, 5];
+            if ((parent.style & DWT.MIRRORED) !is 0) {
+                x -= w - 36;
+                polyline [42] =  polyline [44] =  w-16;
+                polyline [46] = w-35;
+                borderPolygon[36] = borderPolygon[38] = w-17;
+                borderPolygon [40] = w-35;
+            }
             OS.gtk_window_move (cast(GtkWindow*)handle, Math.max(0, x - 17), y - h - TIP_HEIGHT);
         }
     } else {
@@ -208,6 +223,13 @@
                 w-1, h-6+t, w-2, h-5+t, w-2, h-4+t, w-4, h-2+t, w-5, h-2+t, w-6, h-1+t,
                 5, h-1+t, 4, h-2+t, 3, h-2+t, 1, h-4+t, 1, h-5+t, 0, h-6+t,
                 0, 5+t];
+            if ((parent.style & DWT.MIRRORED) !is 0) {
+                x += w - 35;
+                polyline [12] = polyline [14] = 16;
+                polyline [16] = 35;
+                borderPolygon[12] =  borderPolygon[14] = 16;
+                borderPolygon [16] = 35;
+            }
             OS.gtk_window_move (cast(GtkWindow*)handle, Math.min(dest.width - w, x - w + 17), y);
         } else {
             polyline = [
@@ -224,6 +246,13 @@
                 w-17, h-1, w-17, h+TIP_HEIGHT-2, w-36, h-1,
                 5, h-1, 4, h-2, 3, h-2, 1, h-4, 1, h-5, 0, h-6,
                 0, 5];
+            if ((parent.style & DWT.MIRRORED) !is 0) {
+                x += w - 35;
+                polyline [42] =  35;
+                polyline [44] = polyline [46] = 16;
+                borderPolygon[36] = 35;
+                borderPolygon[38] = borderPolygon [40] = 17;
+            }
             OS.gtk_window_move (cast(GtkWindow*)handle, Math.min(dest.width - w, x - w + 17), y - h - TIP_HEIGHT);
         }
     }
--- a/dwt/widgets/Tracker.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Tracker.d	Mon May 12 19:13:01 2008 +0200
@@ -52,7 +52,8 @@
  */
 public class Tracker : Widget {
     Composite parent;
-    GdkCursor* cursor, lastCursor;
+    Cursor cursor;
+    GdkCursor* lastCursor;
     GdkDrawable* window;
     bool tracking, cancelled, grabbed, stippled;
     Rectangle [] rectangles, proportions;
@@ -330,7 +331,9 @@
     OS.gdk_gc_set_function (gc, OS.GDK_XOR);
     for (int i=0; i<rects.length; i++) {
         Rectangle rect = rects [i];
-        OS.gdk_draw_rectangle (window, gc, 0, rect.x, rect.y, rect.width, rect.height);
+        int x = rect.x;
+        if (parent !is null && (parent.style & DWT.MIRRORED) !is 0) x = parent.getClientWidth () - rect.width - x;
+        OS.gdk_draw_rectangle (window, gc, 0, x, rect.y, rect.width, rect.height);
     }
     OS.g_object_unref (gc);
 }
@@ -373,6 +376,7 @@
 }
 
 bool grab () {
+    auto cursor = this.cursor !is null ? this.cursor.handle : null;
     int result = OS.gdk_pointer_grab (window, false, OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_RELEASE_MASK, window, cursor, OS.GDK_CURRENT_TIME);
     return result is OS.GDK_GRAB_SUCCESS;
 }
@@ -417,6 +421,9 @@
         Event event = new Event ();
         event.x = oldX + xChange;
         event.y = oldY + yChange;
+        if (parent !is null && (parent.style & DWT.MIRRORED) !is 0) {
+            event.x = parent.getClientWidth () - event.width - event.x;
+        }
         if ((style & DWT.RESIZE) !is 0) {
             resizeRectangles (xChange, yChange);
             sendEvent (DWT.Resize, event);
@@ -513,6 +520,7 @@
 }
 
 override int gtk_motion_notify_event (GtkWidget* widget, GdkEventMotion* eventPtr) {
+    auto cursor = this.cursor !is null ? this.cursor.handle : null;
     if (cursor !is lastCursor) {
         ungrab ();
         grabbed = grab ();
@@ -640,6 +648,7 @@
     if (yChange < 0 && ((style & DWT.UP) is 0)) yChange = 0;
     if (yChange > 0 && ((style & DWT.DOWN) is 0)) yChange = 0;
     if (xChange is 0 && yChange is 0) return;
+    if (parent !is null && (parent.style & DWT.MIRRORED) !is 0) xChange *= -1;
     bounds.x += xChange; bounds.y += yChange;
     for (int i = 0; i < rectangles.length; i++) {
         rectangles [i].x += xChange;
@@ -704,7 +713,7 @@
     this.oldY = oldY ;
 
     grabbed = grab ();
-    lastCursor = cursor;
+    lastCursor = this.cursor !is null ? this.cursor.handle : null;
 
     /* Tracker behaves like a Dialog with its own OS event loop. */
     GdkEvent* gdkEvent;
@@ -812,6 +821,7 @@
 
 void resizeRectangles (int xChange, int yChange) {
     if (bounds is null) return;
+    if (parent !is null && (parent.style & DWT.MIRRORED) !is 0) xChange *= -1;
     /*
     * If the cursor orientation has not been set in the orientation of
     * this change then try to set it here.
@@ -935,8 +945,7 @@
  */
 public void setCursor (Cursor value) {
     checkWidget ();
-    cursor = null;
-    if (value !is null) cursor = value.handle;
+    cursor = value;
 }
 
 /**
--- a/dwt/widgets/Tree.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Tree.d	Mon May 12 19:13:01 2008 +0200
@@ -227,11 +227,17 @@
 
 static int checkStyle (int style) {
     /*
-    * To be compatible with Windows, force the H_SCROLL
-    * and V_SCROLL style bits.  On Windows, it is not
-    * possible to create a tree without scroll bars.
+    * Feature in Windows.  Even when WS_HSCROLL or
+    * WS_VSCROLL is not specified, Windows creates
+    * trees and tables with scroll bars.  The fix
+    * is to set H_SCROLL and V_SCROLL.
+    *
+    * NOTE: This code appears on all platforms so that
+    * applications have consistent scroll bar behavior.
     */
-    style |= DWT.H_SCROLL | DWT.V_SCROLL;
+    if ((style & DWT.NO_SCROLL) is 0) {
+        style |= DWT.H_SCROLL | DWT.V_SCROLL;
+    }
     /* GTK is always FULL_SELECTION */
     style |= DWT.FULL_SELECTION;
     return checkBits (style, DWT.SINGLE, DWT.MULTI, 0, 0, 0, 0);
@@ -429,7 +435,7 @@
     addListener (DWT.Collapse, typedListener);
 }
 
-int calculateWidth (GtkTreeViewColumn *column, GtkTreeIter* iter) {
+int calculateWidth (GtkTreeViewColumn *column, GtkTreeIter* iter, bool recurse) {
     OS.gtk_tree_view_column_cell_set_cell_data (column, modelHandle, iter, false, false);
     /*
     * Bug in GTK.  The width calculated by gtk_tree_view_column_cell_get_size()
@@ -443,7 +449,16 @@
 
     int width = 0;
     int w;
+    GtkTreePath* path = null;
+
     if (OS.gtk_tree_view_get_expander_column (handle) is column) {
+        /* indent */
+        GdkRectangle rect;
+        OS.gtk_widget_realize (handle);
+        path = OS.gtk_tree_model_get_path (modelHandle, iter);
+        OS.gtk_tree_view_get_cell_area (handle, path, column, &rect);
+        width += rect.x;
+        /* expander */
         OS.gtk_widget_style_get1 (handle, OS.expander_size.ptr, &w);
         width += w  + TreeItem.EXPANDER_EXTRA_PADDING;
     }
@@ -461,6 +476,21 @@
         temp = OS.g_list_next (temp);
     }
     OS.g_list_free (list);
+
+    if (recurse) {
+        if (path is null) path = OS.gtk_tree_model_get_path (modelHandle, iter);
+        bool expanded = OS.gtk_tree_view_row_expanded (handle, path) !is 0;
+        if (expanded) {
+            GtkTreeIter childIter;
+            bool valid = OS.gtk_tree_model_iter_children (modelHandle, &childIter, iter) !is 0;
+            while (valid) {
+                width = Math.max (width, calculateWidth (column, &childIter, true));
+                valid = OS.gtk_tree_model_iter_next (modelHandle, &childIter) !is 0;
+            }
+        }
+    }
+
+    if (path !is null) OS.gtk_tree_path_free (path);
     return width;
 }
 
@@ -939,6 +969,18 @@
     if (checkRenderer !is null) display.removeWidget (cast(GtkWidget*)checkRenderer);
 }
 
+public void deselect (TreeItem item) {
+    checkWidget ();
+    if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (item.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT);
+    bool fixColumn = showFirstColumn ();
+    auto selection = OS.gtk_tree_view_get_selection (handle);
+    OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+    OS.gtk_tree_selection_unselect_iter (selection, item.handle);
+    OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+    if (fixColumn) hideFirstColumn ();
+}
+
 /**
  * Deselects all selected items in the receiver.
  *
@@ -1124,6 +1166,13 @@
     return new Rectangle (fixedX  - binX , fixedY  - binY , width, height);
 }
 
+int getClientWidth () {
+    int w, h;
+    OS.gtk_widget_realize (handle);
+    OS.gdk_drawable_get_size(OS.gtk_tree_view_get_bin_window(handle), &w, &h);
+    return w;
+}
+
 /**
  * Returns the column at the given, zero-relative index in the
  * receiver. Throws an exception if the index is out of range.
@@ -2303,37 +2352,9 @@
         if (item !is null && !item.isDisposed ()) item.release (false);
     }
     items = new TreeItem[4];
-    /*
-    * Bug in GTK.  In version 2.3.2, when the property fixed-height-mode
-    * is set and there are items in the list, OS.gtk_tree_store_clear()
-    * segment faults.  The fix is to create a new empty model instead.
-    */
     auto selection = OS.gtk_tree_view_get_selection (handle);
     OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
-    /*
-    * Bug in GTK.  In version 2.8, when gtk_tree_view_set_model() is called, GTK
-    * does not remove the timer used to show animation when expanding a node. This
-    * can cause two possible crashes. The first one happens when the timer expires and
-    * it accesses the expanding node which has been already destroyed. The second one
-    * happens if a new item is created and destroyed before the timer expires. The fix
-    * is to remove the timer by disposing the first item in the tree.
-    */
-    if (OS.GTK_VERSION < OS.buildVERSION(2, 10, 0)) {
-        if (OS.gtk_tree_model_iter_n_children (modelHandle, null) !is 0) {
-            GtkTreeIter iter;
-            OS.gtk_tree_model_iter_nth_child (modelHandle, &iter, null, 0);
-            OS.gtk_tree_store_remove (modelHandle, &iter);
-        }
-    }
-    // TODO verify if true for tree store
-    //OS.gtk_tree_store_clear (modelHandle);
-    auto oldModel = modelHandle;
-    uint[] types = getColumnTypes (Math.max (1,columnCount));
-    auto newModel = OS.gtk_tree_store_newv (types.length, types.ptr);
-    if (newModel is null) error (DWT.ERROR_NO_HANDLES);
-    OS.gtk_tree_view_set_model (handle, newModel);
-    OS.g_object_unref (oldModel);
-    modelHandle = newModel;
+    OS.gtk_tree_store_clear (modelHandle);
     OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
 
     /* Disable searching when using VIRTUAL */
@@ -2458,7 +2479,7 @@
                 sendEvent (DWT.MeasureItem, event);
                 gc.dispose ();
                 contentWidth  = event.width - imageWidth;
-                contentHeight  = event.height;
+                if (contentHeight < event.height) contentHeight = event.height;
                 if (width !is null) *width = contentWidth;
                 if (height !is null) *height = contentHeight;
             }
@@ -2529,6 +2550,7 @@
                     gc.setForeground (item.getForeground (columnIndex));
                 }
                 gc.setFont (item.getFont (columnIndex));
+                if ((style & DWT.MIRRORED) !is 0) rect.x = getClientWidth () - rect.width - rect.x;
                 gc.setClipping (rect.x, rect.y, rect.width, rect.height);
                 Event event = new Event ();
                 event.item = item;
@@ -2610,6 +2632,7 @@
                     gc.setForeground (foreground);
                 }
                 gc.setFont (item.getFont (columnIndex));
+                if ((style & DWT.MIRRORED) !is 0) rect.x = getClientWidth () - rect.width - rect.x;
                 gc.setClipping (rect.x, rect.y, rect.width, rect.height);
                 Event event = new Event ();
                 event.item = item;
@@ -2663,7 +2686,7 @@
 public void setInsertMark (TreeItem item, bool before) {
     checkWidget ();
     if (item is null) {
-        OS.gtk_tree_view_unset_rows_drag_dest(handle);
+        OS.gtk_tree_view_set_drag_dest_row(handle, null, OS.GTK_TREE_VIEW_DROP_BEFORE);
         return;
     }
     if (item.isDisposed()) error (DWT.ERROR_INVALID_ARGUMENT);
@@ -2716,6 +2739,19 @@
     count = Math.max (0, count);
     setItemCount (null, count);
 }
+
+public void select (TreeItem item) {
+    checkWidget ();
+    if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (item.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT);
+    bool fixColumn = showFirstColumn ();
+    auto selection = OS.gtk_tree_view_get_selection (handle);
+    OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+    OS.gtk_tree_selection_select_iter (selection, item.handle);
+    OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
+    if (fixColumn) hideFirstColumn ();
+}
+
 /**
  * Selects all of the items in the receiver.
  * <p>
@@ -2893,7 +2929,7 @@
     */
     if (((style & DWT.VIRTUAL) !is 0) && OS.GTK_VERSION < OS.buildVERSION (2, 3, 2)) return;
     int width = OS.gtk_tree_view_column_get_fixed_width (column);
-    int itemWidth = calculateWidth (column, cast(GtkTreeIter*)item.handle);
+    int itemWidth = calculateWidth (column, cast(GtkTreeIter*)item.handle, true);
     if (width < itemWidth) {
         OS.gtk_tree_view_column_set_fixed_width (column, itemWidth);
     }
--- a/dwt/widgets/TreeColumn.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/TreeColumn.d	Mon May 12 19:13:01 2008 +0200
@@ -202,6 +202,7 @@
 
 void createWidget (int index) {
     parent.createItem (this, index);
+    setOrientation ();
     hookEvents ();
     register ();
     text = "";
@@ -426,7 +427,7 @@
         GtkTreeIter iter;
         if (OS.gtk_tree_model_get_iter_first (parent.modelHandle, &iter)) {
             do {
-                width = Math.max (width, parent.calculateWidth (cast(GtkTreeViewColumn*)handle, &iter));
+                width = Math.max (width, parent.calculateWidth (cast(GtkTreeViewColumn*)handle, &iter, true));
             } while (OS.gtk_tree_model_iter_next(parent.modelHandle, &iter));
         }
     }
@@ -576,6 +577,15 @@
     OS.gtk_tree_view_column_set_reorderable (handle, moveable);
 }
 
+void setOrientation() {
+    if ((parent.style & DWT.RIGHT_TO_LEFT) !is 0) {
+        if (buttonHandle !is null) {
+            OS.gtk_widget_set_direction (buttonHandle, OS.GTK_TEXT_DIR_RTL);
+            display.doSetDirectionProc(buttonHandle, OS.GTK_TEXT_DIR_RTL);
+        }
+    }
+}
+
 /**
  * Sets the resizable attribute.  A column that is
  * not resizable cannot be dragged by the user but
--- a/dwt/widgets/TreeItem.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/TreeItem.d	Mon May 12 19:13:01 2008 +0200
@@ -221,6 +221,79 @@
     if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS);
 }
 
+Color _getBackground () {
+    void* ptr;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Tree.BACKGROUND_COLUMN, &ptr);
+    if (ptr is null) return parent.getBackground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+Color _getBackground (int index) {
+    int count = Math.max (1, parent.columnCount);
+    if (0 > index || index > count - 1) return _getBackground ();
+    void* ptr;
+    int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_BACKGROUND, &ptr);
+    if (ptr is null) return _getBackground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+bool _getChecked () {
+    void* ptr;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Tree.CHECKED_COLUMN, &ptr);
+    return ptr !is null;
+}
+
+Color _getForeground () {
+    void* ptr;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Tree.FOREGROUND_COLUMN, &ptr);
+    if (ptr is null) return parent.getForeground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+Color _getForeground (int index) {
+    int count = Math.max (1, parent.columnCount);
+    if (0 > index || index > count - 1) return _getForeground ();
+    void* ptr;
+    int modelIndex =  parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_FOREGROUND, &ptr);
+    if (ptr is null) return _getForeground ();
+    GdkColor* gdkColor = new GdkColor ();
+    *gdkColor = *cast(GdkColor*) ptr;
+    return Color.gtk_new (display, gdkColor);
+}
+
+Image _getImage (int index) {
+    int count = Math.max (1, parent.getColumnCount ());
+    if (0 > index || index > count - 1) return null;
+    void* ptr;
+    int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_PIXBUF, &ptr);
+    if (ptr is null) return null;
+    ImageList imageList = parent.imageList;
+    int imageIndex = imageList.indexOf (ptr);
+    if (imageIndex is -1) return null;
+    return imageList.get (imageIndex);
+}
+
+String _getText (int index) {
+    int count = Math.max (1, parent.getColumnCount ());
+    if (0 > index || index > count - 1) return "";
+    void* ptr;
+    int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
+    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_TEXT, &ptr);
+    if (ptr is null) return ""; //$NON-NLS-1$
+    char[] buffer = tango.stdc.stringz.fromStringz( cast(char*)ptr).dup;
+    OS.g_free (ptr);
+    return buffer;
+}
+
 void clear () {
     if (parent.currentItem is this) return;
     if (cached || (parent.style & DWT.VIRTUAL) is 0) {
@@ -318,11 +391,7 @@
 public Color getBackground () {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    void* ptr;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Tree.BACKGROUND_COLUMN, &ptr);
-    if (ptr is null) return parent.getBackground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getBackground ();
 }
 
 /**
@@ -341,14 +410,7 @@
 public Color getBackground (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.columnCount);
-    if (0 > index || index > count - 1) return getBackground ();
-    void* ptr;
-    int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_BACKGROUND, &ptr);
-    if (ptr is null) return getBackground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getBackground (index);
 }
 
 /**
@@ -381,7 +443,7 @@
     OS.gtk_widget_realize (parentHandle);
     GdkRectangle rect;
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
-    OS.gtk_tree_path_free (path);
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
 
     if (OS.GTK_VERSION < OS.buildVERSION (2, 8, 18) && OS.gtk_tree_view_get_expander_column (parentHandle) is column) {
         int buffer;
@@ -392,6 +454,18 @@
         rect.x += buffer;
         //rect.width -= buffer [0]; // TODO Is this required for some versions?
     }
+    /*
+    * Bug in GTK. In GTK 2.8.x, the cell area is left aligned even
+    * when the widget is mirrored. The fix is to sum up the indentation
+    * of the expanders.
+    */
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0 && (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0))) {
+        int depth = OS.gtk_tree_path_get_depth (path);
+        int  expanderSize;
+        OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &expanderSize);
+        rect.x += depth * (expanderSize + TreeItem.EXPANDER_EXTRA_PADDING);
+    }
+    OS.gtk_tree_path_free (path);
 
     if (index is 0 && (parent.style & DWT.CHECK) !is 0) {
         if (OS.GTK_VERSION >= OS.buildVERSION (2, 1, 3)) {
@@ -408,7 +482,8 @@
             rect.width -= w  + buffer;
         }
     }
-    return new Rectangle (rect.x, rect.y, rect.width + 1, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 /**
@@ -443,7 +518,7 @@
 
     GdkRectangle rect;
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
-    OS.gtk_tree_path_free (path);
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
     int right = rect.x + rect.width;
 
     int x, w;
@@ -456,6 +531,19 @@
         OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &buffer);
         rect.x += buffer + TreeItem.EXPANDER_EXTRA_PADDING;
     }
+    /*
+    * Bug in GTK. In GTK 2.8.x, the cell area is left aligned even
+    * when the widget is mirrored. The fix is to sum up the indentation
+    * of the expanders.
+    */
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0 && (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0))) {
+        int depth = OS.gtk_tree_path_get_depth (path);
+        int expanderSize;
+        OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &expanderSize);
+        rect.x += depth * (expanderSize + TreeItem.EXPANDER_EXTRA_PADDING);
+    }
+    OS.gtk_tree_path_free (path);
+
     OS.gtk_widget_style_get1 (parentHandle, OS.horizontal_separator.ptr, &buffer);
     int horizontalSeparator = buffer;
     rect.x += horizontalSeparator;
@@ -476,7 +564,8 @@
             rect.width = Math.max (0, right - rect.x);
         }
     }
-    return new Rectangle (rect.x, rect.y, rect.width + 1, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 /**
@@ -496,9 +585,7 @@
     checkWidget();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
     if ((parent.style & DWT.CHECK) is 0) return false;
-    void* ptr;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Tree.CHECKED_COLUMN, &ptr);
-    return ptr !is null;
+    return _getChecked ();
 }
 
 /**
@@ -579,11 +666,7 @@
 public Color getForeground () {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    void* ptr;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, Tree.FOREGROUND_COLUMN, &ptr);
-    if (ptr is null) return parent.getForeground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getForeground ();
 }
 
 /**
@@ -603,14 +686,7 @@
 public Color getForeground (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.columnCount);
-    if (0 > index || index > count - 1) return getForeground ();
-    void* ptr;
-    int modelIndex =  parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_FOREGROUND, &ptr);
-    if (ptr is null) return getForeground ();
-    GdkColor* gdkColor = cast(GdkColor*)ptr;
-    return Color.gtk_new (display, gdkColor);
+    return _getForeground (index);
 }
 
 /**
@@ -656,16 +732,7 @@
 public Image getImage (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.getColumnCount ());
-    if (0 > index || index > count - 1) return null;
-    void* ptr;
-    int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_PIXBUF, &ptr);
-    if (ptr is null) return null;
-    ImageList imageList = parent.imageList;
-    int imageIndex = imageList.indexOf (ptr);
-    if (imageIndex is -1) return null;
-    return imageList.get (imageIndex);
+    return _getImage (index);
 }
 
 /**
@@ -701,8 +768,7 @@
     auto path = OS.gtk_tree_model_get_path (parent.modelHandle, handle);
     OS.gtk_widget_realize (parentHandle);
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
-    OS.gtk_tree_path_free (path);
-
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
     if (OS.GTK_VERSION < OS.buildVERSION (2, 8, 18) && OS.gtk_tree_view_get_expander_column (parentHandle) is column) {
         int buffer;
         OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &buffer);
@@ -712,6 +778,18 @@
         //int horizontalSeparator = buffer[0];
         //rect.x += horizontalSeparator;
     }
+    /*
+    * Bug in GTK. In GTK 2.8.x, the cell area is left aligned even
+    * when the widget is mirrored. The fix is to sum up the indentation
+    * of the expanders.
+    */
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0 && (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0))) {
+        int depth = OS.gtk_tree_path_get_depth (path);
+        int expanderSize;
+        OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &expanderSize);
+        rect.x += depth * (expanderSize + TreeItem.EXPANDER_EXTRA_PADDING);
+    }
+    OS.gtk_tree_path_free (path);
 
     /*
     * The OS call gtk_cell_renderer_get_size() provides the width of image to be drawn
@@ -733,7 +811,8 @@
         OS.gtk_cell_renderer_get_size (pixbufRenderer, parentHandle, null, null, null, &w, null);
         rect.width = w;
     }
-    return new Rectangle (rect.x, rect.y, rect.width, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 /**
@@ -874,15 +953,7 @@
 public String getText (int index) {
     checkWidget ();
     if (!parent.checkData (this)) error (DWT.ERROR_WIDGET_DISPOSED);
-    int count = Math.max (1, parent.getColumnCount ());
-    if (0 > index || index > count - 1) return "";
-    void* ptr;
-    int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
-    OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Tree.CELL_TEXT, &ptr);
-    if (ptr is null) return ""; //$NON-NLS-1$
-    String res = tango.stdc.stringz.fromStringz( cast(char*)ptr ).dup;
-    OS.g_free (ptr);
-    return res;
+    return _getText (index);
 }
 
 /**
@@ -928,7 +999,7 @@
 
     GdkRectangle rect;
     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
-    OS.gtk_tree_path_free (path);
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
     int right = rect.x + rect.width;
 
     int x, w;
@@ -940,6 +1011,19 @@
         OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &buffer);
         rect.x += buffer + TreeItem.EXPANDER_EXTRA_PADDING;
     }
+    /*
+    * Bug in GTK. In GTK 2.8.x, the cell area is left aligned even
+    * when the widget is mirrored. The fix is to sum up the indentation
+    * of the expanders.
+    */
+    if ((parent.getStyle () & DWT.MIRRORED) !is 0 && (OS.GTK_VERSION < OS.buildVERSION (2, 10, 0))) {
+        int depth = OS.gtk_tree_path_get_depth (path);
+        int expanderSize;
+        OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &expanderSize);
+        rect.x += depth * (expanderSize + TreeItem.EXPANDER_EXTRA_PADDING);
+    }
+    OS.gtk_tree_path_free (path);
+
     OS.gtk_widget_style_get1 (parentHandle, OS.horizontal_separator.ptr, &buffer);
     int horizontalSeparator = buffer;
     rect.x += horizontalSeparator;
@@ -959,7 +1043,8 @@
             rect.width = Math.max (0, right - rect.x);
         }
     }
-    return new Rectangle (rect.x, rect.y, rect.width + 1, rect.height + 1);
+    int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+    return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
 /**
@@ -1095,6 +1180,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getBackground ().opEquals (color)) return;
     GdkColor* gdkColor = color !is null ? color.handle : null;
     OS.gtk_tree_store_set1 (parent.modelHandle, cast(GtkTreeIter*)handle, Tree.BACKGROUND_COLUMN, gdkColor);
     /*
@@ -1134,6 +1220,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getBackground (index).opEquals (color)) return;
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
@@ -1191,6 +1278,7 @@
 public void setChecked (bool checked) {
     checkWidget();
     if ((parent.style & DWT.CHECK) is 0) return;
+    if (_getChecked () is checked) return;
     OS.gtk_tree_store_set1 (parent.modelHandle, cast(GtkTreeIter*)handle, Tree.CHECKED_COLUMN, cast(void*)cast(int)checked);
     /*
     * GTK+'s "inconsistent" state does not match DWT's concept of grayed.  To
@@ -1252,10 +1340,11 @@
     if (font !is null && font.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
-    if (this.font is font) return;
-    if (this.font !is null && this.font ==/*eq*/font) return;
+    Font oldFont = this.font;
+    if (oldFont is font) return;
     this.font = font;
-    auto fontHandle = font !is null ? font.handle : null;
+    if (oldFont !is null && oldFont.opEquals (font)) return;
+    void* fontHandle = font !is null ? font.handle : null;
     OS.gtk_tree_store_set1 (parent.modelHandle, cast(GtkTreeIter*)handle, Tree.FONT_COLUMN, fontHandle);
     /*
     * Bug in GTK.  When using fixed-height-mode,
@@ -1297,11 +1386,13 @@
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     if (cellFont is null) {
+        if (font is null) return;
         cellFont = new Font [count];
     }
-    if (cellFont [index] is font) return;
-    if (cellFont [index] !is null && cellFont [index] ==/*eq*/font ) return;
+    Font oldFont = cellFont [index];
+    if (oldFont is font) return;
     cellFont [index] = font;
+    if (oldFont !is null && oldFont.opEquals (font)) return;
 
     int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
     auto fontHandle  = font !is null ? font.handle : null;
@@ -1369,6 +1460,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getForeground ().opEquals (color)) return;
     GdkColor *gdkColor = color !is null ? color.handle : null;
     OS.gtk_tree_store_set1 (parent.modelHandle, cast(GtkTreeIter*)handle, Tree.FOREGROUND_COLUMN, gdkColor);
     /*
@@ -1408,6 +1500,7 @@
     if (color !is null && color.isDisposed ()) {
         DWT.error (DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (_getForeground (index).opEquals (color)) return;
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     int modelIndex = parent.columnCount is 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
@@ -1465,6 +1558,7 @@
 public void setGrayed (bool grayed) {
     checkWidget();
     if ((parent.style & DWT.CHECK) is 0) return;
+    if (this.grayed is grayed) return;
     this.grayed = grayed;
     /*
     * GTK+'s "inconsistent" state does not match DWT's concept of grayed.
@@ -1497,6 +1591,9 @@
     if (image !is null && image.isDisposed()) {
         error(DWT.ERROR_INVALID_ARGUMENT);
     }
+    if (image !is null && image.type is DWT.ICON) {
+        if (image.opEquals (_getImage (index))) return;
+    }
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     GdkPixbuf* pixbuf;
@@ -1541,7 +1638,7 @@
                      * the style.
                      */
                     auto style = OS.gtk_widget_get_modifier_style (parentHandle);
-                    OS.gtk_widget_modify_style (parentHandle, style);
+                    parent.modifyStyle (parentHandle, style);
                 }
             }
         }
@@ -1615,6 +1712,7 @@
 public void setText (int index, String string) {
     checkWidget ();
     if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
+    if (_getText (index).equals (string)) return;
     int count = Math.max (1, parent.getColumnCount ());
     if (0 > index || index > count - 1) return;
     char* buffer = tango.stdc.stringz.toStringz(string);
--- a/dwt/widgets/Widget.d	Mon May 12 15:36:37 2008 +0200
+++ b/dwt/widgets/Widget.d	Mon May 12 19:13:01 2008 +0200
@@ -152,32 +152,33 @@
     static const int MOTION_NOTIFY_EVENT_INVERSE = 34;
     static const int MOVE_FOCUS = 35;
     static const int OUTPUT = 36;
-    static const int POPUP_MENU = 37;
-    static const int PREEDIT_CHANGED = 38;
-    static const int REALIZE = 39;
-    static const int ROW_ACTIVATED = 40;
-    static const int SCROLL_CHILD = 41;
-    static const int SCROLL_EVENT = 42;
-    static const int SELECT = 43;
-    static const int SHOW = 44;
-    static const int SHOW_HELP = 45;
-    static const int SIZE_ALLOCATE = 46;
-    static const int STYLE_SET = 47;
-    static const int SWITCH_PAGE = 48;
-    static const int TEST_COLLAPSE_ROW = 49;
-    static const int TEST_EXPAND_ROW = 50;
-    static const int TEXT_BUFFER_INSERT_TEXT = 51;
-    static const int TOGGLED = 52;
-    static const int UNMAP = 53;
-    static const int UNMAP_EVENT = 54;
-    static const int UNREALIZE = 55;
-    static const int VALUE_CHANGED = 56;
-    static const int VISIBILITY_NOTIFY_EVENT = 57;
-    static const int WINDOW_STATE_EVENT = 58;
-    static const int ACTIVATE_INVERSE = 59;
-    static const int DAY_SELECTED = 60;
-    static const int MONTH_CHANGED = 61;
-    static const int LAST_SIGNAL = 62;
+    static const int POPULATE_POPUP = 37;
+    static const int POPUP_MENU = 38;
+    static const int PREEDIT_CHANGED = 39;
+    static const int REALIZE = 40;
+    static const int ROW_ACTIVATED = 41;
+    static const int SCROLL_CHILD = 42;
+    static const int SCROLL_EVENT = 43;
+    static const int SELECT = 44;
+    static const int SHOW = 45;
+    static const int SHOW_HELP = 46;
+    static const int SIZE_ALLOCATE = 47;
+    static const int STYLE_SET = 48;
+    static const int SWITCH_PAGE = 49;
+    static const int TEST_COLLAPSE_ROW = 50;
+    static const int TEST_EXPAND_ROW = 51;
+    static const int TEXT_BUFFER_INSERT_TEXT = 52;
+    static const int TOGGLED = 53;
+    static const int UNMAP = 54;
+    static const int UNMAP_EVENT = 55;
+    static const int UNREALIZE = 56;
+    static const int VALUE_CHANGED = 57;
+    static const int VISIBILITY_NOTIFY_EVENT = 58;
+    static const int WINDOW_STATE_EVENT = 59;
+    static const int ACTIVATE_INVERSE = 60;
+    static const int DAY_SELECTED = 61;
+    static const int MONTH_CHANGED = 62;
+    static const int LAST_SIGNAL = 63;
 
     template UD_Getter( String name ){
         const String UD_Getter = "void* ud"~name~"(){ return getDisplay().getWindowProcUserData( "~name~"); }\n";
@@ -219,6 +220,7 @@
     mixin ( UD_Getter!( "MOTION_NOTIFY_EVENT_INVERSE" ));
     mixin ( UD_Getter!( "MOVE_FOCUS" ));
     mixin ( UD_Getter!( "OUTPUT" ));
+    mixin ( UD_Getter!( "POPULATE_POPUP" ));
     mixin ( UD_Getter!( "POPUP_MENU" ));
     mixin ( UD_Getter!( "PREEDIT_CHANGED" ));
     mixin ( UD_Getter!( "REALIZE" ));
@@ -385,6 +387,11 @@
         }
     }
     style = checkBits (style, DWT.LEFT_TO_RIGHT, DWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
+    /* Versions of GTK prior to 2.8 do not render RTL text properly */
+    if (OS.GTK_VERSION < OS.buildVERSION (2, 8, 0)) {
+        style &= ~DWT.RIGHT_TO_LEFT;
+        style |= DWT.LEFT_TO_RIGHT;
+    }
 }
 
 /**
@@ -612,6 +619,33 @@
     return display;
 }
 
+/**
+ * Returns an array of listeners who will be notified when an event
+ * of the given type occurs. The event type is one of the event constants
+ * defined in class <code>DWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @return an array of listeners that will be notified when the event occurs
+ *
+ * @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 Listener
+ * @see DWT
+ * @see #addListener(int, Listener)
+ * @see #removeListener(int, Listener)
+ * @see #notifyListeners
+ *
+ * @since 3.4
+ */
+public Listener[] getListeners (int eventType) {
+    checkWidget();
+    if (eventTable is null) return new Listener[0];
+    return eventTable.getListeners(eventType);
+}
+
 String getName () {
 //  String str = getClass ().getName ();
 //  int index = str.lastIndexOf ('.');
@@ -788,6 +822,10 @@
     return 0;
 }
 
+int /*long*/ gtk_populate_popup (GtkWidget* widget, GtkWidget* menu) {
+    return 0;
+}
+
 int /*long*/ gtk_popup_menu (GtkWidget* widget) {
     return 0;
 }
@@ -909,7 +947,15 @@
     return 0;
 }
 
+void fixedSizeAllocateProc(GtkWidget* widget, GtkAllocation* allocationPtr) {
+    return Display.oldFixedSizeAllocateProc(widget, allocationPtr);
+}
+
 char [] fixMnemonic (String str) {
+    return fixMnemonic (str, true);
+}
+
+char [] fixMnemonic (String str, bool replace) {
     int len = str.length;
     String text = str[0 .. len].dup;
     int i = 0, j = 0;
@@ -920,11 +966,15 @@
                 if (i + 1 < len && text [i + 1] is '&') {
                     i++;
                 } else {
-                    text [i] = '_';
+                    if (replace) {
+                        text [i] = '_';
+                    } else {
+                        i++;
+                    }
                 }
                 break;
             case '_':
-                result [j++] = '_';
+                if (replace) result [j++] = '_';
                 break;
             default:
         }
@@ -1019,6 +1069,10 @@
     return keyval1 is keyval2;
 }
 
+void modifyStyle (GtkWidget* handle, GtkRcStyle* style) {
+    OS.gtk_widget_modify_style (handle, style);
+}
+
 /**
  * Notifies all of the receiver's listeners for events
  * of the given type that one such event has occurred by
@@ -1258,7 +1312,7 @@
     return sendIMKeyEvent (type, keyEvent, chars) !is null;
 }
 
-char [] sendIMKeyEvent (int type, GdkEventKey* keyEvent, char  [] chars) {
+char [] sendIMKeyEvent (int type, GdkEventKey* keyEvent, char [] chars) {
     int index = 0, count = 0, state = 0;
     GdkEvent*  ptr = null;
     if (keyEvent is null) {
@@ -1453,7 +1507,7 @@
     flags = OS.gtk_rc_style_get_color_flags (style, OS.GTK_STATE_ACTIVE);
     flags = (color is null) ? flags & ~OS.GTK_RC_TEXT: flags | OS.GTK_RC_TEXT;
     OS.gtk_rc_style_set_color_flags (style, OS.GTK_STATE_ACTIVE, flags);
-    OS.gtk_widget_modify_style (handle, style);
+    modifyStyle (handle, style);
 }
 
 bool setInputState (Event event, int state) {
@@ -1661,6 +1715,9 @@
         case EVENT:
             trace( "EVENT" );
             return gtk_event (handle, cast(GdkEvent*)arg0);
+        case POPULATE_POPUP:
+            trace( "POPULATE_POPUP" );
+            return gtk_populate_popup (handle, cast(GtkWidget*)arg0);
         case EVENT_AFTER:
             trace( "EVENT_AFTER" );
             return gtk_event_after (handle, cast(GdkEvent*)arg0);