1 /*
   2  * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 #include <dlfcn.h>
  26 #include <setjmp.h>
  27 #include <X11/Xlib.h>
  28 #include <limits.h>
  29 #include <stdio.h>
  30 #include <string.h>
  31 #include "gtk2_interface.h"
  32 #include "java_awt_Transparency.h"
  33 
  34 #define GTK2_LIB "libgtk-x11-2.0.so.0"
  35 #define GTHREAD_LIB "libgthread-2.0.so.0"
  36 
  37 #define G_TYPE_INVALID                  G_TYPE_MAKE_FUNDAMENTAL (0)
  38 #define G_TYPE_NONE                     G_TYPE_MAKE_FUNDAMENTAL (1)
  39 #define G_TYPE_INTERFACE                G_TYPE_MAKE_FUNDAMENTAL (2)
  40 #define G_TYPE_CHAR                     G_TYPE_MAKE_FUNDAMENTAL (3)
  41 #define G_TYPE_UCHAR                    G_TYPE_MAKE_FUNDAMENTAL (4)
  42 #define G_TYPE_BOOLEAN                  G_TYPE_MAKE_FUNDAMENTAL (5)
  43 #define G_TYPE_INT                      G_TYPE_MAKE_FUNDAMENTAL (6)
  44 #define G_TYPE_UINT                     G_TYPE_MAKE_FUNDAMENTAL (7)
  45 #define G_TYPE_LONG                     G_TYPE_MAKE_FUNDAMENTAL (8)
  46 #define G_TYPE_ULONG                    G_TYPE_MAKE_FUNDAMENTAL (9)
  47 #define G_TYPE_INT64                    G_TYPE_MAKE_FUNDAMENTAL (10)
  48 #define G_TYPE_UINT64                   G_TYPE_MAKE_FUNDAMENTAL (11)
  49 #define G_TYPE_ENUM                     G_TYPE_MAKE_FUNDAMENTAL (12)
  50 #define G_TYPE_FLAGS                    G_TYPE_MAKE_FUNDAMENTAL (13)
  51 #define G_TYPE_FLOAT                    G_TYPE_MAKE_FUNDAMENTAL (14)
  52 #define G_TYPE_DOUBLE                   G_TYPE_MAKE_FUNDAMENTAL (15)
  53 #define G_TYPE_STRING                   G_TYPE_MAKE_FUNDAMENTAL (16)
  54 #define G_TYPE_POINTER                  G_TYPE_MAKE_FUNDAMENTAL (17)
  55 #define G_TYPE_BOXED                    G_TYPE_MAKE_FUNDAMENTAL (18)
  56 #define G_TYPE_PARAM                    G_TYPE_MAKE_FUNDAMENTAL (19)
  57 #define G_TYPE_OBJECT                   G_TYPE_MAKE_FUNDAMENTAL (20)
  58 
  59 #define GTK_TYPE_BORDER                 ((*fp_gtk_border_get_type)())
  60 
  61 #define G_TYPE_FUNDAMENTAL_SHIFT        (2)
  62 #define G_TYPE_MAKE_FUNDAMENTAL(x)      ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT))
  63 #define MIN(a, b)  (((a) < (b)) ? (a) : (b))
  64 
  65 #define CONV_BUFFER_SIZE 128
  66 
  67 #define NO_SYMBOL_EXCEPTION 1
  68 
  69 /* SynthConstants */
  70 const gint ENABLED    = 1 << 0;
  71 const gint MOUSE_OVER = 1 << 1;
  72 const gint PRESSED    = 1 << 2;
  73 const gint DISABLED   = 1 << 3;
  74 const gint FOCUSED    = 1 << 8;
  75 const gint SELECTED   = 1 << 9;
  76 const gint DEFAULT    = 1 << 10;
  77 
  78 static void *gtk2_libhandle = NULL;
  79 static void *gthread_libhandle = NULL;
  80 static gboolean flag_g_thread_get_initialized = FALSE;
  81 static jmp_buf j;
  82 
  83 /* Widgets */
  84 static GtkWidget *gtk2_widget = NULL;
  85 static GtkWidget *gtk2_window = NULL;
  86 static GtkFixed  *gtk2_fixed  = NULL;
  87 
  88 /* Paint system */
  89 static GdkPixmap *gtk2_white_pixmap = NULL;
  90 static GdkPixmap *gtk2_black_pixmap = NULL;
  91 static GdkPixbuf *gtk2_white_pixbuf = NULL;
  92 static GdkPixbuf *gtk2_black_pixbuf = NULL;
  93 static int gtk2_pixbuf_width = 0;
  94 static int gtk2_pixbuf_height = 0;
  95 
  96 /* Static buffer for conversion from java.lang.String to UTF-8 */
  97 static char convertionBuffer[CONV_BUFFER_SIZE];
  98 
  99 static gboolean new_combo = TRUE;
 100 const char ENV_PREFIX[] = "GTK_MODULES=";
 101 
 102 /*******************/
 103 enum GtkWidgetType
 104 {
 105     _GTK_ARROW_TYPE,
 106     _GTK_BUTTON_TYPE,
 107     _GTK_CHECK_BUTTON_TYPE,
 108     _GTK_CHECK_MENU_ITEM_TYPE,
 109     _GTK_COLOR_SELECTION_DIALOG_TYPE,
 110     _GTK_COMBO_BOX_TYPE,
 111     _GTK_COMBO_BOX_ARROW_BUTTON_TYPE,
 112     _GTK_COMBO_BOX_TEXT_FIELD_TYPE,
 113     _GTK_CONTAINER_TYPE,
 114     _GTK_ENTRY_TYPE,
 115     _GTK_FRAME_TYPE,
 116     _GTK_HANDLE_BOX_TYPE,
 117     _GTK_HPANED_TYPE,
 118     _GTK_HPROGRESS_BAR_TYPE,
 119     _GTK_HSCALE_TYPE,
 120     _GTK_HSCROLLBAR_TYPE,
 121     _GTK_HSEPARATOR_TYPE,
 122     _GTK_IMAGE_TYPE,
 123     _GTK_MENU_TYPE,
 124     _GTK_MENU_BAR_TYPE,
 125     _GTK_MENU_ITEM_TYPE,
 126     _GTK_NOTEBOOK_TYPE,
 127     _GTK_LABEL_TYPE,
 128     _GTK_RADIO_BUTTON_TYPE,
 129     _GTK_RADIO_MENU_ITEM_TYPE,
 130     _GTK_SCROLLED_WINDOW_TYPE,
 131     _GTK_SEPARATOR_MENU_ITEM_TYPE,
 132     _GTK_SEPARATOR_TOOL_ITEM_TYPE,
 133     _GTK_SPIN_BUTTON_TYPE,
 134     _GTK_TEXT_VIEW_TYPE,
 135     _GTK_TOGGLE_BUTTON_TYPE,
 136     _GTK_TOOLBAR_TYPE,
 137     _GTK_TOOLTIP_TYPE,
 138     _GTK_TREE_VIEW_TYPE,
 139     _GTK_VIEWPORT_TYPE,
 140     _GTK_VPANED_TYPE,
 141     _GTK_VPROGRESS_BAR_TYPE,
 142     _GTK_VSCALE_TYPE,
 143     _GTK_VSCROLLBAR_TYPE,
 144     _GTK_VSEPARATOR_TYPE,
 145     _GTK_WINDOW_TYPE,
 146     _GTK_DIALOG_TYPE,
 147     _GTK_WIDGET_TYPE_SIZE
 148 };
 149 
 150 
 151 static GtkWidget *gtk2_widgets[_GTK_WIDGET_TYPE_SIZE];
 152 
 153 /*************************
 154  * Glib function pointers
 155  *************************/
 156 
 157 static gboolean (*fp_g_main_context_iteration)(GMainContext *context,
 158                                              gboolean may_block);
 159 
 160 static GValue*      (*fp_g_value_init)(GValue *value, GType g_type);
 161 static gboolean     (*fp_g_type_is_a)(GType type, GType is_a_type);
 162 static gboolean     (*fp_g_value_get_boolean)(const GValue *value);
 163 static gchar        (*fp_g_value_get_char)(const GValue *value);
 164 static guchar       (*fp_g_value_get_uchar)(const GValue *value);
 165 static gint         (*fp_g_value_get_int)(const GValue *value);
 166 static guint        (*fp_g_value_get_uint)(const GValue *value);
 167 static glong        (*fp_g_value_get_long)(const GValue *value);
 168 static gulong       (*fp_g_value_get_ulong)(const GValue *value);
 169 static gint64       (*fp_g_value_get_int64)(const GValue *value);
 170 static guint64      (*fp_g_value_get_uint64)(const GValue *value);
 171 static gfloat       (*fp_g_value_get_float)(const GValue *value);
 172 static gdouble      (*fp_g_value_get_double)(const GValue *value);
 173 static const gchar* (*fp_g_value_get_string)(const GValue *value);
 174 static gint         (*fp_g_value_get_enum)(const GValue *value);
 175 static guint        (*fp_g_value_get_flags)(const GValue *value);
 176 static GParamSpec*  (*fp_g_value_get_param)(const GValue *value);
 177 static gpointer*    (*fp_g_value_get_boxed)(const GValue *value);
 178 static gpointer*    (*fp_g_value_get_pointer)(const GValue *value);
 179 static GObject*     (*fp_g_value_get_object)(const GValue *value);
 180 static GParamSpec*  (*fp_g_param_spec_int)(const gchar *name,
 181         const gchar *nick, const gchar *blurb,
 182         gint minimum, gint maximum, gint default_value,
 183         GParamFlags flags);
 184 static void         (*fp_g_object_get)(gpointer object,
 185                                        const gchar* fpn, ...);
 186 static void         (*fp_g_object_set)(gpointer object,
 187                                        const gchar *first_property_name,
 188                                        ...);
 189 /************************
 190  * GDK function pointers
 191  ************************/
 192 static GdkPixmap *(*fp_gdk_pixmap_new)(GdkDrawable *drawable,
 193         gint width, gint height, gint depth);
 194 static GdkGC *(*fp_gdk_gc_new)(GdkDrawable*);
 195 static void (*fp_gdk_rgb_gc_set_foreground)(GdkGC*, guint32);
 196 static void (*fp_gdk_draw_rectangle)(GdkDrawable*, GdkGC*, gboolean,
 197         gint, gint, gint, gint);
 198 static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace,
 199         gboolean has_alpha, int bits_per_sample, int width, int height);
 200 static GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest,
 201         GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y,
 202         int dest_x, int dest_y, int width, int height);
 203 static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable,
 204         gint* width, gint* height);
 205 
 206 /************************
 207  * Gtk function pointers
 208  ************************/
 209 static gboolean (*fp_gtk_init_check)(int* argc, char** argv);
 210 
 211 /* Painting */
 212 static void (*fp_gtk_paint_hline)(GtkStyle* style, GdkWindow* window,
 213         GtkStateType state_type, GdkRectangle* area, GtkWidget* widget,
 214         const gchar* detail, gint x1, gint x2, gint y);
 215 static void (*fp_gtk_paint_vline)(GtkStyle* style, GdkWindow* window,
 216         GtkStateType state_type, GdkRectangle* area, GtkWidget* widget,
 217         const gchar* detail, gint y1, gint y2, gint x);
 218 static void (*fp_gtk_paint_shadow)(GtkStyle* style, GdkWindow* window,
 219         GtkStateType state_type, GtkShadowType shadow_type,
 220         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 221         gint x, gint y, gint width, gint height);
 222 static void (*fp_gtk_paint_arrow)(GtkStyle* style, GdkWindow* window,
 223         GtkStateType state_type, GtkShadowType shadow_type,
 224         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 225         GtkArrowType arrow_type, gboolean fill, gint x, gint y,
 226         gint width, gint height);
 227 static void (*fp_gtk_paint_diamond)(GtkStyle* style, GdkWindow* window,
 228         GtkStateType state_type, GtkShadowType shadow_type,
 229         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 230         gint x, gint y, gint width, gint height);
 231 static void (*fp_gtk_paint_box)(GtkStyle* style, GdkWindow* window,
 232         GtkStateType state_type, GtkShadowType shadow_type,
 233         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 234         gint x, gint y, gint width, gint height);
 235 static void (*fp_gtk_paint_flat_box)(GtkStyle* style, GdkWindow* window,
 236         GtkStateType state_type, GtkShadowType shadow_type,
 237         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 238         gint x, gint y, gint width, gint height);
 239 static void (*fp_gtk_paint_check)(GtkStyle* style, GdkWindow* window,
 240         GtkStateType state_type, GtkShadowType shadow_type,
 241         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 242         gint x, gint y, gint width, gint height);
 243 static void (*fp_gtk_paint_option)(GtkStyle* style, GdkWindow* window,
 244         GtkStateType state_type, GtkShadowType shadow_type,
 245         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 246         gint x, gint y, gint width, gint height);
 247 static void (*fp_gtk_paint_box_gap)(GtkStyle* style, GdkWindow* window,
 248         GtkStateType state_type, GtkShadowType shadow_type,
 249         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 250         gint x, gint y, gint width, gint height,
 251         GtkPositionType gap_side, gint gap_x, gint gap_width);
 252 static void (*fp_gtk_paint_extension)(GtkStyle* style, GdkWindow* window,
 253         GtkStateType state_type, GtkShadowType shadow_type,
 254         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 255         gint x, gint y, gint width, gint height, GtkPositionType gap_side);
 256 static void (*fp_gtk_paint_focus)(GtkStyle* style, GdkWindow* window,
 257         GtkStateType state_type, GdkRectangle* area, GtkWidget* widget,
 258         const gchar* detail, gint x, gint y, gint width, gint height);
 259 static void (*fp_gtk_paint_slider)(GtkStyle* style, GdkWindow* window,
 260         GtkStateType state_type, GtkShadowType shadow_type,
 261         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 262         gint x, gint y, gint width, gint height, GtkOrientation orientation);
 263 static void (*fp_gtk_paint_handle)(GtkStyle* style, GdkWindow* window,
 264         GtkStateType state_type, GtkShadowType shadow_type,
 265         GdkRectangle* area, GtkWidget* widget, const gchar* detail,
 266         gint x, gint y, gint width, gint height, GtkOrientation orientation);
 267 static void (*fp_gtk_paint_expander)(GtkStyle* style, GdkWindow* window,
 268         GtkStateType state_type, GdkRectangle* area, GtkWidget* widget,
 269         const gchar* detail, gint x, gint y, GtkExpanderStyle expander_style);
 270 static void (*fp_gtk_style_apply_default_background)(GtkStyle* style,
 271         GdkWindow* window, gboolean set_bg, GtkStateType state_type,
 272         GdkRectangle* area, gint x, gint y, gint width, gint height);
 273 
 274 /* Widget creation */
 275 static GtkWidget* (*fp_gtk_arrow_new)(GtkArrowType arrow_type,
 276                                       GtkShadowType shadow_type);
 277 static GtkWidget* (*fp_gtk_button_new)();
 278 static GtkWidget* (*fp_gtk_check_button_new)();
 279 static GtkWidget* (*fp_gtk_check_menu_item_new)();
 280 static GtkWidget* (*fp_gtk_color_selection_dialog_new)(const gchar* title);
 281 static GtkWidget* (*fp_gtk_combo_box_new)();
 282 static GtkWidget* (*fp_gtk_combo_box_entry_new)();
 283 static GtkWidget* (*fp_gtk_entry_new)();
 284 static GtkWidget* (*fp_gtk_fixed_new)();
 285 static GtkWidget* (*fp_gtk_handle_box_new)();
 286 static GtkWidget* (*fp_gtk_hpaned_new)();
 287 static GtkWidget* (*fp_gtk_vpaned_new)();
 288 static GtkWidget* (*fp_gtk_hscale_new)(GtkAdjustment* adjustment);
 289 static GtkWidget* (*fp_gtk_vscale_new)(GtkAdjustment* adjustment);
 290 static GtkWidget* (*fp_gtk_hscrollbar_new)(GtkAdjustment* adjustment);
 291 static GtkWidget* (*fp_gtk_vscrollbar_new)(GtkAdjustment* adjustment);
 292 static GtkWidget* (*fp_gtk_hseparator_new)();
 293 static GtkWidget* (*fp_gtk_vseparator_new)();
 294 static GtkWidget* (*fp_gtk_image_new)();
 295 static GtkWidget* (*fp_gtk_label_new)(const gchar* str);
 296 static GtkWidget* (*fp_gtk_menu_new)();
 297 static GtkWidget* (*fp_gtk_menu_bar_new)();
 298 static GtkWidget* (*fp_gtk_menu_item_new)();
 299 static GtkWidget* (*fp_gtk_notebook_new)();
 300 static GtkWidget* (*fp_gtk_progress_bar_new)();
 301 static GtkWidget* (*fp_gtk_progress_bar_set_orientation)(
 302         GtkProgressBar *pbar,
 303         GtkProgressBarOrientation orientation);
 304 static GtkWidget* (*fp_gtk_radio_button_new)(GSList *group);
 305 static GtkWidget* (*fp_gtk_radio_menu_item_new)(GSList *group);
 306 static GtkWidget* (*fp_gtk_scrolled_window_new)(GtkAdjustment *hadjustment,
 307         GtkAdjustment *vadjustment);
 308 static GtkWidget* (*fp_gtk_separator_menu_item_new)();
 309 static GtkWidget* (*fp_gtk_separator_tool_item_new)();
 310 static GtkWidget* (*fp_gtk_text_view_new)();
 311 static GtkWidget* (*fp_gtk_toggle_button_new)();
 312 static GtkWidget* (*fp_gtk_toolbar_new)();
 313 static GtkWidget* (*fp_gtk_tree_view_new)();
 314 static GtkWidget* (*fp_gtk_viewport_new)(GtkAdjustment *hadjustment,
 315         GtkAdjustment *vadjustment);
 316 static GtkWidget* (*fp_gtk_window_new)(GtkWindowType type);
 317 static GtkWidget* (*fp_gtk_dialog_new)();
 318 static GtkWidget* (*fp_gtk_spin_button_new)(GtkAdjustment *adjustment,
 319         gdouble climb_rate, guint digits);
 320 static GtkWidget* (*fp_gtk_frame_new)(const gchar *label);
 321 
 322 /* Other widget operations */
 323 static GtkObject* (*fp_gtk_adjustment_new)(gdouble value,
 324         gdouble lower, gdouble upper, gdouble step_increment,
 325         gdouble page_increment, gdouble page_size);
 326 static void (*fp_gtk_container_add)(GtkContainer *window, GtkWidget *widget);
 327 static void (*fp_gtk_menu_shell_append)(GtkMenuShell *menu_shell,
 328         GtkWidget *child);
 329 static void (*fp_gtk_menu_item_set_submenu)(GtkMenuItem *menu_item,
 330         GtkWidget *submenu);
 331 static void (*fp_gtk_widget_realize)(GtkWidget *widget);
 332 static GdkPixbuf* (*fp_gtk_widget_render_icon)(GtkWidget *widget,
 333         const gchar *stock_id, GtkIconSize size, const gchar *detail);
 334 static void (*fp_gtk_widget_set_name)(GtkWidget *widget, const gchar *name);
 335 static void (*fp_gtk_widget_set_parent)(GtkWidget *widget, GtkWidget *parent);
 336 static void (*fp_gtk_widget_set_direction)(GtkWidget *widget,
 337         GtkTextDirection direction);
 338 static void (*fp_gtk_widget_style_get)(GtkWidget *widget,
 339         const gchar *first_property_name, ...);
 340 static void (*fp_gtk_widget_class_install_style_property)(
 341         GtkWidgetClass* class, GParamSpec *pspec);
 342 static GParamSpec* (*fp_gtk_widget_class_find_style_property)(
 343         GtkWidgetClass* class, const gchar* property_name);
 344 static void (*fp_gtk_widget_style_get_property)(GtkWidget* widget,
 345         const gchar* property_name, GValue* value);
 346 static char* (*fp_pango_font_description_to_string)(
 347         const PangoFontDescription* fd);
 348 static GtkSettings* (*fp_gtk_settings_get_default)();
 349 static GtkSettings* (*fp_gtk_widget_get_settings)(GtkWidget *widget);
 350 static GType        (*fp_gtk_border_get_type)();
 351 static void (*fp_gtk_arrow_set)(GtkWidget* arrow,
 352                                 GtkArrowType arrow_type,
 353                                 GtkShadowType shadow_type);
 354 static void (*fp_gtk_widget_size_request)(GtkWidget *widget,
 355                                           GtkRequisition *requisition);
 356 static GtkAdjustment* (*fp_gtk_range_get_adjustment)(GtkRange* range);
 357 
 358 /* Method bodies */
 359 const char *getStrFor(JNIEnv *env, jstring val)
 360 {
 361     int length = (*env)->GetStringLength(env, val);
 362     if (length > CONV_BUFFER_SIZE-1)
 363     {
 364         length = CONV_BUFFER_SIZE-1;
 365 #ifdef INTERNAL_BUILD
 366         fprintf(stderr, "Note: Detail is too long: %d chars\n", length);
 367 #endif /* INTERNAL_BUILD */
 368     }
 369 
 370     (*env)->GetStringUTFRegion(env, val, 0, length, convertionBuffer);
 371     return convertionBuffer;
 372 }
 373 
 374 static void throw_exception(JNIEnv *env, const char* name, const char* message)
 375 {
 376     jclass class = (*env)->FindClass(env, name);
 377 
 378     if (class != NULL)
 379         (*env)->ThrowNew(env, class, message);
 380 
 381     (*env)->DeleteLocalRef(env, class);
 382 }
 383 
 384 /* This is a workaround for the bug:
 385  * http://sourceware.org/bugzilla/show_bug.cgi?id=1814
 386  * (dlsym/dlopen clears dlerror state)
 387  * This bug is specific to Linux, but there is no harm in
 388  * applying this workaround on Solaris as well.
 389  */
 390 static void* dl_symbol(const char* name)
 391 {
 392     void* result = dlsym(gtk2_libhandle, name);
 393     if (!result)
 394         longjmp(j, NO_SYMBOL_EXCEPTION);
 395 
 396     return result;
 397 }
 398 
 399 static void* dl_symbol_gthread(const char* name)
 400 {
 401     void* result = dlsym(gthread_libhandle, name);
 402     if (!result)
 403         longjmp(j, NO_SYMBOL_EXCEPTION);
 404 
 405     return result;
 406 }
 407 
 408 gboolean gtk2_check_version()
 409 {
 410     if (gtk2_libhandle != NULL) {
 411         /* We've already successfully opened the GTK libs, so return true. */
 412         return TRUE;
 413     } else {
 414         void *lib = NULL;
 415         gboolean result = FALSE;
 416 
 417         lib = dlopen(GTK2_LIB, RTLD_LAZY | RTLD_LOCAL);
 418         if (lib == NULL) {
 419             return FALSE;
 420         }
 421 
 422         fp_gtk_check_version = dlsym(lib, "gtk_check_version");
 423         /* Check for GTK 2.2+ */
 424         if (!fp_gtk_check_version(2, 2, 0)) {
 425             result = TRUE;
 426         }
 427 
 428         dlclose(lib);
 429 
 430         return result;
 431     }
 432 }
 433 
 434 /**
 435  * Functions for sun_awt_X11_GtkFileDialogPeer.c
 436  */
 437 void gtk2_file_chooser_load()
 438 {
 439     fp_gtk_file_chooser_get_filename = dl_symbol(
 440             "gtk_file_chooser_get_filename");
 441     fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new");
 442     fp_gtk_file_chooser_set_current_folder = dl_symbol(
 443             "gtk_file_chooser_set_current_folder");
 444     fp_gtk_file_chooser_set_filename = dl_symbol(
 445             "gtk_file_chooser_set_filename");
 446     fp_gtk_file_chooser_set_current_name = dl_symbol(
 447             "gtk_file_chooser_set_current_name");
 448     fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom");
 449     fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter");
 450     fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type");
 451     fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new");
 452     if (fp_gtk_check_version(2, 8, 0) == NULL) {
 453         fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol(
 454                 "gtk_file_chooser_set_do_overwrite_confirmation");
 455     }
 456     fp_gtk_file_chooser_set_select_multiple = dl_symbol(
 457             "gtk_file_chooser_set_select_multiple");
 458     fp_gtk_file_chooser_get_current_folder = dl_symbol(
 459             "gtk_file_chooser_get_current_folder");
 460     fp_gtk_file_chooser_get_filenames = dl_symbol(
 461             "gtk_file_chooser_get_filenames");
 462     fp_gtk_g_slist_length = dl_symbol("g_slist_length");
 463 }
 464 
 465 gboolean gtk2_load()
 466 {
 467     gboolean result;
 468     int i;
 469     int (*handler)();
 470     int (*io_handler)();
 471     char *gtk_modules_env;
 472 
 473     gtk2_libhandle = dlopen(GTK2_LIB, RTLD_LAZY | RTLD_LOCAL);
 474     gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL);
 475 
 476     if (gtk2_libhandle == NULL || gthread_libhandle == NULL)
 477         return FALSE;
 478 
 479     if (setjmp(j) == 0)
 480     {
 481         fp_gtk_check_version = dl_symbol("gtk_check_version");
 482         /* Check for GTK 2.2+ */
 483         if (fp_gtk_check_version(2, 2, 0)) {
 484             longjmp(j, NO_SYMBOL_EXCEPTION);
 485         }
 486 
 487         /* GLib */
 488         fp_g_free = dl_symbol("g_free");
 489         fp_g_object_unref = dl_symbol("g_object_unref");
 490 
 491         fp_g_main_context_iteration =
 492             dl_symbol("g_main_context_iteration");
 493 
 494         fp_g_value_init = dl_symbol("g_value_init");
 495         fp_g_type_is_a = dl_symbol("g_type_is_a");
 496 
 497         fp_g_value_get_boolean = dl_symbol("g_value_get_boolean");
 498         fp_g_value_get_char = dl_symbol("g_value_get_char");
 499         fp_g_value_get_uchar = dl_symbol("g_value_get_uchar");
 500         fp_g_value_get_int = dl_symbol("g_value_get_int");
 501         fp_g_value_get_uint = dl_symbol("g_value_get_uint");
 502         fp_g_value_get_long = dl_symbol("g_value_get_long");
 503         fp_g_value_get_ulong = dl_symbol("g_value_get_ulong");
 504         fp_g_value_get_int64 = dl_symbol("g_value_get_int64");
 505         fp_g_value_get_uint64 = dl_symbol("g_value_get_uint64");
 506         fp_g_value_get_float = dl_symbol("g_value_get_float");
 507         fp_g_value_get_double = dl_symbol("g_value_get_double");
 508         fp_g_value_get_string = dl_symbol("g_value_get_string");
 509         fp_g_value_get_enum = dl_symbol("g_value_get_enum");
 510         fp_g_value_get_flags = dl_symbol("g_value_get_flags");
 511         fp_g_value_get_param = dl_symbol("g_value_get_param");
 512         fp_g_value_get_boxed = dl_symbol("g_value_get_boxed");
 513         fp_g_value_get_pointer = dl_symbol("g_value_get_pointer");
 514         fp_g_value_get_object = dl_symbol("g_value_get_object");
 515         fp_g_param_spec_int = dl_symbol("g_param_spec_int");
 516         fp_g_object_get = dl_symbol("g_object_get");
 517         fp_g_object_set = dl_symbol("g_object_set");
 518 
 519         /* GDK */
 520         fp_gdk_pixmap_new = dl_symbol("gdk_pixmap_new");
 521         fp_gdk_pixbuf_get_from_drawable =
 522             dl_symbol("gdk_pixbuf_get_from_drawable");
 523         fp_gdk_gc_new = dl_symbol("gdk_gc_new");
 524         fp_gdk_rgb_gc_set_foreground =
 525             dl_symbol("gdk_rgb_gc_set_foreground");
 526         fp_gdk_draw_rectangle = dl_symbol("gdk_draw_rectangle");
 527         fp_gdk_drawable_get_size = dl_symbol("gdk_drawable_get_size");
 528 
 529         /* Pixbuf */
 530         fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new");
 531         fp_gdk_pixbuf_new_from_file =
 532                 dl_symbol("gdk_pixbuf_new_from_file");
 533         fp_gdk_pixbuf_get_width = dl_symbol("gdk_pixbuf_get_width");
 534         fp_gdk_pixbuf_get_height = dl_symbol("gdk_pixbuf_get_height");
 535         fp_gdk_pixbuf_get_pixels = dl_symbol("gdk_pixbuf_get_pixels");
 536         fp_gdk_pixbuf_get_rowstride =
 537                 dl_symbol("gdk_pixbuf_get_rowstride");
 538         fp_gdk_pixbuf_get_has_alpha =
 539                 dl_symbol("gdk_pixbuf_get_has_alpha");
 540         fp_gdk_pixbuf_get_bits_per_sample =
 541                 dl_symbol("gdk_pixbuf_get_bits_per_sample");
 542         fp_gdk_pixbuf_get_n_channels =
 543                 dl_symbol("gdk_pixbuf_get_n_channels");
 544 
 545         /* GTK painting */
 546         fp_gtk_init_check = dl_symbol("gtk_init_check");
 547         fp_gtk_paint_hline = dl_symbol("gtk_paint_hline");
 548         fp_gtk_paint_vline = dl_symbol("gtk_paint_vline");
 549         fp_gtk_paint_shadow = dl_symbol("gtk_paint_shadow");
 550         fp_gtk_paint_arrow = dl_symbol("gtk_paint_arrow");
 551         fp_gtk_paint_diamond = dl_symbol("gtk_paint_diamond");
 552         fp_gtk_paint_box = dl_symbol("gtk_paint_box");
 553         fp_gtk_paint_flat_box = dl_symbol("gtk_paint_flat_box");
 554         fp_gtk_paint_check = dl_symbol("gtk_paint_check");
 555         fp_gtk_paint_option = dl_symbol("gtk_paint_option");
 556         fp_gtk_paint_box_gap = dl_symbol("gtk_paint_box_gap");
 557         fp_gtk_paint_extension = dl_symbol("gtk_paint_extension");
 558         fp_gtk_paint_focus = dl_symbol("gtk_paint_focus");
 559         fp_gtk_paint_slider = dl_symbol("gtk_paint_slider");
 560         fp_gtk_paint_handle = dl_symbol("gtk_paint_handle");
 561         fp_gtk_paint_expander = dl_symbol("gtk_paint_expander");
 562         fp_gtk_style_apply_default_background =
 563                 dl_symbol("gtk_style_apply_default_background");
 564 
 565         /* GTK widgets */
 566         fp_gtk_arrow_new = dl_symbol("gtk_arrow_new");
 567         fp_gtk_button_new = dl_symbol("gtk_button_new");
 568         fp_gtk_spin_button_new = dl_symbol("gtk_spin_button_new");
 569         fp_gtk_check_button_new = dl_symbol("gtk_check_button_new");
 570         fp_gtk_check_menu_item_new =
 571                 dl_symbol("gtk_check_menu_item_new");
 572         fp_gtk_color_selection_dialog_new =
 573                 dl_symbol("gtk_color_selection_dialog_new");
 574         fp_gtk_entry_new = dl_symbol("gtk_entry_new");
 575         fp_gtk_fixed_new = dl_symbol("gtk_fixed_new");
 576         fp_gtk_handle_box_new = dl_symbol("gtk_handle_box_new");
 577         fp_gtk_image_new = dl_symbol("gtk_image_new");
 578         fp_gtk_hpaned_new = dl_symbol("gtk_hpaned_new");
 579         fp_gtk_vpaned_new = dl_symbol("gtk_vpaned_new");
 580         fp_gtk_hscale_new = dl_symbol("gtk_hscale_new");
 581         fp_gtk_vscale_new = dl_symbol("gtk_vscale_new");
 582         fp_gtk_hscrollbar_new = dl_symbol("gtk_hscrollbar_new");
 583         fp_gtk_vscrollbar_new = dl_symbol("gtk_vscrollbar_new");
 584         fp_gtk_hseparator_new = dl_symbol("gtk_hseparator_new");
 585         fp_gtk_vseparator_new = dl_symbol("gtk_vseparator_new");
 586         fp_gtk_label_new = dl_symbol("gtk_label_new");
 587         fp_gtk_menu_new = dl_symbol("gtk_menu_new");
 588         fp_gtk_menu_bar_new = dl_symbol("gtk_menu_bar_new");
 589         fp_gtk_menu_item_new = dl_symbol("gtk_menu_item_new");
 590         fp_gtk_menu_item_set_submenu =
 591                 dl_symbol("gtk_menu_item_set_submenu");
 592         fp_gtk_notebook_new = dl_symbol("gtk_notebook_new");
 593         fp_gtk_progress_bar_new =
 594             dl_symbol("gtk_progress_bar_new");
 595         fp_gtk_progress_bar_set_orientation =
 596             dl_symbol("gtk_progress_bar_set_orientation");
 597         fp_gtk_radio_button_new =
 598             dl_symbol("gtk_radio_button_new");
 599         fp_gtk_radio_menu_item_new =
 600             dl_symbol("gtk_radio_menu_item_new");
 601         fp_gtk_scrolled_window_new =
 602             dl_symbol("gtk_scrolled_window_new");
 603         fp_gtk_separator_menu_item_new =
 604             dl_symbol("gtk_separator_menu_item_new");
 605         fp_gtk_text_view_new = dl_symbol("gtk_text_view_new");
 606         fp_gtk_toggle_button_new =
 607             dl_symbol("gtk_toggle_button_new");
 608         fp_gtk_toolbar_new = dl_symbol("gtk_toolbar_new");
 609         fp_gtk_tree_view_new = dl_symbol("gtk_tree_view_new");
 610         fp_gtk_viewport_new = dl_symbol("gtk_viewport_new");
 611         fp_gtk_window_new = dl_symbol("gtk_window_new");
 612         fp_gtk_window_present = dl_symbol("gtk_window_present");
 613         fp_gtk_window_move = dl_symbol("gtk_window_move");
 614         fp_gtk_window_resize = dl_symbol("gtk_window_resize");
 615 
 616           fp_gtk_dialog_new = dl_symbol("gtk_dialog_new");
 617         fp_gtk_frame_new = dl_symbol("gtk_frame_new");
 618 
 619         fp_gtk_adjustment_new = dl_symbol("gtk_adjustment_new");
 620         fp_gtk_container_add = dl_symbol("gtk_container_add");
 621         fp_gtk_menu_shell_append =
 622             dl_symbol("gtk_menu_shell_append");
 623         fp_gtk_widget_realize = dl_symbol("gtk_widget_realize");
 624         fp_gtk_widget_destroy = dl_symbol("gtk_widget_destroy");
 625         fp_gtk_widget_render_icon =
 626             dl_symbol("gtk_widget_render_icon");
 627         fp_gtk_widget_set_name =
 628             dl_symbol("gtk_widget_set_name");
 629         fp_gtk_widget_set_parent =
 630             dl_symbol("gtk_widget_set_parent");
 631         fp_gtk_widget_set_direction =
 632             dl_symbol("gtk_widget_set_direction");
 633         fp_gtk_widget_style_get =
 634             dl_symbol("gtk_widget_style_get");
 635         fp_gtk_widget_class_install_style_property =
 636             dl_symbol("gtk_widget_class_install_style_property");
 637         fp_gtk_widget_class_find_style_property =
 638             dl_symbol("gtk_widget_class_find_style_property");
 639         fp_gtk_widget_style_get_property =
 640             dl_symbol("gtk_widget_style_get_property");
 641         fp_pango_font_description_to_string =
 642             dl_symbol("pango_font_description_to_string");
 643         fp_gtk_settings_get_default =
 644             dl_symbol("gtk_settings_get_default");
 645         fp_gtk_widget_get_settings =
 646             dl_symbol("gtk_widget_get_settings");
 647         fp_gtk_border_get_type =  dl_symbol("gtk_border_get_type");
 648         fp_gtk_arrow_set = dl_symbol("gtk_arrow_set");
 649         fp_gtk_widget_size_request =
 650             dl_symbol("gtk_widget_size_request");
 651         fp_gtk_range_get_adjustment =
 652             dl_symbol("gtk_range_get_adjustment");
 653 
 654         fp_gtk_widget_hide = dl_symbol("gtk_widget_hide");
 655         fp_gtk_main_quit = dl_symbol("gtk_main_quit");
 656         fp_g_signal_connect_data = dl_symbol("g_signal_connect_data");
 657         fp_gtk_widget_show = dl_symbol("gtk_widget_show");
 658         fp_gtk_main = dl_symbol("gtk_main");
 659 
 660         /**
 661          * GLib thread system
 662          */
 663         fp_g_thread_init = dl_symbol_gthread("g_thread_init");
 664         fp_gdk_threads_init = dl_symbol("gdk_threads_init");
 665         fp_gdk_threads_enter = dl_symbol("gdk_threads_enter");
 666         fp_gdk_threads_leave = dl_symbol("gdk_threads_leave");
 667 
 668         /**
 669          * Functions for sun_awt_X11_GtkFileDialogPeer.c
 670          */
 671         if (fp_gtk_check_version(2, 4, 0) == NULL) {
 672             // The current GtkFileChooser is available from GTK+ 2.4
 673             gtk2_file_chooser_load();
 674         }
 675 
 676         /* Some functions may be missing in pre-2.4 GTK.
 677            We handle them specially here.
 678          */
 679         fp_gtk_combo_box_new = dlsym(gtk2_libhandle, "gtk_combo_box_new");
 680         if (fp_gtk_combo_box_new == NULL) {
 681             fp_gtk_combo_box_new = dl_symbol("gtk_combo_new");
 682         }
 683 
 684         fp_gtk_combo_box_entry_new =
 685             dlsym(gtk2_libhandle, "gtk_combo_box_entry_new");
 686         if (fp_gtk_combo_box_entry_new == NULL) {
 687             fp_gtk_combo_box_entry_new = dl_symbol("gtk_combo_new");
 688             new_combo = FALSE;
 689         }
 690 
 691         fp_gtk_separator_tool_item_new =
 692             dlsym(gtk2_libhandle, "gtk_separator_tool_item_new");
 693         if (fp_gtk_separator_tool_item_new == NULL) {
 694             fp_gtk_separator_tool_item_new =
 695                 dl_symbol("gtk_vseparator_new");
 696         }
 697     }
 698     /* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION
 699      * Otherwise we can check the return value of setjmp method.
 700      */
 701     else
 702     {
 703         dlclose(gtk2_libhandle);
 704         gtk2_libhandle = NULL;
 705 
 706         dlclose(gthread_libhandle);
 707         gthread_libhandle = NULL;
 708 
 709         return FALSE;
 710     }
 711 
 712     /*
 713      * Strip the AT-SPI GTK_MODULEs if present
 714      */
 715     gtk_modules_env = getenv ("GTK_MODULES");
 716 
 717     if (gtk_modules_env && strstr (gtk_modules_env, "atk-bridge") ||
 718         gtk_modules_env && strstr (gtk_modules_env, "gail"))
 719     {
 720         /* the new env will be smaller than the old one */
 721         gchar *s, *new_env = malloc (sizeof(ENV_PREFIX)+strlen (gtk_modules_env));
 722 
 723         if (new_env != NULL )
 724         {
 725             /* careful, strtok modifies its args */
 726             gchar *tmp_env = strdup (gtk_modules_env);
 727             strcpy(new_env, ENV_PREFIX);
 728 
 729             /* strip out 'atk-bridge' and 'gail' */
 730             size_t PREFIX_LENGTH = strlen(ENV_PREFIX);
 731             while (s = strtok(tmp_env, ":"))
 732             {
 733                 if ((!strstr (s, "atk-bridge")) && (!strstr (s, "gail")))
 734                 {
 735                     if (strlen (new_env) > PREFIX_LENGTH) {
 736                         new_env = strcat (new_env, ":");
 737                     }
 738                     new_env = strcat(new_env, s);
 739                 }
 740                 if (tmp_env)
 741                 {
 742                     free (tmp_env);
 743                     tmp_env = NULL; /* next call to strtok arg1==NULL */
 744                 }
 745             }
 746             putenv (new_env);
 747             free (new_env);
 748         }
 749     }
 750 
 751     /*
 752      * GTK should be initialized with gtk_init_check() before use.
 753      *
 754      * gtk_init_check installs its own error handlers. It is critical that
 755      * we preserve error handler set from AWT. Otherwise we'll crash on
 756      * BadMatch errors which we would normally ignore. The IO error handler
 757      * is preserved here, too, just for consistency.
 758     */
 759     handler = XSetErrorHandler(NULL);
 760     io_handler = XSetIOErrorHandler(NULL);
 761 
 762     if (fp_gtk_check_version(2, 2, 0) == NULL) {
 763         // Init the thread system to use GLib in a thread-safe mode
 764         if (!flag_g_thread_get_initialized) {
 765             flag_g_thread_get_initialized = TRUE;
 766 
 767             fp_g_thread_init(NULL);
 768 
 769             //According the GTK documentation, gdk_threads_init() should be
 770             //called before gtk_init() or gtk_init_check()
 771             fp_gdk_threads_init();
 772         }
 773     }
 774     result = (*fp_gtk_init_check)(NULL, NULL);
 775 
 776     XSetErrorHandler(handler);
 777     XSetIOErrorHandler(io_handler);
 778 
 779     /* Initialize widget array. */
 780     for (i = 0; i < _GTK_WIDGET_TYPE_SIZE; i++)
 781     {
 782         gtk2_widgets[i] = NULL;
 783     }
 784 
 785     return result;
 786 }
 787 
 788 int gtk2_unload()
 789 {
 790     int i;
 791     char *gtk2_error;
 792 
 793     if (!gtk2_libhandle)
 794         return TRUE;
 795 
 796     /* Release painting objects */
 797     if (gtk2_white_pixmap != NULL) {
 798         (*fp_g_object_unref)(gtk2_white_pixmap);
 799         (*fp_g_object_unref)(gtk2_black_pixmap);
 800         (*fp_g_object_unref)(gtk2_white_pixbuf);
 801         (*fp_g_object_unref)(gtk2_black_pixbuf);
 802         gtk2_white_pixmap = gtk2_black_pixmap =
 803             gtk2_white_pixbuf = gtk2_black_pixbuf = NULL;
 804     }
 805     gtk2_pixbuf_width = 0;
 806     gtk2_pixbuf_height = 0;
 807 
 808     if (gtk2_window != NULL) {
 809         /* Destroying toplevel widget will destroy all contained widgets */
 810         (*fp_gtk_widget_destroy)(gtk2_window);
 811 
 812         /* Unset some static data so they get reinitialized on next load */
 813         gtk2_window = NULL;
 814     }
 815 
 816     dlerror();
 817     dlclose(gtk2_libhandle);
 818     dlclose(gthread_libhandle);
 819     if ((gtk2_error = dlerror()) != NULL)
 820     {
 821         return FALSE;
 822     }
 823     return TRUE;
 824 }
 825 
 826 /* Dispatch all pending events from the GTK event loop.
 827  * This is needed to catch theme change and update widgets' style.
 828  */
 829 void flush_gtk_event_loop()
 830 {
 831     while( (*fp_g_main_context_iteration)(NULL, FALSE));
 832 }
 833 
 834 /*
 835  * Initialize components of containment hierarchy. This creates a GtkFixed
 836  * inside a GtkWindow. All widgets get realized.
 837  */
 838 static void init_containers()
 839 {
 840     if (gtk2_window == NULL)
 841     {
 842         gtk2_window = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);
 843         gtk2_fixed = (GtkFixed *)(*fp_gtk_fixed_new)();
 844         (*fp_gtk_container_add)((GtkContainer*)gtk2_window,
 845                                 (GtkWidget *)gtk2_fixed);
 846         (*fp_gtk_widget_realize)(gtk2_window);
 847         (*fp_gtk_widget_realize)((GtkWidget *)gtk2_fixed);
 848     }
 849 }
 850 
 851 /*
 852  * Ensure everything is ready for drawing an element of the specified width
 853  * and height.
 854  *
 855  * We should somehow handle translucent images. GTK can draw to X Drawables
 856  * only, which don't support alpha. When we retrieve the image back from
 857  * the server, translucency information is lost. There're several ways to
 858  * work around this:
 859  * 1) Subclass GdkPixmap and cache translucent objects on client side. This
 860  * requires us to implement parts of X server drawing logic on client side.
 861  * Many X requests can potentially be "translucent"; e.g. XDrawLine with
 862  * fill=tile and a translucent tile is a "translucent" operation, whereas
 863  * XDrawLine with fill=solid is an "opaque" one. Moreover themes can (and some
 864  * do) intermix transparent and opaque operations which makes caching even
 865  * more problematic.
 866  * 2) Use Xorg 32bit ARGB visual when available. GDK has no native support
 867  * for it (as of version 2.6). Also even in JDS 3 Xorg does not support
 868  * these visuals by default, which makes optimizing for them pointless.
 869  * We can consider doing this at a later point when ARGB visuals become more
 870  * popular.
 871  * 3') GTK has plans to use Cairo as its graphical backend (presumably in
 872  * 2.8), and Cairo supports alpha. With it we could also get rid of the
 873  * unnecessary round trip to server and do all the drawing on client side.
 874  * 4) For now we draw to two different pixmaps and restore alpha channel by
 875  * comparing results. This can be optimized by using subclassed pixmap and
 876  * doing the second drawing only if necessary.
 877 */
 878 void gtk2_init_painting(JNIEnv *env, gint width, gint height)
 879 {
 880     GdkGC *gc;
 881     GdkPixbuf *white, *black;
 882 
 883     init_containers();
 884 
 885     if (gtk2_pixbuf_width < width || gtk2_pixbuf_height < height)
 886     {
 887         white = (*fp_gdk_pixbuf_new)(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
 888         black = (*fp_gdk_pixbuf_new)(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
 889 
 890         if (white == NULL || black == NULL)
 891         {
 892             snprintf(convertionBuffer, CONV_BUFFER_SIZE, "Couldn't create pixbuf of size %dx%d", width, height);
 893             throw_exception(env, "java/lang/RuntimeException", convertionBuffer);
 894             fp_gdk_threads_leave();
 895             return;
 896         }
 897 
 898         if (gtk2_white_pixmap != NULL) {
 899             /* free old stuff */
 900             (*fp_g_object_unref)(gtk2_white_pixmap);
 901             (*fp_g_object_unref)(gtk2_black_pixmap);
 902             (*fp_g_object_unref)(gtk2_white_pixbuf);
 903             (*fp_g_object_unref)(gtk2_black_pixbuf);
 904         }
 905 
 906         gtk2_white_pixmap = (*fp_gdk_pixmap_new)(gtk2_window->window, width, height, -1);
 907         gtk2_black_pixmap = (*fp_gdk_pixmap_new)(gtk2_window->window, width, height, -1);
 908 
 909         gtk2_white_pixbuf = white;
 910         gtk2_black_pixbuf = black;
 911 
 912         gtk2_pixbuf_width = width;
 913         gtk2_pixbuf_height = height;
 914     }
 915 
 916     /* clear the pixmaps */
 917     gc = (*fp_gdk_gc_new)(gtk2_white_pixmap);
 918     (*fp_gdk_rgb_gc_set_foreground)(gc, 0xffffff);
 919     (*fp_gdk_draw_rectangle)(gtk2_white_pixmap, gc, TRUE, 0, 0, width, height);
 920     (*fp_g_object_unref)(gc);
 921 
 922     gc = (*fp_gdk_gc_new)(gtk2_black_pixmap);
 923     (*fp_gdk_rgb_gc_set_foreground)(gc, 0x000000);
 924     (*fp_gdk_draw_rectangle)(gtk2_black_pixmap, gc, TRUE, 0, 0, width, height);
 925     (*fp_g_object_unref)(gc);
 926 }
 927 
 928 /*
 929  * Restore image from white and black pixmaps and copy it into destination
 930  * buffer. This method compares two pixbufs taken from white and black
 931  * pixmaps and decodes color and alpha components. Pixbufs are RGB without
 932  * alpha, destination buffer is ABGR.
 933  *
 934  * The return value is the transparency type of the resulting image, either
 935  * one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and
 936  * java_awt_Transparency_TRANSLUCENT.
 937  */
 938 gint gtk2_copy_image(gint *dst, gint width, gint height)
 939 {
 940     gint i, j, r, g, b;
 941     guchar *white, *black;
 942     gint stride, padding;
 943     gboolean is_opaque = TRUE;
 944     gboolean is_bitmask = TRUE;
 945 
 946     (*fp_gdk_pixbuf_get_from_drawable)(gtk2_white_pixbuf, gtk2_white_pixmap,
 947             NULL, 0, 0, 0, 0, width, height);
 948     (*fp_gdk_pixbuf_get_from_drawable)(gtk2_black_pixbuf, gtk2_black_pixmap,
 949             NULL, 0, 0, 0, 0, width, height);
 950 
 951     white = (*fp_gdk_pixbuf_get_pixels)(gtk2_white_pixbuf);
 952     black = (*fp_gdk_pixbuf_get_pixels)(gtk2_black_pixbuf);
 953     stride = (*fp_gdk_pixbuf_get_rowstride)(gtk2_black_pixbuf);
 954     padding = stride - width * 4;
 955 
 956     for (i = 0; i < height; i++) {
 957         for (j = 0; j < width; j++) {
 958             int r1 = *white++;
 959             int r2 = *black++;
 960             int alpha = 0xff + r2 - r1;
 961 
 962             switch (alpha) {
 963                 case 0:       /* transparent pixel */
 964                     r = g = b = 0;
 965                     black += 3;
 966                     white += 3;
 967                     is_opaque = FALSE;
 968                     break;
 969 
 970                 case 0xff:    /* opaque pixel */
 971                     r = r2;
 972                     g = *black++;
 973                     b = *black++;
 974                     black++;
 975                     white += 3;
 976                     break;
 977 
 978                 default:      /* translucent pixel */
 979                     r = 0xff * r2 / alpha;
 980                     g = 0xff * *black++ / alpha;
 981                     b = 0xff * *black++ / alpha;
 982                     black++;
 983                     white += 3;
 984                     is_opaque = FALSE;
 985                     is_bitmask = FALSE;
 986                     break;
 987             }
 988 
 989             *dst++ = (alpha << 24 | r << 16 | g << 8 | b);
 990         }
 991 
 992         white += padding;
 993         black += padding;
 994     }
 995     return is_opaque ? java_awt_Transparency_OPAQUE :
 996                        (is_bitmask ? java_awt_Transparency_BITMASK :
 997                                      java_awt_Transparency_TRANSLUCENT);
 998 }
 999 
1000 static void
1001 gtk2_set_direction(GtkWidget *widget, GtkTextDirection dir)
1002 {
1003     /*
1004      * Some engines (inexplicably) look at the direction of the widget's
1005      * parent, so we need to set the direction of both the widget and its
1006      * parent.
1007      */
1008     (*fp_gtk_widget_set_direction)(widget, dir);
1009     if (widget->parent != NULL) {
1010         (*fp_gtk_widget_set_direction)(widget->parent, dir);
1011     }
1012 }
1013 
1014 /*
1015  * Initializes the widget to correct state for some engines.
1016  * This is a pure empirical method.
1017  */
1018 static void init_toggle_widget(WidgetType widget_type, gint synth_state)
1019 {
1020     gboolean is_active = ((synth_state & SELECTED) != 0);
1021 
1022     if (widget_type == RADIO_BUTTON ||
1023         widget_type == CHECK_BOX ||
1024         widget_type == TOGGLE_BUTTON) {
1025         ((GtkToggleButton*)gtk2_widget)->active = is_active;
1026     }
1027 
1028     if ((synth_state & FOCUSED) != 0) {
1029         ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS;
1030     } else {
1031         ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS;
1032     }
1033 
1034     if ((synth_state & MOUSE_OVER) != 0 && (synth_state & PRESSED) == 0 ||
1035            (synth_state & FOCUSED) != 0 && (synth_state & PRESSED) != 0) {
1036         gtk2_widget->state = GTK_STATE_PRELIGHT;
1037     } else if ((synth_state & DISABLED) != 0) {
1038         gtk2_widget->state = GTK_STATE_INSENSITIVE;
1039     } else {
1040         gtk2_widget->state = is_active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL;
1041     }
1042 }
1043 
1044 /* GTK state_type filter */
1045 static GtkStateType get_gtk_state_type(WidgetType widget_type, gint synth_state)
1046 {
1047     GtkStateType result = GTK_STATE_NORMAL;
1048 
1049     if ((synth_state & DISABLED) != 0) {
1050         result = GTK_STATE_INSENSITIVE;
1051     } else if ((synth_state & PRESSED) != 0) {
1052         result = GTK_STATE_ACTIVE;
1053     } else if ((synth_state & MOUSE_OVER) != 0) {
1054         result = GTK_STATE_PRELIGHT;
1055     }
1056     return result;
1057 }
1058 
1059 /* GTK shadow_type filter */
1060 static GtkShadowType get_gtk_shadow_type(WidgetType widget_type, gint synth_state)
1061 {
1062     GtkShadowType result = GTK_SHADOW_OUT;
1063 
1064     if ((synth_state & SELECTED) != 0) {
1065         result = GTK_SHADOW_IN;
1066     }
1067     return result;
1068 }
1069 
1070 
1071 static GtkWidget* gtk2_get_arrow(GtkArrowType arrow_type, GtkShadowType shadow_type)
1072 {
1073     GtkWidget *arrow = NULL;
1074     if (NULL == gtk2_widgets[_GTK_ARROW_TYPE])
1075     {
1076         gtk2_widgets[_GTK_ARROW_TYPE] = (*fp_gtk_arrow_new)(arrow_type, shadow_type);
1077         (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, gtk2_widgets[_GTK_ARROW_TYPE]);
1078         (*fp_gtk_widget_realize)(gtk2_widgets[_GTK_ARROW_TYPE]);
1079     }
1080     arrow = gtk2_widgets[_GTK_ARROW_TYPE];
1081 
1082     (*fp_gtk_arrow_set)(arrow, arrow_type, shadow_type);
1083     return arrow;
1084 }
1085 
1086 static GtkAdjustment* create_adjustment()
1087 {
1088     return (GtkAdjustment *)
1089             (*fp_gtk_adjustment_new)(50.0, 0.0, 100.0, 10.0, 20.0, 20.0);
1090 }
1091 
1092 /**
1093  * Returns a pointer to the cached native widget for the specified widget
1094  * type.
1095  */
1096 static GtkWidget *gtk2_get_widget(WidgetType widget_type)
1097 {
1098     gboolean init_result = FALSE;
1099     GtkWidget *result = NULL;
1100     switch (widget_type)
1101     {
1102         case BUTTON:
1103         case TABLE_HEADER:
1104             if (init_result = (NULL == gtk2_widgets[_GTK_BUTTON_TYPE]))
1105             {
1106                 gtk2_widgets[_GTK_BUTTON_TYPE] = (*fp_gtk_button_new)();
1107             }
1108             result = gtk2_widgets[_GTK_BUTTON_TYPE];
1109             break;
1110         case CHECK_BOX:
1111             if (init_result = (NULL == gtk2_widgets[_GTK_CHECK_BUTTON_TYPE]))
1112             {
1113                 gtk2_widgets[_GTK_CHECK_BUTTON_TYPE] =
1114                     (*fp_gtk_check_button_new)();
1115             }
1116             result = gtk2_widgets[_GTK_CHECK_BUTTON_TYPE];
1117             break;
1118         case CHECK_BOX_MENU_ITEM:
1119             if (init_result = (NULL == gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE]))
1120             {
1121                 gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE] =
1122                     (*fp_gtk_check_menu_item_new)();
1123             }
1124             result = gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE];
1125             break;
1126         /************************************************************
1127          *    Creation a dedicated color chooser is dangerous because
1128          * it deadlocks the EDT
1129          ************************************************************/
1130 /*        case COLOR_CHOOSER:
1131             if (init_result =
1132                     (NULL == gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE]))
1133             {
1134                 gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE] =
1135                     (*fp_gtk_color_selection_dialog_new)(NULL);
1136             }
1137             result = gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE];
1138             break;*/
1139         case COMBO_BOX:
1140             if (init_result = (NULL == gtk2_widgets[_GTK_COMBO_BOX_TYPE]))
1141             {
1142                 gtk2_widgets[_GTK_COMBO_BOX_TYPE] =
1143                     (*fp_gtk_combo_box_new)();
1144             }
1145             result = gtk2_widgets[_GTK_COMBO_BOX_TYPE];
1146             break;
1147         case COMBO_BOX_ARROW_BUTTON:
1148             if (init_result =
1149                     (NULL == gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE]))
1150             {
1151                 gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE] =
1152                      (*fp_gtk_toggle_button_new)();
1153             }
1154             result = gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE];
1155             break;
1156         case COMBO_BOX_TEXT_FIELD:
1157             if (init_result =
1158                     (NULL == gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE]))
1159             {
1160                 result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] =
1161                      (*fp_gtk_entry_new)();
1162 
1163                 GtkSettings* settings = fp_gtk_widget_get_settings(result);
1164                 fp_g_object_set(settings, "gtk-cursor-blink", FALSE, NULL);
1165             }
1166             result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE];
1167             break;
1168         case DESKTOP_ICON:
1169         case INTERNAL_FRAME_TITLE_PANE:
1170         case LABEL:
1171             if (init_result = (NULL == gtk2_widgets[_GTK_LABEL_TYPE]))
1172             {
1173                 gtk2_widgets[_GTK_LABEL_TYPE] =
1174                     (*fp_gtk_label_new)(NULL);
1175             }
1176             result = gtk2_widgets[_GTK_LABEL_TYPE];
1177             break;
1178         case DESKTOP_PANE:
1179         case PANEL:
1180         case ROOT_PANE:
1181             if (init_result = (NULL == gtk2_widgets[_GTK_CONTAINER_TYPE]))
1182             {
1183                 /* There is no constructor for a container type.  I've
1184                  * choosen GtkFixed container since it has a default
1185                  * constructor.
1186                  */
1187                 gtk2_widgets[_GTK_CONTAINER_TYPE] =
1188                     (*fp_gtk_fixed_new)();
1189             }
1190             result = gtk2_widgets[_GTK_CONTAINER_TYPE];
1191             break;
1192         case EDITOR_PANE:
1193         case TEXT_AREA:
1194         case TEXT_PANE:
1195             if (init_result = (NULL == gtk2_widgets[_GTK_TEXT_VIEW_TYPE]))
1196             {
1197                 gtk2_widgets[_GTK_TEXT_VIEW_TYPE] =
1198                     (*fp_gtk_text_view_new)();
1199             }
1200             result = gtk2_widgets[_GTK_TEXT_VIEW_TYPE];
1201             break;
1202         case FORMATTED_TEXT_FIELD:
1203         case PASSWORD_FIELD:
1204         case TEXT_FIELD:
1205             if (init_result = (NULL == gtk2_widgets[_GTK_ENTRY_TYPE]))
1206             {
1207                 gtk2_widgets[_GTK_ENTRY_TYPE] =
1208                     (*fp_gtk_entry_new)();
1209 
1210                 GtkSettings* settings =
1211                     fp_gtk_widget_get_settings(gtk2_widgets[_GTK_ENTRY_TYPE]);
1212                 fp_g_object_set(settings, "gtk-cursor-blink", FALSE, NULL);
1213             }
1214             result = gtk2_widgets[_GTK_ENTRY_TYPE];
1215             break;
1216         case HANDLE_BOX:
1217             if (init_result = (NULL == gtk2_widgets[_GTK_HANDLE_BOX_TYPE]))
1218             {
1219                 gtk2_widgets[_GTK_HANDLE_BOX_TYPE] =
1220                     (*fp_gtk_handle_box_new)();
1221             }
1222             result = gtk2_widgets[_GTK_HANDLE_BOX_TYPE];
1223             break;
1224         case HSCROLL_BAR:
1225         case HSCROLL_BAR_BUTTON_LEFT:
1226         case HSCROLL_BAR_BUTTON_RIGHT:
1227         case HSCROLL_BAR_TRACK:
1228         case HSCROLL_BAR_THUMB:
1229             if (init_result = (NULL == gtk2_widgets[_GTK_HSCROLLBAR_TYPE]))
1230             {
1231                 gtk2_widgets[_GTK_HSCROLLBAR_TYPE] =
1232                     (*fp_gtk_hscrollbar_new)(create_adjustment());
1233             }
1234             result = gtk2_widgets[_GTK_HSCROLLBAR_TYPE];
1235             break;
1236         case HSEPARATOR:
1237             if (init_result = (NULL == gtk2_widgets[_GTK_HSEPARATOR_TYPE]))
1238             {
1239                 gtk2_widgets[_GTK_HSEPARATOR_TYPE] =
1240                     (*fp_gtk_hseparator_new)();
1241             }
1242             result = gtk2_widgets[_GTK_HSEPARATOR_TYPE];
1243             break;
1244         case HSLIDER:
1245         case HSLIDER_THUMB:
1246         case HSLIDER_TRACK:
1247             if (init_result = (NULL == gtk2_widgets[_GTK_HSCALE_TYPE]))
1248             {
1249                 gtk2_widgets[_GTK_HSCALE_TYPE] =
1250                     (*fp_gtk_hscale_new)(NULL);
1251             }
1252             result = gtk2_widgets[_GTK_HSCALE_TYPE];
1253             break;
1254         case HSPLIT_PANE_DIVIDER:
1255         case SPLIT_PANE:
1256             if (init_result = (NULL == gtk2_widgets[_GTK_HPANED_TYPE]))
1257             {
1258                 gtk2_widgets[_GTK_HPANED_TYPE] = (*fp_gtk_hpaned_new)();
1259             }
1260             result = gtk2_widgets[_GTK_HPANED_TYPE];
1261             break;
1262         case IMAGE:
1263             if (init_result = (NULL == gtk2_widgets[_GTK_IMAGE_TYPE]))
1264             {
1265                 gtk2_widgets[_GTK_IMAGE_TYPE] = (*fp_gtk_image_new)();
1266             }
1267             result = gtk2_widgets[_GTK_IMAGE_TYPE];
1268             break;
1269         case INTERNAL_FRAME:
1270             if (init_result = (NULL == gtk2_widgets[_GTK_WINDOW_TYPE]))
1271             {
1272                 gtk2_widgets[_GTK_WINDOW_TYPE] =
1273                     (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);
1274             }
1275             result = gtk2_widgets[_GTK_WINDOW_TYPE];
1276             break;
1277         case TOOL_TIP:
1278             if (init_result = (NULL == gtk2_widgets[_GTK_TOOLTIP_TYPE]))
1279             {
1280                 result = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);
1281                 (*fp_gtk_widget_set_name)(result, "gtk-tooltips");
1282                 gtk2_widgets[_GTK_TOOLTIP_TYPE] = result;
1283             }
1284             result = gtk2_widgets[_GTK_TOOLTIP_TYPE];
1285             break;
1286         case LIST:
1287         case TABLE:
1288         case TREE:
1289         case TREE_CELL:
1290             if (init_result = (NULL == gtk2_widgets[_GTK_TREE_VIEW_TYPE]))
1291             {
1292                 gtk2_widgets[_GTK_TREE_VIEW_TYPE] =
1293                     (*fp_gtk_tree_view_new)();
1294             }
1295             result = gtk2_widgets[_GTK_TREE_VIEW_TYPE];
1296             break;
1297         case TITLED_BORDER:
1298             if (init_result = (NULL == gtk2_widgets[_GTK_FRAME_TYPE]))
1299             {
1300                 gtk2_widgets[_GTK_FRAME_TYPE] = fp_gtk_frame_new(NULL);
1301             }
1302             result = gtk2_widgets[_GTK_FRAME_TYPE];
1303             break;
1304         case POPUP_MENU:
1305             if (init_result = (NULL == gtk2_widgets[_GTK_MENU_TYPE]))
1306             {
1307                 gtk2_widgets[_GTK_MENU_TYPE] =
1308                     (*fp_gtk_menu_new)();
1309             }
1310             result = gtk2_widgets[_GTK_MENU_TYPE];
1311             break;
1312         case MENU:
1313         case MENU_ITEM:
1314         case MENU_ITEM_ACCELERATOR:
1315             if (init_result = (NULL == gtk2_widgets[_GTK_MENU_ITEM_TYPE]))
1316             {
1317                 gtk2_widgets[_GTK_MENU_ITEM_TYPE] =
1318                     (*fp_gtk_menu_item_new)();
1319             }
1320             result = gtk2_widgets[_GTK_MENU_ITEM_TYPE];
1321             break;
1322         case MENU_BAR:
1323             if (init_result = (NULL == gtk2_widgets[_GTK_MENU_BAR_TYPE]))
1324             {
1325                 gtk2_widgets[_GTK_MENU_BAR_TYPE] =
1326                     (*fp_gtk_menu_bar_new)();
1327             }
1328             result = gtk2_widgets[_GTK_MENU_BAR_TYPE];
1329             break;
1330         case COLOR_CHOOSER:
1331         case OPTION_PANE:
1332             if (init_result = (NULL == gtk2_widgets[_GTK_DIALOG_TYPE]))
1333             {
1334                 gtk2_widgets[_GTK_DIALOG_TYPE] =
1335                     (*fp_gtk_dialog_new)();
1336             }
1337             result = gtk2_widgets[_GTK_DIALOG_TYPE];
1338             break;
1339         case POPUP_MENU_SEPARATOR:
1340             if (init_result =
1341                     (NULL == gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE]))
1342             {
1343                 gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE] =
1344                     (*fp_gtk_separator_menu_item_new)();
1345             }
1346             result = gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE];
1347             break;
1348         case HPROGRESS_BAR:
1349             if (init_result = (NULL == gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE]))
1350             {
1351                 gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE] =
1352                     (*fp_gtk_progress_bar_new)();
1353             }
1354             result = gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE];
1355             break;
1356         case VPROGRESS_BAR:
1357             if (init_result = (NULL == gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE]))
1358             {
1359                 gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE] =
1360                     (*fp_gtk_progress_bar_new)();
1361                 /*
1362                  * Vertical JProgressBars always go bottom-to-top,
1363                  * regardless of the ComponentOrientation.
1364                  */
1365                 (*fp_gtk_progress_bar_set_orientation)(
1366                     (GtkProgressBar *)gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE],
1367                     GTK_PROGRESS_BOTTOM_TO_TOP);
1368             }
1369             result = gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE];
1370             break;
1371         case RADIO_BUTTON:
1372             if (init_result = (NULL == gtk2_widgets[_GTK_RADIO_BUTTON_TYPE]))
1373             {
1374                 gtk2_widgets[_GTK_RADIO_BUTTON_TYPE] =
1375                     (*fp_gtk_radio_button_new)(NULL);
1376             }
1377             result = gtk2_widgets[_GTK_RADIO_BUTTON_TYPE];
1378             break;
1379         case RADIO_BUTTON_MENU_ITEM:
1380             if (init_result =
1381                     (NULL == gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE]))
1382             {
1383                 gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE] =
1384                     (*fp_gtk_radio_menu_item_new)(NULL);
1385             }
1386             result = gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE];
1387             break;
1388         case SCROLL_PANE:
1389             if (init_result =
1390                     (NULL == gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE]))
1391             {
1392                 gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE] =
1393                     (*fp_gtk_scrolled_window_new)(NULL, NULL);
1394             }
1395             result = gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE];
1396             break;
1397         case SPINNER:
1398         case SPINNER_ARROW_BUTTON:
1399         case SPINNER_TEXT_FIELD:
1400             if (init_result = (NULL == gtk2_widgets[_GTK_SPIN_BUTTON_TYPE]))
1401             {
1402                 result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE] =
1403                     (*fp_gtk_spin_button_new)(NULL, 0, 0);
1404 
1405                 GtkSettings* settings = fp_gtk_widget_get_settings(result);
1406                 fp_g_object_set(settings, "gtk-cursor-blink", FALSE, NULL);
1407             }
1408             result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE];
1409             break;
1410         case TABBED_PANE:
1411         case TABBED_PANE_TAB_AREA:
1412         case TABBED_PANE_CONTENT:
1413         case TABBED_PANE_TAB:
1414             if (init_result = (NULL == gtk2_widgets[_GTK_NOTEBOOK_TYPE]))
1415             {
1416                 gtk2_widgets[_GTK_NOTEBOOK_TYPE] =
1417                     (*fp_gtk_notebook_new)(NULL);
1418             }
1419             result = gtk2_widgets[_GTK_NOTEBOOK_TYPE];
1420             break;
1421         case TOGGLE_BUTTON:
1422             if (init_result = (NULL == gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE]))
1423             {
1424                 gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE] =
1425                     (*fp_gtk_toggle_button_new)(NULL);
1426             }
1427             result = gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE];
1428             break;
1429         case TOOL_BAR:
1430         case TOOL_BAR_DRAG_WINDOW:
1431             if (init_result = (NULL == gtk2_widgets[_GTK_TOOLBAR_TYPE]))
1432             {
1433                 gtk2_widgets[_GTK_TOOLBAR_TYPE] =
1434                     (*fp_gtk_toolbar_new)(NULL);
1435             }
1436             result = gtk2_widgets[_GTK_TOOLBAR_TYPE];
1437             break;
1438         case TOOL_BAR_SEPARATOR:
1439             if (init_result =
1440                     (NULL == gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE]))
1441             {
1442                 gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE] =
1443                     (*fp_gtk_separator_tool_item_new)();
1444             }
1445             result = gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE];
1446             break;
1447         case VIEWPORT:
1448             if (init_result = (NULL == gtk2_widgets[_GTK_VIEWPORT_TYPE]))
1449             {
1450                 GtkAdjustment *adjustment = create_adjustment();
1451                 gtk2_widgets[_GTK_VIEWPORT_TYPE] =
1452                     (*fp_gtk_viewport_new)(adjustment, adjustment);
1453             }
1454             result = gtk2_widgets[_GTK_VIEWPORT_TYPE];
1455             break;
1456         case VSCROLL_BAR:
1457         case VSCROLL_BAR_BUTTON_UP:
1458         case VSCROLL_BAR_BUTTON_DOWN:
1459         case VSCROLL_BAR_TRACK:
1460         case VSCROLL_BAR_THUMB:
1461             if (init_result = (NULL == gtk2_widgets[_GTK_VSCROLLBAR_TYPE]))
1462             {
1463                 gtk2_widgets[_GTK_VSCROLLBAR_TYPE] =
1464                     (*fp_gtk_vscrollbar_new)(create_adjustment());
1465             }
1466             result = gtk2_widgets[_GTK_VSCROLLBAR_TYPE];
1467             break;
1468         case VSEPARATOR:
1469             if (init_result = (NULL == gtk2_widgets[_GTK_VSEPARATOR_TYPE]))
1470             {
1471                 gtk2_widgets[_GTK_VSEPARATOR_TYPE] =
1472                     (*fp_gtk_vseparator_new)();
1473             }
1474             result = gtk2_widgets[_GTK_VSEPARATOR_TYPE];
1475             break;
1476         case VSLIDER:
1477         case VSLIDER_THUMB:
1478         case VSLIDER_TRACK:
1479             if (init_result = (NULL == gtk2_widgets[_GTK_VSCALE_TYPE]))
1480             {
1481                 gtk2_widgets[_GTK_VSCALE_TYPE] =
1482                     (*fp_gtk_vscale_new)(NULL);
1483             }
1484             result = gtk2_widgets[_GTK_VSCALE_TYPE];
1485             /*
1486              * Vertical JSliders start at the bottom, while vertical
1487              * GtkVScale widgets start at the top (by default), so to fix
1488              * this we set the "inverted" flag to get the Swing behavior.
1489              */
1490             ((GtkRange*)result)->inverted = 1;
1491             break;
1492         case VSPLIT_PANE_DIVIDER:
1493             if (init_result = (NULL == gtk2_widgets[_GTK_VPANED_TYPE]))
1494             {
1495                 gtk2_widgets[_GTK_VPANED_TYPE] = (*fp_gtk_vpaned_new)();
1496             }
1497             result = gtk2_widgets[_GTK_VPANED_TYPE];
1498             break;
1499         default:
1500             result = NULL;
1501             break;
1502     }
1503 
1504     if (result != NULL && init_result)
1505     {
1506         if (widget_type == RADIO_BUTTON_MENU_ITEM ||
1507                 widget_type == CHECK_BOX_MENU_ITEM ||
1508                 widget_type == MENU_ITEM ||
1509                 widget_type == MENU ||
1510                 widget_type == POPUP_MENU_SEPARATOR)
1511         {
1512             GtkWidget *menu = gtk2_get_widget(POPUP_MENU);
1513             (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu, result);
1514         }
1515         else if (widget_type == POPUP_MENU)
1516         {
1517             GtkWidget *menu_bar = gtk2_get_widget(MENU_BAR);
1518             GtkWidget *root_menu = (*fp_gtk_menu_item_new)();
1519             (*fp_gtk_menu_item_set_submenu)((GtkMenuItem*)root_menu, result);
1520             (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu_bar, root_menu);
1521         }
1522         else if (widget_type == COMBO_BOX_ARROW_BUTTON ||
1523                  widget_type == COMBO_BOX_TEXT_FIELD)
1524         {
1525             /*
1526             * We add a regular GtkButton/GtkEntry to a GtkComboBoxEntry
1527             * in order to trick engines into thinking it's a real combobox
1528             * arrow button/text field.
1529             */
1530             GtkWidget *combo = (*fp_gtk_combo_box_entry_new)();
1531 
1532             if (new_combo && widget_type == COMBO_BOX_ARROW_BUTTON) {
1533                 (*fp_gtk_widget_set_parent)(result, combo);
1534                 ((GtkBin*)combo)->child = result;
1535             } else {
1536                 (*fp_gtk_container_add)((GtkContainer *)combo, result);
1537             }
1538             (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, combo);
1539         }
1540         else if (widget_type != TOOL_TIP &&
1541                  widget_type != INTERNAL_FRAME &&
1542                  widget_type != OPTION_PANE)
1543         {
1544             (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, result);
1545         }
1546         (*fp_gtk_widget_realize)(result);
1547     }
1548     return result;
1549 }
1550 
1551 void gtk2_paint_arrow(WidgetType widget_type, GtkStateType state_type,
1552         GtkShadowType shadow_type, const gchar *detail,
1553         gint x, gint y, gint width, gint height,
1554         GtkArrowType arrow_type, gboolean fill)
1555 {
1556     static int w, h;
1557     static GtkRequisition size;
1558 
1559     if (widget_type == COMBO_BOX_ARROW_BUTTON || widget_type == TABLE)
1560         gtk2_widget = gtk2_get_arrow(arrow_type, shadow_type);
1561     else
1562         gtk2_widget = gtk2_get_widget(widget_type);
1563 
1564     switch (widget_type)
1565     {
1566         case SPINNER_ARROW_BUTTON:
1567             x = 1;
1568             y = ((arrow_type == GTK_ARROW_UP) ? 2 : 0);
1569             height -= 2;
1570             width -= 3;
1571 
1572             w = width / 2;
1573             w -= w % 2 - 1;
1574             h = (w + 1) / 2;
1575             break;
1576 
1577         case HSCROLL_BAR_BUTTON_LEFT:
1578         case HSCROLL_BAR_BUTTON_RIGHT:
1579         case VSCROLL_BAR_BUTTON_UP:
1580         case VSCROLL_BAR_BUTTON_DOWN:
1581             w = width / 2;
1582             h = height / 2;
1583             break;
1584 
1585         case COMBO_BOX_ARROW_BUTTON:
1586         case TABLE:
1587             x = 1;
1588             (*fp_gtk_widget_size_request)(gtk2_widget, &size);
1589             w = size.width - ((GtkMisc*)gtk2_widget)->xpad * 2;
1590             h = size.height - ((GtkMisc*)gtk2_widget)->ypad * 2;
1591             w = h = MIN(MIN(w, h), MIN(width,height)) * 0.7;
1592             break;
1593 
1594         default:
1595             w = width;
1596             h = height;
1597             break;
1598     }
1599     x += (width - w) / 2;
1600     y += (height - h) / 2;
1601 
1602     (*fp_gtk_paint_arrow)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1603             shadow_type, NULL, gtk2_widget, detail, arrow_type, fill,
1604             x, y, w, h);
1605     (*fp_gtk_paint_arrow)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1606             shadow_type, NULL, gtk2_widget, detail, arrow_type, fill,
1607             x, y, w, h);
1608 }
1609 
1610 void gtk2_paint_box(WidgetType widget_type, GtkStateType state_type,
1611                     GtkShadowType shadow_type, const gchar *detail,
1612                     gint x, gint y, gint width, gint height,
1613                     gint synth_state, GtkTextDirection dir)
1614 {
1615     gtk2_widget = gtk2_get_widget(widget_type);
1616 
1617     /*
1618      * The clearlooks engine sometimes looks at the widget's state field
1619      * instead of just the state_type variable that we pass in, so to account
1620      * for those cases we set the widget's state field accordingly.  The
1621      * flags field is similarly important for things like focus/default state.
1622      */
1623     gtk2_widget->state = state_type;
1624 
1625     if (widget_type == HSLIDER_TRACK) {
1626         /*
1627          * For horizontal JSliders with right-to-left orientation, we need
1628          * to set the "inverted" flag to match the native GTK behavior where
1629          * the foreground highlight is on the right side of the slider thumb.
1630          * This is needed especially for the ubuntulooks engine, which looks
1631          * exclusively at the "inverted" flag to determine on which side of
1632          * the thumb to paint the highlight...
1633          */
1634         ((GtkRange*)gtk2_widget)->inverted = (dir == GTK_TEXT_DIR_RTL);
1635 
1636         /*
1637          * Note however that other engines like clearlooks will look at both
1638          * the "inverted" field and the text direction to determine how
1639          * the foreground highlight is painted:
1640          *     !inverted && ltr --> paint highlight on left side
1641          *     !inverted && rtl --> paint highlight on right side
1642          *      inverted && ltr --> paint highlight on right side
1643          *      inverted && rtl --> paint highlight on left side
1644          * So the only way to reliably get the desired results for horizontal
1645          * JSlider (i.e., highlight on left side for LTR ComponentOrientation
1646          * and highlight on right side for RTL ComponentOrientation) is to
1647          * always override text direction as LTR, and then set the "inverted"
1648          * flag accordingly (as we have done above).
1649          */
1650         dir = GTK_TEXT_DIR_LTR;
1651     }
1652 
1653     /*
1654      * Some engines (e.g. clearlooks) will paint the shadow of certain
1655      * widgets (e.g. COMBO_BOX_ARROW_BUTTON) differently depending on the
1656      * the text direction.
1657      */
1658     gtk2_set_direction(gtk2_widget, dir);
1659 
1660     switch (widget_type) {
1661     case BUTTON:
1662         if (synth_state & DEFAULT) {
1663             ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_DEFAULT;
1664         } else {
1665             ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_DEFAULT;
1666         }
1667         break;
1668     case TOGGLE_BUTTON:
1669         init_toggle_widget(widget_type, synth_state);
1670         break;
1671     case HSCROLL_BAR_BUTTON_LEFT:
1672         /*
1673          * The clearlooks engine will draw a "left" button when:
1674          *   x == w->allocation.x
1675          *
1676          * The ubuntulooks engine will draw a "left" button when:
1677          *   [x,y,width,height]
1678          *     intersects
1679          *   [w->alloc.x,w->alloc.y,width,height]
1680          *
1681          * The values that are set below should ensure that a "left"
1682          * button is rendered for both of these (and other) engines.
1683          */
1684         gtk2_widget->allocation.x = x;
1685         gtk2_widget->allocation.y = y;
1686         gtk2_widget->allocation.width = width;
1687         gtk2_widget->allocation.height = height;
1688         break;
1689     case HSCROLL_BAR_BUTTON_RIGHT:
1690         /*
1691          * The clearlooks engine will draw a "right" button when:
1692          *   x + width == w->allocation.x + w->allocation.width
1693          *
1694          * The ubuntulooks engine will draw a "right" button when:
1695          *   [x,y,width,height]
1696          *     does not intersect
1697          *   [w->alloc.x,w->alloc.y,width,height]
1698          *     but does intersect
1699          *   [w->alloc.x+width,w->alloc.y,width,height]
1700          *
1701          * The values that are set below should ensure that a "right"
1702          * button is rendered for both of these (and other) engines.
1703          */
1704         gtk2_widget->allocation.x = x+width;
1705         gtk2_widget->allocation.y = 0;
1706         gtk2_widget->allocation.width = 0;
1707         gtk2_widget->allocation.height = height;
1708         break;
1709     case VSCROLL_BAR_BUTTON_UP:
1710         /*
1711          * The clearlooks engine will draw an "up" button when:
1712          *   y == w->allocation.y
1713          *
1714          * The ubuntulooks engine will draw an "up" button when:
1715          *   [x,y,width,height]
1716          *     intersects
1717          *   [w->alloc.x,w->alloc.y,width,height]
1718          *
1719          * The values that are set below should ensure that an "up"
1720          * button is rendered for both of these (and other) engines.
1721          */
1722         gtk2_widget->allocation.x = x;
1723         gtk2_widget->allocation.y = y;
1724         gtk2_widget->allocation.width = width;
1725         gtk2_widget->allocation.height = height;
1726         break;
1727     case VSCROLL_BAR_BUTTON_DOWN:
1728         /*
1729          * The clearlooks engine will draw a "down" button when:
1730          *   y + height == w->allocation.y + w->allocation.height
1731          *
1732          * The ubuntulooks engine will draw a "down" button when:
1733          *   [x,y,width,height]
1734          *     does not intersect
1735          *   [w->alloc.x,w->alloc.y,width,height]
1736          *     but does intersect
1737          *   [w->alloc.x,w->alloc.y+height,width,height]
1738          *
1739          * The values that are set below should ensure that a "down"
1740          * button is rendered for both of these (and other) engines.
1741          */
1742         gtk2_widget->allocation.x = x;
1743         gtk2_widget->allocation.y = y+height;
1744         gtk2_widget->allocation.width = width;
1745         gtk2_widget->allocation.height = 0;
1746         break;
1747     default:
1748         break;
1749     }
1750 
1751     (*fp_gtk_paint_box)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1752             shadow_type, NULL, gtk2_widget, detail, x, y, width, height);
1753     (*fp_gtk_paint_box)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1754             shadow_type, NULL, gtk2_widget, detail, x, y, width, height);
1755 
1756     /*
1757      * Reset the text direction to the default value so that we don't
1758      * accidentally affect other operations and widgets.
1759      */
1760     gtk2_set_direction(gtk2_widget, GTK_TEXT_DIR_LTR);
1761 }
1762 
1763 void gtk2_paint_box_gap(WidgetType widget_type, GtkStateType state_type,
1764         GtkShadowType shadow_type, const gchar *detail,
1765         gint x, gint y, gint width, gint height,
1766         GtkPositionType gap_side, gint gap_x, gint gap_width)
1767 {
1768     /* Clearlooks needs a real clip area to paint the gap properly */
1769     GdkRectangle area = { x, y, width, height };
1770 
1771     gtk2_widget = gtk2_get_widget(widget_type);
1772     (*fp_gtk_paint_box_gap)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1773             shadow_type, &area, gtk2_widget, detail,
1774             x, y, width, height, gap_side, gap_x, gap_width);
1775     (*fp_gtk_paint_box_gap)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1776             shadow_type, &area, gtk2_widget, detail,
1777             x, y, width, height, gap_side, gap_x, gap_width);
1778 }
1779 
1780 void gtk2_paint_check(WidgetType widget_type, gint synth_state,
1781         const gchar *detail, gint x, gint y, gint width, gint height)
1782 {
1783     GtkStateType state_type = get_gtk_state_type(widget_type, synth_state);
1784     GtkShadowType shadow_type = get_gtk_shadow_type(widget_type, synth_state);
1785 
1786     gtk2_widget = gtk2_get_widget(widget_type);
1787     init_toggle_widget(widget_type, synth_state);
1788 
1789     (*fp_gtk_paint_check)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1790             shadow_type, NULL, gtk2_widget, detail,
1791             x, y, width, height);
1792     (*fp_gtk_paint_check)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1793             shadow_type, NULL, gtk2_widget, detail,
1794             x, y, width, height);
1795 }
1796 
1797 void gtk2_paint_diamond(WidgetType widget_type, GtkStateType state_type,
1798         GtkShadowType shadow_type, const gchar *detail,
1799         gint x, gint y, gint width, gint height)
1800 {
1801     gtk2_widget = gtk2_get_widget(widget_type);
1802     (*fp_gtk_paint_diamond)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1803             shadow_type, NULL, gtk2_widget, detail,
1804             x, y, width, height);
1805     (*fp_gtk_paint_diamond)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1806             shadow_type, NULL, gtk2_widget, detail,
1807             x, y, width, height);
1808 }
1809 
1810 void gtk2_paint_expander(WidgetType widget_type, GtkStateType state_type,
1811         const gchar *detail, gint x, gint y, gint width, gint height,
1812         GtkExpanderStyle expander_style)
1813 {
1814     gtk2_widget = gtk2_get_widget(widget_type);
1815     (*fp_gtk_paint_expander)(gtk2_widget->style, gtk2_white_pixmap,
1816             state_type, NULL, gtk2_widget, detail,
1817             x + width / 2, y + height / 2, expander_style);
1818     (*fp_gtk_paint_expander)(gtk2_widget->style, gtk2_black_pixmap,
1819             state_type, NULL, gtk2_widget, detail,
1820             x + width / 2, y + height / 2, expander_style);
1821 }
1822 
1823 void gtk2_paint_extension(WidgetType widget_type, GtkStateType state_type,
1824         GtkShadowType shadow_type, const gchar *detail,
1825         gint x, gint y, gint width, gint height, GtkPositionType gap_side)
1826 {
1827     gtk2_widget = gtk2_get_widget(widget_type);
1828     (*fp_gtk_paint_extension)(gtk2_widget->style, gtk2_white_pixmap,
1829             state_type, shadow_type, NULL, gtk2_widget, detail,
1830             x, y, width, height, gap_side);
1831     (*fp_gtk_paint_extension)(gtk2_widget->style, gtk2_black_pixmap,
1832             state_type, shadow_type, NULL, gtk2_widget, detail,
1833             x, y, width, height, gap_side);
1834 }
1835 
1836 void gtk2_paint_flat_box(WidgetType widget_type, GtkStateType state_type,
1837         GtkShadowType shadow_type, const gchar *detail,
1838         gint x, gint y, gint width, gint height, gboolean has_focus)
1839 {
1840     gtk2_widget = gtk2_get_widget(widget_type);
1841 
1842     if (has_focus)
1843         ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS;
1844     else
1845         ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS;
1846 
1847     (*fp_gtk_paint_flat_box)(gtk2_widget->style, gtk2_white_pixmap,
1848             state_type, shadow_type, NULL, gtk2_widget, detail,
1849             x, y, width, height);
1850     (*fp_gtk_paint_flat_box)(gtk2_widget->style, gtk2_black_pixmap,
1851             state_type, shadow_type, NULL, gtk2_widget, detail,
1852             x, y, width, height);
1853 }
1854 
1855 void gtk2_paint_focus(WidgetType widget_type, GtkStateType state_type,
1856         const char *detail, gint x, gint y, gint width, gint height)
1857 {
1858     gtk2_widget = gtk2_get_widget(widget_type);
1859     (*fp_gtk_paint_focus)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1860             NULL, gtk2_widget, detail, x, y, width, height);
1861     (*fp_gtk_paint_focus)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1862             NULL, gtk2_widget, detail, x, y, width, height);
1863 }
1864 
1865 void gtk2_paint_handle(WidgetType widget_type, GtkStateType state_type,
1866         GtkShadowType shadow_type, const gchar *detail,
1867         gint x, gint y, gint width, gint height, GtkOrientation orientation)
1868 {
1869     gtk2_widget = gtk2_get_widget(widget_type);
1870     (*fp_gtk_paint_handle)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1871             shadow_type, NULL, gtk2_widget, detail,
1872             x, y, width, height, orientation);
1873     (*fp_gtk_paint_handle)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1874             shadow_type, NULL, gtk2_widget, detail,
1875             x, y, width, height, orientation);
1876 }
1877 
1878 void gtk2_paint_hline(WidgetType widget_type, GtkStateType state_type,
1879         const gchar *detail, gint x, gint y, gint width, gint height)
1880 {
1881     gtk2_widget = gtk2_get_widget(widget_type);
1882     (*fp_gtk_paint_hline)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1883             NULL, gtk2_widget, detail, x, x + width, y);
1884     (*fp_gtk_paint_hline)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1885             NULL, gtk2_widget, detail, x, x + width, y);
1886 }
1887 
1888 void gtk2_paint_option(WidgetType widget_type, gint synth_state,
1889         const gchar *detail, gint x, gint y, gint width, gint height)
1890 {
1891     GtkStateType state_type = get_gtk_state_type(widget_type, synth_state);
1892     GtkShadowType shadow_type = get_gtk_shadow_type(widget_type, synth_state);
1893 
1894     gtk2_widget = gtk2_get_widget(widget_type);
1895     init_toggle_widget(widget_type, synth_state);
1896 
1897     (*fp_gtk_paint_option)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1898             shadow_type, NULL, gtk2_widget, detail,
1899             x, y, width, height);
1900     (*fp_gtk_paint_option)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1901             shadow_type, NULL, gtk2_widget, detail,
1902             x, y, width, height);
1903 }
1904 
1905 void gtk2_paint_shadow(WidgetType widget_type, GtkStateType state_type,
1906                        GtkShadowType shadow_type, const gchar *detail,
1907                        gint x, gint y, gint width, gint height,
1908                        gint synth_state, GtkTextDirection dir)
1909 {
1910     gtk2_widget = gtk2_get_widget(widget_type);
1911 
1912     /*
1913      * The clearlooks engine sometimes looks at the widget's state field
1914      * instead of just the state_type variable that we pass in, so to account
1915      * for those cases we set the widget's state field accordingly.  The
1916      * flags field is similarly important for things like focus state.
1917      */
1918     gtk2_widget->state = state_type;
1919 
1920     /*
1921      * Some engines (e.g. clearlooks) will paint the shadow of certain
1922      * widgets (e.g. COMBO_BOX_TEXT_FIELD) differently depending on the
1923      * the text direction.
1924      */
1925     gtk2_set_direction(gtk2_widget, dir);
1926 
1927     switch (widget_type) {
1928     case COMBO_BOX_TEXT_FIELD:
1929     case FORMATTED_TEXT_FIELD:
1930     case PASSWORD_FIELD:
1931     case SPINNER_TEXT_FIELD:
1932     case TEXT_FIELD:
1933         if (synth_state & FOCUSED) {
1934             ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS;
1935         } else {
1936             ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS;
1937         }
1938         break;
1939     default:
1940         break;
1941     }
1942 
1943     (*fp_gtk_paint_shadow)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1944             shadow_type, NULL, gtk2_widget, detail, x, y, width, height);
1945     (*fp_gtk_paint_shadow)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1946             shadow_type, NULL, gtk2_widget, detail, x, y, width, height);
1947 
1948     /*
1949      * Reset the text direction to the default value so that we don't
1950      * accidentally affect other operations and widgets.
1951      */
1952     gtk2_set_direction(gtk2_widget, GTK_TEXT_DIR_LTR);
1953 }
1954 
1955 void gtk2_paint_slider(WidgetType widget_type, GtkStateType state_type,
1956         GtkShadowType shadow_type, const gchar *detail,
1957         gint x, gint y, gint width, gint height, GtkOrientation orientation)
1958 {
1959     gtk2_widget = gtk2_get_widget(widget_type);
1960     (*fp_gtk_paint_slider)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1961             shadow_type, NULL, gtk2_widget, detail,
1962             x, y, width, height, orientation);
1963     (*fp_gtk_paint_slider)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1964             shadow_type, NULL, gtk2_widget, detail,
1965             x, y, width, height, orientation);
1966 }
1967 
1968 void gtk2_paint_vline(WidgetType widget_type, GtkStateType state_type,
1969         const gchar *detail, gint x, gint y, gint width, gint height)
1970 {
1971     gtk2_widget = gtk2_get_widget(widget_type);
1972     (*fp_gtk_paint_vline)(gtk2_widget->style, gtk2_white_pixmap, state_type,
1973             NULL, gtk2_widget, detail, y, y + height, x);
1974     (*fp_gtk_paint_vline)(gtk2_widget->style, gtk2_black_pixmap, state_type,
1975             NULL, gtk2_widget, detail, y, y + height, x);
1976 }
1977 
1978 void gtk_paint_background(WidgetType widget_type, GtkStateType state_type,
1979         gint x, gint y, gint width, gint height)
1980 {
1981     gtk2_widget = gtk2_get_widget(widget_type);
1982     (*fp_gtk_style_apply_default_background)(gtk2_widget->style,
1983             gtk2_white_pixmap, TRUE, state_type, NULL, x, y, width, height);
1984     (*fp_gtk_style_apply_default_background)(gtk2_widget->style,
1985             gtk2_black_pixmap, TRUE, state_type, NULL, x, y, width, height);
1986 }
1987 
1988 GdkPixbuf *gtk2_get_stock_icon(gint widget_type, const gchar *stock_id,
1989         GtkIconSize size, GtkTextDirection direction, const char *detail)
1990 {
1991     init_containers();
1992     gtk2_widget = gtk2_get_widget((widget_type < 0) ? IMAGE : widget_type);
1993     gtk2_widget->state = GTK_STATE_NORMAL;
1994     (*fp_gtk_widget_set_direction)(gtk2_widget, direction);
1995     return (*fp_gtk_widget_render_icon)(gtk2_widget, stock_id, size, detail);
1996 }
1997 
1998 /*************************************************/
1999 gint gtk2_get_xthickness(JNIEnv *env, WidgetType widget_type)
2000 {
2001     init_containers();
2002 
2003     gtk2_widget = gtk2_get_widget(widget_type);
2004     GtkStyle* style = gtk2_widget->style;
2005     return style->xthickness;
2006 }
2007 
2008 gint gtk2_get_ythickness(JNIEnv *env, WidgetType widget_type)
2009 {
2010     init_containers();
2011 
2012     gtk2_widget = gtk2_get_widget(widget_type);
2013     GtkStyle* style = gtk2_widget->style;
2014     return style->ythickness;
2015 }
2016 
2017 /*************************************************/
2018 guint8 recode_color(guint16 channel)
2019 {
2020     return (guint8)(channel>>8);
2021 }
2022 
2023 gint gtk2_get_color_for_state(JNIEnv *env, WidgetType widget_type,
2024                               GtkStateType state_type, ColorType color_type)
2025 {
2026     gint result = 0;
2027     GdkColor *color = NULL;
2028 
2029     init_containers();
2030 
2031     gtk2_widget = gtk2_get_widget(widget_type);
2032     GtkStyle* style = gtk2_widget->style;
2033 
2034     switch (color_type)
2035     {
2036         case FOREGROUND:
2037             color = &(style->fg[state_type]);
2038             break;
2039         case BACKGROUND:
2040             color = &(style->bg[state_type]);
2041             break;
2042         case TEXT_FOREGROUND:
2043             color = &(style->text[state_type]);
2044             break;
2045         case TEXT_BACKGROUND:
2046             color = &(style->base[state_type]);
2047             break;
2048         case LIGHT:
2049             color = &(style->light[state_type]);
2050             break;
2051         case DARK:
2052             color = &(style->dark[state_type]);
2053             break;
2054         case MID:
2055             color = &(style->mid[state_type]);
2056             break;
2057         case FOCUS:
2058         case BLACK:
2059             color = &(style->black);
2060             break;
2061         case WHITE:
2062             color = &(style->white);
2063             break;
2064     }
2065 
2066     if (color)
2067         result = recode_color(color->red)   << 16 |
2068                  recode_color(color->green) << 8  |
2069                  recode_color(color->blue);
2070 
2071     return result;
2072 }
2073 
2074 /*************************************************/
2075 jobject create_Boolean(JNIEnv *env, jboolean boolean_value);
2076 jobject create_Integer(JNIEnv *env, jint int_value);
2077 jobject create_Long(JNIEnv *env, jlong long_value);
2078 jobject create_Float(JNIEnv *env, jfloat float_value);
2079 jobject create_Double(JNIEnv *env, jdouble double_value);
2080 jobject create_Character(JNIEnv *env, jchar char_value);
2081 jobject create_Insets(JNIEnv *env, GtkBorder *border);
2082 
2083 jobject gtk2_get_class_value(JNIEnv *env, WidgetType widget_type, jstring jkey)
2084 {
2085     init_containers();
2086 
2087     const char* key = getStrFor(env, jkey);
2088     gtk2_widget = gtk2_get_widget(widget_type);
2089 
2090     GValue value;
2091     value.g_type = 0;
2092 
2093     GParamSpec* param = (*fp_gtk_widget_class_find_style_property)(
2094                                     ((GTypeInstance*)gtk2_widget)->g_class, key);
2095     if( param )
2096     {
2097         (*fp_g_value_init)( &value, param->value_type );
2098         (*fp_gtk_widget_style_get_property)(gtk2_widget, key, &value);
2099 
2100         if( (*fp_g_type_is_a)( param->value_type, G_TYPE_BOOLEAN ))
2101         {
2102             gboolean val = (*fp_g_value_get_boolean)(&value);
2103             return create_Boolean(env, (jboolean)val);
2104         }
2105         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_CHAR ))
2106         {
2107             gchar val = (*fp_g_value_get_char)(&value);
2108             return create_Character(env, (jchar)val);
2109         }
2110         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UCHAR ))
2111         {
2112             guchar val = (*fp_g_value_get_uchar)(&value);
2113             return create_Character(env, (jchar)val);
2114         }
2115         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_INT ))
2116         {
2117             gint val = (*fp_g_value_get_int)(&value);
2118             return create_Integer(env, (jint)val);
2119         }
2120         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UINT ))
2121         {
2122             guint val = (*fp_g_value_get_uint)(&value);
2123             return create_Integer(env, (jint)val);
2124         }
2125         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_LONG ))
2126         {
2127             glong val = (*fp_g_value_get_long)(&value);
2128             return create_Long(env, (jlong)val);
2129         }
2130         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_ULONG ))
2131         {
2132             gulong val = (*fp_g_value_get_ulong)(&value);
2133             return create_Long(env, (jlong)val);
2134         }
2135         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_INT64 ))
2136         {
2137             gint64 val = (*fp_g_value_get_int64)(&value);
2138             return create_Long(env, (jlong)val);
2139         }
2140         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UINT64 ))
2141         {
2142             guint64 val = (*fp_g_value_get_uint64)(&value);
2143             return create_Long(env, (jlong)val);
2144         }
2145         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_FLOAT ))
2146         {
2147             gfloat val = (*fp_g_value_get_float)(&value);
2148             return create_Float(env, (jfloat)val);
2149         }
2150         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_DOUBLE ))
2151         {
2152             gdouble val = (*fp_g_value_get_double)(&value);
2153             return create_Double(env, (jdouble)val);
2154         }
2155         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_ENUM ))
2156         {
2157             gint val = (*fp_g_value_get_enum)(&value);
2158             return create_Integer(env, (jint)val);
2159         }
2160         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_FLAGS ))
2161         {
2162             guint val = (*fp_g_value_get_flags)(&value);
2163             return create_Integer(env, (jint)val);
2164         }
2165         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_STRING ))
2166         {
2167             const gchar* val = (*fp_g_value_get_string)(&value);
2168 
2169             /* We suppose that all values come in C locale and
2170              * utf-8 representation of a string is the same as
2171              * the string itself. If this isn't so we should
2172              * use g_convert.
2173              */
2174             return (*env)->NewStringUTF(env, val);
2175         }
2176         else if( (*fp_g_type_is_a)( param->value_type, GTK_TYPE_BORDER ))
2177         {
2178             GtkBorder *border = (GtkBorder*)(*fp_g_value_get_boxed)(&value);
2179             return border ? create_Insets(env, border) : NULL;
2180         }
2181 
2182         /*      TODO: Other types are not supported yet.*/
2183 /*        else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_PARAM ))
2184         {
2185             GParamSpec* val = (*fp_g_value_get_param)(&value);
2186             printf( "Param: %p\n", val );
2187         }
2188         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_BOXED ))
2189         {
2190             gpointer* val = (*fp_g_value_get_boxed)(&value);
2191             printf( "Boxed: %p\n", val );
2192         }
2193         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_POINTER ))
2194         {
2195             gpointer* val = (*fp_g_value_get_pointer)(&value);
2196             printf( "Pointer: %p\n", val );
2197         }
2198         else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_OBJECT ))
2199         {
2200             GObject* val = (GObject*)(*fp_g_value_get_object)(&value);
2201             printf( "Object: %p\n", val );
2202         }*/
2203     }
2204 
2205     return NULL;
2206 }
2207 
2208 void gtk2_set_range_value(WidgetType widget_type, jdouble value,
2209                           jdouble min, jdouble max, jdouble visible)
2210 {
2211     GtkAdjustment *adj;
2212 
2213     gtk2_widget = gtk2_get_widget(widget_type);
2214 
2215     adj = (*fp_gtk_range_get_adjustment)((GtkRange *)gtk2_widget);
2216     adj->value = (gdouble)value;
2217     adj->lower = (gdouble)min;
2218     adj->upper = (gdouble)max;
2219     adj->page_size = (gdouble)visible;
2220 }
2221 
2222 /*************************************************/
2223 jobject create_Object(JNIEnv *env, jmethodID *cid,
2224                              const char* class_name,
2225                              const char* signature,
2226                              jvalue* value)
2227 {
2228     jclass  class;
2229     jobject result;
2230 
2231     class = (*env)->FindClass(env, class_name);
2232     if( class == NULL )
2233         return NULL; /* can't find/load the class, exception thrown */
2234 
2235     if( *cid == NULL)
2236     {
2237         *cid = (*env)->GetMethodID(env, class, "<init>", signature);
2238         if( *cid == NULL )
2239         {
2240             (*env)->DeleteLocalRef(env, class);
2241             return NULL; /* can't find/get the method, exception thrown */
2242         }
2243     }
2244 
2245     result = (*env)->NewObjectA(env, class, *cid, value);
2246 
2247     (*env)->DeleteLocalRef(env, class);
2248     return result;
2249 }
2250 
2251 jobject create_Boolean(JNIEnv *env, jboolean boolean_value)
2252 {
2253     static jmethodID cid = NULL;
2254     jvalue value;
2255 
2256     value.z = boolean_value;
2257 
2258     return create_Object(env, &cid, "java/lang/Boolean", "(Z)V", &value);
2259 }
2260 
2261 jobject create_Integer(JNIEnv *env, jint int_value)
2262 {
2263     static jmethodID cid = NULL;
2264     jvalue value;
2265 
2266     value.i = int_value;
2267 
2268     return create_Object(env, &cid, "java/lang/Integer", "(I)V", &value);
2269 }
2270 
2271 jobject create_Long(JNIEnv *env, jlong long_value)
2272 {
2273     static jmethodID cid = NULL;
2274     jvalue value;
2275 
2276     value.j = long_value;
2277 
2278     return create_Object(env, &cid, "java/lang/Long", "(J)V", &value);
2279 }
2280 
2281 jobject create_Float(JNIEnv *env, jfloat float_value)
2282 {
2283     static jmethodID cid = NULL;
2284     jvalue value;
2285 
2286     value.f = float_value;
2287 
2288     return create_Object(env, &cid, "java/lang/Float", "(F)V", &value);
2289 }
2290 
2291 jobject create_Double(JNIEnv *env, jdouble double_value)
2292 {
2293     static jmethodID cid = NULL;
2294     jvalue value;
2295 
2296     value.d = double_value;
2297 
2298     return create_Object(env, &cid, "java/lang/Double", "(D)V", &value);
2299 }
2300 
2301 jobject create_Character(JNIEnv *env, jchar char_value)
2302 {
2303     static jmethodID cid = NULL;
2304     jvalue value;
2305 
2306     value.c = char_value;
2307 
2308     return create_Object(env, &cid, "java/lang/Character", "(C)V", &value);
2309 }
2310 
2311 
2312 jobject create_Insets(JNIEnv *env, GtkBorder *border)
2313 {
2314     static jmethodID cid = NULL;
2315     jvalue values[4];
2316 
2317     values[0].i = border->top;
2318     values[1].i = border->left;
2319     values[2].i = border->bottom;
2320     values[3].i = border->right;
2321 
2322     return create_Object(env, &cid, "java/awt/Insets", "(IIII)V", values);
2323 }
2324 
2325 /*********************************************/
2326 jstring gtk2_get_pango_font_name(JNIEnv *env, WidgetType widget_type)
2327 {
2328     init_containers();
2329 
2330     gtk2_widget = gtk2_get_widget(widget_type);
2331     jstring  result = NULL;
2332     GtkStyle* style = gtk2_widget->style;
2333 
2334     if (style && style->font_desc)
2335     {
2336         gchar* val = (*fp_pango_font_description_to_string)(style->font_desc);
2337         result = (*env)->NewStringUTF(env, val);
2338         (*fp_g_free)( val );
2339     }
2340 
2341     return result;
2342 }
2343 
2344 /***********************************************/
2345 jobject get_string_property(JNIEnv *env, GtkSettings* settings, const gchar* key)
2346 {
2347     jobject result = NULL;
2348     gchar*  strval = NULL;
2349 
2350     (*fp_g_object_get)(settings, key, &strval, NULL);
2351     result = (*env)->NewStringUTF(env, strval);
2352     (*fp_g_free)(strval);
2353 
2354     return result;
2355 }
2356 /*
2357 jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key)
2358 {
2359     gint    intval = NULL;
2360 
2361     (*fp_g_object_get)(settings, key, &intval, NULL);
2362     return create_Integer(env, intval);
2363 }*/
2364 
2365 jobject gtk2_get_setting(JNIEnv *env, Setting property)
2366 {
2367     GtkSettings* settings = (*fp_gtk_settings_get_default)();
2368 
2369     switch (property)
2370     {
2371         case GTK_FONT_NAME:
2372             return get_string_property(env, settings, "gtk-font-name");
2373         case GTK_ICON_SIZES:
2374             return get_string_property(env, settings, "gtk-icon-sizes");
2375     }
2376 
2377     return NULL;
2378 }