1. /*
  2. * @(#)Frame.java 1.97 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.awt.peer.FramePeer;
  9. import java.awt.event.*;
  10. import java.util.Vector;
  11. import java.io.ObjectOutputStream;
  12. import java.io.ObjectInputStream;
  13. import java.io.IOException;
  14. import sun.awt.AppContext;
  15. import java.lang.ref.WeakReference;
  16. /**
  17. * A Frame is a top-level window with a title and a border.
  18. * <p>
  19. * The size of the frame includes any area designated for the
  20. * border. The dimensions of the border area can be obtained
  21. * using the <code>getInsets</code> method, however, since
  22. * these dimensions are platform-dependent, a valid insets
  23. * value cannot be obtained until the frame is made displayable
  24. * by either calling <code>pack</code> or <code>show</code>.
  25. * Since the border area is included in the overall size of the
  26. * frame, the border effectively obscures a portion of the frame,
  27. * constraining the area available for rendering and/or displaying
  28. * subcomponents to the rectangle which has an upper-left corner
  29. * location of <code>(insets.left, insets.top)</code>, and has a size of
  30. * <code>width - (insets.left + insets.right)</code> by
  31. * <code>height - (insets.top + insets.bottom)</code>.
  32. * <p>
  33. * The default layout for a frame is BorderLayout.
  34. * <p>
  35. * Frames are capable of generating the following types of window events:
  36. * WindowOpened, WindowClosing, WindowClosed, WindowIconified,
  37. * WindowDeiconified, WindowActivated, WindowDeactivated.
  38. *
  39. * @version 1.97, 11/29/01
  40. * @author Sami Shaio
  41. * @see WindowEvent
  42. * @see Window#addWindowListener
  43. * @since JDK1.0
  44. */
  45. public class Frame extends Window implements MenuContainer {
  46. /* Note: These are being obsoleted; programs should use the Cursor class
  47. * variables going forward. See Cursor and Component.setCursor.
  48. */
  49. /**
  50. * @deprecated replaced by <code>Cursor.DEFAULT_CURSOR</code>.
  51. */
  52. public static final int DEFAULT_CURSOR = Cursor.DEFAULT_CURSOR;
  53. /**
  54. * @deprecated replaced by <code>Cursor.CROSSHAIR_CURSOR</code>.
  55. */
  56. public static final int CROSSHAIR_CURSOR = Cursor.CROSSHAIR_CURSOR;
  57. /**
  58. * @deprecated replaced by <code>Cursor.TEXT_CURSOR</code>.
  59. */
  60. public static final int TEXT_CURSOR = Cursor.TEXT_CURSOR;
  61. /**
  62. * @deprecated replaced by <code>Cursor.WAIT_CURSOR</code>.
  63. */
  64. public static final int WAIT_CURSOR = Cursor.WAIT_CURSOR;
  65. /**
  66. * @deprecated replaced by <code>Cursor.SW_RESIZE_CURSOR</code>.
  67. */
  68. public static final int SW_RESIZE_CURSOR = Cursor.SW_RESIZE_CURSOR;
  69. /**
  70. * @deprecated replaced by <code>Cursor.SE_RESIZE_CURSOR</code>.
  71. */
  72. public static final int SE_RESIZE_CURSOR = Cursor.SE_RESIZE_CURSOR;
  73. /**
  74. * @deprecated replaced by <code>Cursor.NW_RESIZE_CURSOR</code>.
  75. */
  76. public static final int NW_RESIZE_CURSOR = Cursor.NW_RESIZE_CURSOR;
  77. /**
  78. * @deprecated replaced by <code>Cursor.NE_RESIZE_CURSOR</code>.
  79. */
  80. public static final int NE_RESIZE_CURSOR = Cursor.NE_RESIZE_CURSOR;
  81. /**
  82. * @deprecated replaced by <code>Cursor.N_RESIZE_CURSOR</code>.
  83. */
  84. public static final int N_RESIZE_CURSOR = Cursor.N_RESIZE_CURSOR;
  85. /**
  86. * @deprecated replaced by <code>Cursor.S_RESIZE_CURSOR</code>.
  87. */
  88. public static final int S_RESIZE_CURSOR = Cursor.S_RESIZE_CURSOR;
  89. /**
  90. * @deprecated replaced by <code>Cursor.W_RESIZE_CURSOR</code>.
  91. */
  92. public static final int W_RESIZE_CURSOR = Cursor.W_RESIZE_CURSOR;
  93. /**
  94. * @deprecated replaced by <code>Cursor.E_RESIZE_CURSOR</code>.
  95. */
  96. public static final int E_RESIZE_CURSOR = Cursor.E_RESIZE_CURSOR;
  97. /**
  98. * @deprecated replaced by <code>Cursor.HAND_CURSOR</code>.
  99. */
  100. public static final int HAND_CURSOR = Cursor.HAND_CURSOR;
  101. /**
  102. * @deprecated replaced by <code>Cursor.MOVE_CURSOR</code>.
  103. */
  104. public static final int MOVE_CURSOR = Cursor.MOVE_CURSOR;
  105. public static final int NORMAL = 0;
  106. public static final int ICONIFIED = 1;
  107. /**
  108. * This is the title of the frame. It can be changed
  109. * at any time. <code>title</code> can be null and if
  110. * this is the case the <code>title</code> = "".
  111. *
  112. * @serial
  113. * @see getTitle()
  114. * @see setTitle()
  115. */
  116. String title = "Untitled";
  117. /**
  118. * <code>icon</code> is the graphical way we can
  119. * represent the frame.
  120. * <code>icon</code> can be null, but obviously if
  121. * you try to set the icon image <code>icon</code>
  122. * cannot be null.
  123. *
  124. * @serial
  125. * @see getIconImage()
  126. * @see setIconImage()
  127. */
  128. Image icon;
  129. /**
  130. * The frames menubar. If <code>menuBar</code> = null
  131. * the frame will not have a menubar.
  132. *
  133. * @serial
  134. * @see getMenuBar()
  135. * @see setMenuBar()
  136. */
  137. MenuBar menuBar;
  138. /**
  139. * This field indicates whether the the frame is resizable
  140. * This property can be changed at any time.
  141. * <code>resizable</code> will be true if the frame is
  142. * resizable, otherwise it will be false.
  143. *
  144. * @serial
  145. * @see isResizable()
  146. */
  147. boolean resizable = true;
  148. /**
  149. * <code>mbManagement</code> is only used by the Motif implementation.
  150. *
  151. * @serial
  152. */
  153. boolean mbManagement = false; /* used only by the Motif impl. */
  154. private int state = NORMAL;
  155. /*
  156. * The Windows owned by the Frame.
  157. * Note: in 1.2 this has been superceded by Window.ownedWindowList
  158. *
  159. * @serial
  160. * @see java.awt.Window#ownedWindowList
  161. */
  162. Vector ownedWindows;
  163. /*
  164. * We insert a weak reference into the Vector of all Frames
  165. * instead of 'this' so that garbage collection can still take
  166. * place correctly.
  167. */
  168. transient private WeakReference weakThis;
  169. private static final String base = "frame";
  170. private static int nameCounter = 0;
  171. /*
  172. * JDK 1.1 serialVersionUID
  173. */
  174. private static final long serialVersionUID = 2673458971256075116L;
  175. static {
  176. /* ensure that the necessary native libraries are loaded */
  177. Toolkit.loadLibraries();
  178. initIDs();
  179. }
  180. /**
  181. * Constructs a new instance of <code>Frame</code> that is
  182. * initially invisible. The title of the <code>Frame</code>
  183. * is empty.
  184. * @see Component#setSize
  185. * @see Component#setVisible
  186. */
  187. public Frame() {
  188. this("");
  189. }
  190. /**
  191. * Constructs a new, initially invisible <code>Frame</code> object
  192. * with the specified title.
  193. * @param title the title to be displayed in the frame's border.
  194. * A <code>null</code> value
  195. * is treated as an empty string, "".
  196. * @see java.awt.Component#setSize
  197. * @see java.awt.Component#setVisible
  198. */
  199. public Frame(String title) {
  200. this.title = title;
  201. visible = false;
  202. setLayout(new BorderLayout());
  203. weakThis = new WeakReference(this);
  204. addToFrameList();
  205. }
  206. /**
  207. * We have to remove the (hard) reference to weakThis in the
  208. * Vector, otherwise the WeakReference instance will never get
  209. * garbage collected.
  210. */
  211. protected void finalize() throws Throwable {
  212. removeFromFrameList();
  213. super.finalize();
  214. }
  215. /**
  216. * Construct a name for this component. Called by getName() when the
  217. * name is null.
  218. */
  219. String constructComponentName() {
  220. synchronized (getClass()) {
  221. return base + nameCounter++;
  222. }
  223. }
  224. /**
  225. * Makes this Frame displayable by connecting it to
  226. * a native screen resource. Making a frame displayable will
  227. * cause any of its children to be made displayable.
  228. * This method is called internally by the toolkit and should
  229. * not be called directly by programs.
  230. * @see Component#isDisplayable
  231. * @see #removeNotify
  232. */
  233. public void addNotify() {
  234. synchronized (getTreeLock()) {
  235. if (peer == null) {
  236. peer = getToolkit().createFrame(this);
  237. }
  238. MenuBar menuBar = this.menuBar;
  239. if (menuBar != null) {
  240. mbManagement = true;
  241. menuBar.addNotify();
  242. ((FramePeer)peer).setMenuBar(menuBar);
  243. }
  244. super.addNotify();
  245. }
  246. }
  247. /**
  248. * Gets the title of the frame. The title is displayed in the
  249. * frame's border.
  250. * @return the title of this frame, or an empty string ("")
  251. * if this frame doesn't have a title.
  252. * @see java.awt.Frame#setTitle
  253. */
  254. public String getTitle() {
  255. return title;
  256. }
  257. /**
  258. * Sets the title for this frame to the specified string.
  259. * @param title the title to be displayed in the frame's border
  260. * @param title the title to be displayed in the frame's border.
  261. * A <code>null</code> value
  262. * is treated as an empty string, "".
  263. * @see java.awt.Frame#getTitle
  264. */
  265. public synchronized void setTitle(String title) {
  266. this.title = title;
  267. FramePeer peer = (FramePeer)this.peer;
  268. if (peer != null) {
  269. peer.setTitle(title);
  270. }
  271. }
  272. /**
  273. * Gets the image to be displayed in the minimized icon
  274. * for this frame.
  275. * @return the icon image for this frame, or <code>null</code>
  276. * if this frame doesn't have an icon image.
  277. * @see java.awt.Frame#setIconImage
  278. */
  279. public Image getIconImage() {
  280. return icon;
  281. }
  282. /**
  283. * Sets the image to displayed in the minimized icon for this frame.
  284. * Not all platforms support the concept of minimizing a window.
  285. * @param image the icon image to be displayed.
  286. * If this parameter is <code>null</code> then the
  287. * icon image is set to the default image, which may vary
  288. * with platform.
  289. * @see java.awt.Frame#getIconImage
  290. */
  291. public synchronized void setIconImage(Image image) {
  292. this.icon = image;
  293. FramePeer peer = (FramePeer)this.peer;
  294. if (peer != null) {
  295. peer.setIconImage(image);
  296. }
  297. }
  298. /**
  299. * Gets the menu bar for this frame.
  300. * @return the menu bar for this frame, or <code>null</code>
  301. * if this frame doesn't have a menu bar.
  302. * @see java.awt.Frame#setMenuBar
  303. */
  304. public MenuBar getMenuBar() {
  305. return menuBar;
  306. }
  307. /**
  308. * Sets the menu bar for this frame to the specified menu bar.
  309. * @param mb the menu bar being set.
  310. * If this parameter is <code>null</code> then any
  311. * existing menu bar on this frame is removed.
  312. * @see java.awt.Frame#getMenuBar
  313. */
  314. public void setMenuBar(MenuBar mb) {
  315. synchronized (getTreeLock()) {
  316. if (menuBar == mb) {
  317. return;
  318. }
  319. if ((mb != null) && (mb.parent != null)) {
  320. mb.parent.remove(mb);
  321. }
  322. if (menuBar != null) {
  323. remove(menuBar);
  324. }
  325. menuBar = mb;
  326. if (menuBar != null) {
  327. menuBar.parent = this;
  328. FramePeer peer = (FramePeer)this.peer;
  329. if (peer != null) {
  330. mbManagement = true;
  331. menuBar.addNotify();
  332. if (valid) {
  333. invalidate();
  334. }
  335. peer.setMenuBar(menuBar);
  336. }
  337. }
  338. }
  339. }
  340. /**
  341. * Indicates whether this frame is resizable by the user.
  342. * By default, all frames are initially resizable.
  343. * @return <code>true</code> if the user can resize this frame;
  344. * <code>false</code> otherwise.
  345. * @see java.awt.Frame#setResizable
  346. */
  347. public boolean isResizable() {
  348. return resizable;
  349. }
  350. /**
  351. * Sets whether this frame is resizable by the user.
  352. * @param resizable <code>true</code> if this frame is resizable;
  353. * <code>false</code> otherwise.
  354. * @see java.awt.Frame#isResizable
  355. */
  356. public void setResizable(boolean resizable) {
  357. boolean testvalid = false;
  358. synchronized (this) {
  359. this.resizable = resizable;
  360. FramePeer peer = (FramePeer)this.peer;
  361. if (peer != null) {
  362. peer.setResizable(resizable);
  363. testvalid = true;
  364. }
  365. }
  366. // On some platforms, changing the resizable state affects
  367. // the insets of the Frame. If we could, we'd call invalidate()
  368. // from the peer, but we need to guarantee that we're not holding
  369. // the Frame lock when we call invalidate().
  370. if (testvalid && valid) {
  371. invalidate();
  372. }
  373. }
  374. /**
  375. * Sets the state of this frame.
  376. * @param state <code>Frame.ICONIFIED</code> if this frame is in
  377. * iconic state; <code>Frame.NORMAL</code> if this frame is
  378. * in normal state.
  379. * @see java.awt.Frame#getState
  380. */
  381. public synchronized void setState(int state) {
  382. this.state = state;
  383. FramePeer peer = (FramePeer)this.peer;
  384. if (peer != null) {
  385. peer.setState(state);
  386. }
  387. }
  388. /**
  389. * Gets the state of this frame.
  390. * @return <code>Frame.ICONIFIED</code> if frame in iconic state;
  391. * <code>Frame.NORMAL</code> if frame is in normal state.
  392. * @see java.awt.Frame#setState
  393. */
  394. public synchronized int getState() {
  395. FramePeer peer = (FramePeer)this.peer;
  396. if (peer != null) {
  397. state = peer.getState();
  398. }
  399. return state;
  400. }
  401. /**
  402. * Removes the specified menu bar from this frame.
  403. * @param m the menu component to remove.
  404. * If this parameter is <code>null</code> then a
  405. * NullPointerException is thrown and no action
  406. * is taken.
  407. */
  408. public void remove(MenuComponent m) {
  409. synchronized (getTreeLock()) {
  410. if (m == menuBar) {
  411. menuBar = null;
  412. FramePeer peer = (FramePeer)this.peer;
  413. if (peer != null) {
  414. mbManagement = true;
  415. if (valid) {
  416. invalidate();
  417. }
  418. peer.setMenuBar(null);
  419. m.removeNotify();
  420. }
  421. m.parent = null;
  422. } else {
  423. super.remove(m);
  424. }
  425. }
  426. }
  427. /**
  428. * Makes this Frame undisplayable by removing its connection
  429. * to its native screen resource. Making a Frame undisplayable
  430. * will cause any of its children to be made undisplayable.
  431. * This method is called by the toolkit internally and should
  432. * not be called directly by programs.
  433. * @see Component#isDisplayable
  434. * @see #addNotify
  435. */
  436. public void removeNotify() {
  437. synchronized (getTreeLock()) {
  438. FramePeer peer = (FramePeer)this.peer;
  439. if (peer != null) {
  440. // get the latest Frame state before disposing
  441. getState();
  442. if (menuBar != null) {
  443. mbManagement = true;
  444. peer.setMenuBar(null);
  445. menuBar.removeNotify();
  446. }
  447. }
  448. super.removeNotify();
  449. }
  450. }
  451. void postProcessKeyEvent(KeyEvent e) {
  452. if (menuBar != null && menuBar.handleShortcut(e)) {
  453. e.consume();
  454. return;
  455. }
  456. super.postProcessKeyEvent(e);
  457. }
  458. /**
  459. * Returns the parameter String of this Frame.
  460. */
  461. protected String paramString() {
  462. String str = super.paramString();
  463. if (resizable) {
  464. str += ",resizable";
  465. }
  466. if (title != null) {
  467. str += ",title=" + title;
  468. }
  469. return str;
  470. }
  471. /**
  472. * @deprecated As of JDK version 1.1,
  473. * replaced by <code>Component.setCursor(Cursor)</code>.
  474. */
  475. public synchronized void setCursor(int cursorType) {
  476. if (cursorType < DEFAULT_CURSOR || cursorType > MOVE_CURSOR) {
  477. throw new IllegalArgumentException("illegal cursor type");
  478. }
  479. setCursor(Cursor.getPredefinedCursor(cursorType));
  480. }
  481. /**
  482. * @deprecated As of JDK version 1.1,
  483. * replaced by <code>Component.getCursor()</code>.
  484. */
  485. public int getCursorType() {
  486. return (getCursor().getType());
  487. }
  488. /**
  489. * Returns an array containing all Frames created by the application.
  490. * If called from an applet, the array will only include the Frames
  491. * accessible by that applet.
  492. * @since JDK1.2
  493. */
  494. public static Frame[] getFrames() {
  495. synchronized (Frame.class) {
  496. Frame realCopy[];
  497. Vector frameList =
  498. (Vector)AppContext.getAppContext().get(Frame.class);
  499. if (frameList != null) {
  500. // Recall that frameList is actually a Vector of WeakReferences
  501. // and calling get() on one of these references may return
  502. // null. Make two arrays-- one the size of the Vector
  503. // (fullCopy with size fullSize), and one the size of all
  504. // non-null get()s (realCopy with size realSize).
  505. int fullSize = frameList.size();
  506. int realSize = 0;
  507. Frame fullCopy[] = new Frame[fullSize];
  508. for (int i = 0; i < fullSize; i++) {
  509. fullCopy[realSize] = (Frame)
  510. (((WeakReference) (frameList.elementAt(i))).get());
  511. if (fullCopy[realSize] != null) {
  512. realSize++;
  513. }
  514. }
  515. if (fullSize != realSize) {
  516. realCopy = new Frame[realSize];
  517. System.arraycopy(fullCopy, 0, realCopy, 0, realSize);
  518. } else {
  519. realCopy = fullCopy;
  520. }
  521. } else {
  522. realCopy = new Frame[0];
  523. }
  524. return realCopy;
  525. }
  526. }
  527. void addToFrameList() {
  528. synchronized (Frame.class) {
  529. Vector frameList = (Vector)appContext.get(Frame.class);
  530. if (frameList == null) {
  531. frameList = new Vector();
  532. appContext.put(Frame.class, frameList);
  533. }
  534. frameList.addElement(weakThis);
  535. }
  536. }
  537. void removeFromFrameList() {
  538. synchronized (Frame.class) {
  539. Vector frameList = (Vector)appContext.get(Frame.class);
  540. if (frameList != null) {
  541. frameList.removeElement(weakThis);
  542. }
  543. }
  544. }
  545. /* Serialization support. If there's a MenuBar we restore
  546. * its (transient) parent field here. Likewise for top level
  547. * windows that are "owned" by this frame.
  548. */
  549. /**
  550. * Frame Serialized Data Version.
  551. *
  552. * @serial
  553. */
  554. private int frameSerializedDataVersion = 1;
  555. /**
  556. * Writes default serializable fields to stream. Writes
  557. * a list of serializable ItemListener(s) as optional data.
  558. * The non-serializable ItemListner(s) are detected and
  559. * no attempt is made to serialize them.
  560. *
  561. * @serialData Null terminated sequence of 0 or more pairs.
  562. * The pair consists of a String and Object.
  563. * The String indicates the type of object and
  564. * is one of the following :
  565. * itemListenerK indicating and ItemListener object.
  566. *
  567. * @see java.awt.Component.itemListenerK
  568. */
  569. private void writeObject(ObjectOutputStream s)
  570. throws IOException
  571. {
  572. s.defaultWriteObject();
  573. }
  574. /**
  575. * Read the ObjectInputStream and if it isnt null
  576. * add a listener to receive item events fired
  577. * by the Frame.
  578. * Unrecognised keys or values will be Ignored.
  579. * @see removeActionListener()
  580. * @see addActionListener()
  581. */
  582. private void readObject(ObjectInputStream s)
  583. throws ClassNotFoundException, IOException
  584. {
  585. s.defaultReadObject();
  586. if (menuBar != null)
  587. menuBar.parent = this;
  588. // Ensure 1.1 serialized Frames can read & hook-up
  589. // owned windows properly
  590. //
  591. if (ownedWindows != null) {
  592. for (int i = 0; i < ownedWindows.size(); i++) {
  593. connectOwnedWindow((Window) ownedWindows.elementAt(i));
  594. }
  595. ownedWindows = null;
  596. }
  597. weakThis = new WeakReference(this);
  598. addToFrameList();
  599. }
  600. /**
  601. * Initialize JNI field and method IDs
  602. */
  603. private static native void initIDs();
  604. }