OSDN Git Service

2004-07-21 Michael Koch <konqueror@gmx.de>
[pf3gnuchains/gcc-fork.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkWindowPeer.c
1 /* gtkwindowpeer.c -- Native implementation of GtkWindowPeer
2    Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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)
9 any later version.
10
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.
15
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
19 02111-1307 USA.
20
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
24 combination.
25
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. */
37
38
39 #include "gtkpeer.h"
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>
44 #include <gdk/gdkx.h>
45 #include <X11/Xatom.h>
46
47 /* FIXME: we're currently seeing the double-activation that occurs
48    with metacity and GTK.  See
49    http://bugzilla.gnome.org/show_bug.cgi?id=140977 for details. */
50
51 static void window_get_frame_extents (GtkWidget *window,
52                                       int *top, int *left,
53                                       int *bottom, int *right);
54
55 static void request_frame_extents (GtkWidget *window);
56
57 static Bool property_notify_predicate (Display *display,
58                                        XEvent  *xevent,
59                                        XPointer arg);
60
61 static GtkLayout *find_layout (GtkWindow *window);
62
63 static void window_delete_cb (GtkWidget *widget, GdkEvent *event,
64                               jobject peer);
65 static void window_destroy_cb (GtkWidget *widget, GdkEvent *event,
66                                jobject peer);
67 static void window_show_cb (GtkWidget *widget, jobject peer);
68 static void window_active_state_change_cb (GtkWidget *widget,
69                                            GParamSpec *pspec,
70                                            jobject peer);
71 static void window_focus_state_change_cb (GtkWidget *widget,
72                                                     GParamSpec *pspec,
73                                                     jobject peer);
74 static gboolean window_focus_in_cb (GtkWidget * widget,
75                                     GdkEventFocus *event,
76                                     jobject peer);
77 static gboolean window_focus_out_cb (GtkWidget * widget,
78                                      GdkEventFocus *event,
79                                      jobject peer);
80 static gboolean window_window_state_cb (GtkWidget *widget,
81                                         GdkEvent *event,
82                                         jobject peer);
83 static jint window_get_new_state (GtkWidget *widget);
84 static gboolean window_property_changed_cb (GtkWidget *widget,
85                                             GdkEventProperty *event,
86                                             jobject peer);
87
88 JNIEXPORT void JNICALL 
89 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create 
90   (JNIEnv *env, jobject obj, jint type, jboolean decorated,
91    jint width, jint height, jobject parent, jintArray jinsets)
92 {
93   GtkWidget *window_widget;
94   GtkWindow *window;
95   void *window_parent;
96   GtkWidget *vbox;
97   GtkWidget *layout;
98   int top = 0;
99   int left = 0;
100   int bottom = 0;
101   int right = 0;
102   jint *insets;
103
104   insets = (*env)->GetIntArrayElements (env, jinsets, 0);
105   insets[0] = insets[1] = insets[2] = insets[3] = 0;
106
107   /* Create global reference and save it for future use */
108   NSA_SET_GLOBAL_REF (env, obj);
109
110   gdk_threads_enter ();
111   
112   window_widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
113   window = GTK_WINDOW (window_widget);
114
115   /* Keep this window in front of its parent, if it has one. */
116   if (parent)
117     {
118       window_parent = NSA_GET_PTR (env, parent);
119       gtk_window_set_transient_for (window, GTK_WINDOW(window_parent));
120     }
121
122   gtk_window_set_decorated (window, decorated);
123
124   gtk_window_set_type_hint (window, type);
125
126   gtk_window_group_add_window (global_gtk_window_group, window);
127
128   vbox = gtk_vbox_new (0, 0);
129   layout = gtk_layout_new (NULL, NULL);
130   gtk_box_pack_end (GTK_BOX (vbox), layout, 1, 1, 0);
131   gtk_container_add (GTK_CONTAINER (window_widget), vbox);
132
133   gtk_widget_show (layout);
134   gtk_widget_show (vbox);
135   gtk_widget_realize (window_widget);
136
137   if (decorated)
138     window_get_frame_extents (window_widget, &top, &left, &bottom, &right);
139
140   gtk_window_set_default_size (window,
141                                MAX (1, width - left - right),
142                                MAX (1, height - top - bottom));
143
144   /* We must set this window's size requisition.  Otherwise when a
145      resize is queued (when gtk_widget_queue_resize is called) the
146      window will snap to its default requisition of 0x0.  If we omit
147      this call, Frames and Dialogs shrink to degenerate 1x1 windows
148      when their resizable property changes. */
149   gtk_widget_set_size_request (window_widget,
150                                MAX (1, width - left - right),
151                                MAX (1, height - top - bottom));
152
153   insets[0] = top;
154   insets[1] = left;
155   insets[2] = bottom;
156   insets[3] = right;
157
158   gdk_threads_leave ();
159
160   (*env)->ReleaseIntArrayElements (env, jinsets, insets, 0);
161
162   NSA_SET_PTR (env, obj, window_widget);
163 }
164
165 JNIEXPORT void JNICALL
166 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetVisible
167   (JNIEnv *env, jobject obj, jboolean visible)
168 {
169   void *ptr;
170
171   ptr = NSA_GET_PTR (env, obj);
172
173   gdk_threads_enter ();
174
175   if (visible)
176     gtk_widget_show (GTK_WIDGET (ptr));
177   else
178     gtk_widget_hide (GTK_WIDGET (ptr));
179
180   XFlush (GDK_DISPLAY ());
181
182   gdk_threads_leave ();
183 }
184
185 JNIEXPORT void JNICALL
186 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectJObject
187   (JNIEnv *env, jobject obj)
188 {
189   void *ptr;
190   GtkLayout *layout;
191
192   ptr = NSA_GET_PTR (env, obj);
193
194   gdk_threads_enter ();
195
196   layout = find_layout (GTK_WINDOW (ptr));
197
198   gtk_widget_realize (GTK_WIDGET (layout));
199
200   connect_awt_hook (env, obj, 1, layout->bin_window);
201
202   gtk_widget_realize (ptr);
203
204   connect_awt_hook (env, obj, 1, GTK_WIDGET (ptr)->window);
205
206   gdk_threads_leave ();
207 }
208
209 JNIEXPORT void JNICALL
210 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectSignals
211   (JNIEnv *env, jobject obj)
212 {
213   void *ptr;
214   jobject *gref;
215   GtkLayout *layout;
216
217   ptr = NSA_GET_PTR (env, obj);
218
219   gref = NSA_GET_GLOBAL_REF (env, obj);
220
221   gdk_threads_enter ();
222
223   gtk_widget_realize (ptr);
224
225   /* Receive events from the GtkLayout too */
226   layout = find_layout (GTK_WINDOW (ptr));
227
228   g_signal_connect (G_OBJECT (layout), "event",
229                     G_CALLBACK (pre_event_handler), *gref);
230
231   /* Connect signals for window event support. */
232   g_signal_connect (G_OBJECT (ptr), "delete-event",
233                     G_CALLBACK (window_delete_cb), *gref);
234
235   g_signal_connect (G_OBJECT (ptr), "destroy-event",
236                     G_CALLBACK (window_destroy_cb), *gref);
237
238   g_signal_connect (G_OBJECT (ptr), "show",
239                     G_CALLBACK (window_show_cb), *gref);
240
241   g_signal_connect (G_OBJECT (ptr), "notify::is-active",
242                     G_CALLBACK (window_active_state_change_cb), *gref);
243
244   g_signal_connect (G_OBJECT (ptr), "notify::has-toplevel-focus",
245                     G_CALLBACK (window_focus_state_change_cb), *gref);
246
247   g_signal_connect (G_OBJECT (ptr), "focus-in-event",
248                     G_CALLBACK (window_focus_in_cb), *gref);
249
250   g_signal_connect (G_OBJECT (ptr), "focus-out-event",
251                     G_CALLBACK (window_focus_out_cb), *gref);
252
253   g_signal_connect (G_OBJECT (ptr), "window-state-event",
254                     G_CALLBACK (window_window_state_cb), *gref);
255
256   g_signal_connect (G_OBJECT (ptr), "property-notify-event",
257                     G_CALLBACK (window_property_changed_cb), *gref);
258
259   gdk_threads_leave ();
260
261   /* Connect the superclass signals.  */
262   Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectSignals (env, obj);
263 }
264
265 /*
266  * Lower the z-level of a window. 
267  */
268
269 JNIEXPORT void JNICALL 
270 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv *env, 
271     jobject obj)
272 {
273   void *ptr;
274   ptr = NSA_GET_PTR (env, obj);
275     
276   gdk_threads_enter ();
277   gdk_window_lower (GTK_WIDGET (ptr)->window);
278
279   XFlush (GDK_DISPLAY ());
280   gdk_threads_leave ();
281 }
282
283 /*
284  * Raise the z-level of a window.
285  */
286
287 JNIEXPORT void JNICALL 
288 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toFront (JNIEnv *env, 
289     jobject obj)
290 {
291   void *ptr;
292   ptr = NSA_GET_PTR (env, obj);
293     
294   gdk_threads_enter ();
295   gdk_window_raise (GTK_WIDGET (ptr)->window);
296
297   XFlush (GDK_DISPLAY ());
298   gdk_threads_leave ();
299 }
300
301 JNIEXPORT void JNICALL
302 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setBoundsCallback
303   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
304    jobject window, jint x, jint y, jint width, jint height)
305 {
306   /* Circumvent package-private access to call Window's
307      setBoundsCallback method. */
308   (*gdk_env)->CallVoidMethod (gdk_env, window, setBoundsCallbackID,
309                               x, y, width, height);
310 }
311
312 JNIEXPORT void JNICALL
313 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setSize
314   (JNIEnv *env, jobject obj, jint width, jint height)
315 {
316   void *ptr = NSA_GET_PTR (env, obj);
317
318   /* Avoid GTK runtime assertion failures. */
319   width = (width < 1) ? 1 : width;
320   height = (height < 1) ? 1 : height;
321
322   gdk_threads_enter ();
323   gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
324   gdk_threads_leave ();
325 }
326
327 JNIEXPORT void JNICALL
328 Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetBounds
329   (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height)
330 {
331   void *ptr = NSA_GET_PTR (env, obj);
332
333   /* Avoid GTK runtime assertion failures. */
334   width = (width < 1) ? 1 : width;
335   height = (height < 1) ? 1 : height;
336
337   gdk_threads_enter ();
338   gtk_window_move (GTK_WINDOW(ptr), x, y);
339   /* The call to gdk_window_move is needed in addition to the call to
340      gtk_window_move.  If gdk_window_move isn't called, then the
341      following set of operations doesn't give the expected results:
342
343      1. show a window
344      2. manually move it to another position on the screen
345      3. hide the window
346      4. reposition the window with Component.setLocation
347      5. show the window
348
349      Instead of being at the position set by setLocation, the window
350      is reshown at the position to which it was moved manually. */
351   gdk_window_move (GTK_WIDGET (ptr)->window, x, y);
352
353   /* Need to change the widget's request size. */
354   gtk_widget_set_size_request (GTK_WIDGET(ptr), width, height);
355   /* Also need to call gtk_window_resize.  If the resize is requested
356      by the program and the window's "resizable" property is true then
357      the size request will not be honoured. */
358   gtk_window_resize (GTK_WINDOW (ptr), width, height);
359   gdk_threads_leave ();
360 }
361
362 JNIEXPORT void JNICALL
363 Java_gnu_java_awt_peer_gtk_GtkFramePeer_removeMenuBarPeer
364   (JNIEnv *env, jobject obj)
365 {
366   void *wptr;
367   GtkWidget *box;
368   GtkWidget *mptr;
369   GList* children;
370
371   wptr = NSA_GET_PTR (env, obj);
372   
373   gdk_threads_enter ();
374
375   box = GTK_BIN (wptr)->child;
376   
377   children = gtk_container_get_children (GTK_CONTAINER (box));
378   
379   while (children != NULL && !GTK_IS_MENU_SHELL (children->data)) 
380   {
381     children = children->next;
382   }
383   
384   /* If there isn't a MenuBar in this Frame's list of children
385      then we can just return. */
386   if (!GTK_IS_MENU_SHELL (children->data))
387     return;
388   else
389     mptr = children->data;
390     
391   /* This will actually destroy the MenuBar. By removing it from
392      its parent, the reference count for the MenuBar widget will
393      decrement to 0. The widget will be automatically destroyed 
394      by Gtk. */
395   gtk_container_remove (GTK_CONTAINER (box), GTK_WIDGET (mptr));  
396   
397   gdk_threads_leave();
398 }  
399   
400 JNIEXPORT void JNICALL
401 Java_gnu_java_awt_peer_gtk_GtkFramePeer_setMenuBarPeer
402   (JNIEnv *env, jobject obj, jobject menubar)
403 {
404   void *wptr;
405   GtkWidget *mptr;
406   GtkWidget *box;
407
408   wptr = NSA_GET_PTR (env, obj);
409   mptr = NSA_GET_PTR (env, menubar);
410   
411   gdk_threads_enter ();
412
413   box = GTK_BIN (wptr)->child;              
414   gtk_box_pack_start (GTK_BOX (box), mptr, 0, 0, 0);
415  
416   gtk_widget_show (mptr);
417
418  
419   gdk_threads_leave ();
420 }
421
422 JNIEXPORT jint JNICALL
423 Java_gnu_java_awt_peer_gtk_GtkFramePeer_getMenuBarHeight
424   (JNIEnv *env, jobject obj __attribute__((unused)), jobject menubar)
425 {
426   GtkWidget *ptr;
427   jint height;
428   GtkRequisition gtkreq;
429   
430   ptr = NSA_GET_PTR (env, menubar);
431
432   gdk_threads_enter ();
433   gtk_widget_size_request (ptr, &gtkreq);
434
435   height = gtkreq.height;
436   gdk_threads_leave ();
437   return height;
438 }
439
440 JNIEXPORT void JNICALL
441 Java_gnu_java_awt_peer_gtk_GtkFramePeer_moveLayout
442   (JNIEnv *env, jobject obj, jint offset)
443 {
444   void* ptr;
445   GList* children;
446   GtkLayout* layout;
447   GtkWidget* widget;
448
449   ptr = NSA_GET_PTR (env, obj);
450
451   gdk_threads_enter ();
452
453   layout = find_layout (GTK_WINDOW (ptr));
454
455   children = gtk_container_get_children (GTK_CONTAINER (layout));
456   
457   while (children != NULL)
458   {
459     widget = children->data;
460     gtk_layout_move (layout, widget, widget->allocation.x,
461                      widget->allocation.y+offset);
462     children = children->next;
463   }
464   
465   gdk_threads_leave ();
466 }
467   
468 JNIEXPORT void JNICALL
469 Java_gnu_java_awt_peer_gtk_GtkFramePeer_gtkLayoutSetVisible
470   (JNIEnv *env, jobject obj, jboolean visible)
471 {
472   void* ptr;
473   GtkLayout* layout;
474
475   ptr = NSA_GET_PTR (env, obj);
476
477   gdk_threads_enter ();
478
479   layout = find_layout (GTK_WINDOW (ptr));
480   
481   if (visible)
482     gtk_widget_show (GTK_WIDGET (layout));
483   else
484     gtk_widget_hide (GTK_WIDGET (layout));
485
486   gdk_threads_leave ();
487 }
488
489 static void
490 window_get_frame_extents (GtkWidget *window,
491                           int *top, int *left, int *bottom, int *right)
492 {
493   unsigned long *extents = NULL;
494
495   /* Guess frame extents in case _NET_FRAME_EXTENTS is not
496      supported. */
497   *top = 23;
498   *left = 6;
499   *bottom = 6;
500   *right = 6;
501
502   /* Request that the window manager set window's
503      _NET_FRAME_EXTENTS property. */
504   request_frame_extents (window);
505
506   /* Attempt to retrieve window's frame extents. */
507   if (gdk_property_get (window->window,
508                         gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
509                         gdk_atom_intern ("CARDINAL", FALSE),
510                         0,
511                         sizeof (unsigned long) * 4,
512                         FALSE,
513                         NULL,
514                         NULL,
515                         NULL,
516                         (guchar **)&extents))
517     {
518       *left = extents [0];
519       *right = extents [1];
520       *top = extents [2];
521       *bottom = extents [3];
522     }
523 }
524
525 static Atom extents_atom = 0;
526
527 /* Requests that the window manager set window's
528    _NET_FRAME_EXTENTS property. */
529 static void
530 request_frame_extents (GtkWidget *window)
531 {
532   const char *request_str = "_NET_REQUEST_FRAME_EXTENTS";
533   GdkAtom request_extents = gdk_atom_intern (request_str, FALSE);
534
535   /* Check if the current window manager supports
536      _NET_REQUEST_FRAME_EXTENTS. */
537   if (gdk_net_wm_supports (request_extents))
538     {
539       GdkDisplay *display = gtk_widget_get_display (window);
540       Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
541
542       GdkWindow *root_window = gdk_get_default_root_window ();
543       Window xroot_window = GDK_WINDOW_XID (root_window);
544
545       Atom extents_request_atom =
546         gdk_x11_get_xatom_by_name_for_display (display, request_str);
547
548       XEvent xevent;
549       XEvent notify_xevent;
550
551       unsigned long window_id = GDK_WINDOW_XID (GDK_DRAWABLE(window->window));
552
553       if (!extents_atom)
554         {
555           const char *extents_str = "_NET_FRAME_EXTENTS";
556           extents_atom =
557             gdk_x11_get_xatom_by_name_for_display (display, extents_str);
558         }
559
560       xevent.xclient.type = ClientMessage;
561       xevent.xclient.message_type = extents_request_atom;
562       xevent.xclient.display = xdisplay;
563       xevent.xclient.window = window_id;
564       xevent.xclient.format = 32;
565       xevent.xclient.data.l[0] = 0;
566       xevent.xclient.data.l[1] = 0;
567       xevent.xclient.data.l[2] = 0;
568       xevent.xclient.data.l[3] = 0;
569       xevent.xclient.data.l[4] = 0;
570
571       XSendEvent (xdisplay, xroot_window, False,
572                   (SubstructureRedirectMask | SubstructureNotifyMask),
573                   &xevent);
574
575       XIfEvent(xdisplay, &notify_xevent,
576                property_notify_predicate, (XPointer) &window_id);
577     }
578 }
579
580 static Bool
581 property_notify_predicate (Display *xdisplay __attribute__((unused)),
582                            XEvent  *event,
583                            XPointer window_id)
584 {
585   unsigned long *window = (unsigned long *) window_id;
586
587   if (event->xany.type == PropertyNotify
588       && event->xany.window == *window
589       && event->xproperty.atom == extents_atom)
590         return True;
591   else
592   return False;
593 }
594
595 static void
596 window_delete_cb (GtkWidget *widget __attribute__((unused)),
597                   GdkEvent *event __attribute__((unused)),
598                   jobject peer)
599 {
600   (*gdk_env)->CallVoidMethod (gdk_env, peer,
601                               postWindowEventID,
602                               (jint) AWT_WINDOW_CLOSING,
603                               (jobject) NULL, (jint) 0);
604 }
605
606 static void
607 window_destroy_cb (GtkWidget *widget __attribute__((unused)),
608                    GdkEvent *event __attribute__((unused)),
609                    jobject peer)
610 {
611   (*gdk_env)->CallVoidMethod (gdk_env, peer,
612                               postWindowEventID,
613                               (jint) AWT_WINDOW_CLOSED,
614                               (jobject) NULL, (jint) 0);
615 }
616
617 static void
618 window_show_cb (GtkWidget *widget __attribute__((unused)),
619                 jobject peer)
620 {
621   (*gdk_env)->CallVoidMethod (gdk_env, peer,
622                               postWindowEventID,
623                               (jint) AWT_WINDOW_OPENED,
624                               (jobject) NULL, (jint) 0);
625 }
626
627 static void
628 window_active_state_change_cb (GtkWidget *widget,
629                                         GParamSpec *pspec,
630                                         jobject peer)
631 {
632   /* FIXME: not sure if this is needed or not. */
633 #if 0
634       if (GTK_WINDOW (widget)->is_active)
635         (*gdk_env)->CallVoidMethod (gdk_env, peer,
636                                     postWindowEventID,
637                                     (jint) AWT_WINDOW_GAINED_FOCUS,
638                                     (jobject) NULL, (jint) 0);
639       else
640         (*gdk_env)->CallVoidMethod (gdk_env, peer,
641                                     postWindowEventID,
642                                     (jint) AWT_WINDOW_DEACTIVATED,
643                                     (jobject) NULL, (jint) 0);
644 #endif
645     }
646
647 static void
648 window_focus_state_change_cb (GtkWidget *widget,
649                               GParamSpec *pspec,
650                               jobject peer)
651     {
652       if (GTK_WINDOW (widget)->has_toplevel_focus)
653         (*gdk_env)->CallVoidMethod (gdk_env, peer,
654                                     postWindowEventID,
655                                     (jint) AWT_WINDOW_ACTIVATED,
656                                     (jobject) NULL, (jint) 0);
657       else
658         (*gdk_env)->CallVoidMethod (gdk_env, peer,
659                                     postWindowEventID,
660                                 (jint) AWT_WINDOW_DEACTIVATED,
661                                     (jobject) NULL, (jint) 0);
662     }
663
664 static gboolean
665 window_focus_in_cb (GtkWidget * widget,
666                    GdkEventFocus *event,
667                    jobject peer)
668 {
669   (*gdk_env)->CallVoidMethod (gdk_env, peer,
670                               postWindowEventID,
671                               (jint) AWT_WINDOW_GAINED_FOCUS,
672                               (jobject) NULL, (jint) 0);
673   return FALSE;
674 }
675
676 static gboolean
677 window_focus_out_cb (GtkWidget * widget,
678                     GdkEventFocus *event,
679                     jobject peer)
680 {
681   (*gdk_env)->CallVoidMethod (gdk_env, peer,
682                               postWindowEventID,
683                               (jint) AWT_WINDOW_LOST_FOCUS,
684                               (jobject) NULL, (jint) 0);
685   return FALSE;
686 }
687
688 static gboolean
689 window_window_state_cb (GtkWidget *widget,
690                         GdkEvent *event,
691                         jobject peer)
692 {
693   jint new_state;
694
695   /* Handle WINDOW_ICONIFIED and WINDOW_DEICONIFIED events. */
696   if (event->window_state.changed_mask & GDK_WINDOW_STATE_ICONIFIED)
697     {
698       /* We've either been iconified or deiconified. */
699       if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
700         {
701           /* We've been iconified. */
702           (*gdk_env)->CallVoidMethod (gdk_env, peer,
703                                       postWindowEventID,
704                                       (jint) AWT_WINDOW_ICONIFIED,
705                                       (jobject) NULL, (jint) 0);
706         }
707       else
708         {
709           /* We've been deiconified. */
710           (*gdk_env)->CallVoidMethod (gdk_env, peer,
711                                       postWindowEventID,
712                                       (jint) AWT_WINDOW_DEICONIFIED,
713                                       (jobject) NULL, (jint) 0);
714         }
715     }
716
717   /* Post a WINDOW_STATE_CHANGED event, passing the new frame state to
718      GtkWindowPeer. */
719   new_state = AWT_FRAME_STATE_NORMAL;
720
721   if (event->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED)
722     new_state |= AWT_FRAME_STATE_ICONIFIED;
723
724   new_state |= window_get_new_state (widget);
725
726   (*gdk_env)->CallVoidMethod (gdk_env, peer,
727                               postWindowEventID,
728                               (jint) AWT_WINDOW_STATE_CHANGED,
729                               (jobject) NULL, new_state);
730   return TRUE;
731 }
732
733 static jint
734 window_get_new_state (GtkWidget *widget)
735 {
736   GdkDisplay *display = gtk_widget_get_display(widget);
737   jint new_state = AWT_FRAME_STATE_NORMAL;
738   Atom type;
739   gint format;
740   gulong atom_count;
741   gulong bytes_after;
742   Atom *atom_list = NULL;
743   gulong i;
744
745   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window),
746                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
747                       0, G_MAXLONG, False, XA_ATOM, &type, &format, &atom_count,
748                       &bytes_after, (guchar **)&atom_list);
749
750   if (type != None)
751     {
752       Atom maxvert = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
753       Atom maxhorz      = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
754
755       i = 0;
756       while (i < atom_count)
757         {
758           if (atom_list[i] == maxhorz)
759             new_state |= AWT_FRAME_STATE_MAXIMIZED_HORIZ;
760           else if (atom_list[i] == maxvert)
761             new_state |= AWT_FRAME_STATE_MAXIMIZED_VERT;
762
763           ++i;
764         }
765
766       XFree (atom_list);
767     }
768   return new_state;
769 }
770
771 static gboolean
772 window_property_changed_cb (GtkWidget *widget __attribute__((unused)),
773                             GdkEventProperty *event,
774                             jobject peer)
775 {
776   unsigned long *extents;
777
778   static int id_set = 0;
779   static jmethodID postInsetsChangedEventID;
780
781   if (!id_set)
782     {
783       jclass gtkwindowpeer = (*gdk_env)->FindClass (gdk_env,
784                                  "gnu/java/awt/peer/gtk/GtkWindowPeer");
785       postInsetsChangedEventID = (*gdk_env)->GetMethodID (gdk_env,
786                                                       gtkwindowpeer,
787                                                       "postInsetsChangedEvent",
788                                                       "(IIII)V");
789       id_set = 1;
790     }
791
792   if (gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE) == event->atom
793       && gdk_property_get (event->window,
794                            gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
795                            gdk_atom_intern ("CARDINAL", FALSE),
796                            0,
797                            sizeof (unsigned long) * 4,
798                            FALSE,
799                            NULL,
800                            NULL,
801                            NULL,
802                            (guchar **)&extents))
803     (*gdk_env)->CallVoidMethod (gdk_env, peer,
804                                 postInsetsChangedEventID,
805                                 (jint) extents[2],  /* top */
806                                 (jint) extents[0],  /* left */
807                                 (jint) extents[3],  /* bottom */
808                                 (jint) extents[1]); /* right */
809
810   return FALSE;
811 }
812
813 static GtkLayout *
814 find_layout (GtkWindow *window)
815 {
816   GList* children;
817   GtkBox* vbox;
818   GtkLayout* layout;
819
820   children = gtk_container_get_children (GTK_CONTAINER (window));
821   vbox = children->data;
822   g_assert (GTK_IS_VBOX (vbox));
823
824   children = gtk_container_get_children (GTK_CONTAINER (vbox));
825   do
826   {
827     layout = children->data;
828     children = children->next;
829   }
830   while (!GTK_IS_LAYOUT (layout) && children != NULL);
831   g_assert (GTK_IS_LAYOUT (layout));
832
833   return layout;
834 }