Mercurial > projects > dwt-linux
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