Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [albireo-dev] size and border

Hi Gordon,

On 2008-02-28 you wrote:
> > /**
> >  * Internal class.
> >  * Please don't use this class; use {@link SwingControl} instead.
> >  */
> > 
> > Does this sound acceptable?
> 
> I have no objection to an intermediate class, but I find it a little 
> awkward that SwingControl would inherit from BorderlessSwingControl. If 
> SwingControl can have a border, then it does not have a good 
> object-oriented "kind of" relationship with BorderlessSwingControl. IMO 
> (without seeing the code) it might be better to have an abstract 
> AbstractSwingControl (or BaseSwingControl) containing the shared code, 
> and have BorderlessSwingControl and SwingControl both inherit from it. 
> You could then move BorderlessSwingControl to the .internal package to 
> make it clear that normal users should not subclass it directly.

Your suggestions prompted me to look again at the proposed class hierarchy,
and I could actually get away without an intermediate superclass of
SwingControl. After this cleanup, the code looks quite reasonable.

Committed.

Bruno


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.57
diff -c -3 -r1.57 SwingControl.java
*** src/org/eclipse/albireo/core/SwingControl.java	16 Apr 2008 16:30:32 -0000	1.57
--- src/org/eclipse/albireo/core/SwingControl.java	16 Apr 2008 20:25:56 -0000
***************
*** 69,77 ****
              handleSettingsChange();
          }
      };
!     private Display display;
      private Composite layoutDeferredAncestor;
  
      private Frame frame;
      private RootPaneContainer rootPaneContainer;
      private JComponent swingComponent;
--- 69,84 ----
              handleSettingsChange();
          }
      };
!     final /*private*/ Display display;
      private Composite layoutDeferredAncestor;
  
+     // The width of the border to keep around the embedded AWT frame.
+     private int borderWidth;
+ 
+     // The immediate holder of the embedded AWT frame. It is == this if
+     // borderWidth == 0, or a different Composite if borderWidth != 0.
+     private Composite borderlessChild;
+ 
      private Frame frame;
      private RootPaneContainer rootPaneContainer;
      private JComponent swingComponent;
***************
*** 111,117 ****
       * @see Widget#getStyle
       */
      public SwingControl(Composite parent, int style) {
!         super(parent, style | SWT.EMBEDDED | SWT.NO_BACKGROUND);
          setLayout(new FillLayout());
          display = getDisplay();
  
--- 118,124 ----
       * @see Widget#getStyle
       */
      public SwingControl(Composite parent, int style) {
!         super(parent, style | ((style & SWT.BORDER) == 0 ? SWT.EMBEDDED : 0) | SWT.NO_BACKGROUND);
          setLayout(new FillLayout());
          display = getDisplay();
  
***************
*** 133,138 ****
--- 140,177 ----
                  });
          }
  
+         // Get the width of the border, i.e. the margins of this Composite.
+         // If style contains SWT.BORDER, it is platform dependent (2 pixels on
+         // Linux/gtk); otherwise it must be 0.
+         borderWidth = getBorderWidth();
+         if ((style & SWT.BORDER) != 0) {
+             // Fix for BR #91896
+             // <https://bugs.eclipse.org/bugs/show_bug.cgi?id=91896>:
+             // Since the SWT_AWT.new_Frame creates a low-level connection
+             // between the handle of its argument Composite and the Frame
+             // it creates, and this low-level connection propagates size
+             // from the Composite to the Frame automatically, it ignores
+             // the border. Work around it by creating an intermediate
+             // Composite.
+             borderlessChild =
+                 new Composite(this, (style & ~SWT.BORDER) | SWT.EMBEDDED | SWT.NO_BACKGROUND) {
+                     /**
+                      * Overridden.
+                      */
+                     public Rectangle getClientArea() {
+                         assert Display.getCurrent() != null;     // On SWT event thread
+                         Rectangle rect = super.getClientArea();
+                         SwingControl.this.assignInitialClientArea(rect);
+                         return rect;
+                     }
+                 };
+         } else {
+             // If no border is needed, there is no need to create another
+             // Composite.
+             assert borderWidth == 0;
+             borderlessChild = this;
+         }
+ 
          // Clean up on dispose
          addListener(SWT.Dispose, new Listener() {
              public void handleEvent(Event event) {
***************
*** 142,148 ****
          // This listener clears garbage during resizing, making it look much cleaner. The garbage
          // is due to use of the sun.awt.noerasebackground property, so this is done only under Windows.
          if (Platform.isWin32()) {
!             addControlListener(new CleanResizeListener());
          }
      }
  
--- 181,187 ----
          // This listener clears garbage during resizing, making it look much cleaner. The garbage
          // is due to use of the sun.awt.noerasebackground property, so this is done only under Windows.
          if (Platform.isWin32()) {
!             borderlessChild.addControlListener(new CleanResizeListener());
          }
      }
  
***************
*** 186,192 ****
          // Make sure Awt environment is initialized.
          AwtEnvironment.getInstance(display);
  
!         frame = SWT_AWT.new_Frame(this);
  
          if (verboseSizeLayout)
              ComponentDebugging.addComponentSizeDebugListeners(frame);
--- 225,231 ----
          // Make sure Awt environment is initialized.
          AwtEnvironment.getInstance(display);
  
!         frame = SWT_AWT.new_Frame(borderlessChild);
  
          if (verboseSizeLayout)
              ComponentDebugging.addComponentSizeDebugListeners(frame);
***************
*** 443,448 ****
--- 482,495 ----
      public Rectangle getClientArea() {
          assert Display.getCurrent() != null;     // On SWT event thread
          Rectangle rect = super.getClientArea();
+         if (borderlessChild == this)
+             assignInitialClientArea(rect);
+         return rect;
+     }
+     /**
+      * Invoked from borderlessChild's override of getClientArea().
+      */
+     void assignInitialClientArea(Rectangle rect) {
          if (INITIAL_CLIENT_AREA_WORKAROUND && initialClientArea == null) {
              synchronized (this) {
                  if (cachedSizesInitialized >= 1) {
***************
*** 460,466 ****
                  initialClientArea = rect;
              }
          }
-         return rect;
      }
  
      // We have bidirectional size propagation, from AWT to SWT, and from
--- 507,512 ----
***************
*** 560,567 ****
                              Point minSize = new Point(min.width, min.height);
                              Point prefSize = new Point(pref.width, pref.height);
                              Point maxSize = new Point(max.width, max.height);
!                             preferredSizeChanged(minSize, prefSize, maxSize);
!                             firePreferredSizeChangedEvent(minSize, prefSize, maxSize);
                          } finally {
                              onBehalfAWTTimes.remove(Thread.currentThread());
                          }
--- 606,619 ----
                              Point minSize = new Point(min.width, min.height);
                              Point prefSize = new Point(pref.width, pref.height);
                              Point maxSize = new Point(max.width, max.height);
!                             // Augment the three sizes.
!                             minSize.x += 2*borderWidth;
!                             minSize.y += 2*borderWidth;
!                             prefSize.x += 2*borderWidth;
!                             prefSize.y += 2*borderWidth;
!                             maxSize.x += 2*borderWidth;
!                             maxSize.y += 2*borderWidth;
!                             notePreferredSizeChanged(minSize, prefSize, maxSize);
                          } finally {
                              onBehalfAWTTimes.remove(Thread.currentThread());
                          }
***************
*** 672,678 ****
                  if ((cachedSizesInitialized >= 2) || 
                          (Platform.isGtk() && Platform.JAVA_VERSION < Platform.javaVersion(1, 6, 0)) ||
                          Platform.isWin32()) {
!                     setAWTSize(width, height);
                  }
              }
          }
--- 724,731 ----
                  if ((cachedSizesInitialized >= 2) || 
                          (Platform.isGtk() && Platform.JAVA_VERSION < Platform.javaVersion(1, 6, 0)) ||
                          Platform.isWin32()) {
!                     setAWTSize(Math.max(width-2*borderWidth, 0),
!                                Math.max(height-2*borderWidth, 0));
                  }
              }
          }
***************
*** 699,718 ****
                  System.err.println("SWT thread: Uninitialized AWT sizes for " + swingComponent);
              return super.computeSize(widthHint, heightHint, changed);
          } else {
-             assert cachedSizesInitialized >= 1;
              synchronized (this) {
                  cachedSizesInitialized = 2;
              }
              int width =
                  (widthHint == SWT.DEFAULT ? pref.width :
                   widthHint < min.width ? min.width :
!                      widthHint > max.width ? max.width :
!                          widthHint);
              int height =
                  (heightHint == SWT.DEFAULT ? pref.height :
                   heightHint < min.width ? min.height :
!                      heightHint > max.width ? max.height :
!                          heightHint);
              if (verboseSizeLayout)
                  System.err.println("SWT thread: Computed size: " + width + " x " + height + " for " + swingComponent);
              return new Point(width, height);
--- 752,773 ----
                  System.err.println("SWT thread: Uninitialized AWT sizes for " + swingComponent);
              return super.computeSize(widthHint, heightHint, changed);
          } else {
              synchronized (this) {
+                 assert cachedSizesInitialized >= 1;
                  cachedSizesInitialized = 2;
              }
              int width =
                  (widthHint == SWT.DEFAULT ? pref.width :
                   widthHint < min.width ? min.width :
!                  widthHint > max.width ? max.width :
!                  widthHint)
!                 + 2*borderWidth;
              int height =
                  (heightHint == SWT.DEFAULT ? pref.height :
                   heightHint < min.width ? min.height :
!                  heightHint > max.width ? max.height :
!                  heightHint)
!                 + 2*borderWidth;
              if (verboseSizeLayout)
                  System.err.println("SWT thread: Computed size: " + width + " x " + height + " for " + swingComponent);
              return new Point(width, height);
***************
*** 731,736 ****
--- 786,800 ----
       */
      public abstract Composite getLayoutAncestor();
  
+     /**
+      * Called when the preferred sizes of this control, as computed by
+      * AWT, have changed.
+      */
+     /*private*/ void notePreferredSizeChanged(Point minSize, Point prefSize, Point maxSize) {
+         preferredSizeChanged(minSize, prefSize, maxSize);
+         firePreferredSizeChangedEvent(minSize, prefSize, maxSize);
+     }
+ 
      // TODO: remove this method and just leave the listener for advanced users?
      /**
       * Called when the preferred sizes of this control, as computed by
***************
*** 753,761 ****
       * The parameters <var>minPoint</var>, <var>prefPoint</var>,
       * <var>maxPoint</var> can usually be ignored: It is often enough to rely on the
       * {@link #layout()} method.
!      * @param minSize The new minimum size for this control, as reported by AWT.
!      * @param prefSize The new preferred size for this control, as reported by AWT.
!      * @param maxSize The new maximum size for this control, as reported by AWT.
       */
      protected void preferredSizeChanged(Point minSize, Point prefSize, Point maxSize) {
          Composite ancestor = getLayoutAncestor();
--- 817,828 ----
       * The parameters <var>minPoint</var>, <var>prefPoint</var>,
       * <var>maxPoint</var> can usually be ignored: It is often enough to rely on the
       * {@link #layout()} method.
!      * @param minSize The new minimum size for this control, as reported by
!      *                AWT, plus the border width on each side.
!      * @param prefSize The new preferred size for this control, as reported by
!      *                 AWT, plus the border width on each side.
!      * @param maxSize The new maximum size for this control, as reported by
!      *                AWT, plus the border width on each side.
       */
      protected void preferredSizeChanged(Point minSize, Point prefSize, Point maxSize) {
          Composite ancestor = getLayoutAncestor();
***************
*** 765,771 ****
              // changed. Objects such as org.eclipse.swt.layout.GridData (for
              // GridLayout) cache the last width and height. We must flush this
              // cached geometry.
!             ancestor.layout(new Control[] { this });
          }
      }
  
--- 832,838 ----
              // changed. Objects such as org.eclipse.swt.layout.GridData (for
              // GridLayout) cache the last width and height. We must flush this
              // cached geometry.
!             ancestor.layout(new Control[] { borderlessChild });
          }
      }
  
***************
*** 869,874 ****
--- 936,943 ----
  
      private void handleDispose() {
          focusHandler.dispose();
+         if (borderlessChild != this)
+             borderlessChild.dispose();
          display.removeListener(SWT.Settings, settingsListener);
      }
  


Back to the top