- menuColor);
- getScreen().putStrXY(x + 1, 0, menu.getTitle(), menuColor);
- // Draw the highlight character
- getScreen().putCharXY(x + 1 + menu.getMnemonic().getShortcutIdx(),
- 0, menu.getMnemonic().getShortcut(), menuMnemonicColor);
-
- if (menu.isActive()) {
- menu.drawChildren();
- // Reset the screen clipping so we can draw the next title.
- getScreen().resetClipping();
- }
- x += menu.getTitle().length() + 2;
- }
-
- for (TMenu menu: subMenus) {
- // Reset the screen clipping so we can draw the next sub-menu.
- getScreen().resetClipping();
- menu.drawChildren();
- }
-
- // Draw the mouse pointer
- invertCell(mouseX, mouseY);
-
- // Place the cursor if it is visible
- TWidget activeWidget = null;
- if (sorted.size() > 0) {
- activeWidget = sorted.get(sorted.size() - 1).getActiveChild();
- if (activeWidget.isCursorVisible()) {
- getScreen().putCursor(true, activeWidget.getCursorAbsoluteX(),
- activeWidget.getCursorAbsoluteY());
- cursor = true;
- }
- }
-
- // Kill the cursor
- if (!cursor) {
- getScreen().hideCursor();
- }
-
- // Flush the screen contents
- backend.flushScreen();
-
- repaint = false;
- }
-
- /**
- * Run this application until it exits.
- */
- public void run() {
- while (!quit) {
- // Timeout is in milliseconds, so default timeout after 1 second
- // of inactivity.
- long timeout = 0;
-
- // If I've got no updates to render, wait for something from the
- // backend or a timer.
- if (!repaint
- && ((mouseX == oldMouseX) && (mouseY == oldMouseY))
- ) {
- // Never sleep longer than 100 millis, to get windows with
- // background tasks an opportunity to update the display.
- timeout = getSleepTime(100);
-
- // See if there are any definitely events waiting to be
- // processed. If so, do not wait -- either there is I/O
- // coming in or the primary/secondary threads are still
- // working.
- synchronized (drainEventQueue) {
- if (drainEventQueue.size() > 0) {
- timeout = 0;
- }
- }
- synchronized (fillEventQueue) {
- if (fillEventQueue.size() > 0) {
- timeout = 0;
- }
- }
- }
-
- if (timeout > 0) {
- // As of now, I've got nothing to do: no I/O, nothing from
- // the consumer threads, no timers that need to run ASAP. So
- // wait until either the backend or the consumer threads have
- // something to do.
- try {
- synchronized (this) {
- this.wait(timeout);
- }
- } catch (InterruptedException e) {
- // I'm awake and don't care why, let's see what's going
- // on out there.
- }
- repaint = true;
- }
-
- // Pull any pending I/O events
- backend.getEvents(fillEventQueue);
-
- // Dispatch each event to the appropriate handler, one at a time.
- for (;;) {
- TInputEvent event = null;
- synchronized (fillEventQueue) {
- if (fillEventQueue.size() == 0) {
- break;
- }
- event = fillEventQueue.remove(0);
- }
- metaHandleEvent(event);
- }
-
- // Wake a consumer thread if we have any pending events.
- synchronized (drainEventQueue) {
- if (drainEventQueue.size() > 0) {
- wakeEventHandler();
- }
- }
-
- // Prevent stepping on the primary or secondary event handler.
- stopEventHandlers();
-
- // Process timers and call doIdle()'s
- doIdle();
-
- // Update the screen
- synchronized (getScreen()) {
- drawAll();
- }
-
- // Let the event handlers run again.
- startEventHandlers();
-
- } // while (!quit)
-
- // Shutdown the event consumer threads
- if (secondaryEventHandler != null) {
- synchronized (secondaryEventHandler) {
- secondaryEventHandler.notify();
- }
- }
- if (primaryEventHandler != null) {
- synchronized (primaryEventHandler) {
- primaryEventHandler.notify();
- }
- }
-
- // Shutdown the user I/O thread(s)
- backend.shutdown();
-
- // Close all the windows. This gives them an opportunity to release
- // resources.
- closeAllWindows();
-
- }
-
- /**
- * Peek at certain application-level events, add to eventQueue, and wake
- * up the consuming Thread.
- *
- * @param event the input event to consume
- */
- private void metaHandleEvent(final TInputEvent event) {
-
- if (debugEvents) {
- System.err.printf(String.format("metaHandleEvents event: %s\n",
- event)); System.err.flush();
- }
-
- if (quit) {
- // Do no more processing if the application is already trying
- // to exit.
- return;
- }
-
- // Special application-wide events -------------------------------
-
- // Abort everything
- if (event instanceof TCommandEvent) {
- TCommandEvent command = (TCommandEvent) event;
- if (command.getCmd().equals(cmAbort)) {
- quit = true;
- return;
- }
- }
-
- // Screen resize
- if (event instanceof TResizeEvent) {
- TResizeEvent resize = (TResizeEvent) event;
- synchronized (getScreen()) {
- getScreen().setDimensions(resize.getWidth(),
- resize.getHeight());
- desktopBottom = getScreen().getHeight() - 1;
- mouseX = 0;
- mouseY = 0;
- oldMouseX = 0;
- oldMouseY = 0;
- }
- return;
- }
-
- // Peek at the mouse position
- if (event instanceof TMouseEvent) {
- TMouseEvent mouse = (TMouseEvent) event;
- synchronized (getScreen()) {
- if ((mouseX != mouse.getX()) || (mouseY != mouse.getY())) {
- oldMouseX = mouseX;
- oldMouseY = mouseY;
- mouseX = mouse.getX();
- mouseY = mouse.getY();
- }
- }
- }
-
- // Put into the main queue
- synchronized (drainEventQueue) {
- drainEventQueue.add(event);
- }
- }
-
- /**
- * Dispatch one event to the appropriate widget or application-level
- * event handler. This is the primary event handler, it has the normal
- * application-wide event handling.
- *
- * @param event the input event to consume
- * @see #secondaryHandleEvent(TInputEvent event)
- */
- private void primaryHandleEvent(final TInputEvent event) {
-
- if (debugEvents) {
- System.err.printf("Handle event: %s\n", event);
- }
-
- // Special application-wide events -----------------------------------
-
- // Peek at the mouse position
- if (event instanceof TMouseEvent) {
- // See if we need to switch focus to another window or the menu
- checkSwitchFocus((TMouseEvent) event);
- }
-
- // Handle menu events
- if ((activeMenu != null) && !(event instanceof TCommandEvent)) {
- TMenu menu = activeMenu;
-
- if (event instanceof TMouseEvent) {
- TMouseEvent mouse = (TMouseEvent) event;
-
- while (subMenus.size() > 0) {
- TMenu subMenu = subMenus.get(subMenus.size() - 1);
- if (subMenu.mouseWouldHit(mouse)) {
- break;
- }
- if ((mouse.getType() == TMouseEvent.Type.MOUSE_MOTION)
- && (!mouse.isMouse1())
- && (!mouse.isMouse2())
- && (!mouse.isMouse3())
- && (!mouse.isMouseWheelUp())
- && (!mouse.isMouseWheelDown())
- ) {
- break;
- }
- // We navigated away from a sub-menu, so close it
- closeSubMenu();
- }
-
- // Convert the mouse relative x/y to menu coordinates
- assert (mouse.getX() == mouse.getAbsoluteX());
- assert (mouse.getY() == mouse.getAbsoluteY());
- if (subMenus.size() > 0) {
- menu = subMenus.get(subMenus.size() - 1);
- }
- mouse.setX(mouse.getX() - menu.getX());
- mouse.setY(mouse.getY() - menu.getY());