001    /* Frame.java -- AWT toplevel window
002       Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006
003       Free Software Foundation, Inc.
004    
005    This file is part of GNU Classpath.
006    
007    GNU Classpath is free software; you can redistribute it and/or modify
008    it under the terms of the GNU General Public License as published by
009    the Free Software Foundation; either version 2, or (at your option)
010    any later version.
011    
012    GNU Classpath is distributed in the hope that it will be useful, but
013    WITHOUT ANY WARRANTY; without even the implied warranty of
014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015    General Public License for more details.
016    
017    You should have received a copy of the GNU General Public License
018    along with GNU Classpath; see the file COPYING.  If not, write to the
019    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020    02110-1301 USA.
021    
022    Linking this library statically or dynamically with other modules is
023    making a combined work based on this library.  Thus, the terms and
024    conditions of the GNU General Public License cover the whole
025    combination.
026    
027    As a special exception, the copyright holders of this library give you
028    permission to link this library with independent modules to produce an
029    executable, regardless of the license terms of these independent
030    modules, and to copy and distribute the resulting executable under
031    terms of your choice, provided that you also meet, for each linked
032    independent module, the terms and conditions of the license of that
033    module.  An independent module is a module which is not derived from
034    or based on this library.  If you modify this library, you may extend
035    this exception to your version of the library, but you are not
036    obligated to do so.  If you do not wish to do so, delete this
037    exception statement from your version. */
038    
039    
040    package java.awt;
041    
042    import java.awt.peer.FramePeer;
043    import java.lang.ref.Reference;
044    import java.lang.ref.ReferenceQueue;
045    import java.lang.ref.WeakReference;
046    import java.util.ArrayList;
047    import java.util.Vector;
048    
049    import javax.accessibility.AccessibleContext;
050    import javax.accessibility.AccessibleRole;
051    import javax.accessibility.AccessibleState;
052    import javax.accessibility.AccessibleStateSet;
053    
054    /**
055      * This class is a top-level window with a title bar and window
056      * decorations.
057      *
058      * @author Aaron M. Renn (arenn@urbanophile.com)
059      */
060    public class Frame extends Window implements MenuContainer
061    {
062    
063      /**
064       * Constant for the default cursor.
065       *
066       * @deprecated Replaced by <code>Cursor.DEFAULT_CURSOR</code> instead.
067       */
068      public static final int DEFAULT_CURSOR = Cursor.DEFAULT_CURSOR;
069    
070      /**
071       * Constant for a cross-hair cursor.
072       *
073       * @deprecated Use <code>Cursor.CROSSHAIR_CURSOR</code> instead.
074       */
075      public static final int CROSSHAIR_CURSOR = Cursor.CROSSHAIR_CURSOR;
076    
077      /**
078       * Constant for a cursor over a text field.
079       *
080       * @deprecated Use <code>Cursor.TEXT_CURSOR</code> instead.
081       */
082      public static final int TEXT_CURSOR = Cursor.TEXT_CURSOR;
083    
084      /**
085       * Constant for a cursor to display while waiting for an action to complete.
086       *
087       * @deprecated Use <code>Cursor.WAIT_CURSOR</code>.
088       */
089      public static final int WAIT_CURSOR = Cursor.WAIT_CURSOR;
090    
091      /**
092       * Cursor used over SW corner of window decorations.
093       *
094       * @deprecated Use <code>Cursor.SW_RESIZE_CURSOR</code> instead.
095       */
096      public static final int SW_RESIZE_CURSOR = Cursor.SW_RESIZE_CURSOR;
097    
098      /**
099       * Cursor used over SE corner of window decorations.
100       * @deprecated Use <code>Cursor.SE_RESIZE_CURSOR</code> instead.
101       */
102      public static final int SE_RESIZE_CURSOR = Cursor.SE_RESIZE_CURSOR;
103    
104      /**
105       * Cursor used over NW corner of window decorations.
106       *
107       * @deprecated Use <code>Cursor.NW_RESIZE_CURSOR</code> instead.
108       */
109      public static final int NW_RESIZE_CURSOR = Cursor.NW_RESIZE_CURSOR;
110    
111      /**
112       * Cursor used over NE corner of window decorations.
113       *
114       * @deprecated Use <code>Cursor.NE_RESIZE_CURSOR</code> instead.
115       */
116      public static final int NE_RESIZE_CURSOR = Cursor.NE_RESIZE_CURSOR;
117    
118      /**
119       * Cursor used over N edge of window decorations.
120       *
121       * @deprecated Use <code>Cursor.N_RESIZE_CURSOR</code> instead.
122       */
123      public static final int N_RESIZE_CURSOR = Cursor.N_RESIZE_CURSOR;
124    
125      /**
126       * Cursor used over S edge of window decorations.
127       *
128       * @deprecated Use <code>Cursor.S_RESIZE_CURSOR</code> instead.
129       */
130      public static final int S_RESIZE_CURSOR = Cursor.S_RESIZE_CURSOR;
131    
132      /**
133       * Cursor used over E edge of window decorations.
134       *
135       * @deprecated Use <code>Cursor.E_RESIZE_CURSOR</code> instead.
136       */
137      public static final int E_RESIZE_CURSOR = Cursor.E_RESIZE_CURSOR;
138    
139      /**
140       * Cursor used over W edge of window decorations.
141       *
142       * @deprecated Use <code>Cursor.W_RESIZE_CURSOR</code> instead.
143       */
144      public static final int W_RESIZE_CURSOR = Cursor.W_RESIZE_CURSOR;
145    
146      /**
147       * Constant for a hand cursor.
148       *
149       * @deprecated Use <code>Cursor.HAND_CURSOR</code> instead.
150       */
151      public static final int HAND_CURSOR = Cursor.HAND_CURSOR;
152    
153      /**
154       * Constant for a cursor used during window move operations.
155       *
156       * @deprecated Use <code>Cursor.MOVE_CURSOR</code> instead.
157       */
158      public static final int MOVE_CURSOR = Cursor.MOVE_CURSOR;
159    
160      public static final int ICONIFIED = 1;
161      public static final int MAXIMIZED_BOTH = 6;
162      public static final int MAXIMIZED_HORIZ = 2;
163      public static final int MAXIMIZED_VERT = 4;
164      public static final int NORMAL = 0;
165    
166    //Serialization version constant
167      private static final long serialVersionUID = 2673458971256075116L;
168    
169      /**
170       * @serial The version of the class data being serialized
171       * FIXME: what is this value?
172       */
173      private int frameSerializedDataVersion;
174    
175      /**
176       * @serial Image used as the icon when this frame is minimized.
177       */
178      private Image icon;
179    
180      /**
181       * @serial Constant used by the JDK Motif peer set.  Not used in
182       * this implementation.
183       */
184      private boolean mbManagement;
185    
186      /**
187       * @serial The menu bar for this frame.
188       */
189      private MenuBar menuBar;
190    
191      /**
192       * @serial A list of other top-level windows owned by this window.
193       */
194      Vector ownedWindows = new Vector();
195    
196      /**
197       * @serial Indicates whether or not this frame is resizable.
198       */
199      private boolean resizable = true;
200    
201      /**
202       * @serial The state of this frame.
203       * // FIXME: What are the values here?
204       * This is package-private to avoid an accessor method.
205       */
206      int state;
207    
208      /**
209       * @serial The title of the frame.
210       */
211      private String title = "";
212    
213      /**
214       * Maximized bounds for this frame.
215       */
216      private Rectangle maximizedBounds;
217    
218      /**
219       * This field indicates whether the frame is undecorated or not.
220       */
221      private boolean undecorated = false;
222    
223      /*
224       * The number used to generate the name returned by getName.
225       */
226      private static transient long next_frame_number;
227    
228      /**
229       * Initializes a new instance of <code>Frame</code> that is not visible
230       * and has no title.
231       */
232      public Frame()
233      {
234        this("");
235        noteFrame(this);
236      }
237    
238      /**
239       * Initializes a new instance of <code>Frame</code> that is not visible
240       * and has the specified title.
241       *
242       * @param title the title of this frame
243       */
244      public Frame(String title)
245      {
246        super();
247        this.title = title;
248        // Top-level frames are initially invisible.
249        visible = false;
250        noteFrame(this);
251      }
252    
253      public Frame(GraphicsConfiguration gc)
254      {
255        super(gc);
256        visible = false;
257        noteFrame(this);
258      }
259    
260      public Frame(String title, GraphicsConfiguration gc)
261      {
262        super(gc);
263        setTitle(title);
264        visible = false;
265        noteFrame(this);
266      }
267    
268      /**
269       * Returns this frame's title string.
270       *
271       * @return this frame's title string
272       */
273      public String getTitle()
274      {
275        return title;
276      }
277    
278      /**
279       * Sets this frame's title to the specified value.
280       *
281       * @param title the new frame title
282       */
283      public synchronized void setTitle(String title)
284      {
285        this.title = title;
286        if (peer != null)
287          ((FramePeer) peer).setTitle(title);
288      }
289    
290      /**
291       * Returns this frame's icon.
292       *
293       * @return this frame's icon, or <code>null</code> if this frame does not
294       *         have an icon
295       */
296      public Image getIconImage()
297      {
298        return icon;
299      }
300    
301      /**
302       * Sets this frame's icon to the specified value.
303       *
304       * @icon the new icon for this frame
305       */
306      public synchronized void setIconImage(Image icon)
307      {
308        this.icon = icon;
309        if (peer != null)
310          ((FramePeer) peer).setIconImage(icon);
311      }
312    
313      /**
314       * Returns this frame's menu bar.
315       *
316       * @return this frame's menu bar, or <code>null</code> if this frame
317       *         does not have a menu bar
318       */
319      public MenuBar getMenuBar()
320      {
321        return menuBar;
322      }
323    
324      /**
325       * Sets this frame's menu bar. Removes any existing menu bar. If the
326       * given menu bar is part of another frame it will be removed from
327       * that frame.
328       *
329       * @param menuBar the new menu bar for this frame
330       */
331      public synchronized void setMenuBar(MenuBar menuBar)
332      {
333        if (this.menuBar != null)
334          remove(this.menuBar);
335    
336        this.menuBar = menuBar;
337        if (menuBar != null)
338          {
339            MenuContainer parent = menuBar.getParent();
340            if (parent != null)
341              parent.remove(menuBar);
342            menuBar.setParent(this);
343    
344            // Create local copy for thread safety.
345            FramePeer p = (FramePeer) peer;
346            if (p != null)
347              {
348                if (menuBar != null)
349                  menuBar.addNotify();
350                if (valid)
351                  invalidate();
352                p.setMenuBar(menuBar);
353              }
354          }
355      }
356    
357      /**
358       * Tests whether or not this frame is resizable.  This will be 
359       * <code>true</code> by default.
360       *
361       * @return <code>true</code> if this frame is resizable, <code>false</code>
362       *         otherwise
363       */
364      public boolean isResizable()
365      {
366        return resizable;
367      }
368    
369      /**
370       * Sets the resizability of this frame to the specified value.
371       *
372       * @param resizable <code>true</code> to make the frame resizable,
373       * <code>false</code> to make it non-resizable
374       */
375      public synchronized void setResizable(boolean resizable)
376      {
377        this.resizable = resizable;
378        if (peer != null)
379          ((FramePeer) peer).setResizable(resizable);
380      }
381    
382      /**
383       * Returns the cursor type of the cursor for this window.  This will
384       * be one of the constants in this class.
385       *
386       * @return the cursor type for this frame
387       *
388       * @deprecated Use <code>Component.getCursor()</code> instead.
389       */
390      public int getCursorType()
391      {
392        return getCursor().getType();
393      }
394    
395      /**
396       * Sets the cursor for this window to the specified type.  The specified
397       * type should be one of the constants in this class.
398       *
399       * @param type the cursor type
400       *
401       * @deprecated Use <code>Component.setCursor(Cursor)</code> instead.
402       */
403      public void setCursor(int type)
404      {
405        setCursor(new Cursor(type));
406      }
407    
408      /**
409       * Removes the specified menu component from this frame. If it is
410       * the current MenuBar it is removed from the frame. If it is a
411       * Popup it is removed from this component. If it is any other menu
412       * component it is ignored.
413       *
414       * @param menu the menu component to remove
415       */
416      public void remove(MenuComponent menu)
417      {
418        if (menu == menuBar)
419          {
420            if (menuBar != null)
421              {
422                if (peer != null)
423                  {
424                    ((FramePeer) peer).setMenuBar(null);
425                    menuBar.removeNotify();
426                  }
427                menuBar.setParent(null);
428              }
429            menuBar = null;
430          }
431        else
432          super.remove(menu);
433      }
434    
435      public void addNotify()
436      {
437        if (menuBar != null)
438          menuBar.addNotify();
439        if (peer == null)
440          peer = getToolkit ().createFrame (this);
441    
442        super.addNotify();
443      }
444    
445      public void removeNotify()
446      {
447        if (menuBar != null)
448          menuBar.removeNotify();
449        super.removeNotify();
450      }
451    
452      /**
453       * Returns a debugging string describing this window.
454       *
455       * @return a debugging string describing this window
456       */
457      protected String paramString()
458      {
459        String title = getTitle();
460    
461        String resizable = "";
462        if (isResizable ())
463          resizable = ",resizable";
464    
465        String state = "";
466        switch (getState ())
467          {
468          case NORMAL:
469            state = ",normal";
470            break;
471          case ICONIFIED:
472            state = ",iconified";
473            break;
474          case MAXIMIZED_BOTH:
475            state = ",maximized-both";
476            break;
477          case MAXIMIZED_HORIZ:
478            state = ",maximized-horiz";
479            break;
480          case MAXIMIZED_VERT:
481            state = ",maximized-vert";
482            break;
483          }
484    
485        return super.paramString () + ",title=" + title + resizable + state;
486      }
487    
488      /**
489       * The list of active frames. GC'ed frames get removed in noteFrame().
490       */
491      private static ArrayList<WeakReference<Frame>> weakFrames =
492        new ArrayList<WeakReference<Frame>>();
493    
494      /**
495       * The death queue for all frames.
496       */ 
497      private static ReferenceQueue weakFramesQueue =
498        new ReferenceQueue<Frame>();
499    
500      private static void noteFrame(Frame f)
501      {
502        synchronized (weakFrames)
503          {
504            // Remove GCed frames from the list.
505            Reference ref = weakFramesQueue.poll();
506            while (ref != null)
507              {
508                weakFrames.remove(ref);
509                ref = weakFramesQueue.poll();
510              }
511            // Add new frame.
512            weakFrames.add(new WeakReference<Frame>(f));
513          }
514      }
515    
516      /**
517       * Returns <code>true</code> when there are any displayable frames,
518       * <code>false</code> otherwise.
519       *
520       * @return <code>true</code> when there are any displayable frames,
521       *         <code>false</code> otherwise
522       */
523      static boolean hasDisplayableFrames()
524      {
525        synchronized (weakFrames)
526          {
527            for (WeakReference<Frame> r : Frame.weakFrames)
528              {
529                Frame f = (Frame) r.get();
530                if (f != null && f.isDisplayable())
531                  return true;
532              }
533          }
534        return false;
535      }
536    
537      public static Frame[] getFrames()
538      {
539        synchronized (weakFrames)
540          {
541            ArrayList<Frame> existingFrames = new ArrayList<Frame>();
542            for (WeakReference<Frame> ref : weakFrames)
543              {
544                Frame f = ref.get();
545                if (f != null)
546                  {
547                    existingFrames.add(f);
548                  }
549              }
550            Frame[] frames = new Frame[existingFrames.size()];
551            frames = existingFrames.toArray(frames);
552            return frames;
553          }
554      }
555    
556      public void setState(int state)
557      {
558        int current_state = getExtendedState ();
559    
560        if (state == NORMAL
561            && (current_state & ICONIFIED) != 0)
562          setExtendedState(current_state | ICONIFIED);
563        
564        if (state == ICONIFIED
565            && (current_state & ~ICONIFIED) == 0)
566          setExtendedState(current_state & ~ICONIFIED);
567      }
568    
569      public int getState()
570      {
571        return (getExtendedState() & ICONIFIED) != 0 ? ICONIFIED : NORMAL;
572      }
573    
574      /**
575       * @since 1.4
576       */
577      public void setExtendedState(int state)
578      {
579        if (getToolkit().isFrameStateSupported(state))
580          {
581            this.state = state;
582            FramePeer p = (FramePeer) peer;
583            if (p != null)
584              p.setState(state);
585          }
586      }
587    
588      /**
589       * @since 1.4
590       */
591      public int getExtendedState()
592      {
593        FramePeer p = (FramePeer) peer;
594        if (p != null)
595          state = p.getState();
596        return state;
597      }
598    
599      /**
600       * @since 1.4
601       */
602      public void setMaximizedBounds(Rectangle maximizedBounds)
603      {
604        this.maximizedBounds = maximizedBounds;
605      }
606    
607      /**
608       * Returns the maximized bounds of this frame.
609       *
610       * @return the maximized rectangle, may be null
611       *
612       * @since 1.4
613       */
614      public Rectangle getMaximizedBounds()
615      {
616        return maximizedBounds;
617      }
618    
619      /**
620       * Returns whether this frame is undecorated or not.
621       * 
622       * @since 1.4
623       */
624      public boolean isUndecorated()
625      {
626        return undecorated;
627      }
628    
629      /**
630       * Disables or enables decorations for this frame. This method can only be
631       * called while the frame is not displayable.
632       * 
633       * @throws IllegalComponentStateException if this frame is displayable
634       * 
635       * @since 1.4
636       */
637      public void setUndecorated(boolean undecorated)
638      {
639        if (isDisplayable())
640          throw new IllegalComponentStateException();
641    
642        this.undecorated = undecorated;
643      }
644    
645      /**
646       * Generate a unique name for this frame.
647       *
648       * @return a unique name for this frame
649       */
650      String generateName()
651      {
652        return "frame" + getUniqueLong();
653      }
654    
655      private static synchronized long getUniqueLong()
656      {
657        return next_frame_number++;
658      }
659      
660      /**
661       * Accessibility support for <code>Frame</code>.
662       */
663      protected class AccessibleAWTFrame extends AccessibleAWTWindow
664      {
665        private static final long serialVersionUID = -6172960752956030250L;
666    
667        /**
668         * Gets the role of this object.
669         * @return AccessibleRole.FRAME
670         */
671        public AccessibleRole getAccessibleRole()
672        {
673          return AccessibleRole.FRAME;
674        }
675        
676        /**
677         * Gets the state set of this object.
678         * @return The current state of this frame.
679         */
680        public AccessibleStateSet getAccessibleStateSet()
681        {
682          AccessibleStateSet states = super.getAccessibleStateSet();
683          if (isResizable())
684            states.add(AccessibleState.RESIZABLE);
685          if ((state & ICONIFIED) != 0)
686            states.add(AccessibleState.ICONIFIED);
687          return states;
688        }
689      }
690      
691      /**
692       * Gets the AccessibleContext associated with this <code>Frame</code>.
693       * The context is created, if necessary.
694       *
695       * @return the associated context
696       */
697      public AccessibleContext getAccessibleContext()
698      {
699        // Create the context if this is the first request.
700        if (accessibleContext == null)
701          accessibleContext = new AccessibleAWTFrame();
702        return accessibleContext;
703      }
704    }