64
65 import sun.lwawt.macosx.CDropTarget;
66
67 import com.sun.java.swing.SwingUtilities3;
68
69 public abstract class LWComponentPeer<T extends Component, D extends JComponent>
70 implements ComponentPeer, DropTargetPeer
71 {
72 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWComponentPeer");
73
74 // State lock is to be used for modifications to this
75 // peer's fields (e.g. bounds, background, font, etc.)
76 // It should be the last lock in the lock chain
77 private final Object stateLock =
78 new StringBuilder("LWComponentPeer.stateLock");
79
80 // The lock to operate with the peers hierarchy. AWT tree
81 // lock is not used as there are many peers related ops
82 // to be done on the toolkit thread, and we don't want to
83 // depend on a public lock on this thread
84 private final static Object peerTreeLock =
85 new StringBuilder("LWComponentPeer.peerTreeLock");
86
87 /**
88 * A custom tree-lock used for the hierarchy of the delegate Swing
89 * components.
90 * The lock synchronizes access to the delegate
91 * internal state. Think of it as a 'virtual EDT'.
92 */
93 // private final Object delegateTreeLock =
94 // new StringBuilder("LWComponentPeer.delegateTreeLock");
95
96 private T target;
97
98 // Container peer. It may not be the peer of the target's direct
99 // parent, for example, in the case of hw/lw mixing. However,
100 // let's skip this scenario for the time being. We also assume
101 // the container peer is not null, which might also be false if
102 // addNotify() is called for a component outside of the hierarchy.
103 // The exception is LWWindowPeers: their parents are always null
104 private LWContainerPeer containerPeer;
105
106 // Handy reference to the top-level window peer. Window peer is
107 // borrowed from the containerPeer in constructor, and should also
108 // be updated when the component is reparented to another container
109 private LWWindowPeer windowPeer;
110
111 private AtomicBoolean disposed = new AtomicBoolean(false);
112
113 // Bounds are relative to parent peer
114 private Rectangle bounds = new Rectangle();
115 private Region region;
116
117 // Component state. Should be accessed under the state lock
118 private boolean visible = false;
119 private boolean enabled = true;
120
121 private Color background;
122 private Color foreground;
123 private Font font;
124
125 // Paint area to coalesce all the paint events and store
126 // the target dirty area
127 private RepaintArea targetPaintArea;
128
129 // private volatile boolean paintPending;
130 private volatile boolean isLayouting;
131
132 private D delegate = null;
133 private Container delegateContainer;
134 private Component delegateDropTarget;
135 private final Object dropTargetLock = new Object();
136
137 private int fNumDropTargets = 0;
138 private CDropTarget fDropTarget = null;
139
140 private PlatformComponent platformComponent;
141
142 private final class DelegateContainer extends Container {
143 {
144 enableEvents(0xFFFFFFFF);
145 }
146
147 DelegateContainer() {
148 super();
149 }
150
151 @Override
152 public boolean isLightweight() {
153 return false;
154 }
155
156 @Override
157 public Point getLocation() {
158 return getLocationOnScreen();
159 }
160
161 @Override
162 public Point getLocationOnScreen() {
163 return LWComponentPeer.this.getLocationOnScreen();
164 }
165
166 @Override
167 public int getX() {
168 return getLocation().x;
169 }
170
171 @Override
172 public int getY() {
173 return getLocation().y;
174 }
175 }
176
177 public LWComponentPeer(T target, PlatformComponent platformComponent) {
178 this.target = target;
179 this.platformComponent = platformComponent;
180
181 initializeContainerPeer();
182 // Container peer is always null for LWWindowPeers, so
183 // windowPeer is always null for them as well. On the other
184 // hand, LWWindowPeer shouldn't use windowPeer at all
185 if (containerPeer != null) {
186 windowPeer = containerPeer.getWindowPeerOrSelf();
187 }
188 // don't bother about z-order here as updateZOrder()
189 // will be called from addNotify() later anyway
190 if (containerPeer != null) {
191 containerPeer.addChildPeer(this);
192 }
193
194 // the delegate must be created after the target is set
195 AWTEventListener toolkitListener = null;
196 synchronized (Toolkit.getDefaultToolkit()) {
197 try {
198 toolkitListener = getToolkitAWTEventListener();
199 setToolkitAWTEventListener(null);
200
201 synchronized (getDelegateLock()) {
202 delegate = createDelegate();
203 if (delegate != null) {
204 delegateContainer = new DelegateContainer();
205 delegateContainer.add(delegate);
206 delegateContainer.addNotify();
207 delegate.addNotify();
208 } else {
209 return;
210 }
211 }
212
213 } finally {
214 setToolkitAWTEventListener(toolkitListener);
215 }
216
217 // todo swing: later on we will probably have one global RM
218 SwingUtilities3.setDelegateRepaintManager(delegate, new RepaintManager() {
219 @Override
220 public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {
221 repaintPeer(SwingUtilities.convertRectangle(
222 c, new Rectangle(x, y, w, h), getDelegate()));
223 }
224 });
225 }
226 }
227
261 }
262
263 /**
264 * This method is called under getDelegateLock().
265 * Overridden in subclasses.
266 */
267 protected D createDelegate() {
268 return null;
269 }
270
271 protected final D getDelegate() {
272 synchronized (getStateLock()) {
273 return delegate;
274 }
275 }
276
277 protected Component getDelegateFocusOwner() {
278 return getDelegate();
279 }
280
281 /*
282 * Initializes this peer by fetching all the properties from the target.
283 * The call to initialize() is not placed to LWComponentPeer ctor to
284 * let the subclass ctor to finish completely first. Instead, it's the
285 * LWToolkit object who is responsible for initialization.
286 */
287 public void initialize() {
288 platformComponent.initialize(target, this, getPlatformWindow());
289 targetPaintArea = new LWRepaintArea();
290 if (getDelegate() != null) {
291 synchronized (getDelegateLock()) {
292 resetColorsAndFont(delegate);
293 getDelegate().setOpaque(true);
294 }
295 }
296 setBackground(target.getBackground());
297 setForeground(target.getForeground());
298 setFont(target.getFont());
299 setBounds(target.getBounds());
300 setEnabled(target.isEnabled());
301 setVisible(target.isVisible());
302 }
303
304 private static void resetColorsAndFont(final Container c) {
305 c.setBackground(null);
306 c.setForeground(null);
307 c.setFont(null);
308 for (int i = 0; i < c.getComponentCount(); i++) {
309 resetColorsAndFont((Container) c.getComponent(i));
310 }
311 }
312
313 final Object getStateLock() {
314 return stateLock;
315 }
316
317 // Synchronize all operations with the Swing delegates under
318 // AWT tree lock, using a new separate lock to synchronize
319 // access to delegates may lead deadlocks
320 final Object getDelegateLock() {
321 //return delegateTreeLock;
322 return getTarget().getTreeLock();
323 }
324
325 protected final static Object getPeerTreeLock() {
326 return peerTreeLock;
327 }
328
329 final T getTarget() {
330 return target;
331 }
332
333 // Just a helper method
334 // Returns the window peer or null if this is a window peer
335 protected final LWWindowPeer getWindowPeer() {
336 return windowPeer;
337 }
338
339 // Returns the window peer or 'this' if this is a window peer
340 protected LWWindowPeer getWindowPeerOrSelf() {
341 return getWindowPeer();
342 }
343
344 // Just a helper method
345 protected final LWContainerPeer getContainerPeer() {
741
742 final D delegate = getDelegate();
743
744 if (delegate != null) {
745 synchronized (getDelegateLock()) {
746 delegate.setEnabled(status);
747 }
748 } else {
749 repaintPeer();
750 }
751 }
752
753 // Helper method
754 public final boolean isEnabled() {
755 synchronized (getStateLock()) {
756 return enabled;
757 }
758 }
759
760 @Override
761 public void setVisible(boolean v) {
762 synchronized (getStateLock()) {
763 if (visible == v) {
764 return;
765 }
766 visible = v;
767 }
768
769 final D delegate = getDelegate();
770
771 if (delegate != null) {
772 synchronized (getDelegateLock()) {
773 delegate.setVisible(v);
774 }
775 }
776 if (visible) {
777 repaintPeer();
778 } else {
779 repaintParent(getBounds());
780 }
781 }
782
783 // Helper method
784 public final boolean isVisible() {
785 synchronized (getStateLock()) {
786 return visible;
787 }
788 }
1338 public final void repaintPeer() {
1339 repaintPeer(getSize());
1340 }
1341
1342 public void repaintPeer(final Rectangle r) {
1343 final Rectangle toPaint = getSize().intersection(r);
1344 if (!isShowing() || toPaint.isEmpty()) {
1345 return;
1346 }
1347
1348 postPaintEvent(toPaint.x, toPaint.y, toPaint.width, toPaint.height);
1349 }
1350
1351 /**
1352 * Determines whether this peer is showing on screen. This means that the
1353 * peer must be visible, and it must be in a container that is visible and
1354 * showing.
1355 *
1356 * @see #isVisible()
1357 */
1358 protected boolean isShowing() {
1359 synchronized (getPeerTreeLock()) {
1360 if (isVisible()) {
1361 final LWContainerPeer container = getContainerPeer();
1362 return (container == null) || container.isShowing();
1363 }
1364 }
1365 return false;
1366 }
1367
1368 /**
1369 * Paints the peer. Overridden in subclasses to delegate the actual painting
1370 * to Swing components.
1371 */
1372 protected final void paintPeer(final Graphics g) {
1373 final D delegate = getDelegate();
1374 if (delegate != null) {
1375 if (!SwingUtilities.isEventDispatchThread()) {
1376 throw new InternalError("Painting must be done on EDT");
1377 }
1378 synchronized (getDelegateLock()) {
|
64
65 import sun.lwawt.macosx.CDropTarget;
66
67 import com.sun.java.swing.SwingUtilities3;
68
69 public abstract class LWComponentPeer<T extends Component, D extends JComponent>
70 implements ComponentPeer, DropTargetPeer
71 {
72 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWComponentPeer");
73
74 // State lock is to be used for modifications to this
75 // peer's fields (e.g. bounds, background, font, etc.)
76 // It should be the last lock in the lock chain
77 private final Object stateLock =
78 new StringBuilder("LWComponentPeer.stateLock");
79
80 // The lock to operate with the peers hierarchy. AWT tree
81 // lock is not used as there are many peers related ops
82 // to be done on the toolkit thread, and we don't want to
83 // depend on a public lock on this thread
84 private static final Object peerTreeLock =
85 new StringBuilder("LWComponentPeer.peerTreeLock");
86
87 private final T target;
88
89 // Container peer. It may not be the peer of the target's direct
90 // parent, for example, in the case of hw/lw mixing. However,
91 // let's skip this scenario for the time being. We also assume
92 // the container peer is not null, which might also be false if
93 // addNotify() is called for a component outside of the hierarchy.
94 // The exception is LWWindowPeers: their parents are always null
95 private LWContainerPeer containerPeer;
96
97 // Handy reference to the top-level window peer. Window peer is
98 // borrowed from the containerPeer in constructor, and should also
99 // be updated when the component is reparented to another container
100 private LWWindowPeer windowPeer;
101
102 private final AtomicBoolean disposed = new AtomicBoolean(false);
103
104 // Bounds are relative to parent peer
105 private final Rectangle bounds = new Rectangle();
106 private Region region;
107
108 // Component state. Should be accessed under the state lock
109 private boolean visible = false;
110 private boolean enabled = true;
111
112 private Color background;
113 private Color foreground;
114 private Font font;
115
116 /**
117 * Paint area to coalesce all the paint events and store the target dirty
118 * area.
119 */
120 private final RepaintArea targetPaintArea;
121
122 // private volatile boolean paintPending;
123 private volatile boolean isLayouting;
124
125 private D delegate = null;
126 private Container delegateContainer;
127 private Component delegateDropTarget;
128 private final Object dropTargetLock = new Object();
129
130 private int fNumDropTargets = 0;
131 private CDropTarget fDropTarget = null;
132
133 private final PlatformComponent platformComponent;
134
135 private final class DelegateContainer extends Container {
136 {
137 enableEvents(0xFFFFFFFF);
138 }
139
140 DelegateContainer() {
141 super();
142 }
143
144 @Override
145 public boolean isLightweight() {
146 return false;
147 }
148
149 @Override
150 public Point getLocation() {
151 return getLocationOnScreen();
152 }
153
154 @Override
155 public Point getLocationOnScreen() {
156 return LWComponentPeer.this.getLocationOnScreen();
157 }
158
159 @Override
160 public int getX() {
161 return getLocation().x;
162 }
163
164 @Override
165 public int getY() {
166 return getLocation().y;
167 }
168 }
169
170 public LWComponentPeer(T target, PlatformComponent platformComponent) {
171 targetPaintArea = new LWRepaintArea();
172 this.target = target;
173 this.platformComponent = platformComponent;
174
175 initializeContainerPeer();
176 // Container peer is always null for LWWindowPeers, so
177 // windowPeer is always null for them as well. On the other
178 // hand, LWWindowPeer shouldn't use windowPeer at all
179 if (containerPeer != null) {
180 windowPeer = containerPeer.getWindowPeerOrSelf();
181 }
182 // don't bother about z-order here as updateZOrder()
183 // will be called from addNotify() later anyway
184 if (containerPeer != null) {
185 containerPeer.addChildPeer(this);
186 }
187
188 // the delegate must be created after the target is set
189 AWTEventListener toolkitListener = null;
190 synchronized (Toolkit.getDefaultToolkit()) {
191 try {
192 toolkitListener = getToolkitAWTEventListener();
193 setToolkitAWTEventListener(null);
194
195 synchronized (getDelegateLock()) {
196 delegate = createDelegate();
197 if (delegate != null) {
198 delegate.setVisible(false);
199 delegateContainer = new DelegateContainer();
200 delegateContainer.add(delegate);
201 delegateContainer.addNotify();
202 delegate.addNotify();
203 resetColorsAndFont(delegate);
204 delegate.setOpaque(true);
205 } else {
206 return;
207 }
208 }
209
210 } finally {
211 setToolkitAWTEventListener(toolkitListener);
212 }
213
214 // todo swing: later on we will probably have one global RM
215 SwingUtilities3.setDelegateRepaintManager(delegate, new RepaintManager() {
216 @Override
217 public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {
218 repaintPeer(SwingUtilities.convertRectangle(
219 c, new Rectangle(x, y, w, h), getDelegate()));
220 }
221 });
222 }
223 }
224
258 }
259
260 /**
261 * This method is called under getDelegateLock().
262 * Overridden in subclasses.
263 */
264 protected D createDelegate() {
265 return null;
266 }
267
268 protected final D getDelegate() {
269 synchronized (getStateLock()) {
270 return delegate;
271 }
272 }
273
274 protected Component getDelegateFocusOwner() {
275 return getDelegate();
276 }
277
278 /**
279 * Initializes this peer. The call to initialize() is not placed to
280 * LWComponentPeer ctor to let the subclass ctor to finish completely first.
281 * Instead, it's the LWToolkit object who is responsible for initialization.
282 * Note that we call setVisible() at the end of initialization.
283 */
284 public final void initialize() {
285 platformComponent.initialize(target, this, getPlatformWindow());
286 initializeImpl();
287 setVisible(target.isVisible());
288 }
289
290 /**
291 * Fetching general properties from the target. Should be overridden in
292 * subclasses to initialize specific peers properties.
293 */
294 void initializeImpl() {
295 setBackground(target.getBackground());
296 setForeground(target.getForeground());
297 setFont(target.getFont());
298 setBounds(target.getBounds());
299 setEnabled(target.isEnabled());
300 }
301
302 private static void resetColorsAndFont(final Container c) {
303 c.setBackground(null);
304 c.setForeground(null);
305 c.setFont(null);
306 for (int i = 0; i < c.getComponentCount(); i++) {
307 resetColorsAndFont((Container) c.getComponent(i));
308 }
309 }
310
311 final Object getStateLock() {
312 return stateLock;
313 }
314
315 /**
316 * Synchronize all operations with the Swing delegates under AWT tree lock,
317 * using a new separate lock to synchronize access to delegates may lead
318 * deadlocks. Think of it as a 'virtual EDT'.
319 *
320 * @return DelegateLock
321 */
322 final Object getDelegateLock() {
323 return getTarget().getTreeLock();
324 }
325
326 protected static final Object getPeerTreeLock() {
327 return peerTreeLock;
328 }
329
330 final T getTarget() {
331 return target;
332 }
333
334 // Just a helper method
335 // Returns the window peer or null if this is a window peer
336 protected final LWWindowPeer getWindowPeer() {
337 return windowPeer;
338 }
339
340 // Returns the window peer or 'this' if this is a window peer
341 protected LWWindowPeer getWindowPeerOrSelf() {
342 return getWindowPeer();
343 }
344
345 // Just a helper method
346 protected final LWContainerPeer getContainerPeer() {
742
743 final D delegate = getDelegate();
744
745 if (delegate != null) {
746 synchronized (getDelegateLock()) {
747 delegate.setEnabled(status);
748 }
749 } else {
750 repaintPeer();
751 }
752 }
753
754 // Helper method
755 public final boolean isEnabled() {
756 synchronized (getStateLock()) {
757 return enabled;
758 }
759 }
760
761 @Override
762 public void setVisible(final boolean v) {
763 synchronized (getStateLock()) {
764 if (visible == v) {
765 return;
766 }
767 visible = v;
768 }
769 setVisibleImpl(v);
770 }
771
772 protected void setVisibleImpl(final boolean v) {
773 final D delegate = getDelegate();
774
775 if (delegate != null) {
776 synchronized (getDelegateLock()) {
777 delegate.setVisible(v);
778 }
779 }
780 if (visible) {
781 repaintPeer();
782 } else {
783 repaintParent(getBounds());
784 }
785 }
786
787 // Helper method
788 public final boolean isVisible() {
789 synchronized (getStateLock()) {
790 return visible;
791 }
792 }
1342 public final void repaintPeer() {
1343 repaintPeer(getSize());
1344 }
1345
1346 public void repaintPeer(final Rectangle r) {
1347 final Rectangle toPaint = getSize().intersection(r);
1348 if (!isShowing() || toPaint.isEmpty()) {
1349 return;
1350 }
1351
1352 postPaintEvent(toPaint.x, toPaint.y, toPaint.width, toPaint.height);
1353 }
1354
1355 /**
1356 * Determines whether this peer is showing on screen. This means that the
1357 * peer must be visible, and it must be in a container that is visible and
1358 * showing.
1359 *
1360 * @see #isVisible()
1361 */
1362 protected final boolean isShowing() {
1363 synchronized (getPeerTreeLock()) {
1364 if (isVisible()) {
1365 final LWContainerPeer container = getContainerPeer();
1366 return (container == null) || container.isShowing();
1367 }
1368 }
1369 return false;
1370 }
1371
1372 /**
1373 * Paints the peer. Overridden in subclasses to delegate the actual painting
1374 * to Swing components.
1375 */
1376 protected final void paintPeer(final Graphics g) {
1377 final D delegate = getDelegate();
1378 if (delegate != null) {
1379 if (!SwingUtilities.isEventDispatchThread()) {
1380 throw new InternalError("Painting must be done on EDT");
1381 }
1382 synchronized (getDelegateLock()) {
|