Package: com.multiversesocial.hyperview
Topic: hosting application-level Java applets in HyperView 3.2

Applet Migration Guide

HyperView V3.2 — run application-level applets (with some modifications)
version V3.2guideJDK 26

Overview

HyperView 3.2 can host application-level applets: programs originally written as java.applet.Applet subclasses (games, demos, visual tools) that use the applet lifecycle, drawing, sound, images, parameters, the mouse and the keyboard. With some code changes they run inside the HyperView desktop application, not a browser. The framework keeps applet-style APIs under HyperView names: Orange (applet-like base component), OrangeStub (in place of AppletStub), OrangeContext (in place of AppletContext), AudioClip/SoundClip (sound), and HyperFrame (a frame that runs an Orange as an application).

The reference port is Asteroids: Mike Hall’s 1998 applet, ported by Tony Swain (not MIT; it keeps Mike Hall’s notice and terms). Every statement in this guide is based on the 3.2 source, with file and line references.

In one sentence: a ported applet is a class that extends ViewMain. It overrides main() in place of init(), draws in a ViewPane, and gets HyperView’s normal mouse, keyboard and event handling.

No source file in the 3.2 tree imports java.applet or javax.swing.JApplet. Names like getAppletContext() are HyperView’s own methods.

Why migration is required on JDK 26

How hosting works

The host class: extend ViewMain

The drawing surface: a ViewPane (how Asteroids works)

Mouse and keyboard: the event path

Because your class extends ViewMain, input reaches your panes through HyperView’s normal event handling. Nothing extra has to be registered. The path in the 3.2 code:

  1. HyperFrame captures the events. It registers itself as an AWTEventListener for mouse, mouse-motion, mouse-wheel, key and window events (HyperFrame.java lines 187–190). eventDispatched() (line 209) puts MOUSE_MOVED, MOUSE_DRAGGED, MOUSE_PRESSED, MOUSE_RELEASED and MOUSE_EXITED events into the HyperMouse ring buffer (mouse.msg[]), and KEY_PRESSED/KEY_RELEASED into the HyperKeyboard ring buffer (keyMsg[], lines 270–293), then wakes that thread.
  2. The HyperMouse thread (started by HyperView, HyperView.java lines 1229–1238) converts each event to view coordinates and stores them in curView.mouseX/curView.mouseY (HyperMouse.java lines 179–184). On a move it calls onMouseOver() on the gadget under the pointer if GAD_MOUSEOVER_ENA is set (lines 225–233). On a left-button press it finds the top enabled, displayed gadget under the pointer (lines 490–580):
    • if the gadget has GAD_KEYBOARD_ENA, it gets keyboard focus (keyboard.focus, lines 520–522);
    • if it has GOB_CLICK_METHOD, clickX/clickY are set relative to the gadget and GOB_DO_ONCLICK is flagged (lines 558–563);
    • otherwise, if a Dispatch was attached with addDispatch(), the Dispatch is flagged to run (lines 567–570).
    On release it flags GOB_DO_RELEASE for the clicked gadget if GOB_RELEASE_METHOD is set in gobFlags2 (lines 685–688). The right button (BUTTON3) grabs and moves gadgets and opens menus (“Right Mouse to grab”).
  3. The HyperView display loop calls onClick() and onRelease() on the flagged gadgets while holding the view monitor, so they don’t need to synchronize with drawing (HyperView.java lines 1885–1903). Flagged Dispatches run from the same loop (line 2477).
  4. The mouse wheel: HyperView is registered as the frame’s MouseWheelListener (line 1261). mouseWheelMoved() forwards the event to the gadget with keyboard focus if it has GAD_MOUSE_WHEEL_ENA in gadFlags2 (lines 1097–1106).
  5. The keyboard thread calls inKey() on the focused gadget. If that leaves keys in the buffer, curView.inKey() (your view’s default handler) gets them (HyperKeyboard.java lines 105–123).

What the ported classes override:

OverrideEnable withReplaces
boolean main() in your ViewMain subclass— (HyperView calls it once)init()
void onClick() on the panegobFlags |= GOB_CLICK_METHODmouseDown()
void onRelease()gobFlags2 |= GOB_RELEASE_METHODmouseUp()
void onMouseOver()gadFlags |= GAD_MOUSEOVER_ENAmouseEnter() / mouseMove()
void mouseWheelMoved(MouseWheelEvent)gadFlags2 |= GAD_MOUSE_WHEEL_ENA + keyboard focusMouseWheelListener
void inKey()gadFlags |= GAD_KEYBOARD_ENA + keyboard focuskeyDown() / keyUp()

Pointer position at any time: curView.mouseX, curView.mouseY (view coordinates). Asteroids uses the keyboard path: GAD_KEYBOARD_ENA, focus set by AsteroidsDispatch (line 72), and Asteroids.inKey() (lines 863–1072).

What is supported — and what isn’t

Supported (with the modifications below)

Not supported

API mapping: Applet → HyperView

Applet APIHyperView 3.2 equivalent
extends java.applet.Appletextends ViewMain. ViewMain is the application class that HyperView (the abstract base, itself an Orange) starts; your subclass is hosted by HyperFrame and gets HyperView’s normal display, mouse, keyboard and event handling. The applet’s drawing goes in a ViewPane subclass, as in Asteroids.
init()Override main() in your ViewMain subclass: HyperView calls it once (“Call the implementer’s ViewMain.main()”, HyperView.java lines 1529–1530) after HyperFrame has called init(). Pane setup goes in the ViewPane constructor (HyperView, x, y, width, height).
start()HyperFrame calls start() on your ViewMain subclass (HyperFrame.java line 183). Your ViewPane’s own start() starts its animation thread and is called by your Dispatch.
stop()halt() (Haltable, Orange.halt()). Stop threads cooperatively: Thread.stop() is removed in JDK 26.
destroy()expunge() (Orange.expunge(), HyperView.expunge()).
paint(Graphics) / update(Graphics) / repaint()Not used. HyperView’s own paint() is empty and update(Graphics) only sets a flag; it draws from its own thread. A ViewPane draws into its graphics field (its off-screen gob image) from its own loop and HyperView composites it (Asteroids.update()).
getGraphics(), size()The inherited graphics field and getSize() (Asteroids.java lines 226–227).
getParameter(name)Orange.getParameter() → HyperFrame.getParameter(), which returns the Java system property parameter.<name in lower case>. From a ViewPane call curView.getParameter("name").
getParameterInfo()Exists; always returns an empty array.
getDocumentBase()HyperFrame.getDocumentBase(): file:/// + the working directory (user.dir).
getCodeBase()HyperFrame.getCodeBase(): the codebase system property if set, else file:/// + the start directory.
getImage(URL[, name])Same signatures on Orange/HyperFrame (via Toolkit.getImage). Preferred for bundled media: HyperView.getImageFromJar(name) / resolveResourceURL(name).
getAudioClip(...), play(...), java.applet.AudioClipHyperView’s own AudioClip interface (play(), loop(), halt() instead of stop()). Orange.getAudioClip/play still exist (javax.sound.sampled Clip). Preferred: new SoundClip(name, curView), which searches the jar’s res/ first and converts μ-law/A-law .au files to PCM.
showStatus(msg)Prints to standard output (Orange prints "Status: " + msg; HyperFrame prints the message).
getAppletContext() / AppletContextOrange.getAppletContext() returns the Orange itself as an OrangeContext (AppletContext-compatible methods). getOrangeContext() is the same.
AppletStub / setStub() / appletResize()OrangeStub (orangeResize() instead of appletResize()); HyperFrame is the stub and calls setStub(this) (HyperFrame.java line 102).
showDocument(URL[, target])Only prints a status line; no browser is opened.
isActive()HyperFrame always returns true.
getAppletInfo()No framework hook. Asteroids simply renamed it getOrangeInfo().
mouseDown(Event, x, y)public void onClick() on your pane, enabled by gobFlags |= GOB_CLICK_METHOD. clickX/clickY hold the click position relative to the pane (HyperMouse.java lines 558–563; HyperView calls it at lines 1887–1897).
mouseUp(Event, x, y)public void onRelease(), enabled by gobFlags2 |= GOB_RELEASE_METHOD (HyperMouse.java lines 685–688; HyperView.java lines 1899–1903).
mouseMove / mouseDrag(Event, x, y)Read curView.mouseX / curView.mouseY: HyperMouse stores the pointer position in view coordinates for every move, drag, press and release (HyperMouse.java lines 179–184).
mouseEnter / mouseExitpublic void onMouseOver(), enabled by gadFlags |= GAD_MOUSEOVER_ENA; called while the pointer moves over the pane (HyperMouse.java lines 225–233).
MouseWheelListenerpublic void mouseWheelMoved(MouseWheelEvent) on the pane, enabled by gadFlags2 |= GAD_MOUSE_WHEEL_ENA; delivered to the gadget with keyboard focus (HyperView.java lines 1097–1106).
keyDown / keyUp(Event, key), handleEventpublic void inKey(). HyperFrame puts key events in the HyperKeyboard ring buffer; the keyboard thread calls inKey() on the focused Gadget (curView.keyboard.focus), and keys it leaves go to curView.inKey() (HyperKeyboard.java lines 105–123).
Thread.sleep() timingAllowed, but Asteroids uses wait() on a monitor with HyperView’s clock curView.now.

Step-by-step port checklist

  1. Copy the applet source to src/com/multiversesocial/hyperview/ and add package com.multiversesocial.hyperview;. The ViewPane, Dispatch and HyperView constructors and fields such as curView and graphics are package-private, so the class must be in this package.
  2. Delete import java.applet.* / javax.swing.JApplet. Change extends Applet to extends ViewMain. Move the drawing and animation code into a new ViewPane subclass (your applet’s pane).
  3. Move the body of init() into public boolean main() in your ViewMain subclass (call super.main() first to keep the ViewMain screen) and return true. Add a public static void main(String[] args) that does new HyperFrame(new MyApplet(), (byte) IncrementalID.reset(0), args, 640, 480).
  4. Give the pane a constructor MyGame(HyperView tView, int x, int y, int w, int h) that calls super(tView, x, y, w, h). Use the inherited graphics field in place of getGraphics(), getSize() in place of size(), and curView.createImage() for off-screen images.
  5. Set the gadget flags Asteroids uses: gadFlags |= GADGETON | GAD_KEYBOARD_ENA | GAD_LAYER_ENA | GAD_MOUSEOVER_ENA; gobFlags |= GOB_NO_SELECT;, and take keyboard = (HyperKeyboard) curView.keyboard.
  6. Rename stop() to halt() and remove every Thread.stop(). Stop loops cooperatively (set the thread field to null and have the loop test Thread.currentThread() == loopThread).
  7. Replace repaint() / paint(Graphics) / update(Graphics) with a no-argument update() called from your loop. Draw off-screen, blit into graphics with curView as the ImageObserver, and set a flag such as updated = true after the first frame.
  8. Replace java.applet.AudioClip / getAudioClip() with new SoundClip("name.au", curView). Rename stop() on clips to halt(). Put the media files in src/com/multiversesocial/hyperview/res/.
  9. Replace mouseDown() with onClick() (set GOB_CLICK_METHOD; read clickX/clickY), mouseUp() with onRelease() (GOB_RELEASE_METHOD in gobFlags2), mouseMove()/mouseDrag() with reads of curView.mouseX/mouseY, mouseEnter() with onMouseOver(), and wheel listeners with mouseWheelMoved() (GAD_MOUSE_WHEEL_ENA in gadFlags2).
  10. Replace keyDown/keyUp(Event,int) with public void inKey(), which drains keyboard.keyMsg[] and advances keyboard.mainBufferIndex. Map Event.LEFT and character codes to KeyEvent.VK_*.
  11. Replace getParameter() calls with curView.getParameter() and supply values as -Dparameter.<name>=value (see Parameters).
  12. Write a Dispatch launcher for the pane and attach it to a Gadget in your main() (see Launch).
  13. Build with compile26, start your class with java -cp dist/hyperview-3.2.jar com.multiversesocial.hyperview.MyApplet (run26 starts the plain ViewMain), click your gadget, then leave with the “x” gadget or the abort CLI command.

Before / after skeleton

Before — classic applet (illustrative; typical 1990s applet structure, as in Mike Hall’s Asteroids)

// Classic applet (runs only on JDK 8 or older; java.applet is gone in JDK 26)
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;

public class MyGame extends Applet implements Runnable {
   Thread loop;
   AudioClip boom;
   Image offImage; Graphics offGraphics;
   int shotX, shotY;
   boolean left;

   public void init()  { boom = getAudioClip(getDocumentBase(), "boom.au"); }
   public void start() { loop = new Thread(this); loop.start(); }
   public void stop()  { loop.stop(); loop = null; }      // Thread.stop: removed in JDK 26
   public void run() {
      while (Thread.currentThread() == loop) {
         step();
         repaint();
         try { Thread.sleep(50); } catch (InterruptedException e) { break; }
      }
   }
   public void paint(Graphics g)  { update(g); }
   public void update(Graphics g) {
      Dimension d = size();
      if (offImage == null) { offImage = createImage(d.width, d.height); offGraphics = offImage.getGraphics(); }
      /* ... draw into offGraphics ... */
      g.drawImage(offImage, 0, 0, this);
   }
   public boolean mouseDown(Event e, int x, int y) { shotX = x; shotY = y; boom.play(); return true; }
   public boolean keyDown(Event e, int key) { if (key == Event.LEFT) left = true; return true; }
   public boolean keyUp(Event e, int key)   { if (key == Event.LEFT) left = false; return true; }
}

After (1 of 2) — the applet class extends ViewMain (illustrative; compiled against the 3.2 classes)

// Your applet class: extends ViewMain (the class HyperView starts; HyperView is the abstract base)
package com.multiversesocial.hyperview;        // required: ViewPane/Dispatch constructors are package-private

public class MyApplet extends ViewMain {
   public MyApplet() { }

   public boolean main() {                     // was init(); HyperView calls main() once
      super.main();                            // keep the normal ViewMain screen (omit to start from an empty view)
      setTitle(" My Applet ");
      Gadget myGameGadget = new Gadget(this, " My Game ", 387, 96);
      myGameGadget.addDispatch(new MyGameDispatch(this));   // click it to run the game
      myGameGadget.enable();
      return true;                             // false = fatal error ("Fatal error in ViewMain.main()")
   }

   public static void main(String[] args) {    // same steps as HyperView.main(), with your class
      int tID = (byte) IncrementalID.reset(0);
      new HyperFrame(new MyApplet(), tID, args, 640, 480);
   }
}

After (2 of 2) — the pane, with mouse and keyboard handlers (illustrative; calls taken from Asteroids.java, HyperMouse.java and HyperView.java; compiled against the 3.2 classes)

// The drawing surface: a ViewPane (the pattern of Asteroids.java), with mouse and keyboard input
package com.multiversesocial.hyperview;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;

public class MyGame extends ViewPane implements Runnable {
   Thread loopThread;
   SoundClip boom;                             // HyperView's replacement for java.applet.AudioClip
   Image offImage; Graphics offGraphics;
   boolean updated = false;                    // the launcher waits for the first frame
   boolean left = false;
   int shotX, shotY;

   MyGame(HyperView tView, int tx, int ty, int tWidth, int tHeight) {
      super(tView, tx, ty, tWidth, tHeight);
      curView = tView;
      keyboard = (HyperKeyboard) curView.keyboard;
      gadFlags  |= GADGETON | GAD_KEYBOARD_ENA | GAD_LAYER_ENA | GAD_MOUSEOVER_ENA;
      gadFlags2 |= GAD_MOUSE_WHEEL_ENA;        // mouseWheelMoved() while this pane has keyboard focus
      gobFlags  |= GOB_NO_SELECT | GOB_CLICK_METHOD;   // onClick() on a left click
      gobFlags2 |= GOB_RELEASE_METHOD;                 // onRelease() when the button is let go
      boom = new SoundClip("boom.au", curView);        // looks in res/ inside the jar first
   }
   public void start() { loopThread = new Thread(this); loopThread.start(); }
   public void halt()  { loopThread = null; }          // was stop(); the loop checks loopThread
   public void run() {
      long startTime = curView.now;                    // HyperView's clock (Asteroids uses it)
      while (Thread.currentThread() == loopThread) {
         step();
         update();                                     // was repaint(): draw directly
         startTime += 21;
         long val = Math.max(0L, startTime - curView.now);
         if (val > 0) synchronized (this) { try { wait(val); } catch (InterruptedException e) { break; } }
      }
   }
   public void update() {                              // was update(Graphics g)
      if (offImage == null) { offImage = curView.createImage(width, height); offGraphics = offImage.getGraphics(); }
      /* ... draw into offGraphics ... */
      graphics.drawImage(offImage, mpX, mpY, mpX2, mpY2, mpX, mpY, mpX2, mpY2, curView);
      updated = true;
   }
   public void onClick() {                             // was mouseDown(Event e, int x, int y)
      shotX = clickX;                                  // relative to this pane
      shotY = clickY;
      boom.play();
   }
   public void onRelease() { }                         // was mouseUp(Event e, int x, int y)
   public void onMouseOver() { }                       // was mouseEnter()/mouseMove(): pointer is over the pane
   public void mouseWheelMoved(MouseWheelEvent e) { }  // wheel, while this pane has keyboard focus
   public void inKey() {                               // was keyDown()/keyUp()
      while (keyboard.mainBufferIndex != keyboard.intBufferIndex) {
         int index = keyboard.mainBufferIndex;
         KeyEvent e = keyboard.keyMsg[index].keyEvent;
         if (e != null) {
            boolean pressed = (keyboard.keyMsg[index].flags & KeyboardConstants.PRESSED) != 0;
            if (e.getKeyCode() == KeyEvent.VK_LEFT) left = pressed;
         }
         keyboard.mainBufferIndex++;                   // consume the key (see Asteroids.inKey())
         if (!(keyboard.mainBufferIndex < keyboard.MAX_KEYS)) keyboard.mainBufferIndex = 0;
      }
   }
   void step() { /* game logic, unchanged; pointer position is curView.mouseX / curView.mouseY */ }
}

Launching it in HyperView

The launcher follows AsteroidsDispatch.run(). Your main() (above) attaches it to a gadget, as ViewMain does for Asteroids. The class and gadget names are illustrative; the code compiles against the 3.2 classes.

// Launcher: a Dispatch run when the gadget is clicked (pattern of AsteroidsDispatch.java)
package com.multiversesocial.hyperview;

public class MyGameDispatch extends Dispatch {
   MyGame game = null;
   MyGameDispatch(HyperView tView) { super(tView); }

   public boolean run() {
      game = new MyGame(curView, 1, 16, 640, 460);   // (HyperView, x, y, width, height)
      game.start();                                  // starts, but not shown yet
      curView.addAbortRight(game);                   // "x" gadget to leave the stack frame
      while (!game.updated) {                        // wait for the first frame (avoids a white flash)
         synchronized (this) { try { wait(75); } catch (InterruptedException ie) { } notifyAll(); }
      }
      game.gobFlags |= GOB_ON_DISPLAY;               // show it
      curView.keyboard.focus = game;                 // route keys (and the wheel) to the game
      curView.runView();                             // run until an Abort (the "x" gadget or the "abort" CLI command)
      game.halt();                                   // stop the thread when leaving
      game = null;
      return true;                                   // false tells HyperView an error happened
   }
}
./compile26
java -Dsun.net.useExclusiveBind=false -Xms1000m -Xmx1000m -cp dist/hyperview-3.2.jar com.multiversesocial.hyperview.MyApplet

These are the same JVM options run26 uses. run26 itself runs -jar dist/hyperview-3.2.jar, which starts the plain ViewMain. The runView() call is required: the comments in AsteroidsDispatch explain that without it the Dispatch returns at once and “it would look like nothing happened”. curView.setBackImage("hdf.gif") (Asteroids) changes the background behind the pane.

Parameters (in place of <param> tags)

Adding images and sounds

Building

A new .java file in src/com/multiversesocial/hyperview/ is compiled automatically. compile26 compiles every src/**/*.java:

./compile26          # MSYS/bash      (compile26.bat on Windows cmd)
./run26              # then click your gadget in the HyperView window

# the compile step compile26 runs (from README.md):
find src -name '*.java' > build/sources.txt
javac -encoding US-ASCII -Xmaxerrs 5 -g -d build/classes -cp "lib/comm.jar" -sourcepath src @build/sources.txt

Sources must be US-ASCII (-encoding US-ASCII). lib/comm.jar is on the compile classpath because SerialHandler imports javax.comm; your port does not need it.

Worked example: what changed in Asteroids

These are the changes found by comparing HyperView’s Asteroids.java with the copy of Mike Hall’s 1998 Asteroids.java published at wpollock.com/Java/Asteroids/ (“courtesy of The Java Boutique”; other copies may differ slightly). Line numbers refer to the 3.2 file.

AreaOriginal appletHyperView 3.2 port3.2 lines
Package & importsdefault package; imports java.applet.Applet, java.applet.AudioClippackage com.multiversesocial.hyperview;, no java.applet imports; adds java.awt.event.*top of file
Base classextends Applet implements Runnableextends ViewPane implements Runnable107
Info stringgetAppletInfo()getOrangeInfo() (“Orange port by Tony Swain”)193
Initializationinit() with getGraphics() and size()constructor Asteroids(HyperView, x, y, w, h) calling super(...); uses the graphics field and getSize(); waits for curView.keyboard; sets GADGETON | GAD_KEYBOARD_ENA | GAD_LAYER_ENA | GAD_MOUSEOVER_ENA and GOB_NO_SELECT198–288
Stoppingstop() calling loopThread.stop() / loadThread.stop()halt() that only nulls the thread references; the loaders return; the loops end when Thread.currentThread() != loopThread327, 339–352
Frame timingThread.sleep() with System.currentTimeMillis(), DELAY = 50wait() on the pane with curView.now, DELAY = 21115, 347, 396
Drawingrepaint() → paint(g) → update(g), then g.drawImage(offImage, 0, 0, this)the loop calls update() directly; it draws off-screen and blits into the pane with graphics.drawImage(offImage, mpX, mpY, mpX2, mpY2, …, curView), then sets updated = true387, 1074–1200
SoundgetAudioClip(new URL(getDocumentBase(), "crash.au")); fire.au; stop(); loop() for thrusters/saucer/missilenew SoundClip("crash.au", curView) (from res/ in the jar); photon.au with one clip per shot (fireSound[MAX_SHOTS]); halt(); looping sounds now use play()412–450
KeyboardkeyDown/keyUp(Event e, int key) with Event.LEFT and character codesinKey() drains the HyperKeyboard.keyMsg[] ring buffer and uses KeyEvent.VK_* codes with PRESSED/RELEASED flags; focus is set by the launcher863–1072
CollisionPolygon.inside(), checked both waysPolygon.contains(double,double), checked one way94
Colorswhite on blackstars, photons, rocks and the saucer use colors from the HyperView palette curView.color[]1087–1137
Bug fixhyperspace sets ship.currentX twicesets currentX and currentY987
Tuning / extras (not needed for porting)MAX_SHIPS = 3, MAX_SHOTS = 6, high score 0MAX_SHIPS = 5, MAX_SHOTS = 5, high score 14325, extra U key to spawn a saucer, new title text116–117, 284, 944
Launchingan <applet code="Asteroids.class"> tag in a web pageAsteroidsDispatch attached to the “ Asteroids ” Gadget in ViewMain.main() (ViewMain.java lines 192–195)AsteroidsDispatch.java 14–88

The game logic (sprites, collisions, scoring, the update* methods) is almost unchanged. The work is in the base class, lifecycle, drawing, sound, input and launching, which is the checklist above.

Troubleshooting

Related pages & sources

Class pages: Orange · OrangeStub · OrangeContext · Haltable · HyperFrame · HyperView · ViewMain · ViewPane · Gadget · Dispatch · HyperKeyboard · HyperMouse · AudioClip · SoundClip · Asteroids · AsteroidsDispatch

Hits--