This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gui][PATCH] Implement AWT keyboard focus management


Hello,

This patch implements the classes and methods required for proper AWT
keyboard focus management.  Minimal focus test cases work, but more
advanced cases fail currently.  I'm going to check this in on libgcj's
java-gui-branch and I'll fix the remaining problems/FIXMEs there.

Tom

2004-04-22  Thomas Fitzsimmons  <fitzsim@redhat.com>

	* gnu/java/awt/peer/gtk/GtkComponentPeer.java,
	jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
	(handleEvent): Dispatch key press and key release events to
	backing widget.
	(requestFocus): Post a FOCUS_GAINED event to the event queue.
	(gtkWidgetRequestFocus): New method.
	(gtkWidgetDispatchKeyEvent): Likewise.
	* java/awt/Component.java (requestFocus, requestFocus(boolean),
	requestFocusInWindow, requestFocusInWindow(boolean),
	getFocusCycleRootAncestor, nextFocus, transferFocus,
	transferFocusBackward, transferFocusUpCycle, hasFocus,
	isFocusOwner): Implement and document focus-handling methods.
	(setFocusTraversalKeys): Inherit focus traversal keys when
	keystrokes argument is null.  Fix focus-handling documentation
	throughout class.
	* java/awt/Container.java (setFocusTraversalKeys,
	getFocusTraversalKeys, areFocusTraversalKeysSet,
	isFocusCycleRoot, setFocusTraversalPolicy,
	getFocusTraversalPolicy, isFocusTraversalPolicySet,
	setFocusCycleRoot, isFocusCycleRoot, transferFocusDownCycle):
	Implement and document focus-handling methods.
	(transferFocusBackward): Remove method.
	(readObject, writeObject): Implement and document serialization
	methods.
	* java/awt/ContainerOrderFocusTraversalPolicy.java: Implement
	and document.
	* java/awt/DefaultFocusTraversalPolicy.java: Implement and
	document.
	* java/awt/DefaultKeyboardFocusManager.java: Implement and
	partially document.
	* java/awt/EventDispatchThread.java (run): Set default keyboard
	focus manager.  Attempt to dispatch each event to the keyboard
	focus manager before normal dispatch.
	* java/awt/KeyboardFocusManager.java: Implement and partially
	document.
	* java/awt/Window.java (Window): Set focusCycleRoot to true.
	(show): Focus initial component when window is shown for the
	first time.
	* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
	(pre_event_handler): Replace complex key press and key release
	logic with simple callbacks into GtkComponentPeer.
	* jni/gtk-peer/gtkpeer.h: Fix FOCUS_GAINED/FOCUS_LOST reversal.


Index: gnu/java/awt/peer/gtk/GtkComponentPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkComponentPeer.java,v
retrieving revision 1.16.2.3
diff -u -r1.16.2.3 GtkComponentPeer.java
--- gnu/java/awt/peer/gtk/GtkComponentPeer.java	10 Mar 2004 15:48:01 -0000	1.16.2.3
+++ gnu/java/awt/peer/gtk/GtkComponentPeer.java	22 Apr 2004 16:01:10 -0000
@@ -54,12 +54,14 @@
 import java.awt.Image;
 import java.awt.Insets;
 import java.awt.ItemSelectable;
+import java.awt.KeyboardFocusManager;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.Toolkit;
 import java.awt.Window;
 import java.awt.event.FocusEvent;
 import java.awt.event.ItemEvent;
+import java.awt.event.FocusEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.PaintEvent;
@@ -91,6 +93,9 @@
   native void gtkWidgetSetCursor (int type);
   native void gtkWidgetSetBackground (int red, int green, int blue);
   native void gtkWidgetSetForeground (int red, int green, int blue);
+  native void gtkWidgetRequestFocus ();
+  native void gtkWidgetDispatchKeyEvent (int id, long when, int mods,
+                                         int keyCode, char keyChar, int keyLocation);
   native void gtkSetFont (String name, int style, int size);
   native void gtkWidgetQueueDrawArea(int x, int y, int width, int height);
   native void addExposeFilter();
@@ -222,6 +227,7 @@
   public void handleEvent (AWTEvent event)
   {
     int id = event.getID();
+    KeyEvent ke = null;
 
     switch (id)
       {
@@ -251,6 +257,16 @@
             }
         }
         break;
+      case KeyEvent.KEY_PRESSED:
+        ke = (KeyEvent) event;
+        gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiers (),
+                                   ke.getKeyCode (), ke.getKeyChar (), ke.getKeyLocation ());
+        break;
+      case KeyEvent.KEY_RELEASED:
+        ke = (KeyEvent) event;
+        gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiers (),
+                                   ke.getKeyCode (), ke.getKeyChar (), ke.getKeyLocation ());
+        break;
       }
   }
   
@@ -335,7 +351,12 @@
 				 new Rectangle (x, y, width, height)));
   }
 
-  native public void requestFocus ();
+  public void requestFocus ()
+  {
+    System.out.println ("In GtkComponentPeer.requestFocus");
+    gtkWidgetRequestFocus ();
+    postFocusEvent (FocusEvent.FOCUS_GAINED, false);
+  }
 
   public void reshape (int x, int y, int width, int height) 
   {
@@ -456,11 +477,12 @@
 			       int keyCode, char keyChar, int keyLocation)
   {
     q.postEvent (new KeyEvent (awtComponent, id, when, mods,
-			       keyCode, keyChar, keyLocation));
+    			       keyCode, keyChar, keyLocation));
   }
 
   protected void postFocusEvent (int id, boolean temporary)
   {
+    System.out.println ("GtkComponentPeer.postFocusEvent: " + awtComponent);
     q.postEvent (new FocusEvent (awtComponent, id, temporary));
   }
 
Index: java/awt/Component.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Component.java,v
retrieving revision 1.37.2.7
diff -u -r1.37.2.7 Component.java
--- java/awt/Component.java	2 Apr 2004 15:52:54 -0000	1.37.2.7
+++ java/awt/Component.java	22 Apr 2004 16:01:10 -0000
@@ -382,18 +382,18 @@
   boolean focusable = true;
 
   /**
-   * Tracks whether this component uses default focus traversal, or has a
-   * different policy.
+   * Tracks whether this component's {@link #isFocusTraversable}
+   * method has been overridden.
    *
-   * @see #isFocusTraversableOverridden()
    * @since 1.4
    */
   int isFocusTraversableOverridden;
 
   /**
-   * The focus traversal keys, if not inherited from the parent or default
-   * keyboard manager. These sets will contain only AWTKeyStrokes that
-   * represent press and release events to use as focus control.
+   * The focus traversal keys, if not inherited from the parent or
+   * default keyboard focus manager. These sets will contain only
+   * AWTKeyStrokes that represent press and release events to use as
+   * focus control.
    *
    * @see #getFocusTraversalKeys(int)
    * @see #setFocusTraversalKeys(int, Set)
@@ -556,6 +556,12 @@
   transient BufferStrategy bufferStrategy;
 
   /**
+   * true if requestFocus was called on this component when its
+   * top-level ancestor was not focusable.
+   */
+  private transient FocusEvent pendingFocusRequest = null;
+
+  /**
    * The system properties that affect image updating.
    */
   private static transient boolean incrementalDraw;
@@ -2962,6 +2968,7 @@
   {
     if (focusListener == null)
       return;
+
     switch (e.id)
       {
         case FocusEvent.FOCUS_GAINED:
@@ -3410,13 +3417,18 @@
   }
 
   /**
-   * Sets the focus traversal keys for a given type of focus events. Normally,
-   * the default values should match the operating system's native choices. To
-   * disable a given traversal, use <code>Collections.EMPTY_SET</code>. The
-   * event dispatcher will consume PRESSED, RELEASED, and TYPED events for the
-   * specified key, although focus can only transfer on PRESSED or RELEASED.
+   * Sets the focus traversal keys for one of the three focus
+   * traversal directions supported by Components: {@link
+   * #KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS}, {@link
+   * #KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS}, or {@link
+   * #KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS}. Normally, the
+   * default values should match the operating system's native
+   * choices. To disable a given traversal, use
+   * <code>Collections.EMPTY_SET</code>. The event dispatcher will
+   * consume PRESSED, RELEASED, and TYPED events for the specified
+   * key, although focus can only transfer on PRESSED or RELEASED.
    *
-   * <p>The defauts are:
+   * <p>The defaults are:
    * <table>
    *   <th><td>Identifier</td><td>Meaning</td><td>Default</td></th>
    *   <tr><td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td>
@@ -3429,10 +3441,13 @@
    *     <td>Go up a traversal cycle</td><td>None</td></tr>
    * </table>
    *
-   * <p>Specifying null allows inheritance from the parent, or from the current
-   * KeyboardFocusManager default set. If not null, the set must contain only
-   * AWTKeyStrokes that are not already focus keys and are not KEY_TYPED
-   * events.
+   * If keystrokes is null, this component's focus traversal key set
+   * is inherited from one of its ancestors.  If none of its ancestors
+   * has its own set of focus traversal keys, the focus traversal keys
+   * are set to the defaults retrieved from the current
+   * KeyboardFocusManager.  If not null, the set must contain only
+   * AWTKeyStrokes that are not already focus keys and are not
+   * KEY_TYPED events.
    *
    * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or
    *        UP_CYCLE_TRAVERSAL_KEYS
@@ -3447,7 +3462,24 @@
   public void setFocusTraversalKeys(int id, Set keystrokes)
   {
     if (keystrokes == null)
-      throw new IllegalArgumentException();
+      {
+        Container parent = getParent ();
+
+        while (parent != null)
+          {
+            if (parent.areFocusTraversalKeysSet (id))
+              {
+                keystrokes = parent.getFocusTraversalKeys (id);
+                break;
+              }
+            parent = parent.getParent ();
+          }
+
+        if (keystrokes == null)
+          keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager ().
+            getDefaultFocusTraversalKeys (id);
+      }
+
     Set sa;
     Set sb;
     String name;
@@ -3475,50 +3507,60 @@
         name = "upCycleFocusTraversalKeys";
         break;
       default:
-        throw new IllegalArgumentException();
+        throw new IllegalArgumentException ();
       }
-    int i = keystrokes.size();
-    Iterator iter = keystrokes.iterator();
+
+    int i = keystrokes.size ();
+    Iterator iter = keystrokes.iterator ();
+
     while (--i >= 0)
       {
-        Object o = iter.next();
-        if (! (o instanceof AWTKeyStroke)
-            || sa.contains(o) || sb.contains(o)
+        Object o = iter.next ();
+        if (!(o instanceof AWTKeyStroke)
+            || sa.contains (o) || sb.contains (o)
             || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
-          throw new IllegalArgumentException();
+          throw new IllegalArgumentException ();
       }
+
     if (focusTraversalKeys == null)
       focusTraversalKeys = new Set[3];
-    keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
-    firePropertyChange(name, focusTraversalKeys[id], keystrokes);
+
+    keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
+    firePropertyChange (name, focusTraversalKeys[id], keystrokes);
+
     focusTraversalKeys[id] = keystrokes;
   }
 
   /**
-   * Returns the set of keys for a given focus traversal action, as defined
-   * in <code>setFocusTraversalKeys</code>. If not set, this is inherited from
-   * the parent component, which may have gotten it from the
-   * KeyboardFocusManager.
+   * Returns the set of keys for a given focus traversal action, as
+   * defined in <code>setFocusTraversalKeys</code>.  If not set, this
+   * is inherited from the parent component, which may have gotten it
+   * from the KeyboardFocusManager.
    *
-   * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or
-   *        UP_CYCLE_TRAVERSAL_KEYS
+   * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS,
+   * or UP_CYCLE_TRAVERSAL_KEYS
    * @throws IllegalArgumentException if id is invalid
-   * @see #setFocusTraversalKeys(int, Set)
+   * @see #setFocusTraversalKeys (int, Set)
    * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
    * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
    * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
    * @since 1.4
    */
-  public Set getFocusTraversalKeys(int id)
+  public Set getFocusTraversalKeys (int id)
   {
-    if (id < KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS
-        || id > KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
+    if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
+        id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
+        id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
       throw new IllegalArgumentException();
+
     Set s = null;
+
     if (focusTraversalKeys != null)
       s = focusTraversalKeys[id];
+
     if (s == null && parent != null)
-      s = parent.getFocusTraversalKeys(id);
+      s = parent.getFocusTraversalKeys (id);
+
     return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager()
                         .getDefaultFocusTraversalKeys(id)) : s;
   }
@@ -3527,269 +3569,405 @@
    * Tests whether the focus traversal keys for a given action are explicitly
    * set or inherited.
    *
-   * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or
-   *        UP_CYCLE_TRAVERSAL_KEYS
+   * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS,
+   * or UP_CYCLE_TRAVERSAL_KEYS
    * @return true if that set is explicitly specified
    * @throws IllegalArgumentException if id is invalid
-   * @see #getFocusTraversalKeys(int)
+   * @see #getFocusTraversalKeys (int)
    * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
    * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
    * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
    * @since 1.4
    */
-  public boolean areFocusTraversalKeysSet(int id)
+  public boolean areFocusTraversalKeysSet (int id)
   {
-    if (id < KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS
-        || id > KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
-      throw new IllegalArgumentException();
+    if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
+        id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
+        id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS)
+      throw new IllegalArgumentException ();
+
     return focusTraversalKeys != null && focusTraversalKeys[id] != null;
   }
 
   /**
-   * Sets whether focus traversal keys are enabled, which consumes traversal
-   * keys and performs the focus event automatically.
+   * Enable or disable focus traversal keys on this Component.  If
+   * they are, then the keyboard focus manager consumes and acts on
+   * key press and release events that trigger focus traversal, and
+   * discards the corresponding key typed events.  If focus traversal
+   * keys are disabled, then all key events that would otherwise
+   * trigger focus traversal are sent to this Component.
    *
    * @param focusTraversalKeysEnabled the new value of the flag
-   * @see #getFocusTraversalKeysEnabled()
-   * @see #setFocusTraversalKeys(int, Set)
-   * @see #getFocusTraversalKeys(int)
+   * @see #getFocusTraversalKeysEnabled ()
+   * @see #setFocusTraversalKeys (int, Set)
+   * @see #getFocusTraversalKeys (int)
    * @since 1.4
    */
-  public void setFocusTraversalKeysEnabled(boolean focusTraversalKeysEnabled)
+  public void setFocusTraversalKeysEnabled (boolean focusTraversalKeysEnabled)
   {
-    firePropertyChange("focusTraversalKeysEnabled",
-                       this.focusTraversalKeysEnabled,
-                       focusTraversalKeysEnabled);
+    firePropertyChange ("focusTraversalKeysEnabled",
+			this.focusTraversalKeysEnabled,
+			focusTraversalKeysEnabled);
     this.focusTraversalKeysEnabled = focusTraversalKeysEnabled;
   }
 
   /**
-   * Tests whether focus traversal keys are enabled. If they are, then focus
-   * traversal keys are consumed and focus events performed automatically,
-   * without the component seeing the keystrokes.
-   *
-   * @return true if focus traversal is enabled
-   * @see #setFocusTraversalKeysEnabled(boolean)
-   * @see #setFocusTraversalKeys(int, Set)
-   * @see #getFocusTraversalKeys(int)
+   * Check whether or not focus traversal keys are enabled on this
+   * Component.  If they are, then the keyboard focus manager consumes
+   * and acts on key press and release events that trigger focus
+   * traversal, and discards the corresponding key typed events.  If
+   * focus traversal keys are disabled, then all key events that would
+   * otherwise trigger focus traversal are sent to this Component.
+   *
+   * @return true if focus traversal keys are enabled
+   * @see #setFocusTraversalKeysEnabled (boolean)
+   * @see #setFocusTraversalKeys (int, Set)
+   * @see #getFocusTraversalKeys (int)
    * @since 1.4
    */
-  public boolean getFocusTraversalKeysEnabled()
+  public boolean getFocusTraversalKeysEnabled ()
   {
     return focusTraversalKeysEnabled;
   }
 
   /**
-   * Requests that this component be given focus. A <code>FOCUS_GAINED</code>
-   * event will be fired if and only if this request is successful. To be
-   * successful, the component must be displayable, visible, and focusable,
-   * and the top-level Window must be able to receive focus. Thus, this
-   * request may fail, or be delayed until the window receives focus. It is
-   * recommended that <code>requestFocusInWindow</code> be used where
-   * possible to be more platform-independent.
+   * Request that this Component be given the keyboard input focus and
+   * that its top-level ancestor become the focused Window.
+   *
+   * For the request to be granted, the Component must be focusable,
+   * displayable and visible and the top-level Window to which it
+   * belongs must be focusable.  If the request is initially denied on
+   * the basis that the top-level Window is not focusable, the request
+   * will be remembered and granted when the Window does become
+   * focused.
+   *
+   * Never assume that this Component is the focus owner until it
+   * receives a FOCUS_GAINED event.
    *
-   * @see #requestFocusInWindow()
+   * The behaviour of this method is platform-dependent.
+   * {@link #requestFocusInWindow} should be used instead.
+   *
+   * @see #requestFocusInWindow ()
    * @see FocusEvent
-   * @see #addFocusListener(FocusListener)
-   * @see #isFocusable()
-   * @see #isDisplayable()
-   * @see KeyboardFocusManager#clearGlobalFocusOwner()
-   */
-  public void requestFocus()
-  {
-    // If there's no peer then this component can't get the focus. We
-    // treat it as a silent rejection of the request.
-    if (peer != null)
-      peer.requestFocus();
+   * @see #addFocusListener (FocusListener)
+   * @see #isFocusable ()
+   * @see #isDisplayable ()
+   * @see KeyboardFocusManager#clearGlobalFocusOwner ()
+   */
+  public void requestFocus ()
+  {
+    if (isDisplayable ()
+	&& isVisible ()
+	&& isFocusable ())
+      {
+	// FIXME: need to get the tree lock here.
+	// Find this Component's top-level ancestor.
+        Container parent = getParent ();
+
+        while (parent != null
+	       && !(parent instanceof Window))
+	  parent = parent.getParent ();
+
+	Window toplevel = (Window) parent;
+	if (toplevel.isFocusableWindow ())
+	  {
+	    if (peer != null)
+	      // This call will cause a FOCUS_GAINED event to be
+	      // posted to the system event queue if the native
+	      // windowing system grants the focus request.
+	      peer.requestFocus ();
+	    else
+	      {
+		// Either our peer hasn't been created yet or we're a
+		// lightweight component.  In either case we want to
+		// post a FOCUS_GAINED event.
+		EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+		eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED));
+	      }
+	  }
+	else
+	  pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED);
+      }
   }
 
   /**
-   * Requests that this component be given focus. A <code>FOCUS_GAINED</code>
-   * event will be fired if and only if this request is successful. To be
-   * successful, the component must be displayable, visible, and focusable,
-   * and the top-level Window must be able to receive focus. Thus, this
-   * request may fail, or be delayed until the window receives focus. It is
-   * recommended that <code>requestFocusInWindow</code> be used where
-   * possible to be more platform-independent.
-   *
-   * <p>If the return value is false, the request is guaranteed to fail. If
-   * it is true, it will likely succeed unless the action is vetoed or
-   * something in the native windowing system intervenes. The temporary flag,
-   * and thus this method in general, is not designed for public use; rather
-   * it is a hook for lightweight components to notify their container in
-   * an attempt to reduce the amount of repainting necessary.
+   * Request that this Component be given the keyboard input focus and
+   * that its top-level ancestor become the focused Window.
+   *
+   * For the request to be granted, the Component must be focusable,
+   * displayable and visible and the top-level Window to which it
+   * belongs must be focusable.  If the request is initially denied on
+   * the basis that the top-level Window is not focusable, the request
+   * will be remembered and granted when the Window does become
+   * focused.
+   *
+   * Never assume that this Component is the focus owner until it
+   * receives a FOCUS_GAINED event.
+   *
+   * The behaviour of this method is platform-dependent.
+   * {@link #requestFocusInWindow} should be used instead.
+   *
+   * If the return value is false, the request is guaranteed to fail.
+   * If the return value is true, the request will succeed unless it
+   * is vetoed or something in the native windowing system intervenes,
+   * preventing this Component's top-level ancestor from becoming
+   * focused.  This method is meant to be called by derived
+   * lightweight Components that want to avoid unnecessary repainting
+   * when they know a given focus transfer need only be temporary.
    *
    * @param temporary true if the focus request is temporary
    * @return true if the request has a chance of success
-   * @see #requestFocusInWindow()
+   * @see #requestFocusInWindow ()
    * @see FocusEvent
-   * @see #addFocusListener(FocusListener)
-   * @see #isFocusable()
-   * @see #isDisplayable()
-   * @see KeyboardFocusManager#clearGlobalFocusOwner()
+   * @see #addFocusListener (FocusListener)
+   * @see #isFocusable ()
+   * @see #isDisplayable ()
+   * @see KeyboardFocusManager#clearGlobalFocusOwner ()
    * @since 1.4
    */
-  protected boolean requestFocus(boolean temporary)
+  protected boolean requestFocus (boolean temporary)
   {
-    // XXX Implement correctly.
-    requestFocus();
+    if (isDisplayable ()
+	&& isVisible ()
+	&& isFocusable ())
+      {
+	// FIXME: need to get the tree lock here.
+	// Find this Component's top-level ancestor.
+        Container parent = getParent ();
+
+        while (parent != null
+	       && !(parent instanceof Window))
+	  parent = parent.getParent ();
+
+	Window toplevel = (Window) parent;
+	if (toplevel.isFocusableWindow ())
+	  {
+	    if (peer != null)
+	      // This call will cause a FOCUS_GAINED event to be
+	      // posted to the system event queue if the native
+	      // windowing system grants the focus request.
+	      peer.requestFocus ();
+	    else
+	      {
+		// Either our peer hasn't been created yet or we're a
+		// lightweight component.  In either case we want to
+		// post a FOCUS_GAINED event.
+		EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+		eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary));
+	      }
+	  }
+	else
+	  // FIXME: need to add a focus listener to our top-level
+	  // ancestor, so that we can post this event when it becomes
+	  // the focused window.
+	  pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary);
+      }
+    // Always return true.
     return true;
   }
 
   /**
-   * Requests that this component be given focus, if it resides in the
-   * top-level window which already has focus. A <code>FOCUS_GAINED</code>
-   * event will be fired if and only if this request is successful. To be
-   * successful, the component must be displayable, visible, and focusable,
-   * and the top-level Window must be focused.
-   *
-   * <p>If the return value is false, the request is guaranteed to fail. If
-   * it is true, it will likely succeed unless the action is vetoed or
-   * something in the native windowing system intervenes. The temporary flag,
-   * and thus this method in general, is not designed for public use; rather
-   * it is a hook for lightweight components to notify their container in
-   * an attempt to reduce the amount of repainting necessary.
+   * Request that this component be given the keyboard input focus, if
+   * its top-level ancestor is the currently focused Window.  A
+   * <code>FOCUS_GAINED</code> event will be fired if and only if this
+   * request is successful. To be successful, the component must be
+   * displayable, visible, and focusable, and its ancestor top-level
+   * Window must be focused.
+   *
+   * If the return value is false, the request is guaranteed to fail.
+   * If the return value is true, the request will succeed unless it
+   * is vetoed or something in the native windowing system intervenes,
+   * preventing this Component's top-level ancestor from becoming
+   * focused.
    *
    * @return true if the request has a chance of success
-   * @see #requestFocus()
+   * @see #requestFocus ()
    * @see FocusEvent
-   * @see #addFocusListener(FocusListener)
-   * @see #isFocusable()
-   * @see #isDisplayable()
-   * @see KeyboardFocusManager#clearGlobalFocusOwner()
+   * @see #addFocusListener (FocusListener)
+   * @see #isFocusable ()
+   * @see #isDisplayable ()
+   * @see KeyboardFocusManager#clearGlobalFocusOwner ()
    * @since 1.4
    */
-  public boolean requestFocusInWindow()
+  public boolean requestFocusInWindow ()
   {
-    // XXX Implement correctly.
-    requestFocus();
-    return true;
+    return requestFocusInWindow (false);
   }
 
   /**
-   * Requests that this component be given focus, if it resides in the
-   * top-level window which already has focus. A <code>FOCUS_GAINED</code>
-   * event will be fired if and only if this request is successful. To be
-   * successful, the component must be displayable, visible, and focusable,
-   * and the top-level Window must be focused.
-   *
-   * <p>If the return value is false, the request is guaranteed to fail. If
-   * it is true, it will likely succeed unless the action is vetoed or
-   * something in the native windowing system intervenes. The temporary flag,
-   * and thus this method in general, is not designed for public use; rather
-   * it is a hook for lightweight components to notify their container in
-   * an attempt to reduce the amount of repainting necessary.
+   * Request that this component be given the keyboard input focus, if
+   * its top-level ancestor is the currently focused Window.  A
+   * <code>FOCUS_GAINED</code> event will be fired if and only if this
+   * request is successful. To be successful, the component must be
+   * displayable, visible, and focusable, and its ancestor top-level
+   * Window must be focused.
+   *
+   * If the return value is false, the request is guaranteed to fail.
+   * If the return value is true, the request will succeed unless it
+   * is vetoed or something in the native windowing system intervenes,
+   * preventing this Component's top-level ancestor from becoming
+   * focused.  This method is meant to be called by derived
+   * lightweight Components that want to avoid unnecessary repainting
+   * when they know a given focus transfer need only be temporary.
    *
    * @param temporary true if the focus request is temporary
    * @return true if the request has a chance of success
-   * @see #requestFocus()
+   * @see #requestFocus ()
    * @see FocusEvent
-   * @see #addFocusListener(FocusListener)
-   * @see #isFocusable()
-   * @see #isDisplayable()
-   * @see KeyboardFocusManager#clearGlobalFocusOwner()
+   * @see #addFocusListener (FocusListener)
+   * @see #isFocusable ()
+   * @see #isDisplayable ()
+   * @see KeyboardFocusManager#clearGlobalFocusOwner ()
    * @since 1.4
    */
-  protected boolean requestFocusInWindow(boolean temporary)
+  protected boolean requestFocusInWindow (boolean temporary)
   {
-    // XXX Implement correctly.
-    requestFocus();
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+    Window focusedWindow = manager.getFocusedWindow ();
+
+    if (focusedWindow != null)
+      {
+	// FIXME: get tree lock here.
+	Container parent = getParent ();
+
+	while (parent != null
+	       && !(parent instanceof Window))
+	  parent = parent.getParent ();
+
+	Window toplevel = (Window) parent;
+
+	// Check if top-level ancestor is currently focused window.
+	if (focusedWindow == toplevel)
+	  {
+	    if (peer != null)
+	      // This call will cause a FOCUS_GAINED event to be
+	      // posted to the system event queue if the native
+	      // windowing system grants the focus request.
+	      peer.requestFocus ();
+	    else
+	      {
+		// Either our peer hasn't been created yet or we're a
+		// lightweight component.  In either case we want to
+		// post a FOCUS_GAINED event.
+		EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+		eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary));
+	      }
+	  }
+	else
+	  return false;
+      }
+
     return true;
   }
 
   /**
-   * Transfers focus to the next component in the focus traversal order, as
-   * though this were the current focus owner.
+   * Transfers focus to the next component in the focus traversal
+   * order, as though this were the current focus owner.
    *
    * @see #requestFocus()
    * @since 1.1
    */
-  public void transferFocus()
+  public void transferFocus ()
   {
-    Component next;
-    if (parent == null)
-      next = findNextFocusComponent(null);
-    else
-      next = parent.findNextFocusComponent(this);
-    if (next != null && next != this)
-      next.requestFocus();
+    nextFocus ();
   }
 
   /**
-   * Returns the root container that owns the focus cycle where this component
-   * resides. A focus cycle root is in two cycles, one as the ancestor, and
-   * one as the focusable element; this call always returns the ancestor.
+   * Returns the root container that owns the focus cycle where this
+   * component resides. A focus cycle root is in two cycles, one as
+   * the ancestor, and one as the focusable element; this call always
+   * returns the ancestor.
    *
    * @return the ancestor container that owns the focus cycle
    * @since 1.4
    */
-  public Container getFocusCycleRootAncestor()
+  public Container getFocusCycleRootAncestor ()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    if (this instanceof Window
+	&& ((Container) this).isFocusCycleRoot ())
+      return (Container) this;
+
+    Container parent = getParent ();
+
+    while (parent != null
+	   && !parent.isFocusCycleRoot ())
+      parent = parent.getParent ();
+
+    return parent;
   }
 
   /**
-   * Tests if the container is the ancestor of the focus cycle that this
-   * component belongs to.
+   * Tests if the container is the ancestor of the focus cycle that
+   * this component belongs to.
    *
    * @param c the container to test
    * @return true if c is the focus cycle root
    * @since 1.4
    */
-  public boolean isFocusCycleRoot(Container c)
+  public boolean isFocusCycleRoot (Container c)
   {
-    return c == getFocusCycleRootAncestor();
+    return c == getFocusCycleRootAncestor ();
   }
 
   /**
-   * AWT 1.0 focus event processor.
+   * AWT 1.0 focus event processor.  Transfers focus to the next
+   * component in the focus traversal order, as though this were the
+   * current focus owner.
    *
-   * @deprecated use {@link #transferFocus()} instead
+   * @deprecated use {@link #transferFocus ()} instead
    */
-  public void nextFocus()
+  public void nextFocus ()
   {
-    transferFocus();
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+    manager.focusNextComponent (this);
   }
 
   /**
-   * Transfers focus to the previous component in the focus traversal order, as
-   * though this were the current focus owner.
+   * Transfers focus to the previous component in the focus traversal
+   * order, as though this were the current focus owner.
    *
-   * @see #requestFocus()
+   * @see #requestFocus ()
    * @since 1.4
    */
-  public void transferFocusBackward()
+  public void transferFocusBackward ()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+    manager.focusPreviousComponent (this);
   }
 
   /**
-   * Transfers focus to the focus cycle root of this component. However, if
-   * this is a Window, the default focus owner in the window in the current
-   * focus cycle is focused instead.
+   * Transfers focus to the focus cycle root of this component.
+   * However, if this is a Window, the default focus owner in the
+   * window in the current focus cycle is focused instead.
    *
-   * @see #requestFocus()
-   * @see #isFocusCycleRoot()
+   * @see #requestFocus ()
+   * @see #isFocusCycleRoot ()
    * @since 1.4
    */
-  public void transferFocusUpCycle()
+  public void transferFocusUpCycle ()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+    manager.upFocusCycle (this);
   }
 
   /**
-   * Tests if this component is the focus owner. Use {@link #isFocusOwner()}
-   * instead.
+   * Tests if this component is the focus owner. Use {@link
+   * #isFocusOwner ()} instead.
    *
    * @return true if this component owns focus
    * @since 1.2
    */
-  public boolean hasFocus()
+  public boolean hasFocus ()
   {
-    return isFocusOwner();
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+    Component focusOwner = manager.getFocusOwner ();
+
+    return this == focusOwner;
   }
 
   /**
@@ -3800,8 +3978,7 @@
    */
   public boolean isFocusOwner()
   {
-    // XXX Implement.
-    throw new Error("not implemented");
+    return hasFocus ();
   }
 
   /**
@@ -4336,6 +4513,8 @@
    * making the request. This is overridden by Container; when called for an
    * ordinary component there is no child and so we always return null.
    *
+   * FIXME: is this still needed, in light of focus traversal policies?
+   *
    * @param child the component making the request
    * @return the next component to focus on
    */
@@ -4896,23 +5075,23 @@
      * Tests whether this component can accept focus.
      *
      * @return true if this is focus traversable
-     * @see #getAccessibleStateSet()
+     * @see #getAccessibleStateSet ()
      * @see AccessibleState#FOCUSABLE
      * @see AccessibleState#FOCUSED
      */
-    public boolean isFocusTraversable()
+    public boolean isFocusTraversable ()
     {
-      return Component.this.isFocusTraversable();
+      return Component.this.isFocusTraversable ();
     }
 
     /**
      * Requests focus for this component.
      *
-     * @see #isFocusTraversable()
+     * @see #isFocusTraversable ()
      */
-    public void requestFocus()
+    public void requestFocus ()
     {
-      Component.this.requestFocus();
+      Component.this.requestFocus ();
     }
 
     /**
Index: java/awt/Container.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Container.java,v
retrieving revision 1.34.2.6
diff -u -r1.34.2.6 Container.java
--- java/awt/Container.java	10 Mar 2004 21:43:01 -0000	1.34.2.6
+++ java/awt/Container.java	22 Apr 2004 16:01:10 -0000
@@ -46,10 +46,16 @@
 import java.awt.peer.LightweightPeer;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.io.Serializable;
+import java.util.Collections;
 import java.util.EventListener;
+import java.util.Iterator;
+import java.util.HashSet;
 import java.util.Set;
 import javax.accessibility.Accessible;
 import javax.swing.SwingUtilities;
@@ -93,6 +99,21 @@
   transient ContainerListener containerListener;
   transient PropertyChangeSupport changeSupport; 
 
+  /** The focus traversal policy that determines how focus is
+      transferred between this Container and its children. */
+  private FocusTraversalPolicy focusTraversalPolicy;
+
+  /**
+   * The focus traversal keys, if not inherited from the parent or default
+   * keyboard manager. These sets will contain only AWTKeyStrokes that
+   * represent press and release events to use as focus control.
+   *
+   * @see #getFocusTraversalKeys(int)
+   * @see #setFocusTraversalKeys(int, Set)
+   * @since 1.4
+   */
+  transient Set[] focusTraversalKeys;
+
   /**
    * Default constructor for subclasses.
    */
@@ -1068,9 +1089,89 @@
       throw new IllegalArgumentException ();
 
     if (keystrokes == null)
-      throw new IllegalArgumentException ();
+      {
+        Container parent = getParent ();
+
+        while (parent != null)
+          {
+            if (parent.areFocusTraversalKeysSet (id))
+              {
+                keystrokes = parent.getFocusTraversalKeys (id);
+                break;
+              }
+            parent = parent.getParent ();
+          }
+
+        if (keystrokes == null)
+          keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager ().
+            getDefaultFocusTraversalKeys (id);
+      }
+
+    Set sa;
+    Set sb;
+    Set sc;
+    String name;
+    switch (id)
+      {
+      case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
+        sa = getFocusTraversalKeys
+          (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+        sb = getFocusTraversalKeys
+          (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+        sc = getFocusTraversalKeys
+          (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+        name = "forwardFocusTraversalKeys";
+        break;
+      case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
+        sa = getFocusTraversalKeys
+          (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+        sb = getFocusTraversalKeys
+          (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+        sc = getFocusTraversalKeys
+          (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+        name = "backwardFocusTraversalKeys";
+        break;
+      case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS:
+        sa = getFocusTraversalKeys
+          (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+        sb = getFocusTraversalKeys
+          (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+        sc = getFocusTraversalKeys
+          (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+        name = "upCycleFocusTraversalKeys";
+        break;
+      case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS:
+        sa = getFocusTraversalKeys
+          (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+        sb = getFocusTraversalKeys
+          (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+        sc = getFocusTraversalKeys
+          (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+        name = "downCycleFocusTraversalKeys";
+        break;
+      default:
+        throw new IllegalArgumentException ();
+      }
+
+    int i = keystrokes.size ();
+    Iterator iter = keystrokes.iterator ();
+
+    while (--i >= 0)
+      {
+        Object o = iter.next ();
+        if (!(o instanceof AWTKeyStroke)
+            || sa.contains (o) || sb.contains (o) || sc.contains (o)
+            || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
+          throw new IllegalArgumentException ();
+      }
+
+    if (focusTraversalKeys == null)
+      focusTraversalKeys = new Set[3];
+
+    keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
+    firePropertyChange (name, focusTraversalKeys[id], keystrokes);
 
-    throw new Error ("not implemented");
+    focusTraversalKeys[id] = keystrokes;
   }
   
   /**
@@ -1085,7 +1186,7 @@
    *
    * @since 1.4
    */
-  public Set getFocusTraversalKeys(int id)
+  public Set getFocusTraversalKeys (int id)
   {
     if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
         id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
@@ -1093,9 +1194,18 @@
         id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
       throw new IllegalArgumentException ();
 
-    return null;
+    Set s = null;
+
+    if (focusTraversalKeys != null)
+      s = focusTraversalKeys[id];
+
+    if (s == null && parent != null)
+      s = parent.getFocusTraversalKeys (id);
+
+    return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager()
+                        .getDefaultFocusTraversalKeys(id)) : s;
   }
-  
+
   /**
    * Returns whether the Set of focus traversal keys for the given focus
    * traversal operation has been explicitly defined for this Container.
@@ -1110,7 +1220,7 @@
    *
    * @since 1.4
    */
-  public boolean areFocusTraversalKeysSet(int id)
+  public boolean areFocusTraversalKeysSet (int id)
   {
     if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
         id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
@@ -1118,43 +1228,148 @@
         id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
       throw new IllegalArgumentException ();
 
-    return false;
+    return focusTraversalKeys != null && focusTraversalKeys[id] != null;
   }
-  
-  public boolean isFocusCycleRoot(Container c)
+
+  /**
+   * Check whether the given Container is the focus cycle root of this
+   * Container's focus traversal cycle.  If this Container is a focus
+   * cycle root itself, then it will be in two different focus cycles
+   * -- it's own, and that of its ancestor focus cycle root's.  In
+   * that case, if <code>c</code> is either of those containers, this
+   * method will return true.
+   *
+   * @param c the candidate Container
+   *
+   * @return true if c is the focus cycle root of the focus traversal
+   * cycle to which this Container belongs, false otherwise
+   *
+   * @since 1.4
+   */
+  public boolean isFocusCycleRoot (Container c)
   {
+    if (this == c
+        && isFocusCycleRoot ())
+      return true;
+
+    Container ancestor = getFocusCycleRootAncestor ();
+
+    if (c == ancestor)
+      return true;
+
     return false;
   }
-  
-  public void transferFocusBackward()
-  {
-  }
-  
-  public void setFocusTraversalPolicy(FocusTraversalPolicy policy)
+
+  /**
+   * If this Container is a focus cycle root, set the focus traversal
+   * policy that determines the focus traversal order for its
+   * children.  If non-null, this policy will be inherited by all
+   * inferior focus cycle roots.  If <code>policy</code> is null, this
+   * Container will inherit its policy from the closest ancestor focus
+   * cycle root that's had its policy set.
+   *
+   * @param policy the new focus traversal policy for this Container or null
+   *
+   * @since 1.4
+   */
+  public void setFocusTraversalPolicy (FocusTraversalPolicy policy)
   {
+    focusTraversalPolicy = policy;
   }
-  
-  public FocusTraversalPolicy getFocusTraversalPolicy()
+
+  /**
+   * Return the focus traversal policy that determines the focus
+   * traversal order for this Container's children.  This method
+   * returns null if this Container is not a focus cycle root.  If the
+   * focus traversal policy has not been set explicitly, then this
+   * method will return an ancestor focus cycle root's policy instead.
+   *
+   * @return this Container's focus traversal policy or null
+   *
+   * @since 1.4
+   */
+  public FocusTraversalPolicy getFocusTraversalPolicy ()
   {
-    return null;
+    if (!isFocusCycleRoot ())
+      return null;
+
+    if (focusTraversalPolicy == null)
+      {
+        Container ancestor = getFocusCycleRootAncestor ();
+
+	if (ancestor != this)
+	  return ancestor.getFocusTraversalPolicy ();
+	else
+	  {
+	    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+	    return manager.getDefaultFocusTraversalPolicy ();
+	  }
+      }
+    else
+      return focusTraversalPolicy;
   }
-  
-  public boolean isFocusTraversalPolicySet()
+
+  /**
+   * Check whether this Container's focus traversal policy has been
+   * explicitly set.  If it has not, then this Container will inherit
+   * its focus traversal policy from one of its ancestor focus cycle
+   * roots.
+   *
+   * @return true if focus traversal policy is set, false otherwise
+  */
+  public boolean isFocusTraversalPolicySet ()
   {
-    return false;
+    return focusTraversalPolicy == null;
   }
-  
-  public void setFocusCycleRoot(boolean focusCycleRoot)
+
+  /**
+   * Set whether or not this Container is the root of a focus
+   * traversal cycle.  This Container's focus traversal policy
+   * determines the order of focus traversal.  Some policies prevent
+   * the focus from being transferred between two traversal cycles
+   * until an up or down traversal operation is performed.  In that
+   * case, normal traversal (not up or down) is limited to this
+   * Container and all of this Container's descendents that are not
+   * descendents of inferior focus cycle roots.  In the default case
+   * however, ContainerOrderFocusTraversalPolicy is in effect, and it
+   * supports implicit down-cycle traversal operations.
+   *
+   * @return true if this is a focus cycle root, false otherwise
+   *
+   * @since 1.4
+   */
+  public void setFocusCycleRoot (boolean focusCycleRoot)
   {
+    this.focusCycleRoot = focusCycleRoot;
   }
-  
-  public boolean isFocusCycleRoot()
+
+  /**
+   * Check whether this Container is a focus cycle root.
+   *
+   * @return true if this is a focus cycle root, false otherwise
+   *
+   * @since 1.4
+   */
+  public boolean isFocusCycleRoot ()
   {
-    return false;
+    return focusCycleRoot;
   }
-  
-  public void transferFocusDownCycle()
+
+  /**
+   * Transfer focus down one focus traversal cycle.  If this Container
+   * is a focus cycle root, then its default component becomes the
+   * focus owner, and this Container becomes the current focus cycle
+   * root.  No traversal will occur if this Container is not a focus
+   * cycle root.
+   *
+   * @since 1.4
+   */
+  public void transferFocusDownCycle ()
   {
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+    manager.downFocusCycle (this);
   }
 
   /**
@@ -1369,6 +1584,61 @@
 	      }
           }
       }
+  }
+
+  /**
+   * Deserialize this Container:
+   * <ol>
+   * <li>Read from the stream the default serializable fields.</li>
+   * <li>Read a list of serializable ContainerListeners as optional
+   * data.  If the list is null, no listeners will be registered.</li>
+   * <li>Read this Container's FocusTraversalPolicy as optional data.
+   * If this is null, then this Container will use a
+   * DefaultFocusTraversalPolicy.</li>
+   * </ol>
+   *
+   * @param s the stream to read from
+   * @throws ClassNotFoundException if deserialization fails
+   * @throws IOException if the stream fails
+   */
+  private void readObject (ObjectInputStream s)
+    throws ClassNotFoundException, IOException
+  {
+    s.defaultReadObject ();
+    String key = (String) s.readObject ();
+    while (key != null)
+      {
+        Object object = s.readObject ();
+        if ("containerL".equals (key))
+          addContainerListener((ContainerListener) object);
+        // FIXME: under what key is the focus traversal policy stored?
+        else if ("focusTraversalPolicy".equals (key))
+          setFocusTraversalPolicy ((FocusTraversalPolicy) object);
+
+        key = (String) s.readObject();
+      }
+  }
+
+  /**
+   * Serialize this Container:
+   * <ol>
+   * <li>Write to the stream the default serializable fields.</li>
+   * <li>Write the list of serializable ContainerListeners as optional
+   * data.</li>
+   * <li>Write this Container's FocusTraversalPolicy as optional data.</li>
+   * </ol>
+   *
+   * @param s the stream to write to
+   * @throws IOException if the stream fails
+   */
+  private void writeObject (ObjectOutputStream s) throws IOException
+  {
+    s.defaultWriteObject ();
+    AWTEventMulticaster.save (s, "containerL", containerListener);
+    if (focusTraversalPolicy instanceof Serializable)
+      s.writeObject (focusTraversalPolicy);
+    else
+      s.writeObject (null);
   }
 
   // Nested classes.
Index: java/awt/ContainerOrderFocusTraversalPolicy.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java,v
retrieving revision 1.5
diff -u -r1.5 ContainerOrderFocusTraversalPolicy.java
--- java/awt/ContainerOrderFocusTraversalPolicy.java	24 Mar 2003 13:50:32 -0000	1.5
+++ java/awt/ContainerOrderFocusTraversalPolicy.java	22 Apr 2004 16:01:10 -0000
@@ -41,7 +41,23 @@
 import java.io.Serializable;
 
 /**
+ * ContainerOrderFocusTraversalPolicy defines a focus traversal order
+ * based on the order in which Components were packed in a Container.
+ * This policy performs a pre-order traversal of the Component
+ * hierarchy starting from a given focus cycle root.  Portions of the
+ * hierarchy that are not visible and displayable are skipped.
+ *
+ * By default, this policy transfers focus down-cycle implicitly.
+ * That is, if a forward traversal is requested on a focus cycle root
+ * and the focus cycle root has focusable children, the focus will
+ * automatically be transfered down to the lower focus cycle.
+ *
+ * The default implementation of accept accepts only Components that
+ * are visible, displayable, enabled and focusable.  Derived classes
+ * can override these acceptance criteria by overriding accept.
+ *
  * @author Michael Koch
+ * @author Thomas Fitzsimmons <fitzsim@redhat.com>
  * @since 1.4
  */
 public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy
@@ -52,12 +68,15 @@
    */
   static final long serialVersionUID = 486933713763926351L;
 
+  /**
+   * True if implicit down cycling is enabled.
+   */
   private boolean implicitDownCycleTraversal = true;
 
   /**
    * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object.
    */
-  public ContainerOrderFocusTraversalPolicy()
+  public ContainerOrderFocusTraversalPolicy ()
   {
     // Nothing to do here
   }
@@ -66,37 +85,193 @@
    * Returns the Component that should receive the focus after current.
    * root must be a focus cycle root of current.
    *
+   * @param root a focus cycle root of current
+   * @param current a (possibly indirect) child of root, or root itself
+   *
+   * @return the next Component in the focus traversal order for root,
+   * or null if no acceptable Component exists.
+   *
    * @exception IllegalArgumentException If root is not a focus cycle
    * root of current, or if either root or current is null.
    */
-  public Component getComponentAfter(Container root, Component current)
+  public Component getComponentAfter (Container root, Component current)
   {
-    if (root == null
-        || current == null)
-      throw new IllegalArgumentException ();
-    
+    if (root == null)
+      throw new IllegalArgumentException ("focus cycle root is null");
+    if (current == null)
+      throw new IllegalArgumentException ("current component is null");
+
+    // FIXME: is this the right thing to do here? it move the context
+    // for traversal up one focus traversal cycle.
+    if ((Component) root == current)
+      root = current.getFocusCycleRootAncestor ();
+
+    Container ancestor = current.getFocusCycleRootAncestor ();
+    Container prevAncestor = ancestor;
+    while (ancestor != root)
+      {
+	ancestor = current.getFocusCycleRootAncestor ();
+	if (ancestor == prevAncestor)
+	  {
+	    // We've reached the top focus cycle root ancestor.  Check
+	    // if it is root.
+	    if (ancestor != root)
+	      throw new IllegalArgumentException ("the given container is not"
+						  + " a focus cycle root of the"
+						  + " current component");
+	    else
+	      break;
+	  }
+	prevAncestor = ancestor;
+      }
+
+    // FIXME: need locking on root.
+    Component[] components = root.getComponents ();
+    int componentIndex = 0;
+    int numComponents = root.getComponentCount ();
+
+    // Find component's index.
+    for (int i = 0; i < numComponents; i++)
+      {
+	if (components[i] == current)
+	  componentIndex = i;
+      }
+
+    // Search forward for the next acceptable component.
+    for (int i = componentIndex + 1; i < numComponents; i++)
+      {
+        if (components[i] instanceof Container)
+          {
+            Component result = getFirstComponent ((Container) components[i]);
+
+            if (result != null
+		&& implicitDownCycleTraversal)
+              return result;
+          }
+
+	if (accept (components[i]))
+	  return components[i];
+      }
+
+    for (int i = 0; i < componentIndex; i++)
+      {
+        if (components[i] instanceof Container)
+          {
+            Component result = getFirstComponent ((Container) components[i]);
+
+            if (result != null
+		&& implicitDownCycleTraversal)
+              return result;
+          }
+
+	// FIXME: see below.
+	if (accept (components[i]))
+	  return components[i];
+      }
+
+    // No acceptable component found.
     return null;
   }
 
   /**
-   * Returns the Component that should receive the focus before current.
-   * root must be a focus cycle root of current.
+   * Returns the Component that should receive the focus before
+   * <code>current</code>.  <code>root</code> must be a focus cycle
+   * root of current.
+   *
+   * @param root a focus cycle root of current
+   * @param current a (possibly indirect) child of root, or root itself
+   *
+   * @return the previous Component in the focus traversal order for
+   * root, or null if no acceptable Component exists.
    *
    * @exception IllegalArgumentException If root is not a focus cycle
    * root of current, or if either root or current is null.
    */
-  public Component getComponentBefore(Container root, Component current)
+  public Component getComponentBefore (Container root, Component current)
   {
-    if (root == null
-        || current == null)
-      throw new IllegalArgumentException ();
+    if (root == null)
+      throw new IllegalArgumentException ("focus cycle root is null");
+    if (current == null)
+      throw new IllegalArgumentException ("current component is null");
+
+    // FIXME: is this the right thing to do here? it move the context
+    // for traversal up one focus traversal cycle.
+    if ((Component) root == current)
+      root = current.getFocusCycleRootAncestor ();
+
+    Container ancestor = current.getFocusCycleRootAncestor ();
+    Container prevAncestor = ancestor;
+    while (ancestor != root)
+      {
+	ancestor = current.getFocusCycleRootAncestor ();
+	if (ancestor == prevAncestor)
+	  {
+	    // We've reached the top focus cycle root ancestor.  Check
+	    // if it is root.
+	    if (ancestor != root)
+	      throw new IllegalArgumentException ("the given container is not"
+						  + " a focus cycle root of the"
+						  + " current component");
+	    else
+	      break;
+	  }
+	prevAncestor = ancestor;
+      }
+
+    // FIXME: need locking on root.
+    Component[] components = root.getComponents ();
+    int componentIndex = 0;
+    int numComponents = root.getComponentCount ();
+
+    // Find component's index.
+    for (int i = 0; i < numComponents; i++)
+      {
+	if (components[i] == current)
+	  componentIndex = i;
+      }
 
+    // Search backward for the next acceptable component.
+    for (int i = componentIndex - 1; i >= 0; i--)
+      {
+        if (components[i] instanceof Container)
+          {
+            Component result = getLastComponent ((Container) components[i]);
+
+            if (result != null)
+              return result;
+          }
+
+	if (accept (components[i]))
+	  return components[i];
+      }
+
+    for (int i = numComponents - 1; i > componentIndex; i--)
+      {
+        if (components[i] instanceof Container)
+          {
+            Component result = getLastComponent ((Container) components[i]);
+
+            if (result != null)
+              return result;
+          }
+
+	// FIXME: see below.
+	if (accept (components[i]))
+	  return components[i];
+      }
+
+    // No acceptable component found.
     return null;
   }
 
   /**
    * Returns the first Component of root that should receive the focus.
    *
+   * @param root a focus cycle root
+   *
+   * @return the first Component in the focus traversal order for
+   * root, or null if no acceptable Component exists.
+   *
    * @exception IllegalArgumentException If root is null.
    */
   public Component getFirstComponent(Container root)
@@ -119,16 +294,17 @@
 	
         if (component instanceof Container)
           {
-            Component result = getLastComponent ((Container) component);
+            Component result = getFirstComponent ((Container) component);
 
             if (result != null)
               return result;
           }
-        else
-          {
-            if (accept (component))
-              return component;
-          }
+
+	// FIXME: can the container itself be focused?  if not, then
+	// this part needs to be in the else clause of the if
+	// statement above.
+	if (accept (component))
+	  return component;
       }
 
     return null;
@@ -137,9 +313,14 @@
   /**
    * Returns the last Component of root that should receive the focus.
    *
+   * @param root a focus cycle root
+   *
+   * @return the last Component in the focus traversal order for
+   * root, or null if no acceptable Component exists.
+   *
    * @exception IllegalArgumentException If root is null.
    */
-  public Component getLastComponent(Container root)
+  public Component getLastComponent (Container root)
   {
     if (root == null)
       throw new IllegalArgumentException ();
@@ -164,11 +345,10 @@
             if (result != null)
               return result;
           }
-        else
-          {
-            if (accept (component))
-              return component;
-          }
+
+	// FIXME: see above.
+	if (accept (component))
+	  return component;
       }
 
     return null;
@@ -177,28 +357,58 @@
   /**
    * Returns the default Component of root that should receive the focus.
    *
+   * @param root a focus cycle root
+   *
+   * @return the default Component in the focus traversal order for
+   * root, or null if no acceptable Component exists.
+   *
    * @exception IllegalArgumentException If root is null.
    */
-  public Component getDefaultComponent(Container root)
+  public Component getDefaultComponent (Container root)
   {
     return getFirstComponent (root);
   }
 
-  public void setImplicitDownCycleTraversal(boolean value)
+  /**
+   * Set whether or not implicit down cycling is enabled.  If it is,
+   * then initiating a forward focus traversal operation onto a focus
+   * cycle root, the focus will be implicitly transferred into the
+   * root container's focus cycle.
+   *
+   * @param value the setting for implicit down cycling
+   */
+  public void setImplicitDownCycleTraversal (boolean value)
   {
     implicitDownCycleTraversal = value;
   }
 
-  public boolean getImplicitDownCycleTraversal()
+  /**
+   * Check whether or not implicit down cycling is enabled.  If it is,
+   * then initiating a forward focus traversal operation onto a focus
+   * cycle root, the focus will be implicitly transferred into the
+   * root container's focus cycle.
+   *
+   * @return true if the focus will be transferred down-cycle
+   * implicitly
+   */
+  public boolean getImplicitDownCycleTraversal ()
   {
     return implicitDownCycleTraversal;
   }
 
-  protected boolean accept(Component current)
+  /**
+   * Check whether the given Component is an acceptable target for the
+   * keyboard input focus.
+   *
+   * @param current the Component to check
+   *
+   * @return true if current is acceptable, false otherwise
+   */
+  protected boolean accept (Component current)
   {
     return (current.visible
-            && current.isDisplayable()
+            && current.isDisplayable ()
             && current.enabled
             && current.focusable);
   }
-} // class ContainerOrderFocusTraversalPolicy
+}
Index: java/awt/DefaultFocusTraversalPolicy.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/DefaultFocusTraversalPolicy.java,v
retrieving revision 1.1
diff -u -r1.1 DefaultFocusTraversalPolicy.java
--- java/awt/DefaultFocusTraversalPolicy.java	9 Aug 2002 04:26:14 -0000	1.1
+++ java/awt/DefaultFocusTraversalPolicy.java	22 Apr 2004 16:01:10 -0000
@@ -39,17 +39,73 @@
 package java.awt;
 
 /**
- * STUB CLASS ONLY
+ * DefaultFocusTraversalPolicy is the default focus traversal policy
+ * used by Containers.
+ *
+ * This policy sharpens ContainerOrderFocusTraversalPolicy's
+ * acceptance criteria, to reject those Components that have
+ * unfocusable peers.  Despite this extra strictness, this policy will
+ * always accept a Component that has explicitly been set focusable by
+ * any means.
+ *
+ * This AWT implementation assumes that the peers of the following
+ * Components are not focusable: Canvas, Panel, Label, ScrollPane,
+ * Scrollbar, Window, and any lightweight Component.
+ *
+ * A Component's focusability is independent of the focusability of
+ * its peer.
+ *
+ * @author Thomas Fitzsimmons <fitzsim@redhat.com>
+ * @since 1.4
  */
 public class DefaultFocusTraversalPolicy
   extends ContainerOrderFocusTraversalPolicy
 {
-  public DefaultFocusTraversalPolicy()
+  /**
+   * Construct a default focus traversal policy.
+   */
+  public DefaultFocusTraversalPolicy ()
   {
   }
 
-  protected boolean accept(Component comp)
+  /**
+   * Check whether a given Component would be acceptable as a focus
+   * owner.  The Component must be displayable, visible and enabled to
+   * be acceptable.  If the Component's focus traversability has been
+   * overridden, by overriding Component.isFocusTraversable or
+   * Component.isFocusable, or by calling Component.setFocusable, then
+   * the Component will be accepted if it is focusable.  If the
+   * Component uses the default focus traversable behaviour, then
+   * <code>comp</code> will always be rejected if it is a Canvas,
+   * Panel, Label, ScrollPane, Scrollbar, Window or lightweight
+   * Component.
+   *
+   * @param comp the Component to check
+   *
+   * @return true if the Component is an acceptable target for
+   * keyboard input focus, false otherwise
+   */
+  protected boolean accept (Component comp)
   {
-    throw new Error("not implemented");
+    if (comp.visible
+	&& comp.isDisplayable ()
+	&& comp.enabled)
+      {
+	if (comp.isFocusTraversableOverridden != 0
+	    && comp.isFocusTraversable ())
+	  return true;
+	else
+	  {
+	    if (!(comp instanceof Canvas
+		  || comp instanceof Panel
+		  || comp instanceof Label
+		  || comp instanceof ScrollPane
+		  || comp instanceof Scrollbar
+		  || comp instanceof Window
+		  || comp.isLightweight ()))
+	      return true;
+	  }
+      }
+    return false;
   }
-} // class DefaultFocusTraversalPolicy
+}
Index: java/awt/DefaultKeyboardFocusManager.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/DefaultKeyboardFocusManager.java,v
retrieving revision 1.1
diff -u -r1.1 DefaultKeyboardFocusManager.java
--- java/awt/DefaultKeyboardFocusManager.java	9 Aug 2002 04:26:14 -0000	1.1
+++ java/awt/DefaultKeyboardFocusManager.java	22 Apr 2004 16:01:10 -0000
@@ -38,59 +38,434 @@
 
 package java.awt;
 
-import java.awt.event.KeyEvent;
+import java.util.*;
+import java.awt.event.*;
 
-/**
- * STUB CLASS ONLY
- */
+// FIXME: finish documentation
 public class DefaultKeyboardFocusManager extends KeyboardFocusManager
 {
-  public DefaultKeyboardFocusManager()
+  /**
+   * This class models a request to delay the dispatch of events that
+   * arrive after a certain time, until a certain component becomes
+   * the focus owner.
+   */
+  private class EventDelayRequest implements Comparable
+  {
+    /** A {@link java.util.List} of {@link java.awt.event.KeyEvent}s
+        that are being delayed, pending this request's {@link
+        Component} receiving the keyboard focus. */
+    private LinkedList enqueuedKeyEvents = new LinkedList ();
+
+    /** An event timestamp.  All events that arrive after this time
+        should be queued in the {@link #enqueuedKeyEvents} {@link
+        java.util.List}. */
+    public long timestamp;
+    /** When this {@link Component} becomes focused, all events
+        between this EventDelayRequest and the next one in will be
+        dispatched from {@link #enqueuedKeyEvents}. */
+    public Component focusedComp;
+
+    /**
+     * Construct a new EventDelayRequest.
+     *
+     * @param timestamp events that arrive after this time will be
+     * delayed
+     * @param focusedComp the Component that needs to receive focus
+     * before events are dispatched
+     */
+    public EventDelayRequest (long timestamp, Component focusedComp)
+    {
+      this.timestamp = timestamp;
+      this.focusedComp = focusedComp;
+    }
+
+    public int compareTo (Object o)
+    {
+      if (!(o instanceof EventDelayRequest))
+        throw new ClassCastException ();
+
+      EventDelayRequest request = (EventDelayRequest) o;
+
+      if (request.timestamp < timestamp)
+        return -1;
+      else if (request.timestamp == timestamp)
+        return 0;
+      else
+        return 1;
+    }
+
+    public boolean equals (Object o)
+    {
+      if (!(o instanceof EventDelayRequest) || o == null)
+        return false;
+
+      EventDelayRequest request = (EventDelayRequest) o;
+
+      return (request.timestamp == timestamp
+              && request.focusedComp == focusedComp);
+    }
+
+    public void enqueueEvent (KeyEvent e)
+    {
+      KeyEvent last = (KeyEvent) enqueuedKeyEvents.getLast ();
+      if (last != null && e.getWhen () < last.getWhen ())
+        throw new RuntimeException ("KeyEvents enqueued out-of-order");
+
+      if (e.getWhen () <= timestamp)
+        throw new RuntimeException ("KeyEvents enqueued before starting timestamp");
+
+      enqueuedKeyEvents.add (e);
+    }
+
+    public void dispatchEvents ()
+    {
+      int size = enqueuedKeyEvents.size ();
+      for (int i = 0; i < size; i++)
+        {
+          KeyEvent e = (KeyEvent) enqueuedKeyEvents.remove (0);
+          dispatchKeyEvent (e);
+        }
+    }
+
+    public void discardEvents ()
+    {
+      enqueuedKeyEvents.clear ();
+    }
+  }
+
+  /** The {@link java.util.SortedSet} of current {@link
+      #EventDelayRequest}s. */
+  private SortedSet delayRequests = new TreeSet ();
+
+  public DefaultKeyboardFocusManager ()
   {
   }
 
-  public boolean dispatchEvent(AWTEvent e)
+  public boolean dispatchEvent (AWTEvent e)
   {
-    throw new Error("not implemented");
+    if (e instanceof WindowEvent)
+      {
+        Window target = (Window) e.getSource ();
+
+        if (e.id == WindowEvent.WINDOW_ACTIVATED)
+          setGlobalActiveWindow (target);
+        else if (e.id == WindowEvent.WINDOW_GAINED_FOCUS)
+          setGlobalFocusedWindow (target);
+        else if (e.id != WindowEvent.WINDOW_LOST_FOCUS
+                 && e.id != WindowEvent.WINDOW_DEACTIVATED)
+          return false;
+
+        target.dispatchEvent (e);
+        return true;
+      }
+    else if (e instanceof FocusEvent)
+      {
+        Component target = (Component) e.getSource ();
+
+        if (e.id == FocusEvent.FOCUS_GAINED)
+          {
+            if (((FocusEvent) e).isTemporary ())
+              setGlobalFocusOwner (target);
+            else
+              {
+                System.out.println ("SETTING FOCUS TO: " + target);
+                setGlobalPermanentFocusOwner (target);
+              }
+          }
+
+        target.dispatchEvent (e);
+        return true;
+      }
+    else if (e instanceof KeyEvent)
+      {
+        // Loop through all registered KeyEventDispatchers, giving
+        // each a chance to handle this event.
+        Iterator i = keyEventDispatchers.iterator ();
+
+        while (i.hasNext ())
+          {
+            KeyEventDispatcher dispatcher = (KeyEventDispatcher) i.next ();
+            if (dispatcher.dispatchKeyEvent ((KeyEvent) e))
+              return true;
+          }
+
+        // processKeyEvent checks if this event represents a focus
+        // traversal key stroke.
+        Component focusOwner = getGlobalPermanentFocusOwner ();
+        processKeyEvent (focusOwner, (KeyEvent) e);
+
+        if (e.isConsumed ())
+          return true;
+
+        if (enqueueKeyEvent ((KeyEvent) e))
+          // This event was enqueued for dispatch at a later time.
+          return true;
+        else
+          // This event wasn't handled by any of the registered
+          // KeyEventDispatchers, and wasn't enqueued for dispatch
+          // later, so send it to the default dispatcher.
+          return dispatchKeyEvent ((KeyEvent) e);
+      }
+
+    return false;
   }
-  public boolean dispatchKeyEvent(KeyEvent e)
+
+  private boolean enqueueKeyEvent (KeyEvent e)
   {
-    throw new Error("not implemented");
+    Iterator i = delayRequests.iterator ();
+    boolean oneEnqueued = false;
+    while (i.hasNext ())
+      {
+        EventDelayRequest request = (EventDelayRequest) i.next ();
+        if (e.getWhen () > request.timestamp)
+          {
+            request.enqueueEvent (e);
+            oneEnqueued = true;
+          }
+      }
+    return oneEnqueued;
+  }
+
+  public boolean dispatchKeyEvent (KeyEvent e)
+  {
+    //    System.out.println ("DefaultKeyboardFocusManager.dispatchKeyEvent: " + e);
+
+    Component focusOwner = getGlobalPermanentFocusOwner ();
+
+    focusOwner.dispatchEvent (e);
+
+    // Loop through all registered KeyEventPostProcessors, giving
+    // each a chance to process this event.
+    Iterator i = keyEventPostProcessors.iterator ();
+
+    while (i.hasNext ())
+      {
+        KeyEventPostProcessor processor = (KeyEventPostProcessor) i.next ();
+        if (processor.postProcessKeyEvent ((KeyEvent) e))
+          return true;
+      }
+
+    // The event hasn't been consumed yet.  Check if it is an
+    // MenuShortcut.
+    if (postProcessKeyEvent (e))
+      return true;
+
+    // FIXME: how do we "pass the event to the peers for processing"?
+
+    // Always return true.
+    return true;
   }
-  public boolean postProcessKeyEvent(KeyEvent e)
+
+  public boolean postProcessKeyEvent (KeyEvent e)
   {
-    throw new Error("not implemented");
+    //    System.out.println ("DefaultKeyboardFocusManager.postProcessKeyEvent: " + e);
+
+    // Check if this event represents a menu shortcut.
+
+    // MenuShortcuts are activated by Ctrl- KeyEvents.
+    int modifiers = e.getModifiers ();
+    if ((modifiers & KeyEvent.CTRL_MASK) != 0
+        || (modifiers & KeyEvent.CTRL_DOWN_MASK) != 0)
+      {
+        Window focusedWindow = getGlobalFocusedWindow ();
+        if (focusedWindow instanceof Frame)
+          {
+            MenuBar menubar = ((Frame) focusedWindow).getMenuBar ();
+
+            if (menubar != null)
+              {
+                // If there's a menubar, loop through all menu items,
+                // checking whether each one has a shortcut, and if
+                // so, whether this key event should activate it.
+                int numMenus = menubar.getMenuCount ();
+
+                for (int i = 0; i < numMenus; i++)
+                  {
+                    Menu menu = menubar.getMenu (i);
+                    int numItems = menu.getItemCount ();
+
+                    for (int j = 0; j < numItems; j++)
+                      {
+                        MenuItem item = menu.getItem (j);
+                        MenuShortcut shortcut = item.getShortcut ();
+
+                        if (shortcut != null)
+                          {
+                            // Dispatch a new ActionEvent if this is a
+                            // Shift- KeyEvent and the shortcut requires
+                            // the Shift modifier, or if the shortcut
+                            // doesn't require the Shift modifier.
+                            if ((shortcut.usesShiftModifier ()
+                                 && ((modifiers & KeyEvent.SHIFT_MASK) != 0
+                                     || (modifiers & KeyEvent.SHIFT_DOWN_MASK) != 0)
+                                 || !shortcut.usesShiftModifier ())
+                                && shortcut.getKey () == e.getKeyCode ())
+                              {
+                                item.dispatchEvent (new ActionEvent (item,
+                                                                     ActionEvent.ACTION_PERFORMED,
+                                                                     item.getActionCommand (),
+                                                                     modifiers));
+                                // The event was dispatched.
+                                return true;
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+    return false;
   }
-  public void processKeyEvent(Component comp, KeyEvent e)
+
+  public void processKeyEvent (Component comp, KeyEvent e)
   {
-    throw new Error("not implemented");
+    //    System.out.println ("DefaultKeyboardFocusManager.processKeyEvent: " + e);
+
+    AWTKeyStroke keystroke = AWTKeyStroke.getAWTKeyStrokeForEvent (e);
+
+    Set forwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
+    Set backwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
+    Set upKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
+    Set downKeystrokes = null;
+    if (comp instanceof Container)
+      downKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
+
+    if (forwardKeystrokes.contains (keystroke))
+      {
+        focusNextComponent (comp);
+        e.consume ();
+      }
+    else if (backwardKeystrokes.contains (keystroke))
+      {
+        focusPreviousComponent (comp);
+        e.consume ();
+      }
+    else if (upKeystrokes.contains (keystroke))
+      {
+        upFocusCycle (comp);
+        e.consume ();
+      }
+    else if (comp instanceof Container
+             && downKeystrokes.contains (keystroke))
+      {
+        downFocusCycle ((Container) comp);
+        e.consume ();
+      }
   }
-  protected void enqueueKeyEvents(long after, Component comp)
+
+  protected void enqueueKeyEvents (long after, Component untilFocused)
   {
-    throw new Error("not implemented");
+    System.out.println ("DefaultKeyboardFocusManager.enqueueKeyEvents: " + untilFocused);
+
+    delayRequests.add (new EventDelayRequest (after, untilFocused));
   }
-  protected void dequeueKeyEvents(long after, Component comp)
+
+  protected void dequeueKeyEvents (long after, Component untilFocused)
   {
-    throw new Error("not implemented");
+    System.out.println ("DefaultKeyboardFocusManager.dequeueKeyEvents: " + untilFocused);
+
+    // FIXME: need synchronization on delayRequests and enqueuedKeyEvents.
+
+    // Remove the KeyEvent with the oldest timestamp, which should be
+    // the first element in the SortedSet.
+    if (after < 0)
+      {
+        int size = delayRequests.size ();
+        if (size > 0)
+          delayRequests.remove (delayRequests.first ());
+      }
+    else
+      {
+        EventDelayRequest template = new EventDelayRequest (after, untilFocused);
+        if (delayRequests.contains (template))
+          {
+            EventDelayRequest actual = (EventDelayRequest) delayRequests.tailSet (template).first ();
+            delayRequests.remove (actual);
+            actual.dispatchEvents ();
+          }
+      }
   }
-  protected void discardKeyEvents(Component comp)
+
+  protected void discardKeyEvents (Component comp)
   {
-    throw new Error("not implemented");
+    System.out.println ("DefaultKeyboardFocusManager.discardKeyEvents: " + comp);
+
+    // FIXME: need synchronization on delayRequests and enqueuedKeyEvents.
+
+    Iterator i = delayRequests.iterator ();
+
+    while (i.hasNext ())
+      {
+        EventDelayRequest request = (EventDelayRequest) i.next ();
+
+        if (request.focusedComp == comp
+            || (comp instanceof Container
+                && ((Container) comp).isAncestorOf (request.focusedComp)))
+          request.discardEvents ();
+      }
   }
-  public void focusPreviousComponent(Component comp)
+
+  public void focusPreviousComponent (Component comp)
   {
-    throw new Error("not implemented");
+    System.out.println ("DefaultKeyboardFocusManager.focusPreviousComponent: " + comp);
+
+    Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+    Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+    FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+
+    Component previous = policy.getComponentBefore (focusCycleRoot, focusComp);
+    previous.requestFocus ();
   }
-  public void focusNextComponent(Component comp)
+
+  public void focusNextComponent (Component comp)
   {
-    throw new Error("not implemented");
+    System.out.println ("DefaultKeyboardFocusManager.focusNextComponent: " + comp);
+
+    Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+    Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+    FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+
+    Component next = policy.getComponentAfter (focusCycleRoot, focusComp);
+    System.out.println ("Got next component: " + next);
+    System.out.println ("Got focus comp: " + focusComp);
+    next.requestFocus ();
   }
-  public void upFocusCycle(Component comp)
+
+  public void upFocusCycle (Component comp)
   {
-    throw new Error("not implemented");
+    System.out.println ("DefaultKeyboardFocusManager.upFocusCycle: " + comp);
+
+    Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp;
+    Container focusCycleRoot = focusComp.getFocusCycleRootAncestor ();
+
+    if (focusCycleRoot instanceof Window)
+      {
+        FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy ();
+        Component defaultComponent = policy.getDefaultComponent (focusCycleRoot);
+        defaultComponent.requestFocus ();
+      }
+    else
+      {
+        Container parentFocusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor ();
+
+        focusCycleRoot.requestFocus ();
+        setGlobalCurrentFocusCycleRoot (parentFocusCycleRoot);
+      }
   }
-  public void downFocusCycle(Container cont)
+
+  public void downFocusCycle (Container cont)
   {
-    throw new Error("not implemented");
+    System.out.println ("DefaultKeyboardFocusManager.downFocusCycle: " + cont);
+
+    if (cont == null)
+      return;
+
+    if (cont.isFocusCycleRoot (cont))
+      {
+        FocusTraversalPolicy policy = cont.getFocusTraversalPolicy ();
+        Component defaultComponent = policy.getDefaultComponent (cont);
+        defaultComponent.requestFocus ();
+        setGlobalCurrentFocusCycleRoot (cont);
+      }
   }
 } // class DefaultKeyboardFocusManager
Index: java/awt/EventDispatchThread.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/EventDispatchThread.java,v
retrieving revision 1.5
diff -u -r1.5 EventDispatchThread.java
--- java/awt/EventDispatchThread.java	16 Jan 2004 16:15:49 -0000	1.5
+++ java/awt/EventDispatchThread.java	22 Apr 2004 16:01:10 -0000
@@ -57,6 +57,9 @@
 
   public void run()
   {
+    // Set the default KeyboardFocusManager.
+    KeyboardFocusManager.setCurrentKeyboardFocusManager (null);
+
     while (true)
       {
         try
@@ -67,7 +70,23 @@
 	      // We are interrupted when we should finish executing
 	      return;
 	    }
-	  queue.dispatchEvent(evt);
+
+          KeyboardFocusManager manager;
+          manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+          // Try to dispatch this event to the current keyboard focus
+          // manager.  It will dispatch all FocusEvents, all
+          // WindowEvents related to focus, and all KeyEvents,
+          // returning true.  Otherwise, it returns false and we
+          // dispatch the event normally.
+          if (!manager.dispatchEvent (evt))
+            {
+              queue.dispatchEvent(evt);
+            }
+          else
+            {
+              //              System.out.println ("Dispatched " + evt + " to DefaultKeyboardFocusManager");
+            }
 	}
 	catch (InterruptedException ie)
 	{
Index: java/awt/KeyboardFocusManager.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/KeyboardFocusManager.java,v
retrieving revision 1.2
diff -u -r1.2 KeyboardFocusManager.java
--- java/awt/KeyboardFocusManager.java	13 Feb 2003 07:02:12 -0000	1.2
+++ java/awt/KeyboardFocusManager.java	22 Apr 2004 16:01:10 -0000
@@ -39,34 +39,66 @@
 package java.awt;
 
 import java.awt.event.KeyEvent;
+import java.awt.event.FocusEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.beans.PropertyVetoException;
 import java.beans.VetoableChangeListener;
 import java.beans.VetoableChangeSupport;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
+// FIXME: finish documentation
+
 /**
  *
+ * FIXME: discuss applet contexts and thread groups and codebases
+ * being insulated.
+ *
+ * FIXME: discuss where default focus traversal key sets apply
+ * (inherited by child Components etc.)
+ *
  * @author Eric Blake <ebb9@email.byu.edu>
+ * @author Thomas Fitzsimmons <fitzsim@redhat.com>
  * @since 1.4
  * @status partially updated to 1.4, needs documentation.
  */
 public abstract class KeyboardFocusManager
   implements KeyEventDispatcher, KeyEventPostProcessor
 {
+  /** Identifies {@link AWTKeyStroke}s that move the focus forward in
+      the focus cycle. */
   public static final int FORWARD_TRAVERSAL_KEYS = 0;
+
+  /** Identifies {@link AWTKeyStroke}s that move the focus backward in
+      the focus cycle. */
   public static final int BACKWARD_TRAVERSAL_KEYS = 1;
+
+  /** Identifies {@link AWTKeyStroke}s that move the focus up to the
+      parent focus cycle root. */
   public static final int UP_CYCLE_TRAVERSAL_KEYS = 2;
+
+  /** Identifies {@link AWTKeyStroke}s that move the focus down to the
+      child focus cycle root. */
   public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3;
 
+  /** The set of {@link AWTKeyStroke}s that cause focus to be moved to
+      the next focusable Component in the focus cycle. */
   private static final Set DEFAULT_FORWARD_KEYS;
+
+  /** The set of {@link AWTKeyStroke}s that cause focus to be moved to
+      the previous focusable Component in the focus cycle. */
   private static final Set DEFAULT_BACKWARD_KEYS;
+
+  /** Populate the DEFAULT_FORWARD_KEYS and DEFAULT_BACKWARD_KEYS
+      {@link java.util.Set}s. */
   static
   {
     Set s = new HashSet();
@@ -83,232 +115,403 @@
     DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s);
   }
 
-  private static KeyboardFocusManager current
-    = new DefaultKeyboardFocusManager();
-
-  // XXX Not implemented correctly. I think a good implementation here may
-  // be to have permanentFocusOwner be null, and fall back to focusOwner,
-  // unless a temporary focus change is in effect.
-  private static Component focusOwner;
-  private static Component permanentFocusOwner;
-
-  private static Window focusedWindow;
-  private static Window activeWindow;
-  private static Container focusCycleRoot;
+  /** The global object {@link java.util.Map}s. */
 
+  /** For security reasons, {@link java.applet.Applet}s in different
+      codebases must be insulated from one another.  Since {@link
+      KeyboardFocusManager}s have the ability to return {@link
+      Component}s from a given {@link java.applet.Applet}, each
+      codebase must have an independent {@link KeyboardFocusManager}.
+      Since each codebase has its own {@link ThreadGroup} in which its
+      {@link Applet}s run, it makes sense to partition {@link
+      KeyboardFocusManager}s according to {@link
+      java.lang.ThreadGroup}.  Thus, currentKeyboardFocusManagers is a
+      {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}. */
+  private static Map currentKeyboardFocusManagers = new HashMap ();
+
+  /** {@link java.applet.Applet}s in one codebase must not be allowed
+      to access {@link Component}s in {@link java.applet.Applet}s in
+      other codebases.  To enforce this restriction, we key the
+      following {@link java.util.Map}s on {@link java.lang.ThreadGroup}s (which
+      are per-codebase).  For example, if {@link
+      java.lang.ThreadGroup} A calls {@link #setGlobalFocusOwner},
+      passing {@link Component} C, currentFocusOwners[A] is assigned
+      C, and all other currentFocusOwners values are nullified.  Then
+      if {@link java.lang.ThreadGroup} A subsequently calls {@link
+      #getGlobalFocusOwner}, it will return currentFocusOwners[A],
+      that is, {@link Component} C.  If another {@link
+      java.lang.ThreadGroup} K calls {@link #getGlobalFocusOwner}, it
+      will return currentFocusOwners[K], that is, null.
+
+      Since this is a static field, we ensure that there is only one
+      focused {@link Component} per class loader. */
+  private static Map currentFocusOwners = new HashMap ();
+
+  /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s
+      that stores the {@link Component} that owns the permanent
+      keyboard focus. @see currentFocusOwners */
+  private static Map currentPermanentFocusOwners = new HashMap ();
+
+  /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s
+      that stores the focused {@link Window}. @see
+      currentFocusOwners */
+  private static Map currentFocusedWindows = new HashMap ();
+
+  /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s
+      that stores the active {@link Window}. @see
+      currentFocusOwners */
+  private static Map currentActiveWindows = new HashMap ();
+
+  /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s
+      that stores the focus cycle root {@link Container}. @see
+      currentFocusOwners */
+  private static Map currentFocusCycleRoots = new HashMap ();
+
+  /** The default {@link FocusTraveralPolicy} that focus-managing
+      {@link Container}s will use to define their initial focus
+      traversal policy. */
   private FocusTraversalPolicy defaultPolicy;
-  private Set[] defaultFocusKeys = new Set[] {
+
+  /** An array that stores the {@link #FORWARD_TRAVERSAL_KEYS}, {@link
+      #BACKWARD_TRAVERSAL_KEYS}, {@link #UP_CYCLE_TRAVERSAL_KEYS} and
+      {@link #DOWN_CYCLE_TRAVERSAL_KEYS} {@link AWTKeyStroke}s {@link
+      java.util.Set}s. */
+  private Set[] defaultFocusKeys = new Set[]
+  {
     DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS,
     Collections.EMPTY_SET, Collections.EMPTY_SET
   };
 
-  private final PropertyChangeSupport propertyChangeSupport
-    = new PropertyChangeSupport(this);
-  private final VetoableChangeSupport vetoableChangeSupport
-    = new VetoableChangeSupport(this);
+  private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport (this);
+  private final VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport (this);
+
+  /** A list of {@link KeyEventDispatcher}s that process {@link
+      KeyEvent}s before they are processed the default keyboard focus
+      manager. */
   private final ArrayList keyEventDispatchers = new ArrayList();
-  private final ArrayList keyEventPostProcessors = new ArrayList();
 
-
-  public KeyboardFocusManager()
-  {
-  }
+  /** A list of {@link KeyEventPostProcessor}s that process unconsumed
+      {@link KeyEvent}s. */
+  private final ArrayList keyEventPostProcessors = new ArrayList();
 
-  public static KeyboardFocusManager getCurrentKeyboardFocusManager()
+  /**
+   * Construct a KeyboardFocusManager.
+   */
+  public KeyboardFocusManager ()
   {
-    // XXX Need a way to divide this into contexts.
-    return current;
   }
 
-  public static void setCurrentKeyboardFocusManager(KeyboardFocusManager m)
+  /**
+   * Retrieve the keyboard focus manager associated with the {@link
+   * java.lang.ThreadGroup} to which the calling thread belongs.
+   *
+   * @return the keyboard focus manager associated with the current
+   * thread group
+   */
+  public static KeyboardFocusManager getCurrentKeyboardFocusManager ()
+  {
+    ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+    return (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup);
+  }
+
+  /**
+   * Set the keyboard focus manager associated with the {@link
+   * java.lang.ThreadGroup} to which the calling thread belongs.
+   *
+   * @param m the keyboard focus manager for the current thread group
+   */
+  public static void setCurrentKeyboardFocusManager (KeyboardFocusManager m)
   {
-    SecurityManager sm = System.getSecurityManager();
+    SecurityManager sm = System.getSecurityManager ();
     if (sm != null)
-      sm.checkPermission(new AWTPermission("replaceKeyboardFocusManager"));
-    // XXX Need a way to divide this into contexts.
-    current = m == null ? new DefaultKeyboardFocusManager() : m;
-  }
+      sm.checkPermission (new AWTPermission ("replaceKeyboardFocusManager"));
 
-  public Component getFocusOwner()
-  {
-    // XXX Need an easy way to test if this thread is in the context of the
-    // global focus owner, to avoid creating the exception in the first place.
-    try
-      {
-        return getGlobalFocusOwner();
-      }
-    catch (SecurityException e)
-      {
-        return null;
-      }
-  }
-
-  protected Component getGlobalFocusOwner()
-  {
-    // XXX Need a way to test if this thread is in the context of the focus
-    // owner, and throw a SecurityException if that is the case.
-    // XXX Implement.
-    return focusOwner;
-  }
+    ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+    KeyboardFocusManager manager;
 
-  protected void setGlobalFocusOwner(Component owner)
+    if (m == null)
+      manager = new DefaultKeyboardFocusManager ();
+    else
+      manager = m;
+
+    currentKeyboardFocusManagers.put (currentGroup, manager);
+  }
+
+  /**
+   * Retrieve the {@link Component} that has the keyboard focus, or
+   * null if the focus owner was not set by a thread in the current
+   * {@link java.lang.ThreadGroup}.
+   *
+   * @return the keyboard focus owner or null
+   */
+  public Component getFocusOwner ()
+  {
+    return (Component) getObject (currentFocusOwners);
+  }
+
+  /**
+   * Retrieve the {@link Component} that has the keyboard focus,
+   * regardless of whether or not it was set by a thread in the
+   * current {@link java.lang.ThreadGroup}.  If there is no temporary
+   * focus owner in effect then this method will return the same value
+   * as {@link #getGlobalPermanentFocusOwner}.
+   *
+   * @return the keyboard focus owner
+   * @throws SecurityException if this is not the keyboard focus
+   * manager associated with the current {@link java.lang.ThreadGroup}
+   */
+  protected Component getGlobalFocusOwner ()
+  {
+    // Check if there is a temporary focus owner.
+    Component focusOwner = (Component) getGlobalObject (currentFocusOwners);
+
+    return (focusOwner == null) ? getGlobalPermanentFocusOwner () : focusOwner;
+  }
+
+  /**
+   * Set the {@link Component} that will be returned by {@link
+   * #getFocusOwner} (when it is called from the current {@link
+   * java.lang.ThreadGroup}) and {@link #getGlobalFocusOwner}.  This
+   * method does not actually transfer the keyboard focus.
+   *
+   * @param owner the Component to return from getFocusOwner and
+   * getGlobalFocusOwner
+   *
+   * @see Component.requestFocus ()
+   * @see Component.requestFocusInWindow ()
+   */
+  protected void setGlobalFocusOwner (Component owner)
   {
-    // XXX Should this send focus events to the components involved?
     if (owner == null || owner.focusable)
-      {
-        firePropertyChange("focusOwner", focusOwner, owner);
-        try
-          {
-            fireVetoableChange("focusOwner", focusOwner, owner);
-            focusOwner = owner;
-          }
-        catch (PropertyVetoException e)
-          {
-          }
-      }
+      setGlobalObject (currentFocusOwners, owner, "focusOwner");
   }
 
-  public void clearGlobalFocusOwner()
+  /**
+   * Clear the global focus owner and deliver a FOCUS_LOST event to
+   * the previously-focused {@link Component}.  Until another {@link
+   * Component} becomes the keyboard focus owner, key events will be
+   * discarded by top-level windows.
+   */
+  public void clearGlobalFocusOwner ()
   {
-    // XXX Is this enough?
-    setGlobalFocusOwner(null);
-  }
-
-  public Component getPermanentFocusOwner()
-  {
-    // XXX Need an easy way to test if this thread is in the context of the
-    // global focus owner, to avoid creating the exception in the first place.
-    try
+    synchronized (currentFocusOwners)
       {
-        return getGlobalPermanentFocusOwner();
-      }
-    catch (SecurityException e)
-      {
-        return null;
-      }
-  }
+        Component focusOwner = getGlobalFocusOwner ();
+        Component permanentFocusOwner = getGlobalPermanentFocusOwner ();
 
-  protected Component getGlobalPermanentFocusOwner()
-  {
-    // XXX Need a way to test if this thread is in the context of the focus
-    // owner, and throw a SecurityException if that is the case.
-    // XXX Implement.
-    return permanentFocusOwner == null ? focusOwner : permanentFocusOwner;
-  }
+        setGlobalFocusOwner (null);
+        setGlobalPermanentFocusOwner (null);
 
-  protected void setGlobalPermanentFocusOwner(Component focusOwner)
-  {
-    // XXX Should this send focus events to the components involved?
-    if (focusOwner == null || focusOwner.focusable)
-      {
-        firePropertyChange("permanentFocusOwner", permanentFocusOwner,
-                           focusOwner);
-        try
+        // Inform the old focus owner that it has lost permanent
+        // focus.
+        if (focusOwner != null)
           {
-            fireVetoableChange("permanentFocusOwner", permanentFocusOwner,
-                               focusOwner);
-            permanentFocusOwner = focusOwner;
+            // We can't cache the event queue, because of
+            // bootstrapping issues.  We need to set the default
+            // KeyboardFocusManager in EventQueue before the event
+            // queue is started.
+            EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+            if (focusOwner != permanentFocusOwner)
+              q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, true));
+            else
+              q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, false));
           }
-        catch (PropertyVetoException e)
+
+        if (focusOwner != permanentFocusOwner)
           {
+            EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+            q.postEvent (new FocusEvent (permanentFocusOwner, FocusEvent.FOCUS_LOST, false));
           }
       }
   }
 
-  public Window getFocusedWindow()
+  /**
+   * Retrieve the {@link Component} that has the permanent keyboard
+   * focus, or null if the focus owner was not set by a thread in the
+   * current {@link java.lang.ThreadGroup}.
+   *
+   * @return the keyboard focus owner or null
+   */
+  public Component getPermanentFocusOwner ()
+  {
+    return (Component) getObject (currentPermanentFocusOwners);
+  }
+
+  /**
+   * Retrieve the {@link Component} that has the permanent keyboard
+   * focus, regardless of whether or not it was set by a thread in the
+   * current {@link java.lang.ThreadGroup}.
+   *
+   * @return the keyboard focus owner
+   * @throws SecurityException if this is not the keyboard focus
+   * manager associated with the current {@link java.lang.ThreadGroup}
+   */
+  protected Component getGlobalPermanentFocusOwner ()
+  {
+    return (Component) getGlobalObject (currentPermanentFocusOwners);
+  }
+
+  /**
+   * Set the {@link Component} that will be returned by {@link
+   * #getPermanentFocusOwner} (when it is called from the current
+   * {@link java.lang.ThreadGroup}) and {@link
+   * #getGlobalPermanentFocusOwner}.  This method does not actually
+   * transfer the keyboard focus.
+   *
+   * @param focusOwner the Component to return from
+   * getPermanentFocusOwner and getGlobalPermanentFocusOwner
+   *
+   * @see Component.requestFocus ()
+   * @see Component.requestFocusInWindow ()
+   */
+  protected void setGlobalPermanentFocusOwner (Component focusOwner)
   {
-    // XXX Need an easy way to test if this thread is in the context of the
-    // global focus owner, to avoid creating the exception in the first place.
-    try
-      {
-        return getGlobalFocusedWindow();
-      }
-    catch (SecurityException e)
-      {
-        return null;
-      }
-  }
-
-  protected Window getGlobalFocusedWindow()
-  {
-    // XXX Need a way to test if this thread is in the context of the focus
-    // owner, and throw a SecurityException if that is the case.
-    // XXX Implement.
-    return focusedWindow;
+    System.out.println ("in setGlobalFocusOwner: " + focusOwner);
+    if (focusOwner == null || focusOwner.focusable)
+      setGlobalObject (currentPermanentFocusOwners, focusOwner,
+		       "permanentFocusOwner");
   }
 
-  protected void setGlobalFocusedWindow(Window window)
+  /**
+   * Retrieve the {@link Window} that is or contains the keyboard
+   * focus owner, or null if the focused window was not set by a
+   * thread in the current {@link java.lang.ThreadGroup}.
+   *
+   * @return the focused window or null
+   */
+  public Window getFocusedWindow ()
+  {
+    return (Window) getObject (currentFocusedWindows);
+  }
+
+  /**
+   * Retrieve the {@link Window} that is or contains the focus owner,
+   * regardless of whether or not the {@link Window} was set focused
+   * by a thread in the current {@link java.lang.ThreadGroup}.
+   *
+   * @return the focused window
+   * @throws SecurityException if this is not the keyboard focus
+   * manager associated with the current {@link java.lang.ThreadGroup}
+   */
+  protected Window getGlobalFocusedWindow ()
+  {
+    return (Window) getGlobalObject (currentFocusedWindows);
+  }
+
+  /**
+   * Set the {@link Window} that will be returned by {@link
+   * #getFocusedWindow} (when it is called from the current {@link
+   * java.lang.ThreadGroup}) and {@link #getGlobalFocusedWindow}.
+   * This method does not actually cause <code>window</code> to become
+   * the focused {@link Window}.
+   *
+   * @param window the Window to return from getFocusedWindow and
+   * getGlobalFocusedWindow
+   */
+  protected void setGlobalFocusedWindow (Window window)
   {
-    // XXX Should this send focus events to the windows involved?
     if (window == null || window.focusable)
-      {
-        firePropertyChange("focusedWindow", focusedWindow, window);
-        try
-          {
-            fireVetoableChange("focusedWindow", focusedWindow, window);
-            focusedWindow = window;
-          }
-        catch (PropertyVetoException e)
-          {
-          }
-      }
+      setGlobalObject (currentFocusedWindows, window, "focusedWindow");
   }
 
+  /**
+   * Retrieve the active {@link Window}, or null if the active window
+   * was not set by a thread in the current {@link
+   * java.lang.ThreadGroup}.
+   *
+   * @return the active window or null
+   */
   public Window getActiveWindow()
   {
-    // XXX Need an easy way to test if this thread is in the context of the
-    // global focus owner, to avoid creating the exception in the first place.
-    try
-      {
-        return getGlobalActiveWindow();
-      }
-    catch (SecurityException e)
-      {
-        return null;
-      }
+    return (Window) getObject (currentActiveWindows);
   }
 
+  /**
+   * Retrieve the active {@link Window}, regardless of whether or not
+   * the {@link Window} was made active by a thread in the current
+   * {@link java.lang.ThreadGroup}.
+   *
+   * @return the active window
+   * @throws SecurityException if this is not the keyboard focus
+   * manager associated with the current {@link java.lang.ThreadGroup}
+   */
   protected Window getGlobalActiveWindow()
   {
-    // XXX Need a way to test if this thread is in the context of the focus
-    // owner, and throw a SecurityException if that is the case.
-    // XXX Implement.
-    return activeWindow;
+    return (Window) getGlobalObject (currentActiveWindows);
   }
 
+  /**
+   * Set the {@link Window} that will be returned by {@link
+   * #getActiveWindow} (when it is called from the current {@link
+   * java.lang.ThreadGroup}) and {@link #getGlobalActiveWindow}.  This
+   * method does not actually cause <code>window</code> to be made
+   * active.
+   *
+   * @param window the Window to return from getActiveWindow and
+   * getGlobalActiveWindow
+   */
   protected void setGlobalActiveWindow(Window window)
   {
-    // XXX Should this send focus events to the windows involved?
-    firePropertyChange("activeWindow", activeWindow, window);
-    try
-      {
-        fireVetoableChange("activeWindow", activeWindow, window);
-        activeWindow = window;
-      }
-    catch (PropertyVetoException e)
-      {
-      }
+    setGlobalObject (currentActiveWindows, window, "activeWindow");
   }
 
-  public FocusTraversalPolicy getDefaultFocusTraversalPolicy()
+  /**
+   * Retrieve the default {@link FocusTraversalPolicy}.
+   * Focus-managing {@link Container}s use the returned object to
+   * define their initial focus traversal policy.
+   *
+   * @return a non-null default FocusTraversalPolicy object
+   */
+  public FocusTraversalPolicy getDefaultFocusTraversalPolicy ()
   {
     if (defaultPolicy == null)
-      defaultPolicy = new DefaultFocusTraversalPolicy();
+      defaultPolicy = new DefaultFocusTraversalPolicy ();
     return defaultPolicy;
   }
 
-  public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy)
+  /**
+   * Set the {@link FocusTraversalPolicy} returned by {@link
+   * #getDefaultFocusTraversalPolicy}.  Focus-managing {@link
+   * Container}s created after this call will use policy as their
+   * initial focus traversal policy.  Existing {@link Container}s'
+   * focus traversal policies will not be affected by calls to this
+   * method.
+   *
+   * @param policy the FocusTraversalPolicy that will be returned by
+   * subsequent calls to getDefaultFocusTraversalPolicy
+   * @throws IllegalArgumentException if policy is null
+   */
+  public void setDefaultFocusTraversalPolicy (FocusTraversalPolicy policy)
   {
     if (policy == null)
-      throw new IllegalArgumentException();
-    firePropertyChange("defaultFocusTraversalPolicy", defaultPolicy, policy);
+      throw new IllegalArgumentException ();
+    firePropertyChange ("defaultFocusTraversalPolicy", defaultPolicy, policy);
     defaultPolicy = policy;
   }
 
-  public void setDefaultFocusTraversalKeys(int id, Set keystrokes)
-  {
+  /**
+   * Set the default {@link java.util.Set} of focus traversal keys for
+   * one of the focus traversal directions.
+   *
+   * @param id focus traversal direction identifier
+   * @param keystrokes set of AWTKeyStrokes
+   *
+   * @see #FORWARD_TRAVERSAL_KEYS
+   * @see #BACKWARD_TRAVERSAL_KEYS
+   * @see #UP_CYCLE_TRAVERSAL_KEYS
+   * @see #DOWN_CYCLE_TRAVERSAL_KEYS
+   */
+  public void setDefaultFocusTraversalKeys (int id, Set keystrokes)
+  {
+    if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
+        id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
+        id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
+        id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
+      throw new IllegalArgumentException ();
+
     if (keystrokes == null)
-      throw new IllegalArgumentException();
+      throw new IllegalArgumentException ();
+
     Set sa;
     Set sb;
     Set sc;
@@ -340,56 +543,82 @@
         type = "downCycleDefaultFocusTraversalKeys";
         break;
       default:
-        throw new IllegalArgumentException();
+        throw new IllegalArgumentException ();
       }
-    int i = keystrokes.size();
-    Iterator iter = keystrokes.iterator();
+    int i = keystrokes.size ();
+    Iterator iter = keystrokes.iterator ();
     while (--i >= 0)
       {
-        Object o = iter.next();
-        if (! (o instanceof AWTKeyStroke)
-            || sa.contains(o) || sb.contains(o) || sc.contains(o)
+        Object o = iter.next ();
+        if (!(o instanceof AWTKeyStroke)
+            || sa.contains (o) || sb.contains (o) || sc.contains (o)
             || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
-          throw new IllegalArgumentException();
+          throw new IllegalArgumentException ();
       }
-    keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes));
-    firePropertyChange(type, defaultFocusKeys[id], keystrokes);
+    keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
+    firePropertyChange (type, defaultFocusKeys[id], keystrokes);
     defaultFocusKeys[id] = keystrokes;
   }
 
-  public Set getDefaultFocusTraversalKeys(int id)
+  /**
+   * Retrieve the default {@link java.util.Set} of focus traversal
+   * keys for one of the focus traversal directions.
+   *
+   * @param id focus traversal direction identifier
+   *
+   * @return the default set of AWTKeyStrokes
+   *
+   * @see #FORWARD_TRAVERSAL_KEYS
+   * @see #BACKWARD_TRAVERSAL_KEYS
+   * @see #UP_CYCLE_TRAVERSAL_KEYS
+   * @see #DOWN_CYCLE_TRAVERSAL_KEYS
+   */
+  public Set getDefaultFocusTraversalKeys (int id)
   {
     if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS)
-      throw new IllegalArgumentException();
+      throw new IllegalArgumentException ();
     return defaultFocusKeys[id];
   }
 
-  public Container getCurrentFocusCycleRoot()
-  {
-    // XXX Need an easy way to test if this thread is in the context of the
-    // global focus owner, to avoid creating the exception in the first place.
-    try
-      {
-        return getGlobalCurrentFocusCycleRoot();
-      }
-    catch (SecurityException e)
-      {
-        return null;
-      }
-  }
-
-  protected Container getGlobalCurrentFocusCycleRoot()
-  {
-    // XXX Need a way to test if this thread is in the context of the focus
-    // owner, and throw a SecurityException if that is the case.
-    // XXX Implement.
-    return focusCycleRoot;
-  }
-
-  public void setGlobalCurrentFocusCycleRoot(Container cycleRoot)
+  /**
+   * Retrieve the current focus cycle root, or null if the focus owner
+   * was not set by a thread in the current {@link
+   * java.lang.ThreadGroup}.
+   *
+   * @return the current focus cycle root or null
+   */
+  public Container getCurrentFocusCycleRoot ()
+  {
+    return (Container) getObject (currentFocusCycleRoots);
+  }
+
+  /**
+   * Retrieve the current focus cycle root, regardless of whether or
+   * not it was made set by a thread in the current {@link
+   * java.lang.ThreadGroup}.
+   *
+   * @return the current focus cycle root
+   * @throws SecurityException if this is not the keyboard focus
+   * manager associated with the current {@link java.lang.ThreadGroup}
+   */
+  protected Container getGlobalCurrentFocusCycleRoot ()
+  {
+    return (Container) getGlobalObject (currentFocusCycleRoots);
+  }
+
+  /**
+   * Set the {@link Container} that will be returned by {@link
+   * #getCurrentFocusCycleRoot} (when it is called from the current
+   * {@link java.lang.ThreadGroup}) and {@link
+   * #getGlobalCurrentFocusCycleRoot}.  This method does not actually
+   * make <code>cycleRoot</code> the current focus cycle root.
+   * 
+   * @param cycleRoot the focus cycle root to return from
+   * getCurrentFocusCycleRoot and getGlobalCurrentFocusCycleRoot
+   */
+  public void setGlobalCurrentFocusCycleRoot (Container cycleRoot)
   {
-    firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot);
-    focusCycleRoot = cycleRoot;
+    setGlobalObject (currentFocusCycleRoots, cycleRoot, "currentFocusCycleRoot");
   }
 
   public void addPropertyChangeListener(PropertyChangeListener l)
@@ -484,73 +713,196 @@
     keyEventDispatchers.remove(dispatcher);
   }
 
-  protected List getKeyEventDispatchers()
+  protected List getKeyEventDispatchers ()
   {
-    return (List) keyEventDispatchers.clone();
+    return (List) keyEventDispatchers.clone ();
   }
 
-  public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
+  public void addKeyEventPostProcessor (KeyEventPostProcessor postProcessor)
   {
     if (postProcessor != null)
-      keyEventPostProcessors.add(postProcessor);
+      keyEventPostProcessors.add (postProcessor);
   }
 
-  public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor)
+  public void removeKeyEventPostProcessor (KeyEventPostProcessor postProcessor)
   {
-    keyEventPostProcessors.remove(postProcessor);
+    keyEventPostProcessors.remove (postProcessor);
   }
 
-  protected List getKeyEventPostProcessors()
+  protected List getKeyEventPostProcessors ()
   {
-    return (List) keyEventPostProcessors.clone();
+    return (List) keyEventPostProcessors.clone ();
   }
 
-  public abstract boolean dispatchEvent(AWTEvent e);
+  public abstract boolean dispatchEvent (AWTEvent e);
 
-  public final void redispatchEvent(Component target, AWTEvent e)
+  public final void redispatchEvent (Component target, AWTEvent e)
   {
-    throw new Error("not implemented");
+    e.setSource (target);
+    dispatchEvent (e);
   }
 
-  public abstract boolean dispatchKeyEvent(KeyEvent e);
+  public abstract boolean dispatchKeyEvent (KeyEvent e);
 
-  public abstract boolean postProcessKeyEvent(KeyEvent e);
+  public abstract boolean postProcessKeyEvent (KeyEvent e);
 
-  public abstract void processKeyEvent(Component focused, KeyEvent e);
+  public abstract void processKeyEvent (Component focused, KeyEvent e);
 
-  protected abstract void enqueueKeyEvents(long after, Component untilFocused);
+  protected abstract void enqueueKeyEvents (long after, Component untilFocused);
 
-  protected abstract void dequeueKeyEvents(long after, Component untilFocused);
+  protected abstract void dequeueKeyEvents (long after, Component untilFocused);
 
-  protected abstract void discardKeyEvents(Component comp);
+  protected abstract void discardKeyEvents (Component comp);
 
-  public abstract void focusNextComponent(Component comp);
+  public abstract void focusNextComponent (Component comp);
 
-  public abstract void focusPreviousComponent(Component comp);
+  public abstract void focusPreviousComponent (Component comp);
 
-  public abstract void upFocusCycle(Component comp);
+  public abstract void upFocusCycle (Component comp);
 
-  public abstract void downFocusCycle(Container cont);
+  public abstract void downFocusCycle (Container cont);
 
-  public final void focusNextComponent()
+  public final void focusNextComponent ()
   {
-    focusNextComponent(focusOwner);
+    focusNextComponent (null);
   }
 
-  public final void focusPreviousComponent()
+  public final void focusPreviousComponent ()
   {
-    focusPreviousComponent(focusOwner);
+    focusPreviousComponent (null);
   }
 
-  public final void upFocusCycle()
+  public final void upFocusCycle ()
   {
-    upFocusCycle(focusOwner);
+    upFocusCycle (null);
   }
 
-  public final void downFocusCycle()
+  public final void downFocusCycle ()
   {
+    Component focusOwner = getGlobalFocusOwner ();
     if (focusOwner instanceof Container
-        && ((Container) focusOwner).isFocusCycleRoot())
-      downFocusCycle((Container) focusOwner);
+        && ((Container) focusOwner).isFocusCycleRoot ())
+      downFocusCycle ((Container) focusOwner);
+  }
+
+  /**
+   * Retrieve an object from one of the global object {@link
+   * java.util.Map}s, if the object was set by the a thread in the
+   * current {@link java.lang.ThreadGroup}.  Otherwise, return null.
+   *
+   * @param globalMap one of the global object Maps
+   *
+   * @return a global object set by the current ThreadGroup, or null
+   *
+   * @see getFocusOwner
+   * @see getPermanentFocusOwner
+   * @see getFocusedWindow
+   * @see getActiveWindow
+   * @see getCurrentFocusCycleRoot
+   */
+  private Object getObject (Map globalMap)
+  {
+    ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+    return globalMap.get (currentGroup);
+  }
+
+  /**
+   * Retrieve an object from one of the global object {@link
+   * java.util.Map}s, regardless of whether or not the object was set
+   * by a thread in the current {@link java.lang.ThreadGroup}.
+   *
+   * @param globalMap one of the global object Maps
+   *
+   * @return a global object set by the current ThreadGroup, or null
+   *
+   * @throws SecurityException if this is not the keyboard focus
+   * manager associated with the current {@link java.lang.ThreadGroup}
+   *
+   * @see getGlobalFocusOwner
+   * @see getGlobalPermanentFocusOwner
+   * @see getGlobalFocusedWindow
+   * @see getGlobalActiveWindow
+   * @see getGlobalCurrentFocusCycleRoot
+   */
+  private Object getGlobalObject (Map globalMap)
+  {
+    ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+    KeyboardFocusManager managerForCallingThread
+      = (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup);
+
+    if (this != managerForCallingThread)
+      throw new SecurityException ("Attempted to retrieve an object from a "
+                                   + "keyboard focus manager that isn't "
+                                   + "associated with the current thread group.");
+
+    synchronized (globalMap)
+      {
+        Collection globalObjects = globalMap.values ();
+        Iterator i = globalObjects.iterator ();
+        Component globalObject;
+
+        while (i.hasNext ())
+          {
+            globalObject = (Component) i.next ();
+            if (globalObject != null)
+              return globalObject;
+          }
+      }
+
+    // No Object was found.
+    return null;
+  }
+
+  /**
+   * Set an object in one of the global object {@link java.util.Map}s,
+   * that will be returned by subsequent calls to getGlobalObject on
+   * the same {@link java.util.Map}.
+   *
+   * @param globalMap one of the global object Maps
+   * @param newObject the object to set
+   * @param property the property that will change
+   *
+   * @see setGlobalFocusOwner
+   * @see setGlobalPermanentFocusOwner
+   * @see setGlobalFocusedWindow
+   * @see setGlobalActiveWindow
+   * @see setGlobalCurrentFocusCycleRoot
+   */
+  private void setGlobalObject (Map globalMap,
+                                Object newObject,
+                                String property)
+  {
+    synchronized (globalMap)
+      {
+        // Save old object.
+        Object oldObject = getGlobalObject (globalMap);
+
+        // Nullify old object.
+        Collection threadGroups = globalMap.keySet ();
+        Iterator i = threadGroups.iterator ();
+        while (i.hasNext ())
+          {
+            ThreadGroup oldThreadGroup = (ThreadGroup) i.next ();
+            if (globalMap.get (oldThreadGroup) != null)
+              {
+                globalMap.put (oldThreadGroup, null);
+                // There should only be one object set at a time, so
+                // we can short circuit.
+                break;
+              }
+          }
+
+        ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup ();
+        firePropertyChange (property, oldObject, newObject);
+        try
+          {
+            fireVetoableChange (property, oldObject, newObject);
+            // Set new object.
+            globalMap.put (currentGroup, newObject);
+          }
+        catch (PropertyVetoException e)
+          {
+          }
+      }
   }
-} // class KeyboardFocusManager
+}
Index: java/awt/Window.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Window.java,v
retrieving revision 1.32.12.2
diff -u -r1.32.12.2 Window.java
--- java/awt/Window.java	17 Feb 2004 21:26:32 -0000	1.32.12.2
+++ java/awt/Window.java	22 Apr 2004 16:01:10 -0000
@@ -83,6 +83,8 @@
   private transient GraphicsConfiguration graphicsConfiguration;
   private transient AccessibleContext accessibleContext;
 
+  private transient boolean shown;
+
   /** 
    * This (package access) constructor is used by subclasses that want
    * to build windows that do not have parents.  Eg. toplevel
@@ -92,6 +94,9 @@
   Window()
   {
     visible = false;
+    // Windows are the only Containers that default to being focus
+    // cycle roots.
+    focusCycleRoot = true;
     setLayout(new BorderLayout());
   }
 
@@ -242,6 +247,24 @@
     validate();
     super.show();
     toFront();
+
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+    manager.setGlobalFocusedWindow (this);
+
+    if (!shown)
+      {
+        FocusTraversalPolicy policy = getFocusTraversalPolicy ();
+        Component initialFocusOwner = null;
+
+        if (policy != null)
+          initialFocusOwner = policy.getInitialComponent (this);
+
+        if (initialFocusOwner != null)
+          initialFocusOwner.requestFocusInWindow (false);
+
+        System.out.println ("GOT INITIAL FOCUS OWNER: " + initialFocusOwner);
+        shown = true;
+      }
   }
 
   public void hide()
@@ -627,9 +650,16 @@
    * @return The component that has focus, or <code>null</code> if no
    * component has focus.
    */
-  public Component getFocusOwner()
+  public Component getFocusOwner ()
   {
-    // FIXME
+    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
+
+    Window activeWindow = manager.getActiveWindow ();
+
+    // The currently-focused Component belongs to the active Window.
+    if (activeWindow == this)
+      return manager.getFocusOwner ();
+
     return null;
   }
 
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c,v
retrieving revision 1.15.2.3
diff -u -r1.15.2.3 gnu_java_awt_peer_gtk_GtkComponentPeer.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c	26 Mar 2004 20:30:37 -0000	1.15.2.3
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c	22 Apr 2004 16:01:10 -0000
@@ -42,6 +42,12 @@
 
 static GtkWidget *find_fg_color_widget (GtkWidget *widget);
 static GtkWidget *find_bg_color_widget (GtkWidget *widget);
+static gboolean focus_in_cb (GtkWidget *widget,
+                             GdkEventFocus *event,
+                             jobject peer);
+static gboolean focus_out_cb (GtkWidget *widget,
+                              GdkEventFocus *event,
+                              jobject peer);
 
 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkGenericPeer_dispose
   (JNIEnv *env, jobject obj)
@@ -128,7 +134,7 @@
   gdk_threads_leave ();
 }
 
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_requestFocus
+JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetRequestFocus
   (JNIEnv *env, jobject obj)
 {
   void *ptr;
@@ -136,7 +142,59 @@
   ptr = NSA_GET_PTR (env, obj);
   
   gdk_threads_enter ();
-  // gtk_widget_grab_focus (GTK_WIDGET (ptr));
+  gtk_widget_grab_focus (GTK_WIDGET (ptr));
+  gdk_threads_leave ();
+}
+
+/*
+ * Translate a Java KeyEvent object into a GdkEventKey event, then
+ * pass it to the GTK main loop for processing.
+ */
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetDispatchKeyEvent
+  (JNIEnv *env, jobject obj, jint id, jlong when, jint mods,
+   jint keyCode, jchar keyChar, jint keyLocation)
+{
+  void *ptr;
+  GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
+
+  ptr = NSA_GET_PTR (env, obj);
+
+  // FIXME: need to flesh this out.
+  // Translate
+  if (id == AWT_KEY_PRESSED)
+    event->type = GDK_KEY_PRESS;
+  else if (id == AWT_KEY_RELEASED)
+    event->type = GDK_KEY_RELEASE;
+  else
+    // Don't send AWT KEY_TYPED events to GTK.
+    return;
+
+  // FIXME: this won't work for TextAreas or Lists, which are packed
+  // in GtkScrolledWindows.
+  if (GTK_IS_BUTTON (ptr))
+    event->key.window = GTK_BUTTON (ptr)->event_window;
+  else
+    event->key.window = GTK_WIDGET (ptr)->window;
+
+  event->key.send_event = TRUE;
+
+  event->key.time = (guint32) when;
+  // Translate state
+  event->key.state = 0;
+  // Translate keyval
+  event->key.keyval = keyCode;
+  event->key.length = 1;
+  // Translate keyChar
+  event->key.string = g_strdup ("a");
+  event->key.hardware_keycode = 0;
+  event->key.group = 0;
+
+  gdk_threads_enter ();
+
+  g_printerr ("sending event\n");
+  gtk_main_do_event (event);
+
   gdk_threads_leave ();
 }
 
@@ -775,6 +833,12 @@
   g_signal_connect (GTK_OBJECT (ptr), "event", 
                     G_CALLBACK (pre_event_handler), *gref);
 
+  g_signal_connect (G_OBJECT (ptr), "focus-in-event",
+                    G_CALLBACK (focus_in_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "focus-out-event",
+                    G_CALLBACK (focus_out_cb), *gref);
+
   gdk_threads_leave ();
 }
 
@@ -813,3 +877,26 @@
   return bg_color_widget;
 }
 
+static gboolean focus_in_cb (GtkWidget *widget,
+                             GdkEventFocus *event,
+                             jobject peer)
+{
+  g_printerr ("            focus in: %p\n", peer);
+  (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                              postFocusEventID,
+                              AWT_FOCUS_GAINED,
+                              JNI_FALSE);
+  return FALSE;
+}
+
+static gboolean focus_out_cb (GtkWidget *widget,
+                              GdkEventFocus *event,
+                              jobject peer)
+{
+  g_printerr ("            focus out: %p\n", peer);
+  (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                              postFocusEventID,
+                              AWT_FOCUS_LOST,
+                              JNI_FALSE);
+  return FALSE;
+}
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c,v
retrieving revision 1.19.2.1
diff -u -r1.19.2.1 gnu_java_awt_peer_gtk_GtkEvents.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c	5 Mar 2004 22:24:50 -0000	1.19.2.1
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c	22 Apr 2004 16:01:10 -0000
@@ -1055,104 +1055,54 @@
           }
       }
       break;
+
     case GDK_FOCUS_CHANGE:
       (*gdk_env)->CallVoidMethod (gdk_env, peer,
 				  postFocusEventID,
-				  (jint) (event->focus_change.in) ? 
+				  (jint) (event->focus_change.in) ?
 				  AWT_FOCUS_GAINED : AWT_FOCUS_LOST,
 				  JNI_FALSE);
       break;
     case GDK_KEY_PRESS:
-    case GDK_KEY_RELEASE:
-      {
-        GdkWindow *obj_window;
-        jobject *focus_obj_ptr = NULL;
-	int generates_key_typed = 0;
-
-        /* A widget with a grab will get key events */
-	if (!GTK_IS_WINDOW (widget))
-	  focus_obj_ptr = &peer;
-	else
-	  {
-            GtkWindow *window;
-
-            /* Check if we have an enabled focused widget in this window.
-	       If not don't handle the event. */
-	    window = GTK_WINDOW (widget);
-	    if (!window->focus_widget
-	        || !GTK_WIDGET_IS_SENSITIVE (window->focus_widget)
-	        || !window->focus_widget->window)
-	      return FALSE;
-	
-            /* TextArea peers are attached to the scrolled window
-               that contains the GtkTextView, not to the text view
-               itself.  Same for List. */
-            if (GTK_IS_TEXT_VIEW (window->focus_widget)
-                || GTK_IS_CLIST (window->focus_widget))
-              {
-                obj_window = gtk_widget_get_parent (window->focus_widget)->window;
-              }
-            else if (GTK_IS_BUTTON (window->focus_widget))
-	      /* GtkButton events go to the "event_window" and this is what
-	         we registered when the button was created. */
-              obj_window = GTK_BUTTON (window->focus_widget)->event_window;
-            else
-              obj_window = window->focus_widget->window;
-
-            gdk_property_get (obj_window,
-                              gdk_atom_intern ("_GNU_GTKAWT_ADDR", FALSE),
-                              gdk_atom_intern ("CARDINAL", FALSE),
-                              0,
-                              sizeof (jobject),
-                              FALSE,
-                              NULL,
-                              NULL,
-                              NULL,
-                              (guchar **)&focus_obj_ptr);
-
-            /* If the window has no jobject attached we can't send anything */
-	    if (!focus_obj_ptr)
-	      return FALSE;
-	      
-	    /* Should we generate an AWT_KEY_TYPED event? */
-	    generates_key_typed = generates_key_typed_event (event, window->focus_widget);
-	  }	
+        if (GTK_IS_WINDOW (widget))
+          {
+            g_print("got key event on widget %s\n", gtk_widget_get_name (widget));
 
-	if (event->type == GDK_KEY_PRESS)	
-	  {
-            (*gdk_env)->CallVoidMethod (gdk_env, *focus_obj_ptr,
-				        postKeyEventID,
-				        (jint) AWT_KEY_PRESSED,
-				        (jlong) event->key.time,
+            (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                                        postKeyEventID,
+                                        (jint) AWT_KEY_PRESSED,
+                                        (jlong) event->key.time,
                                         keyevent_state_to_awt_mods (event),
                                         keysym_to_awt_keycode (event),
                                         keyevent_to_awt_keychar (event),
                                         keysym_to_awt_keylocation (event));
-
-            if (generates_key_typed)
-              {
-                (*gdk_env)->CallVoidMethod (gdk_env, *focus_obj_ptr,
-                                            postKeyEventID,
-                                            (jint) AWT_KEY_TYPED,
-                                            (jlong) event->key.time,
-                                            state_to_awt_mods (event->key.state),
-                                            VK_UNDEFINED,
-                                            keyevent_to_awt_keychar (event),
-                                            AWT_KEY_LOCATION_UNKNOWN);
-              }
+            return TRUE;
           }
-	else /* GDK_KEY_RELEASE */
-          {
-	    (*gdk_env)->CallVoidMethod (gdk_env, *focus_obj_ptr,
-				        postKeyEventID,
-				        (jint) AWT_KEY_RELEASED,
-				        (jlong) event->key.time,
-			                keyevent_state_to_awt_mods (event),
-			                keysym_to_awt_keycode (event),
+        else
+          return FALSE;
+        break;
+    case GDK_KEY_RELEASE:
+      if (GTK_IS_WINDOW (widget))
+        {
+            g_print("got key event on widget %s\n", gtk_widget_get_name (widget));
+
+            (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                                        postKeyEventID,
+                                        (jint) AWT_KEY_RELEASED,
+                                        (jlong) event->key.time,
+                                        keyevent_state_to_awt_mods (event),
+                                        keysym_to_awt_keycode (event),
                                         keyevent_to_awt_keychar (event),
                                         keysym_to_awt_keylocation (event));
-	  }
-      }
+            return TRUE;
+        }
+      else
+        {
+          // We generated this event after Java processed the
+          // corresponding event on the window.
+          if (event->key.send_event)
+            return FALSE;
+        }
       break;
     default:
       break;
Index: jni/gtk-peer/gtkpeer.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gtkpeer.h,v
retrieving revision 1.12
diff -u -r1.12 gtkpeer.h
--- jni/gtk-peer/gtkpeer.h	23 Dec 2003 19:24:00 -0000	1.12
+++ jni/gtk-peer/gtkpeer.h	22 Apr 2004 16:01:10 -0000
@@ -361,8 +361,8 @@
 #define VK_ALT_GRAPH 65406
 #define VK_UNDEFINED 0
 
-#define AWT_FOCUS_LOST 1004
-#define AWT_FOCUS_GAINED 1005
+#define AWT_FOCUS_GAINED 1004
+#define AWT_FOCUS_LOST 1005
 
 #define AWT_WINDOW_OPENED 200
 #define AWT_WINDOW_CLOSING 201

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]