OSDN Git Service

2006-08-02 Sven de Marothy <sven@physto.se>
[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   cp_gtk_button_init_jni ();
189   cp_gtk_checkbox_init_jni ();
190   cp_gtk_choice_init_jni ();
191   cp_gtk_component_init_jni ();
192   cp_gtk_filedialog_init_jni ();
193   cp_gtk_list_init_jni ();
194   cp_gtk_menuitem_init_jni ();
195   cp_gtk_scrollbar_init_jni ();
196   cp_gtk_textcomponent_init_jni ();
197   cp_gtk_window_init_jni ();
198
199   cp_gtk_global_window_group = gtk_window_group_new ();
200
201   init_dpi_conversion_factor ();
202 }
203
204
205 /** Initialize GLIB's threads properly, based on the value of the
206     gnu.classpath.awt.gtk.portable.native.sync Java system property.  If
207     that's unset, use the PORTABLE_NATIVE_SYNC config.h macro.  (TODO: 
208     In some release following 0.10, that config.h macro will go away.)
209     */ 
210 static void 
211 init_glib_threads(JNIEnv *env, jint portableNativeSync)
212 {
213   if (portableNativeSync < 0)
214     {
215 #ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system
216                                property */ 
217       portableNativeSync = 1;
218 #else
219       portableNativeSync = 0;
220 #endif
221     }
222   
223   (*env)->GetJavaVM( env, &cp_gtk_the_vm );
224   if (!g_thread_supported ())
225     {
226       if (portableNativeSync)
227         g_thread_init ( &cp_gtk_portable_native_sync_jni_functions );
228       else
229         g_thread_init ( NULL );
230     }
231   else
232     {
233       /* Warn if portable native sync is desired but the threading
234          system is already initialized.  In that case we can't
235          override the threading implementation with our portable
236          native sync functions. */
237       if (portableNativeSync)
238         g_printerr ("peer warning: portable native sync disabled.\n");
239     }
240
241   /* Debugging progress message; uncomment if needed: */
242   /*   printf("called gthread init\n"); */
243 }
244
245 void
246 cp_gtk_print_current_thread (void)
247 {
248   (*cp_gtk_gdk_env())->CallStaticVoidMethod (cp_gtk_gdk_env(), gtkgenericpeer, printCurrentThreadID);
249 }
250
251 /* This is a big hack, needed until this pango bug is resolved:
252    http://bugzilla.gnome.org/show_bug.cgi?id=119081.
253    See: http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html
254    for details. */
255 static void
256 init_dpi_conversion_factor ()
257 {
258   GtkSettings *settings = gtk_settings_get_default ();
259   GObjectClass *klass;
260
261   klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings));
262   if (g_object_class_find_property (klass, "gtk-xft-dpi"))
263     {
264       int int_dpi;
265       g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
266       /* If int_dpi == -1 gtk-xft-dpi returns the default value. So we
267          have to do approximate calculation here.  */
268       if (int_dpi < 0)
269         cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
270       else
271         cp_gtk_dpi_conversion_factor =
272           PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
273
274       g_signal_connect (settings, "notify::gtk-xft-dpi",
275                         G_CALLBACK (dpi_changed_cb), NULL);
276     }
277   else
278     /* Approximate. */
279     cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
280 }
281
282 static void
283 dpi_changed_cb (GtkSettings  *settings,
284                 GParamSpec *pspec __attribute__((unused)))
285 {
286   int int_dpi;
287   g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
288   if (int_dpi < 0)
289     cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
290   else
291     cp_gtk_dpi_conversion_factor =
292       PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
293 }
294
295 #if GTK_MINOR_VERSION > 4
296 static void
297 glog_func (const gchar *log_domain,
298            GLogLevelFlags log_level,
299            const gchar *message,
300            gpointer user_data)
301 {
302   old_glog_func (log_domain, log_level, message, user_data);
303   if (log_level & (G_LOG_LEVEL_ERROR
304                    | G_LOG_LEVEL_CRITICAL
305                    | G_LOG_LEVEL_WARNING))
306     {
307       JNIEnv *env = cp_gtk_gdk_env ();
308       jthrowable *exc = (*env)->ExceptionOccurred(env);
309       gchar *detail = g_strconcat (log_domain, ": ", message, NULL);
310       JCL_ThrowException (env, "java/lang/InternalError", detail);
311       g_free (detail);
312       (*env)->ExceptionDescribe (env);
313       if (exc != NULL)
314         (*env)->Throw (env, exc);
315       else
316         (*env)->ExceptionClear (env);
317     }
318 }
319 #endif
320
321 JNIEXPORT void JNICALL
322 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkMain
323 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
324 {
325   gdk_threads_enter ();
326
327   gtk_main ();
328
329   gdk_threads_leave ();
330 }
331
332
333 static jint gdk_color_to_java_color (GdkColor color);
334
335
336 JNIEXPORT void JNICALL 
337 Java_gnu_java_awt_peer_gtk_GtkToolkit_beep
338   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
339 {
340   gdk_threads_enter ();
341
342   gdk_beep ();
343
344   gdk_threads_leave ();
345 }
346
347 JNIEXPORT void JNICALL 
348 Java_gnu_java_awt_peer_gtk_GtkToolkit_sync
349   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
350 {
351   gdk_threads_enter ();
352
353   gdk_flush ();
354
355   gdk_threads_leave ();
356 }
357
358 JNIEXPORT void JNICALL 
359 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenSizeDimensions
360   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
361    jintArray jdims)
362 {
363   jint *dims = (*env)->GetIntArrayElements (env, jdims, 0);  
364
365   gdk_threads_enter ();
366
367   dims[0] = gdk_screen_width ();
368   dims[1] = gdk_screen_height ();
369
370   gdk_threads_leave ();
371
372   (*env)->ReleaseIntArrayElements(env, jdims, dims, 0);
373 }
374
375 JNIEXPORT jint JNICALL 
376 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenResolution
377   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
378 {
379   jint res;
380
381   gdk_threads_enter ();
382
383   res = gdk_screen_width () / (gdk_screen_width_mm () / 25.4);
384
385   gdk_threads_leave ();
386
387   return res;
388 }
389
390 /**
391  * Report the number of mouse buttons
392  * Returns the number of buttons of the first mouse found, or -1 if no mouse
393  * seems to be connected.
394  */
395 JNIEXPORT jint JNICALL 
396 Java_gnu_java_awt_peer_gtk_GtkToolkit_getMouseNumberOfButtons
397   (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
398 {
399   jint res = -1;
400   GList *devices;
401   GdkDevice *d;
402
403   gdk_threads_enter ();
404
405   /* FIXME: Why doesn't this return the correct number? */
406   devices = gdk_devices_list();
407
408   while( res == -1 && devices != NULL )
409     {
410       d = GDK_DEVICE( devices->data );
411       if( d->source == GDK_SOURCE_MOUSE )
412         res = d->num_keys;
413       devices = devices->next;
414     }
415
416   gdk_threads_leave ();
417
418   return res;
419 }
420
421 #define CONVERT(type, state) \
422   gdk_color_to_java_color (style->type[GTK_STATE_ ## state])
423
424 JNIEXPORT void JNICALL
425 Java_gnu_java_awt_peer_gtk_GtkToolkit_loadSystemColors
426   (JNIEnv *env, jobject obj __attribute__((unused)),
427    jintArray jcolors)
428 {
429   jint *colors;
430   GtkStyle *style;
431
432   /* FIXME: this was deadlocking so assume it is thread-safe for now;
433      we need to replace this call with a .properties file anyway. */
434 #if 0
435   gdk_threads_enter ();
436 #endif
437
438   colors = (*env)->GetIntArrayElements (env, jcolors, 0);
439
440   style = gtk_widget_get_default_style ();
441
442   colors[AWT_DESKTOP]                 = CONVERT (bg, SELECTED);
443   colors[AWT_ACTIVE_CAPTION]          = CONVERT (bg, SELECTED);
444   colors[AWT_ACTIVE_CAPTION_TEXT]     = CONVERT (text, SELECTED);
445   colors[AWT_ACTIVE_CAPTION_BORDER]   = CONVERT (fg, NORMAL);
446   colors[AWT_INACTIVE_CAPTION]        = CONVERT (base, INSENSITIVE);
447   colors[AWT_INACTIVE_CAPTION_TEXT]   = CONVERT (fg, INSENSITIVE);
448   colors[AWT_INACTIVE_CAPTION_BORDER] = CONVERT (fg, INSENSITIVE);
449   colors[AWT_WINDOW]                  = CONVERT (bg, NORMAL);
450   colors[AWT_WINDOW_BORDER]           = CONVERT (fg, NORMAL);
451   colors[AWT_WINDOW_TEXT]             = CONVERT (fg, NORMAL);
452   colors[AWT_MENU]                    = CONVERT (bg, NORMAL);
453   colors[AWT_MENU_TEXT]               = CONVERT (fg, NORMAL);
454   colors[AWT_TEXT]                    = CONVERT (bg, NORMAL);
455   colors[AWT_TEXT_TEXT]               = CONVERT (fg, NORMAL);
456   colors[AWT_TEXT_HIGHLIGHT]          = CONVERT (bg, SELECTED);
457   colors[AWT_TEXT_HIGHLIGHT_TEXT]     = CONVERT (fg, SELECTED);
458   colors[AWT_TEXT_INACTIVE_TEXT]      = CONVERT (bg, INSENSITIVE);
459   colors[AWT_CONTROL]                 = CONVERT (bg, NORMAL);
460   colors[AWT_CONTROL_TEXT]            = CONVERT (fg, NORMAL);
461   colors[AWT_CONTROL_HIGHLIGHT]       = CONVERT (base, ACTIVE);
462   colors[AWT_CONTROL_LT_HIGHLIGHT]    = CONVERT (bg, PRELIGHT);
463   colors[AWT_CONTROL_SHADOW]          = CONVERT (bg, ACTIVE);
464   colors[AWT_CONTROL_DK_SHADOW]       = CONVERT (fg, INSENSITIVE);
465   colors[AWT_SCROLLBAR]               = CONVERT (base, INSENSITIVE);
466   colors[AWT_INFO]                    = CONVERT (bg, NORMAL);
467   colors[AWT_INFO_TEXT]               = CONVERT (fg, NORMAL);
468
469   (*env)->ReleaseIntArrayElements(env, jcolors, colors, 0);
470
471 #if 0
472   gdk_threads_leave ();
473 #endif
474 }
475
476 #undef CONVERT
477
478 static jint
479 gdk_color_to_java_color (GdkColor gdk_color)
480 {
481   guchar red;
482   guchar green;
483   guchar blue;
484   float factor;
485
486   factor = 255.0 / 65535.0;
487
488   red   = (float) gdk_color.red   * factor;
489   green = (float) gdk_color.green * factor;
490   blue  = (float) gdk_color.blue  * factor;
491
492   return (jint) (0xff000000 | (red << 16) | (green << 8) | blue);
493 }