001/* Window.java --
002   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005  Free Software Foundation
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt;
040
041import java.awt.event.ComponentEvent;
042import java.awt.event.WindowEvent;
043import java.awt.event.WindowFocusListener;
044import java.awt.event.WindowListener;
045import java.awt.event.WindowStateListener;
046import java.awt.image.BufferStrategy;
047import java.awt.peer.WindowPeer;
048import java.lang.ref.Reference;
049import java.lang.ref.WeakReference;
050import java.util.EventListener;
051import java.util.Iterator;
052import java.util.Locale;
053import java.util.ResourceBundle;
054import java.util.Vector;
055
056import javax.accessibility.Accessible;
057import javax.accessibility.AccessibleContext;
058import javax.accessibility.AccessibleRole;
059import javax.accessibility.AccessibleState;
060import javax.accessibility.AccessibleStateSet;
061
062/**
063 * This class represents a top-level window with no decorations.
064 *
065 * @author Aaron M. Renn (arenn@urbanophile.com)
066 * @author Warren Levy  (warrenl@cygnus.com)
067 */
068public class Window extends Container implements Accessible
069{
070  private static final long serialVersionUID = 4497834738069338734L;
071
072  // Serialized fields, from Sun's serialization spec.
073  private String warningString = null;
074  private int windowSerializedDataVersion = 0; // FIXME
075  /** @since 1.2 */
076  // private FocusManager focusMgr;  // FIXME: what is this?
077  /** @since 1.2 */
078  private int state = 0;
079  /** @since 1.4 */
080  private boolean focusableWindowState = true;
081  /** @since 1.5 */
082  private boolean alwaysOnTop = false;
083
084  // A list of other top-level windows owned by this window.
085  private transient Vector ownedWindows = new Vector();
086
087  private transient WindowListener windowListener;
088  private transient WindowFocusListener windowFocusListener;
089  private transient WindowStateListener windowStateListener;
090
091  private transient boolean shown;
092
093  // This is package-private to avoid an accessor method.
094  transient Component windowFocusOwner;
095
096  /*
097   * The number used to generate the name returned by getName.
098   */
099  private static transient long next_window_number;
100
101  protected class AccessibleAWTWindow extends AccessibleAWTContainer
102  {
103    private static final long serialVersionUID = 4215068635060671780L;
104
105    public AccessibleRole getAccessibleRole()
106    {
107      return AccessibleRole.WINDOW;
108    }
109
110    public AccessibleStateSet getAccessibleStateSet()
111    {
112      AccessibleStateSet states = super.getAccessibleStateSet();
113      if (isActive())
114        states.add(AccessibleState.ACTIVE);
115      return states;
116    }
117  }
118
119  /**
120   * This (package access) constructor is used by subclasses that want
121   * to build windows that do not have parents.  Eg. toplevel
122   * application frames.  Subclasses cannot call super(null), since
123   * null is an illegal argument.
124   */
125  Window()
126  {
127    visible = false;
128    // Windows are the only Containers that default to being focus
129    // cycle roots.
130    focusCycleRoot = true;
131    setLayout(new BorderLayout());
132
133    GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment();
134    graphicsConfig = g.getDefaultScreenDevice().getDefaultConfiguration();
135  }
136
137  Window(GraphicsConfiguration gc)
138  {
139    this();
140    graphicsConfig = gc;
141  }
142
143  /**
144   * Initializes a new instance of <code>Window</code> with the specified
145   * parent.  The window will initially be invisible.
146   *
147   * @param owner The owning <code>Frame</code> of this window.
148   *
149   * @exception IllegalArgumentException If the owner's GraphicsConfiguration
150   * is not from a screen device, or if owner is null; this exception is always
151   * thrown when GraphicsEnvironment.isHeadless returns true.
152   */
153  public Window(Frame owner)
154  {
155    this (owner, owner.getGraphicsConfiguration ());
156  }
157
158  /**
159   * Initializes a new instance of <code>Window</code> with the specified
160   * parent.  The window will initially be invisible.
161   *
162   * @exception IllegalArgumentException If the owner's GraphicsConfiguration
163   * is not from a screen device, or if owner is null; this exception is always
164   * thrown when GraphicsEnvironment.isHeadless returns true.
165   *
166   * @since 1.2
167   */
168  public Window(Window owner)
169  {
170    this (owner, owner.getGraphicsConfiguration ());
171  }
172
173  /**
174   * Initializes a new instance of <code>Window</code> with the specified
175   * parent.  The window will initially be invisible.
176   *
177   * @exception IllegalArgumentException If owner is null or if gc is not from a
178   * screen device; this exception is always thrown when
179   * GraphicsEnvironment.isHeadless returns true.
180   *
181   * @since 1.3
182   */
183  public Window(Window owner, GraphicsConfiguration gc)
184  {
185    this ();
186
187    synchronized (getTreeLock())
188      {
189        if (owner == null)
190          throw new IllegalArgumentException ("owner must not be null");
191
192        parent = owner;
193        owner.ownedWindows.add(new WeakReference(this));
194      }
195
196    // FIXME: make this text visible in the window.
197    SecurityManager s = System.getSecurityManager();
198    if (s != null && ! s.checkTopLevelWindow(this))
199      warningString = System.getProperty("awt.appletWarning");
200
201    if (gc != null
202        && gc.getDevice().getType() != GraphicsDevice.TYPE_RASTER_SCREEN)
203      throw new IllegalArgumentException ("gc must be from a screen device");
204
205    if (gc == null)
206      graphicsConfig = GraphicsEnvironment.getLocalGraphicsEnvironment()
207                                          .getDefaultScreenDevice()
208                                          .getDefaultConfiguration();
209    else
210      graphicsConfig = gc;
211  }
212
213  /**
214   * Creates the native peer for this window.
215   */
216  public void addNotify()
217  {
218    if (peer == null)
219      peer = getToolkit().createWindow(this);
220    super.addNotify();
221  }
222
223  /**
224   * Relays out this window's child components at their preferred size.
225   *
226   * @specnote pack() doesn't appear to be called internally by show(), so
227   *             we duplicate some of the functionality.
228   */
229  public void pack()
230  {
231    if (parent != null && !parent.isDisplayable())
232      parent.addNotify();
233    if (peer == null)
234      addNotify();
235
236    setSize(getPreferredSize());
237
238    validate();
239  }
240
241  /**
242   * Shows on-screen this window and any of its owned windows for whom
243   * isVisible returns true.
244   * @specnote: Deprecated starting in 1.5.
245   */
246  @Deprecated
247  public void show()
248  {
249    synchronized (getTreeLock())
250      {
251        if (peer == null)
252          addNotify();
253
254        validate();
255        if (visible)
256          toFront();
257        else
258          {
259            super.show();
260            // Show visible owned windows.
261            Iterator e = ownedWindows.iterator();
262            while (e.hasNext())
263              {
264                Window w = (Window) (((Reference) e.next()).get());
265                if (w != null)
266                  {
267                    if (w.isVisible())
268                      w.getPeer().setVisible(true);
269                  }
270                else
271                  // Remove null weak reference from ownedWindows.
272                  // Unfortunately this can't be done in the Window's
273                  // finalize method because there is no way to guarantee
274                  // synchronous access to ownedWindows there.
275                  e.remove();
276              }
277          }
278        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
279        manager.setGlobalFocusedWindow(this);
280
281        if (! shown)
282          {
283            FocusTraversalPolicy policy = getFocusTraversalPolicy();
284            Component initialFocusOwner = null;
285
286            if (policy != null)
287              initialFocusOwner = policy.getInitialComponent(this);
288
289            if (initialFocusOwner != null)
290              initialFocusOwner.requestFocusInWindow();
291
292            // Post WINDOW_OPENED from here.
293            if (windowListener != null
294                || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)
295              {
296                WindowEvent ev = new WindowEvent(this,
297                                                 WindowEvent.WINDOW_OPENED);
298                Toolkit tk = Toolkit.getDefaultToolkit();
299                tk.getSystemEventQueue().postEvent(ev);
300              }
301            shown = true;
302          }
303      }
304  }
305
306  /**
307   * @specnote: Deprecated starting in 1.5.
308   */
309  @Deprecated
310  public void hide()
311  {
312    // Hide visible owned windows.
313    synchronized (getTreeLock ())
314      {
315        Iterator e = ownedWindows.iterator();
316        while(e.hasNext())
317          {
318            Window w = (Window)(((Reference) e.next()).get());
319            if (w != null)
320              {
321                if (w.isVisible() && w.getPeer() != null)
322                  w.getPeer().setVisible(false);
323              }
324            else
325              e.remove();
326          }
327      }
328    super.hide();
329  }
330
331  /**
332   * Destroys any resources associated with this window.  This includes
333   * all components in the window and all owned top-level windows.
334   */
335  public void dispose()
336  {
337    hide();
338
339    synchronized (getTreeLock ())
340      {
341        Iterator e = ownedWindows.iterator();
342        while(e.hasNext())
343          {
344            Window w = (Window)(((Reference) e.next()).get());
345            if (w != null)
346              w.dispose();
347            else
348              // Remove null weak reference from ownedWindows.
349              e.remove();
350          }
351
352        for (int i = 0; i < ncomponents; ++i)
353          component[i].removeNotify();
354        this.removeNotify();
355
356        // Post WINDOW_CLOSED from here.
357        if (windowListener != null
358            || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)
359          {
360            WindowEvent ev = new WindowEvent(this,
361                                             WindowEvent.WINDOW_CLOSED);
362            Toolkit tk = Toolkit.getDefaultToolkit();
363            tk.getSystemEventQueue().postEvent(ev);
364          }
365      }
366  }
367
368  /**
369   * Sends this window to the back so that all other windows display in
370   * front of it.
371   *
372   * If the window is set to be always-on-top, this will remove its
373   * always-on-top status.
374   */
375  public void toBack()
376  {
377    if (peer != null)
378      {
379        if( alwaysOnTop )
380          setAlwaysOnTop( false );
381        ( (WindowPeer) peer ).toBack();
382      }
383  }
384
385  /**
386   * Brings this window to the front so that it displays in front of
387   * any other windows.
388   */
389  public void toFront()
390  {
391    if (peer != null)
392      ( (WindowPeer) peer ).toFront();
393  }
394
395  /**
396   * Returns the toolkit used to create this window.
397   *
398   * @return The toolkit used to create this window.
399   *
400   * @specnote Unlike Component.getToolkit, this implementation always
401   *           returns the value of Toolkit.getDefaultToolkit().
402   */
403  public Toolkit getToolkit()
404  {
405    return Toolkit.getDefaultToolkit();
406  }
407
408  /**
409   * Returns the warning string that will be displayed if this window is
410   * popped up by an unsecure applet or application.
411   *
412   * @return The unsecure window warning message.
413   */
414  public final String getWarningString()
415  {
416    return warningString;
417  }
418
419  /**
420   * Returns the locale that this window is configured for.
421   *
422   * @return The locale this window is configured for.
423   */
424  public Locale getLocale()
425  {
426    return locale == null ? Locale.getDefault() : locale;
427  }
428
429  /*
430  /** @since 1.2
431  public InputContext getInputContext()
432  {
433    // FIXME
434  }
435  */
436
437  /**
438   * Sets the cursor for this window to the specifiec cursor.
439   *
440   * @param cursor The new cursor for this window.
441   */
442  public void setCursor(Cursor cursor)
443  {
444    super.setCursor(cursor);
445  }
446
447  public Window getOwner()
448  {
449    return (Window) parent;
450  }
451
452  /** @since 1.2 */
453  public Window[] getOwnedWindows()
454  {
455    Window [] trimmedList;
456    synchronized (getTreeLock ())
457      {
458        // Windows with non-null weak references in ownedWindows.
459        Window [] validList = new Window [ownedWindows.size()];
460
461        Iterator e = ownedWindows.iterator();
462        int numValid = 0;
463        while (e.hasNext())
464          {
465            Window w = (Window)(((Reference) e.next()).get());
466            if (w != null)
467              validList[numValid++] = w;
468            else
469              // Remove null weak reference from ownedWindows.
470              e.remove();
471          }
472
473        if (numValid != validList.length)
474          {
475            trimmedList = new Window [numValid];
476            System.arraycopy (validList, 0, trimmedList, 0, numValid);
477          }
478        else
479          trimmedList = validList;
480      }
481    return trimmedList;
482  }
483
484  /**
485   * Adds the specified listener to the list of <code>WindowListeners</code>
486   * that will receive events for this window.
487   *
488   * @param listener The <code>WindowListener</code> to add.
489   */
490  public synchronized void addWindowListener(WindowListener listener)
491  {
492    if (listener != null)
493      {
494        newEventsOnly = true;
495        windowListener = AWTEventMulticaster.add(windowListener, listener);
496      }
497  }
498
499  /**
500   * Removes the specified listener from the list of
501   * <code>WindowListeners</code> that will receive events for this window.
502   *
503   * @param listener The <code>WindowListener</code> to remove.
504   */
505  public synchronized void removeWindowListener(WindowListener listener)
506  {
507    windowListener = AWTEventMulticaster.remove(windowListener, listener);
508  }
509
510  /**
511   * Returns an array of all the window listeners registered on this window.
512   *
513   * @since 1.4
514   */
515  public synchronized WindowListener[] getWindowListeners()
516  {
517    return (WindowListener[])
518      AWTEventMulticaster.getListeners(windowListener,
519                                       WindowListener.class);
520  }
521
522  /**
523   * Returns an array of all the window focus listeners registered on this
524   * window.
525   *
526   * @since 1.4
527   */
528  public synchronized WindowFocusListener[] getWindowFocusListeners()
529  {
530    return (WindowFocusListener[])
531      AWTEventMulticaster.getListeners(windowFocusListener,
532                                       WindowFocusListener.class);
533  }
534
535  /**
536   * Returns an array of all the window state listeners registered on this
537   * window.
538   *
539   * @since 1.4
540   */
541  public synchronized WindowStateListener[] getWindowStateListeners()
542  {
543    return (WindowStateListener[])
544      AWTEventMulticaster.getListeners(windowStateListener,
545                                       WindowStateListener.class);
546  }
547
548  /**
549   * Adds the specified listener to this window.
550   */
551  public void addWindowFocusListener (WindowFocusListener wfl)
552  {
553    if (wfl != null)
554      {
555        newEventsOnly = true;
556        windowFocusListener = AWTEventMulticaster.add (windowFocusListener,
557                                                       wfl);
558      }
559  }
560
561  /**
562   * Adds the specified listener to this window.
563   *
564   * @since 1.4
565   */
566  public void addWindowStateListener (WindowStateListener wsl)
567  {
568    if (wsl != null)
569      {
570        newEventsOnly = true;
571        windowStateListener = AWTEventMulticaster.add (windowStateListener,
572                                                       wsl);
573      }
574  }
575
576  /**
577   * Removes the specified listener from this window.
578   */
579  public void removeWindowFocusListener (WindowFocusListener wfl)
580  {
581    windowFocusListener = AWTEventMulticaster.remove (windowFocusListener, wfl);
582  }
583
584  /**
585   * Removes the specified listener from this window.
586   *
587   * @since 1.4
588   */
589  public void removeWindowStateListener (WindowStateListener wsl)
590  {
591    windowStateListener = AWTEventMulticaster.remove (windowStateListener, wsl);
592  }
593
594  /**
595   * Returns an array of all the objects currently registered as FooListeners
596   * upon this Window. FooListeners are registered using the addFooListener
597   * method.
598   *
599   * @exception ClassCastException If listenerType doesn't specify a class or
600   * interface that implements java.util.EventListener.
601   *
602   * @since 1.3
603   */
604  public <T extends EventListener> T[] getListeners(Class<T> listenerType)
605  {
606    if (listenerType == WindowListener.class)
607      return (T[]) getWindowListeners();
608    return super.getListeners(listenerType);
609  }
610
611  void dispatchEventImpl(AWTEvent e)
612  {
613    if (e.getID() == ComponentEvent.COMPONENT_RESIZED)
614      {
615        invalidate();
616        validate();
617      }
618    super.dispatchEventImpl(e);
619  }
620
621  /**
622   * Processes the specified event for this window.  If the event is an
623   * instance of <code>WindowEvent</code>, then
624   * <code>processWindowEvent()</code> is called to process the event,
625   * otherwise the superclass version of this method is invoked.
626   *
627   * @param evt The event to process.
628   */
629  protected void processEvent(AWTEvent evt)
630  {
631    if (evt instanceof WindowEvent)
632      {
633        WindowEvent we = (WindowEvent) evt;
634        switch (evt.getID())
635          {
636          case WindowEvent.WINDOW_OPENED:
637          case WindowEvent.WINDOW_CLOSED:
638          case WindowEvent.WINDOW_CLOSING:
639          case WindowEvent.WINDOW_ICONIFIED:
640          case WindowEvent.WINDOW_DEICONIFIED:
641          case WindowEvent.WINDOW_ACTIVATED:
642          case WindowEvent.WINDOW_DEACTIVATED:
643            processWindowEvent(we);
644            break;
645          case WindowEvent.WINDOW_GAINED_FOCUS:
646          case WindowEvent.WINDOW_LOST_FOCUS:
647            processWindowFocusEvent(we);
648            break;
649          case WindowEvent.WINDOW_STATE_CHANGED:
650            processWindowStateEvent(we);
651            break;
652          }
653      }
654    else
655      super.processEvent(evt);
656  }
657
658  /**
659   * Dispatches this event to any listeners that are listening for
660   * <code>WindowEvents</code> on this window.  This method only gets
661   * invoked if it is enabled via <code>enableEvents()</code> or if
662   * a listener has been added.
663   *
664   * @param evt The event to process.
665   */
666  protected void processWindowEvent(WindowEvent evt)
667  {
668    if (windowListener != null)
669      {
670        switch (evt.getID())
671          {
672          case WindowEvent.WINDOW_ACTIVATED:
673            windowListener.windowActivated(evt);
674            break;
675          case WindowEvent.WINDOW_CLOSED:
676            windowListener.windowClosed(evt);
677            break;
678          case WindowEvent.WINDOW_CLOSING:
679            windowListener.windowClosing(evt);
680            break;
681          case WindowEvent.WINDOW_DEACTIVATED:
682            windowListener.windowDeactivated(evt);
683            break;
684          case WindowEvent.WINDOW_DEICONIFIED:
685            windowListener.windowDeiconified(evt);
686            break;
687          case WindowEvent.WINDOW_ICONIFIED:
688            windowListener.windowIconified(evt);
689            break;
690          case WindowEvent.WINDOW_OPENED:
691            windowListener.windowOpened(evt);
692            break;
693          }
694      }
695  }
696
697  /**
698   * Identifies if this window is active.  The active window is a Frame or
699   * Dialog that has focus or owns the active window.
700   *
701   * @return true if active, else false.
702   * @since 1.4
703   */
704  public boolean isActive()
705  {
706    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
707    return manager.getActiveWindow() == this;
708  }
709
710  /**
711   * Identifies if this window is focused.  A window is focused if it is the
712   * focus owner or it contains the focus owner.
713   *
714   * @return true if focused, else false.
715   * @since 1.4
716   */
717  public boolean isFocused()
718  {
719    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
720    return manager.getFocusedWindow() == this;
721  }
722
723  /**
724   * Returns the child window that has focus if this window is active.
725   * This method returns <code>null</code> if this window is not active
726   * or no children have focus.
727   *
728   * @return The component that has focus, or <code>null</code> if no
729   * component has focus.
730   */
731  public Component getFocusOwner ()
732  {
733    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
734
735    Window activeWindow = manager.getActiveWindow ();
736
737    // The currently-focused Component belongs to the active Window.
738    if (activeWindow == this)
739      return manager.getFocusOwner ();
740    else
741      return null;
742  }
743
744  /**
745   * Returns the child component of this window that would receive
746   * focus if this window were to become focused.  If the window
747   * already has the top-level focus, then this method returns the
748   * same component as getFocusOwner.  If no child component has
749   * requested focus within the window, then the initial focus owner
750   * is returned.  If this is a non-focusable window, this method
751   * returns null.
752   *
753   * @return the child component of this window that most recently had
754   * the focus, or <code>null</code>
755   * @since 1.4
756   */
757  public Component getMostRecentFocusOwner ()
758  {
759    return windowFocusOwner;
760  }
761
762  /**
763   * Set the focus owner for this window.  This method is used to
764   * remember which component was focused when this window lost
765   * top-level focus, so that when it regains top-level focus the same
766   * child component can be refocused.
767   *
768   * @param windowFocusOwner the component in this window that owns
769   * the focus.
770   */
771  void setFocusOwner (Component windowFocusOwner)
772  {
773    this.windowFocusOwner = windowFocusOwner;
774  }
775
776  /**
777   * Post a Java 1.0 event to the event queue.
778   *
779   * @param e The event to post.
780   *
781   * @deprecated
782   */
783  public boolean postEvent(Event e)
784  {
785    return handleEvent (e);
786  }
787
788  /**
789   * Tests whether or not this window is visible on the screen.
790   *
791   * In contrast to the normal behaviour of Container, which is that
792   * a container is showing if its parent is visible and showing, a Window
793   * is even showing, if its parent (i.e. an invisible Frame) is not showing.
794   *
795   * @return <code>true</code> if this window is visible, <code>false</code>
796   * otherwise.
797   */
798  public boolean isShowing()
799  {
800    return isVisible();
801  }
802
803  public void setLocationRelativeTo(Component c)
804  {
805    int x = 0;
806    int y = 0;
807
808    if (c == null || !c.isShowing())
809      {
810        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
811        Point center = ge.getCenterPoint();
812        x = center.x - (width / 2);
813        y = center.y - (height / 2);
814      }
815    else
816      {
817        int cWidth = c.getWidth();
818        int cHeight = c.getHeight();
819        Dimension screenSize = getToolkit().getScreenSize();
820
821        x = c.getLocationOnScreen().x;
822        y = c.getLocationOnScreen().y;
823
824        // If bottom of component is cut off, window placed
825        // on the left or the right side of component
826        if ((y + cHeight) > screenSize.height)
827          {
828            // If the right side of the component is closer to the center
829            if ((screenSize.width / 2 - x) <= 0)
830              {
831                if ((x - width) >= 0)
832                  x -= width;
833                else
834                  x = 0;
835              }
836            else
837              {
838                if ((x + cWidth + width) <= screenSize.width)
839                  x += cWidth;
840                else
841                  x = screenSize.width - width;
842              }
843
844            y = screenSize.height - height;
845          }
846        else if (cWidth > width || cHeight > height)
847          {
848            // If right side of component is cut off
849            if ((x + width) > screenSize.width)
850              x = screenSize.width - width;
851            // If left side of component is cut off
852            else if (x < 0)
853              x = 0;
854            else
855              x += (cWidth - width) / 2;
856
857            y += (cHeight - height) / 2;
858          }
859        else
860          {
861            // If right side of component is cut off
862            if ((x + width) > screenSize.width)
863              x = screenSize.width - width;
864            // If left side of component is cut off
865            else if (x < 0 || (x - (width - cWidth) / 2) < 0)
866              x = 0;
867            else
868              x -= (width - cWidth) / 2;
869
870            if ((y - (height - cHeight) / 2) > 0)
871              y -= (height - cHeight) / 2;
872            else
873              y = 0;
874          }
875      }
876
877    setLocation(x, y);
878  }
879
880  /**
881   * A BltBufferStrategy for windows.
882   */
883  private class WindowBltBufferStrategy extends BltBufferStrategy
884  {
885    /**
886     * Creates a block transfer strategy for this window.
887     *
888     * @param numBuffers the number of buffers in this strategy
889     * @param accelerated true if the buffer should be accelerated,
890     * false otherwise
891     */
892    WindowBltBufferStrategy(int numBuffers, boolean accelerated)
893    {
894      super(numBuffers,
895            new BufferCapabilities(new ImageCapabilities(accelerated),
896                                   new ImageCapabilities(accelerated),
897                                   BufferCapabilities.FlipContents.COPIED));
898    }
899  }
900
901  /**
902   * A FlipBufferStrategy for windows.
903   */
904  private class WindowFlipBufferStrategy extends FlipBufferStrategy
905  {
906    /**
907     * Creates a flip buffer strategy for this window.
908     *
909     * @param numBuffers the number of buffers in this strategy
910     *
911     * @throws AWTException if the requested number of buffers is not
912     * supported
913     */
914    WindowFlipBufferStrategy(int numBuffers)
915      throws AWTException
916    {
917      super(numBuffers,
918            new BufferCapabilities(new ImageCapabilities(true),
919                                   new ImageCapabilities(true),
920                                   BufferCapabilities.FlipContents.COPIED));
921    }
922  }
923
924  /**
925   * Creates a buffering strategy that manages how this window is
926   * repainted.  This method attempts to create the optimum strategy
927   * based on the desired number of buffers.  Hardware or software
928   * acceleration may be used.
929   *
930   * createBufferStrategy attempts different levels of optimization,
931   * but guarantees that some strategy with the requested number of
932   * buffers will be created even if it is not optimal.  First it
933   * attempts to create a page flipping strategy, then an accelerated
934   * blitting strategy, then an unaccelerated blitting strategy.
935   *
936   * Calling this method causes any existing buffer strategy to be
937   * destroyed.
938   *
939   * @param numBuffers the number of buffers in this strategy
940   *
941   * @throws IllegalArgumentException if requested number of buffers
942   * is less than one
943   * @throws IllegalStateException if this window is not displayable
944   *
945   * @since 1.4
946   */
947  public void createBufferStrategy(int numBuffers)
948  {
949    if (numBuffers < 1)
950      throw new IllegalArgumentException("Window.createBufferStrategy: number"
951                                         + " of buffers is less than one");
952
953    if (!isDisplayable())
954      throw new IllegalStateException("Window.createBufferStrategy: window is"
955                                      + " not displayable");
956
957    BufferStrategy newStrategy = null;
958
959    // try a flipping strategy
960    try
961      {
962        newStrategy = new WindowFlipBufferStrategy(numBuffers);
963      }
964    catch (AWTException e)
965      {
966      }
967
968    // fall back to an accelerated blitting strategy
969    if (newStrategy == null)
970      newStrategy = new WindowBltBufferStrategy(numBuffers, true);
971
972    bufferStrategy = newStrategy;
973  }
974
975  /**
976   * Creates a buffering strategy that manages how this window is
977   * repainted.  This method attempts to create a strategy based on
978   * the specified capabilities and throws an exception if the
979   * requested strategy is not supported.
980   *
981   * Calling this method causes any existing buffer strategy to be
982   * destroyed.
983   *
984   * @param numBuffers the number of buffers in this strategy
985   * @param caps the requested buffering capabilities
986   *
987   * @throws AWTException if the requested capabilities are not
988   * supported
989   * @throws IllegalArgumentException if requested number of buffers
990   * is less than one or if caps is null
991   *
992   * @since 1.4
993   */
994  public void createBufferStrategy(int numBuffers, BufferCapabilities caps)
995    throws AWTException
996  {
997    if (numBuffers < 1)
998      throw new IllegalArgumentException("Window.createBufferStrategy: number"
999                                         + " of buffers is less than one");
1000
1001    if (caps == null)
1002      throw new IllegalArgumentException("Window.createBufferStrategy:"
1003                                         + " capabilities object is null");
1004
1005    // a flipping strategy was requested
1006    if (caps.isPageFlipping())
1007      bufferStrategy = new WindowFlipBufferStrategy(numBuffers);
1008    else
1009      bufferStrategy = new WindowBltBufferStrategy(numBuffers, true);
1010  }
1011
1012  /**
1013   * Returns the buffer strategy used by the window.
1014   *
1015   * @return the buffer strategy.
1016   * @since 1.4
1017   */
1018  public BufferStrategy getBufferStrategy()
1019  {
1020    return bufferStrategy;
1021  }
1022
1023  /**
1024   * @since 1.2
1025   *
1026   * @deprecated replaced by Component.applyComponentOrientation.
1027   */
1028  public void applyResourceBundle(ResourceBundle rb)
1029  {
1030    applyComponentOrientation(ComponentOrientation.getOrientation(rb));
1031  }
1032
1033  /**
1034   * @since 1.2
1035   *
1036   * @deprecated
1037   */
1038  public void applyResourceBundle(String rbName)
1039  {
1040    ResourceBundle rb = ResourceBundle.getBundle(rbName, Locale.getDefault(),
1041      ClassLoader.getSystemClassLoader());
1042    if (rb != null)
1043      applyResourceBundle(rb);
1044  }
1045
1046  /**
1047   * Gets the AccessibleContext associated with this <code>Window</code>.
1048   * The context is created, if necessary.
1049   *
1050   * @return the associated context
1051   */
1052  public AccessibleContext getAccessibleContext()
1053  {
1054    /* Create the context if this is the first request */
1055    if (accessibleContext == null)
1056      accessibleContext = new AccessibleAWTWindow();
1057    return accessibleContext;
1058  }
1059
1060  /**
1061   * Get graphics configuration.  The implementation for Window will
1062   * not ask any parent containers, since Window is a toplevel
1063   * window and not actually embedded in the parent component.
1064   */
1065  public GraphicsConfiguration getGraphicsConfiguration()
1066  {
1067    GraphicsConfiguration conf = graphicsConfig;
1068    if (conf == null)
1069      {
1070        conf = GraphicsEnvironment.getLocalGraphicsEnvironment()
1071        .getDefaultScreenDevice().getDefaultConfiguration();
1072        graphicsConfig = conf;
1073      }
1074    return conf;
1075  }
1076
1077  protected void processWindowFocusEvent(WindowEvent event)
1078  {
1079    if (windowFocusListener != null)
1080      {
1081        switch (event.getID ())
1082          {
1083          case WindowEvent.WINDOW_GAINED_FOCUS:
1084            windowFocusListener.windowGainedFocus (event);
1085            break;
1086
1087          case WindowEvent.WINDOW_LOST_FOCUS:
1088            windowFocusListener.windowLostFocus (event);
1089            break;
1090
1091          default:
1092            break;
1093          }
1094      }
1095  }
1096
1097  /**
1098   * @since 1.4
1099   */
1100  protected void processWindowStateEvent(WindowEvent event)
1101  {
1102    if (windowStateListener != null
1103        && event.getID () == WindowEvent.WINDOW_STATE_CHANGED)
1104      windowStateListener.windowStateChanged (event);
1105  }
1106
1107  /**
1108   * Returns whether this <code>Window</code> can get the focus or not.
1109   *
1110   * @since 1.4
1111   */
1112  public final boolean isFocusableWindow ()
1113  {
1114    if (getFocusableWindowState () == false)
1115      return false;
1116
1117    if (this instanceof Dialog
1118        || this instanceof Frame)
1119      return true;
1120
1121    // FIXME: Implement more possible cases for returning true.
1122
1123    return false;
1124  }
1125
1126  /**
1127   * Returns the value of the focusableWindowState property.
1128   *
1129   * @since 1.4
1130   */
1131  public boolean getFocusableWindowState ()
1132  {
1133    return focusableWindowState;
1134  }
1135
1136  /**
1137   * Sets the value of the focusableWindowState property.
1138   *
1139   * @since 1.4
1140   */
1141  public void setFocusableWindowState (boolean focusableWindowState)
1142  {
1143    this.focusableWindowState = focusableWindowState;
1144  }
1145
1146  /**
1147   * Check whether this Container is a focus cycle root.
1148   * Returns always <code>true</code> as Windows are the
1149   * root of the focus cycle.
1150   *
1151   * @return Always <code>true</code>.
1152   *
1153   * @since 1.4
1154   */
1155  public final boolean isFocusCycleRoot()
1156  {
1157    return true;
1158  }
1159
1160  /**
1161   * Set whether or not this Container is the root of a focus
1162   * traversal cycle. Windows are the root of the focus cycle
1163   * and therefore this method does nothing.
1164   *
1165   * @param focusCycleRoot ignored.
1166   *
1167   * @since 1.4
1168   */
1169  public final void setFocusCycleRoot(boolean focusCycleRoot)
1170  {
1171    // calls to the method are ignored
1172  }
1173
1174  /**
1175   * Returns the root container that owns the focus cycle where this
1176   * component resides. Windows have no ancestors and this method
1177   * returns always <code>null</code>.
1178   *
1179   * @return Always <code>null</code>.
1180   * @since 1.4
1181   */
1182  public final Container getFocusCycleRootAncestor()
1183  {
1184    return null;
1185  }
1186
1187  /**
1188   * Returns whether the Windows is an always-on-top window,
1189   * meaning whether the window can be obscured by other windows or not.
1190   *
1191   * @return <code>true</code> if the windows is always-on-top,
1192   * <code>false</code> otherwise.
1193   * @since 1.5
1194   */
1195  public final boolean isAlwaysOnTop()
1196  {
1197    return alwaysOnTop;
1198  }
1199
1200  /**
1201   * Sets the always-on-top state of this window (if supported).
1202   *
1203   * Setting a window to always-on-top means it will not be obscured
1204   * by any other windows (with the exception of other always-on-top
1205   * windows). Not all platforms may support this.
1206   *
1207   * If an window's always-on-top status is changed to false, the window
1208   * will remain at the front but not be anchored there.
1209   *
1210   * Calling toBack() on an always-on-top window will change its
1211   * always-on-top status to false.
1212   *
1213   * @since 1.5
1214   */
1215  public final void setAlwaysOnTop(boolean alwaysOnTop)
1216  {
1217    SecurityManager sm = System.getSecurityManager();
1218    if (sm != null)
1219      sm.checkPermission( new AWTPermission("setWindowAlwaysOnTop") );
1220
1221    if( this.alwaysOnTop == alwaysOnTop )
1222      return;
1223
1224    if( alwaysOnTop )
1225      toFront();
1226
1227    firePropertyChange("alwaysOnTop", this.alwaysOnTop, alwaysOnTop );
1228    this.alwaysOnTop = alwaysOnTop;
1229
1230    if (peer != null)
1231      ( (WindowPeer) peer).updateAlwaysOnTop();
1232    else
1233      System.out.println("Null peer?!");
1234  }
1235
1236  /**
1237   * Generate a unique name for this window.
1238   *
1239   * @return A unique name for this window.
1240   */
1241  String generateName()
1242  {
1243    return "win" + getUniqueLong();
1244  }
1245
1246  /**
1247   * Overridden to handle WindowEvents.
1248   *
1249   * @return <code>true</code> when the specified event type is enabled,
1250   *         <code>false</code> otherwise
1251   */
1252  boolean eventTypeEnabled(int type)
1253  {
1254    boolean enabled = false;
1255    switch (type)
1256      {
1257        case WindowEvent.WINDOW_OPENED:
1258        case WindowEvent.WINDOW_CLOSED:
1259        case WindowEvent.WINDOW_CLOSING:
1260        case WindowEvent.WINDOW_ICONIFIED:
1261        case WindowEvent.WINDOW_DEICONIFIED:
1262        case WindowEvent.WINDOW_ACTIVATED:
1263        case WindowEvent.WINDOW_DEACTIVATED:
1264          enabled = ((eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)
1265                    || windowListener != null;
1266          break;
1267        case WindowEvent.WINDOW_GAINED_FOCUS:
1268        case WindowEvent.WINDOW_LOST_FOCUS:
1269          enabled = ((eventMask & AWTEvent.WINDOW_FOCUS_EVENT_MASK) != 0)
1270                    || windowFocusListener != null;
1271          break;
1272        case WindowEvent.WINDOW_STATE_CHANGED:
1273          enabled = ((eventMask & AWTEvent.WINDOW_STATE_EVENT_MASK) != 0)
1274                    || windowStateListener != null;
1275          break;
1276        default:
1277          enabled = super.eventTypeEnabled(type);
1278      }
1279    return enabled;
1280  }
1281
1282  private static synchronized long getUniqueLong()
1283  {
1284    return next_window_number++;
1285  }
1286}