This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: improve frame insets calculation


Hello,

The width and height arguments to java.awt.Frame's setSize method are
supposed to represent the frame's outer dimensions -- the width and
height of the frame, including its borders.  In the AWT, a frame's
borders are its insets.

Implementing this in X has historically been difficult, because there is
no standard way of obtaining from the window manager a frame's border
dimensions ("extents").  It has always been possible for the client (in
the X sense) to calculate the frame extents of its window, but only
after the window is actually visible on screen.

Here are some implementation strategies that I've tried, along with the
reasons they failed:

1) guess an initial size, show the window, calculate the insets upon
receiving a ConfigureNotify event, then resize the window to the exact
dimensions given by setSize.  The problems:

	a) it looks weird to the user.  
	b) because the extents calculation occurs in an event handler, 	and
also involves round trip queries to the X server, and also 	because
setting the size of a window triggers more configure 	events, there are
many race conditions that can leave the window 	in an inconsistent state
(e.g. with the frame torn away from its 	child window).

2) hard-code the extents based on some default window manager theme.  Of
course, this approach will give wrong results for different window
manager themes and different title bar font sizes.  The AWT treats a
Frame's extents as its insets, so if the hard-coded title bar height is
less than the actual title bar height, components along the top of the
window will be partially obscured.

In order to solve this properly, it was necessary to extend the window
manager to include two new hints, now part of a draft version of the
Extended Window Manager Hints specification: _NET_FRAME_EXTENTS and
_NET_REQUEST_FRAME_EXTENTS.

The current CVS version of metacity has a working implementation of
these hints.  The attached patch adds support for them to libgcj's GTK
peers.  It was tested with metacity versions 2.4.34 and CVS HEAD.

The patch should work with older window managers that don't yet support
the frame extents hints (e.g. metacity 2.4.34) -- the fallback case
hard-codes the border dimensions, so it suffers from the problems
mentioned in 2).

OK to commit?

Tom

2004-01-12  Thomas Fitzsimmons  <fitzsim@redhat.com>

	* gnu/java/awt/peer/gtk/GtkComponentPeer.java
	(initializeInsets): Remove method.
	(GtkComponentPeer): Initialize insets field.  Remove call to
	initializeInsets.
	* gnu/java/awt/peer/gtk/GtkDialogPeer.java (initializeInsets):
	Remove method.
	* gnu/java/awt/peer/gtk/GtkFramePeer.java (initializeInsets):
	Remove method.
	* gnu/java/awt/peer/gtk/GtkWindowPeer.java,
	jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c:
	(latestInsets): Remove field.
	(native create): Add insets parameter.  Call
	window_get_frame_extents.  Set the window's default size and
	size request based on its frame extents.
	(create): Initialize insets.
	(postInsetsChangedEvent): New method.
	(postConfigureEvent): Remove parameters top, left, bottom,
	right.  Remove insets-related logic.
	(connectJObject): Handle property-notify-event.
	(window_get_frame_extents, request_frame_extents,
	property_notify_predicate, window_property_changed_cb): New
	static functions.
	* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
	(pre_event_handler): Remove insets-related logic for configure
	events.
	* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c (gtkInit):
	Update postConfigureEvent signature.

Index: gnu/java/awt/peer/gtk/GtkComponentPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkComponentPeer.java,v
retrieving revision 1.12
diff -u -r1.12 GtkComponentPeer.java
--- gnu/java/awt/peer/gtk/GtkComponentPeer.java	5 Jan 2004 21:13:46 -0000	1.12
+++ gnu/java/awt/peer/gtk/GtkComponentPeer.java	12 Jan 2004 23:35:24 -0000
@@ -96,11 +96,6 @@
     throw new RuntimeException ();
   }
 
-  void initializeInsets ()
-  {
-    insets = new Insets (0, 0, 0, 0);
-  }
-
   native void connectJObject ();
   native void connectSignals ();
 
@@ -108,6 +103,7 @@
   {
     super (awtComponent);
     this.awtComponent = awtComponent;
+    insets = new Insets (0, 0, 0, 0);
 
     /* temporary try/catch block until all peers use this creation method */
     try {
@@ -126,8 +122,6 @@
 	setBackground (awtComponent.getBackground ());
       if (awtComponent.getFont() != null)
 	setFont(awtComponent.getFont());
-
-      initializeInsets ();
 
       setCursor (awtComponent.getCursor ());
       Rectangle bounds = awtComponent.getBounds ();
Index: gnu/java/awt/peer/gtk/GtkDialogPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkDialogPeer.java,v
retrieving revision 1.8
diff -u -r1.8 GtkDialogPeer.java
--- gnu/java/awt/peer/gtk/GtkDialogPeer.java	24 Oct 2003 19:40:29 -0000	1.8
+++ gnu/java/awt/peer/gtk/GtkDialogPeer.java	12 Jan 2004 23:35:24 -0000
@@ -41,7 +41,6 @@
 import java.awt.AWTEvent;
 import java.awt.Component;
 import java.awt.Dialog;
-import java.awt.Insets;
 import java.awt.peer.DialogPeer;
 
 public class GtkDialogPeer extends GtkWindowPeer
@@ -50,17 +49,6 @@
   public GtkDialogPeer (Dialog dialog)
   {
     super (dialog);
-  }
-
-  void initializeInsets ()
-  {
-    synchronized (latestInsets)
-      {
-	insets = new Insets (latestInsets.top,
-			     latestInsets.left,
-			     latestInsets.bottom,
-			     latestInsets.right);
-      }
   }
 
   void create ()
Index: gnu/java/awt/peer/gtk/GtkFramePeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkFramePeer.java,v
retrieving revision 1.7
diff -u -r1.7 GtkFramePeer.java
--- gnu/java/awt/peer/gtk/GtkFramePeer.java	31 Dec 2003 08:58:30 -0000	1.7
+++ gnu/java/awt/peer/gtk/GtkFramePeer.java	12 Jan 2004 23:35:24 -0000
@@ -43,7 +43,6 @@
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Image;
-import java.awt.Insets;
 import java.awt.MenuBar;
 import java.awt.Rectangle;
 import java.awt.event.PaintEvent;
@@ -69,21 +68,6 @@
   public GtkFramePeer (Frame frame)
   {
     super (frame);
-  }
-
-  void initializeInsets ()
-  {
-    // Unfortunately, X does not provide a clean way to calculate the
-    // dimensions of a frame's borders before it has been displayed.
-    // So we guess and then fix the dimensions upon receipt of the
-    // first configure event.
-    synchronized (latestInsets)
-      {
-	insets = new Insets (latestInsets.top,
-			     latestInsets.left,
-			     latestInsets.bottom,
-			     latestInsets.right);
-      }
   }
 
   void create ()
Index: gnu/java/awt/peer/gtk/GtkWindowPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkWindowPeer.java,v
retrieving revision 1.9
diff -u -r1.9 GtkWindowPeer.java
--- gnu/java/awt/peer/gtk/GtkWindowPeer.java	11 Dec 2003 13:50:50 -0000	1.9
+++ gnu/java/awt/peer/gtk/GtkWindowPeer.java	12 Jan 2004 23:35:24 -0000
@@ -40,7 +40,6 @@
 
 import java.awt.Component;
 import java.awt.Dimension;
-import java.awt.Insets;
 import java.awt.Window;
 import java.awt.Frame;
 import java.awt.event.WindowEvent;
@@ -61,30 +60,30 @@
   private boolean hasBeenShown = false;
   private int oldState = Frame.NORMAL;
 
-  // Unfortunately, X does not provide a clean way to calculate the
-  // dimensions of a window's borders before it has been displayed.
-  // So when creating the application's first window we guess the
-  // border dimensions.  Then if need be for that window, we fix the
-  // dimensions upon receipt of the first configure event.  Windows
-  // created after the first one will use the latest inset values
-  // received in postConfigureEvent.
-  static Insets latestInsets = new Insets (20, 6, 6, 6);
-
   native void create (int type, boolean decorated,
 		      int width, int height,
-		      GtkWindowPeer parent);
+		      GtkWindowPeer parent,
+		      int[] insets);
 
   void create (int type, boolean decorated)
   {
     GtkWindowPeer parent_peer = null;
     Component parent = awtComponent.getParent();
+    int[] insets = new int [] { 0, 0, 0, 0 };
+
     if (parent != null)
       parent_peer = (GtkWindowPeer) awtComponent.getParent().getPeer();
 
     create (type, decorated,
 	    awtComponent.getWidth(),
 	    awtComponent.getHeight(),
-	    parent_peer);
+	    parent_peer,
+	    insets);
+
+    this.insets.top = insets [0];
+    this.insets.left = insets [1];
+    this.insets.bottom = insets [2];
+    this.insets.right = insets [3];
   }
 
   void create ()
@@ -132,7 +131,7 @@
     // 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);
+	     awtComponent.getHeight() - insets.top - insets.bottom);
     set ("allow_shrink", resizable);
     set ("allow_grow", resizable);
   }
@@ -141,67 +140,29 @@
 				 int x, int y,
 				 int width, int height);
 
-  protected void postConfigureEvent (int x, int y, int width, int height,
-				     int top, int left, int bottom, int right)
+  protected void postInsetsChangedEvent (int top, int left,
+					 int bottom, int right)
   {
-    // Configure events tell us the location and dimensions of the
-    // window within the frame borders, and the dimensions of the
-    // frame borders (top, left, bottom, right).
-
-    // If our borders change we need to make sure that a new layout
-    // will happen, since Sun forgets to handle this case.
-    if (insets.top != top
-	|| insets.left != left
-	|| insets.bottom != bottom
-	|| insets.right != right)
-      {
-	// When our insets change, we receive a configure event with
-	// the new insets, the old window location and the old window
-	// dimensions.  We update our Window object's location and
-	// size using our old inset values.
-	setBoundsCallback ((Window) awtComponent,
-			   x - insets.left,
-			   y - insets.top,
-			   width + insets.left + insets.right,
-			   height + insets.top + insets.bottom);
-
-	// The peer's dimensions do not get updated automatically when
-	// insets change so we need to do it manually.
-	setSize (width + (insets.left - left) + (insets.right - right),
-		 height + (insets.top - top) + (insets.bottom - bottom));
-
-	insets.top = top;
-	insets.left = left;
-	insets.bottom = bottom;
-	insets.right = right;
-
-	synchronized (latestInsets)
-	  {
-	    latestInsets.top = top;
-	    latestInsets.left = left;
-	    latestInsets.bottom = bottom;
-	    latestInsets.right = right;
-	  }
-      }
-    else
-      {
-	int frame_x = x - insets.left;
-	int frame_y = y - insets.top;
-	int frame_width = width + insets.left + insets.right;
-	int frame_height = height + insets.top + insets.bottom;
-
-	if (frame_x != awtComponent.getX()
-	    || frame_y != awtComponent.getY()
-	    || frame_width != awtComponent.getWidth()
-	    || frame_height != awtComponent.getHeight())
-	  {
-	    setBoundsCallback ((Window) awtComponent,
-			       frame_x,
-			       frame_y,
-			       frame_width,
-			       frame_height);
-	  }
-      }
+    insets.top = top;
+    insets.left = left;
+    insets.bottom = bottom;
+    insets.right = right;
+  }
+
+  protected void postConfigureEvent (int x, int y, int width, int height)
+  {
+    int frame_x = x - insets.left;
+    int frame_y = y - insets.top;
+    int frame_width = width + insets.left + insets.right;
+    int frame_height = height + insets.top + insets.bottom;
+
+    if (frame_x != awtComponent.getX()
+	|| frame_y != awtComponent.getY()
+	|| frame_width != awtComponent.getWidth()
+	|| frame_height != awtComponent.getHeight())
+      setBoundsCallback ((Window) awtComponent,
+			 frame_x, frame_y, frame_width, frame_height);
+
     awtComponent.validate();
   }
 
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c,v
retrieving revision 1.16
diff -u -r1.16 gnu_java_awt_peer_gtk_GtkEvents.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c	5 Jan 2004 21:41:21 -0000	1.16
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c	12 Jan 2004 23:35:24 -0000
@@ -989,40 +989,18 @@
 	    
 	if (widget && GTK_WIDGET_TOPLEVEL (widget))
 	  {
-	    gint top, left, right, bottom;
-
 	    /* Configure events are not posted to the AWT event
 	       queue, and as such, the gdk/gtk peer functions will
 	       be called back before postConfigureEvent
 	       returns. */
 	    gdk_threads_leave ();
 
-	    /* FIXME: hard-code these values for now. */
-	    if (GTK_IS_PLUG (widget))
-	      {
-		top = 0;
-		left = 0;
-		bottom = 0;
-		right = 0;
-	      }
-	    else
-	      {
-		top = 20;
-		left = 6;
-		bottom = 6;
-		right = 6;
-	      }
-
  	    (*gdk_env)->CallVoidMethod (gdk_env, peer,
 					postConfigureEventID,
 					(jint) event->configure.x,
 					(jint) event->configure.y,
 					(jint) event->configure.width,
-					(jint) event->configure.height,
-					(jint) top,
-					(jint) left,
-					(jint) bottom,
-					(jint) right);
+					(jint) event->configure.height);
 	    gdk_threads_enter ();
 	  }
       }
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c,v
retrieving revision 1.11
diff -u -r1.11 gnu_java_awt_peer_gtk_GtkMainThread.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c	23 Dec 2003 19:24:00 -0000	1.11
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c	12 Jan 2004 23:35:24 -0000
@@ -168,7 +168,7 @@
   postMouseEventID = (*env)->GetMethodID (env, gtkcomponentpeer, 
 					  "postMouseEvent", "(IJIIIIZ)V");
   postConfigureEventID = (*env)->GetMethodID (env, gtkwindowpeer, 
-					  "postConfigureEvent", "(IIIIIIII)V");
+					      "postConfigureEvent", "(IIII)V");
   postWindowEventID = (*env)->GetMethodID (env, gtkwindowpeer,
 					   "postWindowEvent",
 					   "(ILjava/awt/Window;I)V");
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c,v
retrieving revision 1.11
diff -u -r1.11 gnu_java_awt_peer_gtk_GtkWindowPeer.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c	13 Dec 2003 01:15:47 -0000	1.11
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c	12 Jan 2004 23:35:24 -0000
@@ -44,6 +44,16 @@
 #include <gdk/gdkx.h>
 #include <X11/Xatom.h>
 
+static void window_get_frame_extents (GtkWidget *window,
+                                      int *top, int *left,
+                                      int *bottom, int *right);
+
+static void request_frame_extents (GtkWidget *window);
+
+static int property_notify_predicate (Display *xdisplay,
+                                      XEvent  *event,
+                                      XPointer window_id);
+
 static void window_delete_cb (GtkWidget *widget, GdkEvent *event,
 			      jobject peer);
 static void window_destroy_cb (GtkWidget *widget, GdkEvent *event,
@@ -59,6 +69,9 @@
 					GdkEvent *event,
 					jobject peer);
 static jint window_get_new_state (GtkWidget *widget);
+static gboolean window_property_changed_cb (GtkWidget *widget,
+					    GdkEventProperty *event,
+					    jobject peer);
 
 /*
  * Make a new window.
@@ -67,12 +80,21 @@
 JNIEXPORT void JNICALL 
 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create 
   (JNIEnv *env, jobject obj, jint type, jboolean decorated,
-   jint width, jint height, jobject parent)
+   jint width, jint height, jobject parent, jintArray jinsets)
 {
   GtkWidget *window_widget;
   GtkWindow *window;
   void *window_parent;
-  GtkWidget *vbox, *layout;
+  GtkWidget *vbox;
+  GtkWidget *layout;
+  int top = 0;
+  int left = 0;
+  int bottom = 0;
+  int right = 0;
+  jint *insets;
+
+  insets = (*env)->GetIntArrayElements (env, jinsets, 0);
+  insets[0] = insets[1] = insets[2] = insets[3] = 0;
 
   /* Create global reference and save it for future use */
   NSA_SET_GLOBAL_REF (env, obj);
@@ -82,19 +104,6 @@
   window_widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   window = GTK_WINDOW (window_widget);
 
-  // Avoid GTK runtime assertion failures.
-  width = (width < 1) ? 1 : width;
-  height = (height < 1) ? 1 : height;
-
-  gtk_window_set_default_size (window, width, height);
-
-  /* We must set this window's size requisition.  Otherwise when a
-     resize is queued (when gtk_widget_queue_resize is called) the
-     window will snap to its default requisition of 0x0.  If we omit
-     this call, Frames and Dialogs shrink to degenerate 1x1 windows
-     when their resizable property changes. */
-  gtk_widget_set_size_request (window_widget, width, height);
-
   /* Keep this window in front of its parent, if it has one. */
   if (parent)
     {
@@ -115,9 +124,33 @@
 
   gtk_widget_show (layout);
   gtk_widget_show (vbox);
+  gtk_widget_realize (window_widget);
+
+  if (decorated)
+    window_get_frame_extents (window_widget, &top, &left, &bottom, &right);
+
+  gtk_window_set_default_size (window,
+			       MAX (1, width - left - right),
+			       MAX (1, height - top - bottom));
+
+  /* We must set this window's size requisition.  Otherwise when a
+     resize is queued (when gtk_widget_queue_resize is called) the
+     window will snap to its default requisition of 0x0.  If we omit
+     this call, Frames and Dialogs shrink to degenerate 1x1 windows
+     when their resizable property changes. */
+  gtk_widget_set_size_request (window_widget,
+			       MAX (1, width - left - right),
+			       MAX (1, height - top - bottom));
+
+  insets[0] = top;
+  insets[1] = left;
+  insets[2] = bottom;
+  insets[3] = right;
 
   gdk_threads_leave ();
 
+  (*env)->ReleaseIntArrayElements (env, jinsets, insets, 0);
+
   NSA_SET_PTR (env, obj, window_widget);
 }
 
@@ -176,6 +209,9 @@
 
   connect_awt_hook (env, obj, 1, GTK_WIDGET (ptr)->window);
 
+  g_signal_connect (G_OBJECT (ptr), "property-notify-event",
+		    G_CALLBACK (window_property_changed_cb), obj);
+
   gdk_threads_leave ();
 }
 
@@ -291,7 +327,7 @@
 {
   void *ptr = NSA_GET_PTR (env, obj);
 
-  // Avoid GTK runtime assertion failures.
+  /* Avoid GTK runtime assertion failures. */
   width = (width < 1) ? 1 : width;
   height = (height < 1) ? 1 : height;
 
@@ -306,7 +342,7 @@
 {
   void *ptr = NSA_GET_PTR (env, obj);
 
-  // Avoid GTK runtime assertion failures.
+  /* Avoid GTK runtime assertion failures. */
   width = (width < 1) ? 1 : width;
   height = (height < 1) ? 1 : height;
 
@@ -365,6 +401,112 @@
 }
 
 static void
+window_get_frame_extents (GtkWidget *window,
+                          int *top, int *left, int *bottom, int *right)
+{
+  unsigned long *extents = NULL;
+
+  /* Guess frame extents in case _NET_FRAME_EXTENTS is not
+     supported. */
+  *top = 23;
+  *left = 6;
+  *bottom = 6;
+  *right = 6;
+
+  /* Request that the window manager set window's
+     _NET_FRAME_EXTENTS property. */
+  request_frame_extents (window);
+
+  /* Attempt to retrieve window's frame extents. */
+  if (gdk_property_get (window->window,
+                        gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
+                        gdk_atom_intern ("CARDINAL", FALSE),
+                        0,
+                        sizeof (unsigned long) * 4,
+                        FALSE,
+                        NULL,
+                        NULL,
+                        NULL,
+                        (guchar **)&extents))
+    {
+      *left = extents [0];
+      *right = extents [1];
+      *top = extents [2];
+      *bottom = extents [3];
+    }
+}
+
+static Atom extents_atom = 0;
+
+/* Requests that the window manager set window's
+   _NET_FRAME_EXTENTS property. */
+static void
+request_frame_extents (GtkWidget *window)
+{
+  const char *request_str = "_NET_REQUEST_FRAME_EXTENTS";
+  GdkAtom request_extents = gdk_atom_intern (request_str, FALSE);
+
+  /* Check if the current window manager supports
+     _NET_REQUEST_FRAME_EXTENTS. */
+  if (gdk_net_wm_supports (request_extents))
+    {
+      GdkDisplay *display = gtk_widget_get_display (window);
+      Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+      GdkWindow *root_window = gdk_get_default_root_window ();
+      Window xroot_window = GDK_WINDOW_XID (root_window);
+
+      Atom extents_request_atom =
+	gdk_x11_get_xatom_by_name_for_display (display, request_str);
+
+      XEvent xevent;
+      XEvent notify_xevent;
+
+      unsigned long window_id = GDK_WINDOW_XID (GDK_DRAWABLE(window->window));
+
+      if (!extents_atom)
+	{
+	  const char *extents_str = "_NET_FRAME_EXTENTS";
+	  extents_atom =
+	    gdk_x11_get_xatom_by_name_for_display (display, extents_str);
+	}
+
+      xevent.xclient.type = ClientMessage;
+      xevent.xclient.message_type = extents_request_atom;
+      xevent.xclient.display = xdisplay;
+      xevent.xclient.window = window_id;
+      xevent.xclient.format = 32;
+      xevent.xclient.data.l[0] = 0;
+      xevent.xclient.data.l[1] = 0;
+      xevent.xclient.data.l[2] = 0;
+      xevent.xclient.data.l[3] = 0;
+      xevent.xclient.data.l[4] = 0;
+
+      XSendEvent (xdisplay, xroot_window, False,
+		  (SubstructureRedirectMask | SubstructureNotifyMask),
+                  &xevent);
+
+      XIfEvent(xdisplay, &notify_xevent,
+	       property_notify_predicate, (XPointer) &window_id);
+    }
+}
+
+static int
+property_notify_predicate (Display *xdisplay __attribute__((unused)),
+                           XEvent  *event,
+                           XPointer window_id)
+{
+  unsigned long *window = (unsigned long *) window_id;
+
+  if (event->xany.type == PropertyNotify
+      && event->xany.window == *window
+      && event->xproperty.atom == extents_atom)
+        return True;
+
+  return False;
+}
+
+static void
 window_delete_cb (GtkWidget *widget __attribute__((unused)),
 		  GdkEvent *event __attribute__((unused)),
 		  jobject peer)
@@ -513,4 +655,45 @@
       XFree (atom_list);
     }
   return new_state;
+}
+
+static gboolean
+window_property_changed_cb (GtkWidget *widget __attribute__((unused)),
+                            GdkEventProperty *event,
+                            jobject peer)
+{
+  unsigned long *extents;
+
+  static int id_set = 0;
+  static jmethodID postInsetsChangedEventID;
+
+  if (!id_set)
+    {
+      jclass gtkwindowpeer = (*gdk_env)->FindClass (gdk_env,
+				 "gnu/java/awt/peer/gtk/GtkWindowPeer");
+      postInsetsChangedEventID = (*gdk_env)->GetMethodID (gdk_env,
+						      gtkwindowpeer,
+						      "postInsetsChangedEvent",
+						      "(IIII)V");
+    }
+
+  if (gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE) == event->atom
+      && gdk_property_get (event->window,
+                           gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
+                           gdk_atom_intern ("CARDINAL", FALSE),
+                           0,
+                           sizeof (unsigned long) * 4,
+                           FALSE,
+                           NULL,
+                           NULL,
+                           NULL,
+                           (guchar **)&extents))
+    (*gdk_env)->CallVoidMethod (gdk_env, peer,
+				postInsetsChangedEventID,
+				(jint) extents[2],  /* top */
+				(jint) extents[0],  /* left */
+				(jint) extents[3],  /* bottom */
+				(jint) extents[1]); /* right */
+
+  return FALSE;
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]