Index: ChangeLog =================================================================== RCS file: /cvsroot/classpath/classpath/ChangeLog,v retrieving revision 1.1763 diff -u -r1.1763 ChangeLog --- ChangeLog 7 Jan 2004 02:23:37 -0000 1.1763 +++ ChangeLog 13 Jan 2004 22:23:43 -0000 @@ -1,3 +1,33 @@ +2004-01-13 Thomas Fitzsimmons + + * 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. + 2004-01-06 Graydon Hoare * configure.in: Add --enable-gtk-cairo check. Index: gnu/java/awt/peer/gtk/GtkComponentPeer.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java,v retrieving revision 1.56 diff -u -r1.56 GtkComponentPeer.java --- gnu/java/awt/peer/gtk/GtkComponentPeer.java 7 Jan 2004 02:23:37 -0000 1.56 +++ gnu/java/awt/peer/gtk/GtkComponentPeer.java 13 Jan 2004 22:23:43 -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: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java,v retrieving revision 1.18 diff -u -r1.18 GtkDialogPeer.java --- gnu/java/awt/peer/gtk/GtkDialogPeer.java 24 Oct 2003 19:54:22 -0000 1.18 +++ gnu/java/awt/peer/gtk/GtkDialogPeer.java 13 Jan 2004 22:23:43 -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: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java,v retrieving revision 1.17 diff -u -r1.17 GtkFramePeer.java --- gnu/java/awt/peer/gtk/GtkFramePeer.java 7 Jan 2004 02:23:37 -0000 1.17 +++ gnu/java/awt/peer/gtk/GtkFramePeer.java 13 Jan 2004 22:23:43 -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: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java,v retrieving revision 1.25 diff -u -r1.25 GtkWindowPeer.java --- gnu/java/awt/peer/gtk/GtkWindowPeer.java 7 Jan 2004 02:23:37 -0000 1.25 +++ gnu/java/awt/peer/gtk/GtkWindowPeer.java 13 Jan 2004 22:23:43 -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: include/gnu_java_awt_peer_gtk_GtkWindowPeer.h =================================================================== RCS file: /cvsroot/classpath/classpath/include/gnu_java_awt_peer_gtk_GtkWindowPeer.h,v retrieving revision 1.7 diff -u -r1.7 gnu_java_awt_peer_gtk_GtkWindowPeer.h --- include/gnu_java_awt_peer_gtk_GtkWindowPeer.h 7 Jan 2004 02:23:37 -0000 1.7 +++ include/gnu_java_awt_peer_gtk_GtkWindowPeer.h 13 Jan 2004 22:23:43 -0000 @@ -10,7 +10,7 @@ { #endif -extern JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create__IZIILgnu_java_awt_peer_gtk_GtkWindowPeer_2 (JNIEnv *env, jobject, jint, jboolean, jint, jint, jobject); +extern JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create__IZIILgnu_java_awt_peer_gtk_GtkWindowPeer_2_3I (JNIEnv *env, jobject, jint, jboolean, jint, jint, jobject, jintArray); extern JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectJObject (JNIEnv *env, jobject); extern JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectSignals (JNIEnv *env, jobject); extern JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv *env, jobject); Index: native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c,v retrieving revision 1.18 diff -u -r1.18 gnu_java_awt_peer_gtk_GtkEvents.c --- native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c 7 Jan 2004 02:23:37 -0000 1.18 +++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c 13 Jan 2004 22:23:50 -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: native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c,v retrieving revision 1.14 diff -u -r1.14 gnu_java_awt_peer_gtk_GtkMainThread.c --- native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c 7 Jan 2004 02:23:37 -0000 1.14 +++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c 13 Jan 2004 22:23:50 -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: native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c,v retrieving revision 1.15 diff -u -r1.15 gnu_java_awt_peer_gtk_GtkWindowPeer.c --- native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c 7 Jan 2004 02:23:37 -0000 1.15 +++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c 13 Jan 2004 22:23:50 -0000 @@ -44,6 +44,16 @@ #include #include +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, ¬ify_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; }