OSDN Git Service

2005-04-25 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkWindowPeer.c
index 9a8cc32..184ca56 100644 (file)
@@ -1,5 +1,5 @@
 /* gtkwindowpeer.c -- Native implementation of GtkWindowPeer
-   Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -38,165 +38,229 @@ exception statement from your version. */
 
 #include "gtkpeer.h"
 #include "gnu_java_awt_peer_gtk_GtkWindowPeer.h"
-#include "gnu_java_awt_peer_gtk_GtkFramePeer.h"
 #include <gdk/gdkprivate.h>
 #include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
+/* FIXME: we're currently seeing the double-activation that occurs
+   with metacity and GTK.  See
+   http://bugzilla.gnome.org/show_bug.cgi?id=140977 for details. */
+
+static void window_get_frame_extents (GtkWidget *window,
+                                      int *top, int *left,
+                                      int *bottom, int *right);
+
+static void request_frame_extents (GtkWidget *window);
+
+static Bool property_notify_predicate (Display *display,
+                                       XEvent  *xevent,
+                                       XPointer arg);
+
+static void window_delete_cb (GtkWidget *widget, GdkEvent *event,
+                             jobject peer);
+static void window_destroy_cb (GtkWidget *widget, GdkEvent *event,
+                              jobject peer);
+static void window_show_cb (GtkWidget *widget, jobject peer);
+static void window_active_state_change_cb (GtkWidget *widget,
+                                           GParamSpec *pspec,
+                                           jobject peer);
+static void window_focus_state_change_cb (GtkWidget *widget,
+                                          GParamSpec *pspec,
+                                          jobject peer);
+static gboolean window_focus_in_cb (GtkWidget * widget,
+                                    GdkEventFocus *event,
+                                    jobject peer);
+static gboolean window_focus_out_cb (GtkWidget * widget,
+                                     GdkEventFocus *event,
+                                     jobject peer);
+static gboolean window_window_state_cb (GtkWidget *widget,
+                                       GdkEvent *event,
+                                       jobject peer);
+static jint window_get_new_state (GtkWidget *widget);
+static gboolean window_property_changed_cb (GtkWidget *widget,
+                                           GdkEventProperty *event,
+                                           jobject peer);
+static void realize_cb (GtkWidget *widget, jobject peer);
+
+/* Union used for type punning. */
+union extents_union
+{
+  guchar **gu_extents;
+  unsigned long **extents;
+};
 
-static void setBounds (GtkWidget *, jint, jint, jint, jint);
-
-/*
- * Make a new window (any type)
- */
+union atom_list_union
+{
+  guchar **gu_extents;
+  Atom **atom_list;
+};
 
-JNIEXPORT void JNICALL 
-Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create 
-  (JNIEnv *env, jobject obj, jint type)
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create
+  (JNIEnv *env, jobject obj, jint type, jboolean decorated, jobject parent)
 {
-  gpointer window;
-  GtkWidget *vbox, *layout;
+  GtkWidget *window_widget;
+  GtkWindow *window;
+  void *window_parent;
+  GtkWidget *fixed;
+
+  NSA_SET_GLOBAL_REF (env, obj);
 
   gdk_threads_enter ();
-  window = gtk_window_new (type);
+  
+  window_widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  window = GTK_WINDOW (window_widget);
+
+  /* Keep this window in front of its parent, if it has one. */
+  if (parent)
+    {
+      window_parent = NSA_GET_PTR (env, parent);
+      gtk_window_set_transient_for (window, GTK_WINDOW(window_parent));
+    }
+
+  gtk_window_set_decorated (window, decorated);
+
+  gtk_window_set_type_hint (window, type);
 
-  vbox = gtk_vbox_new (0, 0);
-  layout = gtk_layout_new (NULL, NULL);
-  gtk_box_pack_end (GTK_BOX (vbox), layout, 1, 1, 0);
-  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_window_group_add_window (global_gtk_window_group, window);
 
-  gtk_widget_show (layout);
-  gtk_widget_show (vbox);
+  fixed = gtk_fixed_new ();
+  gtk_container_add (GTK_CONTAINER (window_widget), fixed);
+
+  gtk_widget_show (fixed);
 
   gdk_threads_leave ();
 
-  NSA_SET_PTR (env, obj, window);
+  NSA_SET_PTR (env, obj, window_widget);
 }
 
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setVisible
-  (JNIEnv *env, jobject obj, jboolean visible)
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetTitle
+  (JNIEnv *env, jobject obj, jstring title)
 {
+  const char *c_title;
   void *ptr;
 
   ptr = NSA_GET_PTR (env, obj);
 
+  c_title = (*env)->GetStringUTFChars (env, title, NULL);
+
   gdk_threads_enter ();
 
-  if (visible)
-    gtk_widget_show (GTK_WIDGET (ptr));
-  else
-    gtk_widget_hide (GTK_WIDGET (ptr));
+  gtk_window_set_title (GTK_WINDOW (ptr), c_title);
 
-  XFlush (GDK_DISPLAY ());
   gdk_threads_leave ();
+
+  (*env)->ReleaseStringUTFChars (env, title, c_title);
 }
 
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectHooks
-  (JNIEnv *env, jobject obj)
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetResizable
+  (JNIEnv *env, jobject obj, jboolean resizable)
 {
   void *ptr;
-  GtkVBox* vbox;
-  GtkWidget *layout;
-  GList* children;
-  char* name;
+
   ptr = NSA_GET_PTR (env, obj);
 
   gdk_threads_enter ();
 
-   children = gtk_container_get_children(GTK_CONTAINER(ptr));
-   vbox = children->data;
-   name = GTK_OBJECT_TYPE_NAME(vbox);
-   if(!GTK_IS_VBOX(vbox))
-     {
-       printf("*** this is not a vbox\n");
-     }
-   children = gtk_container_get_children(GTK_CONTAINER(vbox));
-   layout = children->data;
-   name = GTK_OBJECT_TYPE_NAME(layout);
-   if(!GTK_IS_LAYOUT(layout))
-     {
-      printf("*** widget is not a layout ***");
-     }
-
-  gtk_widget_realize (layout);
-
-  connect_awt_hook (env, obj, 1, GTK_LAYOUT (layout)->bin_window);
-  
-    gtk_widget_realize (ptr);
+  gtk_window_set_policy (GTK_WINDOW (ptr), resizable, resizable, FALSE);
 
-  connect_awt_hook (env, obj, 1, GTK_WIDGET (ptr)->window);
-  
   gdk_threads_leave ();
 }
 
-void
-setup_window (JNIEnv *env, jobject obj, GtkWidget *window, jint width, 
-             jint height, jboolean visible)
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetModal
+  (JNIEnv *env, jobject obj, jboolean modal)
 {
-  GtkWidget *layout, *vbox;
-
-  gdk_threads_enter();
-  gtk_window_set_policy (GTK_WINDOW (window), 1, 1, 0);
-  gtk_widget_set_usize (window, width, height);
-
-  vbox = gtk_vbox_new (0, 0);
-  layout = gtk_layout_new (NULL, NULL);
-  gtk_box_pack_end (GTK_BOX (vbox), layout, 1, 1, 0);
-  gtk_container_add (GTK_CONTAINER (window), vbox);
-  gtk_widget_realize (layout);
-  connect_awt_hook (env, obj, 1, GTK_LAYOUT(layout)->bin_window);
-  gtk_widget_show (layout);
-  gtk_widget_show (vbox);
-
-  gtk_widget_realize (window);
-/*    setBounds (window, x, y, width, height); */
-
-  connect_awt_hook (env, obj, 1, window->window);
-  set_visible (window, visible);
+  void *ptr;
+
+  ptr = NSA_GET_PTR (env, obj);
+
+  gdk_threads_enter ();
+
+  gtk_window_set_modal (GTK_WINDOW (ptr), modal);
+
   gdk_threads_leave ();
 }
 
-/*
- * Set a frame's title
- */
-
-JNIEXPORT void JNICALL 
-Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setTitle
-  (JNIEnv *env, jobject obj, jstring title)
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetVisible
+  (JNIEnv *env, jobject obj, jboolean visible)
 {
   void *ptr;
-  const char *str;
 
   ptr = NSA_GET_PTR (env, obj);
-  
-  str = (*env)->GetStringUTFChars (env, title, NULL);
-  
+
   gdk_threads_enter ();
-  gtk_window_set_title (GTK_WINDOW (ptr), str);
+
+  if (visible)
+    gtk_widget_show (GTK_WIDGET (ptr));
+  else
+    gtk_widget_hide (GTK_WIDGET (ptr));
+
+  XFlush (GDK_DISPLAY ());
+
   gdk_threads_leave ();
-  
-  (*env)->ReleaseStringUTFChars (env, title, str);
 }
 
-/*
- * Set a window's resizing policy
- */
-
 JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setResizable
-  (JNIEnv *env, jobject obj, jboolean resize)
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectSignals
+  (JNIEnv *env, jobject obj)
 {
   void *ptr;
-  
+  jobject *gref;
+
   ptr = NSA_GET_PTR (env, obj);
-  
+  gref = NSA_GET_GLOBAL_REF (env, obj);
+
   gdk_threads_enter ();
-  gtk_window_set_policy (GTK_WINDOW (ptr), resize, resize, 0);
-  gdk_threads_leave ();
-}
 
+  g_signal_connect (G_OBJECT (ptr), "event",
+                    G_CALLBACK (pre_event_handler), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "delete-event",
+                   G_CALLBACK (window_delete_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "destroy-event",
+                   G_CALLBACK (window_destroy_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "show",
+                   G_CALLBACK (window_show_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "notify::is-active",
+                   G_CALLBACK (window_active_state_change_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "notify::has-toplevel-focus",
+                   G_CALLBACK (window_focus_state_change_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "focus-in-event",
+                    G_CALLBACK (window_focus_in_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "focus-out-event",
+                    G_CALLBACK (window_focus_out_cb), *gref);
 
-/*
- * Lower the z-level of a window. 
- */
+  g_signal_connect (G_OBJECT (ptr), "window-state-event",
+                   G_CALLBACK (window_window_state_cb), *gref);
+
+  g_signal_connect (G_OBJECT (ptr), "property-notify-event",
+                   G_CALLBACK (window_property_changed_cb), *gref);
+
+  g_signal_connect_after (G_OBJECT (ptr), "realize",
+                          G_CALLBACK (realize_cb), *gref);
+
+  g_signal_connect_after (G_OBJECT (ptr), "realize",
+                          G_CALLBACK (connect_awt_hook_cb), *gref);
+
+
+  /* Realize the window here so that its frame extents are known now.
+     That way Window.pack can operate with the accurate insets
+     returned by the window manager rather than the default
+     estimates. */
+  gtk_widget_realize (GTK_WIDGET (ptr));
+
+  gdk_threads_leave ();
+}
 
 JNIEXPORT void JNICALL 
 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv *env, 
@@ -206,16 +270,13 @@ Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv *env,
   ptr = NSA_GET_PTR (env, obj);
     
   gdk_threads_enter ();
+
   gdk_window_lower (GTK_WIDGET (ptr)->window);
+  gdk_flush ();
 
-  XFlush (GDK_DISPLAY ());
   gdk_threads_leave ();
 }
 
-/*
- * Raise the z-level of a window.
- */
-
 JNIEXPORT void JNICALL 
 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toFront (JNIEnv *env, 
     jobject obj)
@@ -224,122 +285,454 @@ Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toFront (JNIEnv *env,
   ptr = NSA_GET_PTR (env, obj);
     
   gdk_threads_enter ();
+
   gdk_window_raise (GTK_WIDGET (ptr)->window);
+  gdk_flush ();
 
-  XFlush (GDK_DISPLAY ());
   gdk_threads_leave ();
 }
 
-static void
-setBounds (GtkWidget *widget, jint x, jint y, jint width, jint height)
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setBoundsCallback
+  (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
+   jobject window, jint x, jint y, jint width, jint height)
 {
-/*    gdk_window_get_root_origin (widget->window, &current_x, &current_y); */
+  /* Circumvent package-private access to call Window's
+     setBoundsCallback method. */
+  (*gdk_env())->CallVoidMethod (gdk_env(), window, setBoundsCallbackID,
+                             x, y, width, height);
+}
+
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setSize
+  (JNIEnv *env, jobject obj, jint width, jint height)
+{
+  void *ptr = NSA_GET_PTR (env, obj);
+
+  /* Avoid GTK runtime assertion failures. */
+  width = (width < 1) ? 1 : width;
+  height = (height < 1) ? 1 : height;
+
+  gdk_threads_enter ();
 
-/*    if (current_x != x || current_y != y) */
-/*      { */
-/*        gdk_window_set_hints (widget->window, x, y, 0, 0, 0, 0, GDK_HINT_POS); */
-/*        gdk_window_move (widget->window, x, y); */
-/*      } */
+  gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
 
-  gtk_widget_set_usize (widget, width, height);
+  gdk_threads_leave ();
 }
 
-JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setBounds
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetBounds
   (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height)
 {
-  void *ptr;
-  GtkWidget *widget;
+  void *ptr = NSA_GET_PTR (env, obj);
 
-  ptr = NSA_GET_PTR (env, obj);
+  /* Avoid GTK runtime assertion failures. */
+  width = (width < 1) ? 1 : width;
+  height = (height < 1) ? 1 : height;
 
   gdk_threads_enter ();
 
-  widget = GTK_WIDGET (ptr);
-  setBounds (widget, x, y, width, height);
-
+  gtk_window_move (GTK_WINDOW(ptr), x, y);
+  /* The call to gdk_window_move is needed in addition to the call to
+     gtk_window_move.  If gdk_window_move isn't called, then the
+     following set of operations doesn't give the expected results:
+
+     1. show a window
+     2. manually move it to another position on the screen
+     3. hide the window
+     4. reposition the window with Component.setLocation
+     5. show the window
+
+     Instead of being at the position set by setLocation, the window
+     is reshown at the position to which it was moved manually. */
+  if (GTK_WIDGET (ptr)->window != NULL)
+    gdk_window_move (GTK_WIDGET (ptr)->window, x, y);
+
+  /* Need to change the widget's request size. */
+  gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
+  /* Also need to call gtk_window_resize.  If the resize is requested
+     by the program and the window's "resizable" property is true then
+     the size request will not be honoured. */
+  gtk_window_resize (GTK_WINDOW (ptr), width, height);
   gdk_threads_leave ();
 }
 
-JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GtkFramePeer_setMenuBarPeer
-  (JNIEnv *env, jobject obj, jobject menubar)
+static void
+window_get_frame_extents (GtkWidget *window,
+                          int *top, int *left, int *bottom, int *right)
 {
-  void *wptr, *mptr;
-  GtkBox *box;
+  unsigned long *extents = NULL;
+  union extents_union gu_ex;
+
+  /* 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. */
+  gu_ex.extents = &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,
+                        gu_ex.gu_extents))
+    {
+      *left = extents [0];
+      *right = extents [1];
+      *top = extents [2];
+      *bottom = extents [3];
+    }
+}
 
-  if (!menubar) return;
+static Atom extents_atom = 0;
 
-  wptr = NSA_GET_PTR (env, obj);
-  mptr = NSA_GET_PTR (env, menubar);
+/* 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);
 
-  if (!mptr) return; /* this case should remove a menu */
+  /* 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 Bool
+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;
+  else
+    return False;
+}
+
+static void
+window_delete_cb (GtkWidget *widget __attribute__((unused)),
+                 GdkEvent *event __attribute__((unused)),
+                 jobject peer)
+{
+  gdk_threads_leave ();
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                             postWindowEventID,
+                             (jint) AWT_WINDOW_CLOSING,
+                             (jobject) NULL, (jint) 0);
   gdk_threads_enter ();
-  box = GTK_BOX (GTK_BIN (wptr)->child);
-  gtk_box_pack_start (box, GTK_WIDGET (mptr), 0, 0, 0);
+}
+
+static void
+window_destroy_cb (GtkWidget *widget __attribute__((unused)),
+                  GdkEvent *event __attribute__((unused)),
+                  jobject peer)
+{
   gdk_threads_leave ();
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                             postWindowEventID,
+                             (jint) AWT_WINDOW_CLOSED,
+                             (jobject) NULL, (jint) 0);
+  gdk_threads_enter ();
 }
 
-JNIEXPORT jint JNICALL
-Java_gnu_java_awt_peer_gtk_GtkFramePeer_getMenuBarHeight
-  (JNIEnv *env, jobject obj)
+static void
+window_show_cb (GtkWidget *widget __attribute__((unused)),
+               jobject peer)
 {
-  void *ptr;
-  GList *children;
-  jint height = 0;
+  gdk_threads_leave ();
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                             postWindowEventID,
+                             (jint) AWT_WINDOW_OPENED,
+                             (jobject) NULL, (jint) 0);
+  gdk_threads_enter ();
+}
 
-  ptr = NSA_GET_PTR (env, obj);
+static void
+window_active_state_change_cb (GtkWidget *widget __attribute__((unused)),
+                              GParamSpec *pspec __attribute__((unused)),
+                              jobject peer __attribute__((unused)))
+{
+  /* FIXME: not sure if this is needed or not. */
+  /* Remove the unused attributes if you fix the below.  */
+#if 0
+  gdk_threads_leave ();
+  if (GTK_WINDOW (widget)->is_active)
+    (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                                postWindowEventID,
+                                (jint) AWT_WINDOW_GAINED_FOCUS,
+                                (jobject) NULL, (jint) 0);
+  else
+    (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                                postWindowEventID,
+                                (jint) AWT_WINDOW_DEACTIVATED,
+                                (jobject) NULL, (jint) 0);
+  gdk_threads_enter ();
+#endif
+}
+
+static void
+window_focus_state_change_cb (GtkWidget *widget,
+                             GParamSpec *pspec __attribute__((unused)),
+                             jobject peer)
+{
+  gdk_threads_leave ();
+  if (GTK_WINDOW (widget)->has_toplevel_focus)
+    (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                                postWindowEventID,
+                                (jint) AWT_WINDOW_ACTIVATED,
+                                (jobject) NULL, (jint) 0);
+  else
+    (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                                postWindowEventID,
+                                (jint) AWT_WINDOW_DEACTIVATED,
+                                (jobject) NULL, (jint) 0);
+  gdk_threads_enter ();
+}
 
+static gboolean
+window_focus_in_cb (GtkWidget * widget  __attribute__((unused)),
+                   GdkEventFocus *event  __attribute__((unused)),
+                   jobject peer)
+{
+  gdk_threads_leave ();
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                              postWindowEventID,
+                              (jint) AWT_WINDOW_GAINED_FOCUS,
+                              (jobject) NULL, (jint) 0);
+  /* FIXME: somewhere after this is handled, the child window is
+     getting an expose event. */
   gdk_threads_enter ();
-  children = gtk_container_children (GTK_CONTAINER (GTK_BIN (ptr)->child));
-  if (g_list_length (children) == 2)
-    {
-      GtkWidget *menubar = GTK_WIDGET (children->data);
-      height = menubar->allocation.height;
+  return FALSE;
+}
 
-    }
+static gboolean
+window_focus_out_cb (GtkWidget * widget __attribute__((unused)),
+                    GdkEventFocus *event __attribute__((unused)),
+                    jobject peer)
+{
   gdk_threads_leave ();
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                              postWindowEventID,
+                              (jint) AWT_WINDOW_LOST_FOCUS,
+                              (jobject) NULL, (jint) 0);
+  /* FIXME: somewhere after this is handled, the child window is
+     getting an expose event. */
+  gdk_threads_enter ();
+  return FALSE;
+}
 
-  return height;
+static gboolean
+window_window_state_cb (GtkWidget *widget,
+                       GdkEvent *event,
+                       jobject peer)
+{
+  jint new_state;
+
+  /* Handle WINDOW_ICONIFIED and WINDOW_DEICONIFIED events. */
+  if (event->window_state.changed_mask & GDK_WINDOW_STATE_ICONIFIED)
+    {
+      /* We've either been iconified or deiconified. */
+      if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
+       {
+         /* We've been iconified. */
+         gdk_threads_leave ();
+         (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                                     postWindowEventID,
+                                     (jint) AWT_WINDOW_ICONIFIED,
+                                     (jobject) NULL, (jint) 0);
+         gdk_threads_enter ();
+       }
+      else
+       {
+         /* We've been deiconified. */
+         gdk_threads_leave ();
+         (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                                     postWindowEventID,
+                                     (jint) AWT_WINDOW_DEICONIFIED,
+                                     (jobject) NULL, (jint) 0);
+         gdk_threads_enter ();
+       }
+    }
+
+  /* Post a WINDOW_STATE_CHANGED event, passing the new frame state to
+     GtkWindowPeer. */
+  new_state = AWT_FRAME_STATE_NORMAL;
+
+  if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
+    new_state |= AWT_FRAME_STATE_ICONIFIED;
+
+  new_state |= window_get_new_state (widget);
+
+  gdk_threads_leave ();
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                             postWindowEventID,
+                             (jint) AWT_WINDOW_STATE_CHANGED,
+                             (jobject) NULL, new_state);
+  gdk_threads_enter ();
+  return TRUE;
 }
 
+static jint
+window_get_new_state (GtkWidget *widget)
+{
+  GdkDisplay *display = gtk_widget_get_display(widget);
+  jint new_state = AWT_FRAME_STATE_NORMAL;
+  Atom type;
+  gint format;
+  gulong atom_count;
+  gulong bytes_after;
+  Atom *atom_list = NULL;
+  union atom_list_union alu;
+  gulong i;
+
+  alu.atom_list = &atom_list;
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), 
+                     GDK_WINDOW_XID (widget->window),
+                     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+                     0, G_MAXLONG, False, XA_ATOM, &type, &format, &atom_count,
+                     &bytes_after, alu.gu_extents);
+
+  if (type != None)
+    {
+      Atom maxvert = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
+      Atom maxhorz     = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
+
+      i = 0;
+      while (i < atom_count)
+        {
+         if (atom_list[i] == maxhorz)
+           new_state |= AWT_FRAME_STATE_MAXIMIZED_HORIZ;
+          else if (atom_list[i] == maxvert)
+           new_state |= AWT_FRAME_STATE_MAXIMIZED_VERT;
+
+          ++i;
+        }
+
+      XFree (atom_list);
+    }
+  return new_state;
+}
 
-void
-gdk_window_get_root_geometry (GdkWindow *window,
-                             gint      *x,
-                             gint      *y,
-                             gint      *width,
-                             gint      *height,
-                             gint      *border,
-                             gint      *depth)
+static gboolean
+window_property_changed_cb (GtkWidget *widget __attribute__((unused)),
+                            GdkEventProperty *event,
+                            jobject peer)
 {
-  GdkWindow *private;
-  unsigned int nchildren;
-  
-  g_return_if_fail (window != NULL);
-  
-  private = (GdkWindow*) window;
-  if (x)
-    *x = 0;
-  if (y)
-    *y = 0;
-  if (width)
-    *width = 0;
-  if (height)
-    *height = 0;
-  if (border)
-    *border = 0;
-  if (depth)
-    *depth = 0;
-
-  if (GDK_WINDOW_DESTROYED (private))
-    return;
-  
-  private = gdk_window_get_toplevel (private);
-  if (GDK_WINDOW_DESTROYED(private))
-    return;
+  unsigned long *extents;
+  union extents_union gu_ex;
+
+  gu_ex.extents = &extents;
+  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,
+                           gu_ex.gu_extents))
+    {
+      gdk_threads_leave ();
+      (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                                   postInsetsChangedEventID,
+                                   (jint) extents[2],  /* top */
+                                   (jint) extents[0],  /* left */
+                                   (jint) extents[3],  /* bottom */
+                                   (jint) extents[1]); /* right */
+      gdk_threads_enter ();
+    }
   
-  gdk_window_get_geometry (private, x, y, width, height, depth);
-      
+
+  return FALSE;
 }
 
+static void
+realize_cb (GtkWidget *widget, jobject peer)
+{
+  jint top = 0;
+  jint left = 0;
+  jint bottom = 0;
+  jint right = 0;
+  jint width = 0;
+  jint height = 0;
+
+  width = (*gdk_env())->CallIntMethod (gdk_env(), peer, windowGetWidthID);
+  height = (*gdk_env())->CallIntMethod (gdk_env(), peer, windowGetHeightID);
+
+  window_get_frame_extents (widget, &top, &left, &bottom, &right);
+
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer,
+                               postInsetsChangedEventID,
+                               top, left, bottom, right);
+
+  gtk_window_set_default_size (GTK_WINDOW (widget),
+                              MAX (1, width - left - right),
+                              MAX (1, height - top - bottom));
+
+  /* set the size like we do in nativeSetBounds */
+  gtk_widget_set_size_request (widget,
+                              MAX (1, width - left - right),
+                              MAX (1, height - top - bottom));
+
+  gtk_window_resize (GTK_WINDOW (widget),
+                    MAX (1, width - left - right),
+                    MAX (1, height - top - bottom));
+}