JDK-6783411 : Reparenting HW components to another toplevel should not destroy their peer
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Future Project
  • OS: generic
  • CPU: generic
  • Submitted: 2008-12-10
  • Updated: 2011-04-28
  • Resolved: 2009-10-06
Related Reports
Relates :  
Relates :  
Relates :  
When a hw component is reparented to another container, its peer usually gets recreated (via removeNotify() and subsequent call to addNotify()). Sometimes it does not happen if the native system allows reparenting w/o destroying the native window object. This even got eased with the fix for 6552803.

All this works quite fine now unless we try reparenting the hw component to another top-level window. Theoretically the native system does not put a constraint on this operation. However from the Java's point of view there's such property like the GraphicsConfiguration/GraphicsDevice for any hw component. Different application windows can obviously be located on different screens in a multi-screen environments, hence to move a hw component from one top-level window to another, we would need to change its graphics configuration. The current code does not provide such functionality, and hence the change request.

EVALUATION Swing heavily over-uses the overridden add/removeNotify() methods. While this might not be correct in all cases (because, say, using the HierarchyListener looks sufficient for that purposes), implementing the solution may require rewritting some Swing code, and doing some testing. This looks somewhat risky. On the other hand, implementing a simlified solution (that would not destroy the peer of a directly reparented HW component only) does not seem very helpful from Swing applications developer perspective: it would be more useful to be able to reparent a lightweight sub-tree instead (like a RootPane, or whatever.) In the meantime, I'm deferring this change request for the future. Perhaps we'll come up with a better idea of a fix, or stronger justification for that change.

EVALUATION In order to preserve backward compatibility, we might want to allow skipping the removeNotify()/addNotify() calls only when a HW component itself gets reparented to another top-level via the addImpl() or setComponentZOrder() methods. If a LW hierarchy gets reparented, we still need to call removeNotify() (which will recursively invoke the removeNotify() on HW components contained within the LW hierarchy).

EVALUATION For X11 systems it is also needed to have the CR 6812298 fixed so that the Visual is correctly updated when a component changes its GC.

EVALUATION We should also handle focus issues correctly. In order to give the developer more freedom, the focus should not follow the component when it gets reparented to another top-level window even if the peer is not recreated. This means we should reset the GlobalPermanentFocusOwner and invoke the transferFocus(true) method just before removeing a focused component from its container.

EVALUATION In case of multi-screen environments it has been noticed that X11 does not allow to reparent windows between diffirent screens (see the documentation of XReparentWindow()). However MS Windows does allow to do so. Since there's no specification when an exception should be thrown by add() or setComponentZOrder(), we may implement a platform-dependent behavior. Note that previously the exception would be thrown on any platform when one tried reparenting a component to a container belonging to a different GraphicsDevice (see Component.checkGD() and Container.checkGD() methods). The proposed fix changes the method name to isDisplayChangedNeeded() which returns a boolean value indicating if the peer.displayChanged() should be invoked on the components being added to a container. Also this method may still throw an exception (as the current checkGD() methods do). We should also ensure that the whole hierarchy of components in a particular toplevel window shares the same GraphicsConfiguration object at every moment of time. For that purpose the field Component.graphicsConfig should be made private. It should only be updated whenever the Window the component belongs to changes its GC. This is implementatble via the sun.awt.AWTAccessor machinery.

EVALUATION Whenever a hw component gets moved to another toplevel, we need to invoke its peer.displayChanged() method to correctly update the graphics configuration of this component.