/*******************************************************************************
 * Copyright (c) 2000, 2008 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
 *******************************************************************************/
package org.eclipse.swt.widgets;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;

public class Display extends Device {

	Thread thread;
	Event [] eventQueue;
	EventTable eventTable, filterTable;
	Synchronizer synchronizer = new Synchronizer (this);
	Runnable [] disposeList;
	int freeSlot;
	int [] indexTable;
	Control [] controlTable;
	static final int GROW_SIZE = 1024;
	
	/* Display Data */
	Object data;
	String [] keys;
	Object [] values;

	/* System Tray */
	Tray tray;

//	int freeSlot;
//	int [] indexTable;
//	Control [] controlTable;
//	static final int GROW_SIZE = 1024;
	
	Object jsDisplay;
	boolean jsDisplayInit = false;
	
	Control currentControl;
	
	static Display Default;
	static Display [] Displays = new Display [4];
	
	/* Package Name */
	static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets."; //$NON-NLS-1$
	/*
	* This code is intentionally commented.  In order
	* to support CLDC, .class cannot be used because
	* it does not compile on some Java compilers when
	* they are targeted for CLDC.
	*/
//	static {
//		String name = Display.class.getName ();
//		int index = name.lastIndexOf ('.');
//		PACKAGE_PREFIX = name.substring (0, index + 1);
//	}
	
	/*
	* 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;
	}
	
public Display () {
	this (null);
}

public Display (DeviceData data) {
	super (data);
}

static boolean isValidClass (Class clazz) {
	String name = clazz.getName ();
	int index = name.lastIndexOf ('.');
	return name.substring (0, index + 1).equals (PACKAGE_PREFIX);
}

//TODO TEMP HACK!!!
void addControl (int /*long*/ handle, Control control) {
	if (controlTable [0] == null) controlTable [0] = control;
}

//void addControl (int /*long*/ handle, Control control) {
//	if (handle == 0) return;
//	if (freeSlot == -1) {
//		int length = (freeSlot = indexTable.length) + GROW_SIZE;
//		int [] newIndexTable = new int [length];
//		Control [] newControlTable = new Control [length];
//		System.arraycopy (indexTable, 0, newIndexTable, 0, freeSlot);
//		System.arraycopy (controlTable, 0, newControlTable, 0, freeSlot);
//		for (int i=freeSlot; i<length-1; i++) newIndexTable [i] = i + 1;
//		newIndexTable [length - 1] = -1;
//		indexTable = newIndexTable;
//		controlTable = newControlTable;
//	}
//	_setID(control, handle, freeSlot + 1);
//	int oldSlot = freeSlot;
//	freeSlot = indexTable [oldSlot];
//	indexTable [oldSlot] = -2;
//	controlTable [oldSlot] = control;
//}

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);
}

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);
}

public void asyncExec (Runnable runnable) {
	synchronized (Device.class) {
		if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
		synchronizer.asyncExec (runnable);
	}
}

public void beep () {
	checkDevice ();
	_beep ();
}

protected void checkDevice () {
	/*if (thread == null) error (SWT.ERROR_WIDGET_DISPOSED);
	if (thread != Thread.currentThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS);
	*/
//TODO: Do we need this? 
	if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
}

static void checkDisplay (Thread thread, boolean multiple) {
	synchronized (Device.class) {
		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);
			}
		}
	}
}

protected void checkSubclass () {
	//TODO: Put in proper subclass checking
	//if (!isValidClass (getClass ())) error (SWT.ERROR_INVALID_SUBCLASS);
}

public void close () {
	checkDevice ();
	Event event = new Event ();
	sendEvent (SWT.Close, event);
	if (event.doit) dispose ();
}

protected void create (DeviceData data) {
	checkSubclass ();
	checkDisplay (thread = Thread.currentThread (), true);
	_createDisplay (data, System.getProperty("org.eclipse.swt.widgets.Display.ID", "swtDisplay"));
	register (this);
	if (Default == null) Default = this;
}

static void deregister (Display display) {
	synchronized (Device.class) {
		for (int i=0; i<Displays.length; i++) {
			if (display == Displays [i]) Displays [i] = null;
		}
	}
}

protected void destroy () {
	if (this == Default) Default = null;
	deregister (this);
	_destroyDisplay ();
}

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;
}

void error (int code) {
	SWT.error (code);
}

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);
}

public Widget findWidget (int handle) {
	checkDevice ();
//	return getControl (handle);
	return null;
}

public Widget findWidget (int handle, int id) {
	//TODO - 
	return null;
}

public Widget findWidget (Widget widget, int id) {
	//TODO - 
	return null;
}

public static Display findDisplay (Thread thread) {
	synchronized (Device.class) {
		for (int i=0; i<Displays.length; i++) {
			Display display = Displays [i];
			if (display != null && display.thread == thread) {
				return display;
			}
		}
		return null;
	}
}

public Shell getActiveShell () {
	//TODO - 
	return null;
}

//public Rectangle getBounds () {
//	//TODO - 
//	return null;
//}

public static Display getCurrent () {
	return findDisplay (Thread.currentThread ());
}

public Rectangle getClientArea () { 
	return super.getClientArea();
}

public Control getCursorControl () {
	//TODO - 
	return null;
}

public Point getCursorLocation () {
	//TODO - 
	return null;
}

public Point[] getCursorSizes () {
	//TODO - 
	return null;
}

public static Display getDefault () {
	synchronized (Device.class) {
		if (Default == null) Default = new Display ();
		return Default;
	}
}

public Object getData () {
	checkDevice ();
	return data;
}

public Object getData (String key) {
	checkDevice ();
	if (key == null) error (SWT.ERROR_NULL_ARGUMENT);
	//TODO - getData hacks
//	if (key.equals (RUN_MESSAGES_IN_IDLE_KEY)) {
//		return new Boolean (runMessagesInIdle);
//	}
	if (keys == null) return null;
	for (int i=0; i<keys.length; i++) {
		if (keys [i].equals (key)) return values [i];
	}
	return null;
}

public int getDismissalAlignment () {
	//TODO - 
	return 0;
}

public int getDoubleClickTime () {
	//TODO - 
	return 0;
}

public Control getFocusControl () {
	//TODO - 
	return null;
}

public boolean getHighContrast () {
	//TODO - 
	return false;
}

public int getIconDepth () {
	//TODO - 
	return 0;
}

public Point[] getIconSizes () {
	//TODO - 
	return null;
}

int getMessageCount () {
	return synchronizer.getMessageCount ();
}

public Monitor[] getMonitors () {
	//TODO - 
	return null;
}

public Monitor getPrimaryMonitor () {
	//TODO - 
	return null;
}

public Shell[] getShells () {
	checkDevice ();
	int index = 0;
	Shell [] result = new Shell [16];
	for (int i = 0; i < controlTable.length; i++) {
		Control control = controlTable [i];
		if (control != null && control instanceof Shell) {
			int j = 0;
			while (j < index) {
				if (result [j] == control) 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) control;	
			}
		}
	}
	if (index == result.length) return result;
	Shell [] newResult = new Shell [index];
	System.arraycopy (result, 0, newResult, 0, index);
	return newResult;
}

public Synchronizer getSynchronizer () {
	checkDevice ();
	return synchronizer;
}

public Thread getSyncThread () {
	synchronized (Device.class) {
		if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
		return synchronizer.syncThread;
	}
}

public Color getSystemColor (int id) {
	checkDevice ();
	switch (id) {
		case SWT.COLOR_INFO_FOREGROUND:
		case SWT.COLOR_INFO_BACKGROUND:
		case SWT.COLOR_TITLE_FOREGROUND:
		case SWT.COLOR_TITLE_BACKGROUND:
		case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:
		case SWT.COLOR_TITLE_INACTIVE_FOREGROUND:
		case SWT.COLOR_TITLE_INACTIVE_BACKGROUND:
		case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:
		case SWT.COLOR_WIDGET_DARK_SHADOW:
		case SWT.COLOR_WIDGET_NORMAL_SHADOW:
		case SWT.COLOR_WIDGET_LIGHT_SHADOW:
		case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW:
		case SWT.COLOR_WIDGET_BACKGROUND:
		case SWT.COLOR_WIDGET_FOREGROUND:
		case SWT.COLOR_WIDGET_BORDER:
		case SWT.COLOR_LIST_FOREGROUND:
		case SWT.COLOR_LIST_BACKGROUND:
		case SWT.COLOR_LIST_SELECTION_TEXT:
		case SWT.COLOR_LIST_SELECTION:
			//TODO
			break;
	}
	return super.getSystemColor (id);	
}

public Cursor getSystemCursor (int id) {
	//TODO-
	return null;
}

public Font getSystemFont () {
	//TODO-
	return null;
}

public Image getSystemImage (int id) {
	//TODO-
	return null;
}

public Tray getSystemTray () {
	//TODO-
	return null;
}

public Thread getThread () {
	synchronized (Device.class) {
		if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
		return thread;
	}
}

//Control getControl (int /*long*/ handle) {
//	if (handle == 0) return null;
//	int index = _getID (handle);
//	if (0 <= index && index < controlTable.length) {
//		Control control = controlTable [index];
//		if (control != null && control.checkHandle (handle)) {
//			return control;
//		}
//	}
//	return null;
//}

//TODO
protected void init () {
	super.init();
	/* Initialize the Widget Table */
	indexTable = new int [GROW_SIZE];
	controlTable = new Control [GROW_SIZE];
	for (int i=0; i<GROW_SIZE-1; i++) indexTable [i] = i + 1;
	indexTable [GROW_SIZE - 1] = -1;
}

public int internal_new_GC (GCData data) {
	return 0;
}

public void internal_dispose_GC (int hDC, GCData data) {
}

boolean isValidThread () {
	return thread == Thread.currentThread ();
}

public Point map (Control from, Control to, Point point) {
//TODO Implement correctly
//	checkDevice ();
	return map(from,to,point.x,point.y);
}

public Point map (Control from, Control to, int x, int y) {
//TODO Implement correctly
//	checkDevice ();
	return new Point (x, y);
}

public Rectangle map (Control from, Control to, Rectangle rectangle) {
	return null;
}

public Rectangle map (Control from, Control to, int x, int y, int width, int height) {
	return null;
}

public boolean post (Event event) {
	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;
}

public boolean readAndDispatch () {
	checkDevice ();
	if(!jsDisplayInit){
		jsDisplayInit = true;
	}
// TODO uncomment if necessary		
//	boolean events = server.readEvent ();
//	if (events) {
//		runDeferredEvents();
//		return true;
//	}
	return runAsyncMessages (false);
}

static void register (Display display) {
	synchronized (Device.class) {
		for (int i=0; i<Displays.length; i++) {
			if (Displays [i] == null) {
				Displays [i] = display;
				return;
			}
		}
		Display [] newDisplays = new Display [Displays.length + 4];
		System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
		newDisplays [Displays.length] = display;
		Displays = newDisplays;
	}
}

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() {
	controlTable = null;
	thread = null;
	eventQueue = null;
	eventTable = null;
	filterTable = null;
	synchronizer = null;
	disposeList = null;
	indexTable = null;
	
	/* Display Data */
	data = null;
	keys = null;
	values = null;

	/* System Tray */
	tray = null;

	_releaseDisplay ();
}

//Control removeControl (int /*long*/ handle) {
//	if (handle == 0) return null;
//	Control control = null;
//	int index = _removeID (handle);
//	if (0 <= index && index < controlTable.length) {
//		control = controlTable [index];
//		controlTable [index] = null;
//		indexTable [index] = freeSlot;
//		freeSlot = index;
//	}
//	return control;
//}

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;
}

public void removeListener (int eventType, Listener listener) {
	checkDevice ();
	if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (eventTable == null) return;
	eventTable.unhook (eventType, listener);
}

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 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.notifyListeners (event.type, 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;
}

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);
	}
}

public void setCursorLocation (int x, int y) {
	//TODO-
}

public void setCursorLocation (Point point) {
	//TODO-
}

public void setData (Object data) {
	checkDevice ();
	this.data = data;
}

public void setData (String key, Object value) {
	checkDevice ();
	if (key == null) error (SWT.ERROR_NULL_ARGUMENT);

	//TODO - hacked setData
//	if (key.equals (RUN_MESSAGES_IN_IDLE_KEY)) {
//		Boolean data = (Boolean) value;
//		runMessagesInIdle = data != null && data.booleanValue ();
//		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;
}

public static void setAppName (String name) {
}

public void setSynchronizer (Synchronizer synchronizer) {
	checkDevice ();
	if (synchronizer == null) error (SWT.ERROR_NULL_ARGUMENT);
	if (synchronizer == this.synchronizer) return;
	Synchronizer oldSynchronizer;
	synchronized (Device.class) {
		oldSynchronizer = this.synchronizer;
		this.synchronizer = synchronizer;
	}
	if (oldSynchronizer != null) {
		oldSynchronizer.runAsyncMessages(true);
	}
}

public boolean sleep () {
	checkDevice ();
	if (getMessageCount () != 0) return true;
	// TODO uncomment if necessary
	//	return server.sleep();
	return true;
}

public void syncExec (Runnable runnable) {
	Synchronizer synchronizer;
	synchronized (Device.class) {
		if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
		synchronizer = this.synchronizer;
	}
	synchronizer.syncExec (runnable);
}

public void timerExec (int milliseconds, Runnable runnable) {
}

public void update () {
}

public void wake () {
	synchronized (Device.class) {
		if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
		if (thread == Thread.currentThread ()) return;
		wakeThread ();
	}
}

/* --------- NATIVE INTERFACE ---------------*/

void _beep () {
}

native void _createDisplay (DeviceData data, String id) /*-{
	if(!$wnd.dojo._hasResource["org.eclipse.swt.Display"]){
		$wnd.dojo._hasResource["org.eclipse.swt.Display"] = true;
		$wnd.dojo.provide("org.eclipse.swt.Display");
		
		$wnd.dojo.require("dijit._Widget");
		$wnd.dojo.require("dijit._Container");
		
		$wnd.dojo.declare(
			"org.eclipse.swt.Display", $wnd.eval("[dijit._Widget, dijit._Container, dijit._Contained]"),{
				baseClass: "swtDisplay",
				postCreate: function(){
					this.inherited("postCreate",arguments); 
					$wnd.dojo.addClass(this.domNode, this.baseClass);
				}
			}
		);
	}
	
	var displayParent = $wnd.dojo.byId(id);
	if (displayParent == null || displayParent == undefined) {
	 	displayParent = $doc.body;
	}
	var display = $doc.createElement("div");
	$wnd.dojo.place(display, displayParent, "first");
	if (!$wnd.dojo.hasClass($doc.body,"tundra") && !$wnd.dojo.hasClass($doc.body,"soria")) {
		$wnd.dojo.addClass($doc.body,"tundra")
	}
	try {
		var self = new $wnd.org.eclipse.swt.Display({}, display);
		$wnd.swt.setCssStyle(self.domNode, {width: "100%", height: "100%"});
		this.@org.eclipse.swt.widgets.Display::jsDisplay = self;
	} catch (e) {
//TODO Have to throw real exception for Java side also	
		 $wnd.alert(e);
	}
}-*/;

void _destroyDisplay () {
	Displays = null;
}

//int _getID(int handle) {
//	return 0;
//}

public void displayRun () {
	Rectangle rect = new Rectangle(0,0,0,0); 
	_getBounds(rect);
	_setBounds(rect.x, rect.y, rect.width, rect.height);
	_displayRun();
}

native void _displayRun ()  /*-{
	var self = this;
 	if ($wnd.dojo.byId("swtLoading")) {
 		$wnd.dojo.byId("swtLoading").style.display = "none";
 	} 
	$wnd.dojo.connect("onbeforeunload",function(){self.@org.eclipse.swt.graphics.Device::dispose()();});
	
//FIXME find better way and place to do that
	var mainShell = this.@org.eclipse.swt.widgets.Display::controlTable[0].@org.eclipse.swt.widgets.Widget::jsObject;
	var mainShellBounds = $wnd.swt.getNativeBounds(mainShell.domNode, true);
	var display = self.@org.eclipse.swt.widgets.Display::jsDisplay;
	var displayBounds = $wnd.swt.getNativeBounds(display.domNode, true);
	if (displayBounds.w < mainShellBounds.w ) {
		display.domNode.style.overflowX = "scroll"
	}
	if (displayBounds.h < mainShellBounds.h ) {
		display.domNode.style.overflowY = "scroll"
	}
}-*/;

//FIXME find better way to do that
protected native void _getBounds (Rectangle rectangle) /*-{
	var self = this.@org.eclipse.swt.widgets.Display::jsDisplay.domNode;
	var width = 0, height = 0;
	
	var styleWidth = self.style.width.replace("px","");
	if (isNaN(styleWidth)) {
		if (self.parentNode && !isNaN(self.parentNode.clientWidth)) {
			var styleWidthPerc = styleWidth.replace(" ","").replace("%","");
			if (self.parentNode!=$doc.body) {
				width = self.parentNode.clientWidth * (styleWidthPerc/100);
			} else {
				width = $doc.body.clientWidth * (styleWidthPerc/100);
			}
		}
	} else {
		width = ((self.clientWidth == styleWidth) && (self.clientWidth!=0)) ? self.clientWidth : Math.max($doc.documentElement.clientWidth, $doc.body.clientWidth);
	}
	
	var styleHeight = self.style.height.replace("px","");
	if (isNaN(styleHeight)) {
		if (self.parentNode && !isNaN(self.parentNode.clientHeight)) {
			var styleHeightPerc = styleHeight.replace(" ","").replace("%","");
			if (self.parentNode!=$doc.body) {
				height = self.parentNode.clientHeight * (styleHeightPerc/100);
			} else {
				var bodyHeight = $doc.body.style.height.match("px")!=null ? $doc.body.clientHeight : Math.max($doc.documentElement.clientHeight, $doc.body.clientHeight); 
				height = bodyHeight * (styleHeightPerc/100);
			}
		}
	} else {
		height = ((self.clientHeight == styleHeight) && (self.clientHeight!=0)) ? self.clientHeight : Math.max($doc.documentElement.clientHeight, $doc.body.clientHeight);
	}
	
	rectangle.@org.eclipse.swt.graphics.Rectangle::x=0;
	rectangle.@org.eclipse.swt.graphics.Rectangle::y=0;
	rectangle.@org.eclipse.swt.graphics.Rectangle::width=width;
	rectangle.@org.eclipse.swt.graphics.Rectangle::height=height;
}-*/;

int getLastEventTime () {
	return 0;
}


//int _removeID(int handle) {
//	return 0;
//}
//
//void _setID(Control control, int handle, int id) {
//}

native void _releaseDisplay () /*-{
	this.@org.eclipse.swt.widgets.Display::jsDisplay.destroy();
	this.@org.eclipse.swt.widgets.Display::jsDisplay = null;
}-*/;

native void _setBounds (int x, int y, int width, int height) /*-{
	$wnd.swt.setNativeBounds(
		this.@org.eclipse.swt.widgets.Display::jsDisplay.domNode, 
		{l:x, t:y, w:width, h:height}
	);
}-*/;

void wakeThread () {
}

}
