[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [albireo-dev] Updated RelayoutExampleView
|
Gordon Hirsch wrote:
> There's some odd behavior with the new example that needs some
> investigation. Not sure if it is a bug in the example, strange SWT
> behavior, or a bug in albireo.
>
> For example, growing both controls at once is not always as symmetrical
> as I would have expected.
While thinking about this issue, I also noticed a thinko regarding the
inhibitSizePropagationToAWT mechanism. Namely, it did not consider the
case that an SWT layout operation, on behalf of a SwingControl, could
set the size of other SwingControl. But this is precisely what happens in
the new RelayoutExampleView.
The fix is to generalize inhibitSizePropagationToAWT as follows.
Index: src/org/eclipse/albireo/core/SwingControl.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/SwingControl.java,v
retrieving revision 1.39
diff -c -3 -r1.39 SwingControl.java
*** src/org/eclipse/albireo/core/SwingControl.java 25 Feb 2008 19:33:47 -0000 1.39
--- src/org/eclipse/albireo/core/SwingControl.java 25 Feb 2008 20:07:37 -0000
***************
*** 17,24 ****
--- 17,27 ----
import java.awt.Frame;
import java.awt.Toolkit;
import java.util.ArrayList;
+ import java.util.Collections;
+ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+ import java.util.Map;
import javax.swing.JApplet;
import javax.swing.JComponent;
***************
*** 435,443 ****
// We have bidirectional size propagation, from AWT to SWT, and from
// SWT to AWT. To avoid endless recursion in weird cases (for example,
// when the AWT component refuses to accept the size that the SWT
! // component assigns it), this variable is used. It is accessed only
! // from the SWT event thread.
! boolean inhibitSizePropagationToAWT = false;
/**
* Given the minimum, preferred, and maximum sizes of the Swing
--- 438,485 ----
// We have bidirectional size propagation, from AWT to SWT, and from
// SWT to AWT. To avoid endless recursion in weird cases (for example,
// when the AWT component refuses to accept the size that the SWT
! // component assigns it), we inhibit propagation in this situation:
! // AWT rootpane.validate() ---> SWT layout() -|-> AWT frame.setBounds.
! //
! // When more than one SwingControl is involved, the situation is more
! // complicated:
! // AWT rootpane1.validate() ---> SWT layout() -|-> AWT frame1.setBounds.
! // ---> AWT frame2.setBounds.
! // The notification from SWT to the AWT frame that triggered the layout is
! // inhibited. The notification from SWT to another AWT frame frame2 is
! // passed through, however - except if frame2 has been validated since
! // then. In the latter case, the SWT layout potentially used outdated
! // sizes from frame2; it *must*not* clobber the new size of frame2.
! //
! // In order to determine the "since then", we need a clock that runs in the
! // AWT thread.
!
! /**
! * The current "time" of the AWT thread. It is incremented when any
! * SwingControl is validated. It's an integer modulo 2^32 (wraps around).
! * Accessed only from the AWT thread. Therefore copies of this integer
! * have to be compared with <code>a - b < 0</code> rather than
! * <code>a < b</code>.
! */
! private static int currentAWTTime;
!
! /**
! * The time at which this component's JRootPane was last validated.
! * Accessed from the AWT thread and the SWT thread, therefore 'volatile'
! * (could also be protected by a lock).
! */
! volatile int lastValidatedAWTTime;
!
! /**
! * When running in the SWT thread on behalf of a notification from the AWT
! * thread, this variable keeps track of the AWT-time that was in effect
! * when this notification was sent.
! * The map key is an SWT thread, belonging to a Display. There can be
! * several of them, therefore a Map.
! * Accessed only from the SWT thread(s).
! */
! static Map /*<Thread,Integer>*/ onBehalfAWTTimes =
! Collections.synchronizedMap(new HashMap /*<Thread,Integer>*/ ());
/**
* Given the minimum, preferred, and maximum sizes of the Swing
***************
*** 448,453 ****
--- 490,499 ----
assert EventQueue.isDispatchThread(); // On AWT event thread
if (verboseSizeLayout)
System.err.println("AWT thread: updated component sizes: " + min + " <= " + pref + " <= " + max);
+
+ // Increment and memoize the current AWT time.
+ lastValidatedAWTTime = ++currentAWTTime;
+
boolean mustNotify;
synchronized (this) {
***************
*** 476,495 ****
// Preferred (and min/max) sizes are available for the AWT
// component for the first time. Layout the composite so that those
// sizes can be taken into account.
ThreadingHandler.getInstance().asyncExec(display, new Runnable() {
public void run() {
if (verboseSizeLayout)
System.err.println("AWT->SWT thread: Laying out after size update");
if (!isDisposed()) {
try {
! inhibitSizePropagationToAWT = true;
Point minPoint = new Point(min.width, min.height);
Point prefPoint = new Point(pref.width, pref.height);
Point maxPoint = new Point(max.width, max.height);
preferredSizeChanged(minPoint, prefPoint, maxPoint);
firePreferredSizeChangedEvent(minPoint, prefPoint, maxPoint);
} finally {
! inhibitSizePropagationToAWT = false;
}
}
}
--- 522,542 ----
// Preferred (and min/max) sizes are available for the AWT
// component for the first time. Layout the composite so that those
// sizes can be taken into account.
+ final int onBehalfAWTTime = lastValidatedAWTTime;
ThreadingHandler.getInstance().asyncExec(display, new Runnable() {
public void run() {
if (verboseSizeLayout)
System.err.println("AWT->SWT thread: Laying out after size update");
if (!isDisposed()) {
try {
! onBehalfAWTTimes.put(Thread.currentThread(), new Integer(onBehalfAWTTime));
Point minPoint = new Point(min.width, min.height);
Point prefPoint = new Point(pref.width, pref.height);
Point maxPoint = new Point(max.width, max.height);
preferredSizeChanged(minPoint, prefPoint, maxPoint);
firePreferredSizeChangedEvent(minPoint, prefPoint, maxPoint);
} finally {
! onBehalfAWTTimes.remove(Thread.currentThread());
}
}
}
***************
*** 523,539 ****
assert Display.getCurrent() != null; // On SWT event thread
if (verboseSizeLayout)
System.err.println("SWT thread: Preparing to set size: " + width + " x " + height + " for " + swingComponent);
! EventQueue.invokeLater(
! new Runnable() {
! public void run() {
! if (verboseSizeLayout)
! System.err.println("SWT->AWT thread: Setting size: " + width + " x " + height + " for " + swingComponent);
! if (frame != null) {
! frame.setBounds(0, 0, Math.max(width, 0), Math.max(height, 0));
! frame.validate();
}
! }
! });
}
/**
--- 570,601 ----
assert Display.getCurrent() != null; // On SWT event thread
if (verboseSizeLayout)
System.err.println("SWT thread: Preparing to set size: " + width + " x " + height + " for " + swingComponent);
! // Get the AWT time of the notification that triggered this processing.
! final Integer onBehalfAWTTime = (Integer)onBehalfAWTTimes.get(Thread.currentThread());
! // Shortcut to post a Runnable that has no effect.
! // (lastValidatedAWTTime can only increase until the Runnable is
! // actually run.)
! if (onBehalfAWTTime == null
! || lastValidatedAWTTime - onBehalfAWTTime.intValue() < 0) {
! // Switch to the AWT thread.
! EventQueue.invokeLater(
! new Runnable() {
! public void run() {
! // Compare the AWT time of the notification with the
! // time at which the rootpane was last validated.
! if (onBehalfAWTTime == null
! || lastValidatedAWTTime - onBehalfAWTTime.intValue() < 0) {
! // Set the frame's (and thus also the rootpane's) size.
! if (verboseSizeLayout)
! System.err.println("SWT->AWT thread: Setting size: " + width + " x " + height + " for " + swingComponent);
! if (frame != null) {
! frame.setBounds(0, 0, Math.max(width, 0), Math.max(height, 0));
! frame.validate();
! }
! }
}
! });
! }
}
/**
***************
*** 564,572 ****
if ((cachedSizesInitialized >= 2) ||
(Platform.isGtk() && Platform.JAVA_VERSION < Platform.javaVersion(1, 6, 0)) ||
(Platform.isWin32() && Platform.SWT_VERSION < Platform.SWT_34)) {
! if (!inhibitSizePropagationToAWT) {
! setAWTSize(width, height);
! }
}
}
}
--- 626,632 ----
if ((cachedSizesInitialized >= 2) ||
(Platform.isGtk() && Platform.JAVA_VERSION < Platform.javaVersion(1, 6, 0)) ||
(Platform.isWin32() && Platform.SWT_VERSION < Platform.SWT_34)) {
! setAWTSize(width, height);
}
}
}