1 /* Window.java -- 2 Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.awt; 40 41 import java.awt.event.WindowEvent; 42 import java.awt.event.WindowFocusListener; 43 import java.awt.event.WindowListener; 44 import java.awt.event.WindowStateListener; 45 import java.awt.peer.WindowPeer; 46 import java.lang.ref.Reference; 47 import java.lang.ref.WeakReference; 48 import java.util.Iterator; 49 import java.util.EventListener; 50 import java.util.Locale; 51 import java.util.ResourceBundle; 52 import java.util.Vector; 53 import javax.accessibility.Accessible; 54 import javax.accessibility.AccessibleContext; 55 56 /** 57 * This class represents a top-level window with no decorations. 58 * 59 * @author Aaron M. Renn <arenn@urbanophile.com> 60 * @author Warren Levy <warrenl@cygnus.com> 61 */ 62 public class Window extends Container implements Accessible 63 { 64 private static final long serialVersionUID = 4497834738069338734L; 65 66 // Serialized fields, from Sun's serialization spec. 67 private String warningString = null; 68 private int windowSerializedDataVersion = 0; // FIXME 69 /** @since 1.2 */ 70 // private FocusManager focusMgr; // FIXME: what is this? 71 /** @since 1.2 */ 72 private int state = 0; 73 /** @since 1.4 */ 74 private boolean focusableWindowState = true; 75 76 // A list of other top-level windows owned by this window. 77 private transient Vector ownedWindows = new Vector(); 78 79 private transient WindowListener windowListener; 80 private transient WindowFocusListener windowFocusListener; 81 private transient WindowStateListener windowStateListener; 82 private transient GraphicsConfiguration graphicsConfiguration; 83 private transient AccessibleContext accessibleContext; 84 85 /** 86 * This (package access) constructor is used by subclasses that want 87 * to build windows that do not have parents. Eg. toplevel 88 * application frames. Subclasses cannot call super(null), since 89 * null is an illegal argument. 90 */ Window()91 Window() 92 { 93 visible = false; 94 setLayout(new BorderLayout()); 95 } 96 Window(GraphicsConfiguration gc)97 Window(GraphicsConfiguration gc) 98 { 99 this(); 100 graphicsConfiguration = gc; 101 } 102 103 /** 104 * Initializes a new instance of <code>Window</code> with the specified 105 * parent. The window will initially be invisible. 106 * 107 * @param parent The owning <code>Frame</code> of this window. 108 * 109 * @exception IllegalArgumentException If the owner's GraphicsConfiguration 110 * is not from a screen device, or if owner is null; this exception is always 111 * thrown when GraphicsEnvironment.isHeadless returns true. 112 */ Window(Frame owner)113 public Window(Frame owner) 114 { 115 this (owner, owner.getGraphicsConfiguration ()); 116 } 117 118 /** 119 * Initializes a new instance of <code>Window</code> with the specified 120 * parent. The window will initially be invisible. 121 * 122 * @exception IllegalArgumentException If the owner's GraphicsConfiguration 123 * is not from a screen device, or if owner is null; this exception is always 124 * thrown when GraphicsEnvironment.isHeadless returns true. 125 * 126 * @since 1.2 127 */ Window(Window owner)128 public Window(Window owner) 129 { 130 this (owner, owner.getGraphicsConfiguration ()); 131 } 132 133 /** 134 * Initializes a new instance of <code>Window</code> with the specified 135 * parent. The window will initially be invisible. 136 * 137 * @exception IllegalArgumentException If owner is null or if gc is not from a 138 * screen device; this exception is always thrown when 139 * GraphicsEnvironment.isHeadless returns true. 140 * 141 * @since 1.3 142 */ Window(Window owner, GraphicsConfiguration gc)143 public Window(Window owner, GraphicsConfiguration gc) 144 { 145 this (); 146 147 synchronized (getTreeLock()) 148 { 149 if (owner == null) 150 throw new IllegalArgumentException ("owner must not be null"); 151 152 parent = owner; 153 owner.ownedWindows.add(new WeakReference(this)); 154 } 155 156 // FIXME: make this text visible in the window. 157 SecurityManager s = System.getSecurityManager(); 158 if (s != null && ! s.checkTopLevelWindow(this)) 159 warningString = System.getProperty("awt.appletWarning"); 160 161 if (gc != null 162 && gc.getDevice().getType() != GraphicsDevice.TYPE_RASTER_SCREEN) 163 throw new IllegalArgumentException ("gc must be from a screen device"); 164 165 // FIXME: until we implement this, it just causes AWT to crash. 166 // if (gc == null) 167 // graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment() 168 // .getDefaultScreenDevice() 169 // .getDefaultConfiguration(); 170 // else 171 graphicsConfiguration = gc; 172 } 173 getGraphicsConfigurationImpl()174 GraphicsConfiguration getGraphicsConfigurationImpl() 175 { 176 if (graphicsConfiguration != null) 177 return graphicsConfiguration; 178 179 return super.getGraphicsConfigurationImpl(); 180 } 181 182 /** 183 * Creates the native peer for this window. 184 */ addNotify()185 public void addNotify() 186 { 187 if (peer == null) 188 peer = getToolkit().createWindow(this); 189 super.addNotify(); 190 } 191 192 /** 193 * Relays out this window's child components at their preferred size. 194 * 195 * @specnote pack() doesn't appear to be called internally by show(), so 196 * we duplicate some of the functionality. 197 */ pack()198 public void pack() 199 { 200 if (parent != null && !parent.isDisplayable()) 201 parent.addNotify(); 202 if (peer == null) 203 addNotify(); 204 205 setSize(getPreferredSize()); 206 207 validate(); 208 } 209 210 /** 211 * Shows on-screen this window and any of its owned windows for whom 212 * isVisible returns true. 213 */ show()214 public void show() 215 { 216 if (parent != null && !parent.isDisplayable()) 217 parent.addNotify(); 218 if (peer == null) 219 addNotify(); 220 221 // Show visible owned windows. 222 synchronized (getTreeLock()) 223 { 224 Iterator e = ownedWindows.iterator(); 225 while(e.hasNext()) 226 { 227 Window w = (Window)(((Reference) e.next()).get()); 228 if (w != null) 229 { 230 if (w.isVisible()) 231 w.getPeer().setVisible(true); 232 } 233 else 234 // Remove null weak reference from ownedWindows. 235 // Unfortunately this can't be done in the Window's 236 // finalize method because there is no way to guarantee 237 // synchronous access to ownedWindows there. 238 e.remove(); 239 } 240 } 241 validate(); 242 super.show(); 243 toFront(); 244 } 245 hide()246 public void hide() 247 { 248 // Hide visible owned windows. 249 synchronized (getTreeLock ()) 250 { 251 Iterator e = ownedWindows.iterator(); 252 while(e.hasNext()) 253 { 254 Window w = (Window)(((Reference) e.next()).get()); 255 if (w != null) 256 { 257 if (w.isVisible() && w.getPeer() != null) 258 w.getPeer().setVisible(false); 259 } 260 else 261 e.remove(); 262 } 263 } 264 super.hide(); 265 } 266 isDisplayable()267 public boolean isDisplayable() 268 { 269 if (super.isDisplayable()) 270 return true; 271 return peer != null; 272 } 273 274 /** 275 * Destroys any resources associated with this window. This includes 276 * all components in the window and all owned top-level windows. 277 */ dispose()278 public void dispose() 279 { 280 hide(); 281 282 synchronized (getTreeLock ()) 283 { 284 Iterator e = ownedWindows.iterator(); 285 while(e.hasNext()) 286 { 287 Window w = (Window)(((Reference) e.next()).get()); 288 if (w != null) 289 w.dispose(); 290 else 291 // Remove null weak reference from ownedWindows. 292 e.remove(); 293 } 294 295 for (int i = 0; i < ncomponents; ++i) 296 component[i].removeNotify(); 297 this.removeNotify(); 298 299 // Post a WINDOW_CLOSED event. 300 WindowEvent we = new WindowEvent(this, WindowEvent.WINDOW_CLOSED); 301 getToolkit().getSystemEventQueue().postEvent(we); 302 } 303 } 304 305 /** 306 * Sends this window to the back so that all other windows display in 307 * front of it. 308 */ toBack()309 public void toBack() 310 { 311 if (peer != null) 312 { 313 WindowPeer wp = (WindowPeer) peer; 314 wp.toBack(); 315 } 316 } 317 318 /** 319 * Brings this window to the front so that it displays in front of 320 * any other windows. 321 */ toFront()322 public void toFront() 323 { 324 if (peer != null) 325 { 326 WindowPeer wp = (WindowPeer) peer; 327 wp.toFront(); 328 } 329 } 330 331 /** 332 * Returns the toolkit used to create this window. 333 * 334 * @return The toolkit used to create this window. 335 * 336 * @specnote Unlike Component.getToolkit, this implementation always 337 * returns the value of Toolkit.getDefaultToolkit(). 338 */ getToolkit()339 public Toolkit getToolkit() 340 { 341 return Toolkit.getDefaultToolkit(); 342 } 343 344 /** 345 * Returns the warning string that will be displayed if this window is 346 * popped up by an unsecure applet or application. 347 * 348 * @return The unsecure window warning message. 349 */ getWarningString()350 public final String getWarningString() 351 { 352 return warningString; 353 } 354 355 /** 356 * Returns the locale that this window is configured for. 357 * 358 * @return The locale this window is configured for. 359 */ getLocale()360 public Locale getLocale() 361 { 362 return locale == null ? Locale.getDefault() : locale; 363 } 364 365 /* 366 /** @since 1.2 367 public InputContext getInputContext() 368 { 369 // FIXME 370 } 371 */ 372 373 /** 374 * Sets the cursor for this window to the specifiec cursor. 375 * 376 * @param cursor The new cursor for this window. 377 */ setCursor(Cursor cursor)378 public void setCursor(Cursor cursor) 379 { 380 super.setCursor(cursor); 381 } 382 getOwner()383 public Window getOwner() 384 { 385 return (Window) parent; 386 } 387 388 /** @since 1.2 */ getOwnedWindows()389 public Window[] getOwnedWindows() 390 { 391 Window [] trimmedList; 392 synchronized (getTreeLock ()) 393 { 394 // Windows with non-null weak references in ownedWindows. 395 Window [] validList = new Window [ownedWindows.size()]; 396 397 Iterator e = ownedWindows.iterator(); 398 int numValid = 0; 399 while (e.hasNext()) 400 { 401 Window w = (Window)(((Reference) e.next()).get()); 402 if (w != null) 403 validList[numValid++] = w; 404 else 405 // Remove null weak reference from ownedWindows. 406 e.remove(); 407 } 408 409 if (numValid != validList.length) 410 { 411 trimmedList = new Window [numValid]; 412 System.arraycopy (validList, 0, trimmedList, 0, numValid); 413 } 414 else 415 trimmedList = validList; 416 } 417 return trimmedList; 418 } 419 420 /** 421 * Adds the specified listener to the list of <code>WindowListeners</code> 422 * that will receive events for this window. 423 * 424 * @param listener The <code>WindowListener</code> to add. 425 */ addWindowListener(WindowListener listener)426 public synchronized void addWindowListener(WindowListener listener) 427 { 428 windowListener = AWTEventMulticaster.add(windowListener, listener); 429 } 430 431 /** 432 * Removes the specified listener from the list of 433 * <code>WindowListeners</code> that will receive events for this window. 434 * 435 * @param listener The <code>WindowListener</code> to remove. 436 */ removeWindowListener(WindowListener listener)437 public synchronized void removeWindowListener(WindowListener listener) 438 { 439 windowListener = AWTEventMulticaster.remove(windowListener, listener); 440 } 441 442 /** 443 * Returns an array of all the window listeners registered on this window. 444 * 445 * @since 1.4 446 */ getWindowListeners()447 public synchronized WindowListener[] getWindowListeners() 448 { 449 return (WindowListener[]) 450 AWTEventMulticaster.getListeners(windowListener, 451 WindowListener.class); 452 } 453 454 /** 455 * Returns an array of all the window focus listeners registered on this 456 * window. 457 * 458 * @since 1.4 459 */ getWindowFocusListeners()460 public synchronized WindowFocusListener[] getWindowFocusListeners() 461 { 462 return (WindowFocusListener[]) 463 AWTEventMulticaster.getListeners(windowFocusListener, 464 WindowFocusListener.class); 465 } 466 467 /** 468 * Returns an array of all the window state listeners registered on this 469 * window. 470 * 471 * @since 1.4 472 */ getWindowStateListeners()473 public synchronized WindowStateListener[] getWindowStateListeners() 474 { 475 return (WindowStateListener[]) 476 AWTEventMulticaster.getListeners(windowStateListener, 477 WindowStateListener.class); 478 } 479 480 /** 481 * Adds the specified listener to this window. 482 */ addWindowFocusListener(WindowFocusListener wfl)483 public void addWindowFocusListener (WindowFocusListener wfl) 484 { 485 windowFocusListener = AWTEventMulticaster.add (windowFocusListener, wfl); 486 } 487 488 /** 489 * Adds the specified listener to this window. 490 * 491 * @since 1.4 492 */ addWindowStateListener(WindowStateListener wsl)493 public void addWindowStateListener (WindowStateListener wsl) 494 { 495 windowStateListener = AWTEventMulticaster.add (windowStateListener, wsl); 496 } 497 498 /** 499 * Removes the specified listener from this window. 500 */ removeWindowFocusListener(WindowFocusListener wfl)501 public void removeWindowFocusListener (WindowFocusListener wfl) 502 { 503 windowFocusListener = AWTEventMulticaster.remove (windowFocusListener, wfl); 504 } 505 506 /** 507 * Removes the specified listener from this window. 508 * 509 * @since 1.4 510 */ removeWindowStateListener(WindowStateListener wsl)511 public void removeWindowStateListener (WindowStateListener wsl) 512 { 513 windowStateListener = AWTEventMulticaster.remove (windowStateListener, wsl); 514 } 515 516 /** 517 * Returns an array of all the objects currently registered as FooListeners 518 * upon this Window. FooListeners are registered using the addFooListener 519 * method. 520 * 521 * @exception ClassCastException If listenerType doesn't specify a class or 522 * interface that implements java.util.EventListener. 523 * 524 * @since 1.3 525 */ getListeners(Class listenerType)526 public EventListener[] getListeners(Class listenerType) 527 { 528 if (listenerType == WindowListener.class) 529 return getWindowListeners(); 530 return super.getListeners(listenerType); 531 } 532 dispatchEventImpl(AWTEvent e)533 void dispatchEventImpl(AWTEvent e) 534 { 535 // Make use of event id's in order to avoid multiple instanceof tests. 536 if (e.id <= WindowEvent.WINDOW_LAST 537 && e.id >= WindowEvent.WINDOW_FIRST 538 && (windowListener != null 539 || windowFocusListener != null 540 || windowStateListener != null 541 || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)) 542 processEvent(e); 543 else 544 super.dispatchEventImpl(e); 545 } 546 547 /** 548 * Processes the specified event for this window. If the event is an 549 * instance of <code>WindowEvent</code>, then 550 * <code>processWindowEvent()</code> is called to process the event, 551 * otherwise the superclass version of this method is invoked. 552 * 553 * @param event The event to process. 554 */ processEvent(AWTEvent evt)555 protected void processEvent(AWTEvent evt) 556 { 557 if (evt instanceof WindowEvent) 558 processWindowEvent((WindowEvent) evt); 559 else 560 super.processEvent(evt); 561 } 562 563 /** 564 * Dispatches this event to any listeners that are listening for 565 * <code>WindowEvents</code> on this window. This method only gets 566 * invoked if it is enabled via <code>enableEvents()</code> or if 567 * a listener has been added. 568 * 569 * @param event The event to process. 570 */ processWindowEvent(WindowEvent evt)571 protected void processWindowEvent(WindowEvent evt) 572 { 573 int id = evt.getID(); 574 575 if (id == WindowEvent.WINDOW_GAINED_FOCUS 576 || id == WindowEvent.WINDOW_LOST_FOCUS) 577 processWindowFocusEvent (evt); 578 else if (id == WindowEvent.WINDOW_STATE_CHANGED) 579 processWindowStateEvent (evt); 580 else 581 { 582 if (windowListener != null) 583 { 584 switch (evt.getID()) 585 { 586 case WindowEvent.WINDOW_ACTIVATED: 587 windowListener.windowActivated(evt); 588 break; 589 590 case WindowEvent.WINDOW_CLOSED: 591 windowListener.windowClosed(evt); 592 break; 593 594 case WindowEvent.WINDOW_CLOSING: 595 windowListener.windowClosing(evt); 596 break; 597 598 case WindowEvent.WINDOW_DEACTIVATED: 599 windowListener.windowDeactivated(evt); 600 break; 601 602 case WindowEvent.WINDOW_DEICONIFIED: 603 windowListener.windowDeiconified(evt); 604 break; 605 606 case WindowEvent.WINDOW_ICONIFIED: 607 windowListener.windowIconified(evt); 608 break; 609 610 case WindowEvent.WINDOW_OPENED: 611 windowListener.windowOpened(evt); 612 break; 613 614 default: 615 break; 616 } 617 } 618 } 619 } 620 621 /** 622 * Returns the child window that has focus if this window is active. 623 * This method returns <code>null</code> if this window is not active 624 * or no children have focus. 625 * 626 * @return The component that has focus, or <code>null</code> if no 627 * component has focus. 628 */ getFocusOwner()629 public Component getFocusOwner() 630 { 631 // FIXME 632 return null; 633 } 634 635 /** 636 * Post a Java 1.0 event to the event queue. 637 * 638 * @param event The event to post. 639 * 640 * @deprecated 641 */ postEvent(Event e)642 public boolean postEvent(Event e) 643 { 644 // FIXME 645 return false; 646 } 647 648 /** 649 * Tests whether or not this window is visible on the screen. 650 * 651 * @return <code>true</code> if this window is visible, <code>false</code> 652 * otherwise. 653 */ isShowing()654 public boolean isShowing() 655 { 656 return super.isShowing(); 657 } 658 659 /** 660 * @since 1.2 661 * 662 * @deprecated 663 */ applyResourceBundle(ResourceBundle rb)664 public void applyResourceBundle(ResourceBundle rb) 665 { 666 throw new Error ("Not implemented"); 667 } 668 669 /** 670 * @since 1.2 671 * 672 * @deprecated 673 */ applyResourceBundle(String rbName)674 public void applyResourceBundle(String rbName) 675 { 676 ResourceBundle rb = ResourceBundle.getBundle(rbName); 677 if (rb != null) 678 applyResourceBundle(rb); 679 } 680 getAccessibleContext()681 public AccessibleContext getAccessibleContext() 682 { 683 // FIXME 684 //return null; 685 throw new Error ("Not implemented"); 686 } 687 688 /** 689 * Get graphics configuration. The implementation for Window will 690 * not ask any parent containers, since Window is a toplevel 691 * window and not actually embedded in the parent component. 692 */ getGraphicsConfiguration()693 public GraphicsConfiguration getGraphicsConfiguration() 694 { 695 if (graphicsConfiguration != null) return graphicsConfiguration; 696 if (peer != null) return peer.getGraphicsConfiguration(); 697 return null; 698 } 699 processWindowFocusEvent(WindowEvent event)700 protected void processWindowFocusEvent(WindowEvent event) 701 { 702 if (windowFocusListener != null) 703 { 704 switch (event.getID ()) 705 { 706 case WindowEvent.WINDOW_GAINED_FOCUS: 707 windowFocusListener.windowGainedFocus (event); 708 break; 709 710 case WindowEvent.WINDOW_LOST_FOCUS: 711 windowFocusListener.windowLostFocus (event); 712 break; 713 714 default: 715 break; 716 } 717 } 718 } 719 720 /** 721 * @since 1.4 722 */ processWindowStateEvent(WindowEvent event)723 protected void processWindowStateEvent(WindowEvent event) 724 { 725 if (windowStateListener != null 726 && event.getID () == WindowEvent.WINDOW_STATE_CHANGED) 727 windowStateListener.windowStateChanged (event); 728 } 729 730 /** 731 * Returns whether this <code>Window</code> can get the focus or not. 732 * 733 * @since 1.4 734 */ isFocusableWindow()735 public final boolean isFocusableWindow () 736 { 737 if (getFocusableWindowState () == false) 738 return false; 739 740 if (this instanceof Dialog 741 || this instanceof Frame) 742 return true; 743 744 // FIXME: Implement more possible cases for returning true. 745 746 return false; 747 } 748 749 /** 750 * Returns the value of the focusableWindowState property. 751 * 752 * @since 1.4 753 */ getFocusableWindowState()754 public boolean getFocusableWindowState () 755 { 756 return focusableWindowState; 757 } 758 759 /** 760 * Sets the value of the focusableWindowState property. 761 * 762 * @since 1.4 763 */ setFocusableWindowState(boolean focusableWindowState)764 public void setFocusableWindowState (boolean focusableWindowState) 765 { 766 this.focusableWindowState = focusableWindowState; 767 } 768 769 // setBoundsCallback is needed so that when a user moves a window, 770 // the Window's location can be updated without calling the peer's 771 // setBounds method. When a user moves a window the peer window's 772 // location is updated automatically and the windowing system sends 773 // a message back to the application informing it of its updated 774 // dimensions. We must update the AWT Window class with these new 775 // dimensions. But we don't want to call the peer's setBounds 776 // method, because the peer's dimensions have already been updated. 777 // (Under X, having this method prevents Configure event loops when 778 // moving windows: Component.setBounds -> peer.setBounds -> 779 // postConfigureEvent -> Component.setBounds -> ... In some cases 780 // Configure event loops cause windows to jitter back and forth 781 // continuously). setBoundsCallback(int x, int y, int w, int h)782 void setBoundsCallback (int x, int y, int w, int h) 783 { 784 if (this.x == x && this.y == y && width == w && height == h) 785 return; 786 invalidate(); 787 this.x = x; 788 this.y = y; 789 width = w; 790 height = h; 791 } 792 } 793