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