changeset 18:92223a4ecca7

start of image port
author Frank Benoit <benoit@tionex.de>
date Mon, 07 Jan 2008 03:41:50 +0100
parents 4db14dc0bc45
children b73b14942338
files dwt/graphics/Color.d dwt/graphics/Cursor.d dwt/graphics/Device.d dwt/graphics/Drawable.d dwt/graphics/Font.d dwt/graphics/GC.d dwt/graphics/GCData.d dwt/graphics/Image.d dwt/graphics/ImageData.d dwt/graphics/ImageLoader.d dwt/graphics/Pattern.d dwt/graphics/Region.d dwt/graphics/Resource.d dwt/internal/BidiUtil.d dwt/internal/gtk/OS.d dwt/internal/gtk/c/gdktypes.d dwt/internal/gtk/c/gobjecttypes.d dwt/widgets/Display.d todo.txt
diffstat 19 files changed, 10902 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/dwt/graphics/Color.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/graphics/Color.d	Mon Jan 07 03:41:50 2008 +0100
@@ -16,6 +16,7 @@
 import dwt.internal.gtk.c.gdktypes : GdkColor, GdkColormap;
 import dwt.graphics.Resource;
 import dwt.graphics.RGB;
+import dwt.graphics.Device;
 
 import tango.text.convert.Format;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/graphics/Cursor.d	Mon Jan 07 03:41:50 2008 +0100
@@ -0,0 +1,544 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.graphics.Cursor;
+
+class Cursor {
+}
+
+/++++
+import dwt.*;
+import dwt.internal.gtk.*;
+
+/**
+ * Instances of this class manage operating system resources that
+ * specify the appearance of the on-screen pointer. To create a
+ * cursor you specify the device and either a simple cursor style
+ * describing one of the standard operating system provided cursors
+ * or the image and mask data for the desired appearance.
+ * <p>
+ * Application code must explicitly invoke the <code>Cursor.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>
+ *   CURSOR_ARROW, CURSOR_WAIT, CURSOR_CROSS, CURSOR_APPSTARTING, CURSOR_HELP,
+ *   CURSOR_SIZEALL, CURSOR_SIZENESW, CURSOR_SIZENS, CURSOR_SIZENWSE, CURSOR_SIZEWE,
+ *   CURSOR_SIZEN, CURSOR_SIZES, CURSOR_SIZEE, CURSOR_SIZEW, CURSOR_SIZENE, CURSOR_SIZESE,
+ *   CURSOR_SIZESW, CURSOR_SIZENW, CURSOR_UPARROW, CURSOR_IBEAM, CURSOR_NO, CURSOR_HAND
+ * </dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the above styles may be specified.
+ * </p>
+ */
+public final class Cursor extends Resource {
+	/**
+	 * the handle to the OS cursor resource
+	 * (Warning: This field is platform dependent)
+	 * <p>
+	 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+	 * public API. It is marked public only so that it can be shared
+	 * within the packages provided by SWT. It is not available on all
+	 * platforms and should never be accessed from application code.
+	 * </p>
+	 */
+	public int /*long*/ handle;
+
+	static final byte[] APPSTARTING_SRC = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+		0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+		0x7c, 0x00, 0x00, 0x00, (byte)0xfc, 0x00, 0x00, 0x00, (byte)0xfc, 0x01, 0x00, 0x00,
+		(byte)0xfc, 0x3b, 0x00, 0x00, 0x7c, 0x38, 0x00, 0x00, 0x6c, 0x54, 0x00, 0x00,
+		(byte)0xc4, (byte)0xdc, 0x00, 0x00, (byte)0xc0, 0x44, 0x00, 0x00, (byte)0x80, 0x39, 0x00, 0x00,
+		(byte)0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+	static final byte[] APPSTARTING_MASK = {
+		0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+		0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+		(byte)0xfe, 0x00, 0x00, 0x00, (byte)0xfe, 0x01, 0x00, 0x00, (byte)0xfe, 0x3b, 0x00, 0x00,
+		(byte)0xfe, 0x7f, 0x00, 0x00, (byte)0xfe, 0x7f, 0x00, 0x00, (byte)0xfe, (byte)0xfe, 0x00, 0x00,
+		(byte)0xee, (byte)0xff, 0x01, 0x00, (byte)0xe4, (byte)0xff, 0x00, 0x00, (byte)0xc0, 0x7f, 0x00, 0x00,
+		(byte)0xc0, 0x7f, 0x00, 0x00, (byte)0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+Cursor () {
+}
+
+/**
+ * Constructs a new cursor given a device and a style
+ * constant describing the desired cursor appearance.
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param style the style of cursor to allocate
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_INVALID_ARGUMENT - when an unknown style is specified</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ *
+ * @see SWT#CURSOR_ARROW
+ * @see SWT#CURSOR_WAIT
+ * @see SWT#CURSOR_CROSS
+ * @see SWT#CURSOR_APPSTARTING
+ * @see SWT#CURSOR_HELP
+ * @see SWT#CURSOR_SIZEALL
+ * @see SWT#CURSOR_SIZENESW
+ * @see SWT#CURSOR_SIZENS
+ * @see SWT#CURSOR_SIZENWSE
+ * @see SWT#CURSOR_SIZEWE
+ * @see SWT#CURSOR_SIZEN
+ * @see SWT#CURSOR_SIZES
+ * @see SWT#CURSOR_SIZEE
+ * @see SWT#CURSOR_SIZEW
+ * @see SWT#CURSOR_SIZENE
+ * @see SWT#CURSOR_SIZESE
+ * @see SWT#CURSOR_SIZESW
+ * @see SWT#CURSOR_SIZENW
+ * @see SWT#CURSOR_UPARROW
+ * @see SWT#CURSOR_IBEAM
+ * @see SWT#CURSOR_NO
+ * @see SWT#CURSOR_HAND
+ */
+public Cursor(Device device, int style) {
+	if (device == null) device = Device.getDevice();
+	if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	this.device = device;
+	int shape = 0;
+	switch (style) {
+		case SWT.CURSOR_APPSTARTING:	break;
+		case SWT.CURSOR_ARROW:			shape = OS.GDK_LEFT_PTR; break;
+		case SWT.CURSOR_WAIT:			shape = OS.GDK_WATCH; break;
+		case SWT.CURSOR_CROSS:			shape = OS.GDK_CROSS; break;
+		case SWT.CURSOR_HAND:			shape = OS.GDK_HAND2; break;
+		case SWT.CURSOR_HELP:			shape = OS.GDK_QUESTION_ARROW; break;
+		case SWT.CURSOR_SIZEALL:		shape = OS.GDK_FLEUR; break;
+		case SWT.CURSOR_SIZENESW:		shape = OS.GDK_SIZING; break;
+		case SWT.CURSOR_SIZENS:			shape = OS.GDK_DOUBLE_ARROW; break;
+		case SWT.CURSOR_SIZENWSE:		shape = OS.GDK_SIZING; break;
+		case SWT.CURSOR_SIZEWE:			shape = OS.GDK_SB_H_DOUBLE_ARROW; break;
+		case SWT.CURSOR_SIZEN:			shape = OS.GDK_TOP_SIDE; break;
+		case SWT.CURSOR_SIZES:			shape = OS.GDK_BOTTOM_SIDE; break;
+		case SWT.CURSOR_SIZEE:			shape = OS.GDK_RIGHT_SIDE; break;
+		case SWT.CURSOR_SIZEW:			shape = OS.GDK_LEFT_SIDE; break;
+		case SWT.CURSOR_SIZENE:			shape = OS.GDK_TOP_RIGHT_CORNER; break;
+		case SWT.CURSOR_SIZESE:			shape = OS.GDK_BOTTOM_RIGHT_CORNER; break;
+		case SWT.CURSOR_SIZESW:			shape = OS.GDK_BOTTOM_LEFT_CORNER; break;
+		case SWT.CURSOR_SIZENW:			shape = OS.GDK_TOP_LEFT_CORNER; break;
+		case SWT.CURSOR_UPARROW:		shape = OS.GDK_SB_UP_ARROW; break;
+		case SWT.CURSOR_IBEAM:			shape = OS.GDK_XTERM; break;
+		case SWT.CURSOR_NO:				shape = OS.GDK_X_CURSOR; break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	if (shape == 0 && style == SWT.CURSOR_APPSTARTING) {
+		handle = createCursor(APPSTARTING_SRC, APPSTARTING_MASK, 32, 32, 2, 2, true);
+	} else {
+		handle = OS.gdk_cursor_new(shape);
+	}
+	if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Constructs a new cursor given a device, image and mask
+ * data describing the desired cursor appearance, and the x
+ * and y coordinates of the <em>hotspot</em> (that is, the point
+ * within the area covered by the cursor which is considered
+ * to be where the on-screen pointer is "pointing").
+ * <p>
+ * The mask data is allowed to be null, but in this case the source
+ * must be an ImageData representing an icon that specifies both
+ * color data and mask data.
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param source the color data for the cursor
+ * @param mask the mask data for the cursor (or null)
+ * @param hotspotX the x coordinate of the cursor's hotspot
+ * @param hotspotY the y coordinate of the cursor's hotspot
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the source is null</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the mask is null and the source does not have a mask</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the source and the mask are not the same
+ *          size, or if the hotspot is outside the bounds of the image</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ */
+public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
+	if (device == null) device = Device.getDevice();
+	if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	this.device = device;
+	if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (mask == null) {
+		if (!(source.getTransparencyType() == SWT.TRANSPARENCY_MASK)) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+		mask = source.getTransparencyMask();
+	}
+	/* Check the bounds. Mask must be the same size as source */
+	if (mask.width != source.width || mask.height != source.height) {
+		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	/* Check the hotspots */
+	if (hotspotX >= source.width || hotspotX < 0 ||
+		hotspotY >= source.height || hotspotY < 0) {
+		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	/* Convert depth to 1 */
+	source = ImageData.convertMask(source);
+	mask = ImageData.convertMask(mask);
+
+	/* Swap the bits in each byte and convert to appropriate scanline pad */
+	byte[] sourceData = new byte[source.data.length];
+	byte[] maskData = new byte[mask.data.length];
+	byte[] data = source.data;
+	for (int i = 0; i < data.length; i++) {
+		byte s = data[i];
+		sourceData[i] = (byte)(((s & 0x80) >> 7) |
+			((s & 0x40) >> 5) |
+			((s & 0x20) >> 3) |
+			((s & 0x10) >> 1) |
+			((s & 0x08) << 1) |
+			((s & 0x04) << 3) |
+			((s & 0x02) << 5) |
+			((s & 0x01) << 7));
+		sourceData[i] = (byte) ~sourceData[i];
+	}
+	sourceData = ImageData.convertPad(sourceData, source.width, source.height, source.depth, source.scanlinePad, 1);
+	data = mask.data;
+	for (int i = 0; i < data.length; i++) {
+		byte s = data[i];
+		maskData[i] = (byte)(((s & 0x80) >> 7) |
+			((s & 0x40) >> 5) |
+			((s & 0x20) >> 3) |
+			((s & 0x10) >> 1) |
+			((s & 0x08) << 1) |
+			((s & 0x04) << 3) |
+			((s & 0x02) << 5) |
+			((s & 0x01) << 7));
+		maskData[i] = (byte) ~maskData[i];
+	}
+	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 == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Constructs a new cursor given a device, image data describing
+ * the desired cursor appearance, and the x and y coordinates of
+ * the <em>hotspot</em> (that is, the point within the area
+ * covered by the cursor which is considered to be where the
+ * on-screen pointer is "pointing").
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param source the image data for the cursor
+ * @param hotspotX the x coordinate of the cursor's hotspot
+ * @param hotspotY the y coordinate of the cursor's hotspot
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the hotspot is outside the bounds of the
+ * 		 image</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
+	if (device == null) device = Device.getDevice();
+	if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	this.device = device;
+	if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (hotspotX >= source.width || hotspotX < 0 ||
+		hotspotY >= source.height || hotspotY < 0) {
+		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	int /*long*/ display = 0;
+	if (OS.GTK_VERSION >= OS.VERSION(2, 4, 0) && OS.gdk_display_supports_cursor_color(display = OS.gdk_display_get_default ())) {
+		int width = source.width;
+		int height = source.height;
+		PaletteData palette = source.palette;
+		int /*long*/ pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, true, 8, width, height);
+		if (pixbuf == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+		int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+		int /*long*/ data = OS.gdk_pixbuf_get_pixels(pixbuf);
+		byte[] buffer = source.data;
+		if (!palette.isDirect || source.depth != 24 || stride != source.bytesPerLine || palette.redMask != 0xFF000000 || palette.greenMask != 0xFF0000 || palette.blueMask != 0xFF00) {
+			buffer = new byte[source.width * source.height * 4];
+			if (palette.isDirect) {
+				ImageData.blit(ImageData.BLIT_SRC,
+					source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, palette.redMask, palette.greenMask, palette.blueMask,
+					ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+					buffer, 32, source.width * 4, ImageData.MSB_FIRST, 0, 0, source.width, source.height, 0xFF000000, 0xFF0000, 0xFF00,
+					false, false);
+			} else {
+				RGB[] rgbs = palette.getRGBs();
+				int length = rgbs.length;
+				byte[] srcReds = new byte[length];
+				byte[] srcGreens = new byte[length];
+				byte[] srcBlues = new byte[length];
+				for (int i = 0; i < rgbs.length; i++) {
+					RGB rgb = rgbs[i];
+					if (rgb == null) continue;
+					srcReds[i] = (byte)rgb.red;
+					srcGreens[i] = (byte)rgb.green;
+					srcBlues[i] = (byte)rgb.blue;
+				}
+				ImageData.blit(ImageData.BLIT_SRC,
+					source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, srcReds, srcGreens, srcBlues,
+					ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+					buffer, 32, source.width * 4, ImageData.MSB_FIRST, 0, 0, source.width, source.height, 0xFF000000, 0xFF0000, 0xFF00,
+					false, false);
+			}
+			if (source.maskData != null || source.transparentPixel != -1) {
+				ImageData mask = source.getTransparencyMask();
+				byte[] maskData = mask.data;
+				int maskBpl = mask.bytesPerLine;
+				int offset = 3, maskOffset = 0;
+				for (int y = 0; y<source.height; y++) {
+					for (int x = 0; x<source.width; x++) {
+						buffer[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) != 0 ? (byte)0xff : 0;
+						offset += 4;
+					}
+					maskOffset += maskBpl;
+				}
+			} else if (source.alpha != -1) {
+				byte alpha = (byte)source.alpha;
+				for (int i=3; i<buffer.length; i+=4) {
+					buffer[i] = alpha;
+				}
+			} else if (source.alphaData != null) {
+				byte[] alphaData = source.alphaData;
+				for (int i=3; i<buffer.length; i+=4) {
+					buffer[i] = alphaData[i/4];
+				}
+			}
+		}
+		OS.memmove(data, buffer, stride * height);
+		handle = OS.gdk_cursor_new_from_pixbuf(display, pixbuf, hotspotX, hotspotY);
+		OS.g_object_unref(pixbuf);
+	} else {
+
+		ImageData mask = source.getTransparencyMask();
+
+		/* Ensure depth is equal to 1 */
+		if (source.depth > 1) {
+			/* Create a destination image with no data */
+			ImageData newSource = new ImageData(
+				source.width, source.height, 1, ImageData.bwPalette(),
+				1, null, 0, null, null, -1, -1, 0, 0, 0, 0, 0);
+
+			byte[] newReds = new byte[]{0, (byte)255}, newGreens = newReds, newBlues = newReds;
+
+			/* Convert the source to a black and white image of depth 1 */
+			PaletteData palette = source.palette;
+			if (palette.isDirect) {
+				ImageData.blit(ImageData.BLIT_SRC,
+						source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, palette.redMask, palette.greenMask, palette.blueMask,
+						ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+						newSource.data, newSource.depth, newSource.bytesPerLine, newSource.getByteOrder(), 0, 0, newSource.width, newSource.height, newReds, newGreens, newBlues,
+						false, false);
+			} else {
+				RGB[] rgbs = palette.getRGBs();
+				int length = rgbs.length;
+				byte[] srcReds = new byte[length];
+				byte[] srcGreens = new byte[length];
+				byte[] srcBlues = new byte[length];
+				for (int i = 0; i < rgbs.length; i++) {
+					RGB rgb = rgbs[i];
+					if (rgb == null) continue;
+					srcReds[i] = (byte)rgb.red;
+					srcGreens[i] = (byte)rgb.green;
+					srcBlues[i] = (byte)rgb.blue;
+				}
+				ImageData.blit(ImageData.BLIT_SRC,
+						source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, source.width, source.height, srcReds, srcGreens, srcBlues,
+						ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+						newSource.data, newSource.depth, newSource.bytesPerLine, newSource.getByteOrder(), 0, 0, newSource.width, newSource.height, newReds, newGreens, newBlues,
+						false, false);
+			}
+			source = newSource;
+		}
+
+		/* Swap the bits in each byte and convert to appropriate scanline pad */
+		byte[] sourceData = new byte[source.data.length];
+		byte[] maskData = new byte[mask.data.length];
+		byte[] data = source.data;
+		for (int i = 0; i < data.length; i++) {
+			byte s = data[i];
+			sourceData[i] = (byte)(((s & 0x80) >> 7) |
+				((s & 0x40) >> 5) |
+				((s & 0x20) >> 3) |
+				((s & 0x10) >> 1) |
+				((s & 0x08) << 1) |
+				((s & 0x04) << 3) |
+				((s & 0x02) << 5) |
+				((s & 0x01) << 7));
+		}
+		sourceData = ImageData.convertPad(sourceData, source.width, source.height, source.depth, source.scanlinePad, 1);
+		data = mask.data;
+		for (int i = 0; i < data.length; i++) {
+			byte s = data[i];
+			maskData[i] = (byte)(((s & 0x80) >> 7) |
+				((s & 0x40) >> 5) |
+				((s & 0x20) >> 3) |
+				((s & 0x10) >> 1) |
+				((s & 0x08) << 1) |
+				((s & 0x04) << 3) |
+				((s & 0x02) << 5) |
+				((s & 0x01) << 7));
+		}
+		maskData = ImageData.convertPad(maskData, mask.width, mask.height, mask.depth, mask.scanlinePad, 1);
+		handle = createCursor(sourceData, maskData, source.width, source.height, hotspotX, hotspotY, false);
+	}
+	if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	if (device.tracking) device.new_Object(this);
+}
+
+int /*long*/ createCursor(byte[] sourceData, byte[] maskData, int width, int height, int hotspotX, int hotspotY, boolean reverse) {
+	int /*long*/ sourcePixmap = OS.gdk_bitmap_create_from_data(0, sourceData, width, height);
+	int /*long*/ maskPixmap = OS.gdk_bitmap_create_from_data(0, maskData, width, height);
+	int /*long*/ cursor = 0;
+	if (sourcePixmap != 0 && maskPixmap != 0) {
+		GdkColor foreground = new GdkColor();
+		if (!reverse) foreground.red = foreground.green = foreground.blue = (short)0xFFFF;
+		GdkColor background = new GdkColor();
+		if (reverse) background.red = background.green = background.blue = (short)0xFFFF;
+		cursor = OS.gdk_cursor_new_from_pixmap (sourcePixmap, maskPixmap, foreground, background, hotspotX, hotspotY);
+	}
+	if (sourcePixmap != 0) OS.g_object_unref (sourcePixmap);
+	if (maskPixmap != 0) OS.g_object_unref (maskPixmap);
+	return cursor;
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the cursor. Applications must dispose of all cursors which
+ * they allocate.
+ */
+public void dispose() {
+	if (handle == 0) return;
+	if (device.isDisposed()) return;
+	OS.gdk_cursor_destroy(handle);
+	handle = 0;
+	if (device.tracking) device.dispose_Object(this);
+	device = null;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals(Object object) {
+	if (object == this) return true;
+	if (!(object instanceof Cursor)) return false;
+	Cursor cursor = (Cursor) object;
+	return device == cursor.device && handle == cursor.handle;
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new cursor.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Cursor</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param handle the handle for the cursor
+ *
+ * @private
+ */
+public static Cursor gtk_new(Device device, int /*long*/ handle) {
+	if (device == null) device = Device.getDevice();
+	Cursor cursor = new Cursor();
+	cursor.handle = handle;
+	cursor.device = device;
+	return cursor;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public int hashCode() {
+	return (int)/*64*/handle;
+}
+
+/**
+ * Returns <code>true</code> if the cursor has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the cursor.
+ * When a cursor has been disposed, it is an error to
+ * invoke any other method using the cursor.
+ *
+ * @return <code>true</code> when the cursor is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+	return handle == 0;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+	if (isDisposed()) return "Cursor {*DISPOSED*}";
+	return "Cursor {" + handle + "}";
+}
+
+}
+++++/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/graphics/Device.d	Mon Jan 07 03:41:50 2008 +0100
@@ -0,0 +1,892 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.graphics.Device;
+
+import dwt.internal.gtk.c.gdktypes : GdkColor;
+import dwt.graphics.Color;
+class Device{
+    static Device getDevice(){
+        return null;
+    }
+    void new_Object (Object object) {
+    }
+    void dispose_Object (Object object) {
+    }
+    bool tracking;
+    bool useXRender;
+    bool isDisposed(){
+        return false;
+    }
+    int[] colorRefCount;
+    GdkColor*[] gdkColors;
+    public Color getSystemColor (int id) {
+        return null;
+    }
+}
+
+/++++
+
+import dwt.*;
+import dwt.internal.*;
+import dwt.internal.gtk.*;
+
+/**
+ * This class is the abstract superclass of all device objects,
+ * such as the Display device and the Printer device. Devices
+ * can have a graphics context (GC) created for them, and they
+ * can be drawn on by sending messages to the associated GC.
+ */
+public abstract class Device implements Drawable {
+	/**
+	 * the handle to the X Display
+	 * (Warning: This field is platform dependent)
+	 * <p>
+	 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+	 * public API. It is marked protected only so that it can be shared
+	 * within the packages provided by SWT. It is not available on all
+	 * platforms and should never be accessed from application code.
+	 * </p>
+	 */
+	protected int /*long*/ xDisplay;
+	int /*long*/ shellHandle;
+
+	/* Debugging */
+	public static boolean DEBUG;
+	boolean debug = DEBUG;
+	boolean tracking = DEBUG;
+	Error [] errors;
+	Object [] objects;
+
+	/* Colormap and reference count */
+	GdkColor [] gdkColors;
+	int [] colorRefCount;
+
+	/* Disposed flag */
+	boolean disposed;
+
+	/* Warning and Error Handlers */
+	int /*long*/ logProc;
+	Callback logCallback;
+	//NOT DONE - get list of valid names
+	String [] log_domains = {"GLib-GObject", "GLib", "GObject", "Pango", "ATK", "GdkPixbuf", "Gdk", "Gtk", "GnomeVFS"};
+	int [] handler_ids = new int [log_domains.length];
+	int warningLevel;
+
+	/* X Warning and Error Handlers */
+	static Callback XErrorCallback, XIOErrorCallback;
+	static int /*long*/ XErrorProc, XIOErrorProc, XNullErrorProc, XNullIOErrorProc;
+	static Device[] Devices = new Device[4];
+
+	/*
+	* The following colors are listed in the Windows
+	* Programmer's Reference as the colors in the default
+	* palette.
+	*/
+	Color COLOR_BLACK, COLOR_DARK_RED, COLOR_DARK_GREEN, COLOR_DARK_YELLOW, COLOR_DARK_BLUE;
+	Color COLOR_DARK_MAGENTA, COLOR_DARK_CYAN, COLOR_GRAY, COLOR_DARK_GRAY, COLOR_RED;
+	Color COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE;
+
+	/* System Font */
+	Font systemFont;
+
+	int /*long*/ emptyTab;
+
+	boolean useXRender;
+
+	static boolean CAIRO_LOADED;
+
+	static final Object CREATE_LOCK = new Object();
+
+	/*
+	* TEMPORARY CODE. When a graphics object is
+	* created and the device parameter is null,
+	* the current Display is used. This presents
+	* a problem because SWT graphics does not
+	* reference classes in SWT widgets. The correct
+	* fix is to remove this feature. Unfortunately,
+	* too many application programs rely on this
+	* feature.
+	*
+	* This code will be removed in the future.
+	*/
+	protected static Device CurrentDevice;
+	protected static Runnable DeviceFinder;
+	static {
+		try {
+			Class.forName ("dwt.widgets.Display");
+		} catch (Throwable e) {}
+	}
+
+/*
+* TEMPORARY CODE.
+*/
+static synchronized Device getDevice () {
+	if (DeviceFinder != null) DeviceFinder.run();
+	Device device = CurrentDevice;
+	CurrentDevice = null;
+	return device;
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * You must dispose the device when it is no longer required.
+ * </p>
+ *
+ * @see #create
+ * @see #init
+ *
+ * @since 3.1
+ */
+public Device() {
+	this(null);
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * You must dispose the device when it is no longer required.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #create
+ * @see #init
+ * @see DeviceData
+ */
+public Device(DeviceData data) {
+	synchronized (CREATE_LOCK) {
+		if (data != null) {
+			debug = data.debug;
+			tracking = data.tracking;
+		}
+		if (tracking) {
+			errors = new Error [128];
+			objects = new Object [128];
+		}
+		create (data);
+		init ();
+		register (this);
+
+		/* Initialize the system font slot */
+		systemFont = getSystemFont ();
+	}
+}
+
+void checkCairo() {
+	if (CAIRO_LOADED) return;
+	try {
+		/* Check if cairo is available on the system */
+		byte[] buffer = Converter.wcsToMbcs(null, "libcairo.so.2", true);
+		int /*long*/ libcairo = OS.dlopen(buffer, OS.RTLD_LAZY);
+		if (libcairo != 0) {
+			OS.dlclose(libcairo);
+		} else {
+			try {
+				System.loadLibrary("cairo-swt");
+			} catch (UnsatisfiedLinkError e) {
+				/* Ignore problems loading the fallback library */
+			}
+		}
+		Class.forName("dwt.internal.cairo.Cairo");
+		CAIRO_LOADED = true;
+	} catch (Throwable t) {
+		SWT.error(SWT.ERROR_NO_GRAPHICS_LIBRARY, t, " [Cairo is required]");
+	}
+}
+
+/**
+ * Throws an <code>SWTException</code> if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method <em>should</em> be called by
+ * device implementors to enforce the standard SWT invariants.
+ * <p>
+ * Currently, it is an error to invoke any method (other than
+ * <code>isDisposed()</code> and <code>dispose()</code>) on a
+ * device that has had its <code>dispose()</code> method called.
+ * </p><p>
+ * In future releases of SWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * <p>
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+protected void checkDevice () {
+	if (disposed) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+}
+
+/**
+ * Creates the device in the operating system.  If the device
+ * does not have a handle, this method may do nothing depending
+ * on the device.
+ * <p>
+ * This method is called before <code>init</code>.
+ * </p><p>
+ * Subclasses are supposed to reimplement this method and not
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #init
+ */
+protected void create (DeviceData data) {
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the receiver. After this method has been invoked, the receiver
+ * will answer <code>true</code> when sent the message
+ * <code>isDisposed()</code>.
+ *
+ * @see #release
+ * @see #destroy
+ * @see #checkDevice
+ */
+public void dispose () {
+	if (isDisposed()) return;
+	checkDevice ();
+	release ();
+	destroy ();
+	deregister (this);
+	xDisplay = 0;
+	disposed = true;
+	if (tracking) {
+		objects = null;
+		errors = null;
+	}
+}
+
+void dispose_Object (Object object) {
+	for (int i=0; i<objects.length; i++) {
+		if (objects [i] == object) {
+			objects [i] = null;
+			errors [i] = null;
+			return;
+		}
+	}
+}
+
+static synchronized Device findDevice (int /*long*/ xDisplay) {
+	for (int i=0; i<Devices.length; i++) {
+		Device device = Devices [i];
+		if (device != null && device.xDisplay == xDisplay) {
+			return device;
+		}
+	}
+	return null;
+}
+
+synchronized static void deregister (Device device) {
+	for (int i=0; i<Devices.length; i++) {
+		if (device == Devices [i]) Devices [i] = null;
+	}
+}
+
+/**
+ * Destroys the device in the operating system and releases
+ * the device's handle.  If the device does not have a handle,
+ * this method may do nothing depending on the device.
+ * <p>
+ * This method is called after <code>release</code>.
+ * </p><p>
+ * Subclasses are supposed to reimplement this method and not
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #dispose
+ * @see #release
+ */
+protected void destroy () {
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location.
+ *
+ * @return the bounding rectangle
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getBounds () {
+	checkDevice ();
+	return new Rectangle(0, 0, 0, 0);
+}
+
+/**
+ * Returns a <code>DeviceData</code> based on the receiver.
+ * Modifications made to this <code>DeviceData</code> will not
+ * affect the receiver.
+ *
+ * @return a <code>DeviceData</code> containing the device's data and attributes
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see DeviceData
+ */
+public DeviceData getDeviceData () {
+	checkDevice();
+	DeviceData data = new DeviceData ();
+	data.debug = debug;
+	data.tracking = tracking;
+	int count = 0, length = 0;
+	if (tracking) length = objects.length;
+	for (int i=0; i<length; i++) {
+		if (objects [i] != null) count++;
+	}
+	int index = 0;
+	data.objects = new Object [count];
+	data.errors = new Error [count];
+	for (int i=0; i<length; i++) {
+		if (objects [i] != null) {
+			data.objects [index] = objects [i];
+			data.errors [index] = errors [i];
+			index++;
+		}
+	}
+	return data;
+}
+
+/**
+ * Returns a rectangle which describes the area of the
+ * receiver which is capable of displaying data.
+ *
+ * @return the client area
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getBounds
+ */
+public Rectangle getClientArea () {
+	checkDevice ();
+	return getBounds ();
+}
+
+/**
+ * Returns the bit depth of the screen, which is the number of
+ * bits it takes to represent the number of unique colors that
+ * the screen is currently capable of displaying. This number
+ * will typically be one of 1, 8, 15, 16, 24 or 32.
+ *
+ * @return the depth of the screen
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getDepth () {
+	checkDevice ();
+	return 0;
+}
+
+/**
+ * Returns a point whose x coordinate is the horizontal
+ * dots per inch of the display, and whose y coordinate
+ * is the vertical dots per inch of the display.
+ *
+ * @return the horizontal and vertical DPI
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point getDPI () {
+	checkDevice ();
+	return new Point (72, 72);
+}
+
+/**
+ * Returns <code>FontData</code> objects which describe
+ * the fonts that match the given arguments. If the
+ * <code>faceName</code> is null, all fonts will be returned.
+ *
+ * @param faceName the name of the font to look for, or null
+ * @param scalable if true only scalable fonts are returned, otherwise only non-scalable fonts are returned.
+ * @return the matching font data
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontData[] getFontList (String faceName, boolean scalable) {
+	checkDevice ();
+	if (!scalable) return new FontData[0];
+	int /*long*/[] family = new int /*long*/[1];
+	int /*long*/[] face = new int /*long*/[1];
+	int /*long*/[] families = new int /*long*/[1];
+	int[] n_families = new int[1];
+	int /*long*/[] faces = new int /*long*/[1];
+	int[] n_faces = new int[1];
+	int /*long*/ context = OS.gdk_pango_context_get();
+	OS.pango_context_list_families(context, families, n_families);
+	int nFds = 0;
+	FontData[] fds = new FontData[faceName != null ? 4 : n_families[0]];
+	for (int i=0; i<n_families[0]; i++) {
+		OS.memmove(family, families[0] + i * OS.PTR_SIZEOF, OS.PTR_SIZEOF);
+		boolean match = true;
+		if (faceName != null) {
+			int /*long*/ familyName = OS.pango_font_family_get_name(family[0]);
+			int length = OS.strlen(familyName);
+			byte[] buffer = new byte[length];
+			OS.memmove(buffer, familyName, length);
+			String name = new String(Converter.mbcsToWcs(null, buffer));
+			match = Compatibility.equalsIgnoreCase(faceName, name);
+		}
+		if (match) {
+		    OS.pango_font_family_list_faces(family[0], faces, n_faces);
+		    for (int j=0; j<n_faces[0]; j++) {
+		        OS.memmove(face, faces[0] + j * OS.PTR_SIZEOF, OS.PTR_SIZEOF);
+		        int /*long*/ fontDesc = OS.pango_font_face_describe(face[0]);
+		        Font font = Font.gtk_new(this, fontDesc);
+		        FontData data = font.getFontData()[0];
+				if (nFds == fds.length) {
+					FontData[] newFds = new FontData[fds.length + n_families[0]];
+					System.arraycopy(fds, 0, newFds, 0, nFds);
+					fds = newFds;
+				}
+				fds[nFds++] = data;
+				OS.pango_font_description_free(fontDesc);
+		    }
+		    OS.g_free(faces[0]);
+		    if (faceName != null) break;
+		}
+	}
+	OS.g_free(families[0]);
+	OS.g_object_unref(context);
+	if (nFds == fds.length) return fds;
+	FontData[] result = new FontData[nFds];
+	System.arraycopy(fds, 0, result, 0, nFds);
+	return result;
+}
+
+/**
+ * Returns the matching standard color for the given
+ * constant, which should be one of the color constants
+ * specified in class <code>SWT</code>. Any value other
+ * than one of the SWT color constants which is passed
+ * in will result in the color black. This color should
+ * not be freed because it was allocated by the system,
+ * not the application.
+ *
+ * @param id the color constant
+ * @return the matching color
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see SWT
+ */
+public Color getSystemColor (int id) {
+	checkDevice ();
+	switch (id) {
+		case SWT.COLOR_BLACK: 				return COLOR_BLACK;
+		case SWT.COLOR_DARK_RED: 			return COLOR_DARK_RED;
+		case SWT.COLOR_DARK_GREEN:	 		return COLOR_DARK_GREEN;
+		case SWT.COLOR_DARK_YELLOW: 		return COLOR_DARK_YELLOW;
+		case SWT.COLOR_DARK_BLUE: 			return COLOR_DARK_BLUE;
+		case SWT.COLOR_DARK_MAGENTA: 		return COLOR_DARK_MAGENTA;
+		case SWT.COLOR_DARK_CYAN: 			return COLOR_DARK_CYAN;
+		case SWT.COLOR_GRAY: 				return COLOR_GRAY;
+		case SWT.COLOR_DARK_GRAY: 			return COLOR_DARK_GRAY;
+		case SWT.COLOR_RED: 				return COLOR_RED;
+		case SWT.COLOR_GREEN: 				return COLOR_GREEN;
+		case SWT.COLOR_YELLOW: 				return COLOR_YELLOW;
+		case SWT.COLOR_BLUE: 				return COLOR_BLUE;
+		case SWT.COLOR_MAGENTA: 			return COLOR_MAGENTA;
+		case SWT.COLOR_CYAN: 				return COLOR_CYAN;
+		case SWT.COLOR_WHITE: 				return COLOR_WHITE;
+	}
+	return COLOR_BLACK;
+}
+
+/**
+ * Returns a reasonable font for applications to use.
+ * On some platforms, this will match the "default font"
+ * or "system font" if such can be found.  This font
+ * should not be freed because it was allocated by the
+ * system, not the application.
+ * <p>
+ * Typically, applications which want the default look
+ * should simply not set the font on the widgets they
+ * create. Widgets are always created with the correct
+ * default font for the class of user-interface component
+ * they represent.
+ * </p>
+ *
+ * @return a font
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getSystemFont () {
+	checkDevice ();
+	return systemFont;
+}
+
+/**
+ * Returns <code>true</code> if the underlying window system prints out
+ * warning messages on the console, and <code>setWarnings</code>
+ * had previously been called with <code>true</code>.
+ *
+ * @return <code>true</code>if warnings are being handled, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean getWarnings () {
+	checkDevice ();
+	return warningLevel == 0;
+}
+
+/**
+ * Initializes any internal resources needed by the
+ * device.
+ * <p>
+ * This method is called after <code>create</code>.
+ * </p><p>
+ * If subclasses reimplement this method, they must
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #create
+ */
+protected void init () {
+	if (xDisplay != 0) {
+		int[] event_basep = new int[1], error_basep = new int [1];
+		if (OS.XRenderQueryExtension (xDisplay, event_basep, error_basep)) {
+			int[] major_versionp = new int[1], minor_versionp = new int [1];
+			OS.XRenderQueryVersion (xDisplay, major_versionp, minor_versionp);
+			useXRender = major_versionp[0] > 0 || (major_versionp[0] == 0 && minor_versionp[0] >= 8);
+		}
+	}
+
+	if (debug) {
+		if (xDisplay != 0) {
+			/* Create the warning and error callbacks */
+			Class clazz = getClass ();
+			synchronized (clazz) {
+				int index = 0;
+				while (index < Devices.length) {
+					if (Devices [index] != null) break;
+					index++;
+				}
+				if (index == Devices.length) {
+					XErrorCallback = new Callback (clazz, "XErrorProc", 2);
+					XNullErrorProc = XErrorCallback.getAddress ();
+					if (XNullErrorProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+					XIOErrorCallback = new Callback (clazz, "XIOErrorProc", 1);
+					XNullIOErrorProc = XIOErrorCallback.getAddress ();
+					if (XNullIOErrorProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+					XErrorProc = OS.XSetErrorHandler (XNullErrorProc);
+					XIOErrorProc = OS.XSetIOErrorHandler (XNullIOErrorProc);
+				}
+			}
+			OS.XSynchronize (xDisplay, true);
+		}
+	}
+
+	/* Create GTK warnings and error callbacks */
+	if (xDisplay != 0) {
+		logCallback = new Callback (this, "logProc", 4);
+		logProc = logCallback.getAddress ();
+		if (logProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+		/* Set GTK warning and error handlers */
+		if (debug) {
+			int flags = OS.G_LOG_LEVEL_MASK | OS.G_LOG_FLAG_FATAL | OS.G_LOG_FLAG_RECURSION;
+			for (int i=0; i<log_domains.length; i++) {
+				byte [] log_domain = Converter.wcsToMbcs (null, log_domains [i], true);
+				handler_ids [i] = OS.g_log_set_handler (log_domain, flags, logProc, 0);
+			}
+		}
+	}
+
+	/* Create the standard colors */
+	COLOR_BLACK = new Color (this, 0,0,0);
+	COLOR_DARK_RED = new Color (this, 0x80,0,0);
+	COLOR_DARK_GREEN = new Color (this, 0,0x80,0);
+	COLOR_DARK_YELLOW = new Color (this, 0x80,0x80,0);
+	COLOR_DARK_BLUE = new Color (this, 0,0,0x80);
+	COLOR_DARK_MAGENTA = new Color (this, 0x80,0,0x80);
+	COLOR_DARK_CYAN = new Color (this, 0,0x80,0x80);
+	COLOR_GRAY = new Color (this, 0xC0,0xC0,0xC0);
+	COLOR_DARK_GRAY = new Color (this, 0x80,0x80,0x80);
+	COLOR_RED = new Color (this, 0xFF,0,0);
+	COLOR_GREEN = new Color (this, 0,0xFF,0);
+	COLOR_YELLOW = new Color (this, 0xFF,0xFF,0);
+	COLOR_BLUE = new Color (this, 0,0,0xFF);
+	COLOR_MAGENTA = new Color (this, 0xFF,0,0xFF);
+	COLOR_CYAN = new Color (this, 0,0xFF,0xFF);
+	COLOR_WHITE = new Color (this, 0xFF,0xFF,0xFF);
+
+	emptyTab = OS.pango_tab_array_new(1, false);
+	if (emptyTab == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	OS.pango_tab_array_set_tab(emptyTab, 0, OS.PANGO_TAB_LEFT, 1);
+
+	shellHandle = OS.gtk_window_new(OS.GTK_WINDOW_TOPLEVEL);
+	if (shellHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	OS.gtk_widget_realize(shellHandle);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Device</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ */
+public abstract int /*long*/ internal_new_GC (GCData data);
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Device</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public abstract void internal_dispose_GC (int /*long*/ handle, GCData data);
+
+/**
+ * Returns <code>true</code> if the device has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the device.
+ * When a device has been disposed, it is an error to
+ * invoke any other method using the device.
+ *
+ * @return <code>true</code> when the device is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed () {
+	return disposed;
+}
+
+/**
+ * Loads the font specified by a file.  The font will be
+ * present in the list of fonts available to the application.
+ *
+ * @param path the font file path
+ * @return whether the font was successfully loaded
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if path is null</li>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Font
+ *
+ * @since 3.3
+ */
+public boolean loadFont (String path) {
+	checkDevice();
+	if (path == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+	byte [] buffer = Converter.wcsToMbcs (null, path, true);
+	return OS.FcConfigAppFontAddFile (0, buffer);
+}
+
+int /*long*/ logProc (int /*long*/ log_domain, int /*long*/ log_level, int /*long*/ message, int /*long*/ user_data) {
+	if (warningLevel == 0) {
+		if (DEBUG || debug) {
+			new Error ().printStackTrace ();
+		}
+		OS.g_log_default_handler (log_domain, (int)/*64*/log_level, message, 0);
+	}
+	return 0;
+}
+
+void new_Object (Object object) {
+	for (int i=0; i<objects.length; i++) {
+		if (objects [i] == null) {
+			objects [i] = object;
+			errors [i] = new Error ();
+			return;
+		}
+	}
+	Object [] newObjects = new Object [objects.length + 128];
+	System.arraycopy (objects, 0, newObjects, 0, objects.length);
+	newObjects [objects.length] = object;
+	objects = newObjects;
+	Error [] newErrors = new Error [errors.length + 128];
+	System.arraycopy (errors, 0, newErrors, 0, errors.length);
+	newErrors [errors.length] = new Error ();
+	errors = newErrors;
+}
+
+static synchronized void register (Device device) {
+	for (int i=0; i<Devices.length; i++) {
+		if (Devices [i] == null) {
+			Devices [i] = device;
+			return;
+		}
+	}
+	Device [] newDevices = new Device [Devices.length + 4];
+	System.arraycopy (Devices, 0, newDevices, 0, Devices.length);
+	newDevices [Devices.length] = device;
+	Devices = newDevices;
+}
+
+/**
+ * Releases any internal resources back to the operating
+ * system and clears all fields except the device handle.
+ * <p>
+ * When a device is destroyed, resources that were acquired
+ * on behalf of the programmer need to be returned to the
+ * operating system.  For example, if the device allocated a
+ * font to be used as the system font, this font would be
+ * freed in <code>release</code>.  Also,to assist the garbage
+ * collector and minimize the amount of memory that is not
+ * reclaimed when the programmer keeps a reference to a
+ * disposed device, all fields except the handle are zero'd.
+ * The handle is needed by <code>destroy</code>.
+ * </p>
+ * This method is called before <code>destroy</code>.
+ * </p><p>
+ * If subclasses reimplement this method, they must
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #dispose
+ * @see #destroy
+ */
+protected void release () {
+	if (shellHandle != 0) OS.gtk_widget_destroy(shellHandle);
+	shellHandle = 0;
+
+	if (gdkColors != null) {
+		int /*long*/ colormap = OS.gdk_colormap_get_system();
+		for (int i = 0; i < gdkColors.length; i++) {
+			GdkColor color = gdkColors [i];
+			if (color != null) {
+				while (colorRefCount [i] > 0) {
+					OS.gdk_colormap_free_colors(colormap, color, 1);
+					--colorRefCount [i];
+				}
+			}
+		}
+	}
+	gdkColors = null;
+	colorRefCount = null;
+	COLOR_BLACK = COLOR_DARK_RED = COLOR_DARK_GREEN = COLOR_DARK_YELLOW = COLOR_DARK_BLUE =
+	COLOR_DARK_MAGENTA = COLOR_DARK_CYAN = COLOR_GRAY = COLOR_DARK_GRAY = COLOR_RED =
+	COLOR_GREEN = COLOR_YELLOW = COLOR_BLUE = COLOR_MAGENTA = COLOR_CYAN = COLOR_WHITE = null;
+
+	if (emptyTab != 0) OS.pango_tab_array_free(emptyTab);
+	emptyTab = 0;
+
+	/* Free the GTK error and warning handler */
+	if (xDisplay != 0) {
+		for (int i=0; i<handler_ids.length; i++) {
+			if (handler_ids [i] != 0) {
+				byte [] log_domain = Converter.wcsToMbcs (null, log_domains [i], true);
+				OS.g_log_remove_handler (log_domain, handler_ids [i]);
+				handler_ids [i] = 0;
+			}
+		}
+		logCallback.dispose ();  logCallback = null;
+		handler_ids = null;  log_domains = null;
+		logProc = 0;
+	}
+}
+
+/**
+ * If the underlying window system supports printing warning messages
+ * to the console, setting warnings to <code>false</code> prevents these
+ * messages from being printed. If the argument is <code>true</code> then
+ * message printing is not blocked.
+ *
+ * @param warnings <code>true</code>if warnings should be printed, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setWarnings (boolean warnings) {
+	checkDevice ();
+	if (warnings) {
+		if (--warningLevel == 0) {
+			if (debug) return;
+			if (logProc != 0) {
+				for (int i=0; i<handler_ids.length; i++) {
+					if (handler_ids [i] != 0) {
+						byte [] log_domain = Converter.wcsToMbcs (null, log_domains [i], true);
+						OS.g_log_remove_handler (log_domain, handler_ids [i]);
+						handler_ids [i] = 0;
+					}
+				}
+			}
+		}
+	} else {
+		if (warningLevel++ == 0) {
+			if (debug) return;
+			if (logProc != 0) {
+				int flags = OS.G_LOG_LEVEL_MASK | OS.G_LOG_FLAG_FATAL | OS.G_LOG_FLAG_RECURSION;
+				for (int i=0; i<log_domains.length; i++) {
+					byte [] log_domain = Converter.wcsToMbcs (null, log_domains [i], true);
+					handler_ids [i] = OS.g_log_set_handler (log_domain, flags, logProc, 0);
+				}
+			}
+		}
+	}
+}
+
+static int /*long*/ XErrorProc (int /*long*/ xDisplay, int /*long*/ xErrorEvent) {
+	Device device = findDevice (xDisplay);
+	if (device != null) {
+		if (device.warningLevel == 0) {
+			if (DEBUG || device.debug) {
+				new SWTError ().printStackTrace ();
+			}
+			OS.Call (XErrorProc, xDisplay, xErrorEvent);
+		}
+	} else {
+		if (DEBUG) new SWTError ().printStackTrace ();
+		OS.Call (XErrorProc, xDisplay, xErrorEvent);
+	}
+	return 0;
+}
+
+static int /*long*/ XIOErrorProc (int /*long*/ xDisplay) {
+	Device device = findDevice (xDisplay);
+	if (device != null) {
+		if (DEBUG || device.debug) {
+			new SWTError ().printStackTrace ();
+		}
+	} else {
+		if (DEBUG) new SWTError ().printStackTrace ();
+	}
+	OS.Call (XIOErrorProc, xDisplay, 0);
+	return 0;
+}
+
+}
+++++/
\ No newline at end of file
--- a/dwt/graphics/Drawable.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/graphics/Drawable.d	Mon Jan 07 03:41:50 2008 +0100
@@ -11,10 +11,8 @@
 module dwt.graphics.Drawable;
 
 
-// PORTING_TYPE
-//import dwt.graphics.GCData;
-class GCData{
-}
+import dwt.graphics.GCData;
+
 
 /**
  * Implementers of <code>Drawable</code> can have a graphics context (GC)
--- a/dwt/graphics/Font.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/graphics/Font.d	Mon Jan 07 03:41:50 2008 +0100
@@ -14,7 +14,7 @@
 import dwt.SWT;
 import dwt.graphics.Resource;
 import dwt.graphics.FontData;
-//import dwt.graphics.Device;
+import dwt.graphics.Device;
 import dwt.internal.Converter;
 import dwt.internal.gtk.OS;
 import dwt.internal.gtk.c.pangotypes;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/graphics/GC.d	Mon Jan 07 03:41:50 2008 +0100
@@ -0,0 +1,3922 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.graphics.GC;
+
+import dwt.graphics.Image;
+
+class GC{
+    void drawImage(Image, int, int, int, int, int, int, int, int ){}
+}
+/++++
+import dwt.internal.cairo.*;
+import dwt.internal.gtk.*;
+import dwt.internal.*;
+import dwt.*;
+
+/**
+ * Class <code>GC</code> is where all of the drawing capabilities that are
+ * supported by SWT are located. Instances are used to draw on either an
+ * <code>Image</code>, a <code>Control</code>, or directly on a <code>Display</code>.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
+ * </dl>
+ *
+ * <p>
+ * The SWT drawing coordinate system is the two-dimensional space with the origin
+ * (0,0) at the top left corner of the drawing area and with (x,y) values increasing
+ * to the right and downward respectively.
+ * </p>
+ *
+ * <p>
+ * Application code must explicitly invoke the <code>GC.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required. This is <em>particularly</em>
+ * important on Windows95 and Windows98 where the operating system has a limited
+ * number of device contexts available.
+ * </p>
+ *
+ * <p>
+ * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified.
+ * </p>
+ *
+ * @see dwt.events.PaintEvent
+ */
+public final class GC extends Resource {
+	/**
+	 * the handle to the OS device context
+	 * (Warning: This field is platform dependent)
+	 * <p>
+	 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+	 * public API. It is marked public only so that it can be shared
+	 * within the packages provided by SWT. It is not available on all
+	 * platforms and should never be accessed from application code.
+	 * </p>
+	 */
+	public int /*long*/ handle;
+
+	Drawable drawable;
+	GCData data;
+
+	final static int FOREGROUND = 1 << 0;
+	final static int BACKGROUND = 1 << 1;
+	final static int FONT = 1 << 2;
+	final static int LINE_STYLE = 1 << 3;
+	final static int LINE_CAP = 1 << 4;
+	final static int LINE_JOIN = 1 << 5;
+	final static int LINE_WIDTH = 1 << 6;
+	final static int LINE_MITERLIMIT = 1 << 7;
+	final static int BACKGROUND_BG = 1 << 8;
+	final static int DRAW_OFFSET = 1 << 9;
+	final static int DRAW = FOREGROUND | LINE_WIDTH | LINE_STYLE  | LINE_CAP  | LINE_JOIN | LINE_MITERLIMIT | DRAW_OFFSET;
+	final static int FILL = BACKGROUND;
+
+	static final float[] LINE_DOT = new float[]{1, 1};
+	static final float[] LINE_DASH = new float[]{3, 1};
+	static final float[] LINE_DASHDOT = new float[]{3, 1, 1, 1};
+	static final float[] LINE_DASHDOTDOT = new float[]{3, 1, 1, 1, 1, 1};
+	static final float[] LINE_DOT_ZERO = new float[]{3, 3};
+	static final float[] LINE_DASH_ZERO = new float[]{18, 6};
+	static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6};
+	static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3};
+
+GC() {
+}
+
+/**
+ * Constructs a new instance of this class which has been
+ * configured to draw on the specified drawable. Sets the
+ * foreground color, background color and font in the GC
+ * to match those in the drawable.
+ * <p>
+ * You must dispose the graphics context when it is no longer required.
+ * </p>
+ * @param drawable the drawable to draw on
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
+ *    <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
+ *    <li>ERROR_INVALID_ARGUMENT
+ *          - if the drawable is an image that is not a bitmap or an icon
+ *          - if the drawable is an image or printer that is already selected
+ *            into another graphics context</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ */
+public GC(Drawable drawable) {
+	this(drawable, 0);
+}
+
+/**
+ * Constructs a new instance of this class which has been
+ * configured to draw on the specified drawable. Sets the
+ * foreground color, background color and font in the GC
+ * to match those in the drawable.
+ * <p>
+ * You must dispose the graphics context when it is no longer required.
+ * </p>
+ *
+ * @param drawable the drawable to draw on
+ * @param style the style of GC to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
+ *    <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
+ *    <li>ERROR_INVALID_ARGUMENT
+ *          - if the drawable is an image that is not a bitmap or an icon
+ *          - if the drawable is an image or printer that is already selected
+ *            into another graphics context</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public GC(Drawable drawable, int style) {
+	if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	GCData data = new GCData();
+	data.style = checkStyle(style);
+	int /*long*/ gdkGC = drawable.internal_new_GC(data);
+	Device device = data.device;
+	if (device == null) device = Device.getDevice();
+	if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	this.device = data.device = device;
+	init(drawable, data, gdkGC);
+	if (device.tracking) device.new_Object(this);
+}
+
+static void addCairoString(int /*long*/ cairo, String string, float x, float y, Font font) {
+	byte[] buffer = Converter.wcsToMbcs(null, string, true);
+	if (OS.GTK_VERSION >= OS.VERSION(2, 8, 0)) {
+		int /*long*/ layout = OS.pango_cairo_create_layout(cairo);
+		if (layout == 0) SWT.error(SWT.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);
+		OS.pango_cairo_layout_path(cairo, layout);
+		OS.g_object_unref(layout);
+	} else {
+		GC.setCairoFont(cairo, font);
+		cairo_font_extents_t extents = new cairo_font_extents_t();
+		Cairo.cairo_font_extents(cairo, extents);
+		double baseline = y + extents.ascent;
+		Cairo.cairo_move_to(cairo, x, baseline);
+		Cairo.cairo_text_path(cairo, buffer);
+	}
+}
+
+static int checkStyle (int style) {
+	if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT;
+	return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+}
+
+public static GC gtk_new(Drawable drawable, GCData data) {
+	GC gc = new GC();
+	int /*long*/ gdkGC = drawable.internal_new_GC(data);
+	gc.device = data.device;
+	gc.init(drawable, data, gdkGC);
+	return gc;
+}
+
+void checkGC (int mask) {
+	int state = data.state;
+	if ((state & mask) == mask) return;
+	state = (state ^ mask) & mask;
+	data.state |= mask;
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		if ((state & (BACKGROUND | FOREGROUND)) != 0) {
+			GdkColor color;
+			Pattern pattern;
+			if ((state & FOREGROUND) != 0) {
+				color = data.foreground;
+				pattern = data.foregroundPattern;
+				data.state &= ~BACKGROUND;
+			} else {
+				color = data.background;
+				pattern = data.backgroundPattern;
+				data.state &= ~FOREGROUND;
+			}
+			if  (pattern != null) {
+				Cairo.cairo_set_source(cairo, pattern.handle);
+			} else {
+				Cairo.cairo_set_source_rgba(cairo, (color.red & 0xFFFF) / (float)0xFFFF, (color.green & 0xFFFF) / (float)0xFFFF, (color.blue & 0xFFFF) / (float)0xFFFF, data.alpha / (float)0xFF);
+			}
+		}
+		if ((state & FONT) != 0) {
+			if (data.layout != 0) {
+				OS.pango_layout_set_font_description(data.layout, data.font);
+			}
+			if (OS.GTK_VERSION < OS.VERSION(2, 8, 0)) {
+				setCairoFont(cairo, data.font);
+			}
+		}
+		if ((state & LINE_CAP) != 0) {
+			int cap_style = 0;
+			switch (data.lineCap) {
+				case SWT.CAP_ROUND: cap_style = Cairo.CAIRO_LINE_CAP_ROUND; break;
+				case SWT.CAP_FLAT: cap_style = Cairo.CAIRO_LINE_CAP_BUTT; break;
+				case SWT.CAP_SQUARE: cap_style = Cairo.CAIRO_LINE_CAP_SQUARE; break;
+			}
+			Cairo.cairo_set_line_cap(cairo, cap_style);
+		}
+		if ((state & LINE_JOIN) != 0) {
+			int join_style = 0;
+			switch (data.lineJoin) {
+				case SWT.JOIN_MITER: join_style = Cairo.CAIRO_LINE_JOIN_MITER; break;
+				case SWT.JOIN_ROUND:  join_style = Cairo.CAIRO_LINE_JOIN_ROUND; break;
+				case SWT.JOIN_BEVEL: join_style = Cairo.CAIRO_LINE_JOIN_BEVEL; break;
+			}
+			Cairo.cairo_set_line_join(cairo, join_style);
+		}
+		if ((state & LINE_WIDTH) != 0) {
+			Cairo.cairo_set_line_width(cairo, data.lineWidth == 0 ? 1 : data.lineWidth);
+			switch (data.lineStyle) {
+				case SWT.LINE_DOT:
+				case SWT.LINE_DASH:
+				case SWT.LINE_DASHDOT:
+				case SWT.LINE_DASHDOTDOT:
+					state |= LINE_STYLE;
+			}
+		}
+		if ((state & LINE_STYLE) != 0) {
+			float dashesOffset = 0;
+			float[] dashes = null;
+			float width = data.lineWidth;
+			switch (data.lineStyle) {
+				case SWT.LINE_SOLID: break;
+				case SWT.LINE_DASH: dashes = width != 0 ? LINE_DASH : LINE_DASH_ZERO; break;
+				case SWT.LINE_DOT: dashes = width != 0 ? LINE_DOT : LINE_DOT_ZERO; break;
+				case SWT.LINE_DASHDOT: dashes = width != 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
+				case SWT.LINE_DASHDOTDOT: dashes = width != 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
+				case SWT.LINE_CUSTOM: dashes = data.lineDashes; break;
+			}
+			if (dashes != null) {
+				dashesOffset = data.lineDashesOffset;
+				double[] cairoDashes = new double[dashes.length];
+				for (int i = 0; i < cairoDashes.length; i++) {
+					cairoDashes[i] = width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width;
+				}
+				Cairo.cairo_set_dash(cairo, cairoDashes, cairoDashes.length, dashesOffset);
+			} else {
+				Cairo.cairo_set_dash(cairo, null, 0, 0);
+			}
+		}
+		if ((state & LINE_MITERLIMIT) != 0) {
+			Cairo.cairo_set_miter_limit(cairo, data.lineMiterLimit);
+		}
+		if ((state & DRAW_OFFSET) != 0) {
+			data.cairoXoffset = data.cairoYoffset = 0;
+			double[] matrix = new double[6];
+			Cairo.cairo_get_matrix(cairo, matrix);
+			double scaling = matrix[0];
+			if (scaling < 0) scaling = -scaling;
+			double strokeWidth = data.lineWidth * scaling;
+			if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) {
+				data.cairoXoffset = 0.5 / scaling;
+			}
+			scaling = matrix[3];
+			if (scaling < 0) scaling = -scaling;
+			strokeWidth = data.lineWidth * scaling;
+			if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) {
+				data.cairoYoffset = 0.5 / scaling;
+			}
+		}
+		return;
+	}
+	if ((state & (BACKGROUND | FOREGROUND)) != 0) {
+		GdkColor foreground;
+		if ((state & FOREGROUND) != 0) {
+			foreground = data.foreground;
+			data.state &= ~BACKGROUND;
+		} else {
+			foreground = data.background;
+			data.state &= ~FOREGROUND;
+		}
+		OS.gdk_gc_set_foreground(handle, foreground);
+	}
+	if ((state & BACKGROUND_BG) != 0) {
+		GdkColor background = data.background;
+		OS.gdk_gc_set_background(handle, background);
+	}
+	if ((state & FONT) != 0) {
+		if (data.layout != 0) {
+			OS.pango_layout_set_font_description(data.layout, data.font);
+		}
+	}
+	if ((state & (LINE_CAP | LINE_JOIN | LINE_STYLE | LINE_WIDTH)) != 0) {
+		int cap_style = 0;
+		int join_style = 0;
+		int width = (int)data.lineWidth;
+		int line_style = 0;
+		float[] dashes = null;
+		switch (data.lineCap) {
+			case SWT.CAP_ROUND: cap_style = OS.GDK_CAP_ROUND; break;
+			case SWT.CAP_FLAT: cap_style = OS.GDK_CAP_BUTT; break;
+			case SWT.CAP_SQUARE: cap_style = OS.GDK_CAP_PROJECTING; break;
+		}
+		switch (data.lineJoin) {
+			case SWT.JOIN_ROUND: join_style = OS.GDK_JOIN_ROUND; break;
+			case SWT.JOIN_MITER: join_style = OS.GDK_JOIN_MITER; break;
+			case SWT.JOIN_BEVEL: join_style = OS.GDK_JOIN_BEVEL; break;
+		}
+		switch (data.lineStyle) {
+			case SWT.LINE_SOLID: break;
+			case SWT.LINE_DASH: dashes = width != 0 ? LINE_DASH : LINE_DASH_ZERO; break;
+			case SWT.LINE_DOT: dashes = width != 0 ? LINE_DOT : LINE_DOT_ZERO; break;
+			case SWT.LINE_DASHDOT: dashes = width != 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
+			case SWT.LINE_DASHDOTDOT: dashes = width != 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
+			case SWT.LINE_CUSTOM: dashes = data.lineDashes; break;
+		}
+		if (dashes != null) {
+			if ((state & LINE_STYLE) != 0) {
+				byte[] dash_list = new byte[dashes.length];
+				for (int i = 0; i < dash_list.length; i++) {
+					dash_list[i] = (byte)(width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width);
+				}
+				OS.gdk_gc_set_dashes(handle, 0, dash_list, dash_list.length);
+			}
+			line_style = OS.GDK_LINE_ON_OFF_DASH;
+		} else {
+			line_style = OS.GDK_LINE_SOLID;
+		}
+		OS.gdk_gc_set_line_attributes(handle, width, line_style, cap_style, join_style);
+	}
+}
+
+int /*long*/ convertRgn(int /*long*/ rgn, double[] matrix) {
+	int /*long*/ newRgn = OS.gdk_region_new();
+	int[] nRects = new int[1];
+	int /*long*/[] rects = new int /*long*/[1];
+	OS.gdk_region_get_rectangles(rgn, rects, nRects);
+	GdkRectangle rect = new GdkRectangle();
+	int[] pointArray = new int[8];
+	double[] x = new double[1], y = new double[1];
+	for (int i=0; i<nRects[0]; i++) {
+		OS.memmove(rect, rects[0] + (i * GdkRectangle.sizeof), GdkRectangle.sizeof);
+		x[0] = rect.x;
+		y[0] = rect.y;
+		Cairo.cairo_matrix_transform_point(matrix, x, y);
+		pointArray[0] = (int)x[0];
+		pointArray[1] = (int)y[0];
+		x[0] = rect.x + rect.width;
+		y[0] = rect.y;
+		Cairo.cairo_matrix_transform_point(matrix, x, y);
+		pointArray[2] = (int)Math.round(x[0]);
+		pointArray[3] = (int)y[0];
+		x[0] = rect.x + rect.width;
+		y[0] = rect.y + rect.height;
+		Cairo.cairo_matrix_transform_point(matrix, x, y);
+		pointArray[4] = (int)Math.round(x[0]);
+		pointArray[5] = (int)Math.round(y[0]);
+		x[0] = rect.x;
+		y[0] = rect.y + rect.height;
+		Cairo.cairo_matrix_transform_point(matrix, x, y);
+		pointArray[6] = (int)x[0];
+		pointArray[7] = (int)Math.round(y[0]);
+		int /*long*/ polyRgn = OS.gdk_region_polygon(pointArray, pointArray.length / 2, OS.GDK_EVEN_ODD_RULE);
+		OS.gdk_region_union(newRgn, polyRgn);
+		OS.gdk_region_destroy(polyRgn);
+	}
+	if (rects[0] != 0) OS.g_free(rects[0]);
+	return newRgn;
+}
+
+/**
+ * Copies a rectangular area of the receiver at the specified
+ * position into the image, which must be of type <code>SWT.BITMAP</code>.
+ *
+ * @param image the image to copy into
+ * @param x the x coordinate in the receiver of the area to be copied
+ * @param y the y coordinate in the receiver of the area to be copied
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image is not a bitmap or has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void copyArea(Image image, int x, int y) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (image.type != SWT.BITMAP || image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	Rectangle rect = image.getBounds();
+	int /*long*/ gdkGC = OS.gdk_gc_new(image.pixmap);
+	if (gdkGC == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	OS.gdk_gc_set_subwindow(gdkGC, OS.GDK_INCLUDE_INFERIORS);
+	OS.gdk_draw_drawable(image.pixmap, gdkGC, data.drawable, x, y, 0, 0, rect.width, rect.height);
+	OS.g_object_unref(gdkGC);
+}
+
+/**
+ * Copies a rectangular area of the receiver at the source
+ * position onto the receiver at the destination position.
+ *
+ * @param srcX the x coordinate in the receiver of the area to be copied
+ * @param srcY the y coordinate in the receiver of the area to be copied
+ * @param width the width of the area to copy
+ * @param height the height of the area to copy
+ * @param destX the x coordinate in the receiver of the area to copy to
+ * @param destY the y coordinate in the receiver of the area to copy to
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) {
+	copyArea(srcX, srcY, width, height, destX, destY, true);
+}
+/**
+ * Copies a rectangular area of the receiver at the source
+ * position onto the receiver at the destination position.
+ *
+ * @param srcX the x coordinate in the receiver of the area to be copied
+ * @param srcY the y coordinate in the receiver of the area to be copied
+ * @param width the width of the area to copy
+ * @param height the height of the area to copy
+ * @param destX the x coordinate in the receiver of the area to copy to
+ * @param destY the y coordinate in the receiver of the area to copy to
+ * @param paint if <code>true</code> paint events will be generated for old and obscured areas
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, boolean paint) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (width <= 0 || height <= 0) return;
+	int deltaX = destX - srcX, deltaY = destY - srcY;
+	if (deltaX == 0 && deltaY == 0) return;
+	int /*long*/ drawable = data.drawable;
+	if (data.image == null && paint) OS.gdk_gc_set_exposures(handle, true);
+	OS.gdk_draw_drawable(drawable, handle, drawable, srcX, srcY, destX, destY, width, height);
+	if (data.image == null & paint) {
+		OS.gdk_gc_set_exposures(handle, false);
+		boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY);
+		GdkRectangle rect = new GdkRectangle ();
+		if (disjoint) {
+			rect.x = srcX;
+			rect.y = srcY;
+			rect.width = width;
+			rect.height = height;
+			OS.gdk_window_invalidate_rect (drawable, rect, false);
+//			OS.gdk_window_clear_area_e(drawable, srcX, srcY, width, height);
+		} else {
+			if (deltaX != 0) {
+				int newX = destX - deltaX;
+				if (deltaX < 0) newX = destX + width;
+				rect.x = newX;
+				rect.y = srcY;
+				rect.width = Math.abs(deltaX);
+				rect.height = height;
+				OS.gdk_window_invalidate_rect (drawable, rect, false);
+//				OS.gdk_window_clear_area_e(drawable, newX, srcY, Math.abs(deltaX), height);
+			}
+			if (deltaY != 0) {
+				int newY = destY - deltaY;
+				if (deltaY < 0) newY = destY + height;
+				rect.x = srcX;
+				rect.y = newY;
+				rect.width = width;
+				rect.height = Math.abs(deltaY);
+				OS.gdk_window_invalidate_rect (drawable, rect, false);
+//				OS.gdk_window_clear_area_e(drawable, srcX, newY, width, Math.abs(deltaY));
+			}
+		}
+	}
+}
+
+void createLayout() {
+	int /*long*/ context = OS.gdk_pango_context_get();
+	if (context == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	data.context = context;
+	int /*long*/ layout = OS.pango_layout_new(context);
+	if (layout == 0) SWT.error(SWT.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.gdk_pango_context_set_colormap(context, OS.gdk_colormap_get_system());
+	if (OS.GTK_VERSION >= OS.VERSION(2, 4, 0)) {
+		OS.pango_layout_set_auto_dir(layout, false);
+	}
+}
+
+void disposeLayout() {
+	data.string = null;
+	if (data.context != 0) OS.g_object_unref(data.context);
+	if (data.layout != 0) OS.g_object_unref(data.layout);
+	data.layout = data.context = 0;
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the graphics context. Applications must dispose of all GCs
+ * which they allocate.
+ *
+ * @exception SWTError <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ */
+public void dispose() {
+	if (handle == 0) return;
+	if (data.device.isDisposed()) return;
+
+	if (data.disposeCairo) {
+		int /*long*/ cairo = data.cairo;
+		if (cairo != 0) Cairo.cairo_destroy(cairo);
+		data.cairo = 0;
+	}
+
+	/* Free resources */
+	int /*long*/ clipRgn = data.clipRgn;
+	if (clipRgn != 0) OS.gdk_region_destroy(clipRgn);
+	Image image = data.image;
+	if (image != null) {
+		image.memGC = null;
+		if (image.transparentPixel != -1) image.createMask();
+	}
+
+	disposeLayout();
+
+	/* Dispose the GC */
+	Device device = data.device;
+	drawable.internal_dispose_GC(handle, data);
+
+	data.drawable = data.clipRgn = 0;
+	drawable = null;
+	handle = 0;
+	data.image = null;
+	data.string = null;
+	if (device.tracking) device.dispose_Object(this);
+	data.device = null;
+	data = null;
+}
+
+/**
+ * Draws the outline of a circular or elliptical arc
+ * within the specified rectangular area.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends
+ * for <code>arcAngle</code> degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ * </p><p>
+ * The center of the arc is the center of the rectangle whose origin
+ * is (<code>x</code>, <code>y</code>) and whose size is specified by the
+ * <code>width</code> and <code>height</code> arguments.
+ * </p><p>
+ * The resulting arc covers an area <code>width + 1</code> pixels wide
+ * by <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper-left corner of the arc to be drawn
+ * @param y the y coordinate of the upper-left corner of the arc to be drawn
+ * @param width the width of the arc to be drawn
+ * @param height the height of the arc to be drawn
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(DRAW);
+	if (width < 0) {
+		x = x + width;
+		width = -width;
+	}
+	if (height < 0) {
+		y = y + height;
+		height = -height;
+	}
+	if (width == 0 || height == 0 || arcAngle == 0) return;
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		double xOffset = data.cairoXoffset, yOffset = data.cairoYoffset;
+		if (width == height) {
+            if (arcAngle >= 0) {
+                Cairo.cairo_arc_negative(cairo, x + xOffset + width / 2f, y + yOffset + height / 2f, width / 2f, -startAngle * (float)Compatibility.PI / 180, -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+            } else {
+                Cairo.cairo_arc(cairo, x + xOffset + width / 2f, y + yOffset + height / 2f, width / 2f, -startAngle * (float)Compatibility.PI / 180, -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+            }
+		} else {
+			Cairo.cairo_save(cairo);
+			Cairo.cairo_translate(cairo, x + xOffset + width / 2f, y + yOffset + height / 2f);
+			Cairo.cairo_scale(cairo, width / 2f, height / 2f);
+            if (arcAngle >= 0) {
+                Cairo.cairo_arc_negative(cairo, 0, 0, 1, -startAngle * (float)Compatibility.PI / 180, -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+            } else {
+                Cairo.cairo_arc(cairo, 0, 0, 1, -startAngle * (float)Compatibility.PI / 180, -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+            }
+			Cairo.cairo_restore(cairo);
+		}
+		Cairo.cairo_stroke(cairo);
+		return;
+	}
+	OS.gdk_draw_arc(data.drawable, handle, 0, x, y, width, height, startAngle * 64, arcAngle * 64);
+}
+
+/**
+ * Draws a rectangle, based on the specified arguments, which has
+ * the appearance of the platform's <em>focus rectangle</em> if the
+ * platform supports such a notion, and otherwise draws a simple
+ * rectangle in the receiver's foreground color.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void drawFocus(int x, int y, int width, int height) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	/*
+	* Feature in GTK.  The function gtk_widget_get_default_style()
+	* can't be used here because gtk_paint_focus() uses GCs, which
+	* are not valid in the default style. The fix is to use a style
+	* from a widget.
+	*/
+	int /*long*/ style = OS.gtk_widget_get_style(data.device.shellHandle);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		checkGC(FOREGROUND);
+		int[] lineWidth = new int[1];
+		OS.gtk_widget_style_get(data.device.shellHandle, OS.focus_line_width, lineWidth, 0);
+		Cairo.cairo_save(cairo);
+		Cairo.cairo_set_line_width(cairo, lineWidth[0]);
+		double[] dashes = new double[]{1, 1};
+		double dash_offset = -lineWidth[0] / 2f;
+		while (dash_offset < 0) dash_offset += 2;
+		Cairo.cairo_set_dash(cairo, dashes, dashes.length, dash_offset);
+		Cairo.cairo_rectangle(cairo, x + lineWidth[0] / 2f, y + lineWidth[0] / 2f, width, height);
+		Cairo.cairo_stroke(cairo);
+		Cairo.cairo_restore(cairo);
+		return;
+	}
+	OS.gtk_paint_focus(style, data.drawable, OS.GTK_STATE_NORMAL, null, data.device.shellHandle, new byte[1], x, y, width, height);
+}
+
+/**
+ * Draws the given image in the receiver at the specified
+ * coordinates.
+ *
+ * @param image the image to draw
+ * @param x the x coordinate of where to draw
+ * @param y the y coordinate of where to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the given coordinates are outside the bounds of the image</li>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
+ * </ul>
+ */
+public void drawImage(Image image, int x, int y) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true);
+}
+
+/**
+ * Copies a rectangular area from the source image into a (potentially
+ * different sized) rectangular area in the receiver. If the source
+ * and destination areas are of differing sizes, then the source
+ * area will be stretched or shrunk to fit the destination area
+ * as it is copied. The copy fails if any part of the source rectangle
+ * lies outside the bounds of the source image, or if any of the width
+ * or height arguments are negative.
+ *
+ * @param image the source image
+ * @param srcX the x coordinate in the source image to copy from
+ * @param srcY the y coordinate in the source image to copy from
+ * @param srcWidth the width in pixels to copy from the source
+ * @param srcHeight the height in pixels to copy from the source
+ * @param destX the x coordinate in the destination to copy to
+ * @param destY the y coordinate in the destination to copy to
+ * @param destWidth the width in pixels of the destination rectangle
+ * @param destHeight the height in pixels of the destination rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if any of the width or height arguments are negative.
+ *    <li>ERROR_INVALID_ARGUMENT - if the source rectangle is not contained within the bounds of the source image</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
+ * </ul>
+ */
+public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return;
+	if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) {
+		SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+	}
+	if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false);
+}
+
+void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
+	int[] width = new int[1];
+	int[] height = new int[1];
+ 	OS.gdk_drawable_get_size(srcImage.pixmap, width, height);
+ 	int imgWidth = width[0];
+ 	int imgHeight = height[0];
+ 	if (simple) {
+ 		srcWidth = destWidth = imgWidth;
+ 		srcHeight = destHeight = imgHeight;
+ 	} else {
+ 		simple = srcX == 0 && srcY == 0 &&
+ 			srcWidth == destWidth && destWidth == imgWidth &&
+ 			srcHeight == destHeight && destHeight == imgHeight;
+		if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+		}
+ 	}
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		if (data.alpha != 0) {
+			srcImage.createSurface();
+			Cairo.cairo_save(cairo);
+			Cairo.cairo_rectangle(cairo, destX , destY, destWidth, destHeight);
+			Cairo.cairo_clip(cairo);
+			Cairo.cairo_translate(cairo, destX - srcX, destY - srcY);
+			if (srcWidth != destWidth || srcHeight != destHeight) {
+				Cairo.cairo_scale(cairo, destWidth / (float)srcWidth,  destHeight / (float)srcHeight);
+			}
+			int filter = Cairo.CAIRO_FILTER_GOOD;
+			switch (data.interpolation) {
+				case SWT.DEFAULT: filter = Cairo.CAIRO_FILTER_GOOD; break;
+				case SWT.NONE: filter = Cairo.CAIRO_FILTER_NEAREST; break;
+				case SWT.LOW: filter = Cairo.CAIRO_FILTER_FAST; break;
+				case SWT.HIGH: filter = Cairo.CAIRO_FILTER_BEST; break;
+			}
+			int /*long*/ pattern = Cairo.cairo_pattern_create_for_surface(srcImage.surface);
+			if (pattern == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+			if (srcWidth != destWidth || srcHeight != destHeight) {
+				/*
+				* Bug in Cairo.  When drawing the image streched with an interpolation
+				* alghorithm, the edges of the image are faded.  This is not a bug, but
+				* it is not desired.  To avoid the faded edges, it should be possible to
+				* use cairo_pattern_set_extend() to set the pattern extend to either
+				* CAIRO_EXTEND_REFLECT or CAIRO_EXTEND_PAD, but these are not implemented
+				* in some versions of cairo (1.2.x) and have bugs in others (in 1.4.2 it
+				* draws with black edges).  The fix is to implement CAIRO_EXTEND_REFLECT
+				* by creating an image that is 3 times bigger than the original, drawing
+				* the original image in every quadrant (with an appropriate transform) and
+				* use this image as the pattern.
+				*
+				* NOTE: For some reaons, it is necessary to use CAIRO_EXTEND_PAD with
+				* the image that was created or the edges are still faded.
+				*/
+				if (Cairo.cairo_version () >= Cairo.CAIRO_VERSION_ENCODE(1, 4, 0)) {
+					int /*long*/ surface = Cairo.cairo_image_surface_create(Cairo.CAIRO_FORMAT_ARGB32, imgWidth * 3, imgHeight * 3);
+					int /*long*/ cr = Cairo.cairo_create(surface);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, imgWidth, imgHeight);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_scale(cr, -1, -1);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, -imgWidth, -imgHeight);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, -imgWidth * 3, -imgHeight);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, -imgWidth, -imgHeight * 3);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, -imgWidth * 3, -imgHeight * 3);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_scale(cr, 1, -1);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, -imgWidth, imgHeight);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, -imgWidth * 3, imgHeight);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_scale(cr, -1, -1);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, imgWidth, -imgHeight);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_set_source_surface(cr, srcImage.surface, imgWidth, -imgHeight * 3);
+					Cairo.cairo_paint(cr);
+					Cairo.cairo_destroy(cr);
+					int /*long*/ newPattern = Cairo.cairo_pattern_create_for_surface(surface);
+					Cairo.cairo_surface_destroy(surface);
+					if (newPattern == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+					Cairo.cairo_pattern_destroy(pattern);
+					pattern = newPattern;
+					Cairo.cairo_pattern_set_extend(pattern, Cairo.CAIRO_EXTEND_PAD);
+					double[] matrix = new double[6];
+					Cairo.cairo_matrix_init_translate(matrix, imgWidth, imgHeight);
+					Cairo.cairo_pattern_set_matrix(pattern, matrix);
+				}
+//				Cairo.cairo_pattern_set_extend(pattern, Cairo.CAIRO_EXTEND_REFLECT);
+			}
+			Cairo.cairo_pattern_set_filter(pattern, filter);
+			Cairo.cairo_set_source(cairo, pattern);
+			if (data.alpha != 0xFF) {
+				Cairo.cairo_paint_with_alpha(cairo, data.alpha / (float)0xFF);
+			} else {
+				Cairo.cairo_paint(cairo);
+			}
+			Cairo.cairo_restore(cairo);
+			Cairo.cairo_pattern_destroy(pattern);
+		}
+		return;
+	}
+	if (srcImage.alpha != -1 || srcImage.alphaData != null) {
+		drawImageAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight);
+	} else if (srcImage.transparentPixel != -1 || srcImage.mask != 0) {
+		drawImageMask(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight);
+	} else {
+		drawImage(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight);
+	}
+}
+void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight) {
+	if (srcWidth == destWidth && srcHeight == destHeight) {
+		OS.gdk_draw_drawable(data.drawable, handle, srcImage.pixmap, srcX, srcY, destX, destY, destWidth, destHeight);
+	} else {
+		if (device.useXRender) {
+			drawImageXRender(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight, 0, -1);
+			return;
+		}
+		int /*long*/ pixbuf = scale(srcImage.pixmap, srcX, srcY, srcWidth, srcHeight, destWidth, destHeight);
+		if (pixbuf != 0) {
+			OS.gdk_pixbuf_render_to_drawable(pixbuf, data.drawable, handle, 0, 0, destX, destY, destWidth, destHeight, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
+			OS.g_object_unref(pixbuf);
+		}
+	}
+}
+void drawImageAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight) {
+	if (srcImage.alpha == 0) return;
+	if (srcImage.alpha == 255) {
+		drawImage(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight);
+		return;
+	}
+	if (device.useXRender) {
+		drawImageXRender(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight, srcImage.mask, OS.PictStandardA8);
+		return;
+	}
+	int /*long*/ pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, true, 8, srcWidth, srcHeight);
+	if (pixbuf == 0) return;
+	int /*long*/ colormap = OS.gdk_colormap_get_system();
+	OS.gdk_pixbuf_get_from_drawable(pixbuf, srcImage.pixmap, colormap, srcX, srcY, 0, 0, srcWidth, srcHeight);
+	int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+	int /*long*/ pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+	byte[] line = new byte[stride];
+	byte alpha = (byte)srcImage.alpha;
+	byte[] alphaData = srcImage.alphaData;
+	for (int y=0; y<srcHeight; y++) {
+		int alphaIndex = (y + srcY) * imgWidth + srcX;
+		OS.memmove(line, pixels + (y * stride), stride);
+		for (int x=3; x<stride; x+=4) {
+			line[x] = alphaData == null ? alpha : alphaData[alphaIndex++];
+		}
+		OS.memmove(pixels + (y * stride), line, stride);
+	}
+	if (srcWidth != destWidth || srcHeight != destHeight) {
+		int /*long*/ scaledPixbuf = OS.gdk_pixbuf_scale_simple(pixbuf, destWidth, destHeight, OS.GDK_INTERP_BILINEAR);
+		OS.g_object_unref(pixbuf);
+		if (scaledPixbuf == 0) return;
+		pixbuf = scaledPixbuf;
+	}
+	/*
+	* Feature in GTK.  gdk_draw_pixbuf was introduced in GTK+ 2.2.0 and
+	* supports clipping.
+	*/
+	if (OS.GTK_VERSION >= OS.VERSION (2, 2, 0)) {
+		OS.gdk_draw_pixbuf(data.drawable, handle, pixbuf, 0, 0, destX, destY, destWidth, destHeight, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
+	} else {
+		OS.gdk_pixbuf_render_to_drawable_alpha(pixbuf, data.drawable, 0, 0, destX, destY, destWidth, destHeight, OS.GDK_PIXBUF_ALPHA_BILEVEL, 128, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
+	}
+	OS.g_object_unref(pixbuf);
+}
+void drawImageMask(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight) {
+	int /*long*/ drawable = data.drawable;
+	int /*long*/ colorPixmap = srcImage.pixmap;
+	/* Generate the mask if necessary. */
+	if (srcImage.transparentPixel != -1) srcImage.createMask();
+	int /*long*/ maskPixmap = srcImage.mask;
+
+	if (device.useXRender) {
+		drawImageXRender(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight, maskPixmap, OS.PictStandardA1);
+	} else {
+		if (srcWidth != destWidth || srcHeight != destHeight) {
+			int /*long*/ pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, true, 8, srcWidth, srcHeight);
+			if (pixbuf != 0) {
+				int /*long*/ colormap = OS.gdk_colormap_get_system();
+				OS.gdk_pixbuf_get_from_drawable(pixbuf, colorPixmap, colormap, srcX, srcY, 0, 0, srcWidth, srcHeight);
+				int /*long*/ maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, srcWidth, srcHeight);
+				if (maskPixbuf != 0) {
+					OS.gdk_pixbuf_get_from_drawable(maskPixbuf, maskPixmap, 0, srcX, srcY, 0, 0, srcWidth, srcHeight);
+					int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+					int /*long*/ pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+					byte[] line = new byte[stride];
+					int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf);
+					int /*long*/ maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf);
+					byte[] maskLine = new byte[maskStride];
+					for (int y=0; y<srcHeight; y++) {
+						int /*long*/ offset = pixels + (y * stride);
+						OS.memmove(line, offset, stride);
+						int /*long*/ maskOffset = maskPixels + (y * maskStride);
+						OS.memmove(maskLine, maskOffset, maskStride);
+						for (int x=0; x<srcWidth; x++) {
+							if (maskLine[x * 3] == 0) {
+								line[x*4+3] = 0;
+							}
+						}
+						OS.memmove(offset, line, stride);
+					}
+					OS.g_object_unref(maskPixbuf);
+					int /*long*/ scaledPixbuf = OS.gdk_pixbuf_scale_simple(pixbuf, destWidth, destHeight, OS.GDK_INTERP_BILINEAR);
+					if (scaledPixbuf != 0) {
+						int /*long*/[] colorBuffer = new int /*long*/[1];
+						int /*long*/[] maskBuffer = new int /*long*/[1];
+						OS.gdk_pixbuf_render_pixmap_and_mask(scaledPixbuf, colorBuffer, maskBuffer, 128);
+						colorPixmap = colorBuffer[0];
+						maskPixmap = maskBuffer[0];
+						OS.g_object_unref(scaledPixbuf);
+					}
+				}
+				OS.g_object_unref(pixbuf);
+			}
+			srcX = 0;
+			srcY = 0;
+			srcWidth = destWidth;
+			srcHeight = destHeight;
+		}
+
+		/* Merge clipping with mask if necessary */
+		if (data.clipRgn != 0)	 {
+			int newWidth =  srcX + srcWidth;
+			int newHeight = srcY + srcHeight;
+			int bytesPerLine = (newWidth + 7) / 8;
+			byte[] maskData = new byte[bytesPerLine * newHeight];
+			int /*long*/ mask = OS.gdk_bitmap_create_from_data(0, maskData, newWidth, newHeight);
+			if (mask != 0) {
+				int /*long*/ gc = OS.gdk_gc_new(mask);
+				OS.gdk_region_offset(data.clipRgn, -destX + srcX, -destY + srcY);
+				OS.gdk_gc_set_clip_region(gc, data.clipRgn);
+				OS.gdk_region_offset(data.clipRgn, destX - srcX, destY - srcY);
+				GdkColor color = new GdkColor();
+				color.pixel = 1;
+				OS.gdk_gc_set_foreground(gc, color);
+				OS.gdk_draw_rectangle(mask, gc, 1, 0, 0, newWidth, newHeight);
+				OS.gdk_gc_set_function(gc, OS.GDK_AND);
+				OS.gdk_draw_drawable(mask, gc, maskPixmap, 0, 0, 0, 0, newWidth, newHeight);
+				OS.g_object_unref(gc);
+				if (maskPixmap != 0 && srcImage.mask != maskPixmap) OS.g_object_unref(maskPixmap);
+				maskPixmap = mask;
+			}
+		}
+
+		/* Blit cliping the mask */
+		GdkGCValues values = new GdkGCValues();
+		OS.gdk_gc_get_values(handle, values);
+		OS.gdk_gc_set_clip_mask(handle, maskPixmap);
+		OS.gdk_gc_set_clip_origin(handle, destX - srcX, destY - srcY);
+		OS.gdk_draw_drawable(drawable, handle, colorPixmap, srcX, srcY, destX, destY, srcWidth, srcHeight);
+		OS.gdk_gc_set_values(handle, values, OS.GDK_GC_CLIP_MASK | OS.GDK_GC_CLIP_X_ORIGIN | OS.GDK_GC_CLIP_Y_ORIGIN);
+		if (data.clipRgn != 0) OS.gdk_gc_set_clip_region(handle, data.clipRgn);
+	}
+
+	/* Destroy scaled pixmaps */
+	if (colorPixmap != 0 && srcImage.pixmap != colorPixmap) OS.g_object_unref(colorPixmap);
+	if (maskPixmap != 0 && srcImage.mask != maskPixmap) OS.g_object_unref(maskPixmap);
+	/* Destroy the image mask if the there is a GC created on the image */
+	if (srcImage.transparentPixel != -1 && srcImage.memGC != null) srcImage.destroyMask();
+}
+void drawImageXRender(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight, int /*long*/ maskPixmap, int maskType) {
+	int translateX = 0, translateY = 0;
+	int /*long*/ drawable = data.drawable;
+	if (data.image == null) {
+		int[] x = new int[1], y = new int[1];
+		int /*long*/ [] real_drawable = new int /*long*/ [1];
+		OS.gdk_window_get_internal_paint_info(drawable, real_drawable, x, y);
+		drawable = real_drawable[0];
+		translateX = -x[0];
+		translateY = -y[0];
+	}
+	int /*long*/ xDisplay = OS.GDK_DISPLAY();
+	int /*long*/ maskPict = 0;
+	if (maskPixmap != 0) {
+		int attribCount = 0;
+		XRenderPictureAttributes attrib = null;
+		if (srcImage.alpha != -1) {
+			attribCount = 1;
+			attrib = new XRenderPictureAttributes();
+			attrib.repeat = true;
+		}
+		maskPict = OS.XRenderCreatePicture(xDisplay, OS.gdk_x11_drawable_get_xid(maskPixmap), OS.XRenderFindStandardFormat(xDisplay, maskType), attribCount, attrib);
+		if (maskPict == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	}
+	int /*long*/ format = OS.XRenderFindVisualFormat(xDisplay, OS.gdk_x11_visual_get_xvisual(OS.gdk_visual_get_system()));
+	int /*long*/ destPict = OS.XRenderCreatePicture(xDisplay, OS.gdk_x11_drawable_get_xid(drawable), format, 0, null);
+	if (destPict == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	int /*long*/ srcPict = OS.XRenderCreatePicture(xDisplay, OS.gdk_x11_drawable_get_xid(srcImage.pixmap), format, 0, null);
+	if (srcPict == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	if (srcWidth != destWidth || srcHeight != destHeight) {
+		int[] transform = new int[]{(int)(((float)srcWidth / destWidth) * 65536), 0, 0, 0, (int)(((float)srcHeight / destHeight) * 65536), 0, 0, 0, 65536};
+		OS.XRenderSetPictureTransform(xDisplay, srcPict, transform);
+		if (maskPict != 0) OS.XRenderSetPictureTransform(xDisplay, maskPict, transform);
+		srcX *= destWidth / (float)srcWidth;
+		srcY *= destHeight / (float)srcHeight;
+	}
+	int /*long*/ clipping = data.clipRgn;
+	if (data.damageRgn != 0) {
+		if (clipping == 0) {
+			clipping = data.damageRgn;
+		} else {
+			clipping = OS.gdk_region_new();
+			OS.gdk_region_union(clipping, data.clipRgn);
+			OS.gdk_region_intersect(clipping, data.damageRgn);
+		}
+	}
+	if (clipping != 0) {
+		int[] nRects = new int[1];
+		int /*long*/[] rects = new int /*long*/[1];
+		OS.gdk_region_get_rectangles(clipping, rects, nRects);
+		GdkRectangle rect = new GdkRectangle();
+		short[] xRects = new short[nRects[0] * 4];
+		for (int i=0, j=0; i<nRects[0]; i++, j+=4) {
+			OS.memmove(rect, rects[0] + (i * GdkRectangle.sizeof), GdkRectangle.sizeof);
+			xRects[j] = (short)rect.x;
+			xRects[j+1] = (short)rect.y;
+			xRects[j+2] = (short)rect.width;
+			xRects[j+3] = (short)rect.height;
+		}
+		OS.XRenderSetPictureClipRectangles(xDisplay, destPict, translateX, translateY, xRects, nRects[0]);
+		if (clipping != data.clipRgn && clipping != data.damageRgn) {
+			OS.gdk_region_destroy(clipping);
+		}
+		if (rects[0] != 0) OS.g_free(rects[0]);
+	}
+	OS.XRenderComposite(xDisplay, maskPict != 0 ? OS.PictOpOver : OS.PictOpSrc, srcPict, maskPict, destPict, srcX, srcY, srcX, srcY, destX + translateX, destY + translateY, destWidth, destHeight);
+	OS.XRenderFreePicture(xDisplay, destPict);
+	OS.XRenderFreePicture(xDisplay, srcPict);
+	if (maskPict != 0) OS.XRenderFreePicture(xDisplay, maskPict);
+}
+int /*long*/ scale(int /*long*/ src, int srcX, int srcY, int srcWidth, int srcHeight, int destWidth, int destHeight) {
+	int /*long*/ pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, srcWidth, srcHeight);
+	if (pixbuf == 0) return 0;
+	int /*long*/ colormap = OS.gdk_colormap_get_system();
+	OS.gdk_pixbuf_get_from_drawable(pixbuf, src, colormap, srcX, srcY, 0, 0, srcWidth, srcHeight);
+	int /*long*/ scaledPixbuf = OS.gdk_pixbuf_scale_simple(pixbuf, destWidth, destHeight, OS.GDK_INTERP_BILINEAR);
+	OS.g_object_unref(pixbuf);
+	return scaledPixbuf;
+}
+
+/**
+ * Draws a line, using the foreground color, between the points
+ * (<code>x1</code>, <code>y1</code>) and (<code>x2</code>, <code>y2</code>).
+ *
+ * @param x1 the first point's x coordinate
+ * @param y1 the first point's y coordinate
+ * @param x2 the second point's x coordinate
+ * @param y2 the second point's y coordinate
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawLine(int x1, int y1, int x2, int y2) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(DRAW);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		double xOffset = data.cairoXoffset, yOffset = data.cairoYoffset;
+		Cairo.cairo_move_to(cairo, x1 + xOffset, y1 + yOffset);
+		Cairo.cairo_line_to(cairo, x2 + xOffset, y2 + yOffset);
+		Cairo.cairo_stroke(cairo);
+		return;
+	}
+	OS.gdk_draw_line (data.drawable, handle, x1, y1, x2, y2);
+}
+
+/**
+ * Draws the outline of an oval, using the foreground color,
+ * within the specified rectangular area.
+ * <p>
+ * The result is a circle or ellipse that fits within the
+ * rectangle specified by the <code>x</code>, <code>y</code>,
+ * <code>width</code>, and <code>height</code> arguments.
+ * </p><p>
+ * The oval covers an area that is <code>width + 1</code>
+ * pixels wide and <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper left corner of the oval to be drawn
+ * @param y the y coordinate of the upper left corner of the oval to be drawn
+ * @param width the width of the oval to be drawn
+ * @param height the height of the oval to be drawn
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawOval(int x, int y, int width, int height) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(DRAW);
+	if (width < 0) {
+		x = x + width;
+		width = -width;
+	}
+	if (height < 0) {
+		y = y + height;
+		height = -height;
+	}
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		double xOffset = data.cairoXoffset, yOffset = data.cairoYoffset;
+		if (width == height) {
+			Cairo.cairo_arc_negative(cairo, x + xOffset + width / 2f, y + yOffset + height / 2f, width / 2f, 0, -2 * (float)Compatibility.PI);
+		} else {
+			Cairo.cairo_save(cairo);
+			Cairo.cairo_translate(cairo, x + xOffset + width / 2f, y + yOffset + height / 2f);
+			Cairo.cairo_scale(cairo, width / 2f, height / 2f);
+			Cairo.cairo_arc_negative(cairo, 0, 0, 1, 0, -2 * (float)Compatibility.PI);
+			Cairo.cairo_restore(cairo);
+		}
+		Cairo.cairo_stroke(cairo);
+		return;
+	}
+	OS.gdk_draw_arc(data.drawable, handle, 0, x, y, width, height, 0, 23040);
+}
+
+/**
+ * Draws the path described by the parameter.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param path the path to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Path
+ *
+ * @since 3.1
+ */
+public void drawPath(Path path) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	initCairo();
+	checkGC(DRAW);
+	int /*long*/ cairo = data.cairo;
+	Cairo.cairo_save(cairo);
+	double xOffset = data.cairoXoffset, yOffset = data.cairoYoffset;
+	Cairo.cairo_translate(cairo, xOffset, yOffset);
+	int /*long*/ copy = Cairo.cairo_copy_path(path.handle);
+	if (copy == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	Cairo.cairo_append_path(cairo, copy);
+	Cairo.cairo_path_destroy(copy);
+	Cairo.cairo_stroke(cairo);
+	Cairo.cairo_restore(cairo);
+}
+
+/**
+ * Draws a pixel, using the foreground color, at the specified
+ * point (<code>x</code>, <code>y</code>).
+ * <p>
+ * Note that the receiver's line attributes do not affect this
+ * operation.
+ * </p>
+ *
+ * @param x the point's x coordinate
+ * @param y the point's y coordinate
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void drawPoint (int x, int y) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(DRAW);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		Cairo.cairo_rectangle(cairo, x, y, 1, 1);
+		Cairo.cairo_fill(cairo);
+		return;
+	}
+	OS.gdk_draw_point(data.drawable, handle, x, y);
+}
+
+/**
+ * Draws the closed polygon which is defined by the specified array
+ * of integer coordinates, using the receiver's foreground color. The array
+ * contains alternating x and y values which are considered to represent
+ * points which are the vertices of the polygon. Lines are drawn between
+ * each consecutive pair, and between the first pair and last pair in the
+ * array.
+ *
+ * @param pointArray an array of alternating x and y values which are the vertices of the polygon
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolygon(int[] pointArray) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	checkGC(DRAW);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		drawPolyline(cairo, pointArray, true);
+		Cairo.cairo_stroke(cairo);
+		return;
+	}
+	OS.gdk_draw_polygon(data.drawable, handle, 0, pointArray, pointArray.length / 2);
+}
+
+/**
+ * Draws the polyline which is defined by the specified array
+ * of integer coordinates, using the receiver's foreground color. The array
+ * contains alternating x and y values which are considered to represent
+ * points which are the corners of the polyline. Lines are drawn between
+ * each consecutive pair, but not between the first pair and last pair in
+ * the array.
+ *
+ * @param pointArray an array of alternating x and y values which are the corners of the polyline
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the point array is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolyline(int[] pointArray) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	checkGC(DRAW);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		drawPolyline(cairo, pointArray, false);
+		Cairo.cairo_stroke(cairo);
+		return;
+	}
+	OS.gdk_draw_lines(data.drawable, handle, pointArray, pointArray.length / 2);
+}
+
+void drawPolyline(int /*long*/ cairo, int[] pointArray, boolean close) {
+	int count = pointArray.length / 2;
+	if (count == 0) return;
+	double xOffset = data.cairoXoffset, yOffset = data.cairoYoffset;
+	Cairo.cairo_move_to(cairo, pointArray[0] + xOffset, pointArray[1] + yOffset);
+	for (int i = 1, j=2; i < count; i++, j += 2) {
+		Cairo.cairo_line_to(cairo, pointArray[j] + xOffset, pointArray[j + 1] + yOffset);
+	}
+	if (close) Cairo.cairo_close_path(cairo);
+}
+
+/**
+ * Draws the outline of the rectangle specified by the arguments,
+ * using the receiver's foreground color. The left and right edges
+ * of the rectangle are at <code>x</code> and <code>x + width</code>.
+ * The top and bottom edges are at <code>y</code> and <code>y + height</code>.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRectangle(int x, int y, int width, int height) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(DRAW);
+	if (width < 0) {
+		x = x + width;
+		width = -width;
+	}
+	if (height < 0) {
+		y = y + height;
+		height = -height;
+	}
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		double xOffset = data.cairoXoffset, yOffset = data.cairoYoffset;
+		Cairo.cairo_rectangle(cairo, x + xOffset, y + yOffset, width, height);
+		Cairo.cairo_stroke(cairo);
+		return;
+	}
+	OS.gdk_draw_rectangle(data.drawable, handle, 0, x, y, width, height);
+}
+
+/**
+ * Draws the outline of the specified rectangle, using the receiver's
+ * foreground color. The left and right edges of the rectangle are at
+ * <code>rect.x</code> and <code>rect.x + rect.width</code>. The top
+ * and bottom edges are at <code>rect.y</code> and
+ * <code>rect.y + rect.height</code>.
+ *
+ * @param rect the rectangle to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRectangle(Rectangle rect) {
+	if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	drawRectangle (rect.x, rect.y, rect.width, rect.height);
+}
+/**
+ * Draws the outline of the round-cornered rectangle specified by
+ * the arguments, using the receiver's foreground color. The left and
+ * right edges of the rectangle are at <code>x</code> and <code>x + width</code>.
+ * The top and bottom edges are at <code>y</code> and <code>y + height</code>.
+ * The <em>roundness</em> of the corners is specified by the
+ * <code>arcWidth</code> and <code>arcHeight</code> arguments, which
+ * are respectively the width and height of the ellipse used to draw
+ * the corners.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(DRAW);
+	int nx = x;
+	int ny = y;
+	int nw = width;
+	int nh = height;
+	int naw = arcWidth;
+	int nah = arcHeight;
+	if (nw < 0) {
+		nw = 0 - nw;
+		nx = nx - nw;
+	}
+	if (nh < 0) {
+		nh = 0 - nh;
+		ny = ny -nh;
+	}
+	if (naw < 0) naw = 0 - naw;
+	if (nah < 0) nah = 0 - nah;
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		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);
+		Cairo.cairo_stroke(cairo);
+		return;
+	}
+	int naw2 = naw / 2;
+	int nah2 = nah / 2;
+	int /*long*/ drawable = data.drawable;
+	if (nw > naw) {
+		if (nh > nah) {
+			OS.gdk_draw_arc(drawable, handle, 0, nx, ny, naw, nah, 5760, 5760);
+			OS.gdk_draw_line(drawable, handle, nx + naw2, ny, nx + nw - naw2, ny);
+			OS.gdk_draw_arc(drawable, handle, 0, nx + nw - naw, ny, naw, nah, 0, 5760);
+			OS.gdk_draw_line(drawable, handle, nx + nw, ny + nah2, nx + nw, ny + nh - nah2);
+			OS.gdk_draw_arc(drawable, handle, 0, nx + nw - naw, ny + nh - nah, naw, nah, 17280, 5760);
+			OS.gdk_draw_line(drawable,handle, nx + naw2, ny + nh, nx + nw - naw2, ny + nh);
+			OS.gdk_draw_arc(drawable, handle, 0, nx, ny + nh - nah, naw, nah, 11520, 5760);
+			OS.gdk_draw_line(drawable, handle,  nx, ny + nah2, nx, ny + nh - nah2);
+		} else {
+			OS.gdk_draw_arc(drawable, handle, 0, nx, ny, naw, nh, 5760, 11520);
+			OS.gdk_draw_line(drawable, handle, nx + naw2, ny, nx + nw - naw2, ny);
+			OS.gdk_draw_arc(drawable, handle, 0, nx + nw - naw, ny, naw, nh, 17280, 11520);
+			OS.gdk_draw_line(drawable,handle, nx + naw2, ny + nh, nx + nw - naw2, ny + nh);
+		}
+	} else {
+		if (nh > nah) {
+			OS.gdk_draw_arc(drawable, handle, 0, nx, ny, nw, nah, 0, 11520);
+			OS.gdk_draw_line(drawable, handle, nx + nw, ny + nah2, nx + nw, ny + nh - nah2);
+			OS.gdk_draw_arc(drawable, handle, 0, nx, ny + nh - nah, nw, nah, 11520, 11520);
+			OS.gdk_draw_line(drawable,handle, nx, ny + nah2, nx, ny + nh - nah2);
+		} else {
+			OS.gdk_draw_arc(drawable, handle, 0, nx, ny, nw, nh, 0, 23040);
+		}
+	}
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. No tab expansion or carriage return processing
+ * will be performed. The background of the rectangular area where
+ * the string is being drawn will be filled with the receiver's
+ * background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawString (String string, int x, int y) {
+	drawString(string, x, y, false);
+}
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. No tab expansion or carriage return processing
+ * will be performed. If <code>isTransparent</code> is <code>true</code>,
+ * then the background of the rectangular area where the string is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawString(String string, int x, int y, boolean isTransparent) {
+	drawText(string, x, y, isTransparent ? SWT.DRAW_TRANSPARENT : 0);
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion and carriage return processing
+ * are performed. The background of the rectangular area where
+ * the text is being drawn will be filled with the receiver's
+ * background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText(String string, int x, int y) {
+	drawText(string, x, y, SWT.DRAW_DELIMITER | SWT.DRAW_TAB);
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion and carriage return processing
+ * are performed. If <code>isTransparent</code> is <code>true</code>,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText(String string, int x, int y, boolean isTransparent) {
+	int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB;
+	if (isTransparent) flags |= SWT.DRAW_TRANSPARENT;
+	drawText(string, x, y, flags);
+}
+
+/**
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion, line delimiter and mnemonic
+ * processing are performed according to the specified flags. If
+ * <code>flags</code> includes <code>DRAW_TRANSPARENT</code>,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ * <p>
+ * The parameter <code>flags</code> may be a combination of:
+ * <dl>
+ * <dt><b>DRAW_DELIMITER</b></dt>
+ * <dd>draw multiple lines</dd>
+ * <dt><b>DRAW_TAB</b></dt>
+ * <dd>expand tabs</dd>
+ * <dt><b>DRAW_MNEMONIC</b></dt>
+ * <dd>underline the mnemonic character</dd>
+ * <dt><b>DRAW_TRANSPARENT</b></dt>
+ * <dd>transparent background</dd>
+ * </dl>
+ * </p>
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param flags the flags specifying how to process the text
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText (String string, int x, int y, int flags) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (string.length() == 0) return;
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		if (OS.GTK_VERSION < OS.VERSION(2, 8, 0)) {
+			//TODO - honor flags
+			checkGC(FOREGROUND | FONT);
+			cairo_font_extents_t extents = new cairo_font_extents_t();
+			Cairo.cairo_font_extents(cairo, extents);
+			double baseline = y + extents.ascent;
+			Cairo.cairo_move_to(cairo, x, baseline);
+			byte[] buffer = Converter.wcsToMbcs(null, string, true);
+			Cairo.cairo_show_text(cairo, buffer);
+			Cairo.cairo_new_path(cairo);
+			return;
+		}
+	}
+	setString(string, flags);
+	if (cairo != 0) {
+		if ((flags & SWT.DRAW_TRANSPARENT) == 0) {
+			checkGC(BACKGROUND);
+			int[] width = new int[1], height = new int[1];
+			OS.pango_layout_get_size(data.layout, width, height);
+			Cairo.cairo_rectangle(cairo, x, y, OS.PANGO_PIXELS(width[0]), OS.PANGO_PIXELS(height[0]));
+			Cairo.cairo_fill(cairo);
+		}
+		checkGC(FOREGROUND | FONT);
+		Cairo.cairo_move_to(cairo, x, y);
+		OS.pango_cairo_show_layout(cairo, data.layout);
+		return;
+	}
+	checkGC(FOREGROUND | FONT | BACKGROUND_BG);
+	GdkColor background = null;
+	if ((flags & SWT.DRAW_TRANSPARENT) == 0) background = data.background;
+	if (!data.xorMode) {
+		OS.gdk_draw_layout_with_colors(data.drawable, handle, x, y, data.layout, null, background);
+	} else {
+		int /*long*/ layout = data.layout;
+		int[] w = new int[1], h = new int[1];
+		OS.pango_layout_get_size(layout, w, h);
+		int width = OS.PANGO_PIXELS(w[0]);
+		int height = OS.PANGO_PIXELS(h[0]);
+		int /*long*/ pixmap = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, -1);
+		if (pixmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+		int /*long*/ gdkGC = OS.gdk_gc_new(pixmap);
+		if (gdkGC == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+		GdkColor black = new GdkColor();
+		OS.gdk_gc_set_foreground(gdkGC, black);
+		OS.gdk_draw_rectangle(pixmap, gdkGC, 1, 0, 0, width, height);
+		OS.gdk_gc_set_foreground(gdkGC, data.foreground);
+		OS.gdk_draw_layout_with_colors(pixmap, gdkGC, 0, 0, layout, null, background);
+		OS.g_object_unref(gdkGC);
+		OS.gdk_draw_drawable(data.drawable, handle, pixmap, 0, 0, x, y, width, height);
+		OS.g_object_unref(pixmap);
+	}
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public boolean equals(Object object) {
+	if (object == this) return true;
+	if (!(object instanceof GC)) return false;
+	return handle == ((GC)object).handle;
+}
+
+/**
+ * Fills the interior of a circular or elliptical arc within
+ * the specified rectangular area, with the receiver's background
+ * color.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends
+ * for <code>arcAngle</code> degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ * </p><p>
+ * The center of the arc is the center of the rectangle whose origin
+ * is (<code>x</code>, <code>y</code>) and whose size is specified by the
+ * <code>width</code> and <code>height</code> arguments.
+ * </p><p>
+ * The resulting arc covers an area <code>width + 1</code> pixels wide
+ * by <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper-left corner of the arc to be filled
+ * @param y the y coordinate of the upper-left corner of the arc to be filled
+ * @param width the width of the arc to be filled
+ * @param height the height of the arc to be filled
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawArc
+ */
+public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(FILL);
+	if (width < 0) {
+		x = x + width;
+		width = -width;
+	}
+	if (height < 0) {
+		y = y + height;
+		height = -height;
+	}
+	if (width == 0 || height == 0 || arcAngle == 0) return;
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		if (width == height) {
+            if (arcAngle >= 0) {
+            	Cairo.cairo_arc_negative(cairo, x + width / 2f, y + height / 2f, width / 2f, -startAngle * (float)Compatibility.PI / 180,  -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+            } else {
+            	Cairo.cairo_arc(cairo, x + width / 2f, y + height / 2f, width / 2f, -startAngle * (float)Compatibility.PI / 180,  -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+            }
+			Cairo.cairo_line_to(cairo, x + width / 2f, y + height / 2f);
+		} else {
+			Cairo.cairo_save(cairo);
+			Cairo.cairo_translate(cairo, x + width / 2f, y + height / 2f);
+			Cairo.cairo_scale(cairo, width / 2f, height / 2f);
+			if (arcAngle >= 0) {
+				Cairo.cairo_arc_negative(cairo, 0, 0, 1, -startAngle * (float)Compatibility.PI / 180,  -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+			} else {
+				Cairo.cairo_arc(cairo, 0, 0, 1, -startAngle * (float)Compatibility.PI / 180,  -(startAngle + arcAngle) * (float)Compatibility.PI / 180);
+			}
+			Cairo.cairo_line_to(cairo, 0, 0);
+			Cairo.cairo_restore(cairo);
+		}
+		Cairo.cairo_fill(cairo);
+		return;
+	}
+	OS.gdk_draw_arc(data.drawable, handle, 1, x, y, width, height, startAngle * 64, arcAngle * 64);
+}
+
+/**
+ * Fills the interior of the specified rectangle with a gradient
+ * sweeping from left to right or top to bottom progressing
+ * from the receiver's foreground color to its background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled, may be negative
+ *        (inverts direction of gradient if horizontal)
+ * @param height the height of the rectangle to be filled, may be negative
+ *        (inverts direction of gradient if vertical)
+ * @param vertical if true sweeps from top to bottom, else
+ *        sweeps from left to right
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillGradientRectangle(int x, int y, int width, int height, boolean vertical) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if ((width == 0) || (height == 0)) return;
+
+	/* Rewrite this to use GdkPixbuf */
+
+	RGB backgroundRGB, foregroundRGB;
+	backgroundRGB = getBackground().getRGB();
+	foregroundRGB = getForeground().getRGB();
+
+	RGB fromRGB, toRGB;
+	fromRGB = foregroundRGB;
+	toRGB   = backgroundRGB;
+	boolean swapColors = false;
+	if (width < 0) {
+		x += width; width = -width;
+		if (! vertical) swapColors = true;
+	}
+	if (height < 0) {
+		y += height; height = -height;
+		if (vertical) swapColors = true;
+	}
+	if (swapColors) {
+		fromRGB = backgroundRGB;
+		toRGB   = foregroundRGB;
+	}
+	if (fromRGB.equals(toRGB)) {
+		fillRectangle(x, y, width, height);
+		return;
+	}
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		int /*long*/ pattern;
+		if (vertical) {
+			pattern = Cairo.cairo_pattern_create_linear (0.0, 0.0, 0.0, 1.0);
+		} else {
+			pattern = Cairo.cairo_pattern_create_linear (0.0, 0.0, 1.0, 0.0);
+		}
+		Cairo.cairo_pattern_add_color_stop_rgba (pattern, 0, fromRGB.red / 255f, fromRGB.green / 255f, fromRGB.blue / 255f, data.alpha / 255f);
+		Cairo.cairo_pattern_add_color_stop_rgba (pattern, 1, toRGB.red / 255f, toRGB.green / 255f, toRGB.blue / 255f, data.alpha / 255f);
+		Cairo.cairo_save(cairo);
+		Cairo.cairo_translate(cairo, x, y);
+		Cairo.cairo_scale(cairo, width, height);
+		Cairo.cairo_rectangle(cairo, 0, 0, 1, 1);
+		Cairo.cairo_set_source(cairo, pattern);
+		Cairo.cairo_fill(cairo);
+		Cairo.cairo_restore(cairo);
+		Cairo.cairo_pattern_destroy(pattern);
+		return;
+	}
+	ImageData.fillGradientRectangle(this, data.device,
+		x, y, width, height, vertical, fromRGB, toRGB,
+		8, 8, 8);
+}
+
+/**
+ * Fills the interior of an oval, within the specified
+ * rectangular area, with the receiver's background
+ * color.
+ *
+ * @param x the x coordinate of the upper left corner of the oval to be filled
+ * @param y the y coordinate of the upper left corner of the oval to be filled
+ * @param width the width of the oval to be filled
+ * @param height the height of the oval to be filled
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawOval
+ */
+public void fillOval(int x, int y, int width, int height) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(FILL);
+	if (width < 0) {
+		x = x + width;
+		width = -width;
+	}
+	if (height < 0) {
+		y = y + height;
+		height = -height;
+	}
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		if (width == height) {
+			Cairo.cairo_arc_negative(cairo, x + width / 2f, y + height / 2f, width / 2f, 0, 2 * (float)Compatibility.PI);
+		} else {
+			Cairo.cairo_save(cairo);
+			Cairo.cairo_translate(cairo, x + width / 2f, y + height / 2f);
+			Cairo.cairo_scale(cairo, width / 2f, height / 2f);
+			Cairo.cairo_arc_negative(cairo, 0, 0, 1, 0, 2 * (float)Compatibility.PI);
+			Cairo.cairo_restore(cairo);
+		}
+		Cairo.cairo_fill(cairo);
+		return;
+	}
+	OS.gdk_draw_arc(data.drawable, handle, 1, x, y, width, height, 0, 23040);
+}
+
+/**
+ * Fills the path described by the parameter.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param path the path to fill
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Path
+ *
+ * @since 3.1
+ */
+public void fillPath (Path path) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	initCairo();
+	checkGC(FILL);
+	int /*long*/ cairo = data.cairo;
+	int /*long*/ copy = Cairo.cairo_copy_path(path.handle);
+	if (copy == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	Cairo.cairo_append_path(cairo, copy);
+	Cairo.cairo_path_destroy(copy);
+	Cairo.cairo_fill(cairo);
+}
+
+/**
+ * Fills the interior of the closed polygon which is defined by the
+ * specified array of integer coordinates, using the receiver's
+ * background color. The array contains alternating x and y values
+ * which are considered to represent points which are the vertices of
+ * the polygon. Lines are drawn between each consecutive pair, and
+ * between the first pair and last pair in the array.
+ *
+ * @param pointArray an array of alternating x and y values which are the vertices of the polygon
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawPolygon
+ */
+public void fillPolygon(int[] pointArray) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	checkGC(FILL);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		drawPolyline(cairo, pointArray, true);
+		Cairo.cairo_fill(cairo);
+		return;
+	}
+	OS.gdk_draw_polygon(data.drawable, handle, 1, pointArray, pointArray.length / 2);
+}
+
+/**
+ * Fills the interior of the rectangle specified by the arguments,
+ * using the receiver's background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillRectangle(int x, int y, int width, int height) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(FILL);
+	if (width < 0) {
+		x = x + width;
+		width = -width;
+	}
+	if (height < 0) {
+		y = y + height;
+		height = -height;
+	}
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		Cairo.cairo_rectangle(cairo, x, y, width, height);
+		Cairo.cairo_fill(cairo);
+		return;
+	}
+	OS.gdk_draw_rectangle(data.drawable, handle, 1, x, y, width, height);
+}
+
+/**
+ * Fills the interior of the specified rectangle, using the receiver's
+ * background color.
+ *
+ * @param rect the rectangle to be filled
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillRectangle(Rectangle rect) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	fillRectangle(rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Fills the interior of the round-cornered rectangle specified by
+ * the arguments, using the receiver's background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRoundRectangle
+ */
+public void fillRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	checkGC(FILL);
+	int nx = x;
+	int ny = y;
+	int nw = width;
+	int nh = height;
+	int naw = arcWidth;
+	int nah = arcHeight;
+	if (nw < 0) {
+		nw = 0 - nw;
+		nx = nx - nw;
+	}
+	if (nh < 0) {
+		nh = 0 - nh;
+		ny = ny -nh;
+	}
+	if (naw < 0) naw = 0 - naw;
+	if (nah < 0) nah = 0 - nah;
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		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;
+	}
+	int naw2 = naw / 2;
+	int nah2 = nah / 2;
+	int /*long*/ drawable = data.drawable;
+	if (nw > naw) {
+		if (nh > nah) {
+			OS.gdk_draw_arc(drawable, handle, 1, nx, ny, naw, nah, 5760, 5760);
+			OS.gdk_draw_rectangle(drawable, handle, 1, nx + naw2, ny, nw - naw2 * 2, nh);
+			OS.gdk_draw_arc(drawable, handle, 1, nx + nw - naw, ny, naw, nah, 0, 5760);
+			OS.gdk_draw_rectangle(drawable, handle, 1, nx, ny + nah2, naw2, nh - nah2 * 2);
+			OS.gdk_draw_arc(drawable, handle, 1, nx + nw - naw, ny + nh - nah, naw, nah, 17280, 5760);
+			OS.gdk_draw_rectangle(drawable, handle, 1, nx + nw - naw2, ny + nah2, naw2, nh - nah2 * 2);
+			OS.gdk_draw_arc(drawable, handle, 1, nx, ny + nh - nah, naw, nah, 11520, 5760);
+		} else {
+			OS.gdk_draw_arc(drawable, handle, 1, nx, ny, naw, nh, 5760, 11520);
+			OS.gdk_draw_rectangle(drawable, handle, 1, nx + naw2, ny, nw - naw2 * 2, nh);
+			OS.gdk_draw_arc(drawable, handle, 1, nx + nw - naw, ny, naw, nh, 17280, 11520);
+		}
+	} else {
+		if (nh > nah) {
+			OS.gdk_draw_arc(drawable, handle, 1, nx, ny, nw, nah, 0, 11520);
+			OS.gdk_draw_rectangle(drawable, handle, 1, nx, ny + nah2, nw, nh - nah2 * 2);
+			OS.gdk_draw_arc(drawable, handle, 1, nx, ny + nh - nah, nw, nah, 11520, 11520);
+		} else {
+			OS.gdk_draw_arc(drawable, handle, 1, nx, ny, nw, nh, 0, 23040);
+		}
+	}
+}
+
+int fixMnemonic (char [] buffer) {
+	int i=0, j=0;
+	int mnemonic=-1;
+	while (i < buffer.length) {
+		if ((buffer [j++] = buffer [i++]) == '&') {
+			if (i == buffer.length) {continue;}
+			if (buffer [i] == '&') {i++; continue;}
+			if (mnemonic == -1) mnemonic = j;
+			j--;
+		}
+	}
+	while (j < buffer.length) buffer [j++] = 0;
+	return mnemonic;
+}
+
+/**
+ * Returns the <em>advance width</em> of the specified character in
+ * the font which is currently selected into the receiver.
+ * <p>
+ * The advance width is defined as the horizontal distance the cursor
+ * should move after printing the character in the selected font.
+ * </p>
+ *
+ * @param ch the character to measure
+ * @return the distance in the x direction to move past the character before painting the next
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getAdvanceWidth(char ch) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	//BOGUS
+	return stringExtent(new String(new char[]{ch})).x;
+}
+
+/**
+ * Returns <code>true</code> if receiver is using the operating system's
+ * advanced graphics subsystem.  Otherwise, <code>false</code> is returned
+ * to indicate that normal graphics are in use.
+ * <p>
+ * Advanced graphics may not be installed for the operating system.  In this
+ * case, <code>false</code> is always returned.  Some operating system have
+ * only one graphics subsystem.  If this subsystem supports advanced graphics,
+ * then <code>true</code> is always returned.  If any graphics operation such
+ * as alpha, antialias, patterns, interpolation, paths, clipping or transformation
+ * has caused the receiver to switch from regular to advanced graphics mode,
+ * <code>true</code> is returned.  If the receiver has been explicitly switched
+ * to advanced mode and this mode is supported, <code>true</code> is returned.
+ * </p>
+ *
+ * @return the advanced value
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public boolean getAdvanced() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.cairo != 0;
+}
+
+/**
+ * Returns the receiver's alpha value.
+ *
+ * @return the alpha value
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getAlpha() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.alpha;
+}
+
+/**
+ * Returns the receiver's anti-aliasing setting value, which will be
+ * one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
+ * <code>SWT.ON</code>. Note that this controls anti-aliasing for all
+ * <em>non-text drawing</em> operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getTextAntialias
+ *
+ * @since 3.1
+ */
+public int getAntialias() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+    if (data.cairo == 0) return SWT.DEFAULT;
+    int antialias = Cairo.cairo_get_antialias(data.cairo);
+	switch (antialias) {
+		case Cairo.CAIRO_ANTIALIAS_DEFAULT: return SWT.DEFAULT;
+		case Cairo.CAIRO_ANTIALIAS_NONE: return SWT.OFF;
+		case Cairo.CAIRO_ANTIALIAS_GRAY:
+		case Cairo.CAIRO_ANTIALIAS_SUBPIXEL: return SWT.ON;
+	}
+	return SWT.DEFAULT;
+}
+
+/**
+ * Returns the background color.
+ *
+ * @return the receiver's background color
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getBackground() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return Color.gtk_new(data.device, data.background);
+}
+
+/**
+ * Returns the background pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's background pattern
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Pattern
+ *
+ * @since 3.1
+ */
+public Pattern getBackgroundPattern() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.backgroundPattern;
+}
+
+/**
+ * Returns the width of the specified character in the font
+ * selected into the receiver.
+ * <p>
+ * The width is defined as the space taken up by the actual
+ * character, not including the leading and tailing whitespace
+ * or overhang.
+ * </p>
+ *
+ * @param ch the character to measure
+ * @return the width of the character
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getCharWidth(char ch) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	//BOGUS
+	return stringExtent(new String(new char[]{ch})).x;
+}
+
+/**
+ * Returns the bounding rectangle of the receiver's clipping
+ * region. If no clipping region is set, the return value
+ * will be a rectangle which covers the entire bounds of the
+ * object the receiver is drawing on.
+ *
+ * @return the bounding rectangle of the clipping region
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getClipping() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	/* Calculate visible bounds in device space */
+	int x = 0, y = 0, width = 0, height = 0;
+	int[] w = new int[1], h = new int[1];
+	OS.gdk_drawable_get_size(data.drawable, w, h);
+	width = w[0];
+	height = h[0];
+	/* Intersect visible bounds with clipping in device space and then convert then to user space */
+	int /*long*/ cairo = data.cairo;
+	int /*long*/ clipRgn = data.clipRgn;
+	int /*long*/ damageRgn = data.damageRgn;
+	if (clipRgn != 0 || damageRgn != 0 || cairo != 0) {
+		int /*long*/ rgn = OS.gdk_region_new();
+		GdkRectangle rect = new GdkRectangle();
+		rect.width = width;
+		rect.height = height;
+		OS.gdk_region_union_with_rect(rgn, rect);
+		if (damageRgn != 0) {
+			OS.gdk_region_intersect (rgn, damageRgn);
+		}
+		/* Intersect visible bounds with clipping */
+		if (clipRgn != 0) {
+			/* Convert clipping to device space if needed */
+			if (data.clippingTransform != null) {
+				clipRgn = convertRgn(clipRgn, data.clippingTransform);
+				OS.gdk_region_intersect(rgn, clipRgn);
+				OS.gdk_region_destroy(clipRgn);
+			} else {
+				OS.gdk_region_intersect(rgn, clipRgn);
+			}
+		}
+		/* Convert to user space */
+		if (cairo != 0) {
+			double[] matrix = new double[6];
+			Cairo.cairo_get_matrix(cairo, matrix);
+			Cairo.cairo_matrix_invert(matrix);
+			clipRgn = convertRgn(rgn, matrix);
+			OS.gdk_region_destroy(rgn);
+			rgn = clipRgn;
+		}
+		OS.gdk_region_get_clipbox(rgn, rect);
+		OS.gdk_region_destroy(rgn);
+		x = rect.x;
+		y = rect.y;
+		width = rect.width;
+		height = rect.height;
+	}
+	return new Rectangle(x, y, width, height);
+}
+
+/**
+ * Sets the region managed by the argument to the current
+ * clipping region of the receiver.
+ *
+ * @param region the region to fill with the clipping region
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the region is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getClipping(Region region) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	int /*long*/ clipping = region.handle;
+	OS.gdk_region_subtract(clipping, clipping);
+	int /*long*/ cairo = data.cairo;
+	int /*long*/ clipRgn = data.clipRgn;
+	if (clipRgn == 0) {
+		int[] width = new int[1], height = new int[1];
+		OS.gdk_drawable_get_size(data.drawable, width, height);
+		GdkRectangle rect = new GdkRectangle();
+		rect.width = width[0];
+		rect.height = height[0];
+		OS.gdk_region_union_with_rect(clipping, rect);
+	} else {
+		/* Convert clipping to device space if needed */
+		if (data.clippingTransform != null) {
+			int /*long*/ rgn = convertRgn(clipRgn, data.clippingTransform);
+			OS.gdk_region_union(clipping, rgn);
+			OS.gdk_region_destroy(rgn);
+		} else {
+			OS.gdk_region_union(clipping, clipRgn);
+		}
+	}
+	if (data.damageRgn != 0) {
+		OS.gdk_region_intersect(clipping, data.damageRgn);
+	}
+	/* Convert to user space */
+	if (cairo != 0) {
+		double[] matrix = new double[6];
+		Cairo.cairo_get_matrix(cairo, matrix);
+		Cairo.cairo_matrix_invert(matrix);
+		int /*long*/ rgn = convertRgn(clipping, matrix);
+		OS.gdk_region_subtract(clipping, clipping);
+		OS.gdk_region_union(clipping, rgn);
+		OS.gdk_region_destroy(rgn);
+	}
+}
+
+/**
+ * Returns the receiver's fill rule, which will be one of
+ * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
+ *
+ * @return the receiver's fill rule
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getFillRule() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	int /*long*/ cairo = data.cairo;
+	if (cairo == 0) return SWT.FILL_EVEN_ODD;
+	return Cairo.cairo_get_fill_rule(cairo) == Cairo.CAIRO_FILL_RULE_WINDING ? SWT.FILL_WINDING : SWT.FILL_EVEN_ODD;
+}
+
+/**
+ * Returns the font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getFont() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return Font.gtk_new(data.device, data.font);
+}
+
+/**
+ * Returns a FontMetrics which contains information
+ * about the font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return font metrics for the receiver's font
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontMetrics getFontMetrics() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.context == 0) createLayout();
+	checkGC(FONT);
+	int /*long*/ context = data.context;
+	int /*long*/ lang = OS.pango_context_get_language(context);
+	int /*long*/ metrics = OS.pango_context_get_metrics(context, data.font, 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));
+	fm.averageCharWidth = OS.PANGO_PIXELS(OS.pango_font_metrics_get_approximate_char_width(metrics));
+	fm.height = fm.ascent + fm.descent;
+	OS.pango_font_metrics_unref(metrics);
+	return fm;
+}
+
+/**
+ * Returns the receiver's foreground color.
+ *
+ * @return the color used for drawing foreground things
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getForeground() {
+	if (handle == 0) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
+	return Color.gtk_new(data.device, data.foreground);
+}
+
+/**
+ * Returns the foreground pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's foreground pattern
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Pattern
+ *
+ * @since 3.1
+ */
+public Pattern getForegroundPattern() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.foregroundPattern;
+}
+
+/**
+ * Returns the GCData.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>GC</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @return the receiver's GCData
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see GCData
+ *
+ * @since 3.2
+ */
+public GCData getGCData() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data;
+}
+
+/**
+ * Returns the receiver's interpolation setting, which will be one of
+ * <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
+ * <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
+ *
+ * @return the receiver's interpolation setting
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getInterpolation() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.interpolation;
+}
+
+/**
+ * Returns the receiver's line attributes.
+ *
+ * @return the line attributes used for drawing lines
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public LineAttributes getLineAttributes() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	float[] dashes = null;
+	if (data.lineDashes != null) {
+		dashes = new float[data.lineDashes.length];
+		System.arraycopy(data.lineDashes, 0, dashes, 0, dashes.length);
+	}
+	return new LineAttributes(data.lineWidth, data.lineCap, data.lineJoin, data.lineStyle, dashes, data.lineDashesOffset, data.lineMiterLimit);
+}
+
+/**
+ * Returns the receiver's line cap style, which will be one
+ * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
+ * or <code>SWT.CAP_SQUARE</code>.
+ *
+ * @return the cap style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getLineCap() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.lineCap;
+}
+
+/**
+ * Returns the receiver's line dash style. The default value is
+ * <code>null</code>.
+ *
+ * @return the line dash style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int[] getLineDash() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.lineDashes == null) return null;
+	int[] lineDashes = new int[data.lineDashes.length];
+	for (int i = 0; i < lineDashes.length; i++) {
+		lineDashes[i] = (int)data.lineDashes[i];
+	}
+	return lineDashes;
+}
+
+/**
+ * Returns the receiver's line join style, which will be one
+ * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
+ * or <code>SWT.JOIN_BEVEL</code>.
+ *
+ * @return the join style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getLineJoin() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.lineJoin;
+}
+
+/**
+ * Returns the receiver's line style, which will be one
+ * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
+ * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
+ * <code>SWT.LINE_DASHDOTDOT</code>.
+ *
+ * @return the style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineStyle() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.lineStyle;
+}
+
+/**
+ * Returns the width that will be used when drawing lines
+ * for all of the figure drawing operations (that is,
+ * <code>drawLine</code>, <code>drawRectangle</code>,
+ * <code>drawPolyline</code>, and so forth.
+ *
+ * @return the receiver's line width
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineWidth() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return (int)data.lineWidth;
+}
+
+/**
+ * Returns the receiver's style information.
+ * <p>
+ * Note that the value which is returned by this method <em>may
+ * not match</em> the value which was provided to the constructor
+ * when the receiver was created. This can occur when the underlying
+ * operating system does not support a particular combination of
+ * requested styles.
+ * </p>
+ *
+ * @return the style bits
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public int getStyle () {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.style;
+}
+
+/**
+ * Returns the receiver's text drawing anti-aliasing setting value,
+ * which will be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
+ * <code>SWT.ON</code>. Note that this controls anti-aliasing
+ * <em>only</em> for text drawing operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getAntialias
+ *
+ * @since 3.1
+ */
+public int getTextAntialias() {
+    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+    if (data.cairo == 0) return SWT.DEFAULT;
+    int antialias = Cairo.CAIRO_ANTIALIAS_DEFAULT;
+    if (OS.GTK_VERSION < OS.VERSION(2, 8, 0)) {
+    	int /*long*/ options = Cairo.cairo_font_options_create();
+    	Cairo.cairo_get_font_options(data.cairo, options);
+    	antialias = Cairo.cairo_font_options_get_antialias(options);
+    	Cairo.cairo_font_options_destroy(options);
+    } else {
+    	if (data.context != 0) {
+    		int /*long*/ options = OS.pango_cairo_context_get_font_options(data.context);
+    		if (options != 0) antialias = Cairo.cairo_font_options_get_antialias(options);
+    	}
+    }
+	switch (antialias) {
+		case Cairo.CAIRO_ANTIALIAS_DEFAULT: return SWT.DEFAULT;
+		case Cairo.CAIRO_ANTIALIAS_NONE: return SWT.OFF;
+		case Cairo.CAIRO_ANTIALIAS_GRAY:
+		case Cairo.CAIRO_ANTIALIAS_SUBPIXEL: return SWT.ON;
+	}
+	return SWT.DEFAULT;
+}
+
+/**
+ * Sets the parameter to the transform that is currently being
+ * used by the receiver.
+ *
+ * @param transform the destination to copy the transform into
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Transform
+ *
+ * @since 3.1
+ */
+public void getTransform(Transform transform) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (transform == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		Cairo.cairo_get_matrix(cairo, transform.handle);
+	} else {
+		transform.setElements(1, 0, 0, 1, 0, 0);
+	}
+}
+
+/**
+ * Returns <code>true</code> if this GC is drawing in the mode
+ * where the resulting color in the destination is the
+ * <em>exclusive or</em> of the color values in the source
+ * and the destination, and <code>false</code> if it is
+ * drawing in the mode where the destination color is being
+ * replaced with the source color value.
+ *
+ * @return <code>true</code> true if the receiver is in XOR mode, and false otherwise
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean getXORMode() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.xorMode;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #equals
+ */
+public int hashCode() {
+	return (int)/*64*/handle;
+}
+
+void init(Drawable drawable, GCData data, int /*long*/ gdkGC) {
+	if (data.foreground != null) data.state &= ~FOREGROUND;
+	if (data.background != null) data.state &= ~(BACKGROUND | BACKGROUND_BG);
+	if (data.font != 0) data.state &= ~FONT;
+
+	Image image = data.image;
+	if (image != null) {
+		image.memGC = this;
+		/*
+		 * The transparent pixel mask might change when drawing on
+		 * the image.  Destroy it so that it is regenerated when
+		 * necessary.
+		 */
+		if (image.transparentPixel != -1) image.destroyMask();
+	}
+	this.drawable = drawable;
+	this.data = data;
+	handle = gdkGC;
+}
+
+void initCairo() {
+	data.device.checkCairo();
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) return;
+	int /*long*/ xDisplay = OS.GDK_DISPLAY();
+	int /*long*/ xVisual = OS.gdk_x11_visual_get_xvisual(OS.gdk_visual_get_system());
+	int /*long*/ xDrawable = 0;
+	int translateX = 0, translateY = 0;
+	int /*long*/ drawable = data.drawable;
+	if (data.image != null) {
+		xDrawable = OS.GDK_PIXMAP_XID(drawable);
+	} else {
+		int[] x = new int[1], y = new int[1];
+		int /*long*/ [] real_drawable = new int /*long*/ [1];
+		OS.gdk_window_get_internal_paint_info(drawable, real_drawable, x, y);
+		xDrawable = OS.gdk_x11_drawable_get_xid(real_drawable[0]);
+		translateX = -x[0];
+		translateY = -y[0];
+	}
+	int[] w = new int[1], h = new int[1];
+	OS.gdk_drawable_get_size(drawable, w, h);
+	int width = w[0], height = h[0];
+	int /*long*/ surface = Cairo.cairo_xlib_surface_create(xDisplay, xDrawable, xVisual, width, height);
+	if (surface == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	Cairo.cairo_surface_set_device_offset(surface, translateX, translateY);
+	data.cairo = cairo = Cairo.cairo_create(surface);
+	Cairo.cairo_surface_destroy(surface);
+	if (cairo == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	data.disposeCairo = true;
+	Cairo.cairo_set_fill_rule(cairo, Cairo.CAIRO_FILL_RULE_EVEN_ODD);
+	data.state &= ~(BACKGROUND | FOREGROUND | FONT | LINE_WIDTH | LINE_CAP | LINE_JOIN | LINE_STYLE | DRAW_OFFSET);
+	setCairoClip(cairo, data.clipRgn);
+}
+
+/**
+ * Returns <code>true</code> if the receiver has a clipping
+ * region set into it, and <code>false</code> otherwise.
+ * If this method returns false, the receiver will draw on all
+ * available space in the destination. If it returns true,
+ * it will draw only in the area that is covered by the region
+ * that can be accessed with <code>getClipping(region)</code>.
+ *
+ * @return <code>true</code> if the GC has a clipping region, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean isClipped() {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	return data.clipRgn != 0;
+}
+
+/**
+ * Returns <code>true</code> if the GC has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the GC.
+ * When a GC has been disposed, it is an error to
+ * invoke any other method using the GC.
+ *
+ * @return <code>true</code> when the GC is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+	return handle == 0;
+}
+
+boolean isIdentity(double[] matrix) {
+	if (matrix == null) return true;
+	return matrix[0] == 1 && matrix[1] == 0 && matrix[2] == 0 && matrix[3] == 1 && matrix[4] == 0 && matrix[5] == 0;
+}
+
+/**
+ * Sets the receiver to always use the operating system's advanced graphics
+ * subsystem for all graphics operations if the argument is <code>true</code>.
+ * If the argument is <code>false</code>, the advanced graphics subsystem is
+ * no longer used, advanced graphics state is cleared and the normal graphics
+ * subsystem is used from now on.
+ * <p>
+ * Normally, the advanced graphics subsystem is invoked automatically when
+ * any one of the alpha, antialias, patterns, interpolation, paths, clipping
+ * or transformation operations in the receiver is requested.  When the receiver
+ * is switched into advanced mode, the advanced graphics subsystem performs both
+ * advanced and normal graphics operations.  Because the two subsystems are
+ * different, their output may differ.  Switching to advanced graphics before
+ * any graphics operations are performed ensures that the output is consistent.
+ * </p><p>
+ * Advanced graphics may not be installed for the operating system.  In this
+ * case, this operation does nothing.  Some operating system have only one
+ * graphics subsystem, so switching from normal to advanced graphics does
+ * nothing.  However, switching from advanced to normal graphics will always
+ * clear the advanced graphics state, even for operating systems that have
+ * only one graphics subsystem.
+ * </p>
+ *
+ * @param advanced the new advanced graphics state
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAlpha
+ * @see #setAntialias
+ * @see #setBackgroundPattern
+ * @see #setClipping(Path)
+ * @see #setForegroundPattern
+ * @see #setLineAttributes
+ * @see #setInterpolation
+ * @see #setTextAntialias
+ * @see #setTransform
+ * @see #getAdvanced
+ *
+ * @since 3.1
+ */
+public void setAdvanced(boolean advanced) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (advanced && data.cairo != 0) return;
+	if (advanced) {
+		try {
+			initCairo();
+		} catch (SWTException e) {}
+	} else {
+		if (!data.disposeCairo) return;
+		int /*long*/ cairo = data.cairo;
+		if (cairo != 0) Cairo.cairo_destroy(cairo);
+		data.cairo = 0;
+		data.interpolation = SWT.DEFAULT;
+		data.backgroundPattern = data.foregroundPattern = null;
+		data.state = 0;
+		setClipping(0);
+	}
+}
+
+/**
+ * Sets the receiver's alpha value.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param alpha the alpha value
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setAlpha(int alpha) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.cairo == 0 && (alpha & 0xff) == 0xff) return;
+	initCairo();
+	data.alpha = alpha & 0xff;
+	data.state &= ~(BACKGROUND | FOREGROUND | BACKGROUND_BG);
+}
+
+/**
+ * Sets the receiver's anti-aliasing value to the parameter,
+ * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
+ * or <code>SWT.ON</code>. Note that this controls anti-aliasing for all
+ * <em>non-text drawing</em> operations.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param antialias the anti-aliasing setting
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>,
+ *                                 <code>SWT.OFF</code> or <code>SWT.ON</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * @see #setTextAntialias
+ *
+ * @since 3.1
+ */
+public void setAntialias(int antialias) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.cairo == 0 && antialias == SWT.DEFAULT) return;
+	int mode = 0;
+	switch (antialias) {
+		case SWT.DEFAULT: mode = Cairo.CAIRO_ANTIALIAS_DEFAULT; break;
+		case SWT.OFF: mode = Cairo.CAIRO_ANTIALIAS_NONE; break;
+		case SWT.ON: mode = Cairo.CAIRO_ANTIALIAS_GRAY;
+            break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+    initCairo();
+    int /*long*/ cairo = data.cairo;
+    Cairo.cairo_set_antialias(cairo, mode);
+}
+
+/**
+ * Sets the background color. The background color is used
+ * for fill operations and as the background color when text
+ * is drawn.
+ *
+ * @param color the new background color for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setBackground(Color color) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	data.background = color.handle;
+	data.backgroundPattern = null;
+	data.state &= ~(BACKGROUND | BACKGROUND_BG);
+}
+
+/**
+ * Sets the background pattern. The default value is <code>null</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param pattern the new background pattern
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Pattern
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setBackgroundPattern(Pattern pattern) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	if (data.cairo == 0 && pattern == null) return;
+	initCairo();
+	if (data.backgroundPattern == pattern) return;
+	data.backgroundPattern = pattern;
+	data.state &= ~BACKGROUND;
+}
+
+static void setCairoFont(int /*long*/ cairo, Font font) {
+	setCairoFont(cairo, font.handle);
+}
+
+static void setCairoFont(int /*long*/ cairo, int /*long*/ font) {
+	int /*long*/ family = OS.pango_font_description_get_family(font);
+	int length = OS.strlen(family);
+	byte[] buffer = new byte[length + 1];
+	OS.memmove(buffer, family, length);
+	//TODO - convert font height from pango to cairo
+	double height = OS.PANGO_PIXELS(OS.pango_font_description_get_size(font)) * 96 / 72;
+	int pangoStyle = OS.pango_font_description_get_style(font);
+	int pangoWeight = OS.pango_font_description_get_weight(font);
+	int slant = Cairo.CAIRO_FONT_SLANT_NORMAL;
+	if (pangoStyle == OS.PANGO_STYLE_ITALIC) slant = Cairo.CAIRO_FONT_SLANT_ITALIC;
+	if (pangoStyle == OS.PANGO_STYLE_OBLIQUE) slant = Cairo.CAIRO_FONT_SLANT_OBLIQUE;
+	int weight = Cairo.CAIRO_FONT_WEIGHT_NORMAL;
+	if (pangoWeight == OS.PANGO_WEIGHT_BOLD) weight = Cairo.CAIRO_FONT_WEIGHT_BOLD;
+	Cairo.cairo_select_font_face(cairo, buffer, slant, weight);
+	Cairo.cairo_set_font_size(cairo, height);
+}
+
+static void setCairoClip(int /*long*/ cairo, int /*long*/ clipRgn) {
+	Cairo.cairo_reset_clip(cairo);
+	if (clipRgn == 0) return;
+	if (OS.GTK_VERSION >= OS.VERSION(2, 8, 0)) {
+		OS.gdk_cairo_region(cairo, clipRgn);
+	} else {
+		int[] nRects = new int[1];
+		int /*long*/[] rects = new int /*long*/[1];
+		OS.gdk_region_get_rectangles(clipRgn, rects, nRects);
+		GdkRectangle rect = new GdkRectangle();
+		for (int i=0; i<nRects[0]; i++) {
+			OS.memmove(rect, rects[0] + (i * GdkRectangle.sizeof), GdkRectangle.sizeof);
+			Cairo.cairo_rectangle(cairo, rect.x, rect.y, rect.width, rect.height);
+		}
+		if (rects[0] != 0) OS.g_free(rects[0]);
+	}
+	Cairo.cairo_clip(cairo);
+}
+
+static void setCairoPatternColor(int /*long*/ pattern, int offset, Color c, int alpha) {
+	GdkColor color = c.handle;
+	double aa = (alpha & 0xFF) / (double)0xFF;
+	double red = ((color.red & 0xFFFF) / (double)0xFFFF);
+	double green = ((color.green & 0xFFFF) / (double)0xFFFF);
+	double blue = ((color.blue & 0xFFFF) / (double)0xFFFF);
+	Cairo.cairo_pattern_add_color_stop_rgba(pattern, offset, red, green, blue, aa);
+}
+
+void setClipping(int /*long*/ clipRgn) {
+	int /*long*/ cairo = data.cairo;
+	if (clipRgn == 0) {
+		if (data.clipRgn != 0) {
+			OS.gdk_region_destroy(data.clipRgn);
+			data.clipRgn = 0;
+		}
+		if (cairo != 0) {
+			data.clippingTransform = null;
+			setCairoClip(cairo, clipRgn);
+		} else {
+			int /*long*/ clipping = data.damageRgn != 0 ? data.damageRgn : 0;
+			OS.gdk_gc_set_clip_region(handle, clipping);
+		}
+	} else {
+		if (data.clipRgn == 0) data.clipRgn = OS.gdk_region_new();
+		OS.gdk_region_subtract(data.clipRgn, data.clipRgn);
+		OS.gdk_region_union(data.clipRgn, clipRgn);
+		if (cairo != 0) {
+			if (data.clippingTransform == null) data.clippingTransform = new double[6];
+			Cairo.cairo_get_matrix(cairo, data.clippingTransform);
+			setCairoClip(cairo, clipRgn);
+		} else {
+			int /*long*/ clipping = clipRgn;
+			if (data.damageRgn != 0) {
+				clipping = OS.gdk_region_new();
+				OS.gdk_region_union(clipping, clipRgn);
+				OS.gdk_region_intersect(clipping, data.damageRgn);
+			}
+			OS.gdk_gc_set_clip_region(handle, clipping);
+			if (clipping != clipRgn) OS.gdk_region_destroy(clipping);
+		}
+	}
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the rectangular area specified
+ * by the arguments.
+ *
+ * @param x the x coordinate of the clipping rectangle
+ * @param y the y coordinate of the clipping rectangle
+ * @param width the width of the clipping rectangle
+ * @param height the height of the clipping rectangle
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(int x, int y, int width, int height) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (width < 0) {
+		x = x + width;
+		width = -width;
+	}
+	if (height < 0) {
+		y = y + height;
+		height = -height;
+	}
+	GdkRectangle rect = new GdkRectangle();
+	rect.x = x;
+	rect.y = y;
+	rect.width = width;
+	rect.height = height;
+	int /*long*/ clipRgn = OS.gdk_region_new();
+	OS.gdk_region_union_with_rect(clipRgn, rect);
+	setClipping(clipRgn);
+	OS.gdk_region_destroy(clipRgn);
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the path specified
+ * by the argument.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param path the clipping path.
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Path
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setClipping(Path path) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (path != null && path.isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	setClipping(0);
+	if (path != null) {
+		initCairo();
+		int /*long*/ cairo = data.cairo;
+		int /*long*/ copy = Cairo.cairo_copy_path(path.handle);
+		if (copy == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+		Cairo.cairo_append_path(cairo, copy);
+		Cairo.cairo_path_destroy(copy);
+		Cairo.cairo_clip(cairo);
+	}
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the rectangular area specified
+ * by the argument.  Specifying <code>null</code> for the
+ * rectangle reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param rect the clipping rectangle or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(Rectangle rect) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (rect == null) {
+		setClipping(0);
+	} else {
+		setClipping(rect.x, rect.y, rect.width, rect.height);
+	}
+}
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the region specified
+ * by the argument.  Specifying <code>null</code> for the
+ * region reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param region the clipping region or <code>null</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(Region region) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (region != null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	setClipping(region != null ? region.handle : 0);
+}
+
+/**
+ * Sets the font which will be used by the receiver
+ * to draw and measure text to the argument. If the
+ * argument is null, then a default font appropriate
+ * for the platform will be used instead.
+ *
+ * @param font the new font for the receiver, or null to indicate a default font
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setFont(Font font) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (font == null) font = data.device.systemFont;
+	if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	data.font = font.handle;
+	data.state &= ~FONT;
+	data.stringWidth = data.stringHeight = -1;
+}
+
+/**
+ * Sets the receiver's fill rule to the parameter, which must be one of
+ * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
+ *
+ * @param rule the new fill rule
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.FILL_EVEN_ODD</code>
+ *                                 or <code>SWT.FILL_WINDING</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setFillRule(int rule) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	int cairo_mode = Cairo.CAIRO_FILL_RULE_EVEN_ODD;
+	switch (rule) {
+		case SWT.FILL_WINDING:
+			cairo_mode = Cairo.CAIRO_FILL_RULE_WINDING; break;
+		case SWT.FILL_EVEN_ODD:
+			cairo_mode = Cairo.CAIRO_FILL_RULE_EVEN_ODD; break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	//TODO - need fill rule in X, GDK has no API
+	initCairo();
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		Cairo.cairo_set_fill_rule(cairo, cairo_mode);
+	}
+}
+
+/**
+ * Sets the foreground color. The foreground color is used
+ * for drawing operations including when text is drawn.
+ *
+ * @param color the new foreground color for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setForeground(Color color) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	data.foreground = color.handle;
+	data.foregroundPattern = null;
+	data.state &= ~FOREGROUND;
+}
+
+/**
+ * Sets the foreground pattern. The default value is <code>null</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param pattern the new foreground pattern
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Pattern
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setForegroundPattern(Pattern pattern) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	if (data.cairo == 0 && pattern == null) return;
+	initCairo();
+	if (data.foregroundPattern == pattern) return;
+	data.foregroundPattern = pattern;
+	data.state &= ~FOREGROUND;
+}
+
+/**
+ * Sets the receiver's interpolation setting to the parameter, which
+ * must be one of <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
+ * <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param interpolation the new interpolation setting
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.DEFAULT</code>,
+ *                                 <code>SWT.NONE</code>, <code>SWT.LOW</code> or <code>SWT.HIGH</code>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setInterpolation(int interpolation) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.cairo == 0 && interpolation == SWT.DEFAULT) return;
+	switch (interpolation) {
+		case SWT.DEFAULT:
+		case SWT.NONE:
+		case SWT.LOW:
+		case SWT.HIGH:
+			break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	initCairo();
+	data.interpolation = interpolation;
+}
+
+/**
+ * Sets the receiver's line attributes.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param attributes the line attributes
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the attributes is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if any of the line attributes is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see LineAttributes
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.3
+ */
+public void setLineAttributes(LineAttributes attributes) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (attributes == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	int mask = 0;
+	float lineWidth = attributes.width;
+	if (lineWidth != data.lineWidth) {
+		mask |= LINE_WIDTH | DRAW_OFFSET;
+	}
+	int lineStyle = attributes.style;
+	if (lineStyle != data.lineStyle) {
+		mask |= LINE_STYLE;
+		switch (lineStyle) {
+			case SWT.LINE_SOLID:
+			case SWT.LINE_DASH:
+			case SWT.LINE_DOT:
+			case SWT.LINE_DASHDOT:
+			case SWT.LINE_DASHDOTDOT:
+				break;
+			case SWT.LINE_CUSTOM:
+				if (attributes.dash == null) lineStyle = SWT.LINE_SOLID;
+				break;
+			default:
+				SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+		}
+	}
+	int join = attributes.join;
+	if (join != data.lineJoin) {
+		mask |= LINE_JOIN;
+		switch (join) {
+			case SWT.CAP_ROUND:
+			case SWT.CAP_FLAT:
+			case SWT.CAP_SQUARE:
+				break;
+			default:
+				SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+		}
+	}
+	int cap = attributes.join;
+	if (cap != data.lineCap) {
+		mask |= LINE_CAP;
+		switch (cap) {
+			case SWT.JOIN_MITER:
+			case SWT.JOIN_ROUND:
+			case SWT.JOIN_BEVEL:
+				break;
+			default:
+				SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+		}
+	}
+	float[] dashes = attributes.dash;
+	float[] lineDashes = data.lineDashes;
+	if (dashes != null && dashes.length > 0) {
+		boolean changed = lineDashes == null || lineDashes.length != dashes.length;
+		for (int i = 0; i < dashes.length; i++) {
+			float dash = dashes[i];
+			if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+			if (!changed && lineDashes[i] != dash) changed = true;
+		}
+		if (changed) {
+			float[] newDashes = new float[dashes.length];
+			System.arraycopy(dashes, 0, newDashes, 0, dashes.length);
+			dashes = newDashes;
+			mask |= LINE_STYLE;
+		} else {
+			dashes = lineDashes;
+		}
+	} else {
+		if (lineDashes != null && lineDashes.length > 0) {
+			mask |= LINE_STYLE;
+		} else {
+			dashes = lineDashes;
+		}
+	}
+	float dashOffset = attributes.dashOffset;
+	if (dashOffset != data.lineDashesOffset) {
+		mask |= LINE_STYLE;
+	}
+	float miterLimit = attributes.miterLimit;
+	if (miterLimit != data.lineMiterLimit) {
+		mask |= LINE_MITERLIMIT;
+	}
+	initCairo();
+	if (mask == 0) return;
+	data.lineWidth = lineWidth;
+	data.lineStyle = lineStyle;
+	data.lineCap = cap;
+	data.lineJoin = join;
+	data.lineDashes = dashes;
+	data.lineDashesOffset = dashOffset;
+	data.lineMiterLimit = miterLimit;
+	data.state &= ~mask;
+}
+
+/**
+ * Sets the receiver's line cap style to the argument, which must be one
+ * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
+ * or <code>SWT.CAP_SQUARE</code>.
+ *
+ * @param cap the cap style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineCap(int cap) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.lineCap == cap) return;
+	switch (cap) {
+		case SWT.CAP_ROUND:
+		case SWT.CAP_FLAT:
+		case SWT.CAP_SQUARE:
+			break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	data.lineCap = cap;
+	data.state &= ~LINE_CAP;
+}
+
+/**
+ * Sets the receiver's line dash style to the argument. The default
+ * value is <code>null</code>. If the argument is not <code>null</code>,
+ * the receiver's line style is set to <code>SWT.LINE_CUSTOM</code>, otherwise
+ * it is set to <code>SWT.LINE_SOLID</code>.
+ *
+ * @param dashes the dash style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if any of the values in the array is less than or equal 0</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineDash(int[] dashes) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	float[] lineDashes = data.lineDashes;
+	if (dashes != null && dashes.length > 0) {
+		boolean changed = data.lineStyle != SWT.LINE_CUSTOM || lineDashes == null || lineDashes.length != dashes.length;
+		for (int i = 0; i < dashes.length; i++) {
+			int dash = dashes[i];
+			if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+			if (!changed && lineDashes[i] != dash) changed = true;
+		}
+		if (!changed) return;
+		data.lineDashes = new float[dashes.length];
+		for (int i = 0; i < dashes.length; i++) {
+			data.lineDashes[i] = dashes[i];
+		}
+		data.lineStyle = SWT.LINE_CUSTOM;
+	} else {
+		if (data.lineStyle == SWT.LINE_SOLID && (lineDashes == null || lineDashes.length == 0)) return;
+		data.lineDashes = null;
+		data.lineStyle = SWT.LINE_SOLID;
+	}
+	data.state &= ~LINE_STYLE;
+}
+
+/**
+ * Sets the receiver's line join style to the argument, which must be one
+ * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
+ * or <code>SWT.JOIN_BEVEL</code>.
+ *
+ * @param join the join style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineJoin(int join) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.lineJoin == join) return;
+	switch (join) {
+		case SWT.JOIN_MITER:
+		case SWT.JOIN_ROUND:
+		case SWT.JOIN_BEVEL:
+			break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	data.lineJoin = join;
+	data.state &= ~LINE_JOIN;
+}
+
+/**
+ * Sets the receiver's line style to the argument, which must be one
+ * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
+ * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
+ * <code>SWT.LINE_DASHDOTDOT</code>.
+ *
+ * @param lineStyle the style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineStyle(int lineStyle) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.lineStyle == lineStyle) return;
+	switch (lineStyle) {
+		case SWT.LINE_SOLID:
+		case SWT.LINE_DASH:
+		case SWT.LINE_DOT:
+		case SWT.LINE_DASHDOT:
+		case SWT.LINE_DASHDOTDOT:
+			break;
+		case SWT.LINE_CUSTOM:
+			if (data.lineDashes == null) lineStyle = SWT.LINE_SOLID;
+			break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	data.lineStyle = lineStyle;
+	data.state &= ~LINE_STYLE;
+}
+
+/**
+ * Sets the width that will be used when drawing lines
+ * for all of the figure drawing operations (that is,
+ * <code>drawLine</code>, <code>drawRectangle</code>,
+ * <code>drawPolyline</code>, and so forth.
+ * <p>
+ * Note that line width of zero is used as a hint to
+ * indicate that the fastest possible line drawing
+ * algorithms should be used. This means that the
+ * output may be different from line width one.
+ * </p>
+ *
+ * @param lineWidth the width of a line
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineWidth(int lineWidth) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.lineWidth == lineWidth) return;
+	data.lineWidth = lineWidth;
+	data.state &= ~(LINE_WIDTH | DRAW_OFFSET);
+}
+
+void setString(String string, int flags) {
+	if (data.layout == 0) createLayout();
+	if (string == data.string && (flags & ~SWT.DRAW_TRANSPARENT) == (data.drawFlags  & ~SWT.DRAW_TRANSPARENT)) {
+		return;
+	}
+	byte[] buffer;
+	int mnemonic, length = string.length ();
+	int /*long*/ layout = data.layout;
+	char[] text = new char[length];
+	string.getChars(0, length, text, 0);
+	if ((flags & SWT.DRAW_MNEMONIC) != 0 && (mnemonic = fixMnemonic(text)) != -1) {
+		char[] text1 = new char[mnemonic - 1];
+		System.arraycopy(text, 0, text1, 0, text1.length);
+		byte[] buffer1 = Converter.wcsToMbcs(null, text1, false);
+		char[] text2 = new char[text.length - mnemonic];
+		System.arraycopy(text, mnemonic - 1, text2, 0, text2.length);
+		byte[] buffer2 = Converter.wcsToMbcs(null, text2, false);
+		buffer = new byte[buffer1.length + buffer2.length];
+		System.arraycopy(buffer1, 0, buffer, 0, buffer1.length);
+		System.arraycopy(buffer2, 0, buffer, buffer1.length, buffer2.length);
+		int /*long*/ attr_list = OS.pango_attr_list_new();
+		int /*long*/ attr = OS.pango_attr_underline_new(OS.PANGO_UNDERLINE_LOW);
+		PangoAttribute attribute = new PangoAttribute();
+		OS.memmove(attribute, attr, PangoAttribute.sizeof);
+		attribute.start_index = buffer1.length;
+		attribute.end_index = buffer1.length + 1;
+		OS.memmove(attr, attribute, PangoAttribute.sizeof);
+		OS.pango_attr_list_insert(attr_list, attr);
+		OS.pango_layout_set_attributes(layout, attr_list);
+		OS.pango_attr_list_unref(attr_list);
+	} else {
+		buffer = Converter.wcsToMbcs(null, text, false);
+		OS.pango_layout_set_attributes(layout, 0);
+	}
+	OS.pango_layout_set_text(layout, buffer, buffer.length);
+	OS.pango_layout_set_single_paragraph_mode(layout, (flags & SWT.DRAW_DELIMITER) == 0);
+	OS.pango_layout_set_tabs(layout, (flags & SWT.DRAW_TAB) != 0 ? 0 : data.device.emptyTab);
+	data.string = string;
+	data.stringWidth = data.stringHeight = -1;
+	data.drawFlags = flags;
+}
+
+/**
+ * Sets the receiver's text anti-aliasing value to the parameter,
+ * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
+ * or <code>SWT.ON</code>. Note that this controls anti-aliasing only
+ * for all <em>text drawing</em> operations.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param antialias the anti-aliasing setting
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>,
+ *                                 <code>SWT.OFF</code> or <code>SWT.ON</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * @see #setAntialias
+ *
+ * @since 3.1
+ */
+public void setTextAntialias(int antialias) {
+    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (data.cairo == 0 && antialias == SWT.DEFAULT) return;
+	int mode = 0;
+	switch (antialias) {
+		case SWT.DEFAULT: mode = Cairo.CAIRO_ANTIALIAS_DEFAULT; break;
+		case SWT.OFF: mode = Cairo.CAIRO_ANTIALIAS_NONE; break;
+		case SWT.ON: mode = Cairo.CAIRO_ANTIALIAS_GRAY;
+            break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+    initCairo();
+    int /*long*/ options = Cairo.cairo_font_options_create();
+    Cairo.cairo_font_options_set_antialias(options, mode);
+    if (OS.GTK_VERSION < OS.VERSION(2, 8, 0)) {
+    	Cairo.cairo_set_font_options(data.cairo, options);
+    } else {
+    	if (data.context == 0) createLayout();
+    	OS.pango_cairo_context_set_font_options(data.context, options);
+    }
+    Cairo.cairo_font_options_destroy(options);
+}
+
+/**
+ * Sets the transform that is currently being used by the receiver. If
+ * the argument is <code>null</code>, the current transform is set to
+ * the identity transform.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param transform the transform to set
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ *
+ * @see Transform
+ * @see #getAdvanced
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public void setTransform(Transform transform) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (transform != null && transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	if (data.cairo == 0 && transform == null) return;
+	initCairo();
+	int /*long*/ cairo = data.cairo;
+	if (transform != null) {
+		Cairo.cairo_set_matrix(cairo, transform.handle);
+	} else {
+		Cairo.cairo_identity_matrix(cairo);
+	}
+	data.state &= ~DRAW_OFFSET;
+}
+
+/**
+ * If the argument is <code>true</code>, puts the receiver
+ * in a drawing mode where the resulting color in the destination
+ * is the <em>exclusive or</em> of the color values in the source
+ * and the destination, and if the argument is <code>false</code>,
+ * puts the receiver in a drawing mode where the destination color
+ * is replaced with the source color value.
+ * <p>
+ * Note that this mode in fundamentally unsupportable on certain
+ * platforms, notably Carbon (Mac OS X). Clients that want their
+ * code to run on all platforms need to avoid this method.
+ * </p>
+ *
+ * @param xor if <code>true</code>, then <em>xor</em> mode is used, otherwise <em>source copy</em> mode is used
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @deprecated this functionality is not supported on some platforms
+ */
+public void setXORMode(boolean xor) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	OS.gdk_gc_set_function(handle, xor ? OS.GDK_XOR : OS.GDK_COPY);
+	data.xorMode = xor;
+}
+
+/**
+ * Returns the extent of the given string. No tab
+ * expansion or carriage return processing will be performed.
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point stringExtent(String string) {
+	return textExtent(string, 0);
+}
+
+/**
+ * Returns the extent of the given string. Tab expansion and
+ * carriage return processing are performed.
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string) {
+	return textExtent(string, SWT.DRAW_DELIMITER | SWT.DRAW_TAB);
+}
+
+/**
+ * Returns the extent of the given string. Tab expansion, line
+ * delimiter and mnemonic processing are performed according to
+ * the specified flags, which can be a combination of:
+ * <dl>
+ * <dt><b>DRAW_DELIMITER</b></dt>
+ * <dd>draw multiple lines</dd>
+ * <dt><b>DRAW_TAB</b></dt>
+ * <dd>expand tabs</dd>
+ * <dt><b>DRAW_MNEMONIC</b></dt>
+ * <dd>underline the mnemonic character</dd>
+ * <dt><b>DRAW_TRANSPARENT</b></dt>
+ * <dd>transparent background</dd>
+ * </dl>
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @param flags the flags specifying how to process the text
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string, int flags) {
+	if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	int /*long*/ cairo = data.cairo;
+	if (cairo != 0) {
+		if (OS.GTK_VERSION < OS.VERSION(2, 8, 0)) {
+			//TODO - honor flags
+			checkGC(FONT);
+			byte[] buffer = Converter.wcsToMbcs(null, string, true);
+			cairo_font_extents_t font_extents = new cairo_font_extents_t();
+			Cairo.cairo_font_extents(cairo, font_extents);
+			cairo_text_extents_t extents = new cairo_text_extents_t();
+			Cairo.cairo_text_extents(cairo, buffer, extents);
+			return new Point((int)extents.width, (int)font_extents.height);
+		}
+	}
+	setString(string, flags);
+	checkGC(FONT);
+	if (data.stringWidth != -1) return new Point(data.stringWidth, data.stringHeight);
+	int[] width = new int[1], height = new int[1];
+	OS.pango_layout_get_size(data.layout, width, height);
+	return new Point(data.stringWidth = OS.PANGO_PIXELS(width[0]), data.stringHeight = OS.PANGO_PIXELS(height[0]));
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+	if (isDisposed()) return "GC {*DISPOSED*}";
+	return "GC {" + handle + "}";
+}
+
+}
+++++/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/graphics/GCData.d	Mon Jan 07 03:41:50 2008 +0100
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.graphics.GCData;
+
+import dwt.internal.gtk.c.gdktypes;
+import dwt.SWT;
+import dwt.graphics.Device;
+import dwt.graphics.Pattern;
+import dwt.graphics.Image;
+
+/**
+ * Instances of this class are descriptions of GCs in terms
+ * of unallocated platform-specific data fields.
+ * <p>
+ * <b>IMPORTANT:</b> This class is <em>not</em> part of the public
+ * API for SWT. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms, and should never be called from application code.
+ * </p>
+ */
+public final class GCData {
+	public Device device;
+	public int style, state = -1;
+	public GdkColor* foreground;
+	public GdkColor* background;
+	public int /*long*/ font;
+	public Pattern foregroundPattern;
+	public Pattern backgroundPattern;
+	public int /*long*/ clipRgn;
+	public float lineWidth;
+	public int lineStyle = SWT.LINE_SOLID;
+	public float[] lineDashes;
+	public float lineDashesOffset;
+	public float lineMiterLimit = 10;
+	public int lineCap = SWT.CAP_FLAT;
+	public int lineJoin = SWT.JOIN_MITER;
+	public bool xorMode;
+	public int alpha = 0xFF;
+	public int interpolation = SWT.DEFAULT;
+
+	public int /*long*/ context;
+	public int /*long*/ layout;
+	public int /*long*/ damageRgn;
+	public Image image;
+	public int /*long*/ drawable;
+	public int /*long*/ cairo;
+	public double cairoXoffset, cairoYoffset;
+	public bool disposeCairo;
+	public double[] clippingTransform;
+	public char[] str;
+	public int stringWidth = -1;
+	public int stringHeight = -1;
+	public int drawFlags;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/graphics/Image.d	Mon Jan 07 03:41:50 2008 +0100
@@ -0,0 +1,1198 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.graphics.Image;
+
+import dwt.internal.Converter;
+import dwt.internal.gtk.OS;
+import dwt.internal.gtk.c.cairotypes;
+import dwt.internal.gtk.c.gdktypes;
+import dwt.SWT;
+import dwt.SWTException;
+import dwt.graphics.Color;
+import dwt.graphics.Device;
+import dwt.graphics.Drawable;
+import dwt.graphics.GC;
+import dwt.graphics.GCData;
+import dwt.graphics.ImageData;
+import dwt.graphics.PaletteData;
+import dwt.graphics.RGB;
+import dwt.graphics.Rectangle;
+import dwt.graphics.Resource;
+
+class Image{
+    public this(Device,ImageData){}
+    public void dispose(){}
+}
+
+/+
+import dwt.dwthelper.InputStream;
+
+import tango.text.convert.Format;
+import tango.stdc.string;
+import tango.stdc.stringz;
+
+/**
+ * Instances of this class are graphics which have been prepared
+ * for display on a specific device. That is, they are ready
+ * to paint using methods such as <code>GC.drawImage()</code>
+ * and display on widgets with, for example, <code>Button.setImage()</code>.
+ * <p>
+ * If loaded from a file format that supports it, an
+ * <code>Image</code> may have transparency, meaning that certain
+ * pixels are specified as being transparent when drawn. Examples
+ * of file formats that support transparency are GIF and PNG.
+ * </p><p>
+ * There are two primary ways to use <code>Images</code>.
+ * The first is to load a graphic file from disk and create an
+ * <code>Image</code> from it. This is done using an <code>Image</code>
+ * constructor, for example:
+ * <pre>
+ *    Image i = new Image(device, "C:\\graphic.bmp");
+ * </pre>
+ * A graphic file may contain a color table specifying which
+ * colors the image was intended to possess. In the above example,
+ * these colors will be mapped to the closest available color in
+ * SWT. It is possible to get more control over the mapping of
+ * colors as the image is being created, using code of the form:
+ * <pre>
+ *    ImageData data = new ImageData("C:\\graphic.bmp");
+ *    RGB[] rgbs = data.getRGBs();
+ *    // At this point, rgbs contains specifications of all
+ *    // the colors contained within this image. You may
+ *    // allocate as many of these colors as you wish by
+ *    // using the Color constructor Color(RGB), then
+ *    // create the image:
+ *    Image i = new Image(device, data);
+ * </pre>
+ * <p>
+ * Applications which require even greater control over the image
+ * loading process should use the support provided in class
+ * <code>ImageLoader</code>.
+ * </p><p>
+ * Application code must explicitly invoke the <code>Image.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see Color
+ * @see ImageData
+ * @see ImageLoader
+ */
+public final class Image : Resource, Drawable {
+
+	/**
+	 * specifies whether the receiver is a bitmap or an icon
+	 * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>)
+	 * <p>
+	 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+	 * public API. It is marked public only so that it can be shared
+	 * within the packages provided by SWT. It is not available on all
+	 * platforms and should never be accessed from application code.
+	 * </p>
+	 */
+	public int type;
+
+	/**
+	 * The handle to the OS pixmap resource.
+	 * (Warning: This field is platform dependent)
+	 * <p>
+	 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+	 * public API. It is marked public only so that it can be shared
+	 * within the packages provided by SWT. It is not available on all
+	 * platforms and should never be accessed from application code.
+	 * </p>
+	 */
+	public GdkDrawable* pixmap;
+
+	/**
+	 * The handle to the OS mask resource.
+	 * (Warning: This field is platform dependent)
+	 * <p>
+	 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+	 * public API. It is marked public only so that it can be shared
+	 * within the packages provided by SWT. It is not available on all
+	 * platforms and should never be accessed from application code.
+	 * </p>
+	 */
+	public GdkDrawable* mask;
+
+	cairo_surface_t* surface;
+    cairo_surface_t* surfaceData;
+
+	/**
+	 * specifies the transparent pixel
+	 */
+	int transparentPixel = -1;
+
+	/**
+	 * The GC the image is currently selected in.
+	 */
+	GC memGC;
+
+	/**
+	 * The alpha data of the image.
+	 */
+	byte[] alphaData;
+
+	/**
+	 * The global alpha value to be used for every pixel.
+	 */
+	int alpha = -1;
+
+	/**
+	 * The width of the image.
+	 */
+	int width = -1;
+
+	/**
+	 * The height of the image.
+	 */
+	int height = -1;
+
+	/**
+	 * Specifies the default scanline padding.
+	 */
+	static const int DEFAULT_SCANLINE_PAD = 4;
+
+this() {
+}
+
+/**
+ * Constructs an empty instance of this class with the
+ * specified width and height. The result may be drawn upon
+ * by creating a GC and using any of its drawing operations,
+ * as shown in the following example:
+ * <pre>
+ *    Image i = new Image(device, width, height);
+ *    GC gc = new GC(i);
+ *    gc.drawRectangle(0, 0, 50, 50);
+ *    gc.dispose();
+ * </pre>
+ * <p>
+ * Note: Some platforms may have a limitation on the size
+ * of image that can be created (size depends on width, height,
+ * and depth). For example, Windows 95, 98, and ME do not allow
+ * images larger than 16M.
+ * </p>
+ *
+ * @param device the device on which to create the image
+ * @param width the width of the new image
+ * @param height the height of the new image
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative or zero</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public this(Device device, int width, int height) {
+	if (device is null) device = Device.getDevice();
+	if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	init(device, width, height);
+	if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Constructs a new instance of this class based on the
+ * provided image, with an appearance that varies depending
+ * on the value of the flag. The possible flag values are:
+ * <dl>
+ * <dt><b>IMAGE_COPY</b></dt>
+ * <dd>the result is an identical copy of srcImage</dd>
+ * <dt><b>IMAGE_DISABLE</b></dt>
+ * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd>
+ * <dt><b>IMAGE_GRAY</b></dt>
+ * <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd>
+ * </dl>
+ *
+ * @param device the device on which to create the image
+ * @param srcImage the image to use as the source
+ * @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if srcImage is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the flag is not one of <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code></li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or is otherwise in an invalid state</li>
+ *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is not supported</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public this(Device device, Image srcImage, int flag) {
+	if (device is null) device = Device.getDevice();
+	if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (srcImage is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (srcImage.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	switch (flag) {
+		case SWT.IMAGE_COPY:
+		case SWT.IMAGE_DISABLE:
+		case SWT.IMAGE_GRAY:
+			break;
+		default:
+			SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	this.device = device;
+	this.type = srcImage.type;
+
+	/* Get source image size */
+	int w, h;
+ 	OS.gdk_drawable_get_size(srcImage.pixmap, &w, &h);
+ 	int width = w;
+ 	int height = h;
+
+ 	/* Copy the mask */
+	if ((srcImage.type == SWT.ICON && srcImage.mask !is null ) || srcImage.transparentPixel != -1) {
+		/* Generate the mask if necessary. */
+		if (srcImage.transparentPixel != -1) srcImage.createMask();
+        //PORTING_FIXME cast
+		GdkDrawable* mask = cast(GdkDrawable*) OS.gdk_pixmap_new( null, width, height, 1);
+		if (mask is null ) SWT.error(SWT.ERROR_NO_HANDLES);
+		auto gdkGC = OS.gdk_gc_new(mask);
+		if (gdkGC is null) SWT.error(SWT.ERROR_NO_HANDLES);
+		OS.gdk_draw_drawable(mask, gdkGC, srcImage.mask, 0, 0, 0, 0, width, height);
+		OS.g_object_unref(gdkGC);
+		this.mask = mask;
+		/* Destroy the image mask if the there is a GC created on the image */
+		if (srcImage.transparentPixel != -1 && srcImage.memGC != null) srcImage.destroyMask();
+	}
+
+	/* Copy transparent pixel and alpha data */
+	if (flag != SWT.IMAGE_DISABLE) transparentPixel = srcImage.transparentPixel;
+	alpha = srcImage.alpha;
+	if (srcImage.alphaData != null) {
+		alphaData = srcImage.alphaData.dup;
+	}
+	createAlphaMask(width, height);
+
+	/* Create the new pixmap */
+	auto pixmap = cast(GdkDrawable*) OS.gdk_pixmap_new (cast(GdkDrawable*)OS.GDK_ROOT_PARENT(), width, height, -1);
+	if (pixmap is null) SWT.error(SWT.ERROR_NO_HANDLES);
+	auto gdkGC = OS.gdk_gc_new(pixmap);
+	if (gdkGC is null) SWT.error(SWT.ERROR_NO_HANDLES);
+	this.pixmap = pixmap;
+
+	if (flag == SWT.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;
+	}
+
+	/* Retrieve the source pixmap data */
+	auto pixbuf = OS.gdk_pixbuf_new(cast(GdkColorspace)OS.GDK_COLORSPACE_RGB, false, 8, width, height);
+	if (pixbuf is null) SWT.error(SWT.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 SWT.IMAGE_DISABLE: {
+			Color zeroColor = device.getSystemColor(SWT.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(SWT.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 SWT.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;
+		}
+	}
+
+	/* Copy data back to destination pixmap */
+	OS.gdk_pixbuf_render_to_drawable(pixbuf, pixmap, gdkGC, 0, 0, 0, 0, width, height, cast(GdkRgbDither)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);
+}
+
+/**
+ * Constructs an empty instance of this class with the
+ * width and height of the specified rectangle. The result
+ * may be drawn upon by creating a GC and using any of its
+ * drawing operations, as shown in the following example:
+ * <pre>
+ *    Image i = new Image(device, boundsRectangle);
+ *    GC gc = new GC(i);
+ *    gc.drawRectangle(0, 0, 50, 50);
+ *    gc.dispose();
+ * </pre>
+ * <p>
+ * Note: Some platforms may have a limitation on the size
+ * of image that can be created (size depends on width, height,
+ * and depth). For example, Windows 95, 98, and ME do not allow
+ * images larger than 16M.
+ * </p>
+ *
+ * @param device the device on which to create the image
+ * @param bounds a rectangle specifying the image's width and height (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public this(Device device, Rectangle bounds) {
+	if (device is null) device = Device.getDevice();
+	if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (bounds is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	init(device, bounds.width, bounds.height);
+	if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Constructs an instance of this class from the given
+ * <code>ImageData</code>.
+ *
+ * @param device the device on which to create the image
+ * @param data the image data to create the image from (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the image data is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public this(Device device, ImageData data) {
+	if (device is null) device = Device.getDevice();
+	if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	init(device, data);
+	if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Constructs an instance of this class, whose type is
+ * <code>SWT.ICON</code>, from the two given <code>ImageData</code>
+ * objects. The two images must be the same size. Pixel transparency
+ * in either image will be ignored.
+ * <p>
+ * The mask image should contain white wherever the icon is to be visible,
+ * and black wherever the icon is to be transparent. In addition,
+ * the source image should contain black wherever the icon is to be
+ * transparent.
+ * </p>
+ *
+ * @param device the device on which to create the icon
+ * @param source the color data for the icon
+ * @param mask the mask data for the icon
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if either the source or mask is null </li>
+ *    <li>ERROR_INVALID_ARGUMENT - if source and mask are different sizes</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public this(Device device, ImageData source, ImageData mask) {
+	if (device is null) device = Device.getDevice();
+	if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (source is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (mask is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (source.width != mask.width || source.height != mask.height) {
+		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	mask = ImageData.convertMask (mask);
+	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);
+}
+
+/**
+ * Constructs an instance of this class by loading its representation
+ * from the specified input stream. Throws an error if an error
+ * occurs while loading the image, or if the result is an image
+ * of an unsupported type.  Application code is still responsible
+ * for closing the input stream.
+ * <p>
+ * This constructor is provided for convenience when loading a single
+ * image only. If the stream contains multiple images, only the first
+ * one will be loaded. To load multiple images, use
+ * <code>ImageLoader.load()</code>.
+ * </p><p>
+ * This constructor may be used to load a resource as follows:
+ * </p>
+ * <pre>
+ *     static Image loadImage (Display display, Class clazz, String string) {
+ *          InputStream stream = clazz.getResourceAsStream (string);
+ *          if (stream is null) return null;
+ *          Image image = null;
+ *          try {
+ *               image = new Image (display, stream);
+ *          } catch (SWTException ex) {
+ *          } finally {
+ *               try {
+ *                    stream.close ();
+ *               } catch (IOException ex) {}
+ *          }
+ *          return image;
+ *     }
+ * </pre>
+ *
+ * @param device the device on which to create the image
+ * @param stream the input stream to load the image from
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
+ *    <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data </li>
+ *    <li>ERROR_UNSUPPORTED_DEPTH - if the image stream describes an image with an unsupported depth</li>
+ *    <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public this(Device device, InputStream stream) {
+	if (device is null) device = Device.getDevice();
+	if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	init(device, new ImageData(stream));
+	if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Constructs an instance of this class by loading its representation
+ * from the file with the specified name. Throws an error if an error
+ * occurs while loading the image, or if the result is an image
+ * of an unsupported type.
+ * <p>
+ * This constructor is provided for convenience when loading
+ * a single image only. If the specified file contains
+ * multiple images, only the first one will be used.
+ *
+ * @param device the device on which to create the image
+ * @param filename the name of the file to load the image from
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_IO - if an IO error occurs while reading from the file</li>
+ *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
+ *    <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li>
+ *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public this(Device device, char[] filename) {
+	if (device is null) device = Device.getDevice();
+	if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (filename is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	this.device = device;
+	try {
+		int length = filename.length;
+		auto pixbuf = OS.gdk_pixbuf_new_from_file(toStringz(filename), null);
+		if (pixbuf !is null) {
+			bool hasAlpha = cast(bool)OS.gdk_pixbuf_get_has_alpha(pixbuf);
+			if (hasAlpha) {
+				/*
+				* Bug in GTK. Depending on the image (seems to affect images that have
+				* some degree of transparency all over the image), gdk_pixbuff_render_pixmap_and_mask()
+				* will return a corrupt pixmap. To avoid this, read in and store the alpha channel data
+				* for the image and then set it to 0xFF to prevent any possible corruption from
+				* gdk_pixbuff_render_pixmap_and_mask().
+				*/
+				int width = OS.gdk_pixbuf_get_width(pixbuf);
+				int height = OS.gdk_pixbuf_get_height(pixbuf);
+				int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+				auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+				byte[] line = new byte[stride];
+				alphaData = new byte[width * height];
+				for (int y = 0; y < height; y++) {
+					memmove(line.ptr, pixels + (y * stride), stride);
+					for (int x = 0; x < width; x++) {
+						alphaData[y*width+x] = line[x*4 + 3];
+						line[x*4 + 3] = cast(byte) 0xFF;
+					}
+					memmove(pixels + (y * stride), line.ptr, stride);
+				}
+				createAlphaMask(width, height);
+			}
+			GdkPixmap* pixmap_return;
+			OS.gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap_return, null, 0);
+			this.type = SWT.BITMAP;
+			this.pixmap = cast(GdkDrawable*)pixmap_return;
+			if (pixmap is null) SWT.error(SWT.ERROR_NO_HANDLES);
+			OS.g_object_unref (pixbuf);
+			return;
+		}
+	} catch (SWTException e) {}
+	init(device, new ImageData(filename));
+	if (device.tracking) device.new_Object(this);
+}
+
+void createAlphaMask (int width, int height) {
+	if (device.useXRender && (alpha != -1 || alphaData != null)) {
+		mask = cast(GdkDrawable*)OS.gdk_pixmap_new(null, alpha != -1 ? 1 : width, alpha != -1 ? 1 : height, 8);
+		if (mask is null) SWT.error(SWT.ERROR_NO_HANDLES);
+		auto gc = OS.gdk_gc_new(mask);
+		if (alpha != -1) {
+			GdkColor* color = new GdkColor();
+			color.pixel = (alpha & 0xFF) << 8 | (alpha & 0xFF);
+			OS.gdk_gc_set_foreground(gc, color);
+			OS.gdk_draw_rectangle(mask, gc, 1, 0, 0, 1, 1);
+		} else {
+			GdkImage* imagePtr = OS.gdk_drawable_get_image(mask, 0, 0, width, height);
+			if (imagePtr is null) SWT.error(SWT.ERROR_NO_HANDLES);
+			GdkImage* gdkImage = new GdkImage();
+			*gdkImage = *imagePtr;
+			if (gdkImage.bpl == width) {
+				memmove(gdkImage.mem, alphaData.ptr, alphaData.length);
+			} else {
+				byte[] line = new byte[gdkImage.bpl];
+				for (int y = 0; y < height; y++) {
+                    line[ 0 .. width ] = alphaData[ width * y .. width * y + width ];
+					memmove(gdkImage.mem + (gdkImage.bpl * y), line.ptr, gdkImage.bpl);
+				}
+			}
+			OS.gdk_draw_image(mask, gc, imagePtr, 0, 0, 0, 0, width, height);
+			OS.g_object_unref(imagePtr);
+		}
+		OS.g_object_unref(gc);
+	}
+}
+
+/**
+ * Create the receiver's mask if necessary.
+ */
+void createMask() {
+	if (mask !is null ) return;
+	mask = createMask(getImageData(), false);
+	if (mask is null ) SWT.error(SWT.ERROR_NO_HANDLES);
+}
+
+GdkDrawable* createMask(ImageData image, bool copy) {
+	ImageData mask = image.getTransparencyMask();
+	byte[] data = mask.data;
+	byte[] maskData = copy ? new byte[data.length] : data;
+	for (int i = 0; i < maskData.length; i++) {
+		byte s = data[i];
+		maskData[i] = cast(byte)(((s & 0x80) >> 7) | ((s & 0x40) >> 5) |
+			((s & 0x20) >> 3) | ((s & 0x10) >> 1) | ((s & 0x08) << 1) |
+			((s & 0x04) << 3) | ((s & 0x02) << 5) |	((s & 0x01) << 7));
+	}
+	maskData = ImageData.convertPad(maskData, mask.width, mask.height, mask.depth, mask.scanlinePad, 1);
+	return cast(GdkDrawable*)OS.gdk_bitmap_create_from_data(null, cast(char*)maskData.ptr, mask.width, mask.height);
+}
+
+void createSurface() {
+	if (surface !is null ) return;
+	/* Generate the mask if necessary. */
+	if (transparentPixel != -1) createMask();
+	int w, h;
+	OS.gdk_drawable_get_size(pixmap, &w, &h);
+	int width = w, height = h;
+	if (mask !is null || alpha != -1 || alphaData != null) {
+	 	auto pixbuf = OS.gdk_pixbuf_new( cast(GdkColorspace)OS.GDK_COLORSPACE_RGB, true, 8, width, height);
+		if (pixbuf is null) SWT.error(SWT.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);
+		int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+		auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+		byte[] line = new byte[stride];
+		if (mask !is null && OS.gdk_drawable_get_depth(mask) == 1) {
+			auto maskPixbuf = OS.gdk_pixbuf_new(cast(GdkColorspace)OS.GDK_COLORSPACE_RGB, false, 8, width, height);
+			if (maskPixbuf is null) SWT.error(SWT.ERROR_NO_HANDLES);
+			OS.gdk_pixbuf_get_from_drawable(maskPixbuf, mask, null, 0, 0, 0, 0, width, height);
+			int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf);
+			auto maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf);
+			byte[] maskLine = new byte[maskStride];
+			auto offset = pixels, maskOffset = maskPixels;
+			for (int y=0; y<height; y++) {
+				memmove(line.ptr, offset, stride);
+				memmove(maskLine.ptr, maskOffset, maskStride);
+				for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
+					if (maskLine[x * 3] == 0) {
+						line[offset1 + 0] = line[offset1 + 1] = line[offset1 + 2] = line[offset1 + 3] = 0;
+					}
+					byte temp = line[offset1];
+					line[offset1] = line[offset1 + 2];
+					line[offset1 + 2] = temp;
+				}
+				memmove(offset, line.ptr, stride);
+				offset += stride;
+				maskOffset += maskStride;
+			}
+			OS.g_object_unref(maskPixbuf);
+		} else if (alpha != -1) {
+			auto offset = pixels;
+			for (int y=0; y<height; y++) {
+				memmove(line.ptr, offset, stride);
+				for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
+					line[offset1+3] = cast(byte)alpha;
+					/* pre-multiplied alpha */
+					int r = ((line[offset1 + 0] & 0xFF) * alpha) + 128;
+					r = (r + (r >> 8)) >> 8;
+					int g = ((line[offset1 + 1] & 0xFF) * alpha) + 128;
+					g = (g + (g >> 8)) >> 8;
+					int b = ((line[offset1 + 2] & 0xFF) * alpha) + 128;
+					b = (b + (b >> 8)) >> 8;
+					line[offset1 + 0] = cast(byte)b;
+					line[offset1 + 1] = cast(byte)g;
+					line[offset1 + 2] = cast(byte)r;
+				}
+				memmove(offset, line.ptr, stride);
+				offset += stride;
+			}
+		} else if (alphaData != null) {
+			auto offset = pixels;
+			for (int y = 0; y < h; y++) {
+				memmove (line.ptr, offset, stride);
+				for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
+					int alpha = alphaData [y*w+x] & 0xFF;
+					line[offset1+3] = cast(byte)alpha;
+					/* pre-multiplied alpha */
+					int r = ((line[offset1 + 0] & 0xFF) * alpha) + 128;
+					r = (r + (r >> 8)) >> 8;
+					int g = ((line[offset1 + 1] & 0xFF) * alpha) + 128;
+					g = (g + (g >> 8)) >> 8;
+					int b = ((line[offset1 + 2] & 0xFF) * alpha) + 128;
+					b = (b + (b >> 8)) >> 8;
+					line[offset1 + 0] = cast(byte)b;
+					line[offset1 + 1] = cast(byte)g;
+					line[offset1 + 2] = cast(byte)r;
+				}
+				memmove (offset, line.ptr, stride);
+				offset += stride;
+			}
+		} else {
+			auto offset = pixels;
+			for (int y = 0; y < h; y++) {
+				memmove (line.ptr, offset, stride);
+				for (int x=0, offset1=0; x<width; x++, offset1 += 4) {
+					line[offset1+3] = cast(byte)0xFF;
+					byte temp = line[offset1];
+					line[offset1] = line[offset1 + 2];
+					line[offset1 + 2] = temp;
+				}
+				memmove (offset, line.ptr, stride);
+				offset += stride;
+			}
+		}
+		surfaceData = cast(cairo_surface_t*) OS.g_malloc(stride * height);
+		memmove(surfaceData, pixels, stride * height);
+		surface = Cairo.cairo_image_surface_create_for_data(surfaceData, Cairo.CAIRO_FORMAT_ARGB32, width, height, stride);
+		OS.g_object_unref(pixbuf);
+	} else {
+		auto xDisplay = OS.GDK_DISPLAY();
+		auto xDrawable = OS.GDK_PIXMAP_XID(pixmap);
+		auto xVisual = OS.gdk_x11_visual_get_xvisual(OS.gdk_visual_get_system());
+		surface = Cairo.cairo_xlib_surface_create(xDisplay, xDrawable, xVisual, width, height);
+	}
+	/* Destroy the image mask if the there is a GC created on the image */
+	if (transparentPixel != -1 && memGC != null) destroyMask();
+}
+
+/**
+ * Destroy the receiver's mask if it exists.
+ */
+void destroyMask() {
+	if (mask == 0) return;
+	OS.g_object_unref(mask);
+	mask = 0;
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the image. Applications must dispose of all images which
+ * they allocate.
+ */
+public void dispose () {
+	if (pixmap == 0) return;
+	if (device.isDisposed()) return;
+	if (memGC != null) memGC.dispose();
+	if (pixmap != 0) OS.g_object_unref(pixmap);
+	if (mask != 0) OS.g_object_unref(mask);
+	if (surface != 0) Cairo.cairo_surface_destroy(surface);
+	if (surfaceData != 0) OS.g_free(surfaceData);
+	surfaceData = surface = pixmap = mask = 0;
+	memGC = null;
+	if (device.tracking) device.dispose_Object(this);
+	device = null;
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public int opEquals (Object object) {
+	if (object is this) return true;
+	if ( auto image = cast(Image)object ){
+        return device is image.device && pixmap is image.pixmap;
+    }
+    return false;
+}
+
+/**
+ * Returns the color to which to map the transparent pixel, or null if
+ * the receiver has no transparent pixel.
+ * <p>
+ * There are certain uses of Images that do not support transparency
+ * (for example, setting an image into a button or label). In these cases,
+ * it may be desired to simulate transparency by using the background
+ * color of the widget to paint the transparent pixels of the image.
+ * Use this method to check which color will be used in these cases
+ * in place of transparency. This value may be set with setBackground().
+ * <p>
+ *
+ * @return the background color of the image, or null if there is no transparency in the image
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getBackground() {
+	if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (transparentPixel == -1) return null;
+	//NOT DONE
+	return null;
+}
+
+/**
+ * Returns the bounds of the receiver. The rectangle will always
+ * have x and y values of 0, and the width and height of the
+ * image.
+ *
+ * @return a rectangle specifying the image's bounds
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
+ * </ul>
+ */
+public Rectangle getBounds() {
+	if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (width != -1 && height != -1) {
+		return new Rectangle(0, 0, width, height);
+	}
+	int[] w = new int[1]; int[] h = new int[1];
+	OS.gdk_drawable_get_size(pixmap, w, h);
+	return new Rectangle(0, 0, width = w[0], height = h[0]);
+}
+
+/**
+ * Returns an <code>ImageData</code> based on the receiver
+ * Modifications made to this <code>ImageData</code> will not
+ * affect the Image.
+ *
+ * @return an <code>ImageData</code> containing the image's data and attributes
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
+ * </ul>
+ *
+ * @see ImageData
+ */
+public ImageData getImageData() {
+	if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+
+	int[] w = new int[1], h = new int[1];
+ 	OS.gdk_drawable_get_size(pixmap, w, h);
+ 	int width = w[0], height = h[0];
+ 	int /*long*/ pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, width, height);
+	if (pixbuf == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	int /*long*/ colormap = OS.gdk_colormap_get_system();
+	OS.gdk_pixbuf_get_from_drawable(pixbuf, pixmap, colormap, 0, 0, 0, 0, width, height);
+	int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+	int /*long*/ pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+	byte[] srcData = new byte[stride * height];
+	OS.memmove(srcData, pixels, srcData.length);
+	OS.g_object_unref(pixbuf);
+
+	PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+	ImageData data = new ImageData(width, height, 24, palette);
+	data.data = srcData;
+	data.bytesPerLine = stride;
+
+	if (transparentPixel == -1 && type == SWT.ICON && mask != 0) {
+		/* Get the icon mask data */
+		int /*long*/ gdkImagePtr = OS.gdk_drawable_get_image(mask, 0, 0, width, height);
+		if (gdkImagePtr == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+		GdkImage gdkImage = new GdkImage();
+		OS.memmove(gdkImage, gdkImagePtr);
+		byte[] maskData = new byte[gdkImage.bpl * gdkImage.height];
+		OS.memmove(maskData, gdkImage.mem, maskData.length);
+		OS.g_object_unref(gdkImagePtr);
+		int maskPad;
+		for (maskPad = 1; maskPad < 128; maskPad++) {
+			int bpl = (((width + 7) / 8) + (maskPad - 1)) / maskPad * maskPad;
+			if (gdkImage.bpl == bpl) break;
+		}
+		/* Make mask scanline pad equals to 2 */
+		data.maskPad = 2;
+		maskData = ImageData.convertPad(maskData, width, height, 1, maskPad, data.maskPad);
+		/* Bit swap the mask data if necessary */
+		if (gdkImage.byte_order == OS.GDK_LSB_FIRST) {
+			for (int i = 0; i < maskData.length; i++) {
+				byte b = maskData[i];
+				maskData[i] = cast(byte)(((b & 0x01) << 7) | ((b & 0x02) << 5) |
+					((b & 0x04) << 3) |	((b & 0x08) << 1) | ((b & 0x10) >> 1) |
+					((b & 0x20) >> 3) |	((b & 0x40) >> 5) | ((b & 0x80) >> 7));
+			}
+		}
+		data.maskData = maskData;
+	}
+	data.transparentPixel = transparentPixel;
+	data.alpha = alpha;
+	if (alpha == -1 && alphaData != null) {
+		data.alphaData = new byte[alphaData.length];
+		System.arraycopy(alphaData, 0, data.alphaData, 0, alphaData.length);
+	}
+	return data;
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new image.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param type the type of the image (<code>SWT.BITMAP</code> or <code>SWT.ICON</code>)
+ * @param pixmap the OS handle for the image
+ * @param mask the OS handle for the image mask
+ *
+ * @private
+ */
+public static Image gtk_new(Device device, int type, int /*long*/ pixmap, int /*long*/ mask) {
+	if (device is null) device = Device.getDevice();
+	Image image = new Image();
+	image.type = type;
+	image.pixmap = pixmap;
+	image.mask = mask;
+	image.device = device;
+	return image;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+public hash_t toHash () {
+	return cast(hash_t)/*64*/pixmap;
+}
+
+void init(Device device, int width, int height) {
+	if (width <= 0 || height <= 0) {
+		SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+	}
+	this.device = device;
+	this.type = SWT.BITMAP;
+
+	/* Create the pixmap */
+	this.pixmap = OS.gdk_pixmap_new(OS.GDK_ROOT_PARENT(), width, height, -1);
+	if (pixmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	/* Fill the bitmap with white */
+	GdkColor white = new GdkColor();
+	white.red = cast(short)0xFFFF;
+	white.green = cast(short)0xFFFF;
+	white.blue = cast(short)0xFFFF;
+	auto colormap = OS.gdk_colormap_get_system();
+	OS.gdk_colormap_alloc_color(colormap, white, true, true);
+	auto gdkGC = OS.gdk_gc_new(pixmap);
+	OS.gdk_gc_set_foreground(gdkGC, white);
+	OS.gdk_draw_rectangle(pixmap, gdkGC, 1, 0, 0, width, height);
+	OS.g_object_unref(gdkGC);
+	OS.gdk_colormap_free_colors(colormap, white, 1);
+}
+
+void init(Device device, ImageData image) {
+	if (image is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	this.device = device;
+	int width = image.width;
+	int height = image.height;
+	PaletteData palette = image.palette;
+	if (!(((image.depth == 1 || image.depth == 2 || image.depth == 4 || image.depth == 8) && !palette.isDirect) ||
+		((image.depth == 8) || (image.depth == 16 || image.depth == 24 || image.depth == 32) && palette.isDirect)))
+			SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH);
+	auto pixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, width, height);
+	if (pixbuf == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+	auto data = OS.gdk_pixbuf_get_pixels(pixbuf);
+	byte[] buffer = image.data;
+	if (!palette.isDirect || image.depth != 24 || stride != image.bytesPerLine || palette.redMask != 0xFF0000 || palette.greenMask != 0xFF00 || palette.blueMask != 0xFF) {
+		buffer = new byte[stride * height];
+		if (palette.isDirect) {
+			ImageData.blit(ImageData.BLIT_SRC,
+				image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, palette.redMask, palette.greenMask, palette.blueMask,
+				ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+				buffer, 24, stride, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
+				false, false);
+		} else {
+			RGB[] rgbs = palette.getRGBs();
+			int length = rgbs.length;
+			byte[] srcReds = new byte[length];
+			byte[] srcGreens = new byte[length];
+			byte[] srcBlues = new byte[length];
+			for (int i = 0; i < rgbs.length; i++) {
+				RGB rgb = rgbs[i];
+				if (rgb is null) continue;
+				srcReds[i] = cast(byte)rgb.red;
+				srcGreens[i] = cast(byte)rgb.green;
+				srcBlues[i] = cast(byte)rgb.blue;
+			}
+			ImageData.blit(ImageData.BLIT_SRC,
+				image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues,
+				ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+				buffer, 24, stride, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
+				false, false);
+		}
+	}
+	OS.memmove(data, buffer, stride * height);
+	auto pixmap = OS.gdk_pixmap_new (OS.GDK_ROOT_PARENT(), width, height, -1);
+	if (pixmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	auto gdkGC = OS.gdk_gc_new(pixmap);
+	if (gdkGC == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	OS.gdk_pixbuf_render_to_drawable(pixbuf, pixmap, gdkGC, 0, 0, 0, 0, width, height, OS.GDK_RGB_DITHER_NORMAL, 0, 0);
+	OS.g_object_unref(gdkGC);
+	OS.g_object_unref(pixbuf);
+
+	bool isIcon = image.getTransparencyType() == SWT.TRANSPARENCY_MASK;
+	if (isIcon || image.transparentPixel != -1) {
+		if (image.transparentPixel != -1) {
+			RGB rgb = null;
+			if (palette.isDirect) {
+				rgb = palette.getRGB(image.transparentPixel);
+			} else {
+				if (image.transparentPixel < palette.colors.length) {
+					rgb = palette.getRGB(image.transparentPixel);
+				}
+			}
+			if (rgb != null) {
+				transparentPixel = rgb.red << 16 | rgb.green << 8 | rgb.blue;
+			}
+		}
+		int /*long*/ mask = createMask(image, isIcon);
+		if (mask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+		this.mask = mask;
+		if (isIcon) {
+			this.type = SWT.ICON;
+		} else {
+			this.type = SWT.BITMAP;
+		}
+	} else {
+		this.type = SWT.BITMAP;
+		this.mask = 0;
+		this.alpha = image.alpha;
+		if (image.alpha == -1 && image.alphaData != null) {
+			this.alphaData = new byte[image.alphaData.length];
+			System.arraycopy(image.alphaData, 0, this.alphaData, 0, alphaData.length);
+		}
+		createAlphaMask(width, height);
+	}
+	this.pixmap = pixmap;
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ */
+public int /*long*/ internal_new_GC (GCData data) {
+	if (pixmap == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (type != SWT.BITMAP || memGC != null) {
+		SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	}
+	auto gdkGC = OS.gdk_gc_new(pixmap);
+	if (data != null) {
+		int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+		if ((data.style & mask) == 0) {
+			data.style |= SWT.LEFT_TO_RIGHT;
+		}
+		data.device = device;
+		data.drawable = pixmap;
+		data.background = device.COLOR_WHITE.handle;
+		data.foreground = device.COLOR_BLACK.handle;
+		data.font = device.systemFont.handle;
+		data.image = this;
+	}
+	return gdkGC;
+}
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public void internal_dispose_GC (int /*long*/ gdkGC, GCData data) {
+	OS.g_object_unref(gdkGC);
+}
+
+/**
+ * Returns <code>true</code> if the image has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the image.
+ * When an image has been disposed, it is an error to
+ * invoke any other method using the image.
+ *
+ * @return <code>true</code> when the image is disposed and <code>false</code> otherwise
+ */
+public bool isDisposed() {
+	return pixmap == 0;
+}
+
+/**
+ * Sets the color to which to map the transparent pixel.
+ * <p>
+ * There are certain uses of <code>Images</code> that do not support
+ * transparency (for example, setting an image into a button or label).
+ * In these cases, it may be desired to simulate transparency by using
+ * the background color of the widget to paint the transparent pixels
+ * of the image. This method specifies the color that will be used in
+ * these cases. For example:
+ * <pre>
+ *    Button b = new Button();
+ *    image.setBackground(b.getBackground());
+ *    b.setImage(image);
+ * </pre>
+ * </p><p>
+ * The image may be modified by this operation (in effect, the
+ * transparent regions may be filled with the supplied color).  Hence
+ * this operation is not reversible and it is not legal to call
+ * this function twice or with a null argument.
+ * </p><p>
+ * This method has no effect if the receiver does not have a transparent
+ * pixel value.
+ * </p>
+ *
+ * @param color the color to use when a transparent pixel is specified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setBackground(Color color) {
+	if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+	if (color is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	if (transparentPixel == -1) return;
+	//NOT DONE
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public char[] toString () {
+	if (isDisposed()) return "Image {*DISPOSED*}";
+	return Format( "Image {{{}}", pixmap);
+}
+
+}
++/
\ No newline at end of file
--- a/dwt/graphics/ImageData.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/graphics/ImageData.d	Mon Jan 07 03:41:50 2008 +0100
@@ -13,21 +13,15 @@
 
 import dwt.graphics.PaletteData;
 import dwt.graphics.RGB;
+import dwt.graphics.Image;
+import dwt.graphics.GC;
+import dwt.graphics.Device;
 import dwt.graphics.ImageDataLoader;
 import dwt.SWT;
 import dwt.internal.CloneableCompatibility;
 
 public import dwt.dwthelper.InputStream;
 
-// PORTING_TYPE
-class GC{
-    void drawImage(Image, int, int, int, int, int, int, int, int );
-}
-class Device{}
-class Image{
-    this( Device, ImageData ){}
-    void dispose(){}
-}
 
 /**
  * Instances of this class are device-independent descriptions
--- a/dwt/graphics/ImageLoader.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/graphics/ImageLoader.d	Mon Jan 07 03:41:50 2008 +0100
@@ -14,8 +14,6 @@
 public import dwt.graphics.ImageLoaderListener;
 public import dwt.graphics.ImageLoaderEvent;
 public import dwt.graphics.ImageData;
-//public import dwt.dwthelper.InputStream;
-//public import dwt.dwthelper.OutputStream;
 
 import dwt.SWT;
 import dwt.internal.Compatibility;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/graphics/Pattern.d	Mon Jan 07 03:41:50 2008 +0100
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.graphics.Pattern;
+
+class Pattern{
+}
+/++++
+import dwt.*;
+import dwt.internal.cairo.*;
+
+/**
+ * Instances of this class represent patterns to use while drawing. Patterns
+ * can be specified either as bitmaps or gradients.
+ * <p>
+ * Application code must explicitly invoke the <code>Pattern.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <p>
+ * This class requires the operating system's advanced graphics subsystem
+ * which may not be available on some platforms.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class Pattern extends Resource {
+
+	/**
+	 * the OS resource for the Pattern
+	 * (Warning: This field is platform dependent)
+	 * <p>
+	 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+	 * public API. It is marked public only so that it can be shared
+	 * within the packages provided by SWT. It is not available on all
+	 * platforms and should never be accessed from application code.
+	 * </p>
+	 */
+	public int /*long*/ handle;
+
+/**
+ * Constructs a new Pattern given an image. Drawing with the resulting
+ * pattern will cause the image to be tiled over the resulting area.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param image the image that the pattern will draw
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device, or the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Pattern(Device device, Image image) {
+	if (device == null) device = Device.getDevice();
+	if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	this.device = device;
+	device.checkCairo();
+	image.createSurface();
+	handle = Cairo.cairo_pattern_create_for_surface(image.surface);
+	if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+	Cairo.cairo_pattern_set_extend(handle, Cairo.CAIRO_EXTEND_REPEAT);
+	if (device.tracking) device.new_Object(this);
+}
+
+/**
+ * Constructs a new Pattern that represents a linear, two color
+ * gradient. Drawing with the pattern will cause the resulting area to be
+ * tiled with the gradient specified by the arguments.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param x1 the x coordinate of the starting corner of the gradient
+ * @param y1 the y coordinate of the starting corner of the gradient
+ * @param x2 the x coordinate of the ending corner of the gradient
+ * @param y2 the y coordinate of the ending corner of the gradient
+ * @param color1 the starting color of the gradient
+ * @param color2 the ending color of the gradient
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device,
+ *                              or if either color1 or color2 is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, Color color2) {
+	this(device, x1, y1, x2, y2, color1, 0xFF, color2, 0xFF);
+}
+/**
+ * Constructs a new Pattern that represents a linear, two color
+ * gradient. Drawing with the pattern will cause the resulting area to be
+ * tiled with the gradient specified by the arguments.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param x1 the x coordinate of the starting corner of the gradient
+ * @param y1 the y coordinate of the starting corner of the gradient
+ * @param x2 the x coordinate of the ending corner of the gradient
+ * @param y2 the y coordinate of the ending corner of the gradient
+ * @param color1 the starting color of the gradient
+ * @param alpha1 the starting alpha value of the gradient
+ * @param color2 the ending color of the gradient
+ * @param alpha2 the ending alpha value of the gradient
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device,
+ *                              or if either color1 or color2 is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ *
+ * @since 3.2
+ */
+public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, int alpha1, Color color2, int alpha2) {
+	if (device == null) device = Device.getDevice();
+	if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (color1 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (color1.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	if (color2 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+	if (color2.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+	this.device = device;
+	device.checkCairo();
+	handle = Cairo.cairo_pattern_create_linear(x1, y1, x2, y2);
+	if (handle == 0) SWT.error(SWT.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);
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the Pattern. Applications must dispose of all Patterns that
+ * they allocate.
+ */
+public void dispose() {
+	if (handle == 0) return;
+	if (device.isDisposed()) return;
+	Cairo.cairo_pattern_destroy(handle);
+	handle = 0;
+	if (device.tracking) device.dispose_Object(this);
+	device = null;
+}
+
+/**
+ * Returns <code>true</code> if the Pattern has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the Pattern.
+ * When a Pattern has been disposed, it is an error to
+ * invoke any other method using the Pattern.
+ *
+ * @return <code>true</code> when the Pattern is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+	return handle == 0;
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString() {
+	if (isDisposed()) return "Pattern {*DISPOSED*}";
+	return "Pattern {" + handle + "}";
+}
+
+}
+++++/
\ No newline at end of file
--- a/dwt/graphics/Region.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/graphics/Region.d	Mon Jan 07 03:41:50 2008 +0100
@@ -15,11 +15,12 @@
 import dwt.graphics.Resource;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
-//import dwt.graphics.Device;
+import dwt.graphics.Device;
 import dwt.internal.gtk.OS;
 import dwt.internal.gtk.c.gdktypes;
 
 import tango.text.convert.Format;
+
 /**
  * Instances of this class represent areas of an x-y coordinate
  * system that are aggregates of the areas covered by a number
--- a/dwt/graphics/Resource.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/graphics/Resource.d	Mon Jan 07 03:41:50 2008 +0100
@@ -12,24 +12,8 @@
 
 import dwt.SWT;
 
-//PORTING_TYPE
-//import dwt.graphics.Device;
+import dwt.graphics.Device;
 import dwt.internal.gtk.c.gdktypes : GdkColor;
-class Device{
-    static Device getDevice(){
-        return null;
-    }
-    void new_Object (Object object) {
-    }
-    void dispose_Object (Object object) {
-    }
-    bool tracking;
-    bool isDisposed(){
-        return false;
-    }
-    int[] colorRefCount;
-    GdkColor*[] gdkColors;
-}
 
 /**
  * This class is the abstract superclass of all graphics resource objects.
--- a/dwt/internal/BidiUtil.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/internal/BidiUtil.d	Mon Jan 07 03:41:50 2008 +0100
@@ -10,10 +10,9 @@
  *******************************************************************************/
 module dwt.internal.BidiUtil;
 
-//import dwt.graphics.GC;
+import dwt.graphics.GC;
 
 // PORTING_TYPE
-class GC{}
 class Runnable{}
 
 /*
--- a/dwt/internal/gtk/OS.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/internal/gtk/OS.d	Mon Jan 07 03:41:50 2008 +0100
@@ -27,6 +27,12 @@
         dwt.internal.gtk.c.gthread,
         dwt.internal.gtk.c.gdkpixbuf;
 
+// temporary added, because was not yet available
+private extern(C) GdkWindow* GDK_ROOT_PARENT();
+private extern(C) GdkPixbuf* gdk_pixbuf_new (GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample,
+               int width, int height);
+
+
 template NameOfFunc(alias f) {
     // Note: highly dependent on the .stringof formatting
     // the value begins with "& " which is why the first two chars are cut off
@@ -717,7 +723,9 @@
     mixin ForwardGtkOsCFunc!(.XRenderFindVisualFormat);
 //    mixin ForwardGtkOsCFunc!(Call );
     mixin ForwardGtkOsCFunc!(.GDK_DISPLAY);
+    +/
     mixin ForwardGtkOsCFunc!(.GDK_ROOT_PARENT);
+    /+
     mixin ForwardGtkOsCFunc!(.GDK_TYPE_COLOR);
     mixin ForwardGtkOsCFunc!(.GDK_TYPE_PIXBUF);
     mixin ForwardGtkOsCFunc!(.GTK_IS_BUTTON);
@@ -928,7 +936,7 @@
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_get_pixels);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_get_rowstride);
     mixin ForwardGtkOsCFunc!(.gdk_pixbuf_get_width);
-//    mixin ForwardGtkOsCFunc!(.gdk_pixbuf_new);
+    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);
@@ -1742,65 +1750,65 @@
     mixin ForwardGtkOsCFunc!(.atk_object_add_relationship );
 
     /* Field accessors */
-    
+
     void    GTK_ACCEL_LABEL_SET_ACCEL_STRING( GtkAccelLabel *arg0, gchar * arg1 )
             { arg0.accel_string = arg1; }
-    gchar*  GTK_ACCEL_LABEL_GET_ACCEL_STRING( GtkAccelLabel* arg0) 
+    gchar*  GTK_ACCEL_LABEL_GET_ACCEL_STRING( GtkAccelLabel* arg0)
             { return arg0.accel_string; }
-    
+
     GtkWidget* GTK_SCROLLED_WINDOW_HSCROLLBAR( GtkScrolledWindow* arg0 )
             { return arg0.hscrollbar; }
     GtkWidget* GTK_SCROLLED_WINDOW_VSCROLLBAR( GtkScrolledWindow* arg0 )
             { return arg0.vscrollbar; }
-    
-    int GTK_SCROLLED_WINDOW_SCROLLBAR_SPACING( GtkScrolledWindow* arg0) 
+
+    int GTK_SCROLLED_WINDOW_SCROLLBAR_SPACING( GtkScrolledWindow* arg0)
     {
         return   ((cast(GtkScrolledWindowClass*) ((cast(GTypeInstance*) arg0).g_class) ).scrollbar_spacing >= 0 ?
-                  (cast(GtkScrolledWindowClass*) ((cast(GTypeInstance*) arg0).g_class)).scrollbar_spacing : 3) ; 
+                  (cast(GtkScrolledWindowClass*) ((cast(GTypeInstance*) arg0).g_class)).scrollbar_spacing : 3) ;
     }
-    
-    int  GTK_WIDGET_HEIGHT( GtkWidget* arg0 )                   
+
+    int  GTK_WIDGET_HEIGHT( GtkWidget* arg0 )
          { return arg0.allocation.height; }
-    void GTK_WIDGET_SET_HEIGHT( GtkWidget* arg0, int arg1)      
+    void GTK_WIDGET_SET_HEIGHT( GtkWidget* arg0, int arg1)
          { arg0.allocation.height = arg1; }
-    int  GTK_WIDGET_WIDTH( GtkWidget* arg0)                     
+    int  GTK_WIDGET_WIDTH( GtkWidget* arg0)
          { return arg0.allocation.width; }
-    void GTK_WIDGET_SET_WIDTH( GtkWidget* arg0, int arg1)       
+    void GTK_WIDGET_SET_WIDTH( GtkWidget* arg0, int arg1)
          { arg0.allocation.width = arg1; }
-    GdkWindow* GTK_WIDGET_WINDOW( GtkWidget* arg0)              
+    GdkWindow* GTK_WIDGET_WINDOW( GtkWidget* arg0)
          { return arg0.window; }
-    int  GTK_WIDGET_X( GtkWidget* arg0 )                        
+    int  GTK_WIDGET_X( GtkWidget* arg0 )
          { return arg0.allocation.x; }
-    void GTK_WIDGET_SET_X( GtkWidget* arg0, int arg1)           
+    void GTK_WIDGET_SET_X( GtkWidget* arg0, int arg1)
          { arg0.allocation.x = arg1; }
-    int  GTK_WIDGET_Y( GtkWidget* arg0 )                        
+    int  GTK_WIDGET_Y( GtkWidget* arg0 )
          { return arg0.allocation.y; }
-    void GTK_WIDGET_SET_Y( GtkWidget* arg0, int arg1)           
+    void GTK_WIDGET_SET_Y( GtkWidget* arg0, int arg1)
          { arg0.allocation.y = arg1; }
-    int  GTK_WIDGET_REQUISITION_WIDTH( GtkWidget* arg0 )        
+    int  GTK_WIDGET_REQUISITION_WIDTH( GtkWidget* arg0 )
          { return arg0.requisition.width;  }
-    int  GTK_WIDGET_REQUISITION_HEIGHT( GtkWidget* arg0 )       
+    int  GTK_WIDGET_REQUISITION_HEIGHT( GtkWidget* arg0 )
          { return arg0.requisition.height; }
- 
-    GtkIMContext* GTK_ENTRY_IM_CONTEXT( GtkEntry* arg0 )        
+
+    GtkIMContext* GTK_ENTRY_IM_CONTEXT( GtkEntry* arg0 )
          { return arg0.im_context; }
 
-    GtkIMContext* GTK_TEXTVIEW_IM_CONTEXT( GtkTextView* arg0)   
+    GtkIMContext* GTK_TEXTVIEW_IM_CONTEXT( GtkTextView* arg0)
          { return arg0.im_context; }
 
-    GtkWidget* GTK_TOOLTIPS_TIP_WINDOW( GtkTooltips* arg0)      
+    GtkWidget* GTK_TOOLTIPS_TIP_WINDOW( GtkTooltips* arg0)
          { return arg0.tip_window; }
-    void GTK_TOOLTIPS_SET_ACTIVE( GtkTooltips* arg0, GtkTooltipsData*  arg1 )       
+    void GTK_TOOLTIPS_SET_ACTIVE( GtkTooltips* arg0, GtkTooltipsData*  arg1 )
          { arg0.active_tips_data = arg1; }
 
-    int  GDK_EVENT_TYPE( GdkEvent* arg0 )                    
+    int  GDK_EVENT_TYPE( GdkEvent* arg0 )
          { return arg0.type; }
-    GdkWindow* GDK_EVENT_WINDOW( GdkEventAny* arg0 )            
+    GdkWindow* GDK_EVENT_WINDOW( GdkEventAny* arg0 )
          { return arg0.window; }
 /+
-    int  X_EVENT_TYPE( XEvent* arg0 )                         
+    int  X_EVENT_TYPE( XEvent* arg0 )
          { return arg0.type; }
-    Window X_EVENT_WINDOW( XAnyEvent* arg0 )                    
+    Window X_EVENT_WINDOW( XAnyEvent* arg0 )
          { return arg0.window; }
 
     g_list_data(arg0) (arg0)->data
--- a/dwt/internal/gtk/c/gdktypes.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/internal/gtk/c/gdktypes.d	Mon Jan 07 03:41:50 2008 +0100
@@ -6,7 +6,7 @@
     it under the terms of the GNU Lesser General Public License as published by
     the Free Software Foundation; either version 2.1 of the License, or
     (at your option) any later version.
- 
+
     gtkD is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -1865,7 +1865,21 @@
  * GdkColormap*colormap;
  * the GdkColormap associated with the image
  */
-public struct GdkImage{}
+public struct GdkImage{
+    GObject parent_instance;
+    int type;
+    GdkVisual * visual;
+    int byte_order;
+    int width;
+    int height;
+    ushort depth;
+    ushort bpp;
+    ushort bpl;
+    ushort bits_per_pixel;
+    void * mem;
+    GdkColormap * colormap;
+    void * windowing_data;
+}
 // GObject parentInstance;
 // gdk-Images.html
 // GdkImageType type; /+* read only. +/
--- a/dwt/internal/gtk/c/gobjecttypes.d	Mon Jan 07 01:49:53 2008 +0100
+++ b/dwt/internal/gtk/c/gobjecttypes.d	Mon Jan 07 03:41:50 2008 +0100
@@ -15,7 +15,7 @@
  * along with gtkD; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
- 
+
 // generated automatically - do not change
 // find conversion definition on APILookup.txt
 // implement new conversion functionalities on the wrap.utils pakage
@@ -453,7 +453,11 @@
  * All the fields in the GObject structure are private
  * to the GObject implementation and should never be accessed directly.
  */
-public struct GObject{}
+public struct GObject{
+    GTypeInstance g_type_instance;
+    uint ref_count;
+    void * qdata;
+}
 
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/widgets/Display.d	Mon Jan 07 03:41:50 2008 +0100
@@ -0,0 +1,3998 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.widgets.Display;
+
+
+class Display {
+}
+/++++
+import dwt.*;
+import dwt.internal.*;
+import dwt.internal.gtk.*;
+import dwt.graphics.*;
+
+/**
+ * Instances of this class are responsible for managing the
+ * connection between SWT and the underlying operating
+ * system. Their most important function is to implement
+ * the SWT event loop in terms of the platform event model.
+ * They also provide various methods for accessing information
+ * about the operating system, and have overall control over
+ * the operating system resources which SWT allocates.
+ * <p>
+ * Applications which are built with SWT will <em>almost always</em>
+ * require only a single display. In particular, some platforms
+ * which SWT supports will not allow more than one <em>active</em>
+ * display. In other words, some platforms do not support
+ * creating a new display if one already exists that has not been
+ * sent the <code>dispose()</code> message.
+ * <p>
+ * In SWT, the thread which creates a <code>Display</code>
+ * instance is distinguished as the <em>user-interface thread</em>
+ * for that display.
+ * </p>
+ * The user-interface thread for a particular display has the
+ * following special attributes:
+ * <ul>
+ * <li>
+ * The event loop for that display must be run from the thread.
+ * </li>
+ * <li>
+ * Some SWT API methods (notably, most of the public methods in
+ * <code>Widget</code> and its subclasses), may only be called
+ * from the thread. (To support multi-threaded user-interface
+ * applications, class <code>Display</code> provides inter-thread
+ * communication methods which allow threads other than the
+ * user-interface thread to request that it perform operations
+ * on their behalf.)
+ * </li>
+ * <li>
+ * The thread is not allowed to construct other
+ * <code>Display</code>s until that display has been disposed.
+ * (Note that, this is in addition to the restriction mentioned
+ * above concerning platform support for multiple displays. Thus,
+ * the only way to have multiple simultaneously active displays,
+ * even on platforms which support it, is to have multiple threads.)
+ * </li>
+ * </ul>
+ * Enforcing these attributes allows SWT to be implemented directly
+ * on the underlying operating system's event model. This has
+ * numerous benefits including smaller footprint, better use of
+ * resources, safer memory management, clearer program logic,
+ * better performance, and fewer overall operating system threads
+ * required. The down side however, is that care must be taken
+ * (only) when constructing multi-threaded applications to use the
+ * inter-thread communication mechanisms which this class provides
+ * when required.
+ * </p><p>
+ * All SWT API methods which may only be called from the user-interface
+ * thread are distinguished in their documentation by indicating that
+ * they throw the "<code>ERROR_THREAD_INVALID_ACCESS</code>"
+ * SWT exception.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>(none)</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>Close, Dispose, Settings</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ * @see #syncExec
+ * @see #asyncExec
+ * @see #wake
+ * @see #readAndDispatch
+ * @see #sleep
+ * @see Device#dispose
+ */
+public class Display extends Device {
+
+	/* Events Dispatching and Callback */
+	int gdkEventCount;
+	int /*long*/ [] gdkEvents;
+	Widget [] gdkEventWidgets;
+	int [] dispatchEvents;
+	Event [] eventQueue;
+	int /*long*/ fds;
+	int allocated_nfds;
+	boolean wake;
+	int [] max_priority = new int [1], timeout = new int [1];
+	Callback eventCallback, filterCallback;
+	int /*long*/ eventProc, filterProc, windowProc2, windowProc3, windowProc4, windowProc5;
+	Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5;
+	EventTable eventTable, filterTable;
+	static String APP_NAME = "SWT";
+	static final String DISPATCH_EVENT_KEY = "dwt.internal.gtk.dispatchEvent";
+	static final String ADD_WIDGET_KEY = "dwt.internal.addWidget";
+	int /*long*/ [] closures;
+	int [] signalIds;
+	int /*long*/ shellMapProcClosure;
+
+	/* Widget Table */
+	int [] indexTable;
+	int freeSlot;
+	int /*long*/ lastHandle;
+	Widget lastWidget;
+	Widget [] widgetTable;
+	final static int GROW_SIZE = 1024;
+	static final int SWT_OBJECT_INDEX;
+	static final int SWT_OBJECT_INDEX1;
+	static final int SWT_OBJECT_INDEX2;
+	static {
+		byte [] buffer = Converter.wcsToMbcs (null, "SWT_OBJECT_INDEX", true);
+		SWT_OBJECT_INDEX = OS.g_quark_from_string (buffer);
+		buffer = Converter.wcsToMbcs (null, "SWT_OBJECT_INDEX1", true);
+		SWT_OBJECT_INDEX1 = OS.g_quark_from_string (buffer);
+		buffer = Converter.wcsToMbcs (null, "SWT_OBJECT_INDEX2", true);
+		SWT_OBJECT_INDEX2 = OS.g_quark_from_string (buffer);
+	}
+
+	/* Focus */
+	int focusEvent;
+	Control focusControl;
+	Shell activeShell;
+	boolean activePending;
+	boolean ignoreActivate, ignoreFocus;
+
+	/* Input method resources */
+	Control imControl;
+	int /*long*/ preeditWindow, preeditLabel;
+
+	/* Sync/Async Widget Communication */
+	Synchronizer synchronizer = new Synchronizer (this);
+	Thread thread;
+
+	/* Display Shutdown */
+	Runnable [] disposeList;
+
+	/* System Tray */
+	Tray tray;
+
+	/* Timers */
+	int [] timerIds;
+	Runnable [] timerList;
+	Callback timerCallback;
+	int /*long*/ timerProc;
+	Callback windowTimerCallback;
+	int /*long*/ windowTimerProc;
+
+	/* Caret */
+	Caret currentCaret;
+	Callback caretCallback;
+	int caretId;
+	int /*long*/ caretProc;
+
+	/* Mnemonics */
+	Control mnemonicControl;
+
+	/* Mouse hover */
+	int mouseHoverId;
+	int /*long*/ mouseHoverHandle, mouseHoverProc;
+	Callback mouseHoverCallback;
+
+	/* Menu position callback */
+	int /*long*/ menuPositionProc;
+	Callback menuPositionCallback;
+
+	/* Tooltip size allocate callback */
+	int /*long*/ sizeAllocateProc;
+	Callback sizeAllocateCallback;
+	int /*long*/ sizeRequestProc;
+	Callback sizeRequestCallback;
+
+	/* Shell map callback */
+	int /*long*/ shellMapProc;
+	Callback shellMapCallback;
+
+	/* Idle proc callback */
+	int /*long*/ idleProc;
+	int idleHandle;
+	Callback idleCallback;
+	static final String ADD_IDLE_PROC_KEY = "dwt.internal.gtk2.addIdleProc";
+	static final String REMOVE_IDLE_PROC_KEY = "dwt.internal.gtk2.removeIdleProc";
+	Object idleLock = new Object();
+	boolean idleNeeded;
+
+	/* GtkTreeView callbacks */
+	int[] treeSelection;
+	int treeSelectionLength;
+	int /*long*/ treeSelectionProc;
+	Callback treeSelectionCallback;
+	int /*long*/ cellDataProc;
+	Callback cellDataCallback;
+
+	/* Set direction callback */
+	int /*long*/ setDirectionProc;
+	Callback setDirectionCallback;
+
+	/* Get all children callback */
+	int /*long*/ allChildrenProc, allChildren;
+	Callback allChildrenCallback;
+
+	/* Settings callbacks */
+	int /*long*/ styleSetProc;
+	Callback styleSetCallback;
+	int /*long*/ shellHandle;
+	boolean settingsChanged, runSettings;
+
+	/* Entry focus behaviour */
+	boolean entrySelectOnFocus;
+
+	/* Enter/Exit events */
+	Control currentControl;
+
+	/* Flush exposes */
+	int /*long*/ checkIfEventProc;
+	Callback checkIfEventCallback;
+	int /*long*/ flushWindow;
+	boolean flushAll;
+	GdkRectangle flushRect = new GdkRectangle ();
+	XExposeEvent exposeEvent = new XExposeEvent ();
+	XVisibilityEvent visibilityEvent = new XVisibilityEvent ();
+	int /*long*/ [] flushData = new int /*long*/ [1];
+
+	/* System Resources */
+	Font systemFont;
+	Image errorImage, infoImage, questionImage, warningImage;
+	Cursor [] cursors = new Cursor [SWT.CURSOR_HAND + 1];
+	Resource [] resources;
+	static final int RESOURCE_SIZE = 1 + 4 + SWT.CURSOR_HAND + 1;
+
+	/* Colors */
+	GdkColor COLOR_WIDGET_DARK_SHADOW, COLOR_WIDGET_NORMAL_SHADOW, COLOR_WIDGET_LIGHT_SHADOW;
+	GdkColor COLOR_WIDGET_HIGHLIGHT_SHADOW, COLOR_WIDGET_BACKGROUND, COLOR_WIDGET_FOREGROUND, COLOR_WIDGET_BORDER;
+	GdkColor COLOR_LIST_FOREGROUND, COLOR_LIST_BACKGROUND, COLOR_LIST_SELECTION, COLOR_LIST_SELECTION_TEXT;
+	GdkColor COLOR_INFO_BACKGROUND, COLOR_INFO_FOREGROUND;
+	GdkColor COLOR_TITLE_FOREGROUND, COLOR_TITLE_BACKGROUND, COLOR_TITLE_BACKGROUND_GRADIENT;
+	GdkColor COLOR_TITLE_INACTIVE_FOREGROUND, COLOR_TITLE_INACTIVE_BACKGROUND, COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT;
+
+	/* Popup Menus */
+	Menu [] popups;
+
+	/* Click count*/
+	int clickCount = 1;
+
+	/* Timestamp of the Last Received Events */
+	int lastEventTime, lastUserEventTime;
+
+	/* Fixed Subclass */
+	static int /*long*/ fixed_type;
+	static int /*long*/ fixed_info_ptr;
+	static Callback fixedClassInitCallback, fixedMapCallback;
+	static int /*long*/ fixedClassInitProc, fixedMapProc;
+
+	/* Renderer Subclass */
+	static int /*long*/ text_renderer_type, pixbuf_renderer_type, toggle_renderer_type;
+	static int /*long*/ text_renderer_info_ptr, pixbuf_renderer_info_ptr, toggle_renderer_info_ptr;
+	static Callback rendererClassInitCallback, rendererRenderCallback, rendererGetSizeCallback;
+	static int /*long*/ rendererClassInitProc, rendererRenderProc, rendererGetSizeProc;
+
+	/* Key Mappings */
+	static final int [] [] KeyTable = {
+
+		/* Keyboard and Mouse Masks */
+		{OS.GDK_Alt_L,		SWT.ALT},
+		{OS.GDK_Alt_R,		SWT.ALT},
+		{OS.GDK_Meta_L,	SWT.ALT},
+		{OS.GDK_Meta_R,	SWT.ALT},
+		{OS.GDK_Shift_L,		SWT.SHIFT},
+		{OS.GDK_Shift_R,		SWT.SHIFT},
+		{OS.GDK_Control_L,	SWT.CONTROL},
+		{OS.GDK_Control_R,	SWT.CONTROL},
+//		{OS.GDK_????,		SWT.COMMAND},
+//		{OS.GDK_????,		SWT.COMMAND},
+
+		/* Non-Numeric Keypad Keys */
+		{OS.GDK_Up,						SWT.ARROW_UP},
+		{OS.GDK_KP_Up,					SWT.ARROW_UP},
+		{OS.GDK_Down,					SWT.ARROW_DOWN},
+		{OS.GDK_KP_Down,			SWT.ARROW_DOWN},
+		{OS.GDK_Left,						SWT.ARROW_LEFT},
+		{OS.GDK_KP_Left,				SWT.ARROW_LEFT},
+		{OS.GDK_Right,					SWT.ARROW_RIGHT},
+		{OS.GDK_KP_Right,				SWT.ARROW_RIGHT},
+		{OS.GDK_Page_Up,				SWT.PAGE_UP},
+		{OS.GDK_KP_Page_Up,		SWT.PAGE_UP},
+		{OS.GDK_Page_Down,			SWT.PAGE_DOWN},
+		{OS.GDK_KP_Page_Down,	SWT.PAGE_DOWN},
+		{OS.GDK_Home,					SWT.HOME},
+		{OS.GDK_KP_Home,			SWT.HOME},
+		{OS.GDK_End,						SWT.END},
+		{OS.GDK_KP_End,				SWT.END},
+		{OS.GDK_Insert,					SWT.INSERT},
+		{OS.GDK_KP_Insert,			SWT.INSERT},
+
+		/* Virtual and Ascii Keys */
+		{OS.GDK_BackSpace,		SWT.BS},
+		{OS.GDK_Return,				SWT.CR},
+		{OS.GDK_Delete,				SWT.DEL},
+		{OS.GDK_KP_Delete,		SWT.DEL},
+		{OS.GDK_Escape,			SWT.ESC},
+		{OS.GDK_Linefeed,			SWT.LF},
+		{OS.GDK_Tab,					SWT.TAB},
+		{OS.GDK_ISO_Left_Tab, 	SWT.TAB},
+
+		/* Functions Keys */
+		{OS.GDK_F1,		SWT.F1},
+		{OS.GDK_F2,		SWT.F2},
+		{OS.GDK_F3,		SWT.F3},
+		{OS.GDK_F4,		SWT.F4},
+		{OS.GDK_F5,		SWT.F5},
+		{OS.GDK_F6,		SWT.F6},
+		{OS.GDK_F7,		SWT.F7},
+		{OS.GDK_F8,		SWT.F8},
+		{OS.GDK_F9,		SWT.F9},
+		{OS.GDK_F10,		SWT.F10},
+		{OS.GDK_F11,		SWT.F11},
+		{OS.GDK_F12,		SWT.F12},
+		{OS.GDK_F13,		SWT.F13},
+		{OS.GDK_F14,		SWT.F14},
+		{OS.GDK_F15,		SWT.F15},
+
+		/* Numeric Keypad Keys */
+		{OS.GDK_KP_Multiply,		SWT.KEYPAD_MULTIPLY},
+		{OS.GDK_KP_Add,			SWT.KEYPAD_ADD},
+		{OS.GDK_KP_Enter,			SWT.KEYPAD_CR},
+		{OS.GDK_KP_Subtract,	SWT.KEYPAD_SUBTRACT},
+		{OS.GDK_KP_Decimal,	SWT.KEYPAD_DECIMAL},
+		{OS.GDK_KP_Divide,		SWT.KEYPAD_DIVIDE},
+		{OS.GDK_KP_0,			SWT.KEYPAD_0},
+		{OS.GDK_KP_1,			SWT.KEYPAD_1},
+		{OS.GDK_KP_2,			SWT.KEYPAD_2},
+		{OS.GDK_KP_3,			SWT.KEYPAD_3},
+		{OS.GDK_KP_4,			SWT.KEYPAD_4},
+		{OS.GDK_KP_5,			SWT.KEYPAD_5},
+		{OS.GDK_KP_6,			SWT.KEYPAD_6},
+		{OS.GDK_KP_7,			SWT.KEYPAD_7},
+		{OS.GDK_KP_8,			SWT.KEYPAD_8},
+		{OS.GDK_KP_9,			SWT.KEYPAD_9},
+		{OS.GDK_KP_Equal,	SWT.KEYPAD_EQUAL},
+
+		/* Other keys */
+		{OS.GDK_Caps_Lock,		SWT.CAPS_LOCK},
+		{OS.GDK_Num_Lock,		SWT.NUM_LOCK},
+		{OS.GDK_Scroll_Lock,		SWT.SCROLL_LOCK},
+		{OS.GDK_Pause,				SWT.PAUSE},
+		{OS.GDK_Break,				SWT.BREAK},
+		{OS.GDK_Print,					SWT.PRINT_SCREEN},
+		{OS.GDK_Help,					SWT.HELP},
+
+	};
+
+	/* Multiple Displays. */
+	static Display Default;
+	static Display [] Displays = new Display [4];
+
+	/* Package name */
+	static final String PACKAGE_PREFIX = "dwt.widgets.";
+	/* This code is intentionally commented.
+	 * ".class" can not be used on CLDC.
+	 */
+//	static {
+//		String name = Display.class.getName ();
+//		int index = name.lastIndexOf ('.');
+//		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.
+	*/
+	static final Class OS_LOCK;
+	static {
+		Class lock = null;
+		try {
+			lock = Class.forName ("dwt.internal.gtk.OS");
+		} catch (Throwable th) {
+		}
+		OS_LOCK = lock;
+	}
+
+	/* GTK Version */
+	static final int MAJOR = 2;
+	static final int MINOR = 0;
+	static final int MICRO = 6;
+
+	/* Display Data */
+	Object data;
+	String [] keys;
+	Object [] values;
+
+	/* Initial Guesses for Shell Trimmings. */
+	int borderTrimWidth = 4, borderTrimHeight = 4;
+	int resizeTrimWidth = 6, resizeTrimHeight = 6;
+	int titleBorderTrimWidth = 5, titleBorderTrimHeight = 28;
+	int titleResizeTrimWidth = 6, titleResizeTrimHeight = 29;
+	int titleTrimWidth = 0, titleTrimHeight = 23;
+	boolean ignoreTrim;
+
+	/* Window Manager */
+	String windowManager;
+
+	/*
+	* TEMPORARY CODE.  Install the runnable that
+	* gets the current display. This code will
+	* be removed in the future.
+	*/
+	static {
+		DeviceFinder = new Runnable () {
+			public void run () {
+				Device device = getCurrent ();
+				if (device == null) {
+					device = getDefault ();
+				}
+				setDevice (device);
+			}
+		};
+	}
+
+/*
+* TEMPORARY CODE.
+*/
+static void setDevice (Device device) {
+	CurrentDevice = device;
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * Note: The resulting display is marked as the <em>current</em>
+ * display. If this is the first display which has been
+ * constructed since the application started, it is also
+ * marked as the <em>default</em> display.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if called from a thread that already created an existing display</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see #getCurrent
+ * @see #getDefault
+ * @see Widget#checkSubclass
+ * @see Shell
+ */
+public Display () {
+	this (null);
+}
+
+/**
+ * Constructs a new instance of this class using the parameter.
+ *
+ * @param data the device data
+ */
+public Display (DeviceData data) {
+	super (data);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when an event of the given type occurs anywhere
+ * in a widget. The event type is one of the event constants
+ * defined in class <code>SWT</code>. When the event does occur,
+ * the listener is notified by sending it the <code>handleEvent()</code>
+ * message.
+ * <p>
+ * Setting the type of an event to <code>SWT.None</code> from
+ * within the <code>handleEvent()</code> method can be used to
+ * change the event type and stop subsequent Java listeners
+ * from running. Because event filters run before other listeners,
+ * event filters can both block other listeners and set arbitrary
+ * fields within an event. For this reason, event filters are both
+ * powerful and dangerous. They should generally be avoided for
+ * performance, debugging and code maintenance reasons.
+ * </p>
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #removeFilter
+ * @see #removeListener
+ *
+ * @since 3.0
+ */
+public void addFilter (int eventType, Listener listener) {
+	checkDevice ();
+	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (filterTable == null) filterTable = new EventTable ();
+	filterTable.hook (eventType, listener);
+}
+
+void addGdkEvent (int /*long*/ event) {
+	if (gdkEvents == null) {
+		int length = GROW_SIZE;
+		gdkEvents = new int /*long*/ [length];
+		gdkEventWidgets = new Widget [length];
+		gdkEventCount = 0;
+	}
+	if (gdkEventCount == gdkEvents.length) {
+		int length = gdkEventCount + GROW_SIZE;
+		int /*long*/ [] newEvents = new int /*long*/ [length];
+		System.arraycopy (gdkEvents, 0, newEvents, 0, gdkEventCount);
+		gdkEvents = newEvents;
+		Widget [] newWidgets = new Widget [length];
+		System.arraycopy (gdkEventWidgets, 0, newWidgets, 0, gdkEventCount);
+		gdkEventWidgets = newWidgets;
+	}
+	Widget widget = null;
+	int /*long*/ handle = OS.gtk_get_event_widget (event);
+	if (handle != 0) {
+		do {
+			widget = getWidget (handle);
+		} while (widget == null && (handle = OS.gtk_widget_get_parent (handle)) != 0);
+	}
+	gdkEvents [gdkEventCount] = event;
+	gdkEventWidgets [gdkEventCount] = widget;
+	gdkEventCount++;
+}
+
+void addIdleProc() {
+	synchronized (idleLock){
+		this.idleNeeded = true;
+		if (idleHandle == 0) {
+			idleHandle = OS.g_idle_add (idleProc, 0);
+		}
+	}
+}
+
+/**
+ * Adds the listener to the collection 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>SWT</code>.
+ * When the event does occur in the display, the listener is notified by
+ * sending it the <code>handleEvent()</code> message.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #removeListener
+ *
+ * @since 2.0
+ */
+public void addListener (int eventType, Listener listener) {
+	checkDevice ();
+	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) eventTable = new EventTable ();
+	eventTable.hook (eventType, listener);
+}
+
+int /*long*/ allChildrenProc (int /*long*/ widget, int /*long*/ recurse) {
+	allChildren = OS.g_list_append (allChildren, widget);
+	if (recurse != 0 && OS.GTK_IS_CONTAINER (widget)) {
+		OS.gtk_container_forall (widget, allChildrenProc, recurse);
+	}
+	return 0;
+}
+
+void addMouseHoverTimeout (int /*long*/ handle) {
+	if (mouseHoverId != 0) OS.gtk_timeout_remove (mouseHoverId);
+	mouseHoverId = OS.gtk_timeout_add (400, mouseHoverProc, handle);
+	mouseHoverHandle = handle;
+}
+
+void addPopup (Menu menu) {
+	if (popups == null) popups = new Menu [4];
+	int length = popups.length;
+	for (int i=0; i<length; i++) {
+		if (popups [i] == menu) return;
+	}
+	int index = 0;
+	while (index < length) {
+		if (popups [index] == null) break;
+		index++;
+	}
+	if (index == length) {
+		Menu [] newPopups = new Menu [length + 4];
+		System.arraycopy (popups, 0, newPopups, 0, length);
+		popups = newPopups;
+	}
+	popups [index] = menu;
+}
+
+void addWidget (int /*long*/ handle, Widget widget) {
+	if (handle == 0) return;
+	if (freeSlot == -1) {
+		int length = (freeSlot = indexTable.length) + GROW_SIZE;
+		int[] newIndexTable = new int[length];
+		Widget[] newWidgetTable = new Widget [length];
+		System.arraycopy (indexTable, 0, newIndexTable, 0, freeSlot);
+		System.arraycopy (widgetTable, 0, newWidgetTable, 0, freeSlot);
+		for (int i = freeSlot; i < length - 1; i++) {
+			newIndexTable[i] = i + 1;
+		}
+		newIndexTable[length - 1] = -1;
+		indexTable = newIndexTable;
+		widgetTable = newWidgetTable;
+	}
+	int index = freeSlot + 1;
+	OS.g_object_set_qdata (handle, SWT_OBJECT_INDEX, index);
+	int oldSlot = freeSlot;
+	freeSlot = indexTable[oldSlot];
+	indexTable [oldSlot] = -2;
+	widgetTable [oldSlot] = widget;
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread at the next
+ * reasonable opportunity. The caller of this method continues
+ * to run in parallel, and is not notified when the
+ * runnable has completed.  Specifying <code>null</code> as the
+ * runnable simply wakes the user-interface thread when run.
+ * <p>
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ * </p>
+ *
+ * @param runnable code to run on the user-interface thread or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #syncExec
+ */
+public void asyncExec (Runnable runnable) {
+	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+	synchronized (idleLock) {
+		if (idleNeeded && idleHandle == 0) {
+ 			//NOTE: calling unlocked function in OS
+			idleHandle = OS._g_idle_add (idleProc, 0);
+		}
+	}
+	synchronizer.asyncExec (runnable);
+}
+
+/**
+ * Causes the system hardware to emit a short sound
+ * (if it supports this capability).
+ *
+ * @exception SWTException <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>
+ */
+public void beep () {
+	if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
+	OS.gdk_beep();
+	if (!OS.GDK_WINDOWING_X11 ()) {
+		OS.gdk_flush ();
+	} else {
+		int /*long*/ xDisplay = OS.GDK_DISPLAY ();
+		OS.XFlush (xDisplay);
+	}
+}
+
+int /*long*/ cellDataProc (int /*long*/ tree_column, int /*long*/ cell, int /*long*/ tree_model, int /*long*/ iter, int /*long*/ data) {
+	Widget widget = getWidget (data);
+	if (widget == null) return 0;
+	return widget.cellDataProc (tree_column, cell, tree_model, iter, data);
+}
+
+protected void checkDevice () {
+	if (thread == null) error (SWT.ERROR_WIDGET_DISPOSED);
+	if (thread != Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
+	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+}
+
+static synchronized void checkDisplay (Thread thread, boolean multiple) {
+	for (int i=0; i<Displays.length; i++) {
+		if (Displays [i] != null) {
+			if (!multiple) SWT.error (SWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]");
+			if (Displays [i].thread == thread) SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS);
+		}
+	}
+}
+
+int /*long*/ checkIfEventProc (int /*long*/ display, int /*long*/ xEvent, int /*long*/ userData) {
+	int type = OS.X_EVENT_TYPE (xEvent);
+	switch (type) {
+		case OS.VisibilityNotify:
+		case OS.Expose:
+		case OS.GraphicsExpose:
+			break;
+		default:
+			return 0;
+	}
+	int /*long*/ window = OS.gdk_window_lookup (OS.X_EVENT_WINDOW (xEvent));
+	if (window == 0) return 0;
+	if (flushWindow != 0) {
+		if (flushAll) {
+			int /*long*/ tempWindow = window;
+			do {
+				if (tempWindow == flushWindow) break;
+			} while ((tempWindow = OS.gdk_window_get_parent (tempWindow)) != 0);
+			if (tempWindow != flushWindow) return 0;
+		} else {
+			if (window != flushWindow) return 0;
+		}
+	}
+	OS.memmove (exposeEvent, xEvent, XExposeEvent.sizeof);
+	switch (type) {
+		case OS.Expose:
+		case OS.GraphicsExpose: {
+			flushRect.x = exposeEvent.x;
+			flushRect.y = exposeEvent.y;
+			flushRect.width = exposeEvent.width;
+			flushRect.height = exposeEvent.height;
+			OS.gdk_window_invalidate_rect (window, flushRect, true);
+			exposeEvent.type = -1;
+			OS.memmove (xEvent, exposeEvent, XExposeEvent.sizeof);
+			break;
+		}
+		case OS.VisibilityNotify: {
+			OS.memmove (visibilityEvent, xEvent, XVisibilityEvent.sizeof);
+			OS.gdk_window_get_user_data (window, flushData);
+			int /*long*/ handle = flushData [0];
+			Widget widget = handle != 0 ? getWidget (handle) : null;
+			if (widget != null && widget instanceof Control) {
+				Control control = (Control) widget;
+				if (window == control.paintWindow ()) {
+					if (visibilityEvent.state == OS.VisibilityFullyObscured) {
+						control.state |= Widget.OBSCURED;
+					} else {
+						control.state &= ~Widget.OBSCURED;
+					}
+				}
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Checks that this class can be subclassed.
+ * <p>
+ * IMPORTANT: See the comment in <code>Widget.checkSubclass()</code>.
+ * </p>
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see Widget#checkSubclass
+ */
+protected void checkSubclass () {
+	if (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+/**
+ * Requests that the connection between SWT and the underlying
+ * operating system be closed.
+ *
+ * @exception SWTException <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>
+ *
+ * @see Device#dispose
+ *
+ * @since 2.0
+ */
+public void close () {
+	checkDevice ();
+	Event event = new Event ();
+	sendEvent (SWT.Close, event);
+	if (event.doit) dispose ();
+}
+
+/**
+ * Creates the device in the operating system.  If the device
+ * does not have a handle, this method may do nothing depending
+ * on the device.
+ * <p>
+ * This method is called before <code>init</code>.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #init
+ */
+protected void create (DeviceData data) {
+	checkSubclass ();
+	checkDisplay(thread = Thread.currentThread (), false);
+	createDisplay (data);
+	register ();
+	if (Default == null) Default = this;
+}
+
+synchronized void createDisplay (DeviceData data) {
+	/* Required for g_main_context_wakeup */
+	if (!OS.g_thread_supported ()) {
+		OS.g_thread_init (0);
+	}
+	OS.gtk_set_locale();
+	if (!OS.gtk_init_check (new int /*long*/ [] {0}, null)) {
+		SWT.error (SWT.ERROR_NO_HANDLES, null, " [gtk_init_check() failed]");
+	}
+	if (OS.GDK_WINDOWING_X11 ()) xDisplay = OS.GDK_DISPLAY ();
+	int /*long*/ ptr = OS.gtk_check_version (MAJOR, MINOR, MICRO);
+	if (ptr != 0) {
+		int length = OS.strlen (ptr);
+		byte [] buffer = new byte [length];
+		OS.memmove (buffer, ptr, length);
+		System.out.println ("***WARNING: " + new String (Converter.mbcsToWcs (null, buffer)));
+		System.out.println ("***WARNING: SWT requires GTK " + MAJOR+ "." + MINOR + "." + MICRO);
+		int major = OS.gtk_major_version (), minor = OS.gtk_minor_version (), micro = OS.gtk_micro_version ();
+		System.out.println ("***WARNING: Detected: " + major + "." + minor + "." + micro);
+	}
+	if (fixed_type == 0) {
+		byte [] type_name = Converter.wcsToMbcs (null, "SwtFixed", true);
+		fixedClassInitCallback = new Callback (getClass (), "fixedClassInitProc", 2);
+		fixedClassInitProc = fixedClassInitCallback.getAddress ();
+		if (fixedClassInitProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+		fixedMapCallback = new Callback (getClass (), "fixedMapProc", 1);
+		fixedMapProc = fixedMapCallback.getAddress ();
+		if (fixedMapProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+		GTypeInfo fixed_info = new GTypeInfo ();
+		fixed_info.class_size = (short) OS.GtkFixedClass_sizeof ();
+		fixed_info.class_init = fixedClassInitProc;
+		fixed_info.instance_size = (short) OS.GtkFixed_sizeof ();
+		fixed_info_ptr = OS.g_malloc (GTypeInfo.sizeof);
+		OS.memmove (fixed_info_ptr, fixed_info, GTypeInfo.sizeof);
+		fixed_type = OS.g_type_register_static (OS.GTK_TYPE_FIXED (), type_name, fixed_info_ptr, 0);
+	}
+	if (rendererClassInitProc == 0) {
+		rendererClassInitCallback = new Callback (getClass (), "rendererClassInitProc", 2);
+		rendererClassInitProc = rendererClassInitCallback.getAddress ();
+		if (rendererClassInitProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+	}
+	if (rendererRenderProc == 0) {
+		rendererRenderCallback = new Callback (getClass (), "rendererRenderProc", 7);
+		rendererRenderProc = rendererRenderCallback.getAddress ();
+		if (rendererRenderProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+	}
+	if (rendererGetSizeProc == 0) {
+		rendererGetSizeCallback = new Callback (getClass (), "rendererGetSizeProc", 7);
+		rendererGetSizeProc = rendererGetSizeCallback.getAddress ();
+		if (rendererGetSizeProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+	}
+	if (text_renderer_type == 0) {
+		GTypeInfo renderer_info = new GTypeInfo ();
+		renderer_info.class_size = (short) OS.GtkCellRendererTextClass_sizeof ();
+		renderer_info.class_init = rendererClassInitProc;
+		renderer_info.instance_size = (short) OS.GtkCellRendererText_sizeof ();
+		text_renderer_info_ptr = OS.g_malloc (GTypeInfo.sizeof);
+		OS.memmove (text_renderer_info_ptr, renderer_info, GTypeInfo.sizeof);
+		byte [] type_name = Converter.wcsToMbcs (null, "SwtTextRenderer", true);
+		text_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_TEXT (), type_name, text_renderer_info_ptr, 0);
+	}
+	if (pixbuf_renderer_type == 0) {
+		GTypeInfo renderer_info = new GTypeInfo ();
+		renderer_info.class_size = (short) OS.GtkCellRendererPixbufClass_sizeof ();
+		renderer_info.class_init = rendererClassInitProc;
+		renderer_info.instance_size = (short) OS.GtkCellRendererPixbuf_sizeof ();
+		pixbuf_renderer_info_ptr = OS.g_malloc (GTypeInfo.sizeof);
+		OS.memmove (pixbuf_renderer_info_ptr, renderer_info, GTypeInfo.sizeof);
+		byte [] type_name = Converter.wcsToMbcs (null, "SwtPixbufRenderer", true);
+		pixbuf_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_PIXBUF (), type_name, pixbuf_renderer_info_ptr, 0);
+	}
+	if (toggle_renderer_type == 0) {
+		GTypeInfo renderer_info = new GTypeInfo ();
+		renderer_info.class_size = (short) OS.GtkCellRendererToggleClass_sizeof ();
+		renderer_info.class_init = rendererClassInitProc;
+		renderer_info.instance_size = (short) OS.GtkCellRendererToggle_sizeof ();
+		toggle_renderer_info_ptr = OS.g_malloc (GTypeInfo.sizeof);
+		OS.memmove (toggle_renderer_info_ptr, renderer_info, GTypeInfo.sizeof);
+		byte [] type_name = Converter.wcsToMbcs (null, "SwtToggleRenderer", true);
+		toggle_renderer_type = OS.g_type_register_static (OS.GTK_TYPE_CELL_RENDERER_TOGGLE (), type_name, toggle_renderer_info_ptr, 0);
+	}
+
+	OS.gtk_widget_set_default_direction (OS.GTK_TEXT_DIR_LTR);
+	OS.gdk_rgb_init ();
+	byte [] buffer = Converter.wcsToMbcs (null, APP_NAME, true);
+	OS.g_set_prgname (buffer);
+	OS.gdk_set_program_class (buffer);
+	byte [] flatStyle = Converter.wcsToMbcs (null, "style \"swt-flat\" { GtkToolbar::shadow-type = none } widget \"*.swt-toolbar-flat\" style : highest \"swt-flat\"", true);
+	OS.gtk_rc_parse_string (flatStyle);
+
+	/* Initialize the hidden shell */
+	shellHandle = OS.gtk_window_new (OS.GTK_WINDOW_TOPLEVEL);
+	if (shellHandle == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+	OS.gtk_widget_realize (shellHandle);
+
+	/* Initialize the filter and event callback */
+	eventCallback = new Callback (this, "eventProc", 2);
+	eventProc = eventCallback.getAddress ();
+	if (eventProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+	OS.gdk_event_handler_set (eventProc, 0, 0);
+	filterCallback = new Callback (this, "filterProc", 3);
+	filterProc = filterCallback.getAddress ();
+	if (filterProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+	OS.gdk_window_add_filter  (0, filterProc, 0);
+}
+
+Image createImage (String name) {
+	int /*long*/ style = OS.gtk_widget_get_default_style ();
+	byte[] buffer = Converter.wcsToMbcs (null, name, true);
+	int /*long*/ pixbuf = OS.gtk_icon_set_render_icon (
+		OS.gtk_icon_factory_lookup_default (buffer), style,
+		OS.GTK_TEXT_DIR_NONE, OS.GTK_STATE_NORMAL, OS.GTK_ICON_SIZE_DIALOG, 0, 0);
+	if (pixbuf == 0) return null;
+	int width = OS.gdk_pixbuf_get_width (pixbuf);
+	int height = OS.gdk_pixbuf_get_height (pixbuf);
+	int stride = OS.gdk_pixbuf_get_rowstride (pixbuf);
+	boolean hasAlpha = OS.gdk_pixbuf_get_has_alpha (pixbuf);
+	int /*long*/ pixels = OS.gdk_pixbuf_get_pixels (pixbuf);
+	byte [] data = new byte [stride * height];
+	OS.memmove (data, pixels, data.length);
+	OS.g_object_unref (pixbuf);
+	ImageData imageData = null;
+	if (hasAlpha) {
+		PaletteData palette = new PaletteData (0xFF000000, 0xFF0000, 0xFF00);
+		imageData = new ImageData (width, height, 32, palette);
+		byte [] alpha = new byte [stride * height];
+		for (int y=0; y<height; y++) {
+			for (int x=0; x<width; x++) {
+				alpha [y*width+x] = data [y*stride+x*4+3];
+				data [y*stride+x*4+3] = 0;
+			}
+		}
+		imageData.setAlphas (0, 0, width * height, alpha, 0);
+	} else {
+		PaletteData palette = new PaletteData (0xFF0000, 0xFF00, 0xFF);
+		imageData = new ImageData (width, height, 24, palette);
+	}
+	imageData.data = data;
+	imageData.bytesPerLine = stride;
+	return new Image (this, imageData);
+}
+
+static int /*long*/ createPixbuf(Image image) {
+	int [] w = new int [1], h = new int [1];
+ 	OS.gdk_drawable_get_size (image.pixmap, w, h);
+	int /*long*/ colormap = OS.gdk_colormap_get_system ();
+	int /*long*/ pixbuf;
+	boolean hasMask = image.mask != 0 && OS.gdk_drawable_get_depth (image.mask) == 1;
+	if (hasMask) {
+		pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, true, 8, w [0], h [0]);
+		if (pixbuf == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+		OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w [0], h [0]);
+		int /*long*/ maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, w [0], h [0]);
+		if (maskPixbuf == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+		OS.gdk_pixbuf_get_from_drawable(maskPixbuf, image.mask, 0, 0, 0, 0, 0, w [0], h [0]);
+		int stride = OS.gdk_pixbuf_get_rowstride(pixbuf);
+		int /*long*/ pixels = OS.gdk_pixbuf_get_pixels(pixbuf);
+		byte[] line = new byte[stride];
+		int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf);
+		int /*long*/ maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf);
+		byte[] maskLine = new byte[maskStride];
+		for (int y=0; y<h[0]; y++) {
+			int /*long*/ offset = pixels + (y * stride);
+			OS.memmove(line, offset, stride);
+			int /*long*/ maskOffset = maskPixels + (y * maskStride);
+			OS.memmove(maskLine, maskOffset, maskStride);
+			for (int x=0; x<w[0]; x++) {
+				if (maskLine[x * 3] == 0) {
+					line[x * 4 + 3] = 0;
+				}
+			}
+			OS.memmove(offset, line, stride);
+		}
+		OS.g_object_unref(maskPixbuf);
+	} else {
+		ImageData data = image.getImageData ();
+		boolean hasAlpha = data.getTransparencyType () == SWT.TRANSPARENCY_ALPHA;
+		pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, hasAlpha, 8, w [0], h [0]);
+		if (pixbuf == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+		OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w [0], h [0]);
+		if (hasAlpha) {
+			byte [] alpha = data.alphaData;
+			int stride = OS.gdk_pixbuf_get_rowstride (pixbuf);
+			int /*long*/ pixels = OS.gdk_pixbuf_get_pixels (pixbuf);
+			byte [] line = new byte [stride];
+			for (int y = 0; y < h [0]; y++) {
+				int /*long*/ offset = pixels + (y * stride);
+				OS.memmove (line, offset, stride);
+				for (int x = 0; x < w [0]; x++) {
+					line [x*4+3] = alpha [y*w [0]+x];
+				}
+				OS.memmove (offset, line, stride);
+			}
+		}
+	}
+	return pixbuf;
+}
+
+synchronized void deregister () {
+	for (int i=0; i<Displays.length; i++) {
+		if (this == Displays [i]) Displays [i] = null;
+	}
+}
+
+/**
+ * Destroys the device in the operating system and releases
+ * the device's handle.  If the device does not have a handle,
+ * this method may do nothing depending on the device.
+ * <p>
+ * This method is called after <code>release</code>.
+ * </p>
+ * @see Device#dispose
+ * @see #release
+ */
+protected void destroy () {
+	if (this == Default) Default = null;
+	deregister ();
+	destroyDisplay ();
+}
+
+void destroyDisplay () {
+}
+
+/**
+ * Returns the display which the given thread is the
+ * user-interface thread for, or null if the given thread
+ * is not a user-interface thread for any display.  Specifying
+ * <code>null</code> as the thread will return <code>null</code>
+ * for the display.
+ *
+ * @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 != null && display.thread == thread) {
+			return display;
+		}
+	}
+	return null;
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread just before the
+ * receiver is disposed.  Specifying a <code>null</code> runnable
+ * is ignored.
+ *
+ * @param runnable code to run at dispose time.
+ *
+ * @exception SWTException <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>
+ */
+public void disposeExec (Runnable runnable) {
+	checkDevice ();
+	if (disposeList == null) disposeList = new Runnable [4];
+	for (int i=0; i<disposeList.length; i++) {
+		if (disposeList [i] == null) {
+			disposeList [i] = runnable;
+			return;
+		}
+	}
+	Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
+	System.arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
+	newDisposeList [disposeList.length] = runnable;
+	disposeList = newDisposeList;
+}
+
+/**
+ * Does whatever display specific cleanup is required, and then
+ * uses the code in <code>SWTError.error</code> to handle the error.
+ *
+ * @param code the descriptive error code
+ *
+ * @see SWTError#error
+ */
+void error (int code) {
+	SWT.error (code);
+}
+
+int /*long*/ eventProc (int /*long*/ event, int /*long*/ data) {
+	/*
+	* Use gdk_event_get_time() rather than event.time or
+	* gtk_get_current_event_time().  If the event does not
+	* have a time stamp, then the field will contain garbage.
+	* Note that calling gtk_get_current_event_time() from
+	* outside of gtk_main_do_event() seems to always
+	* return zero.
+	*/
+	int time = OS.gdk_event_get_time (event);
+	if (time != 0) lastEventTime = time;
+
+	int eventType = OS.GDK_EVENT_TYPE (event);
+	switch (eventType) {
+		case OS.GDK_BUTTON_PRESS:
+		case OS.GDK_KEY_PRESS:
+			lastUserEventTime = time;
+	}
+	boolean dispatch = true;
+	if (dispatchEvents != null) {
+		dispatch = false;
+		for (int i = 0; i < dispatchEvents.length; i++) {
+			if (eventType == dispatchEvents [i]) {
+				dispatch = true;
+				break;
+			}
+		}
+	}
+	if (!dispatch) {
+		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;
+	int /*long*/ grabHandle = OS.gtk_grab_get_current ();
+	if (grabHandle != 0 && OS.GTK_IS_WINDOW (grabHandle) && OS.gtk_window_get_modal (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:  {
+				int /*long*/ window = OS.GDK_EVENT_WINDOW (event);
+				int /*long*/ [] user_data = new int /*long*/ [1];
+				do {
+					OS.gdk_window_get_user_data (window, user_data);
+					int /*long*/ handle = user_data [0];
+					if (handle != 0) {
+						Widget widget = getWidget (handle);
+						if (widget != null && widget instanceof Control) {
+							control = (Control) widget;
+							break;
+						}
+					}
+				} while ((window = OS.gdk_window_get_parent (window)) != 0);
+			}
+		}
+		if (control != null) {
+			shell = control.getShell ();
+			if ((shell.style & SWT.ON_TOP) != 0) {
+				OS.gtk_grab_add (shell.shellHandle);
+			}
+		}
+	}
+	OS.gtk_main_do_event (event);
+	if (dispatchEvents == null) putGdkEvents ();
+	if (control != null) {
+		if (shell != null && !shell.isDisposed () && (shell.style & SWT.ON_TOP) != 0) {
+			OS.gtk_grab_remove (shell.shellHandle);
+		}
+	}
+	return 0;
+}
+
+/**
+ * Given the operating system handle for a widget, returns
+ * the instance of the <code>Widget</code> subclass which
+ * represents it in the currently running application, if
+ * such exists, or null if no matching widget can be found.
+ * <p>
+ * <b>IMPORTANT:</b> This method should not be called from
+ * application code. The arguments are platform-specific.
+ * </p>
+ *
+ * @param handle the handle for the widget
+ * @return the SWT widget that the handle represents
+ *
+ * @exception SWTException <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>
+ */
+public Widget findWidget (int /*long*/ handle) {
+	checkDevice ();
+	return getWidget (handle);
+}
+
+/**
+ * Given the operating system handle for a widget,
+ * and widget-specific id, returns the instance of
+ * the <code>Widget</code> subclass which represents
+ * the handle/id pair in the currently running application,
+ * if such exists, or null if no matching widget can be found.
+ * <p>
+ * <b>IMPORTANT:</b> This method should not be called from
+ * application code. The arguments are platform-specific.
+ * </p>
+ *
+ * @param handle the handle for the widget
+ * @param id the id for the subwidget (usually an item)
+ * @return the SWT widget that the handle/id pair represents
+ *
+ * @exception SWTException <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.1
+ */
+public Widget findWidget (int /*long*/ handle, int id) {
+	checkDevice ();
+	return null;
+}
+
+/**
+ * Given a widget and a widget-specific id, returns the
+ * instance of the <code>Widget</code> subclass which represents
+ * the widget/id pair in the currently running application,
+ * if such exists, or null if no matching widget can be found.
+ *
+ * @param widget the widget
+ * @param id the id for the subwidget (usually an item)
+ * @return the SWT subwidget (usually an item) that the widget/id pair represents
+ *
+ * @exception SWTException <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.3
+ */
+public Widget findWidget (Widget widget, int id) {
+	checkDevice ();
+	return null;
+}
+
+static int /*long*/ fixedClassInitProc (int /*long*/ g_class, int /*long*/ class_data) {
+	GtkWidgetClass klass = new GtkWidgetClass ();
+	OS.memmove (klass, g_class);
+	klass.map = fixedMapProc;
+	OS.memmove (g_class, klass);
+	return 0;
+}
+
+static int /*long*/ fixedMapProc (int /*long*/ handle) {
+	Display display = getCurrent ();
+	Widget widget = display.getWidget (handle);
+	if (widget != null) return widget.fixedMapProc (handle);
+	return 0;
+}
+
+static int /*long*/ rendererClassInitProc (int /*long*/ g_class, int /*long*/ class_data) {
+	GtkCellRendererClass klass = new GtkCellRendererClass ();
+	OS.memmove (klass, g_class);
+	klass.render = rendererRenderProc;
+	klass.get_size = rendererGetSizeProc;
+	OS.memmove (g_class, klass);
+	return 0;
+}
+
+static int /*long*/ rendererGetSizeProc (int /*long*/ cell, int /*long*/ handle, int /*long*/ cell_area, int /*long*/ x_offset, int /*long*/ y_offset, int /*long*/ width, int /*long*/ height) {
+	Display display = getCurrent ();
+	Widget widget = display.getWidget (handle);
+	if (widget != null) return widget.rendererGetSizeProc (cell, handle, cell_area, x_offset, y_offset, width, height);
+	return 0;
+}
+
+static int /*long*/ rendererRenderProc (int /*long*/ cell, int /*long*/ window, int /*long*/ handle, int /*long*/ background_area, int /*long*/ cell_area, int /*long*/ expose_area, int /*long*/ flags) {
+	Display display = getCurrent ();
+	Widget widget = display.getWidget (handle);
+	if (widget != null) return widget.rendererRenderProc (cell, window, handle, background_area, cell_area, expose_area, flags);
+	return 0;
+}
+
+void flushExposes (int /*long*/ window, boolean all) {
+	OS.gdk_flush ();
+	OS.gdk_flush ();
+	if (OS.GDK_WINDOWING_X11 ()) {
+		this.flushWindow = window;
+		this.flushAll = all;
+		int /*long*/ xDisplay = OS.GDK_DISPLAY ();
+		int /*long*/ xEvent = OS.g_malloc (XEvent.sizeof);
+		OS.XCheckIfEvent (xDisplay, xEvent, checkIfEventProc, 0);
+		OS.g_free (xEvent);
+		this.flushWindow = 0;
+	}
+}
+
+/**
+ * Returns the currently active <code>Shell</code>, or null
+ * if no shell belonging to the currently running application
+ * is active.
+ *
+ * @return the active shell or null
+ *
+ * @exception SWTException <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>
+ */
+public Shell getActiveShell () {
+	checkDevice ();
+	return activeShell;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location.
+ *
+ * @return the bounding rectangle
+ *
+ * @exception SWTException <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>
+ */
+public Rectangle getBounds () {
+	checkDevice ();
+	return new Rectangle (0, 0, OS.gdk_screen_width (), OS.gdk_screen_height ());
+}
+
+/**
+ * Returns the display which the currently running thread is
+ * the user-interface thread for, or null if the currently
+ * running thread is not a user-interface thread for any display.
+ *
+ * @return the current display
+ */
+public static synchronized Display getCurrent () {
+	Thread current = Thread.currentThread ();
+	for (int i=0; i<Displays.length; i++) {
+		Display display = Displays [i];
+		if (display != null && display.thread == current) return display;
+	}
+	return null;
+}
+
+int getCaretBlinkTime () {
+//	checkDevice ();
+	int /*long*/ settings = OS.gtk_settings_get_default ();
+	if (settings == 0) return 500;
+	int [] buffer = new int [1];
+	OS.g_object_get (settings, OS.gtk_cursor_blink, buffer, 0);
+	if (buffer [0] == 0) return 0;
+	OS.g_object_get (settings, OS.gtk_cursor_blink_time, buffer, 0);
+	if (buffer [0] == 0) return 500;
+	/*
+	* By experimentation, GTK application don't use the whole
+	* blink cycle time.  Instead, they divide up the time, using
+	* an effective blink rate of about 1/2 the total time.
+	*/
+	return buffer [0] / 2;
+}
+
+/**
+ * Returns the control which the on-screen pointer is currently
+ * over top of, or null if it is not currently over one of the
+ * controls built by the currently running application.
+ *
+ * @return the control under the cursor
+ *
+ * @exception SWTException <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>
+ */
+public Control getCursorControl () {
+	checkDevice();
+	int[] x = new int[1], y = new int[1];
+	int /*long*/ window = OS.gdk_window_at_pointer (x,y);
+	if (window == 0) return null;
+	int /*long*/ [] user_data = new int /*long*/ [1];
+	OS.gdk_window_get_user_data (window, user_data);
+	int /*long*/ handle = user_data [0];
+	if (handle == 0) return null;
+	do {
+		Widget widget = getWidget (handle);
+		if (widget != null && widget instanceof Control) {
+			Control control = (Control) widget;
+			if (control.isEnabled ()) return control;
+		}
+	} while ((handle = OS.gtk_widget_get_parent (handle)) != 0);
+	return null;
+}
+
+boolean filterEvent (Event event) {
+	if (filterTable != null) filterTable.sendEvent (event);
+	return false;
+}
+
+boolean filters (int eventType) {
+	if (filterTable == null) return false;
+	return filterTable.hooks (eventType);
+}
+
+int /*long*/ filterProc (int /*long*/ xEvent, int /*long*/ gdkEvent, int /*long*/ data) {
+	if (data == 0) {
+		/*
+		* Feature in GTK.  When button 4, 5, 6, or 7 is released, GTK
+		* does not deliver a corresponding GTK event.  Button 6 and 7
+		* are mapped to buttons 4 and 5 in SWT.  The fix is to change
+		* the button number of the event to a negative number so that
+		* it gets dispatched by GTK.  SWT has been modified to look
+		* for negative button numbers.
+		*/
+		XButtonEvent mouseEvent = new XButtonEvent ();
+		OS.memmove (mouseEvent, xEvent, 4);
+		if (mouseEvent.type == OS.ButtonRelease) {
+			OS.memmove (mouseEvent, xEvent, XButtonEvent.sizeof);
+			switch (mouseEvent.button) {
+				case 6:
+				case 7:
+					mouseEvent.button = -mouseEvent.button;
+					OS.memmove (xEvent, mouseEvent, XButtonEvent.sizeof);
+					break;
+			}
+		}
+	}
+	Widget widget = getWidget (data);
+	if (widget == null) return 0;
+	return widget.filterProc (xEvent, gdkEvent, data);
+}
+
+/**
+ * Returns the location of the on-screen pointer relative
+ * to the top left corner of the screen.
+ *
+ * @return the cursor location
+ *
+ * @exception SWTException <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>
+ */
+public Point getCursorLocation () {
+	checkDevice ();
+	int [] x = new int [1], y = new int [1];
+	OS.gdk_window_get_pointer (0, x, y, null);
+	return new Point (x [0], y [0]);
+}
+
+/**
+ * Returns an array containing the recommended cursor sizes.
+ *
+ * @return the array of cursor sizes
+ *
+ * @exception SWTException <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.0
+ */
+public Point [] getCursorSizes () {
+	checkDevice ();
+	return new Point [] {new Point (16, 16), new Point (32, 32)};
+}
+
+/**
+ * Returns the application defined property of the receiver
+ * with the specified name, or null if it has not been set.
+ * <p>
+ * Applications may have associated arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the display is disposed
+ * of, it is the application's responsibility to provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @param key the name of the property
+ * @return the value of the property or null if it has not been set
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the key is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ *
+ * @see #setData(String, Object)
+ * @see #disposeExec(Runnable)
+ */
+public Object getData (String key) {
+	checkDevice ();
+	if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (key.equals (DISPATCH_EVENT_KEY)) {
+		return dispatchEvents;
+	}
+	if (keys == null) return null;
+	for (int i=0; i<keys.length; i++) {
+		if (keys [i].equals (key)) return values [i];
+	}
+	return null;
+}
+
+/**
+ * Returns the application defined, display specific data
+ * associated with the receiver, or null if it has not been
+ * set. The <em>display specific data</em> is a single,
+ * unnamed field that is stored with every display.
+ * <p>
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the display specific data needs to
+ * be notified when the display is disposed of, it is the
+ * application's responsibility to provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @return the display specific data
+ *
+ * @exception SWTException <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>
+ *
+ * @see #setData(Object)
+ * @see #disposeExec(Runnable)
+ */
+public Object getData () {
+	checkDevice ();
+	return data;
+}
+
+/**
+ * Returns a point whose x coordinate is the horizontal
+ * dots per inch of the display, and whose y coordinate
+ * is the vertical dots per inch of the display.
+ *
+ * @return the horizontal and vertical DPI
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public Point getDPI () {
+	checkDevice ();
+	int widthMM = OS.gdk_screen_width_mm ();
+	int width = OS.gdk_screen_width ();
+	int dpi = Compatibility.round (254 * width, widthMM * 10);
+	return new Point (dpi, dpi);
+}
+
+int /*long*/ gtk_fixed_get_type () {
+	return fixed_type;
+}
+
+int /*long*/ gtk_cell_renderer_text_get_type () {
+	return text_renderer_type;
+}
+
+int /*long*/ gtk_cell_renderer_pixbuf_get_type () {
+	return pixbuf_renderer_type;
+}
+
+int /*long*/ gtk_cell_renderer_toggle_get_type () {
+	return toggle_renderer_type;
+}
+
+/**
+ * Returns the default display. One is created (making the
+ * thread that invokes this method its user-interface thread)
+ * if it did not already exist.
+ *
+ * @return the default display
+ */
+public static synchronized Display getDefault () {
+	if (Default == null) Default = new Display ();
+	return Default;
+}
+
+static boolean isValidClass (Class clazz) {
+	String name = clazz.getName ();
+	int index = name.lastIndexOf ('.');
+	return name.substring (0, index + 1).equals (PACKAGE_PREFIX);
+}
+
+/**
+ * Returns the button dismissal alignment, one of <code>LEFT</code> or <code>RIGHT</code>.
+ * The button dismissal alignment is the ordering that should be used when positioning the
+ * default dismissal button for a dialog.  For example, in a dialog that contains an OK and
+ * CANCEL button, on platforms where the button dismissal alignment is <code>LEFT</code>, the
+ * button ordering should be OK/CANCEL.  When button dismissal alignment is <code>RIGHT</code>,
+ * the button ordering should be CANCEL/OK.
+ *
+ * @return the button dismissal order
+ *
+ * @exception SWTException <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 2.1
+ */
+public int getDismissalAlignment () {
+	checkDevice ();
+	return SWT.RIGHT;
+}
+
+/**
+ * Returns the longest duration, in milliseconds, between
+ * two mouse button clicks that will be considered a
+ * <em>double click</em> by the underlying operating system.
+ *
+ * @return the double click time
+ *
+ * @exception SWTException <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>
+ */
+public int getDoubleClickTime () {
+	checkDevice ();
+	int /*long*/ settings = OS.gtk_settings_get_default ();
+	int [] buffer = new int [1];
+	OS.g_object_get (settings, OS.gtk_double_click_time, buffer, 0);
+	return buffer [0];
+}
+
+/**
+ * Returns the control which currently has keyboard focus,
+ * or null if keyboard events are not currently going to
+ * any of the controls built by the currently running
+ * application.
+ *
+ * @return the control under the cursor
+ *
+ * @exception SWTException <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>
+ */
+public Control getFocusControl () {
+	checkDevice ();
+	if (focusControl != null && !focusControl.isDisposed ()) {
+		return focusControl;
+	}
+	if (activeShell == null) return null;
+	int /*long*/ shellHandle = activeShell.shellHandle;
+	int /*long*/ handle = OS.gtk_window_get_focus (shellHandle);
+	if (handle == 0) return null;
+	do {
+		Widget widget = getWidget (handle);
+		if (widget != null && widget instanceof Control) {
+			Control control = (Control) widget;
+			return control.isEnabled () ? control : null;
+		}
+	} while ((handle = OS.gtk_widget_get_parent (handle)) != 0);
+	return null;
+}
+
+/**
+ * Returns true when the high contrast mode is enabled.
+ * Otherwise, false is returned.
+ * <p>
+ * Note: This operation is a hint and is not supported on
+ * platforms that do not have this concept.
+ * </p>
+ *
+ * @return the high contrast mode
+ *
+ * @exception SWTException <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.0
+ */
+public boolean getHighContrast () {
+	checkDevice ();
+	return false;
+}
+
+public int getDepth () {
+	checkDevice ();
+	GdkVisual visual = new GdkVisual ();
+	OS.memmove (visual, OS.gdk_visual_get_system());
+	return visual.depth;
+}
+
+/**
+ * Returns the maximum allowed depth of icons on this display, in bits per pixel.
+ * On some platforms, this may be different than the actual depth of the display.
+ *
+ * @return the maximum icon depth
+ *
+ * @exception SWTException <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>
+ *
+ * @see Device#getDepth
+ */
+public int getIconDepth () {
+	checkDevice ();
+	return getDepth ();
+}
+
+/**
+ * Returns an array containing the recommended icon sizes.
+ *
+ * @return the array of icon sizes
+ *
+ * @exception SWTException <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>
+ *
+ * @see Decorations#setImages(Image[])
+ *
+ * @since 3.0
+ */
+public Point [] getIconSizes () {
+	checkDevice ();
+	return new Point [] {new Point (16, 16), new Point (32, 32)};
+}
+
+int getLastEventTime () {
+	return lastEventTime;
+}
+
+int getMessageCount () {
+	return synchronizer.getMessageCount ();
+}
+
+/**
+ * Returns the work area, an EWMH property to store the size
+ * and position of the screen not covered by dock and panel
+ * windows.  See http://freedesktop.org/Standards/wm-spec.
+ */
+Rectangle getWorkArea() {
+	byte[] name = Converter.wcsToMbcs (null, "_NET_WORKAREA", true);
+	int /*long*/ atom = OS.gdk_atom_intern (name, true);
+	if (atom == OS.GDK_NONE) return null;
+	int /*long*/[] actualType = new int /*long*/[1];
+	int[] actualFormat = new int[1];
+	int[] actualLength = new int[1];
+	int /*long*/[] data = new int /*long*/[1];
+	if (!OS.gdk_property_get (OS.GDK_ROOT_PARENT (), atom, OS.GDK_NONE, 0, 16, 0, actualType, actualFormat, actualLength, data)) {
+		return null;
+	}
+	Rectangle result = null;
+	if (data [0] != 0) {
+		if (actualLength [0] == 16) {
+			int values [] = new int [4];
+			OS.memmove (values, data[0], 16);
+			result = new Rectangle (values [0],values [1],values [2],values [3]);
+		} else if (actualLength [0] == 32) {
+			long values [] = new long [4];
+			OS.memmove (values, data[0], 32);
+			result = new Rectangle ((int)values [0],(int)values [1],(int)values [2],(int)values [3]);
+		}
+		OS.g_free (data [0]);
+	}
+	return result;
+}
+
+/**
+ * Returns an array of monitors attached to the device.
+ *
+ * @return the array of monitors
+ *
+ * @since 3.0
+ */
+public Monitor [] getMonitors () {
+	checkDevice ();
+	Monitor [] monitors = null;
+	Rectangle workArea = getWorkArea();
+	int /*long*/ screen = OS.gdk_screen_get_default ();
+	if (screen != 0) {
+		int monitorCount = OS.gdk_screen_get_n_monitors (screen);
+		if (monitorCount > 0) {
+			monitors = new Monitor [monitorCount];
+			GdkRectangle dest = new GdkRectangle ();
+			for (int i = 0; i < monitorCount; i++) {
+				OS.gdk_screen_get_monitor_geometry (screen, i, dest);
+				Monitor monitor = new Monitor ();
+				monitor.handle = i;
+				monitor.x = dest.x;
+				monitor.y = dest.y;
+				monitor.width = dest.width;
+				monitor.height = dest.height;
+				if (i == 0 && workArea != null) {
+					monitor.clientX = workArea.x;
+					monitor.clientY = workArea.y;
+					monitor.clientWidth = workArea.width;
+					monitor.clientHeight = workArea.height;
+				} else {
+					monitor.clientX = monitor.x;
+					monitor.clientY = monitor.y;
+					monitor.clientWidth = monitor.width;
+					monitor.clientHeight = monitor.height;
+				}
+				monitors [i] = monitor;
+			}
+		}
+	}
+	if (monitors == null) {
+		/* No multimonitor support detected, default to one monitor */
+		Monitor monitor = new Monitor ();
+		Rectangle bounds = getBounds ();
+		monitor.x = bounds.x;
+		monitor.y = bounds.y;
+		monitor.width = bounds.width;
+		monitor.height = bounds.height;
+		if (workArea != null) {
+			monitor.clientX = workArea.x;
+			monitor.clientY = workArea.y;
+			monitor.clientWidth = workArea.width;
+			monitor.clientHeight = workArea.height;
+		} else {
+			monitor.clientX = monitor.x;
+			monitor.clientY = monitor.y;
+			monitor.clientWidth = monitor.width;
+			monitor.clientHeight = monitor.height;
+		}
+		monitors = new Monitor [] { monitor };
+	}
+	return monitors;
+}
+
+/**
+ * Returns the primary monitor for that device.
+ *
+ * @return the primary monitor
+ *
+ * @since 3.0
+ */
+public Monitor getPrimaryMonitor () {
+	checkDevice ();
+	Monitor [] monitors = getMonitors ();
+	return monitors [0];
+}
+
+/**
+ * Returns a (possibly empty) array containing all shells which have
+ * not been disposed and have the receiver as their display.
+ *
+ * @return the receiver's shells
+ *
+ * @exception SWTException <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>
+ */
+public Shell [] getShells () {
+	checkDevice ();
+	int index = 0;
+	Shell [] result = new Shell [16];
+	for (int i = 0; i < widgetTable.length; i++) {
+		Widget widget = widgetTable [i];
+		if (widget != null && widget instanceof Shell) {
+			int j = 0;
+			while (j < index) {
+				if (result [j] == widget) break;
+				j++;
+			}
+			if (j == index) {
+				if (index == result.length) {
+					Shell [] newResult = new Shell [index + 16];
+					System.arraycopy (result, 0, newResult, 0, index);
+					result = newResult;
+				}
+				result [index++] = (Shell) widget;
+			}
+		}
+	}
+	if (index == result.length) return result;
+	Shell [] newResult = new Shell [index];
+	System.arraycopy (result, 0, newResult, 0, index);
+	return newResult;
+}
+
+/**
+ * Returns the thread that has invoked <code>syncExec</code>
+ * or null if no such runnable is currently being invoked by
+ * the user-interface thread.
+ * <p>
+ * Note: If a runnable invoked by asyncExec is currently
+ * running, this method will return null.
+ * </p>
+ *
+ * @return the receiver's sync-interface thread
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Thread getSyncThread () {
+	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+	return synchronizer.syncThread;
+}
+
+/**
+ * Returns the matching standard color for the given
+ * constant, which should be one of the color constants
+ * specified in class <code>SWT</code>. Any value other
+ * than one of the SWT color constants which is passed
+ * in will result in the color black. This color should
+ * not be free'd because it was allocated by the system,
+ * not the application.
+ *
+ * @param id the color constant
+ * @return the matching color
+ *
+ * @exception SWTException <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>
+ *
+ * @see SWT
+ */
+public Color getSystemColor (int id) {
+	checkDevice ();
+	GdkColor gdkColor = null;
+	switch (id) {
+		case SWT.COLOR_INFO_FOREGROUND: 					gdkColor = COLOR_INFO_FOREGROUND; break;
+		case SWT.COLOR_INFO_BACKGROUND: 					gdkColor = COLOR_INFO_BACKGROUND; break;
+		case SWT.COLOR_TITLE_FOREGROUND:					gdkColor = COLOR_TITLE_FOREGROUND; break;
+		case SWT.COLOR_TITLE_BACKGROUND:					gdkColor = COLOR_TITLE_BACKGROUND; break;
+		case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:			gdkColor = COLOR_TITLE_BACKGROUND_GRADIENT; break;
+		case SWT.COLOR_TITLE_INACTIVE_FOREGROUND:			gdkColor = COLOR_TITLE_INACTIVE_FOREGROUND; break;
+		case SWT.COLOR_TITLE_INACTIVE_BACKGROUND:			gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND; break;
+		case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:	gdkColor = COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT; break;
+		case SWT.COLOR_WIDGET_DARK_SHADOW:					gdkColor = COLOR_WIDGET_DARK_SHADOW; break;
+		case SWT.COLOR_WIDGET_NORMAL_SHADOW:				gdkColor = COLOR_WIDGET_NORMAL_SHADOW; break;
+		case SWT.COLOR_WIDGET_LIGHT_SHADOW: 				gdkColor = COLOR_WIDGET_LIGHT_SHADOW; break;
+		case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW:				gdkColor = COLOR_WIDGET_HIGHLIGHT_SHADOW; break;
+		case SWT.COLOR_WIDGET_BACKGROUND: 					gdkColor = COLOR_WIDGET_BACKGROUND; break;
+		case SWT.COLOR_WIDGET_FOREGROUND: 					gdkColor = COLOR_WIDGET_FOREGROUND; break;
+		case SWT.COLOR_WIDGET_BORDER: 						gdkColor = COLOR_WIDGET_BORDER; break;
+		case SWT.COLOR_LIST_FOREGROUND: 					gdkColor = COLOR_LIST_FOREGROUND; break;
+		case SWT.COLOR_LIST_BACKGROUND: 					gdkColor = COLOR_LIST_BACKGROUND; break;
+		case SWT.COLOR_LIST_SELECTION: 						gdkColor = COLOR_LIST_SELECTION; break;
+		case SWT.COLOR_LIST_SELECTION_TEXT: 				gdkColor = COLOR_LIST_SELECTION_TEXT; break;
+		default:
+			return super.getSystemColor (id);
+	}
+	if (gdkColor == null) return super.getSystemColor (SWT.COLOR_BLACK);
+	return Color.gtk_new (this, gdkColor);
+}
+
+/**
+ * Returns the matching standard platform cursor for the given
+ * constant, which should be one of the cursor constants
+ * specified in class <code>SWT</code>. This cursor should
+ * not be free'd because it was allocated by the system,
+ * not the application.  A value of <code>null</code> will
+ * be returned if the supplied constant is not an SWT cursor
+ * constant.
+ *
+ * @param id the SWT cursor constant
+ * @return the corresponding cursor or <code>null</code>
+ *
+ * @exception SWTException <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>
+ *
+ * @see SWT#CURSOR_ARROW
+ * @see SWT#CURSOR_WAIT
+ * @see SWT#CURSOR_CROSS
+ * @see SWT#CURSOR_APPSTARTING
+ * @see SWT#CURSOR_HELP
+ * @see SWT#CURSOR_SIZEALL
+ * @see SWT#CURSOR_SIZENESW
+ * @see SWT#CURSOR_SIZENS
+ * @see SWT#CURSOR_SIZENWSE
+ * @see SWT#CURSOR_SIZEWE
+ * @see SWT#CURSOR_SIZEN
+ * @see SWT#CURSOR_SIZES
+ * @see SWT#CURSOR_SIZEE
+ * @see SWT#CURSOR_SIZEW
+ * @see SWT#CURSOR_SIZENE
+ * @see SWT#CURSOR_SIZESE
+ * @see SWT#CURSOR_SIZESW
+ * @see SWT#CURSOR_SIZENW
+ * @see SWT#CURSOR_UPARROW
+ * @see SWT#CURSOR_IBEAM
+ * @see SWT#CURSOR_NO
+ * @see SWT#CURSOR_HAND
+ *
+ * @since 3.0
+ */
+public Cursor getSystemCursor (int id) {
+	checkDevice ();
+	if (!(0 <= id && id < cursors.length)) return null;
+	if (cursors [id] == null) {
+		cursors [id] = new Cursor (this, id);
+	}
+	return cursors [id];
+}
+
+/**
+ * Returns the matching standard platform image for the given
+ * constant, which should be one of the icon constants
+ * specified in class <code>SWT</code>. This image should
+ * not be free'd because it was allocated by the system,
+ * not the application.  A value of <code>null</code> will
+ * be returned either if the supplied constant is not an
+ * SWT icon constant or if the platform does not define an
+ * image that corresponds to the constant.
+ *
+ * @param id the SWT icon constant
+ * @return the corresponding image or <code>null</code>
+ *
+ * @exception SWTException <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>
+ *
+ * @see SWT#ICON_ERROR
+ * @see SWT#ICON_INFORMATION
+ * @see SWT#ICON_QUESTION
+ * @see SWT#ICON_WARNING
+ * @see SWT#ICON_WORKING
+ *
+ * @since 3.0
+ */
+public Image getSystemImage (int id) {
+	checkDevice ();
+	switch (id) {
+		case SWT.ICON_ERROR:
+			if (errorImage == null) {
+				errorImage = createImage ("gtk-dialog-error");
+			}
+			return errorImage;
+		case SWT.ICON_INFORMATION:
+		case SWT.ICON_WORKING:
+			if (infoImage == null) {
+				infoImage = createImage ("gtk-dialog-info");
+			}
+			return infoImage;
+		case SWT.ICON_QUESTION:
+			if (questionImage == null) {
+				questionImage = createImage ("gtk-dialog-question");
+			}
+			return questionImage;
+		case SWT.ICON_WARNING:
+			if (warningImage == null) {
+				warningImage = createImage ("gtk-dialog-warning");
+			}
+			return warningImage;
+	}
+	return null;
+}
+
+void initializeSystemColors () {
+	GdkColor gdkColor;
+
+	/* Get Tooltip resources */
+	int /*long*/ tooltipShellHandle = OS.gtk_window_new (OS.GTK_WINDOW_POPUP);
+	if (tooltipShellHandle == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+	byte[] gtk_tooltips = Converter.wcsToMbcs (null, "gtk-tooltips", true);
+	OS.gtk_widget_set_name (tooltipShellHandle, gtk_tooltips);
+	OS.gtk_widget_realize (tooltipShellHandle);
+	int /*long*/ tooltipStyle = OS.gtk_widget_get_style (tooltipShellHandle);
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_fg (tooltipStyle, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_INFO_FOREGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_bg (tooltipStyle, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_INFO_BACKGROUND = gdkColor;
+	OS.gtk_widget_destroy (tooltipShellHandle);
+
+	/* Get Shell resources */
+	int /*long*/ style = OS.gtk_widget_get_style (shellHandle);
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_black (style, gdkColor);
+	COLOR_WIDGET_DARK_SHADOW = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_dark (style, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_WIDGET_NORMAL_SHADOW = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_bg (style, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_WIDGET_LIGHT_SHADOW = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_light (style, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_WIDGET_HIGHLIGHT_SHADOW = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_fg (style, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_WIDGET_FOREGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_bg (style, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_WIDGET_BACKGROUND = gdkColor;
+	//gdkColor = new GdkColor();
+	//OS.gtk_style_get_text (style, OS.GTK_STATE_NORMAL, gdkColor);
+	//COLOR_TEXT_FOREGROUND = gdkColor;
+	//gdkColor = new GdkColor();
+	//OS.gtk_style_get_base (style, OS.GTK_STATE_NORMAL, gdkColor);
+	//COLOR_TEXT_BACKGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_text (style, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_LIST_FOREGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_base (style, OS.GTK_STATE_NORMAL, gdkColor);
+	COLOR_LIST_BACKGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_text (style, OS.GTK_STATE_SELECTED, gdkColor);
+	COLOR_LIST_SELECTION_TEXT = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_base (style, OS.GTK_STATE_SELECTED, gdkColor);
+	COLOR_LIST_SELECTION = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_bg (style, OS.GTK_STATE_SELECTED, gdkColor);
+	COLOR_TITLE_BACKGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_fg (style, OS.GTK_STATE_SELECTED, gdkColor);
+	COLOR_TITLE_FOREGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_light (style, OS.GTK_STATE_SELECTED, gdkColor);
+	COLOR_TITLE_BACKGROUND_GRADIENT = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_bg (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
+	COLOR_TITLE_INACTIVE_BACKGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_fg (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
+	COLOR_TITLE_INACTIVE_FOREGROUND = gdkColor;
+	gdkColor = new GdkColor();
+	OS.gtk_style_get_light (style, OS.GTK_STATE_INSENSITIVE, gdkColor);
+	COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT = gdkColor;
+}
+
+/**
+ * Returns a reasonable font for applications to use.
+ * On some platforms, this will match the "default font"
+ * or "system font" if such can be found.  This font
+ * should not be free'd because it was allocated by the
+ * system, not the application.
+ * <p>
+ * Typically, applications which want the default look
+ * should simply not set the font on the widgets they
+ * create. Widgets are always created with the correct
+ * default font for the class of user-interface component
+ * they represent.
+ * </p>
+ *
+ * @return a font
+ *
+ * @exception SWTException <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>
+ */
+public Font getSystemFont () {
+	checkDevice ();
+	if (systemFont != null) return systemFont;
+	int /*long*/ style = OS.gtk_widget_get_style (shellHandle);
+	int /*long*/ defaultFont = OS.pango_font_description_copy (OS.gtk_style_get_font_desc (style));
+	return systemFont = Font.gtk_new (this, defaultFont);
+}
+
+/**
+ * Returns the single instance of the system tray or null
+ * when there is no system tray available for the platform.
+ *
+ * @return the system tray or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Tray getSystemTray () {
+	checkDevice ();
+	if (tray != null) return tray;
+	return tray = new Tray (this, SWT.NONE);
+}
+
+/**
+ * Returns the user-interface thread for the receiver.
+ *
+ * @return the receiver's user-interface thread
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Thread getThread () {
+	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+	return thread;
+}
+
+Widget getWidget (int /*long*/ handle) {
+	if (handle == 0) return null;
+	if (lastWidget != null && lastHandle == handle) return lastWidget;
+	int /*long*/ index = OS.g_object_get_qdata (handle, SWT_OBJECT_INDEX) - 1;
+	if (0 <= index && index < widgetTable.length) {
+		lastHandle = handle;
+		return lastWidget = widgetTable [(int)/*64*/index];
+	}
+	return null;
+}
+
+int /*long*/ idleProc (int /*long*/ data) {
+	boolean result = runAsyncMessages (false);
+	if (!result) {
+		synchronized (idleLock) {
+			idleHandle = 0;
+		}
+	}
+	return result ? 1 : 0;
+}
+
+/**
+ * Initializes any internal resources needed by the
+ * device.
+ * <p>
+ * This method is called after <code>create</code>.
+ * </p>
+ *
+ * @see #create
+ */
+protected void init () {
+	super.init ();
+	initializeCallbacks ();
+	initializeSystemColors ();
+	initializeSystemSettings ();
+	initializeWidgetTable ();
+	initializeWindowManager ();
+}
+
+void initializeCallbacks () {
+	closures = new int /*long*/ [Widget.LAST_SIGNAL];
+	signalIds = new int [Widget.LAST_SIGNAL];
+
+	/* Cache signals for GtkWidget */
+	signalIds [Widget.BUTTON_PRESS_EVENT] = OS.g_signal_lookup (OS.button_press_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.BUTTON_RELEASE_EVENT] = OS.g_signal_lookup (OS.button_release_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.CONFIGURE_EVENT] = OS.g_signal_lookup (OS.configure_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.DELETE_EVENT] = OS.g_signal_lookup (OS.delete_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.ENTER_NOTIFY_EVENT] = OS.g_signal_lookup (OS.enter_notify_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.EVENT] = OS.g_signal_lookup (OS.event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.EVENT_AFTER] = OS.g_signal_lookup (OS.event_after, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.EXPOSE_EVENT] = OS.g_signal_lookup (OS.expose_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.FOCUS] = OS.g_signal_lookup (OS.focus, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.FOCUS_IN_EVENT] = OS.g_signal_lookup (OS.focus_in_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.FOCUS_OUT_EVENT] = OS.g_signal_lookup (OS.focus_out_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.GRAB_FOCUS] = OS.g_signal_lookup (OS.grab_focus, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.HIDE] = OS.g_signal_lookup (OS.hide, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.KEY_PRESS_EVENT] = OS.g_signal_lookup (OS.key_press_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.KEY_RELEASE_EVENT] = OS.g_signal_lookup (OS.key_release_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.LEAVE_NOTIFY_EVENT] = OS.g_signal_lookup (OS.leave_notify_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.MAP] = OS.g_signal_lookup (OS.map, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.MAP_EVENT] = OS.g_signal_lookup (OS.map_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.MNEMONIC_ACTIVATE] = OS.g_signal_lookup (OS.mnemonic_activate, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.MOTION_NOTIFY_EVENT] = OS.g_signal_lookup (OS.motion_notify_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.POPUP_MENU] = OS.g_signal_lookup (OS.popup_menu, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.REALIZE] = OS.g_signal_lookup (OS.realize, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.SCROLL_EVENT] = OS.g_signal_lookup (OS.scroll_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.SHOW] = OS.g_signal_lookup (OS.show, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.SHOW_HELP] = OS.g_signal_lookup (OS.show_help, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.SIZE_ALLOCATE] = OS.g_signal_lookup (OS.size_allocate, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.STYLE_SET] = OS.g_signal_lookup (OS.style_set, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.UNMAP] = OS.g_signal_lookup (OS.unmap, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.UNMAP_EVENT] = OS.g_signal_lookup (OS.unmap_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.UNREALIZE] = OS.g_signal_lookup (OS.realize, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.VISIBILITY_NOTIFY_EVENT] = OS.g_signal_lookup (OS.visibility_notify_event, OS.GTK_TYPE_WIDGET ());
+	signalIds [Widget.WINDOW_STATE_EVENT] = OS.g_signal_lookup (OS.window_state_event, OS.GTK_TYPE_WIDGET ());
+
+	windowCallback2 = new Callback (this, "windowProc", 2);
+	windowProc2 = windowCallback2.getAddress ();
+	if (windowProc2 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	closures [Widget.ACTIVATE] = OS.g_cclosure_new (windowProc2, Widget.ACTIVATE, 0);
+	closures [Widget.ACTIVATE_INVERSE] = OS.g_cclosure_new (windowProc2, Widget.ACTIVATE_INVERSE, 0);
+	closures [Widget.CHANGED] = OS.g_cclosure_new (windowProc2, Widget.CHANGED, 0);
+	closures [Widget.CLICKED] = OS.g_cclosure_new (windowProc2, Widget.CLICKED, 0);
+	closures [Widget.DAY_SELECTED] = OS.g_cclosure_new (windowProc2, Widget.DAY_SELECTED, 0);
+	closures [Widget.HIDE] = OS.g_cclosure_new (windowProc2, Widget.HIDE, 0);
+	closures [Widget.GRAB_FOCUS] = OS.g_cclosure_new (windowProc2, Widget.GRAB_FOCUS, 0);
+	closures [Widget.MAP] = OS.g_cclosure_new (windowProc2, Widget.MAP, 0);
+	closures [Widget.MONTH_CHANGED] = OS.g_cclosure_new (windowProc2, Widget.MONTH_CHANGED, 0);
+	closures [Widget.OUTPUT] = OS.g_cclosure_new (windowProc2, Widget.OUTPUT, 0);
+	closures [Widget.POPUP_MENU] = OS.g_cclosure_new (windowProc2, Widget.POPUP_MENU, 0);
+	closures [Widget.PREEDIT_CHANGED] = OS.g_cclosure_new (windowProc2, Widget.PREEDIT_CHANGED, 0);
+	closures [Widget.REALIZE] = OS.g_cclosure_new (windowProc2, Widget.REALIZE, 0);
+	closures [Widget.SELECT] = OS.g_cclosure_new (windowProc2, Widget.SELECT, 0);
+	closures [Widget.SHOW] = OS.g_cclosure_new (windowProc2, Widget.SHOW, 0);
+	closures [Widget.VALUE_CHANGED] = OS.g_cclosure_new (windowProc2, Widget.VALUE_CHANGED, 0);
+	closures [Widget.UNMAP] = OS.g_cclosure_new (windowProc2, Widget.UNMAP, 0);
+	closures [Widget.UNREALIZE] = OS.g_cclosure_new (windowProc2, Widget.UNREALIZE, 0);
+
+	windowCallback3 = new Callback (this, "windowProc", 3);
+	windowProc3 = windowCallback3.getAddress ();
+	if (windowProc3 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	closures [Widget.BUTTON_PRESS_EVENT] = OS.g_cclosure_new (windowProc3, Widget.BUTTON_PRESS_EVENT, 0);
+	closures [Widget.BUTTON_PRESS_EVENT_INVERSE] = OS.g_cclosure_new (windowProc3, Widget.BUTTON_PRESS_EVENT_INVERSE, 0);
+	closures [Widget.BUTTON_RELEASE_EVENT] = OS.g_cclosure_new (windowProc3, Widget.BUTTON_RELEASE_EVENT, 0);
+	closures [Widget.BUTTON_RELEASE_EVENT_INVERSE] = OS.g_cclosure_new (windowProc3, Widget.BUTTON_RELEASE_EVENT_INVERSE, 0);
+	closures [Widget.COMMIT] = OS.g_cclosure_new (windowProc3, Widget.COMMIT, 0);
+	closures [Widget.CONFIGURE_EVENT] = OS.g_cclosure_new (windowProc3, Widget.CONFIGURE_EVENT, 0);
+	closures [Widget.DELETE_EVENT] = OS.g_cclosure_new (windowProc3, Widget.DELETE_EVENT, 0);
+	closures [Widget.ENTER_NOTIFY_EVENT] = OS.g_cclosure_new (windowProc3, Widget.ENTER_NOTIFY_EVENT, 0);
+	closures [Widget.EVENT] = OS.g_cclosure_new (windowProc3, Widget.EVENT, 0);
+	closures [Widget.EVENT_AFTER] = OS.g_cclosure_new (windowProc3, Widget.EVENT_AFTER, 0);
+	closures [Widget.EXPOSE_EVENT] = OS.g_cclosure_new (windowProc3, Widget.EXPOSE_EVENT, 0);
+	closures [Widget.EXPOSE_EVENT_INVERSE] = OS.g_cclosure_new (windowProc3, Widget.EXPOSE_EVENT_INVERSE, 0);
+	closures [Widget.FOCUS] = OS.g_cclosure_new (windowProc3, Widget.FOCUS, 0);
+	closures [Widget.FOCUS_IN_EVENT] = OS.g_cclosure_new (windowProc3, Widget.FOCUS_IN_EVENT, 0);
+	closures [Widget.FOCUS_OUT_EVENT] = OS.g_cclosure_new (windowProc3, Widget.FOCUS_OUT_EVENT, 0);
+	closures [Widget.KEY_PRESS_EVENT] = OS.g_cclosure_new (windowProc3, Widget.KEY_PRESS_EVENT, 0);
+	closures [Widget.KEY_RELEASE_EVENT] = OS.g_cclosure_new (windowProc3, Widget.KEY_RELEASE_EVENT, 0);
+	closures [Widget.INPUT] = OS.g_cclosure_new (windowProc3, Widget.INPUT, 0);
+	closures [Widget.LEAVE_NOTIFY_EVENT] = OS.g_cclosure_new (windowProc3, Widget.LEAVE_NOTIFY_EVENT, 0);
+	closures [Widget.MAP_EVENT] = OS.g_cclosure_new (windowProc3, Widget.MAP_EVENT, 0);
+	closures [Widget.MNEMONIC_ACTIVATE] = OS.g_cclosure_new (windowProc3, Widget.MNEMONIC_ACTIVATE, 0);
+	closures [Widget.MOTION_NOTIFY_EVENT] = OS.g_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT, 0);
+	closures [Widget.MOTION_NOTIFY_EVENT_INVERSE] = OS.g_cclosure_new (windowProc3, Widget.MOTION_NOTIFY_EVENT_INVERSE, 0);
+	closures [Widget.MOVE_FOCUS] = OS.g_cclosure_new (windowProc3, Widget.MOVE_FOCUS, 0);
+	closures [Widget.SCROLL_EVENT] = OS.g_cclosure_new (windowProc3, Widget.SCROLL_EVENT, 0);
+	closures [Widget.SHOW_HELP] = OS.g_cclosure_new (windowProc3, Widget.SHOW_HELP, 0);
+	closures [Widget.SIZE_ALLOCATE] = OS.g_cclosure_new (windowProc3, Widget.SIZE_ALLOCATE, 0);
+	closures [Widget.STYLE_SET] = OS.g_cclosure_new (windowProc3, Widget.STYLE_SET, 0);
+	closures [Widget.TOGGLED] = OS.g_cclosure_new (windowProc3, Widget.TOGGLED, 0);
+	closures [Widget.UNMAP_EVENT] = OS.g_cclosure_new (windowProc3, Widget.UNMAP_EVENT, 0);
+	closures [Widget.VISIBILITY_NOTIFY_EVENT] = OS.g_cclosure_new (windowProc3, Widget.VISIBILITY_NOTIFY_EVENT, 0);
+	closures [Widget.WINDOW_STATE_EVENT] = OS.g_cclosure_new (windowProc3, Widget.WINDOW_STATE_EVENT, 0);
+
+	windowCallback4 = new Callback (this, "windowProc", 4);
+	windowProc4 = windowCallback4.getAddress ();
+	if (windowProc4 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	closures [Widget.DELETE_RANGE] = OS.g_cclosure_new (windowProc4, Widget.DELETE_RANGE, 0);
+	closures [Widget.DELETE_TEXT] = OS.g_cclosure_new (windowProc4, Widget.DELETE_TEXT, 0);
+	closures [Widget.ROW_ACTIVATED] = OS.g_cclosure_new (windowProc4, Widget.ROW_ACTIVATED, 0);
+	closures [Widget.SCROLL_CHILD] = OS.g_cclosure_new (windowProc4, Widget.SCROLL_CHILD, 0);
+	closures [Widget.SWITCH_PAGE] = OS.g_cclosure_new (windowProc4, Widget.SWITCH_PAGE, 0);
+	closures [Widget.TEST_COLLAPSE_ROW] = OS.g_cclosure_new (windowProc4, Widget.TEST_COLLAPSE_ROW, 0);
+	closures [Widget.TEST_EXPAND_ROW] = OS.g_cclosure_new (windowProc4, Widget.TEST_EXPAND_ROW, 0);
+
+	windowCallback5 = new Callback (this, "windowProc", 5);
+	windowProc5 = windowCallback5.getAddress ();
+	if (windowProc5 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	closures [Widget.CHANGE_VALUE] = OS.g_cclosure_new (windowProc5, Widget.CHANGE_VALUE, 0);
+	closures [Widget.EXPAND_COLLAPSE_CURSOR_ROW] = OS.g_cclosure_new (windowProc5, Widget.EXPAND_COLLAPSE_CURSOR_ROW, 0);
+	closures [Widget.INSERT_TEXT] = OS.g_cclosure_new (windowProc5, Widget.INSERT_TEXT, 0);
+	closures [Widget.TEXT_BUFFER_INSERT_TEXT] = OS.g_cclosure_new (windowProc5, Widget.TEXT_BUFFER_INSERT_TEXT, 0);
+
+	for (int i = 0; i < Widget.LAST_SIGNAL; i++) {
+		if (closures [i] != 0) OS.g_closure_ref (closures [i]);
+	}
+
+	timerCallback = new Callback (this, "timerProc", 1);
+	timerProc = timerCallback.getAddress ();
+	if (timerProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	windowTimerCallback = new Callback (this, "windowTimerProc", 1);
+	windowTimerProc = windowTimerCallback.getAddress ();
+	if (windowTimerProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	mouseHoverCallback = new Callback (this, "mouseHoverProc", 1);
+	mouseHoverProc = mouseHoverCallback.getAddress ();
+	if (mouseHoverProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	caretCallback = new Callback(this, "caretProc", 1);
+	caretProc = caretCallback.getAddress();
+	if (caretProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	menuPositionCallback = new Callback(this, "menuPositionProc", 5);
+	menuPositionProc = menuPositionCallback.getAddress();
+	if (menuPositionProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	sizeAllocateCallback = new Callback(this, "sizeAllocateProc", 3);
+	sizeAllocateProc = sizeAllocateCallback.getAddress();
+	if (sizeAllocateProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	sizeRequestCallback = new Callback(this, "sizeRequestProc", 3);
+	sizeRequestProc = sizeRequestCallback.getAddress();
+	if (sizeRequestProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	shellMapCallback = new Callback(this, "shellMapProc", 3);
+	shellMapProc = shellMapCallback.getAddress();
+	if (shellMapProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	shellMapProcClosure = OS.g_cclosure_new (shellMapProc, 0, 0);
+	OS.g_closure_ref (shellMapProcClosure);
+
+	treeSelectionCallback = new Callback(this, "treeSelectionProc", 4);
+	treeSelectionProc = treeSelectionCallback.getAddress();
+	if (treeSelectionProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	cellDataCallback = new Callback (this, "cellDataProc", 5);
+	cellDataProc = cellDataCallback.getAddress ();
+	if (cellDataProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	setDirectionCallback = new Callback (this, "setDirectionProc", 2);
+	setDirectionProc = setDirectionCallback.getAddress ();
+	if (setDirectionProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	allChildrenCallback = new Callback (this, "allChildrenProc", 2);
+	allChildrenProc = allChildrenCallback.getAddress ();
+	if (allChildrenProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	checkIfEventCallback = new Callback (this, "checkIfEventProc", 3);
+	checkIfEventProc = checkIfEventCallback.getAddress ();
+	if (checkIfEventProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+	idleCallback = new Callback (this, "idleProc", 1);
+	idleProc = idleCallback.getAddress ();
+	if (idleProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+}
+
+void initializeSystemSettings () {
+	styleSetCallback = new Callback (this, "styleSetProc", 3);
+	styleSetProc = styleSetCallback.getAddress ();
+	if (styleSetProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+	OS.g_signal_connect (shellHandle, OS.style_set, styleSetProc, 0);
+
+	/*
+	* Feature in GTK.  Despite the fact that the
+	* gtk-entry-select-on-focus property is a global
+	* setting, it is initialized when the GtkEntry
+	* is initialized.  This means that it cannot be
+	* accessed before a GtkEntry is created.  The
+	* fix is to for the initializaion by creating
+	* a temporary GtkEntry.
+	*/
+	int /*long*/ entry = OS.gtk_entry_new ();
+	OS.gtk_widget_destroy (entry);
+	int [] buffer2 = new int [1];
+	int /*long*/ settings = OS.gtk_settings_get_default ();
+	OS.g_object_get (settings, OS.gtk_entry_select_on_focus, buffer2, 0);
+	entrySelectOnFocus = buffer2 [0] != 0;
+}
+
+void initializeWidgetTable () {
+	indexTable = new int [GROW_SIZE];
+	widgetTable = new Widget [GROW_SIZE];
+	for (int i=0; i<GROW_SIZE-1; i++) indexTable [i] = i + 1;
+	indexTable [GROW_SIZE - 1] = -1;
+}
+
+void initializeWindowManager () {
+	/* Get the window manager name */
+	windowManager = "";
+	if (OS.GTK_VERSION >= OS.VERSION (2, 2, 0)) {
+		int /*long*/ screen = OS.gdk_screen_get_default ();
+		if (screen != 0) {
+			int /*long*/ ptr2 = OS.gdk_x11_screen_get_window_manager_name (screen);
+			if (ptr2 != 0) {
+				int length = OS.strlen (ptr2);
+				if (length > 0) {
+					byte [] buffer2 = new byte [length];
+					OS.memmove (buffer2, ptr2, length);
+					windowManager = new String (Converter.mbcsToWcs (null, buffer2));
+				}
+			}
+		}
+	}
+}
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Display</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public void internal_dispose_GC (int /*long*/ gdkGC, GCData data) {
+	OS.g_object_unref (gdkGC);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Display</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for gc creation</li>
+ * </ul>
+ */
+public int /*long*/ internal_new_GC (GCData data) {
+	if (isDisposed()) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+	int /*long*/ root = OS.GDK_ROOT_PARENT ();
+	int /*long*/ gdkGC = OS.gdk_gc_new (root);
+	if (gdkGC == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+	OS.gdk_gc_set_subwindow (gdkGC, OS.GDK_INCLUDE_INFERIORS);
+	if (data != null) {
+		int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+		if ((data.style & mask) == 0) {
+			data.style |= SWT.LEFT_TO_RIGHT;
+		}
+		data.device = this;
+		data.drawable = root;
+		data.background = getSystemColor (SWT.COLOR_WHITE).handle;
+		data.foreground = getSystemColor (SWT.COLOR_BLACK).handle;
+		data.font = getSystemFont ().handle;
+	}
+	return gdkGC;
+}
+
+boolean isValidThread () {
+	return thread == Thread.currentThread ();
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle.  When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction.  Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param point to be mapped
+ * @return point with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.1.2
+ */
+public Point map (Control from, Control to, Point point) {
+	checkDevice ();
+	if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+	return map (from, to, point.x, point.y);
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle.  When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction.  Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param x coordinates to be mapped
+ * @param y coordinates to be mapped
+ * @return point with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.1.2
+ */
+public Point map (Control from, Control to, int x, int y) {
+	checkDevice ();
+	if (from != null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+	if (to != null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+	Point point = new Point (x, y);
+	if (from == to) return point;
+	if (from != null) {
+		int /*long*/ window = from.eventWindow ();
+		int [] origin_x = new int [1], origin_y = new int [1];
+		OS.gdk_window_get_origin (window, origin_x, origin_y);
+		point.x += origin_x [0];
+		point.y += origin_y [0];
+	}
+	if (to != null) {
+		int /*long*/ window = to.eventWindow ();
+		int [] origin_x = new int [1], origin_y = new int [1];
+		OS.gdk_window_get_origin (window, origin_x, origin_y);
+		point.x -= origin_x [0];
+		point.y -= origin_y [0];
+	}
+	return point;
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle.  When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction.  Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param rectangle to be mapped
+ * @return rectangle with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.1.2
+ */
+public Rectangle map (Control from, Control to, Rectangle rectangle) {
+	checkDevice();
+	if (rectangle == null) error (SWT.ERROR_NULL_ARGUMENT);
+	return map (from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+}
+
+static char mbcsToWcs (char ch) {
+	int key = ch & 0xFFFF;
+	if (key <= 0x7F) return ch;
+	byte [] buffer;
+	if (key <= 0xFF) {
+		buffer = new byte [1];
+		buffer [0] = (byte) key;
+	} else {
+		buffer = new byte [2];
+		buffer [0] = (byte) ((key >> 8) & 0xFF);
+		buffer [1] = (byte) (key & 0xFF);
+	}
+	char [] result = Converter.mbcsToWcs (null, buffer);
+	if (result.length == 0) return 0;
+	return result [0];
+}
+
+int /*long*/ menuPositionProc (int /*long*/ menu, int /*long*/ x, int /*long*/ y, int /*long*/ push_in, int /*long*/ user_data) {
+	Widget widget = getWidget (menu);
+	if (widget == null) return 0;
+	return widget.menuPositionProc (menu, x, y, push_in, user_data);
+}
+
+/**
+ * Maps a point from one coordinate system to another.
+ * When the control is null, coordinates are mapped to
+ * the display.
+ * <p>
+ * NOTE: On right-to-left platforms where the coordinate
+ * systems are mirrored, special care needs to be taken
+ * when mapping coordinates from one control to another
+ * to ensure the result is correctly mirrored.
+ *
+ * Mapping a point that is the origin of a rectangle and
+ * then adding the width and height is not equivalent to
+ * mapping the rectangle.  When one control is mirrored
+ * and the other is not, adding the width and height to a
+ * point that was mapped causes the rectangle to extend
+ * in the wrong direction.  Mapping the entire rectangle
+ * instead of just one point causes both the origin and
+ * the corner of the rectangle to be mapped.
+ * </p>
+ *
+ * @param from the source <code>Control</code> or <code>null</code>
+ * @param to the destination <code>Control</code> or <code>null</code>
+ * @param x coordinates to be mapped
+ * @param y coordinates to be mapped
+ * @param width coordinates to be mapped
+ * @param height coordinates to be mapped
+ * @return rectangle with mapped coordinates
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed</li>
+ * </ul>
+ * @exception SWTException <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 2.1.2
+ */
+public Rectangle map (Control from, Control to, int x, int y, int width, int height) {
+	checkDevice();
+	if (from != null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+	if (to != null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
+	Rectangle rect = new Rectangle (x, y, width, height);
+	if (from == to) return rect;
+	if (from != null) {
+		int /*long*/ window = from.eventWindow ();
+		int [] origin_x = new int [1], origin_y = new int [1];
+		OS.gdk_window_get_origin (window, origin_x, origin_y);
+		rect.x += origin_x [0];
+		rect.y += origin_y [0];
+	}
+	if (to != null) {
+		int /*long*/ window = to.eventWindow ();
+		int [] origin_x = new int [1], origin_y = new int [1];
+		OS.gdk_window_get_origin (window, origin_x, origin_y);
+		rect.x -= origin_x [0];
+		rect.y -= origin_y [0];
+	}
+	return rect;
+}
+
+int /*long*/ mouseHoverProc (int /*long*/ handle) {
+	Widget widget = getWidget (handle);
+	if (widget == null) return 0;
+	return widget.hoverProc (handle);
+}
+
+/**
+ * Generate a low level system event.
+ *
+ * <code>post</code> is used to generate low level keyboard
+ * and mouse events. The intent is to enable automated UI
+ * testing by simulating the input from the user.  Most
+ * SWT applications should never need to call this method.
+ * <p>
+ * Note that this operation can fail when the operating system
+ * fails to generate the event for any reason.  For example,
+ * this can happen when there is no such key or mouse button
+ * or when the system event queue is full.
+ * </p>
+ * <p>
+ * <b>Event Types:</b>
+ * <p>KeyDown, KeyUp
+ * <p>The following fields in the <code>Event</code> apply:
+ * <ul>
+ * <li>(in) type KeyDown or KeyUp</li>
+ * <p> Either one of:
+ * <li>(in) character a character that corresponds to a keyboard key</li>
+ * <li>(in) keyCode the key code of the key that was typed,
+ *          as defined by the key code constants in class <code>SWT</code></li>
+ * </ul>
+ * <p>MouseDown, MouseUp</p>
+ * <p>The following fields in the <code>Event</code> apply:
+ * <ul>
+ * <li>(in) type MouseDown or MouseUp
+ * <li>(in) button the button that is pressed or released
+ * </ul>
+ * <p>MouseMove</p>
+ * <p>The following fields in the <code>Event</code> apply:
+ * <ul>
+ * <li>(in) type MouseMove
+ * <li>(in) x the x coordinate to move the mouse pointer to in screen coordinates
+ * <li>(in) y the y coordinate to move the mouse pointer to in screen coordinates
+ * </ul>
+ * </dl>
+ *
+ * @param event the event to be generated
+ *
+ * @return true if the event was generated or false otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the event is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ *
+ */
+public boolean post (Event event) {
+	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+	if (event == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (!OS.GDK_WINDOWING_X11()) return false;
+	int /*long*/ xDisplay = OS.GDK_DISPLAY ();
+	int type = event.type;
+	switch (type) {
+		case SWT.KeyDown:
+		case SWT.KeyUp: {
+			int keyCode = 0;
+			int /*long*/ keysym = untranslateKey (event.keyCode);
+			if (keysym != 0) keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
+			if (keyCode == 0) {
+				char key = event.character;
+				switch (key) {
+					case SWT.BS: keysym = OS.GDK_BackSpace; break;
+					case SWT.CR: keysym = OS.GDK_Return; break;
+					case SWT.DEL: keysym = OS.GDK_Delete; break;
+					case SWT.ESC: keysym = OS.GDK_Escape; break;
+					case SWT.TAB: keysym = OS.GDK_Tab; break;
+					case SWT.LF: keysym = OS.GDK_Linefeed; break;
+					default:
+						keysym = wcsToMbcs (key);
+				}
+				keyCode = OS.XKeysymToKeycode (xDisplay, keysym);
+				if (keyCode == 0) return false;
+			}
+			OS.XTestFakeKeyEvent (xDisplay, keyCode, type == SWT.KeyDown, 0);
+			return true;
+		}
+		case SWT.MouseDown:
+		case SWT.MouseMove:
+		case SWT.MouseUp: {
+			if (type == SWT.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 == SWT.MouseDown, 0);
+			}
+			return true;
+		}
+		/*
+		* This code is intentionally commented. After posting a
+		* mouse wheel event the system may respond unpredictably
+		* to subsequent mouse actions.
+		*/
+//		case SWT.MouseWheel: {
+//			if (event.count == 0) return false;
+//			int button = event.count < 0 ? 5 : 4;
+//			OS.XTestFakeButtonEvent (xDisplay, button, type == SWT.MouseWheel, 0);
+//		}
+	}
+	return false;
+}
+
+void postEvent (Event event) {
+	/*
+	* Place the event at the end of the event queue.
+	* This code is always called in the Display's
+	* thread so it must be re-enterant but does not
+	* need to be synchronized.
+	*/
+	if (eventQueue == null) eventQueue = new Event [4];
+	int index = 0;
+	int length = eventQueue.length;
+	while (index < length) {
+		if (eventQueue [index] == null) break;
+		index++;
+	}
+	if (index == length) {
+		Event [] newQueue = new Event [length + 4];
+		System.arraycopy (eventQueue, 0, newQueue, 0, length);
+		eventQueue = newQueue;
+	}
+	eventQueue [index] = event;
+}
+
+void putGdkEvents () {
+	if (gdkEventCount != 0) {
+		for (int i = 0; i < gdkEventCount; i++) {
+			int /*long*/ event = gdkEvents [i];
+			Widget widget = gdkEventWidgets [i];
+			if (widget == null || !widget.isDisposed ()) {
+				OS.gdk_event_put (event);
+			}
+			OS.gdk_event_free (event);
+			gdkEvents [i] = 0;
+			gdkEventWidgets [i] = null;
+		}
+		gdkEventCount = 0;
+	}
+}
+
+/**
+ * Reads an event from the operating system's event queue,
+ * dispatches it appropriately, and returns <code>true</code>
+ * if there is potentially more work to do, or <code>false</code>
+ * if the caller can sleep until another event is placed on
+ * the event queue.
+ * <p>
+ * In addition to checking the system event queue, this method also
+ * checks if any inter-thread messages (created by <code>syncExec()</code>
+ * or <code>asyncExec()</code>) are waiting to be processed, and if
+ * so handles them before returning.
+ * </p>
+ *
+ * @return <code>false</code> if the caller can sleep upon return from this method
+ *
+ * @exception SWTException <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>
+ *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
+ * </ul>
+ *
+ * @see #sleep
+ * @see #wake
+ */
+public boolean readAndDispatch () {
+	checkDevice ();
+	boolean events = false;
+	events |= runSettings ();
+	events |= runPopups ();
+	events |= OS.g_main_context_iteration (0, false);
+	if (events) {
+		runDeferredEvents ();
+		return true;
+	}
+	return runAsyncMessages (false);
+}
+
+synchronized void register () {
+	for (int i=0; i<Displays.length; i++) {
+		if (Displays [i] == null) {
+			Displays [i] = this;
+			return;
+		}
+	}
+	Display [] newDisplays = new Display [Displays.length + 4];
+	System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
+	newDisplays [Displays.length] = this;
+	Displays = newDisplays;
+}
+
+/**
+ * Releases any internal resources back to the operating
+ * system and clears all fields except the device handle.
+ * <p>
+ * Disposes all shells which are currently open on the display.
+ * After this method has been invoked, all related related shells
+ * will answer <code>true</code> when sent the message
+ * <code>isDisposed()</code>.
+ * </p><p>
+ * When a device is destroyed, resources that were acquired
+ * on behalf of the programmer need to be returned to the
+ * operating system.  For example, if the device allocated a
+ * font to be used as the system font, this font would be
+ * freed in <code>release</code>.  Also,to assist the garbage
+ * collector and minimize the amount of memory that is not
+ * reclaimed when the programmer keeps a reference to a
+ * disposed device, all fields except the handle are zero'd.
+ * The handle is needed by <code>destroy</code>.
+ * </p>
+ * This method is called before <code>destroy</code>.
+ *
+ * @see Device#dispose
+ * @see #destroy
+ */
+protected void release () {
+	sendEvent (SWT.Dispose, new Event ());
+	Shell [] shells = getShells ();
+	for (int i=0; i<shells.length; i++) {
+		Shell shell = shells [i];
+		if (!shell.isDisposed ())  shell.dispose ();
+	}
+	if (tray != null) tray.dispose ();
+	tray = null;
+	while (readAndDispatch ()) {}
+	if (disposeList != null) {
+		for (int i=0; i<disposeList.length; i++) {
+			if (disposeList [i] != null) disposeList [i].run ();
+		}
+	}
+	disposeList = null;
+	synchronizer.releaseSynchronizer ();
+	synchronizer = null;
+	releaseDisplay ();
+	super.release ();
+}
+
+void releaseDisplay () {
+	windowCallback2.dispose ();  windowCallback2 = null;
+	windowCallback3.dispose ();  windowCallback3 = null;
+	windowCallback4.dispose ();  windowCallback4 = null;
+	windowCallback5.dispose ();  windowCallback5 = null;
+	windowProc2 = windowProc3 = windowProc4 = windowProc5 = 0;
+
+	/* Dispose xfilter callback */
+	filterCallback.dispose(); filterCallback = null;
+	filterProc = 0;
+
+	/* Dispose checkIfEvent callback */
+	checkIfEventCallback.dispose(); checkIfEventCallback = null;
+	checkIfEventProc = 0;
+
+	/* Dispose preedit window */
+	if (preeditWindow != 0) OS.gtk_widget_destroy (preeditWindow);
+	imControl = null;
+
+	/* Dispose the menu callback */
+	menuPositionCallback.dispose (); menuPositionCallback = null;
+	menuPositionProc = 0;
+
+	/* Dispose the tooltip map callback */
+	sizeAllocateCallback.dispose (); sizeAllocateCallback = null;
+	sizeAllocateProc = 0;
+	sizeRequestCallback.dispose (); sizeRequestCallback = null;
+	sizeRequestProc = 0;
+
+	/* Dispose the shell map callback */
+	shellMapCallback.dispose (); shellMapCallback = null;
+	shellMapProc = 0;
+
+	/* Dispose the run async messages callback */
+	idleCallback.dispose (); idleCallback = null;
+	idleProc = 0;
+	if (idleHandle != 0) OS.g_source_remove (idleHandle);
+	idleHandle = 0;
+
+	/* Dispose GtkTreeView callbacks */
+	treeSelectionCallback.dispose (); treeSelectionCallback = null;
+	treeSelectionProc = 0;
+	cellDataCallback.dispose (); cellDataCallback = null;
+	cellDataProc = 0;
+
+	/* Dispose the set direction callback */
+	setDirectionCallback.dispose (); setDirectionCallback = null;
+	setDirectionProc = 0;
+
+	/* Dispose the set direction callback */
+	allChildrenCallback.dispose (); allChildrenCallback = null;
+	allChildrenProc = 0;
+
+	/* Dispose the caret callback */
+	if (caretId != 0) OS.gtk_timeout_remove (caretId);
+	caretId = 0;
+	caretProc = 0;
+	caretCallback.dispose ();
+	caretCallback = null;
+
+	/* Release closures */
+	for (int i = 0; i < Widget.LAST_SIGNAL; i++) {
+		if (closures [i] != 0) OS.g_closure_unref (closures [i]);
+	}
+	if (shellMapProcClosure != 0) OS.g_closure_unref (shellMapProcClosure);
+
+	/* Dispose the timer callback */
+	if (timerIds != null) {
+		for (int i=0; i<timerIds.length; i++) {
+			if (timerIds [i] != 0) OS.gtk_timeout_remove (timerIds [i]);
+		}
+	}
+	timerIds = null;
+	timerList = null;
+	timerProc = 0;
+	timerCallback.dispose ();
+	timerCallback = null;
+	windowTimerProc = 0;
+	windowTimerCallback.dispose ();
+	windowTimerCallback = null;
+
+	/* Dispose mouse hover callback */
+	if (mouseHoverId != 0) OS.gtk_timeout_remove (mouseHoverId);
+	mouseHoverId = 0;
+	mouseHoverHandle = mouseHoverProc = 0;
+	mouseHoverCallback.dispose ();
+	mouseHoverCallback = null;
+
+	/* Dispose the default font */
+	if (systemFont != null) systemFont.dispose ();
+	systemFont = null;
+
+	/* Dispose the System Images */
+	if (errorImage != null) errorImage.dispose();
+	if (infoImage != null) infoImage.dispose();
+	if (questionImage != null) questionImage.dispose();
+	if (warningImage != null) warningImage.dispose();
+	errorImage = infoImage = questionImage = warningImage = null;
+
+	/* Release the System Cursors */
+	for (int i = 0; i < cursors.length; i++) {
+		if (cursors [i] != null) cursors [i].dispose ();
+	}
+	cursors = null;
+
+	/* Release Acquired Resources */
+	if (resources != null) {
+		for (int i=0; i<resources.length; i++) {
+			if (resources [i] != null) resources [i].dispose ();
+		}
+		resources = null;
+	}
+
+	/* Release the System Colors */
+	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_INFO_BACKGROUND = COLOR_INFO_FOREGROUND = null;
+
+	/* Dispose the event callback */
+	OS.gdk_event_handler_set (0, 0, 0);
+	eventCallback.dispose ();  eventCallback = null;
+
+	/* Dispose the hidden shell */
+	if (shellHandle != 0) OS.gtk_widget_destroy (shellHandle);
+	shellHandle = 0;
+
+	/* Dispose the settings callback */
+	styleSetCallback.dispose(); styleSetCallback = null;
+	styleSetProc = 0;
+
+	/* Release the sleep resources */
+	max_priority = timeout = null;
+	if (fds != 0) OS.g_free (fds);
+	fds = 0;
+
+	/* Release references */
+	popups = null;
+	thread = null;
+	activeShell = null;
+	lastWidget = null;
+	indexTable = null;
+	widgetTable = null;
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when an event of the given type occurs anywhere in
+ * a widget. The event type is one of the event constants defined
+ * in class <code>SWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should no longer be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #addFilter
+ * @see #addListener
+ *
+ * @since 3.0
+ */
+public void removeFilter (int eventType, Listener listener) {
+	checkDevice ();
+	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (filterTable == null) return;
+	filterTable.unhook (eventType, listener);
+	if (filterTable.size () == 0) filterTable = null;
+}
+
+int /*long*/ removeGdkEvent () {
+	if (gdkEventCount == 0) return 0;
+	int /*long*/ event = gdkEvents [0];
+	--gdkEventCount;
+	System.arraycopy (gdkEvents, 1, gdkEvents, 0, gdkEventCount);
+	System.arraycopy (gdkEventWidgets, 1, gdkEventWidgets, 0, gdkEventCount);
+	gdkEvents [gdkEventCount] = 0;
+	gdkEventWidgets [gdkEventCount] = null;
+	if (gdkEventCount == 0) {
+		gdkEvents = null;
+		gdkEventWidgets = null;
+	}
+	return event;
+}
+
+void removeIdleProc () {
+	synchronized(idleLock) {
+		if (idleHandle != 0) OS.g_source_remove (idleHandle);
+		idleNeeded = false;
+		idleHandle = 0;
+	}
+}
+/**
+ * Removes the listener from the collection 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>SWT</code>.
+ *
+ * @param eventType the type of event to listen for
+ * @param listener the listener which should no longer be notified when the event occurs
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ *
+ * @see Listener
+ * @see SWT
+ * @see #addListener
+ *
+ * @since 2.0
+ */
+public void removeListener (int eventType, Listener listener) {
+	checkDevice ();
+	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (eventTable == null) return;
+	eventTable.unhook (eventType, listener);
+}
+
+void removeMouseHoverTimeout (int /*long*/ handle) {
+	if (handle != mouseHoverHandle) return;
+	if (mouseHoverId != 0) OS.gtk_timeout_remove (mouseHoverId);
+	mouseHoverId = 0;
+	mouseHoverHandle = 0;
+}
+
+void removePopup (Menu menu) {
+	if (popups == null) return;
+	for (int i=0; i<popups.length; i++) {
+		if (popups [i] == menu) {
+			popups [i] = null;
+			return;
+		}
+	}
+}
+
+Widget removeWidget (int /*long*/ handle) {
+	if (handle == 0) return null;
+	lastWidget = null;
+	Widget widget = null;
+	int index = (int)/*64*/ OS.g_object_get_qdata (handle, SWT_OBJECT_INDEX) - 1;
+	if (0 <= index && index < widgetTable.length) {
+		widget = widgetTable [index];
+		widgetTable [index] = null;
+		indexTable [index] = freeSlot;
+		freeSlot = index;
+		OS.g_object_set_qdata (handle, SWT_OBJECT_INDEX, 0);
+	}
+	return widget;
+}
+
+boolean runAsyncMessages (boolean all) {
+	return synchronizer.runAsyncMessages (all);
+}
+
+boolean runDeferredEvents () {
+	/*
+	* Run deferred events.  This code is always
+	* called in the Display's thread so it must
+	* be re-enterant but need not be synchronized.
+	*/
+	while (eventQueue != null) {
+
+		/* Take an event off the queue */
+		Event event = eventQueue [0];
+		if (event == null) break;
+		int length = eventQueue.length;
+		System.arraycopy (eventQueue, 1, eventQueue, 0, --length);
+		eventQueue [length] = null;
+
+		/* Run the event */
+		Widget widget = event.widget;
+		if (widget != null && !widget.isDisposed ()) {
+			Widget item = event.item;
+			if (item == null || !item.isDisposed ()) {
+				widget.sendEvent (event);
+			}
+		}
+
+		/*
+		* At this point, the event queue could
+		* be null due to a recursive invokation
+		* when running the event.
+		*/
+	}
+
+	/* Clear the queue */
+	eventQueue = null;
+	return true;
+}
+
+boolean runPopups () {
+	if (popups == null) return false;
+	boolean result = false;
+	while (popups != null) {
+		Menu menu = popups [0];
+		if (menu == null) break;
+		int length = popups.length;
+		System.arraycopy (popups, 1, popups, 0, --length);
+		popups [length] = null;
+		runDeferredEvents ();
+		if (!menu.isDisposed ()) menu._setVisible (true);
+		result = true;
+	}
+	popups = null;
+	return result;
+}
+
+boolean runSettings () {
+	if (!runSettings) return false;
+	runSettings = false;
+	saveResources ();
+	initializeSystemColors ();
+	sendEvent (SWT.Settings, null);
+	Shell [] shells = getShells ();
+	for (int i=0; i<shells.length; i++) {
+		Shell shell = shells [i];
+		if (!shell.isDisposed ()) {
+			shell.fixStyle ();
+			shell.redraw (true);
+			shell.layout (true, true);
+		}
+	}
+	return true;
+}
+
+/**
+ * On platforms which support it, sets the application name
+ * to be the argument. On Motif, for example, this can be used
+ * to set the name used for resource lookup.  Specifying
+ * <code>null</code> for the name clears it.
+ *
+ * @param name the new app name or <code>null</code>
+ */
+public static void setAppName (String name) {
+	APP_NAME = name;
+}
+
+/**
+ * Sets the location of the on-screen pointer relative to the top left corner
+ * of the screen.  <b>Note: It is typically considered bad practice for a
+ * program to move the on-screen pointer location.</b>
+ *
+ * @param x the new x coordinate for the cursor
+ * @param y the new y coordinate for the cursor
+ *
+ * @exception SWTException <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 2.1
+ */
+public void setCursorLocation (int x, int y) {
+	checkDevice ();
+	if (OS.GDK_WINDOWING_X11 ()) {
+		int /*long*/ xDisplay = OS.GDK_DISPLAY ();
+		int /*long*/ xWindow = OS.XDefaultRootWindow (xDisplay);
+		OS.XWarpPointer (xDisplay, OS.None, xWindow, 0, 0, 0, 0, x, y);
+	}
+}
+
+/**
+ * Sets the location of the on-screen pointer relative to the top left corner
+ * of the screen.  <b>Note: It is typically considered bad practice for a
+ * program to move the on-screen pointer location.</b>
+ *
+ * @param point new position
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_NULL_ARGUMENT - if the point is null
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.0
+ */
+public void setCursorLocation (Point point) {
+	checkDevice ();
+	if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
+	setCursorLocation (point.x, point.y);
+}
+
+/**
+ * Sets the application defined property of the receiver
+ * with the specified name to the given argument.
+ * <p>
+ * Applications may have associated arbitrary objects with the
+ * receiver in this fashion. If the objects stored in the
+ * properties need to be notified when the display is disposed
+ * of, it is the application's responsibility provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @param key the name of the property
+ * @param value the new value for the property
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the key is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ *
+ * @see #getData(String)
+ * @see #disposeExec(Runnable)
+ */
+public void setData (String key, Object value) {
+	checkDevice ();
+	if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
+
+	if (key.equals (DISPATCH_EVENT_KEY)) {
+		if (value == null || value instanceof int []) {
+			dispatchEvents = (int []) value;
+			if (value == null) putGdkEvents ();
+			return;
+		}
+	}
+
+	if (key.equals (ADD_WIDGET_KEY)) {
+		Object [] data = (Object []) value;
+		int /*long*/ handle = ((LONG) data [0]).value;
+		Widget widget = (Widget) data [1];
+		if (widget != null) {
+			addWidget (handle, widget);
+		} else {
+			removeWidget (handle);
+		}
+	}
+
+	if (key.equals (ADD_IDLE_PROC_KEY)) {
+		addIdleProc ();
+		return;
+	}
+	if (key.equals (REMOVE_IDLE_PROC_KEY)) {
+		removeIdleProc ();
+		return;
+	}
+
+	/* Remove the key/value pair */
+	if (value == null) {
+		if (keys == null) return;
+		int index = 0;
+		while (index < keys.length && !keys [index].equals (key)) index++;
+		if (index == keys.length) return;
+		if (keys.length == 1) {
+			keys = null;
+			values = null;
+		} else {
+			String [] newKeys = new String [keys.length - 1];
+			Object [] newValues = new Object [values.length - 1];
+			System.arraycopy (keys, 0, newKeys, 0, index);
+			System.arraycopy (keys, index + 1, newKeys, index, newKeys.length - index);
+			System.arraycopy (values, 0, newValues, 0, index);
+			System.arraycopy (values, index + 1, newValues, index, newValues.length - index);
+			keys = newKeys;
+			values = newValues;
+		}
+		return;
+	}
+
+	/* Add the key/value pair */
+	if (keys == null) {
+		keys = new String [] {key};
+		values = new Object [] {value};
+		return;
+	}
+	for (int i=0; i<keys.length; i++) {
+		if (keys [i].equals (key)) {
+			values [i] = value;
+			return;
+		}
+	}
+	String [] newKeys = new String [keys.length + 1];
+	Object [] newValues = new Object [values.length + 1];
+	System.arraycopy (keys, 0, newKeys, 0, keys.length);
+	System.arraycopy (values, 0, newValues, 0, values.length);
+	newKeys [keys.length] = key;
+	newValues [values.length] = value;
+	keys = newKeys;
+	values = newValues;
+}
+
+/**
+ * Sets the application defined, display specific data
+ * associated with the receiver, to the argument.
+ * The <em>display specific data</em> is a single,
+ * unnamed field that is stored with every display.
+ * <p>
+ * Applications may put arbitrary objects in this field. If
+ * the object stored in the display specific data needs to
+ * be notified when the display is disposed of, it is the
+ * application's responsibility provide a
+ * <code>disposeExec()</code> handler which does so.
+ * </p>
+ *
+ * @param data the new display specific data
+ *
+ * @exception SWTException <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>
+ *
+ * @see #getData()
+ * @see #disposeExec(Runnable)
+ */
+public void setData (Object data) {
+	checkDevice ();
+	this.data = data;
+}
+
+int /*long*/ setDirectionProc (int /*long*/ widget, int /*long*/ direction) {
+	OS.gtk_widget_set_direction (widget, (int)/*64*/ direction);
+	if (OS.GTK_IS_CONTAINER (widget)) {
+		OS.gtk_container_forall (widget, setDirectionProc, direction);
+	}
+	return 0;
+}
+
+/**
+ * Sets the synchronizer used by the display to be
+ * the argument, which can not be null.
+ *
+ * @param synchronizer the new synchronizer for the display (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the synchronizer is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ *    <li>ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message</li>
+ * </ul>
+ */
+public void setSynchronizer (Synchronizer synchronizer) {
+	checkDevice ();
+	if (synchronizer == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (this.synchronizer != null) {
+		this.synchronizer.runAsyncMessages(true);
+	}
+	this.synchronizer = synchronizer;
+}
+
+void showIMWindow (Control control) {
+	imControl = control;
+	if (preeditWindow == 0) {
+		preeditWindow = OS.gtk_window_new (OS.GTK_WINDOW_POPUP);
+		if (preeditWindow == 0) error (SWT.ERROR_NO_HANDLES);
+		preeditLabel = OS.gtk_label_new (null);
+		if (preeditLabel == 0) error (SWT.ERROR_NO_HANDLES);
+		OS.gtk_container_add (preeditWindow, preeditLabel);
+		OS.gtk_widget_show (preeditLabel);
+	}
+	int /*long*/ [] preeditString = new int /*long*/ [1];
+	int /*long*/ [] pangoAttrs = new int /*long*/ [1];
+	int /*long*/ imHandle = control.imHandle ();
+	OS.gtk_im_context_get_preedit_string (imHandle, preeditString, pangoAttrs, null);
+	if (preeditString [0] != 0 && OS.strlen (preeditString [0]) > 0) {
+		Control widget = control.findBackgroundControl ();
+		if (widget == null) widget = control;
+		OS.gtk_widget_modify_bg (preeditWindow,  OS.GTK_STATE_NORMAL, widget.getBackgroundColor ());
+		widget.setForegroundColor (preeditLabel, control.getForegroundColor());
+		OS.gtk_widget_modify_font (preeditLabel, control.getFontDescription ());
+		if (pangoAttrs [0] != 0) OS.gtk_label_set_attributes (preeditLabel, pangoAttrs[0]);
+		OS.gtk_label_set_text (preeditLabel, preeditString [0]);
+		Point point = control.toDisplay (control.getIMCaretPos ());
+		OS.gtk_window_move (preeditWindow, point.x, point.y);
+		GtkRequisition requisition = new GtkRequisition ();
+		OS.gtk_widget_size_request (preeditLabel, requisition);
+		OS.gtk_window_resize (preeditWindow, requisition.width, requisition.height);
+		OS.gtk_widget_show (preeditWindow);
+	} else {
+		OS.gtk_widget_hide (preeditWindow);
+	}
+	if (preeditString [0] != 0) OS.g_free (preeditString [0]);
+	if (pangoAttrs [0] != 0) OS.pango_attr_list_unref (pangoAttrs [0]);
+}
+
+/**
+ * Causes the user-interface thread to <em>sleep</em> (that is,
+ * to be put in a state where it does not consume CPU cycles)
+ * until an event is received or it is otherwise awakened.
+ *
+ * @return <code>true</code> if an event requiring dispatching was placed on the queue.
+ *
+ * @exception SWTException <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>
+ *
+ * @see #wake
+ */
+public boolean sleep () {
+	checkDevice ();
+	if (gdkEventCount == 0) {
+		gdkEvents = null;
+		gdkEventWidgets = null;
+	}
+	if (settingsChanged) {
+		settingsChanged = false;
+		runSettings = true;
+		return false;
+	}
+	if (getMessageCount () != 0) return true;
+	if (fds == 0) {
+		allocated_nfds = 2;
+		fds = OS.g_malloc (OS.GPollFD_sizeof () * allocated_nfds);
+	}
+	max_priority [0] = timeout [0] = 0;
+	int /*long*/ context = OS.g_main_context_default ();
+	boolean result = false;
+	do {
+		if (OS.g_main_context_acquire (context)) {
+			result = OS.g_main_context_prepare (context, max_priority);
+			int nfds;
+			while ((nfds = OS.g_main_context_query (context, max_priority [0], timeout, fds, allocated_nfds)) > allocated_nfds) {
+				OS.g_free (fds);
+				allocated_nfds = nfds;
+				fds = OS.g_malloc (OS.GPollFD_sizeof() * allocated_nfds);
+			}
+			int /*long*/ poll = OS.g_main_context_get_poll_func (context);
+			if (poll != 0) {
+				if (nfds > 0 || timeout [0] != 0) {
+					/*
+					* Bug in GTK. For some reason, g_main_context_wakeup() may
+					* fail to wake up the UI thread from the polling function.
+					* The fix is to sleep for a maximum of 50 milliseconds.
+					*/
+					if (timeout [0] < 0) timeout [0] = 50;
+
+					/* Exit the OS lock to allow other threads to enter GTK */
+					Lock lock = OS.lock;
+					int count = lock.lock ();
+					for (int i = 0; i < count; i++) lock.unlock ();
+					try {
+						wake = false;
+						OS.Call (poll, fds, nfds, timeout [0]);
+					} finally {
+						for (int i = 0; i < count; i++) lock.lock ();
+						lock.unlock ();
+					}
+				}
+			}
+			OS.g_main_context_check (context, max_priority [0], fds, nfds);
+			OS.g_main_context_release (context);
+		}
+	} while (!result && getMessageCount () == 0 && !wake);
+	wake = false;
+	return true;
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread after the specified
+ * number of milliseconds have elapsed. If milliseconds is less
+ * than zero, the runnable is not executed.
+ * <p>
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ * </p>
+ *
+ * @param milliseconds the delay before running the runnable
+ * @param runnable code to run on the user-interface thread
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
+ * </ul>
+ * @exception SWTException <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>
+ *
+ * @see #asyncExec
+ */
+public void timerExec (int milliseconds, Runnable runnable) {
+	checkDevice ();
+	if (runnable == null) error (SWT.ERROR_NULL_ARGUMENT);
+	if (timerList == null) timerList = new Runnable [4];
+	if (timerIds == null) timerIds = new int [4];
+	int index = 0;
+	while (index < timerList.length) {
+		if (timerList [index] == runnable) break;
+		index++;
+	}
+	if (index != timerList.length) {
+		OS.gtk_timeout_remove (timerIds [index]);
+		timerList [index] = null;
+		timerIds [index] = 0;
+		if (milliseconds < 0) return;
+	} else {
+		if (milliseconds < 0) return;
+		index = 0;
+		while (index < timerList.length) {
+			if (timerList [index] == null) break;
+			index++;
+		}
+		if (index == timerList.length) {
+			Runnable [] newTimerList = new Runnable [timerList.length + 4];
+			System.arraycopy (timerList, 0, newTimerList, 0, timerList.length);
+			timerList = newTimerList;
+			int [] newTimerIds = new int [timerIds.length + 4];
+			System.arraycopy (timerIds, 0, newTimerIds, 0, timerIds.length);
+			timerIds = newTimerIds;
+		}
+	}
+	int timerId = OS.gtk_timeout_add (milliseconds, timerProc, index);
+	if (timerId != 0) {
+		timerIds [index] = timerId;
+		timerList [index] = runnable;
+	}
+}
+
+int /*long*/ timerProc (int /*long*/ i) {
+	if (timerList == null) return 0;
+	int index = (int)/*64*/i;
+	if (0 <= index && index < timerList.length) {
+		Runnable runnable = timerList [index];
+		timerList [index] = null;
+		timerIds [index] = 0;
+		if (runnable != null) runnable.run ();
+	}
+	return 0;
+}
+
+int /*long*/ caretProc (int /*long*/ clientData) {
+	caretId = 0;
+	if (currentCaret == null) {
+		return 0;
+	}
+	if (currentCaret.blinkCaret()) {
+		int blinkRate = currentCaret.blinkRate;
+		if (blinkRate == 0) return 0;
+		caretId = OS.gtk_timeout_add (blinkRate, caretProc, 0);
+	} else {
+		currentCaret = null;
+	}
+	return 0;
+}
+
+int /*long*/ sizeAllocateProc (int /*long*/ handle, int /*long*/ arg0, int /*long*/ user_data) {
+	Widget widget = getWidget (user_data);
+	if (widget == null) return 0;
+	return widget.sizeAllocateProc (handle, arg0, user_data);
+}
+
+int /*long*/ sizeRequestProc (int /*long*/ handle, int /*long*/ arg0, int /*long*/ user_data) {
+	Widget widget = getWidget (user_data);
+	if (widget == null) return 0;
+	return widget.sizeRequestProc (handle, arg0, user_data);
+}
+
+int /*long*/ treeSelectionProc (int /*long*/ model, int /*long*/ path, int /*long*/ iter, int /*long*/ data) {
+	Widget widget = getWidget (data);
+	if (widget == null) return 0;
+	return widget.treeSelectionProc (model, path, iter, treeSelection, treeSelectionLength++);
+}
+
+void saveResources () {
+	int resourceCount = 0;
+	if (resources == null) {
+		resources = new Resource [RESOURCE_SIZE];
+	} else {
+		resourceCount = resources.length;
+		Resource [] newResources = new Resource [resourceCount + RESOURCE_SIZE];
+		System.arraycopy (resources, 0, newResources, 0, resourceCount);
+		resources = newResources;
+	}
+	if (systemFont != null) {
+		resources [resourceCount++] = systemFont;
+		systemFont = null;
+	}
+	if (errorImage != null) resources [resourceCount++] = errorImage;
+	if (infoImage != null) resources [resourceCount++] = infoImage;
+	if (questionImage != null) resources [resourceCount++] = questionImage;
+	if (warningImage != null) resources [resourceCount++] = warningImage;
+	errorImage = infoImage = questionImage = warningImage = null;
+	for (int i=0; i<cursors.length; i++) {
+		if (cursors [i] != null) resources [resourceCount++] = cursors [i];
+		cursors [i] = null;
+	}
+	if (resourceCount < RESOURCE_SIZE) {
+		Resource [] newResources = new Resource [resourceCount];
+		System.arraycopy (resources, 0, newResources, 0, resourceCount);
+		resources = newResources;
+	}
+}
+
+void sendEvent (int eventType, Event event) {
+	if (eventTable == null && filterTable == null) {
+		return;
+	}
+	if (event == null) event = new Event ();
+	event.display = this;
+	event.type = eventType;
+	if (event.time == 0) event.time = getLastEventTime ();
+	if (!filterEvent (event)) {
+		if (eventTable != null) eventTable.sendEvent (event);
+	}
+}
+
+void setCurrentCaret (Caret caret) {
+	if (caretId != 0) OS.gtk_timeout_remove(caretId);
+	caretId = 0;
+	currentCaret = caret;
+	if (caret == null) return;
+	int blinkRate = currentCaret.blinkRate;
+	caretId = OS.gtk_timeout_add (blinkRate, caretProc, 0);
+}
+
+int /*long*/ shellMapProc (int /*long*/ handle, int /*long*/ arg0, int /*long*/ user_data) {
+	Widget widget = getWidget (handle);
+	if (widget == null) return 0;
+	return widget.shellMapProc (handle, arg0, user_data);
+}
+
+int /*long*/ styleSetProc (int /*long*/ gobject, int /*long*/ arg1, int /*long*/ user_data) {
+	settingsChanged = true;
+	return 0;
+}
+
+/**
+ * Causes the <code>run()</code> method of the runnable to
+ * be invoked by the user-interface thread at the next
+ * reasonable opportunity. The thread which calls this method
+ * is suspended until the runnable completes.  Specifying <code>null</code>
+ * as the runnable simply wakes the user-interface thread.
+ * <p>
+ * Note that at the time the runnable is invoked, widgets
+ * that have the receiver as their display may have been
+ * disposed. Therefore, it is necessary to check for this
+ * case inside the runnable before accessing the widget.
+ * </p>
+ *
+ * @param runnable code to run on the user-interface thread or <code>null</code>
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_FAILED_EXEC - if an exception occurred when executing the runnable</li>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #asyncExec
+ */
+public void syncExec (Runnable runnable) {
+	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+	synchronized (idleLock) {
+		if (idleNeeded && idleHandle == 0) {
+			//NOTE: calling unlocked function in OS
+			idleHandle = OS._g_idle_add (idleProc, 0);
+		}
+	}
+	synchronizer.syncExec (runnable);
+}
+
+static int translateKey (int key) {
+	for (int i=0; i<KeyTable.length; i++) {
+		if (KeyTable [i] [0] == key) return KeyTable [i] [1];
+	}
+	return 0;
+}
+
+static int untranslateKey (int key) {
+	for (int i=0; i<KeyTable.length; i++) {
+		if (KeyTable [i] [1] == key) return KeyTable [i] [0];
+	}
+	return 0;
+}
+
+/**
+ * Forces all outstanding paint requests for the display
+ * to be processed before this method returns.
+ *
+ * @exception SWTException <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>
+ *
+ * @see Control#update()
+ */
+public void update () {
+	checkDevice ();
+	flushExposes (0, true);
+	OS.gdk_window_process_all_updates ();
+}
+
+/**
+ * If the receiver's user-interface thread was <code>sleep</code>ing,
+ * causes it to be awakened and start running again. Note that this
+ * method may be called from any thread.
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #sleep
+ */
+public void wake () {
+	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
+	if (thread == Thread.currentThread ()) return;
+	wakeThread ();
+}
+
+void wakeThread () {
+	OS.g_main_context_wakeup (0);
+	wake = true;
+}
+
+static char wcsToMbcs (char ch) {
+	int key = ch & 0xFFFF;
+	if (key <= 0x7F) return ch;
+	byte [] buffer = Converter.wcsToMbcs (null, new char [] {ch}, false);
+	if (buffer.length == 1) return (char) buffer [0];
+	if (buffer.length == 2) {
+		return (char) (((buffer [0] & 0xFF) << 8) | (buffer [1] & 0xFF));
+	}
+	return 0;
+}
+
+int /*long*/ windowProc (int /*long*/ handle, int /*long*/ user_data) {
+	Widget widget = getWidget (handle);
+	if (widget == null) return 0;
+	return widget.windowProc (handle, user_data);
+}
+
+int /*long*/ windowProc (int /*long*/ handle, int /*long*/ arg0, int /*long*/ user_data) {
+	Widget widget = getWidget (handle);
+	if (widget == null) return 0;
+	return widget.windowProc (handle, arg0, user_data);
+}
+
+int /*long*/ windowProc (int /*long*/ handle, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ user_data) {
+	Widget widget = getWidget (handle);
+	if (widget == null) return 0;
+	return widget.windowProc (handle, arg0, arg1, user_data);
+}
+
+int /*long*/ windowProc (int /*long*/ handle, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2, int /*long*/ user_data) {
+	Widget widget = getWidget (handle);
+	if (widget == null) return 0;
+	return widget.windowProc (handle, arg0, arg1, arg2, user_data);
+}
+
+int /*long*/ windowTimerProc (int /*long*/ handle) {
+	Widget widget = getWidget (handle);
+	if (widget == null) return 0;
+	return widget.timerProc (handle);
+}
+
+}
+++++/
\ No newline at end of file
--- a/todo.txt	Mon Jan 07 01:49:53 2008 +0100
+++ b/todo.txt	Mon Jan 07 03:41:50 2008 +0100
@@ -36,7 +36,7 @@
 graphics/GCData
 graphics/GlyphMetrics
 graphics/Image
-graphics/ImageData                     // OK (GC, Device, Image)
+graphics/ImageData                     // OK
 graphics/ImageDataLoader               // OK
 graphics/ImageLoader                   // OK (FileFormat)
 graphics/ImageLoaderEvent              // OK