![JAR search and dependency download from the Maven repository](/logo.png)
org.eclipse.swt.widgets.Display Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2002, 2021 Innoopract Informationssysteme GmbH 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:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
* Frank Appel - replaced singletons and static fields (Bug 337787)
* Rüdiger Herrmann - exception handler (bug 367773)
******************************************************************************/
package org.eclipse.swt.widgets;
import static org.eclipse.rap.rwt.internal.lifecycle.DisplayUtil.getId;
import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.readPropertyValue;
import static org.eclipse.rap.rwt.remote.JsonMapping.readPoint;
import static org.eclipse.rap.rwt.remote.JsonMapping.readRectangle;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.eclipse.rap.json.JsonValue;
import org.eclipse.rap.rwt.Adaptable;
import org.eclipse.rap.rwt.application.ExceptionHandler;
import org.eclipse.rap.rwt.internal.application.ApplicationContextImpl;
import org.eclipse.rap.rwt.internal.lifecycle.CurrentPhase;
import org.eclipse.rap.rwt.internal.lifecycle.IUIThreadHolder;
import org.eclipse.rap.rwt.internal.lifecycle.LifeCycle;
import org.eclipse.rap.rwt.internal.lifecycle.LifeCycleUtil;
import org.eclipse.rap.rwt.internal.lifecycle.PhaseId;
import org.eclipse.rap.rwt.internal.lifecycle.ProcessActionRunner;
import org.eclipse.rap.rwt.internal.lifecycle.RemoteAdapter;
import org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil;
import org.eclipse.rap.rwt.internal.serverpush.ServerPushManager;
import org.eclipse.rap.rwt.internal.service.ContextProvider;
import org.eclipse.rap.rwt.internal.service.ServletLog;
import org.eclipse.rap.rwt.internal.theme.CssColor;
import org.eclipse.rap.rwt.internal.theme.CssImage;
import org.eclipse.rap.rwt.internal.theme.CssValue;
import org.eclipse.rap.rwt.internal.theme.SimpleSelector;
import org.eclipse.rap.rwt.internal.theme.ThemeUtil;
import org.eclipse.rap.rwt.service.ServerPushSession;
import org.eclipse.rap.rwt.service.UISession;
import org.eclipse.rap.rwt.theme.BoxDimensions;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.SerializableCompatibility;
import org.eclipse.swt.internal.events.EventList;
import org.eclipse.swt.internal.events.EventUtil;
import org.eclipse.swt.internal.widgets.IDisplayAdapter;
import org.eclipse.swt.internal.widgets.IdGenerator;
import org.eclipse.swt.internal.widgets.WidgetRemoteAdapter;
import org.eclipse.swt.internal.widgets.WidgetTreeUtil;
import org.eclipse.swt.internal.widgets.WidgetTreeVisitor;
/**
* 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.
*
* Applications which are built with SWT will almost always
* require only a single display. In particular, some platforms
* which SWT supports will not allow more than one active
* display. In other words, some platforms do not support
* creating a new display if one already exists that has not been
* sent the dispose()
message.
*
* In SWT, the thread which creates a Display
* instance is distinguished as the user-interface thread
* for that display.
*
* The user-interface thread for a particular display has the
* following special attributes:
*
* -
* The event loop for that display must be run from the thread.
*
* -
* Some SWT API methods (notably, most of the public methods in
*
Widget
and its subclasses), may only be called
* from the thread. (To support multi-threaded user-interface
* applications, class Display
provides inter-thread
* communication methods which allow threads other than the
* user-interface thread to request that it perform operations
* on their behalf.)
*
* -
* The thread is not allowed to construct other
*
Display
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.)
*
*
* 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.
*
* 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 "ERROR_THREAD_INVALID_ACCESS
"
* SWT exception.
*
*
* - Styles:
* - (none)
* - Events:
* - Close, Dispose, Skin
*
*
* IMPORTANT: This class is not intended to be subclassed.
*
* @see #syncExec
* @see #asyncExec
* @see #wake
*
* @see #readAndDispatch
* @see #sleep
* @see Device#dispose
*
* @since 1.0
*/
@SuppressWarnings( "deprecation" )
public class Display extends Device implements Adaptable {
private final static String BOUNDS = "bounds";
private final static String DPI = "dpi";
private final static String COLOR_DEPTH = "colorDepth";
private static final String ATTR_INVALIDATE_FOCUS
= DisplayAdapter.class.getName() + "#invalidateFocus";
private static final String APP_NAME = Display.class.getName() + "#appName";
private static final String APP_VERSION = Display.class.getName() + "#appVersion";
private static final int DOUBLE_CLICK_TIME = 500; // Keep in sync with client-side (EventUtil.js)
private static final int GROW_SIZE = 1024;
static final String PACKAGE_PREFIX = "org.eclipse.swt.widgets.";
private static final ExceptionHandler DEFAULT_EXCEPTION_HANDLER = new ExceptionHandler() {
@Override
public void handleException( Throwable throwable ) {
if( throwable instanceof RuntimeException ) {
throw ( RuntimeException )throwable;
}
if( throwable instanceof Error ) {
throw ( Error )throwable;
}
}
};
/**
* 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 Display getCurrent() {
Display result = LifeCycleUtil.getSessionDisplay();
if( result != null ) {
if( result.isDisposed() || result.getThread() != Thread.currentThread() ) {
result = null;
}
}
return result;
}
/**
* Returns the default display. One is created if it did not already exist.
*
* Note: In RWT, a new display is only created if the
* calling thread is the user-interface thread.
*
*
* @return the default display
*/
public static Display getDefault() {
Display display = LifeCycleUtil.getSessionDisplay();
if( display == null || display.isDisposed() ) {
if( isUIThread() ) {
display = new Display();
}
}
return display;
}
private static boolean isUIThread() {
boolean result = false;
if( ContextProvider.hasContext() ) {
IUIThreadHolder uiThreadHolder = LifeCycleUtil.getUIThread( ContextProvider.getUISession() );
Thread uiThread = uiThreadHolder == null ? null : uiThreadHolder.getThread();
result = uiThread == Thread.currentThread();
}
return result;
}
private final List shells;
private transient Thread thread;
private final UISession uiSession;
private final Rectangle bounds;
private final Point dpi;
private final int depth;
private final Point cursorLocation;
private Shell activeShell;
private Collection redrawControls;
private Control focusControl;
private EventTable filterTable;
private EventTable eventTable;
private transient Monitor monitor;
private transient IDisplayAdapter displayAdapter;
private WidgetRemoteAdapter remoteAdapter;
private Runnable[] disposeList;
private Composite[] layoutDeferred;
private int layoutDeferredCount;
private Widget[] skinList;
private int skinCount;
private boolean beep;
/* Display Data */
private Object data;
private String[] keys;
private Object[] values;
private Synchronizer synchronizer;
private TimerExecScheduler scheduler;
/**
* Constructs a new instance of this class.
*
* Note: The resulting display is marked as the current
* display. If this is the first display which has been
* constructed since the application started, it is also
* marked as the default display.
*
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if called from a thread that already created an existing display
* - ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass
*
*
* @see #getCurrent
* @see #getDefault
* @see Widget#checkSubclass
* @see Shell
*/
public Display() {
if( getCurrent() != null ) {
SWT.error( SWT.ERROR_NOT_IMPLEMENTED, null, " [multiple displays]" );
}
LifeCycleUtil.setSessionDisplay( this );
attachThread();
uiSession = ContextProvider.getUISession();
shells = new ArrayList<>();
monitor = new Monitor( this );
cursorLocation = new Point( 0, 0 );
bounds = readInitialBounds();
dpi = readDPI();
depth = readDepth();
synchronizer = new Synchronizer( this );
register();
}
/**
* Returns a rectangle describing the receiver's size and location.
*
* @return the bounding rectangle
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
@Override
public Rectangle getBounds() {
checkDevice();
return new Rectangle( bounds.x, bounds.y, bounds.width, bounds.height );
}
@Override
public Point getDPI() {
checkDevice();
return new Point( dpi.x, dpi.y );
}
@Override
public int getDepth() {
checkDevice();
return depth;
}
/**
* 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
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Control getFocusControl() {
checkDevice();
return focusControl;
}
private void setFocusControl( Control focusControl, boolean fireEvents ) {
if( this.focusControl != focusControl ) {
if( this.focusControl != null && !this.focusControl.isInDispose() ) {
Control currentFocusControl = this.focusControl;
Shell shell = currentFocusControl.getShell();
if( fireEvents ) {
currentFocusControl.notifyListeners( SWT.FocusOut, new Event() );
}
shell.updateDefaultButton( currentFocusControl, false );
}
this.focusControl = focusControl;
if( this.focusControl != null ) {
Control currentFocusControl = this.focusControl;
Shell shell = currentFocusControl.getShell();
if( fireEvents ) {
currentFocusControl.notifyListeners( SWT.FocusIn, new Event() );
}
shell.updateDefaultButton( currentFocusControl, true );
}
}
}
/////////////////////
// Coordinate mapping
/**
* Maps a point from one coordinate system to another.
* When the control is null, coordinates are mapped to
* the display.
*
* 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.
*
*
* @param from the source Control
or null
* @param to the destination Control
or null
* @param point to be mapped
* @return point with mapped coordinates
*
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the point is null
* - ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Point map( Control from, Control to, Point point ) {
checkDevice();
if( point == null ) {
SWT.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.
*
* 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.
*
*
* @param from the source Control
or null
* @param to the destination Control
or null
* @param x coordinates to be mapped
* @param y coordinates to be mapped
* @return point with mapped coordinates
*
* @exception IllegalArgumentException
* - ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Point map( Control from, Control to, int x, int y ) {
checkDevice();
Rectangle rectangle = map( from, to, x, y, 0, 0 );
return new Point( rectangle.x, rectangle.y );
}
/**
* Maps a point from one coordinate system to another.
* When the control is null, coordinates are mapped to
* the display.
*
* 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.
*
*
* @param from the source Control
or null
* @param to the destination Control
or null
* @param rectangle to be mapped
* @return rectangle with mapped coordinates
*
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the rectangle is null
* - ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Rectangle map( Control from, Control to, Rectangle rectangle ) {
checkDevice();
if( rectangle == null ) {
SWT.error( SWT.ERROR_NULL_ARGUMENT );
}
return map( from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height );
}
/**
* Maps a point from one coordinate system to another.
* When the control is null, coordinates are mapped to
* the display.
*
* 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.
*
*
* @param from the source Control
or null
* @param to the destination Control
or null
* @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
* - ERROR_INVALID_ARGUMENT - if the Control from or the Control to have been disposed
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Rectangle map( Control from, Control to, int x, int y, int width, int height ) {
checkDevice();
int newX = x;
int newY = y;
if( from != null ) {
Point fromOrigin = getAbsoluteOrigin( from );
newX = fromOrigin.x + applyMirror( from, newX, width );
newY = fromOrigin.y + newY;
}
if( to != null ) {
Point toOrigin = getAbsoluteOrigin( to );
newX = applyMirror( to, newX - toOrigin.x, width );
newY = newY - toOrigin.y;
}
return new Rectangle( newX, newY, width, height );
}
/*
* Returns the origin of the coordinate system of a given control in absolute
* coordinates, i.e. relative to the display.
*/
private static Point getAbsoluteOrigin( Control control ) {
Control currentControl = control;
Point absolute = new Point( 0, 0 );
while( currentControl != null ) {
Point origin = getOrigin( currentControl );
absolute.x += applyMirror( currentControl.getParent(), origin.x, currentControl.getSize().x );
absolute.y += origin.y;
if( currentControl instanceof Shell ) {
currentControl = null;
} else {
currentControl = currentControl.getParent();
}
}
return new Point( absolute.x, absolute.y );
}
/*
* Returns the origin of the coordinate system of a given control, relative to
* it's parent or, if it does not have a parent, relative to the display.
*/
private static Point getOrigin( Control control ) {
Point result = control.getLocation();
// Due the way that the qx client implementation works, the coordinate
// system of composites starts at the inner edge of their border and thus
// need to be offset by the border width.
// Since only composites can contain child widgets, only they need this
// correction. This implementation seems to be a good fit with SWT.
if( control instanceof Composite ) {
boolean rtl = control.getOrientation() == SWT.RIGHT_TO_LEFT;
BoxDimensions borderWidth = control.getBorder();
result.x += rtl ? borderWidth.right : borderWidth.left;
result.y += borderWidth.top;
}
return result;
}
private static int applyMirror( Control control, int x, int width ) {
if( control != null && control.getOrientation() == SWT.RIGHT_TO_LEFT ) {
BoxDimensions border = control.getBorder();
int innerWidth = control.getSize().x - border.left - border.right;
return innerWidth - x - width;
}
return x;
}
///////////
// Listener
/**
* 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 SWT
.
* When the event does occur in the display, the listener is notified by
* sending it the handleEvent()
message.
*
* @param eventType the type of event to listen for
* @param listener the listener which should be notified when the event occurs
*
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the listener is null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see Listener
* @see SWT
* @see #removeListener
*
* @since 1.3
*/
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 );
}
/**
* 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 SWT
.
*
* @param eventType the type of event to listen for
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the listener is null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see Listener
* @see SWT
* @see #addListener
*
* @since 1.3
*/
public void removeListener( int eventType, Listener listener ) {
checkDevice();
if( listener == null ) {
error( SWT.ERROR_NULL_ARGUMENT );
}
if( eventTable != null ) {
eventTable.unhook( eventType, listener );
}
}
void sendEvent( int eventType, Event event ) {
event.display = this;
event.type = eventType;
if( event.time == 0 ) {
event.time = EventUtil.getLastEventTime();
}
filterEvent( event );
if( eventTable != null ) {
eventTable.sendEvent( event );
}
}
private void notifyListeners( final int eventType, final Event event ) {
ProcessActionRunner.add( new Runnable() {
@Override
public void run() {
sendEvent( eventType, event );
}
} );
}
private boolean isListening( int eventType ) {
return eventTable == null ? false : eventTable.hooks( eventType );
}
//////////
// Dispose
/**
* Causes the run()
method of the runnable to
* be invoked by the user-interface thread just before the
* receiver is disposed. Specifying a null
runnable
* is ignored.
*
* @param runnable code to run at dispose time.
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public void disposeExec( Runnable runnable ) {
checkDevice();
if (disposeList == null) {
disposeList = new Runnable [4];
}
for (int i=0; i
* ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see Device#dispose
*
* @since 1.3
*/
public void close() {
checkDevice();
Event event = new Event();
sendEvent( SWT.Close, event );
if( event.doit ) {
dispose();
}
}
@Override
protected void release() {
sendDisposeEvent();
disposeShells();
runDisposeExecs();
synchronizer.releaseSynchronizer();
if( scheduler != null ) {
scheduler.dispose();
}
filterTable = null;
eventTable = null;
}
@Override
protected void destroy() {
deregister();
}
private void sendDisposeEvent() {
sendEvent( SWT.Dispose, new Event() );
}
private void disposeShells() {
Shell[] shells = getShells();
for( int i = 0; i < shells.length; i++ ) {
Shell shell = shells[ i ];
try {
shell.dispose();
} catch( Throwable thr ) {
ServletLog.log( "Exception while disposing shell: " + shell, thr );
}
}
// TODO [rh] consider dispatching pending messages (e.g. asyncExec)
// while( readAndDispatch() ) {}
}
private void runDisposeExecs() {
checkDevice();
if( disposeList != null ) {
for( int i = 0; i < disposeList.length; i++ ) {
if( disposeList[ i ] != null ) {
try {
disposeList[ i ].run();
} catch( Throwable thr ) {
String msg = "Exception while executing dispose-runnable.";
ServletLog.log( msg, thr );
}
}
}
}
}
/////////////////////
// Adaptable override
@Override
@SuppressWarnings("unchecked")
public T getAdapter( Class adapter ) {
if( adapter == IDisplayAdapter.class ) {
if( displayAdapter == null ) {
displayAdapter = new DisplayAdapter();
}
return ( T )displayAdapter;
}
if( adapter == RemoteAdapter.class ) {
if( remoteAdapter == null ) {
String id = IdGenerator.getInstance( uiSession ).createId( this );
remoteAdapter = new WidgetRemoteAdapter( id );
}
return ( T )remoteAdapter;
}
return null;
}
private ApplicationContextImpl getApplicationContext() {
return ( ApplicationContextImpl )uiSession.getApplicationContext();
}
///////////////////
// Shell management
/**
* 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
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Shell[] getShells() {
checkDevice();
Shell[] result = new Shell[ shells.size() ];
shells.toArray( result );
return result;
}
/**
* Returns the currently active Shell
, or null
* if no shell belonging to the currently running application
* is active.
*
* @return the active shell or null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Shell getActiveShell() {
checkDevice();
return activeShell;
}
final void setActiveShell( Shell activeShell ) {
checkDevice();
if( this.activeShell != activeShell ) {
Shell lastActiveShell = this.activeShell;
if( this.activeShell != null ) {
this.activeShell.saveFocus();
}
// Move active shell to end of list to maintain correct z-order
if( activeShell != null ) {
shells.remove( activeShell );
shells.add( activeShell );
}
if( lastActiveShell != null && !lastActiveShell.hasState( Widget.DISPOSE_SENT ) ) {
lastActiveShell.notifyListeners( SWT.Deactivate, new Event() );
}
this.activeShell = activeShell;
if( activeShell != null ) {
activeShell.notifyListeners( SWT.Activate, new Event() );
}
if( this.activeShell != null ) {
this.activeShell.restoreFocus();
}
}
}
final void addShell( Shell shell ) {
shells.add( shell );
}
final void removeShell( Shell shell ) {
shells.remove( shell );
if( shell == activeShell ) {
int counter = 0;
Shell lastVisibleShell = null;
while( lastVisibleShell == null && counter < shells.size() ) {
counter++;
Shell currentShell = shells.get( shells.size() - counter );
if( currentShell.isVisible() ) {
lastVisibleShell = currentShell;
}
}
setActiveShell( lastVisibleShell );
}
}
////////////////////
// Thread management
/**
* Returns the user-interface thread for the receiver. Note that the
* user-interface thread may change per user-request.
*
* @return the receiver's user-interface thread or null if there's no
* current user-request executed that belongs to the display.
*
* @exception SWTException
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public Thread getThread() {
synchronized( deviceLock ) {
if( isDisposed() ) {
error( SWT.ERROR_DEVICE_DISPOSED );
}
return thread;
}
}
private void attachThread() {
thread = Thread.currentThread();
}
private void detachThread() {
thread = null;
}
//////////////////////
// Information methods
/**
* 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
* null
as the thread will return null
* for the display.
*
* @param thread the user-interface thread
* @return the display for the given thread
*/
public static Display findDisplay( Thread thread ) {
synchronized( Device.class ) {
for( WeakReference displayRef : getDisplays() ) {
if( displayRef != null ) {
Display display = displayRef.get();
if( display != null && !display.isDisposed() && display.thread == thread ) {
return display;
}
}
}
return null;
}
}
/**
* 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
* - ERROR_NULL_ARGUMENT - if the synchronizer is null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
* - ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message
*
*
* @since 1.3
*/
// verbatim copy of SWT code
public void setSynchronizer (Synchronizer synchronizer) {
checkDevice ();
if (synchronizer == null) {
error (SWT.ERROR_NULL_ARGUMENT);
}
if (synchronizer == this.synchronizer) {
return;
}
Synchronizer oldSynchronizer;
synchronized (deviceLock) {
oldSynchronizer = this.synchronizer;
this.synchronizer = synchronizer;
}
if (oldSynchronizer != null) {
oldSynchronizer.runAsyncMessages(true);
}
}
/**
* Gets the synchronizer used by the display.
*
* @return the receiver's synchronizer
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.3
*/
public Synchronizer getSynchronizer() {
checkDevice ();
return synchronizer;
}
/**
* Returns the thread that has invoked syncExec
* or null if no such runnable is currently being invoked by
* the user-interface thread.
*
* Note: If a runnable invoked by asyncExec is currently
* running, this method will return null.
*
*
* @return the receiver's sync-interface thread
*
* @exception SWTException
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.3
*/
public Thread getSyncThread () {
synchronized( deviceLock ) {
if( isDisposed() ) {
error( SWT.ERROR_DEVICE_DISPOSED );
}
return synchronizer.syncThread;
}
}
/**
* Causes the run()
method of the runnable to
* be invoked by the user-interface thread at the next
* reasonable opportunity. Note that the user-interface thread may change
* per user-request. The caller of this method continues
* to run in parallel, and is not notified when the
* runnable has completed. Specifying null
as the
* runnable simply wakes the user-interface thread when run.
*
* 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.
*
*
* @param runnable code to run on the user-interface thread or null
*
* @exception SWTException
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #syncExec
*/
public void asyncExec( Runnable runnable ) {
synchronized( deviceLock ) {
if( isDisposed() ) {
error( SWT.ERROR_DEVICE_DISPOSED );
}
synchronizer.asyncExec( runnable );
}
}
/**
* Causes the run()
method of the runnable to
* be invoked by the user-interface thread at the next
* reasonable opportunity. Note that the user-interface thread may change
* per user-request. The thread which calls this method
* is suspended until the runnable completes. Specifying null
* as the runnable simply wakes the user-interface thread.
*
* 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.
*
*
* @param runnable code to run on the user-interface thread or null
*
* @exception SWTException
* - ERROR_FAILED_EXEC - if an exception occured when executing the runnable
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #asyncExec
*/
public void syncExec( Runnable runnable ) {
Synchronizer synchronizer;
synchronized( deviceLock ) {
if( isDisposed() ) {
error( SWT.ERROR_DEVICE_DISPOSED );
}
synchronizer = this.synchronizer;
}
synchronizer.syncExec( runnable );
}
/**
* Causes the run()
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.
*
* 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.
*
*
* @param milliseconds the delay before running the runnable
* @param runnable code to run on the user-interface thread
*
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the runnable is null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #asyncExec
* @since 1.2
*/
public void timerExec( int milliseconds, Runnable runnable ) {
checkDevice();
if( runnable == null ) {
error( SWT.ERROR_NULL_ARGUMENT );
}
if( scheduler == null ) {
scheduler = createTimerExecScheduler();
}
scheduler.cancel( runnable );
if( milliseconds >= 0 ) {
scheduler.schedule( milliseconds, runnable );
}
}
TimerExecScheduler createTimerExecScheduler() {
return new TimerExecScheduler( this );
}
/**
* Reads an event from the event queue,
* dispatches it appropriately, and returns true
* if there is potentially more work to do, or false
* if the caller can sleep until another event is placed on
* the event queue.
*
* In addition to checking the system event queue, this method also
* checks if any inter-thread messages (created by syncExec()
* or asyncExec()
) are waiting to be processed, and if
* so handles them before returning.
*
*
* @return false
if the caller can sleep upon return from this method
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
* - ERROR_FAILED_EXEC - if an exception occurred while running an inter-thread message
*
*
* @see #sleep
* @see #wake
*
* @since 1.1
*/
public boolean readAndDispatch() {
checkDevice();
return safeReadAndDispatch();
}
private boolean safeReadAndDispatch() {
boolean result = false;
try {
runSkin();
runDeferredLayouts();
result = runPendingMessages();
} catch( RuntimeException runtimeException ) {
handleException( runtimeException );
} catch( Error error ) {
handleException( error );
throw error;
}
return result;
}
private boolean runPendingMessages() {
boolean result = false;
if( PhaseId.PREPARE_UI_ROOT.equals( CurrentPhase.get() )
|| PhaseId.PROCESS_ACTION.equals( CurrentPhase.get() ) )
{
result = ProcessActionRunner.executeNext();
if( !result ) {
result = executeNextEvent();
}
if( !result ) {
result = synchronizer.runAsyncMessages( false );
}
if( !result ) {
result = executeNextRedraw();
}
}
return result;
}
private static boolean executeNextEvent() {
boolean result = false;
Event[] events = EventList.getInstance().getAll();
while( !result && events.length > 0 ) {
Event event = events[ 0 ];
EventList.getInstance().remove( event );
if( EventUtil.allowProcessing( event ) ) {
event.widget.notifyListeners( event.type, event );
result = true;
} else {
events = EventList.getInstance().getAll();
}
}
return result;
}
private void handleException( Throwable throwable ) {
ExceptionHandler exceptionHandler = getExceptionHandler();
exceptionHandler.handleException( throwable );
}
private ExceptionHandler getExceptionHandler() {
ExceptionHandler result = getApplicationContext().getExceptionHandler();
if( result == null ) {
result = DEFAULT_EXCEPTION_HANDLER;
}
return result;
}
/**
* Causes the user-interface thread to sleep (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 true
if an event requiring dispatching was placed on the queue.
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #wake
*
* @since 1.1
*/
public boolean sleep() {
checkDevice();
LifeCycle lifeCycle = getApplicationContext().getLifeCycleFactory().getLifeCycle();
lifeCycle.sleep();
// return true as we cannot reliably determinate what actually caused
// lifeCycle#sleep() to return
return true;
}
/**
* Notifies the client to send a request in order to wake up a sleeping UI thread and to perform
* pending UI updates. Note that this method may be called from any thread.
*
* Note that this method has no effect unless a {@link ServerPushSession} is active.
*
*
* @exception SWTException
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*/
public void wake() {
synchronized( deviceLock ) {
if( isDisposed() ) {
error( SWT.ERROR_DEVICE_DISPOSED );
}
if( thread != Thread.currentThread() ) {
uiSession.exec( new Runnable() {
@Override
public void run() {
synchronizer.asyncExec( new WakeRunnable() );
}
} );
}
}
}
protected void wakeThread() {
uiSession.exec( new Runnable() {
@Override
public void run() {
ServerPushManager.getInstance().wakeClient();
}
} );
}
Object getDeviceLock() {
return deviceLock;
}
//////////
// Redraw
void redrawControl( Control control, boolean redraw ) {
if( redraw ) {
if( redrawControls == null ) {
redrawControls = new LinkedList<>();
}
if( !redrawControls.contains( control ) ) {
redrawControls.add( control );
}
} else {
if( redrawControls != null ) {
redrawControls.remove( control );
}
}
}
boolean needsRedraw( Control control ) {
return redrawControls != null && redrawControls.contains( control );
}
private boolean executeNextRedraw() {
boolean result = false;
if( redrawControls != null ) {
Iterator iterator = redrawControls.iterator();
if( iterator.hasNext() ) {
Control control = iterator.next();
WidgetUtil.getLCA( control ).doRedrawFake( control );
redrawControls.remove( control );
result = true;
}
}
return result;
}
//////////////////////
// Information methods
/**
* 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 null
* @exception SWTException
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
* @since 1.4
*/
public Tray getSystemTray() {
checkDevice();
return null;
}
/**
* Returns the single instance of the application menu bar or null
* when there is no application menu bar for the platform.
*
* @return the application menu bar or null
*
* @exception SWTException
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.4
*/
public Menu getMenuBar() {
checkDevice();
return null;
}
/**
* Returns the single instance of the system taskBar or null
* when there is no system taskBar available for the platform.
*
* @return the system taskBar or null
*
* @exception SWTException
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.4
*/
public TaskBar getSystemTaskBar() {
checkDevice();
return null;
}
/**
* Returns the single instance of the system-provided menu for the application.
* On platforms where no menu is provided for the application this method returns null.
*
* @return the system menu or null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.4
*/
public Menu getSystemMenu() {
checkDevice();
return null;
}
@Override
public Color getSystemColor( int id ) {
checkDevice();
Color result = null;
CssValue value = null;
switch( id ) {
case SWT.COLOR_WIDGET_DARK_SHADOW:
value = ThemeUtil.getCssValue( "Display",
"rwt-darkshadow-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_WIDGET_NORMAL_SHADOW:
value = ThemeUtil.getCssValue( "Display",
"rwt-shadow-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_WIDGET_LIGHT_SHADOW:
value = ThemeUtil.getCssValue( "Display",
"rwt-lightshadow-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW:
value = ThemeUtil.getCssValue( "Display",
"rwt-highlight-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_WIDGET_BORDER:
value = ThemeUtil.getCssValue( "Display",
"rwt-thinborder-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_WIDGET_BACKGROUND:
// TODO [rst] Revise element name
value = ThemeUtil.getCssValue( "NONE",
"background-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_WIDGET_FOREGROUND:
// TODO [rst] Revise element name
value = ThemeUtil.getCssValue( "NONE", "color", SimpleSelector.DEFAULT );
break;
case SWT.COLOR_LIST_FOREGROUND:
value = ThemeUtil.getCssValue( "List", "color", SimpleSelector.DEFAULT );
break;
case SWT.COLOR_LIST_BACKGROUND:
value = ThemeUtil.getCssValue( "List",
"background-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_LIST_SELECTION:
value = ThemeUtil.getCssValue( "List-Item",
"background-color",
SimpleSelector.SELECTED );
break;
case SWT.COLOR_LIST_SELECTION_TEXT:
value = ThemeUtil.getCssValue( "List-Item",
"color",
SimpleSelector.SELECTED );
break;
case SWT.COLOR_INFO_FOREGROUND:
value = ThemeUtil.getCssValue( "Widget-ToolTip",
"color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_INFO_BACKGROUND:
value = ThemeUtil.getCssValue( "Display",
"rwt-infobackground-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_TITLE_FOREGROUND:
value = ThemeUtil.getCssValue( "Shell-Titlebar",
"color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_TITLE_INACTIVE_FOREGROUND:
value = ThemeUtil.getCssValue( "Shell-Titlebar",
"color",
SimpleSelector.INACTIVE );
break;
case SWT.COLOR_TITLE_BACKGROUND:
value = ThemeUtil.getCssValue( "Shell-Titlebar",
"background-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_TITLE_INACTIVE_BACKGROUND:
value = ThemeUtil.getCssValue( "Shell-Titlebar",
"background-color",
SimpleSelector.INACTIVE );
break;
case SWT.COLOR_TITLE_BACKGROUND_GRADIENT:
value = ThemeUtil.getCssValue( "Shell-Titlebar",
"background-gradient-color",
SimpleSelector.DEFAULT );
break;
case SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT:
value = ThemeUtil.getCssValue( "Shell-Titlebar",
"background-gradient-color",
SimpleSelector.INACTIVE );
break;
default:
result = super.getSystemColor( id );
}
if( value != null ) {
result = CssColor.createColor( ( CssColor )value );
if( result == null ) {
// TODO [rst] Revise: theming must prevent transparency for system colors
throw new IllegalArgumentException( "Transparent system color" );
}
}
return result;
}
/**
* Returns the matching standard platform image for the given
* constant, which should be one of the icon constants
* specified in class SWT
. This image should
* not be free'd because it was allocated by the system,
* not the application. A value of null
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 null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see SWT#ICON_ERROR
* @see SWT#ICON_INFORMATION
* @see SWT#ICON_QUESTION
* @see SWT#ICON_WARNING
* @see SWT#ICON_WORKING
*/
public Image getSystemImage( int id ) {
checkDevice();
Image result = null;
switch( id ) {
case SWT.ICON_ERROR:
result = createSystemImage( "rwt-error-image" );
break;
case SWT.ICON_INFORMATION:
result = createSystemImage( "rwt-information-image" );
break;
case SWT.ICON_QUESTION:
result = createSystemImage( "rwt-question-image" );
break;
case SWT.ICON_WARNING:
result = createSystemImage( "rwt-warning-image" );
break;
case SWT.ICON_WORKING:
result = createSystemImage( "rwt-working-image" );
break;
}
return result;
}
private static Image createSystemImage( String cssProperty ) {
Image result = null;
CssValue cssValue = ThemeUtil.getCssValue( "Display", cssProperty, SimpleSelector.DEFAULT );
if( cssValue != null ) {
try {
result = CssImage.createSwtImage( ( CssImage )cssValue );
} catch( IOException ioe ) {
throw new RuntimeException( "Could not read system image", ioe );
}
}
return result;
}
/**
* Returns the matching standard platform cursor for the given
* constant, which should be one of the cursor constants
* specified in class SWT
. This cursor should
* not be free'd because it was allocated by the system,
* not the application. A value of null
will
* be returned if the supplied constant is not an SWT cursor
* constant.
*
* @param id the SWT cursor constant
* @return the corresponding cursor or null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see SWT#CURSOR_ARROW
* @see SWT#CURSOR_WAIT
* @see SWT#CURSOR_CROSS
* @see SWT#CURSOR_HELP
* @see SWT#CURSOR_SIZEALL
* @see SWT#CURSOR_SIZENS
* @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_IBEAM
* @see SWT#CURSOR_HAND
*
* @since 1.3
*/
public Cursor getSystemCursor( int id ) {
checkDevice();
return getApplicationContext().getResourceFactory().getCursor( id );
}
/**
* Returns the longest duration, in milliseconds, between
* two mouse button clicks that will be considered a
* double click .
*
* @return the double click time
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.2
*/
public int getDoubleClickTime() {
checkDevice();
return DOUBLE_CLICK_TIME;
}
/**
* 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 or null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.3
*/
public Control getCursorControl () {
checkDevice();
ControlFinder finder = new ControlFinder( this, getCursorLocation() );
return finder.getControl();
}
/**
* Returns the button dismissal alignment, one of LEFT
or RIGHT
.
* 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 LEFT
, the
* button ordering should be OK/CANCEL. When button dismissal alignment is RIGHT
,
* the button ordering should be CANCEL/OK.
*
* @return the button dismissal order
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.3
*/
public int getDismissalAlignment() {
checkDevice();
return SWT.LEFT;
}
/**
* Returns true when the high contrast mode is enabled.
* Otherwise, false is returned.
*
* Note: This operation is a hint and is not supported on
* platforms that do not have this concept.
*
*
* @return the high contrast mode
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.3
*/
public boolean getHighContrast() {
checkDevice();
return false;
}
/**
* Returns the location of the on-screen pointer relative
* to the top left corner of the screen.
*
* @return the cursor location
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.3
*/
public Point getCursorLocation() {
checkDevice();
return new Point( cursorLocation.x, cursorLocation.y );
}
//////////
// Filters
/**
* 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 SWT
. When the
* event does occur, the listener is notified by sending it the
* handleEvent()
message.
*
* Setting the type of an event to SWT.None
from within the
* handleEvent()
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.
*
*
* NOTE: In RAP, only events that have a matching listener registered on the
* event's source widget are processed on the server. One exception are key events, for which a
* whitelist can be define using {@link org.eclipse.rap.rwt.RWT#ACTIVE_KEYS RWT#ACTIVE_KEYS}.
*
*
* @param eventType the type of event to listen for
* @param listener the listener which should be notified when the event occurs
* @exception IllegalArgumentException
*
* - ERROR_NULL_ARGUMENT - if the listener is null
*
* @exception SWTException
*
* - ERROR_THREAD_INVALID_ACCESS - if not called from the
* thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been
* disposed
*
* @see Listener
* @see SWT
* @see #removeFilter
* @see #removeListener
*/
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 );
}
/**
* 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 SWT
.
*
* @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
*
* - ERROR_NULL_ARGUMENT - if the listener is null
*
* @exception SWTException
*
* - ERROR_THREAD_INVALID_ACCESS - if not called from the
* thread that created the receiver
*
* @see Listener
* @see SWT
* @see #addFilter
* @see #addListener
*/
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;
}
}
boolean filters( int eventType ) {
return filterTable != null ? filterTable.hooks( eventType ) : false;
}
void filterEvent( Event event ) {
if( filterTable != null ) {
filterTable.sendEvent( event );
}
}
void addLayoutDeferred( Composite comp ) {
if( layoutDeferred == null ) {
layoutDeferred = new Composite[ 64 ];
}
if( layoutDeferredCount == layoutDeferred.length ) {
Composite[] temp = new Composite[ layoutDeferred.length + 64 ];
System.arraycopy( layoutDeferred, 0, temp, 0, layoutDeferred.length );
layoutDeferred = temp;
}
layoutDeferred[ layoutDeferredCount++ ] = comp;
}
boolean runDeferredLayouts() {
boolean result = false;
if( layoutDeferredCount != 0 ) {
Composite[] temp = layoutDeferred;
int count = layoutDeferredCount;
layoutDeferred = null;
layoutDeferredCount = 0;
for( int i = 0; i < count; i++ ) {
Composite comp = temp[ i ];
if( !comp.isDisposed() ) {
comp.setLayoutDeferred( false );
}
}
result = true;
}
return result;
}
///////////////////
// Skinning support
void addSkinnableWidget( Widget widget ) {
if( skinList == null ) {
skinList = new Widget[ GROW_SIZE ];
}
if( skinCount >= skinList.length ) {
Widget[] newSkinWidgets = new Widget[ skinList.length + GROW_SIZE ];
System.arraycopy( skinList, 0, newSkinWidgets, 0, skinList.length );
skinList = newSkinWidgets;
}
skinList[ skinCount++ ] = widget;
}
boolean runSkin() {
boolean result = false;
if( skinCount > 0 ) {
Widget[] oldSkinWidgets = skinList;
int count = skinCount;
skinList = new Widget[ GROW_SIZE ];
skinCount = 0;
for( int i = 0; i < count; i++ ) {
Widget widget = oldSkinWidgets[ i ];
if( widget != null && !widget.isDisposed() ) {
widget.removeState( Widget.SKIN_NEEDED );
oldSkinWidgets[ i ] = null;
sendSkinEvent( widget );
}
}
result = true;
}
return result;
}
private void sendSkinEvent( Widget widget ) {
Event event = new Event();
event.widget = widget;
sendEvent( SWT.Skin, event );
}
///////////////
// Data methods
/**
* Returns the application defined, display specific data
* associated with the receiver, or null if it has not been
* set. The display specific data is a single,
* unnamed field that is stored with every display.
*
* 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
* disposeExec()
handler which does so.
*
*
* @return the display specific data
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #setData(Object)
* @see #disposeExec(Runnable)
*
* @since 1.2
*/
public Object getData() {
checkDevice();
return data;
}
/**
* Sets the application defined, display specific data
* associated with the receiver, to the argument.
* The display specific data is a single,
* unnamed field that is stored with every display.
*
* 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
* disposeExec()
handler which does so.
*
*
* @param data the new display specific data
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #getData()
* @see #disposeExec(Runnable)
*
* @since 1.2
*/
public void setData( Object data ) {
checkDevice();
this.data = data;
}
/**
* Sets the application defined property of the receiver
* with the specified name to the given argument.
*
* 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
* disposeExec()
handler which does so.
*
*
* @param key the name of the property
* @param value the new value for the property
*
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the key is null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #getData(String)
* @see #disposeExec(Runnable)
*
* @since 1.2
*/
// [bm]: This is a verbatim copy of SWT, thus no reformatting was done.
public void setData( String key, Object value ) {
checkDevice ();
if (key == null) {
error (SWT.ERROR_NULL_ARGUMENT);
}
/* 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
* 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
* disposeExec()
handler which does so.
*
*
* @param key the name of the property
* @return the value of the property or null if it has not been set
*
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the key is null
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that
* created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see #setData(String, Object)
* @see #disposeExec(Runnable)
*
* @since 1.2
*/
// [bm] This is a verbatim copy of SWT, thus no reformatting was done.
public Object getData( String key ) {
checkDevice ();
if( key == null ) {
error (SWT.ERROR_NULL_ARGUMENT);
}
if (keys == null) {
return null;
}
for (int i=0; i
* Specifying null
for the name clears it.
*
*
* @param name the new app name or null
*
* @since 1.3
*/
public static void setAppName( String name ) {
UISession session = ContextProvider.getUISession();
session.setAttribute( APP_NAME, name );
}
/**
* Sets the application version to the argument.
*
* @param version the new app version
*
* @since 1.3
*/
public static void setAppVersion( String version ) {
UISession session = ContextProvider.getUISession();
session.setAttribute( APP_VERSION, version );
}
/**
* Forces all outstanding paint requests for the display
* to be processed before this method returns.
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @see Control#update()
*
* @since 1.3
*/
public void update() {
checkDevice();
}
/**
* Causes the system hardware to emit a short sound
* (if it supports this capability).
*
* @exception SWTException
* - ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
* - ERROR_DEVICE_DISPOSED - if the receiver has been disposed
*
*
* @since 1.3
*/
public void beep() {
checkDevice();
beep = true;
}
/**
* Returns true if a touch-aware input device is attached to the system,
* enabled, and ready for use.
*
* @since 1.4
*/
public boolean getTouchEnabled() {
checkDevice();
return false;
}
@SuppressWarnings("unchecked")
private void register() {
synchronized( Device.class ) {
boolean registered = false;
WeakReference[] displays = getDisplays();
for( int i = 0; !registered && i < displays.length; i++ ) {
if( canDisplayRefBeReplaced( displays[ i ] ) ) {
displays[ i ] = new WeakReference<>( this );
registered = true;
}
}
if( !registered ) {
WeakReference[] newDisplays = new WeakReference[ displays.length + 4 ];
System.arraycopy( displays, 0, newDisplays, 0, displays.length );
newDisplays[ displays.length ] = new WeakReference<>( this );
setDisplays( newDisplays );
}
}
}
private boolean canDisplayRefBeReplaced( WeakReference displayRef ) {
boolean result = false;
if( displayRef == null ) {
result = true;
} else {
Display display = displayRef.get();
if( display == null || display.thread == thread ) {
result = true;
}
}
return result;
}
private void deregister() {
synchronized( Device.class ) {
WeakReference[] displays = getDisplays();
for( int i = 0; i < displays.length; i++ ) {
WeakReference current = displays[ i ];
if( current != null && this == current.get() ) {
displays[ i ] = null;
}
}
}
}
private static WeakReference[] getDisplays() {
return ContextProvider.getApplicationContext().getDisplaysHolder().getDisplays();
}
private void setDisplays( WeakReference[] displays ) {
getApplicationContext().getDisplaysHolder().setDisplays( displays );
}
/////////////////////
// Consistency checks
@SuppressWarnings( "unused" )
static boolean isValidClass( Class> clazz ) {
// String name = clazz.getName();
// int index = name.lastIndexOf( '.' );
// return name.substring( 0, index + 1 ).equals( PACKAGE_PREFIX );
return true;
}
boolean isValidThread () {
return thread == Thread.currentThread();
}
@Override
protected void checkDevice() {
if( !isValidThread() ) {
error( SWT.ERROR_THREAD_INVALID_ACCESS );
}
if( isDisposed() ) {
error( SWT.ERROR_DEVICE_DISPOSED );
}
}
//////////////////
// Helping methods
/**
* Does whatever display specific cleanup is required, and then uses the code
* in SWTError.error
to handle the error.
*
* @param code the descriptive error code
* @see SWT#error(int)
*/
void error( int code ) {
SWT.error( code );
}
private Rectangle readInitialBounds() {
JsonValue value = readPropertyValue( getId( this ), BOUNDS );
return value != null ? readRectangle( value ) : new Rectangle( 0, 0, 1024, 768 );
}
private Point readDPI() {
JsonValue value = readPropertyValue( getId( this ), DPI );
return value != null ? readPoint( value ) : new Point( 0, 0 );
}
private int readDepth() {
JsonValue value = readPropertyValue( getId( this ), COLOR_DEPTH );
return value != null ? value.asInt() : 16;
}
/////////////////
// Inner classes
private static class WakeRunnable implements Runnable, SerializableCompatibility {
@Override
public void run() {
}
}
private static final class ControlFinder {
private final Display display;
private final Point location;
private final Set foundComponentInParent;
private Control control;
ControlFinder( Display display, Point location ) {
this.display = display;
this.location = new Point( location.x, location.y );
foundComponentInParent = new HashSet<>();
find();
}
Control getControl() {
return control;
}
private void find() {
Shell[] shells = display.getShells();
for( int i = 0; control == null && i < shells.length; i++ ) {
WidgetTreeUtil.accept( shells[ i ], new WidgetTreeVisitor() {
@Override
public boolean visit( Widget widget ) {
if( widget instanceof Control ) {
return visitControl( ( Control )widget );
}
return true;
}
} );
}
}
private boolean visitControl( Control control ) {
Rectangle bounds = getAbsoluteBounds( control );
boolean result = false;
if( control.isVisible() && bounds.contains( location ) ) {
/*
* only assign control to cursor location if there was no other control
* already assigned within the same composite
*/
result = foundComponentInParent.add( control.getParent() );
if( result ) {
this.control = control;
}
}
return result;
}
private static Rectangle getAbsoluteBounds( Control control ) {
Rectangle bounds = control.getBounds();
Point origin = getAbsoluteOrigin( control );
return new Rectangle( origin.x, origin.y, bounds.width, bounds.height );
}
}
private final class DisplayAdapter implements IDisplayAdapter {
@Override
public void setBounds( Rectangle bounds ) {
Display.this.bounds.x = bounds.x;
Display.this.bounds.y = bounds.y;
Display.this.bounds.width = bounds.width;
Display.this.bounds.height = bounds.height;
}
@Override
public void setCursorLocation( int x, int y ) {
cursorLocation.x = x;
cursorLocation.y = y;
}
@Override
public void setActiveShell( Shell activeShell ) {
Display.this.setActiveShell( activeShell );
}
@Override
public void setFocusControl( Control focusControl, boolean fireEvents ) {
Display.this.setFocusControl( focusControl, fireEvents );
}
@Override
public void invalidateFocus() {
ContextProvider.getServiceStore().setAttribute( ATTR_INVALIDATE_FOCUS, Boolean.TRUE );
}
@Override
public boolean isFocusInvalidated() {
Object value = ContextProvider.getServiceStore().getAttribute( ATTR_INVALIDATE_FOCUS );
return value != null;
}
@Override
public Shell[] getShells() {
Shell[] result = new Shell[ shells.size() ];
shells.toArray( result );
return result;
}
@Override
public UISession getUISession() {
return uiSession;
}
@Override
public void attachThread() {
Display.this.attachThread();
}
@Override
public void detachThread() {
Display.this.detachThread();
}
@Override
public boolean isValidThread() {
return Display.this.isValidThread();
}
@Override
public boolean isBeepCalled() {
return beep;
}
@Override
public void resetBeep() {
beep = false;
}
@Override
public void notifyListeners( int eventType, Event event ) {
Display.this.notifyListeners( eventType, event );
}
@Override
public boolean isListening( int eventType ) {
return Display.this.isListening( eventType );
}
}
}