OSDN Git Service

Imported GNU Classpath 0.20
[pf3gnuchains/gcc-fork.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkToolkit.c
1 /* gtktoolkit.c -- Native portion of GtkToolkit
2    Copyright (C) 1998, 1999, 2005  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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 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_GtkToolkit.h"
41 #include "gthread-jni.h"
42 #include "jcl.h"
43 #include <gdk/gdkx.h>
44
45 #define RC_FILE ".classpath-gtkrc"
46
47 /* From java.awt.SystemColor */
48 #define AWT_DESKTOP                  0
49 #define AWT_ACTIVE_CAPTION           1
50 #define AWT_ACTIVE_CAPTION_TEXT      2
51 #define AWT_ACTIVE_CAPTION_BORDER    3
52 #define AWT_INACTIVE_CAPTION         4
53 #define AWT_INACTIVE_CAPTION_TEXT    5
54 #define AWT_INACTIVE_CAPTION_BORDER  6
55 #define AWT_WINDOW                   7
56 #define AWT_WINDOW_BORDER            8
57 #define AWT_WINDOW_TEXT              9
58 #define AWT_MENU                    10
59 #define AWT_MENU_TEXT               11
60 #define AWT_TEXT                    12
61 #define AWT_TEXT_TEXT               13
62 #define AWT_TEXT_HIGHLIGHT          14
63 #define AWT_TEXT_HIGHLIGHT_TEXT     15
64 #define AWT_TEXT_INACTIVE_TEXT      16
65 #define AWT_CONTROL                 17
66 #define AWT_CONTROL_TEXT            18
67 #define AWT_CONTROL_HIGHLIGHT       19
68 #define AWT_CONTROL_LT_HIGHLIGHT    20
69 #define AWT_CONTROL_SHADOW          21
70 #define AWT_CONTROL_DK_SHADOW       22
71 #define AWT_SCROLLBAR               23
72 #define AWT_INFO                    24
73 #define AWT_INFO_TEXT               25
74 #define AWT_NUM_COLORS              26
75
76 struct state_table *cp_gtk_native_state_table;
77 struct state_table *cp_gtk_native_global_ref_table;
78
79 static jclass gtkgenericpeer;
80 static JavaVM *java_vm;
81 static jmethodID printCurrentThreadID;
82
83 union env_union
84 {
85   void *void_env;
86   JNIEnv *jni_env;
87 };
88
89 JNIEnv *
90 cp_gtk_gdk_env()
91 {
92   union env_union tmp;
93   g_assert((*java_vm)->GetEnv(java_vm, &tmp.void_env, JNI_VERSION_1_2) == JNI_OK);
94   return tmp.jni_env;
95 }
96
97
98 GtkWindowGroup *cp_gtk_global_window_group;
99 double cp_gtk_dpi_conversion_factor;
100
101 static void init_glib_threads(JNIEnv *, jint);
102
103 static void init_dpi_conversion_factor (void);
104 static void dpi_changed_cb (GtkSettings  *settings,
105                             GParamSpec   *pspec);
106
107 #if GTK_MINOR_VERSION > 4
108 static GLogFunc old_glog_func;
109 static void glog_func (const gchar *log_domain,
110                        GLogLevelFlags log_level,
111                        const gchar *message,
112                        gpointer user_data);
113 #endif
114
115 /*
116  * Call gtk_init.  It is very important that this happen before any other
117  * gtk calls.
118  *
119  * The portableNativeSync argument may have the values:
120  *   1 if the Java property gnu.classpath.awt.gtk.portable.native.sync
121  *     is set to "true".  
122  *   0 if it is set to "false"
123  *  -1 if unset.
124  */
125
126
127 JNIEXPORT void JNICALL 
128 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkInit (JNIEnv *env, 
129                                                jclass clazz __attribute__((unused)),
130                                                jint portableNativeSync)
131 {
132   int argc = 1;
133   char **argv;
134   char *homedir, *rcpath = NULL;
135
136   gtkgenericpeer = (*env)->FindClass(env, "gnu/java/awt/peer/gtk/GtkGenericPeer");
137
138   gtkgenericpeer = (*env)->NewGlobalRef(env, gtkgenericpeer);
139
140   printCurrentThreadID = (*env)->GetStaticMethodID (env, gtkgenericpeer,
141                                                     "printCurrentThread", "()V");
142  
143   NSA_INIT (env, gtkgenericpeer);
144
145   g_assert((*env)->GetJavaVM(env, &java_vm) == 0);
146
147   /* GTK requires a program's argc and argv variables, and requires that they
148      be valid.  Set it up. */
149   argv = (char **) g_malloc (sizeof (char *) * 2);
150   argv[0] = (char *) g_malloc(1);
151   argv[0][0] = '\0';
152   argv[1] = NULL;
153
154   init_glib_threads(env, portableNativeSync);
155
156   /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */
157   gdk_threads_init();
158
159   gtk_init (&argc, &argv);
160
161 #if SYNCHRONIZE_GDK
162   XSynchronize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), True);
163 #endif
164
165   gtk_widget_set_default_colormap (gdk_rgb_get_colormap ());
166
167   /* Make sure queued calls don't get sent to GTK/GDK while 
168      we're shutting down. */
169   atexit (gdk_threads_enter);
170
171   if ((homedir = getenv ("HOME")))
172     {
173       rcpath = (char *) g_malloc (strlen (homedir) + strlen (RC_FILE) + 2);
174       sprintf (rcpath, "%s/%s", homedir, RC_FILE);
175     }
176   
177   gtk_rc_parse ((rcpath) ? rcpath : RC_FILE);
178
179   g_free (rcpath);
180   g_free (argv[0]);
181   g_free (argv);
182
183   /* On errors or warning print a whole stacktrace. */
184 #if GTK_MINOR_VERSION > 4
185   old_glog_func = g_log_set_default_handler (&glog_func, NULL);
186 #endif
187
188 #if GTK_CAIRO
189   cp_gtk_graphics2d_init_jni ();
190 #endif
191   cp_gtk_graphics_init_jni ();
192   cp_gtk_button_init_jni ();
193   cp_gtk_checkbox_init_jni ();
194   cp_gtk_choice_init_jni ();
195   cp_gtk_component_init_jni ();
196   cp_gtk_filedialog_init_jni ();
197   cp_gtk_list_init_jni ();
198   cp_gtk_menuitem_init_jni ();
199   cp_gtk_scrollbar_init_jni ();
200   cp_gtk_textcomponent_init_jni ();
201   cp_gtk_window_init_jni ();
202
203   cp_gtk_global_window_group = gtk_window_group_new ();
204
205   init_dpi_conversion_factor ();
206 }
207
208
209 /** Initialize GLIB's threads properly, based on the value of the
210     gnu.classpath.awt.gtk.portable.native.sync Java system property.  If
211     that's unset, use the PORTABLE_NATIVE_SYNC config.h macro.  (TODO: 
212     In some release following 0.10, that config.h macro will go away.)
213     */ 
214 static void 
215 init_glib_threads(JNIEnv *env, jint portableNativeSync)
216 {
217   if (portableNativeSync < 0)
218     {
219 #ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system
220                                property */ 
221       portableNativeSync = 1;
222 #else
223       portableNativeSync = 0;
224 #endif
225     }
226   
227   (*env)->GetJavaVM( env, &cp_gtk_the_vm );
228   if (!g_thread_supported ())
229     {
230       if (portableNativeSync)
231         g_thread_init ( &cp_gtk_portable_native_sync_jni_functions );
232       else
233         g_thread_init ( NULL );
234     }
235   else
236     {
237       /* Warn if portable native sync is desired but the threading
238          system is already initialized.  In that case we can't
239          override the threading implementation with our portable
240          native sync functions. */
241       if (portableNativeSync)
242         g_printerr ("peer warning: portable native sync disabled.\n");
243     }
244
245   /* Debugging progress message; uncomment if needed: */
246   /*   printf("called gthread init\n"); */
247 }
248
249 void
250 cp_gtk_print_current_thread (void)
251 {
252   (*cp_gtk_gdk_env())->CallStaticVoidMethod (cp_gtk_gdk_env(), gtkgenericpeer, printCurrentThreadID);
253 }
254
255 /* This is a big hack, needed until this pango bug is resolved:
256    http://bugzilla.gnome.org/show_bug.cgi?id=119081.
257    See: http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html
258    for details. */
259 static void
260 init_dpi_conversion_factor ()
261 {
262   GtkSettings *settings = gtk_settings_get_default ();
263   GObjectClass *klass;
264
265   klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings));
266   if (g_object_class_find_property (klass, "gtk-xft-dpi"))
267     {
268       int int_dpi;
269       g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
270       /* If int_dpi == -1 gtk-xft-dpi returns the default value. So we
271          have to do approximate calculation here.  */
272       if (int_dpi < 0)
273         cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
274       else
275         cp_gtk_dpi_conversion_factor =
276           PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
277
278       g_signal_connect (settings, "notify::gtk-xft-dpi",
279                         G_CALLBACK (dpi_changed_cb), NULL);
280     }
281   else
282     /* Approximate. */
283     cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
284 }
285
286 static void
287 dpi_changed_cb (GtkSettings  *settings,
288                 GParamSpec *pspec __attribute__((unused)))
289 {
290   int int_dpi;
291   g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
292   if (int_dpi < 0)
293     cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
294   else
295     cp_gtk_dpi_conversion_factor =
296       PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
297 }
298
299 #if GTK_MINOR_VERSION > 4
300 static void
301 glog_func (const gchar *log_domain,
302            GLogLevelFlags log_level,
303            const gchar *message,
304            gpointer user_data)
305 {
306   old_glog_func (log_domain, log_level, message, user_data);
307   if (log_level & (G_LOG_LEVEL_ERROR
308                    | G_LOG_LEVEL_CRITICAL
309                    | G_LOG_LEVEL_WARNING))
310     {
311       JNIEnv *env = cp_gtk_gdk_env ();
312       jthrowable *exc = (*env)->ExceptionOccurred(env);
313       gchar *detail = g_strconcat (log_domain, ": ", message, NULL);
314       JCL_ThrowException (env, "java/lang/InternalError", detail);
315       g_free (detail);
316       (*env)->ExceptionDescribe (env);
317       if (exc != NULL)
318         (*env)->Throw (env, exc);
319       else
320         (*env)->ExceptionClear (env);
321     }
322 }
323 #endif
324
325 JNIEXPORT void JNICALL
326 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkMain
327 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
328 {
329   gdk_threads_enter ();
330
331   gtk_main ();
332
333   gdk_threads_leave ();
334 }
335
336
337 static jint gdk_color_to_java_color (GdkColor color);
338
339
340 JNIEXPORT void JNICALL 
341 Java_gnu_java_awt_peer_gtk_GtkToolkit_beep
342   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
343 {
344   gdk_threads_enter ();
345
346   gdk_beep ();
347
348   gdk_threads_leave ();
349 }
350
351 JNIEXPORT void JNICALL 
352 Java_gnu_java_awt_peer_gtk_GtkToolkit_sync
353   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
354 {
355   gdk_threads_enter ();
356
357   gdk_flush ();
358
359   gdk_threads_leave ();
360 }
361
362 JNIEXPORT void JNICALL 
363 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenSizeDimensions
364   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
365    jintArray jdims)
366 {
367   jint *dims = (*env)->GetIntArrayElements (env, jdims, 0);  
368
369   gdk_threads_enter ();
370
371   dims[0] = gdk_screen_width ();
372   dims[1] = gdk_screen_height ();
373
374   gdk_threads_leave ();
375
376   (*env)->ReleaseIntArrayElements(env, jdims, dims, 0);
377 }
378
379 JNIEXPORT jint JNICALL 
380 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenResolution
381   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
382 {
383   jint res;
384
385   gdk_threads_enter ();
386
387   res = gdk_screen_width () / (gdk_screen_width_mm () / 25.4);
388
389   gdk_threads_leave ();
390
391   return res;
392 }
393
394 #define CONVERT(type, state) \
395   gdk_color_to_java_color (style->type[GTK_STATE_ ## state])
396
397 JNIEXPORT void JNICALL
398 Java_gnu_java_awt_peer_gtk_GtkToolkit_loadSystemColors
399   (JNIEnv *env, jobject obj __attribute__((unused)),
400    jintArray jcolors)
401 {
402   jint *colors;
403   GtkStyle *style;
404
405   /* FIXME: this was deadlocking so assume it is thread-safe for now;
406      we need to replace this call with a .properties file anyway. */
407 #if 0
408   gdk_threads_enter ();
409 #endif
410
411   colors = (*env)->GetIntArrayElements (env, jcolors, 0);
412
413   style = gtk_widget_get_default_style ();
414
415   colors[AWT_DESKTOP]                 = CONVERT (bg, SELECTED);
416   colors[AWT_ACTIVE_CAPTION]          = CONVERT (bg, SELECTED);
417   colors[AWT_ACTIVE_CAPTION_TEXT]     = CONVERT (text, SELECTED);
418   colors[AWT_ACTIVE_CAPTION_BORDER]   = CONVERT (fg, NORMAL);
419   colors[AWT_INACTIVE_CAPTION]        = CONVERT (base, INSENSITIVE);
420   colors[AWT_INACTIVE_CAPTION_TEXT]   = CONVERT (fg, INSENSITIVE);
421   colors[AWT_INACTIVE_CAPTION_BORDER] = CONVERT (fg, INSENSITIVE);
422   colors[AWT_WINDOW]                  = CONVERT (bg, NORMAL);
423   colors[AWT_WINDOW_BORDER]           = CONVERT (fg, NORMAL);
424   colors[AWT_WINDOW_TEXT]             = CONVERT (fg, NORMAL);
425   colors[AWT_MENU]                    = CONVERT (bg, NORMAL);
426   colors[AWT_MENU_TEXT]               = CONVERT (fg, NORMAL);
427   colors[AWT_TEXT]                    = CONVERT (bg, NORMAL);
428   colors[AWT_TEXT_TEXT]               = CONVERT (fg, NORMAL);
429   colors[AWT_TEXT_HIGHLIGHT]          = CONVERT (bg, SELECTED);
430   colors[AWT_TEXT_HIGHLIGHT_TEXT]     = CONVERT (fg, SELECTED);
431   colors[AWT_TEXT_INACTIVE_TEXT]      = CONVERT (bg, INSENSITIVE);
432   colors[AWT_CONTROL]                 = CONVERT (bg, NORMAL);
433   colors[AWT_CONTROL_TEXT]            = CONVERT (fg, NORMAL);
434   colors[AWT_CONTROL_HIGHLIGHT]       = CONVERT (base, ACTIVE);
435   colors[AWT_CONTROL_LT_HIGHLIGHT]    = CONVERT (bg, PRELIGHT);
436   colors[AWT_CONTROL_SHADOW]          = CONVERT (bg, ACTIVE);
437   colors[AWT_CONTROL_DK_SHADOW]       = CONVERT (fg, INSENSITIVE);
438   colors[AWT_SCROLLBAR]               = CONVERT (base, INSENSITIVE);
439   colors[AWT_INFO]                    = CONVERT (bg, NORMAL);
440   colors[AWT_INFO_TEXT]               = CONVERT (fg, NORMAL);
441
442   (*env)->ReleaseIntArrayElements(env, jcolors, colors, 0);
443
444 #if 0
445   gdk_threads_leave ();
446 #endif
447 }
448
449 #undef CONVERT
450
451 static jint
452 gdk_color_to_java_color (GdkColor gdk_color)
453 {
454   guchar red;
455   guchar green;
456   guchar blue;
457   float factor;
458
459   factor = 255.0 / 65535.0;
460
461   red   = (float) gdk_color.red   * factor;
462   green = (float) gdk_color.green * factor;
463   blue  = (float) gdk_color.blue  * factor;
464
465   return (jint) (0xff000000 | (red << 16) | (green << 8) | blue);
466 }