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