Hi Tom,

On Wed, 2006-03-29 at 10:39 -0500, Thomas Fitzsimmons wrote:
> Calling setLocation from postConfigureEvent is
> extremely fragile because it causes a call back into the peer's
> setBounds, which can cause another configure event.  Previously the
> second configure event would have slightly different coordinates and so
> would cause another call to postConfigureEvent, leading to the "ghost
> dragger" effect.  This loop could probably be broken by using
> ComponentEvents as you suggest.  Care to test that approach to see how
> robust/performant it is?

OK, here it is. I need to test it some more, clean it up and write a
proper ChangeLog entry. But it seems robust and to perform OK. At least
not worse then what we currently have. It also cleans up the code a bit
(imho). If you could take a look and/or try it out on something nasty
that would be appreciated.

Thanks,

Mark
Index: gnu/java/awt/peer/gtk/GtkFramePeer.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java,v
retrieving revision 1.45
diff -u -r1.45 GtkFramePeer.java
--- gnu/java/awt/peer/gtk/GtkFramePeer.java	16 Mar 2006 03:24:18 -0000	1.45
+++ gnu/java/awt/peer/gtk/GtkFramePeer.java	29 Mar 2006 21:37:12 -0000
@@ -1,5 +1,5 @@
 /* GtkFramePeer.java -- Implements FramePeer with GTK
-   Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2002, 2004, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -122,25 +122,11 @@
 
   public void setBounds (int x, int y, int width, int height)
   {
-    // prevent window_configure_cb -> awtComponent.setSize ->
-    // peer.setBounds -> nativeSetBounds self-deadlock on GDK lock.
-    if (Thread.currentThread() == GtkToolkit.mainThread)
-      {
-        int menuBarWidth = width - insets.left - insets.right;
-        if (menuBar != null && menuBarWidth > 0)
-          setMenuBarWidthUnlocked (menuBar, menuBarWidth);
-
-        return;
-      }
-
     int menuBarWidth = width - insets.left - insets.right;
     if (menuBar != null && menuBarWidth > 0)
       setMenuBarWidth (menuBar, menuBarWidth);
 
-    nativeSetBounds (x, y,
-		     width - insets.left - insets.right,
-		     height - insets.top - insets.bottom
-		     + menuBarHeight);
+    super.setBounds(x, y, width, height + menuBarHeight);
   }  
   
   public void setResizable (boolean resizable)
@@ -198,26 +184,16 @@
 
   protected void postConfigureEvent (int x, int y, int width, int height)
   {
-    int frame_width = width + insets.left + insets.right;
     // Since insets.top already includes the MenuBar's height, we need
     // to subtract the MenuBar's height from the top inset.
-    int frame_height = height + insets.top + insets.bottom - menuBarHeight;
+    int frame_height = height - menuBarHeight;
 
-    if (frame_width != awtComponent.getWidth()
-        || frame_height != awtComponent.getHeight())
-      awtComponent.setSize(frame_width, frame_height);
-
-    int frame_x = x - insets.left;
     // Likewise, since insets.top includes the MenuBar height, we need
     // to add back the MenuBar height to the frame's y position.  If
     // no MenuBar exists in this frame, the MenuBar height will be 0.
-    int frame_y = y - insets.top + menuBarHeight;
+    int frame_y = y + menuBarHeight;
 
-    if (frame_x != awtComponent.getX()
-        || frame_y != awtComponent.getY())
-      {
-        // awtComponent.setLocation(frame_x, frame_y);
-      }
+    super.postConfigureEvent(x, frame_y, width, frame_height);
   }
 
   public int getState ()
Index: gnu/java/awt/peer/gtk/GtkWindowPeer.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java,v
retrieving revision 1.47
diff -u -r1.47 GtkWindowPeer.java
--- gnu/java/awt/peer/gtk/GtkWindowPeer.java	16 Mar 2006 03:24:18 -0000	1.47
+++ gnu/java/awt/peer/gtk/GtkWindowPeer.java	29 Mar 2006 21:37:12 -0000
@@ -1,5 +1,5 @@
 /* GtkWindowPeer.java -- Implements WindowPeer with GTK
-   Copyright (C) 1998, 1999, 2002, 2005  Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2002, 2005, 2006  Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -44,6 +44,7 @@
 import java.awt.Graphics;
 import java.awt.Rectangle;
 import java.awt.Window;
+import java.awt.event.ComponentEvent;
 import java.awt.event.PaintEvent;
 import java.awt.event.WindowEvent;
 import java.awt.peer.WindowPeer;
@@ -63,20 +64,37 @@
   private boolean hasBeenShown = false;
   private int oldState = Frame.NORMAL;
 
+  // Cached awt window component location, width and height.
+  private int x, y, width, height;
+
   native void gtkWindowSetTitle (String title);
   native void gtkWindowSetResizable (boolean resizable);
   native void gtkWindowSetModal (boolean modal);
 
   native void realize ();
 
+  /** Returns the cached width of the AWT window component. */
+  int getX ()
+  {
+    return x;
+  }
+
+  /** Returns the cached width of the AWT window component. */
+  int getY ()
+  {
+    return y;
+  }
+
+  /** Returns the cached width of the AWT window component. */
   int getWidth ()
   {
-    return awtComponent.getWidth();
+    return width;
   }
 
+  /** Returns the cached height of the AWT window component. */
   int getHeight ()
   {
-    return awtComponent.getHeight();
+    return height;
   }
 
   native void create (int type, boolean decorated, GtkWindowPeer parent);
@@ -86,6 +104,10 @@
     Window window = (Window) awtComponent;
     GtkWindowPeer parent_peer = null;
     Component parent = awtComponent.getParent();
+    x = awtComponent.getX();
+    y = awtComponent.getY();
+    height = awtComponent.getHeight();
+    width = awtComponent.getWidth();
     
     if (!window.isFocusableWindow())
       type = GDK_WINDOW_TYPE_HINT_MENU;
@@ -130,37 +152,28 @@
   native void nativeSetLocation (int x, int y);
   native void nativeSetLocationUnlocked (int x, int y);
 
-  public void setLocation (int x, int y)
+  // Called from show.
+  protected void setLocation (int x, int y)
   {
-    // prevent window_configure_cb -> awtComponent.setSize ->
-    // peer.setBounds -> nativeSetBounds self-deadlock on GDK lock.
-    if (Thread.currentThread() == GtkToolkit.mainThread)
-      return;
     nativeSetLocation (x, y);
   }
 
-  public void setLocationUnlocked (int x, int y)
-  {
-    nativeSetLocationUnlocked (x, y);
-  }
-  
   public void setBounds (int x, int y, int width, int height)
   {
-    // prevent window_configure_cb -> awtComponent.setSize ->
-    // peer.setBounds -> nativeSetBounds self-deadlock on GDK lock.
-    if (Thread.currentThread() == GtkToolkit.mainThread)
-      return;
-
-    nativeSetBounds (x, y,
-		     width - insets.left - insets.right,
-		     height - insets.top - insets.bottom);
-  }
-
-  public void setBoundsUnlocked (int x, int y, int width, int height)
-  {
-    nativeSetBoundsUnlocked (x, y,
-                             width - insets.left - insets.right,
-                             height - insets.top - insets.bottom);
+    if (x != getX()
+	|| y != getY()
+	|| width != getWidth()
+	|| height != getHeight())
+      {
+	this.x = x;
+	this.y = y;
+	this.width = width;
+	this.height = height;
+	
+	nativeSetBounds (x, y,
+			 width - insets.left - insets.right,
+			 height - insets.top - insets.bottom);
+      }
   }
 
   public void setTitle (String title)
@@ -168,15 +181,25 @@
     gtkWindowSetTitle (title);
   }
 
-  native void setSize (int width, int height);
-
+  // Called from setResizable
+  protected native void setSize (int width, int height);
+  
+  /**
+   * Needed by both GtkFramePeer and GtkDialogPeer subclasses, so
+   * implemented here. But never actually called on a GtkWindowPeer
+   * itself.
+   */
   public void setResizable (boolean resizable)
   {
     // Call setSize; otherwise when resizable is changed from true to
     // false the window will shrink to the dimensions it had before it
     // was resizable.
-    setSize (awtComponent.getWidth() - insets.left - insets.right,
-	     awtComponent.getHeight() - insets.top - insets.bottom);
+    x = awtComponent.getX();
+    y = awtComponent.getY();
+    width = awtComponent.getWidth();
+    height = awtComponent.getHeight();
+    setSize (width - insets.left - insets.right,
+	     height - insets.top - insets.bottom);
     gtkWindowSetResizable (resizable);
   }
 
@@ -196,22 +219,32 @@
     int frame_width = width + insets.left + insets.right;
     int frame_height = height + insets.top + insets.bottom;
 
-    if (frame_width != awtComponent.getWidth()
-	|| frame_height != awtComponent.getHeight())
-      awtComponent.setSize(frame_width, frame_height);
+    if (frame_width != getWidth()
+	|| frame_height != getHeight())
+      {
+	this.width = frame_width;
+	this.height = frame_height;
+	q().postEvent(new ComponentEvent(awtComponent,
+					 ComponentEvent.COMPONENT_RESIZED));
+      }
 
     int frame_x = x - insets.left;
     int frame_y = y - insets.top;
 
-    if (frame_x != awtComponent.getX()
-	|| frame_y != awtComponent.getY())
+    if (frame_x != getX()
+	|| frame_y != getY())
       {
-        // awtComponent.setLocation(frame_x, frame_y);
+	this.x = frame_x;
+	this.y = frame_y;
+	q().postEvent(new ComponentEvent(awtComponent,
+					 ComponentEvent.COMPONENT_MOVED));
       }
   }
 
   public void show ()
   {
+    width = awtComponent.getWidth();
+    height = awtComponent.getHeight();
     setLocation(awtComponent.getX(), awtComponent.getY());
     setVisible (true);
   }
@@ -296,4 +329,11 @@
 			  x + insets.left, y + insets.top, 
 			  clickCount, popupTrigger);
   }
+
+  // We override this to keep it in sync with our internal
+  // representation.
+  public Rectangle getBounds()
+  {
+    return new Rectangle(x, y, width, height);
+  }
 }
Index: java/awt/Window.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/awt/Window.java,v
retrieving revision 1.67
diff -u -r1.67 Window.java
--- java/awt/Window.java	25 Mar 2006 10:54:32 -0000	1.67
+++ java/awt/Window.java	29 Mar 2006 21:37:12 -0000
@@ -1,5 +1,5 @@
 /* Window.java --
-   Copyright (C) 1999, 2000, 2002, 2003, 2004  Free Software Foundation
+   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006  Free Software Foundation
 
 This file is part of GNU Classpath.
 
@@ -622,10 +622,25 @@
 	    || windowStateListener != null
 	    || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0))
       processEvent(e);
-    else if (e.id == ComponentEvent.COMPONENT_RESIZED)
-      validate ();
-    else
-      super.dispatchEventImpl(e);
+    else 
+      {
+	if (e.id == ComponentEvent.COMPONENT_RESIZED
+	    || e.id == ComponentEvent.COMPONENT_MOVED)
+	  {
+	    Rectangle bounds = peer.getBounds();
+	    x = bounds.x;
+	    y = bounds.y;
+	    height = bounds.height;
+	    width = bounds.width;
+	    
+	    if (e.id == ComponentEvent.COMPONENT_RESIZED)
+	      {
+		invalidate();
+		validate();
+	      }
+	  }
+	super.dispatchEventImpl(e);
+      }
   }
 
   /**

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to