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 }