001    /* Window.java --
002       Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005  Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt;
040    
041    import java.awt.event.ComponentEvent;
042    import java.awt.event.WindowEvent;
043    import java.awt.event.WindowFocusListener;
044    import java.awt.event.WindowListener;
045    import java.awt.event.WindowStateListener;
046    import java.awt.image.BufferStrategy;
047    import java.awt.peer.WindowPeer;
048    import java.lang.ref.Reference;
049    import java.lang.ref.WeakReference;
050    import java.util.EventListener;
051    import java.util.Iterator;
052    import java.util.Locale;
053    import java.util.ResourceBundle;
054    import java.util.Vector;
055    
056    import javax.accessibility.Accessible;
057    import javax.accessibility.AccessibleContext;
058    import javax.accessibility.AccessibleRole;
059    import javax.accessibility.AccessibleState;
060    import 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     */
068    public 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    }