+ if (event instanceof TMenuEvent) {
+ if (onMenu((TMenuEvent) event)) {
+ return;
+ }
+ }
+
+ // Dispatch events to the active window -------------------------------
+ boolean dispatchToDesktop = true;
+ TWindow window = activeWindow;
+ if (window != null) {
+ assert (window.isActive());
+ assert (window.isShown());
+ if (event instanceof TMouseEvent) {
+ TMouseEvent mouse = (TMouseEvent) event;
+ // Convert the mouse relative x/y to window coordinates
+ assert (mouse.getX() == mouse.getAbsoluteX());
+ assert (mouse.getY() == mouse.getAbsoluteY());
+ mouse.setX(mouse.getX() - window.getX());
+ mouse.setY(mouse.getY() - window.getY());
+
+ if (window.mouseWouldHit(mouse)) {
+ dispatchToDesktop = false;
+ }
+ } else if (event instanceof TKeypressEvent) {
+ dispatchToDesktop = false;
+ }
+
+ if (debugEvents) {
+ System.err.printf("TApplication dispatch event: %s\n",
+ event);
+ }
+ window.handleEvent(event);
+ }
+ if (dispatchToDesktop) {
+ // This event is fair game for the desktop to process.
+ if (desktop != null) {
+ desktop.handleEvent(event);
+ }
+ }
+ }
+
+ /**
+ * Dispatch one event to the appropriate widget or application-level
+ * event handler. This is the secondary event handler used by certain
+ * special dialogs (currently TMessageBox and TFileOpenBox).
+ *
+ * @param event the input event to consume
+ * @see #primaryHandleEvent(TInputEvent event)
+ */
+ private void secondaryHandleEvent(final TInputEvent event) {
+ // Peek at the mouse position
+ if (event instanceof TMouseEvent) {
+ TMouseEvent mouse = (TMouseEvent) event;
+ if ((mouseX != mouse.getX()) || (mouseY != mouse.getY())) {
+ oldMouseX = mouseX;
+ oldMouseY = mouseY;
+ mouseX = mouse.getX();
+ mouseY = mouse.getY();
+ }
+ }
+
+ secondaryEventReceiver.handleEvent(event);
+ }
+
+ /**
+ * Enable a widget to override the primary event thread.
+ *
+ * @param widget widget that will receive events
+ */
+ public final void enableSecondaryEventReceiver(final TWidget widget) {
+ if (debugThreads) {
+ System.err.println(System.currentTimeMillis() +
+ " enableSecondaryEventReceiver()");
+ }
+
+ assert (secondaryEventReceiver == null);
+ assert (secondaryEventHandler == null);
+ assert ((widget instanceof TMessageBox)
+ || (widget instanceof TFileOpenBox));
+ secondaryEventReceiver = widget;
+ secondaryEventHandler = new WidgetEventHandler(this, false);
+
+ (new Thread(secondaryEventHandler)).start();
+ }
+
+ /**
+ * Yield to the secondary thread.
+ */
+ public final void yield() {
+ assert (secondaryEventReceiver != null);
+
+ while (secondaryEventReceiver != null) {
+ synchronized (primaryEventHandler) {
+ try {
+ primaryEventHandler.wait();
+ } catch (InterruptedException e) {
+ // SQUASH
+ }
+ }
+ }
+ }
+
+ /**
+ * Do stuff when there is no user input.
+ */
+ private void doIdle() {
+ if (debugThreads) {
+ System.err.printf(System.currentTimeMillis() + " " +
+ Thread.currentThread() + " doIdle()\n");
+ }
+
+ synchronized (timers) {
+
+ if (debugThreads) {
+ System.err.printf(System.currentTimeMillis() + " " +
+ Thread.currentThread() + " doIdle() 2\n");
+ }
+
+ // Run any timers that have timed out
+ Date now = new Date();
+ List<TTimer> keepTimers = new LinkedList<TTimer>();
+ for (TTimer timer: timers) {
+ if (timer.getNextTick().getTime() <= now.getTime()) {
+ // Something might change, so repaint the screen.
+ repaint = true;
+ timer.tick();
+ if (timer.recurring) {
+ keepTimers.add(timer);
+ }
+ } else {
+ keepTimers.add(timer);
+ }
+ }
+ timers = keepTimers;
+ }
+
+ // Call onIdle's
+ for (TWindow window: windows) {
+ window.onIdle();
+ }
+ if (desktop != null) {
+ desktop.onIdle();
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // TWindow management -----------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Return the total number of windows.
+ *
+ * @return the total number of windows
+ */
+ public final int windowCount() {
+ return windows.size();
+ }
+
+ /**
+ * Return the number of windows that are showing.
+ *
+ * @return the number of windows that are showing on screen
+ */
+ public final int shownWindowCount() {
+ int n = 0;
+ for (TWindow w: windows) {
+ if (w.isShown()) {
+ n++;
+ }
+ }
+ return n;
+ }
+
+ /**
+ * Return the number of windows that are hidden.
+ *
+ * @return the number of windows that are hidden
+ */
+ public final int hiddenWindowCount() {
+ int n = 0;
+ for (TWindow w: windows) {
+ if (w.isHidden()) {
+ n++;
+ }
+ }
+ return n;
+ }
+
+ /**
+ * Check if a window instance is in this application's window list.
+ *
+ * @param window window to look for
+ * @return true if this window is in the list
+ */
+ public final boolean hasWindow(final TWindow window) {
+ if (windows.size() == 0) {
+ return false;
+ }
+ for (TWindow w: windows) {
+ if (w == window) {
+ assert (window.getApplication() == this);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Activate a window: bring it to the top and have it receive events.
+ *
+ * @param window the window to become the new active window
+ */
+ public void activateWindow(final TWindow window) {
+ if (hasWindow(window) == false) {
+ /*
+ * Someone has a handle to a window I don't have. Ignore this
+ * request.
+ */
+ return;
+ }
+
+ // Whatever window might be moving/dragging, stop it now.
+ for (TWindow w: windows) {
+ if (w.inMovements()) {
+ w.stopMovements();
+ }
+ }
+
+ assert (windows.size() > 0);
+
+ if (window.isHidden()) {
+ // Unhiding will also activate.
+ showWindow(window);
+ return;
+ }
+ assert (window.isShown());
+
+ if (windows.size() == 1) {
+ assert (window == windows.get(0));
+ if (activeWindow == null) {
+ activeWindow = window;
+ window.setZ(0);
+ activeWindow.setActive(true);
+ activeWindow.onFocus();
+ }
+
+ assert (window.isActive());
+ assert (activeWindow == window);
+ return;
+ }
+
+ if (activeWindow == window) {
+ assert (window.isActive());
+
+ // Window is already active, do nothing.
+ return;