/******************************************************************************* * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.widgets; import java.util.*; import java.util.function.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.cocoa.*; /** * 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.
*
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.)
* 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.
*
* IMPORTANT: This class is not intended to be subclassed. *
* @see #syncExec * @see #asyncExec * @see #wake * @see #readAndDispatch * @see #sleep * @see Device#dispose * @see Display snippets * @see Sample code and further information * @noextend This class is not intended to be subclassed by clients. */ @SuppressWarnings({"rawtypes", "unchecked"}) public class Display extends Device { static byte[] types = {'*','\0'}; static int size = C.PTR_SIZEOF, align = C.PTR_SIZEOF == 4 ? 2 : 3; /* Mac Dark and Light appearance */ enum APPEARANCE { Dark, Light, } APPEARANCE appAppearance; /* Windows and Events */ Event [] eventQueue; EventTable eventTable, filterTable; boolean disposing; int sendEventCount; /* gesture event state */ double rotation; double magnification; boolean gestureActive; /* touch event state */ int touchCounter; long primaryIdentifier; NSMutableArray currentTouches; TouchSource[] touchSources; /* Sync/Async Widget Communication */ Synchronizer synchronizer; ConsumerhandleEvent()
* 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.
*
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 run()
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 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 ornull
*
* @exception SWTException
* IMPORTANT: See the comment in Widget.checkSubclass()
.
*
* 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
* This method is called before init
.
*
release
.
*
* @see Device#dispose
* @see #release
*/
@Override
protected void destroy () {
if (this == Default) Default = null;
deregister (this);
destroyDisplay ();
}
void destroyDisplay () {
application = null;
}
/**
* 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 * IMPORTANT: This method should not be called from * application code. The arguments are platform-specific. *
* * @param handle the handle for the widget * @return the SWT widget that the handle represents * * @exception SWTExceptionWidget
subclass which represents
* the handle/id pair in the currently running application,
* if such exists, or null if no matching widget can be found.
* * IMPORTANT: This method should not be called from * application code. The arguments are platform-specific. *
* * @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 SWTExceptionWidget
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 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 (int i=0; inull
*
* @exception SWTException
* 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.
*
* 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.
*
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 null
*
* @exception SWTException * Note: This operation is a hint and is not supported on * platforms that do not have this concept. *
* * @return the high contrast mode * * @exception SWTExceptionsyncExec
* 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 SWTExceptionSWT
. 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 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 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 null
if there is no application menu bar for the platform.
*
* @return the application menu bar, or null
*
* @exception SWTException null
on platforms where no menu is provided for the application.
*
* @return the system menu, or null
*
* @exception SWTException null
*
* @exception SWTException null
*
* @exception SWTException true
if a touch-aware input device is detected, or false
otherwise
*
* @exception SWTException
* This method is called after create
.
*
* IMPORTANT: This method is not part of the public
* API for Display
. 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.
*
* IMPORTANT: This method is not part of the public
* API for Display
. 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.
*
post
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.
* * 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. *
** Event Types: *
KeyDown, KeyUp *
The following fields in the Event
apply:
*
Either one of:
*SWT
Optional (on some platforms):
*SWT
* MouseDown, MouseUp
*The following fields in the Event
apply:
*
MouseMove
*The following fields in the Event
apply:
*
MouseWheel
*The following fields in the Event
apply:
* 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 sourceControl
or null
* @param to the destination Control
or null
* @param point to be mapped
* @return point with mapped coordinates
*
* @exception IllegalArgumentException * 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 sourceControl
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 * 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 sourceControl
or null
* @param to the destination Control
or null
* @param rectangle to be mapped
* @return rectangle with mapped coordinates
*
* @exception IllegalArgumentException * 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 sourceControl
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 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.
*
false
if the caller can sleep upon return from this method
*
* @exception SWTException true
when sent the message
* isDisposed()
.
*
* 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 release
. 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 destroy
.
*
destroy
.
*
* @see Device#dispose
* @see #destroy
*/
@Override
protected void release () {
disposing = true;
sendEvent (SWT.Dispose, new Event ());
Shell [] shells = getShells ();
for (int i=0; iSWT
.
*
* @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 SWT
.
*
* @param eventType the type of event to listen for
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException
* Specifying null
for the name clears it.
*
null
*/
public static void setAppName (String name) {
APP_NAME = name;
}
/**
* Sets the application version to the argument.
*
* @param version the new app version
*
* @since 3.6
*/
public static void setAppVersion (String version) {
APP_VERSION = version;
}
//TODO use custom timer instead of timerExec
NSPoint hoverLastLocation;
Runnable hoverTimer = () -> {
if (currentControl != null && !currentControl.isDisposed()) {
currentControl.sendMouseEvent (null, SWT.MouseHover, trackingControl != null && !trackingControl.isDisposed());
}
};
//TODO - use custom timer instead of timerExec
Runnable caretTimer = new Runnable () {
@Override
public void run () {
if (currentCaret != null) {
if (currentCaret == null || currentCaret.isDisposed()) return;
if (currentCaret.blinkCaret ()) {
int blinkRate = currentCaret.blinkRate;
if (blinkRate != 0) timerExec (blinkRate, this);
} else {
currentCaret = null;
}
}
}
};
//TODO - use custom timer instead of timerExec
Runnable defaultButtonTimer = new Runnable() {
@Override
public void run() {
if (isDisposed ()) return;
Shell shell = getActiveShell();
if (shell != null && !shell.isDisposed()) {
Button defaultButton = shell.defaultButton;
if (defaultButton != null && !defaultButton.isDisposed()) {
NSView view = defaultButton.view;
view.display();
}
}
if (isDisposed ()) return;
if (hasDefaultButton()) timerExec(DEFAULT_BUTTON_INTERVAL, this);
}
};
void setCurrentCaret (Caret caret) {
currentCaret = caret;
int blinkRate = currentCaret != null ? currentCaret.blinkRate : -1;
timerExec (blinkRate, caretTimer);
}
void setCursor (Control control) {
Cursor cursor = null;
if (control != null && !control.isDisposed()) cursor = control.findCursor ();
if (cursor == null) {
NSWindow window = application.keyWindow();
if (window != null) {
if (window.areCursorRectsEnabled ()) {
window.disableCursorRects ();
window.enableCursorRects ();
}
return;
}
cursor = getSystemCursor (SWT.CURSOR_ARROW);
}
lockCursor = false;
cursor.handle.set ();
lockCursor = true;
}
/**
* Sets the location of the on-screen pointer relative to the top left corner
* of the screen. Note: It is typically considered bad practice for a
* program to move the on-screen pointer location.
*
* @param x the new x coordinate for the cursor
* @param y the new y coordinate for the cursor
*
* @exception SWTException
* 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.
*
* 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.
*
* The default SWT error handling policy is to rethrow exceptions.
*
* @param runtimeExceptionHandler new exception handler to be registered.
* @since 3.106
*/
public final void setRuntimeExceptionHandler (Consumer
* The default SWT error handling policy is to rethrow exceptions.
*
* @param errorHandler new error handler to be registered.
* @since 3.106
*/
public final void setErrorHandler (Consumer
* 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.
*
* 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.
* null
.
* @since 3.106
*/
public final Consumernull
.
* @since 3.106
*/
public final Consumertrue
if an event requiring dispatching was placed on the queue.
*
* @exception SWTException
*
*
* @see #wake
*/
public boolean sleep () {
checkDevice ();
if (getMessageCount () != 0) return true;
sendPreExternalEventDispatchEvent ();
try {
addPool();
allowTimers = runAsyncMessages = false;
NSRunLoop.currentRunLoop().runMode(OS.NSDefaultRunLoopMode, NSDate.distantFuture());
allowTimers = runAsyncMessages = true;
} finally {
removePool();
}
sendPostExternalEventDispatchEvent ();
return true;
}
int sourceProc (int info) {
return 0;
}
/**
* Causes the run()
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 null
* as the runnable simply wakes the user-interface thread.
* null
*
* @exception SWTException
*
*
* @see #asyncExec
*/
public void syncExec (Runnable runnable) {
Synchronizer synchronizer;
synchronized (Device.class) {
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.
*
*
* @exception SWTException
*
*
* @see #asyncExec
*/
public void timerExec (int milliseconds, Runnable runnable) {
checkDevice ();
//TODO - remove a timer, reschedule a timer not tested
if (runnable == null) error (SWT.ERROR_NULL_ARGUMENT);
if (timerList == null) timerList = new Runnable [4];
if (nsTimers == null) nsTimers = new NSTimer [4];
int index = 0;
while (index < timerList.length) {
if (timerList [index] == runnable) break;
index++;
}
if (index != timerList.length) {
NSTimer timer = nsTimers [index];
if (timer == null) {
timerList [index] = null;
} else {
if (milliseconds < 0) {
timer.invalidate();
timer.release();
timerList [index] = null;
nsTimers [index] = null;
} else {
timer.setFireDate(NSDate.dateWithTimeIntervalSinceNow (milliseconds / 1000.0));
}
return;
}
}
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;
NSTimer [] newTimerIds = new NSTimer [nsTimers.length + 4];
System.arraycopy (nsTimers, 0, newTimerIds, 0, nsTimers.length);
nsTimers = newTimerIds;
}
NSNumber userInfo = NSNumber.numberWithInt(index);
NSTimer timer = NSTimer.scheduledTimerWithTimeInterval(milliseconds / 1000.0, timerDelegate, OS.sel_timerProc_, userInfo, false);
NSRunLoop runLoop = NSRunLoop.currentRunLoop();
runLoop.addTimer(timer, OS.NSModalPanelRunLoopMode);
runLoop.addTimer(timer, OS.NSEventTrackingRunLoopMode);
timer.retain();
if (timer != null) {
nsTimers [index] = timer;
timerList [index] = runnable;
}
}
long /*int*/ timerProc (long /*int*/ id, long /*int*/ sel, long /*int*/ timerID) {
NSTimer timer = new NSTimer (timerID);
try {
NSNumber number = new NSNumber(timer.userInfo());
int index = number.intValue();
if (timerList == null) return 0;
if (0 <= index && index < timerList.length) {
if (allowTimers) {
Runnable runnable = timerList [index];
timerList [index] = null;
nsTimers [index] = null;
if (runnable != null) {
try {
runnable.run ();
} catch (RuntimeException exception) {
runtimeExceptionHandler.accept (exception);
} catch (Error exception) {
errorHandler.accept (exception);
}
}
} else {
nsTimers [index] = null;
wakeThread ();
}
}
} finally {
timer.invalidate();
timer.release();
}
return 0;
}
/**
* Forces all outstanding paint requests for the display
* to be processed before this method returns.
*
* @exception SWTException
*
*
* @see Control#update()
*/
public void update () {
checkDevice ();
Shell [] shells = getShells ();
for (int i=0; i
*
*
* @see #sleep
*/
public void wake () {
synchronized (Device.class) {
if (isDisposed ()) error (SWT.ERROR_DEVICE_DISPOSED);
if (thread == Thread.currentThread ()) return;
wakeThread ();
}
}
void wakeThread () {
//new pool?
NSObject object = new NSObject().alloc().init();
object.performSelectorOnMainThread(OS.sel_release, null, false);
}
Control findControl (boolean checkTrim) {
return findControl(checkTrim, null);
}
Control findControl (boolean checkTrim, NSView[] hitView) {
NSView view = null;
NSPoint screenLocation = NSEvent.mouseLocation();
long /*int*/ hitWindowNumber = 0;
if (OS.VERSION >= 0x1060) {
hitWindowNumber = NSWindow.windowNumberAtPoint(screenLocation, 0);
} else {
long /*int*/ outWindow[] = new long /*int*/ [1];
OS.FindWindow ((long /*int*/)screenLocation.x, (long /*int*/)(getPrimaryFrame().height - screenLocation.y), outWindow);
if (outWindow[0] != 0) {
hitWindowNumber = OS.HIWindowGetCGWindowID(outWindow[0]);
}
}
NSWindow window = application.windowWithWindowNumber(hitWindowNumber);
if (window != null) {
NSView contentView = window.contentView();
if (contentView != null) contentView = contentView.superview();
if (contentView != null) {
NSPoint location = window.convertScreenToBase(screenLocation);
view = contentView.hitTest (location);
if (view == null && !checkTrim) {
view = contentView;
}
}
}
Control control = null;
if (view != null) {
do {
Widget widget = getWidget (view);
if (widget instanceof Control) {
control = (Control)widget;
break;
}
view = view.superview();
} while (view != null);
}
if (checkTrim) {
if (control != null && control.isTrim (view)) control = null;
}
if (control != null && hitView != null) hitView[0] = view;
return control;
}
void finishLaunching (long /*int*/ id, long /*int*/ sel) {
/*
* [NSApplication finishLaunching] cannot run multiple times otherwise
* multiple main menus are added.
*/
if (launched) return;
launched = true;
objc_super super_struct = new objc_super();
super_struct.receiver = id;
super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
OS.objc_msgSendSuper(super_struct, sel);
}
void applicationDidBecomeActive (long /*int*/ id, long /*int*/ sel, long /*int*/ notification) {
NSWindow keyWindow = application.keyWindow();
if (keyWindow != null) {
keyWindow.orderFrontRegardless();
} else {
setMenuBar (menuBar);
}
checkFocus();
checkEnterExit(findControl(true), null, false);
}
void applicationDidResignActive (long /*int*/ id, long /*int*/ sel, long /*int*/ notification) {
checkFocus();
checkEnterExit(null, null, false);
}
long /*int*/ applicationNextEventMatchingMask (long /*int*/ id, long /*int*/ sel, long /*int*/ mask, long /*int*/ expiration, long /*int*/ mode, long /*int*/ dequeue) {
if (dequeue != 0 && trackingControl != null && !trackingControl.isDisposed()) runDeferredEvents();
sendPreExternalEventDispatchEvent();
try {
objc_super super_struct = new objc_super();
super_struct.receiver = id;
super_struct.super_class = OS.objc_msgSend(id, OS.sel_superclass);
long /*int*/ result = OS.objc_msgSendSuper(super_struct, sel, mask, expiration, mode, dequeue != 0);
if (result != 0) {
/*
* Feature of Cocoa. When an NSComboBox's items list is visible it runs an event
* loop that will close the list in response to a processed NSApplicationDefined
* event.
*
* Mozilla-style Browsers are a common source of NSApplicationDefined events that
* will cause this to happen, which is not desirable in the context of SWT. The
* workaround is to detect this case and to not return the event that would trigger
* this to happen.
*/
if (dequeue != 0 && currentCombo != null && !currentCombo.isDisposed()) {
NSEvent nsEvent = new NSEvent(result);
if (mozillaRunning) {
if (nsEvent.type() == OS.NSApplicationDefined) {
return 0;
}
}
if (nsEvent.type() == OS.NSKeyDown) {
currentCombo.sendTrackingKeyEvent(nsEvent, SWT.KeyDown);
}
}
if (dequeue != 0 && trackingControl != null && !trackingControl.isDisposed()) {
applicationSendTrackingEvent(new NSEvent(result), trackingControl);
}
}
return result;
} finally {
sendPostExternalEventDispatchEvent();
}
}
void applicationSendTrackingEvent (NSEvent nsEvent, Control trackingControl) {
int type = (int)/*64*/nsEvent.type();
boolean runEnterExit = false;
Control runEnterExitControl = null;
switch (type) {
case OS.NSLeftMouseDown:
case OS.NSRightMouseDown:
case OS.NSOtherMouseDown:
clickCount = (int)(clickCountButton == nsEvent.buttonNumber() ? nsEvent.clickCount() : 1);
clickCountButton = (int)nsEvent.buttonNumber();
trackingControl.sendMouseEvent (nsEvent, SWT.MouseDown, true);
break;
case OS.NSLeftMouseUp:
case OS.NSRightMouseUp:
case OS.NSOtherMouseUp:
runEnterExit = true;
runEnterExitControl = findControl(true);
Control control = trackingControl;
this.trackingControl = null;
if (clickCount == 2) {
control.sendMouseEvent (nsEvent, SWT.MouseDoubleClick, false);
}
if (!control.isDisposed()) control.sendMouseEvent (nsEvent, SWT.MouseUp, false);
break;
case OS.NSLeftMouseDragged:
case OS.NSRightMouseDragged:
case OS.NSOtherMouseDragged:
runEnterExit = true;
runEnterExitControl = trackingControl;
//FALL THROUGH
case OS.NSMouseMoved:
trackingControl.sendMouseEvent (nsEvent, SWT.MouseMove, true);
break;
}
if (runEnterExit) {
if (runEnterExitControl == null || !runEnterExitControl.isDisposed()) checkEnterExit (runEnterExitControl, nsEvent, false);
}
}
void applicationSendEvent (long /*int*/ id, long /*int*/ sel, long /*int*/ event) {
NSEvent nsEvent = new NSEvent(event);
NSWindow window = nsEvent.window ();
if (performKeyEquivalent(window, nsEvent)) return;
int type = (int)/*64*/nsEvent.type ();
boolean activate = false, down = false;
switch (type) {
case OS.NSLeftMouseDown:
case OS.NSRightMouseDown:
case OS.NSOtherMouseDown:
activate = down = true;
case OS.NSLeftMouseUp:
case OS.NSRightMouseUp:
case OS.NSOtherMouseUp:
activate = true;
case OS.NSLeftMouseDragged:
case OS.NSRightMouseDragged:
case OS.NSOtherMouseDragged:
case OS.NSMouseMoved:
case OS.NSMouseEntered:
case OS.NSMouseExited:
case OS.NSKeyDown:
case OS.NSKeyUp:
case OS.NSScrollWheel:
// TODO: Add touch detection here...
if (window != null) {
Shell shell = (Shell) getWidget (window.id);
if (shell != null) {
Shell modalShell = shell.getModalShell ();
if (modalShell != null) {
if (activate) {
if (application.isActive()) {
modalShell.window.orderFrontRegardless();
} else {
application.activateIgnoringOtherApps(true);
}
if (down) {
NSRect rect = window.contentView().frame();
NSPoint pt = window.convertBaseToScreen(nsEvent.locationInWindow());
if (OS.NSPointInRect(pt, rect)) beep ();
}
}
return;
}
}
}
break;
}
if (type != OS.NSAppKitDefined) sendEvent = true;
/*
* Feature in Cocoa. The help key triggers context-sensitive help but doesn't get forwarded to the window as a key event.
* If the event is destined for the key window, is the help key, and is an NSKeyDown, send it directly to the window first.
*/
if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyDown && (nsEvent.modifierFlags() & OS.NSHelpKeyMask) != 0) {
window.sendEvent(nsEvent);
}
/*
* Feature in Cocoa. NSKeyUp events are not delivered to the window if the command key is down.
* If the event is destined for the key window, and it's a key up and the command key is down, send it directly to the window.
*/
if (window != null && window.isKeyWindow() && nsEvent.type() == OS.NSKeyUp && (nsEvent.modifierFlags() & OS.NSCommandKeyMask) != 0) {
window.sendEvent(nsEvent);
} else {
objc_super super_struct = new objc_super ();
super_struct.receiver = id;
super_struct.super_class = OS.objc_msgSend (id, OS.sel_superclass);
OS.objc_msgSendSuper (super_struct, sel, event);
}
if (type != OS.NSAppKitDefined) sendEvent = false;
}
void applicationWillFinishLaunching (long /*int*/ id, long /*int*/ sel, long /*int*/ notification) {
boolean loaded = false;
/*
* Bug in AWT: If the AWT starts up first when the VM was started on the first thread it assumes that
* a Carbon-based SWT will be used, so it calls NSApplicationLoad(). This causes the Carbon menu
* manager to create an application menu that isn't accessible via NSMenu. It is, however, accessible
* via the Carbon menu manager, so find and delete the menu items it added.
*
* Note that this code will continue to work if Apple does change this. GetIndMenuWithCommandID will
* return a non-zero value indicating failure, which we ignore.
*/
if (isEmbedded) {
long /*int*/ outMenu [] = new long /*int*/ [1];
short outIndex[] = new short[1];
int status = OS.GetIndMenuItemWithCommandID(0, OS.kHICommandHide, 1, outMenu, outIndex);
if (status == 0) OS.DeleteMenuItem(outMenu[0], outIndex[0]);
status = OS.GetIndMenuItemWithCommandID(0, OS.kHICommandHideOthers, 1, outMenu, outIndex);
if (status == 0) OS.DeleteMenuItem(outMenu[0], outIndex[0]);
status = OS.GetIndMenuItemWithCommandID(0, OS.kHICommandShowAll, 1, outMenu, outIndex);
if (status == 0) OS.DeleteMenuItem(outMenu[0], outIndex[0]);
status = OS.GetIndMenuItemWithCommandID(0, OS.kHICommandQuit, 1, outMenu, outIndex);
if (status == 0) OS.DeleteMenuItem(outMenu[0], outIndex[0]);
status = OS.GetIndMenuItemWithCommandID(0, OS.kHICommandServices, 1, outMenu, outIndex);
if (status == 0) OS.DeleteMenuItem(outMenu[0], outIndex[0]);
}
/*
* Get the default locale's language, and then the display name of the language. Some Mac OS X localizations use the
* display name of the language, but many use the ISO two-char abbreviation instead.
*/
Locale loc = Locale.getDefault();
String languageISOValue = loc.getLanguage();
NSLocale englishLocale = (NSLocale) new NSLocale().alloc();
englishLocale = new NSLocale(englishLocale.initWithLocaleIdentifier(NSString.stringWith("en_US")));
NSString languageDisplayName = englishLocale.displayNameForKey(OS.NSLocaleLanguageCode, NSString.stringWith(languageISOValue));
if (englishLocale != null) englishLocale.release();
/* To find the nib look for each of these paths, in order, until one is found:
* /System/Library/..../Resources/