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);
+ }
}
/**
signature.asc
Description: This is a digitally signed message part
