1 /* gtkwindowpeer.c -- Native implementation of GtkWindowPeer
2 Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 #include "gnu_java_awt_peer_gtk_GtkComponentPeer.h"
41 #include "gnu_java_awt_peer_gtk_GtkWindowPeer.h"
42 #include "gnu_java_awt_peer_gtk_GtkFramePeer.h"
43 #include <gdk/gdkprivate.h>
45 #include <X11/Xatom.h>
47 static void window_get_frame_extents (GtkWidget *window,
49 int *bottom, int *right);
51 static void request_frame_extents (GtkWidget *window);
53 static int property_notify_predicate (Display *xdisplay,
57 static void window_delete_cb (GtkWidget *widget, GdkEvent *event,
59 static void window_destroy_cb (GtkWidget *widget, GdkEvent *event,
61 static void window_show_cb (GtkWidget *widget, jobject peer);
62 static gboolean window_focus_in_cb (GtkWidget * widget,
65 static gboolean window_focus_out_cb (GtkWidget * widget,
68 static gboolean window_window_state_cb (GtkWidget *widget,
71 static jint window_get_new_state (GtkWidget *widget);
72 static gboolean window_property_changed_cb (GtkWidget *widget,
73 GdkEventProperty *event,
75 static void menubar_resize_cb (GtkWidget *widget, GtkAllocation *alloc,
82 JNIEXPORT void JNICALL
83 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create
84 (JNIEnv *env, jobject obj, jint type, jboolean decorated,
85 jint width, jint height, jobject parent, jintArray jinsets)
87 GtkWidget *window_widget;
98 insets = (*env)->GetIntArrayElements (env, jinsets, 0);
99 insets[0] = insets[1] = insets[2] = insets[3] = 0;
101 /* Create global reference and save it for future use */
102 NSA_SET_GLOBAL_REF (env, obj);
104 gdk_threads_enter ();
106 window_widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
107 window = GTK_WINDOW (window_widget);
109 /* Keep this window in front of its parent, if it has one. */
112 window_parent = NSA_GET_PTR (env, parent);
113 gtk_window_set_transient_for (window, GTK_WINDOW(window_parent));
116 gtk_window_set_decorated (window, decorated);
118 gtk_window_set_type_hint (window, type);
120 gtk_window_group_add_window (global_gtk_window_group, window);
122 vbox = gtk_vbox_new (0, 0);
123 layout = gtk_layout_new (NULL, NULL);
124 gtk_box_pack_end (GTK_BOX (vbox), layout, 1, 1, 0);
125 gtk_container_add (GTK_CONTAINER (window_widget), vbox);
127 gtk_widget_show (layout);
128 gtk_widget_show (vbox);
129 gtk_widget_realize (window_widget);
132 window_get_frame_extents (window_widget, &top, &left, &bottom, &right);
134 gtk_window_set_default_size (window,
135 MAX (1, width - left - right),
136 MAX (1, height - top - bottom));
138 /* We must set this window's size requisition. Otherwise when a
139 resize is queued (when gtk_widget_queue_resize is called) the
140 window will snap to its default requisition of 0x0. If we omit
141 this call, Frames and Dialogs shrink to degenerate 1x1 windows
142 when their resizable property changes. */
143 gtk_widget_set_size_request (window_widget,
144 MAX (1, width - left - right),
145 MAX (1, height - top - bottom));
152 gdk_threads_leave ();
154 (*env)->ReleaseIntArrayElements (env, jinsets, insets, 0);
156 NSA_SET_PTR (env, obj, window_widget);
159 JNIEXPORT void JNICALL
160 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetVisible
161 (JNIEnv *env, jobject obj, jboolean visible)
165 ptr = NSA_GET_PTR (env, obj);
167 gdk_threads_enter ();
170 gtk_widget_show (GTK_WIDGET (ptr));
172 gtk_widget_hide (GTK_WIDGET (ptr));
174 XFlush (GDK_DISPLAY ());
176 gdk_threads_leave ();
179 JNIEXPORT void JNICALL
180 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectJObject
181 (JNIEnv *env, jobject obj)
184 GtkWidget* vbox, *layout;
187 ptr = NSA_GET_PTR (env, obj);
189 gdk_threads_enter ();
191 children = gtk_container_get_children(GTK_CONTAINER(ptr));
192 vbox = children->data;
194 if(!GTK_IS_VBOX(vbox))
196 printf("*** this is not a vbox\n");
198 children = gtk_container_get_children(GTK_CONTAINER(vbox));
201 layout = children->data;
202 children = children->next;
204 while (!GTK_IS_LAYOUT (layout) && children != NULL);
206 if(!GTK_IS_LAYOUT(layout))
208 printf("*** widget is not a layout ***");
211 gtk_widget_realize (layout);
213 connect_awt_hook (env, obj, 1, GTK_LAYOUT (layout)->bin_window);
215 gtk_widget_realize (ptr);
217 connect_awt_hook (env, obj, 1, GTK_WIDGET (ptr)->window);
219 g_signal_connect (G_OBJECT (ptr), "property-notify-event",
220 G_CALLBACK (window_property_changed_cb), obj);
222 gdk_threads_leave ();
225 JNIEXPORT void JNICALL
226 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectSignals
227 (JNIEnv *env, jobject obj)
229 void *ptr = NSA_GET_PTR (env, obj);
230 jobject *gref = NSA_GET_GLOBAL_REF (env, obj);
233 gdk_threads_enter ();
235 gtk_widget_realize (ptr);
237 /* Connect signals for window event support. */
238 g_signal_connect (G_OBJECT (ptr), "delete-event",
239 G_CALLBACK (window_delete_cb), *gref);
241 g_signal_connect (G_OBJECT (ptr), "destroy-event",
242 G_CALLBACK (window_destroy_cb), *gref);
244 g_signal_connect (G_OBJECT (ptr), "show",
245 G_CALLBACK (window_show_cb), *gref);
247 g_signal_connect (G_OBJECT (ptr), "focus-in-event",
248 G_CALLBACK (window_focus_in_cb), *gref);
250 g_signal_connect (G_OBJECT (ptr), "focus-out-event",
251 G_CALLBACK (window_focus_out_cb), *gref);
253 g_signal_connect (G_OBJECT (ptr), "window-state-event",
254 G_CALLBACK (window_window_state_cb), *gref);
256 gdk_threads_leave ();
258 /* Connect the superclass signals. */
259 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectSignals (env, obj);
263 * Set a frame's title
266 JNIEXPORT void JNICALL
267 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setTitle
268 (JNIEnv *env, jobject obj, jstring title)
273 ptr = NSA_GET_PTR (env, obj);
275 str = (*env)->GetStringUTFChars (env, title, NULL);
277 gdk_threads_enter ();
278 gtk_window_set_title (GTK_WINDOW (ptr), str);
279 gdk_threads_leave ();
281 (*env)->ReleaseStringUTFChars (env, title, str);
285 * Lower the z-level of a window.
288 JNIEXPORT void JNICALL
289 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv *env,
293 ptr = NSA_GET_PTR (env, obj);
295 gdk_threads_enter ();
296 gdk_window_lower (GTK_WIDGET (ptr)->window);
298 XFlush (GDK_DISPLAY ());
299 gdk_threads_leave ();
303 * Raise the z-level of a window.
306 JNIEXPORT void JNICALL
307 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toFront (JNIEnv *env,
311 ptr = NSA_GET_PTR (env, obj);
313 gdk_threads_enter ();
314 gdk_window_raise (GTK_WIDGET (ptr)->window);
316 XFlush (GDK_DISPLAY ());
317 gdk_threads_leave ();
320 JNIEXPORT void JNICALL
321 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setBoundsCallback
322 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
323 jobject window, jint x, jint y, jint width, jint height)
325 /* Circumvent package-private access to call Window's
326 setBoundsCallback method. */
327 (*gdk_env)->CallVoidMethod (gdk_env, window, setBoundsCallbackID,
328 x, y, width, height);
331 JNIEXPORT void JNICALL
332 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setSize
333 (JNIEnv *env, jobject obj, jint width, jint height)
335 void *ptr = NSA_GET_PTR (env, obj);
337 /* Avoid GTK runtime assertion failures. */
338 width = (width < 1) ? 1 : width;
339 height = (height < 1) ? 1 : height;
341 gdk_threads_enter ();
342 gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
343 gdk_threads_leave ();
346 JNIEXPORT void JNICALL
347 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetBounds
348 (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height)
350 void *ptr = NSA_GET_PTR (env, obj);
352 /* Avoid GTK runtime assertion failures. */
353 width = (width < 1) ? 1 : width;
354 height = (height < 1) ? 1 : height;
356 gdk_threads_enter ();
357 gtk_window_move (GTK_WINDOW(ptr), x, y);
358 /* Need to change the widget's request size. */
359 gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
360 /* Also need to call gtk_window_resize. If the resize is requested
361 by the program and the window's "resizable" property is true then
362 the size request will not be honoured. */
363 gtk_window_resize (GTK_WINDOW (ptr), width, height);
364 gdk_threads_leave ();
367 JNIEXPORT void JNICALL
368 Java_gnu_java_awt_peer_gtk_GtkFramePeer_removeMenuBarPeer
369 (JNIEnv *env, jobject obj, jobject menubar)
375 wptr = NSA_GET_PTR (env, obj);
376 mptr = NSA_GET_PTR (env, menubar);
378 gdk_threads_enter ();
380 box = GTK_BIN (wptr)->child;
381 gtk_container_remove (GTK_CONTAINER (box), GTK_WIDGET (mptr));
386 JNIEXPORT void JNICALL
387 Java_gnu_java_awt_peer_gtk_GtkFramePeer_setMenuBarPeer
388 (JNIEnv *env, jobject obj, jobject menubar)
393 jobject *gref = NSA_GET_GLOBAL_REF (env, obj);
395 wptr = NSA_GET_PTR (env, obj);
396 mptr = NSA_GET_PTR (env, menubar);
398 gdk_threads_enter ();
400 g_signal_connect (G_OBJECT (mptr), "size-allocate",
401 G_CALLBACK (menubar_resize_cb), *gref);
402 box = GTK_BIN (wptr)->child;
403 gtk_box_pack_start (GTK_BOX (box), mptr, 0, 0, 0);
405 gtk_widget_show (mptr);
408 gdk_threads_leave ();
411 JNIEXPORT jint JNICALL
412 Java_gnu_java_awt_peer_gtk_GtkFramePeer_getMenuBarHeight
413 (JNIEnv *env, jobject obj, jobject menubar)
418 ptr = NSA_GET_PTR (env, menubar);
420 gdk_threads_enter ();
421 height = ptr->allocation.height;
422 gdk_threads_leave ();
427 window_get_frame_extents (GtkWidget *window,
428 int *top, int *left, int *bottom, int *right)
430 unsigned long *extents = NULL;
432 /* Guess frame extents in case _NET_FRAME_EXTENTS is not
439 /* Request that the window manager set window's
440 _NET_FRAME_EXTENTS property. */
441 request_frame_extents (window);
443 /* Attempt to retrieve window's frame extents. */
444 if (gdk_property_get (window->window,
445 gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
446 gdk_atom_intern ("CARDINAL", FALSE),
448 sizeof (unsigned long) * 4,
453 (guchar **)&extents))
456 *right = extents [1];
458 *bottom = extents [3];
462 static Atom extents_atom = 0;
464 /* Requests that the window manager set window's
465 _NET_FRAME_EXTENTS property. */
467 request_frame_extents (GtkWidget *window)
469 const char *request_str = "_NET_REQUEST_FRAME_EXTENTS";
470 GdkAtom request_extents = gdk_atom_intern (request_str, FALSE);
472 /* Check if the current window manager supports
473 _NET_REQUEST_FRAME_EXTENTS. */
474 if (gdk_net_wm_supports (request_extents))
476 GdkDisplay *display = gtk_widget_get_display (window);
477 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
479 GdkWindow *root_window = gdk_get_default_root_window ();
480 Window xroot_window = GDK_WINDOW_XID (root_window);
482 Atom extents_request_atom =
483 gdk_x11_get_xatom_by_name_for_display (display, request_str);
486 XEvent notify_xevent;
488 unsigned long window_id = GDK_WINDOW_XID (GDK_DRAWABLE(window->window));
492 const char *extents_str = "_NET_FRAME_EXTENTS";
494 gdk_x11_get_xatom_by_name_for_display (display, extents_str);
497 xevent.xclient.type = ClientMessage;
498 xevent.xclient.message_type = extents_request_atom;
499 xevent.xclient.display = xdisplay;
500 xevent.xclient.window = window_id;
501 xevent.xclient.format = 32;
502 xevent.xclient.data.l[0] = 0;
503 xevent.xclient.data.l[1] = 0;
504 xevent.xclient.data.l[2] = 0;
505 xevent.xclient.data.l[3] = 0;
506 xevent.xclient.data.l[4] = 0;
508 XSendEvent (xdisplay, xroot_window, False,
509 (SubstructureRedirectMask | SubstructureNotifyMask),
512 XIfEvent(xdisplay, ¬ify_xevent,
513 property_notify_predicate, (XPointer) &window_id);
518 property_notify_predicate (Display *xdisplay __attribute__((unused)),
522 unsigned long *window = (unsigned long *) window_id;
524 if (event->xany.type == PropertyNotify
525 && event->xany.window == *window
526 && event->xproperty.atom == extents_atom)
533 window_delete_cb (GtkWidget *widget __attribute__((unused)),
534 GdkEvent *event __attribute__((unused)),
537 (*gdk_env)->CallVoidMethod (gdk_env, peer,
539 (jint) AWT_WINDOW_CLOSING,
540 (jobject) NULL, (jint) 0);
544 window_destroy_cb (GtkWidget *widget __attribute__((unused)),
545 GdkEvent *event __attribute__((unused)),
548 (*gdk_env)->CallVoidMethod (gdk_env, peer,
550 (jint) AWT_WINDOW_CLOSED,
551 (jobject) NULL, (jint) 0);
555 window_show_cb (GtkWidget *widget __attribute__((unused)),
558 (*gdk_env)->CallVoidMethod (gdk_env, peer,
560 (jint) AWT_WINDOW_OPENED,
561 (jobject) NULL, (jint) 0);
565 window_focus_in_cb (GtkWidget * widget __attribute__((unused)),
566 GdkEventFocus *event __attribute__((unused)),
569 /* FIXME: when hiding then showing, we get two sets of
570 (LOST_FOCUS/DEACTIVATED, ACTIVATED/GAINED_FOCUS) events. */
571 (*gdk_env)->CallVoidMethod (gdk_env, peer,
573 (jint) AWT_WINDOW_ACTIVATED,
574 (jobject) NULL, (jint) 0);
576 (*gdk_env)->CallVoidMethod (gdk_env, peer,
578 (jint) AWT_WINDOW_GAINED_FOCUS,
579 (jobject) NULL, (jint) 0);
584 window_focus_out_cb (GtkWidget * widget __attribute__((unused)),
585 GdkEventFocus *event __attribute__((unused)),
588 (*gdk_env)->CallVoidMethod (gdk_env, peer,
590 (jint) AWT_WINDOW_LOST_FOCUS,
591 (jobject) NULL, (jint) 0);
593 (*gdk_env)->CallVoidMethod (gdk_env, peer,
595 (jint) AWT_WINDOW_DEACTIVATED,
596 (jobject) NULL, (jint) 0);
601 window_window_state_cb (GtkWidget *widget,
607 /* Handle WINDOW_ICONIFIED and WINDOW_DEICONIFIED events. */
608 if (event->window_state.changed_mask & GDK_WINDOW_STATE_ICONIFIED)
610 /* We've either been iconified or deiconified. */
611 if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
613 /* We've been iconified. */
614 (*gdk_env)->CallVoidMethod (gdk_env, peer,
616 (jint) AWT_WINDOW_ICONIFIED,
617 (jobject) NULL, (jint) 0);
621 /* We've been deiconified. */
622 (*gdk_env)->CallVoidMethod (gdk_env, peer,
624 (jint) AWT_WINDOW_DEICONIFIED,
625 (jobject) NULL, (jint) 0);
629 /* Post a WINDOW_STATE_CHANGED event, passing the new frame state to
631 new_state = AWT_FRAME_STATE_NORMAL;
633 if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
634 new_state |= AWT_FRAME_STATE_ICONIFIED;
636 new_state |= window_get_new_state (widget);
638 (*gdk_env)->CallVoidMethod (gdk_env, peer,
640 (jint) AWT_WINDOW_STATE_CHANGED,
641 (jobject) NULL, new_state);
646 window_get_new_state (GtkWidget *widget)
648 GdkDisplay *display = gtk_widget_get_display(widget);
649 jint new_state = AWT_FRAME_STATE_NORMAL;
654 Atom *atom_list = NULL;
657 XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window),
658 gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
659 0, G_MAXLONG, False, XA_ATOM, &type, &format, &atom_count,
660 &bytes_after, (guchar **)&atom_list);
664 Atom maxvert = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
665 Atom maxhorz = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
668 while (i < atom_count)
670 if (atom_list[i] == maxhorz)
671 new_state |= AWT_FRAME_STATE_MAXIMIZED_HORIZ;
672 else if (atom_list[i] == maxvert)
673 new_state |= AWT_FRAME_STATE_MAXIMIZED_VERT;
684 window_property_changed_cb (GtkWidget *widget __attribute__((unused)),
685 GdkEventProperty *event,
688 unsigned long *extents;
690 static int id_set = 0;
691 static jmethodID postInsetsChangedEventID;
695 jclass gtkwindowpeer = (*gdk_env)->FindClass (gdk_env,
696 "gnu/java/awt/peer/gtk/GtkWindowPeer");
697 postInsetsChangedEventID = (*gdk_env)->GetMethodID (gdk_env,
699 "postInsetsChangedEvent",
704 if (gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE) == event->atom
705 && gdk_property_get (event->window,
706 gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
707 gdk_atom_intern ("CARDINAL", FALSE),
709 sizeof (unsigned long) * 4,
714 (guchar **)&extents))
715 (*gdk_env)->CallVoidMethod (gdk_env, peer,
716 postInsetsChangedEventID,
717 (jint) extents[2], /* top */
718 (jint) extents[0], /* left */
719 (jint) extents[3], /* bottom */
720 (jint) extents[1]); /* right */
725 static void menubar_resize_cb (GtkWidget *widget, GtkAllocation *alloc,
728 static int id_set = 0;
729 static jmethodID postSizeAllocateEventID;
733 jclass gtkframepeer = (*gdk_env)->FindClass (gdk_env,
734 "gnu/java/awt/peer/gtk/GtkFramePeer");
735 postSizeAllocateEventID = (*gdk_env)->GetMethodID (gdk_env,
737 "postSizeAllocateEvent",
742 (*gdk_env)->CallVoidMethod (gdk_env, peer,
743 postSizeAllocateEventID);