1/*
2 * Copyright (c) 2005, 2016, 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 <string.h>
30#include "gtk3_interface.h"
31#include "java_awt_Transparency.h"
32#include "sizecalc.h"
33#include <jni_util.h>
34#include <stdio.h>
35#include "awt.h"
36
37static void *gtk3_libhandle = NULL;
38static void *gthread_libhandle = NULL;
39
40static jmp_buf j;
41
42/* Widgets */
43static GtkWidget *gtk3_widget = NULL;
44static GtkWidget *gtk3_window = NULL;
45static GtkFixed  *gtk3_fixed  = NULL;
46static GtkStyleProvider *gtk3_css = NULL;
47
48/* Paint system */
49static cairo_surface_t *surface = NULL;
50static cairo_t *cr = NULL;
51
52static const char ENV_PREFIX[] = "GTK_MODULES=";
53
54static GtkWidget *gtk3_widgets[_GTK_WIDGET_TYPE_SIZE];
55
56static void throw_exception(JNIEnv *env, const char* name, const char* message)
57{
58    jclass class = (*env)->FindClass(env, name);
59
60    if (class != NULL)
61        (*env)->ThrowNew(env, class, message);
62
63    (*env)->DeleteLocalRef(env, class);
64}
65
66static void gtk3_add_state(GtkWidget *widget, GtkStateType state) {
67    GtkStateType old_state = fp_gtk_widget_get_state(widget);
68    fp_gtk_widget_set_state(widget, old_state | state);
69}
70
71static void gtk3_remove_state(GtkWidget *widget, GtkStateType state) {
72    GtkStateType old_state = fp_gtk_widget_get_state(widget);
73    fp_gtk_widget_set_state(widget, old_state & ~state);
74}
75
76/* This is a workaround for the bug:
77 * http://sourceware.org/bugzilla/show_bug.cgi?id=1814
78 * (dlsym/dlopen clears dlerror state)
79 * This bug is specific to Linux, but there is no harm in
80 * applying this workaround on Solaris as well.
81 */
82static void* dl_symbol(const char* name)
83{
84    void* result = dlsym(gtk3_libhandle, name);
85    if (!result)
86        longjmp(j, NO_SYMBOL_EXCEPTION);
87
88    return result;
89}
90
91static void* dl_symbol_gthread(const char* name)
92{
93    void* result = dlsym(gthread_libhandle, name);
94    if (!result)
95        longjmp(j, NO_SYMBOL_EXCEPTION);
96
97    return result;
98}
99
100gboolean gtk3_check(const char* lib_name, gboolean load)
101{
102    if (gtk3_libhandle != NULL) {
103        /* We've already successfully opened the GTK libs, so return true. */
104        return TRUE;
105    } else {
106#ifdef RTLD_NOLOAD
107        void *lib = dlopen(lib_name, RTLD_LAZY | RTLD_NOLOAD);
108        if (!load || lib != NULL) {
109            return lib != NULL;
110        }
111#else
112#ifdef _AIX
113        /* On AIX we could implement this with the help of loadquery(L_GETINFO, ..)  */
114        /* (see reload_table() in hotspot/src/os/aix/vm/loadlib_aix.cpp) but it is   */
115        /* probably not worth it because most AIX servers don't have GTK libs anyway */
116#endif
117#endif
118        return dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL) != NULL;
119    }
120}
121
122#define ADD_SUPPORTED_ACTION(actionStr)                                        \
123do {                                                                           \
124    jfieldID fld_action = (*env)->GetStaticFieldID(env, cls_action, actionStr, \
125                                                 "Ljava/awt/Desktop$Action;"); \
126    if (!(*env)->ExceptionCheck(env)) {                                        \
127        jobject action = (*env)->GetStaticObjectField(env, cls_action,         \
128                                                                  fld_action); \
129        (*env)->CallBooleanMethod(env, supportedActions, mid_arrayListAdd,     \
130                                                                      action); \
131    } else {                                                                   \
132        (*env)->ExceptionClear(env);                                           \
133    }                                                                          \
134} while(0);
135
136
137static void update_supported_actions(JNIEnv *env) {
138    GVfs * (*fp_g_vfs_get_default) (void);
139    const gchar * const * (*fp_g_vfs_get_supported_uri_schemes) (GVfs * vfs);
140    const gchar * const * schemes = NULL;
141
142    jclass cls_action = (*env)->FindClass(env, "java/awt/Desktop$Action");
143    CHECK_NULL(cls_action);
144    jclass cls_xDesktopPeer = (*env)->
145                                     FindClass(env, "sun/awt/X11/XDesktopPeer");
146    CHECK_NULL(cls_xDesktopPeer);
147    jfieldID fld_supportedActions = (*env)->GetStaticFieldID(env,
148                      cls_xDesktopPeer, "supportedActions", "Ljava/util/List;");
149    CHECK_NULL(fld_supportedActions);
150    jobject supportedActions = (*env)->GetStaticObjectField(env,
151                                        cls_xDesktopPeer, fld_supportedActions);
152
153    jclass cls_arrayList = (*env)->FindClass(env, "java/util/ArrayList");
154    CHECK_NULL(cls_arrayList);
155    jmethodID mid_arrayListAdd = (*env)->GetMethodID(env, cls_arrayList, "add",
156                                                       "(Ljava/lang/Object;)Z");
157    CHECK_NULL(mid_arrayListAdd);
158    jmethodID mid_arrayListClear = (*env)->GetMethodID(env, cls_arrayList,
159                                                                "clear", "()V");
160    CHECK_NULL(mid_arrayListClear);
161
162    (*env)->CallVoidMethod(env, supportedActions, mid_arrayListClear);
163
164    ADD_SUPPORTED_ACTION("OPEN");
165
166    /**
167     * gtk_show_uri() documentation says:
168     *
169     * > you need to install gvfs to get support for uri schemes such as http://
170     * > or ftp://, as only local files are handled by GIO itself.
171     *
172     * So OPEN action was safely added here.
173     * However, it looks like Solaris 11 have gvfs support only for 32-bit
174     * applications only by default.
175     */
176
177    fp_g_vfs_get_default = dl_symbol("g_vfs_get_default");
178    fp_g_vfs_get_supported_uri_schemes =
179                           dl_symbol("g_vfs_get_supported_uri_schemes");
180    dlerror();
181
182    if (fp_g_vfs_get_default && fp_g_vfs_get_supported_uri_schemes) {
183        GVfs * vfs = fp_g_vfs_get_default();
184        schemes = vfs ? fp_g_vfs_get_supported_uri_schemes(vfs) : NULL;
185        if (schemes) {
186            int i = 0;
187            while (schemes[i]) {
188                if (strcmp(schemes[i], "http") == 0) {
189                    ADD_SUPPORTED_ACTION("BROWSE");
190                    ADD_SUPPORTED_ACTION("MAIL");
191                    break;
192                }
193                i++;
194            }
195        }
196    } else {
197#ifdef DEBUG
198        fprintf(stderr, "Cannot load g_vfs_get_supported_uri_schemes\n");
199#endif /* DEBUG */
200    }
201
202}
203/**
204 * Functions for awt_Desktop.c
205 */
206static gboolean gtk3_show_uri_load(JNIEnv *env) {
207    gboolean success = FALSE;
208    dlerror();
209    fp_gtk_show_uri = dl_symbol("gtk_show_uri");
210    const char *dlsym_error = dlerror();
211    if (dlsym_error) {
212#ifdef DEBUG
213        fprintf (stderr, "Cannot load symbol: %s \n", dlsym_error);
214#endif /* DEBUG */
215    } else if (fp_gtk_show_uri == NULL) {
216#ifdef DEBUG
217        fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n");
218#endif /* DEBUG */
219    } else {
220        gtk->gtk_show_uri = fp_gtk_show_uri;
221        update_supported_actions(env);
222        success = TRUE;
223    }
224    return success;
225}
226
227/**
228 * Functions for sun_awt_X11_GtkFileDialogPeer.c
229 */
230static void gtk3_file_chooser_load()
231{
232    fp_gtk_file_chooser_get_filename = dl_symbol(
233            "gtk_file_chooser_get_filename");
234    fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new");
235    fp_gtk_file_chooser_set_current_folder = dl_symbol(
236            "gtk_file_chooser_set_current_folder");
237    fp_gtk_file_chooser_set_filename = dl_symbol(
238            "gtk_file_chooser_set_filename");
239    fp_gtk_file_chooser_set_current_name = dl_symbol(
240            "gtk_file_chooser_set_current_name");
241    fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom");
242    fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter");
243    fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type");
244    fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new");
245    fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol(
246                "gtk_file_chooser_set_do_overwrite_confirmation");
247    fp_gtk_file_chooser_set_select_multiple = dl_symbol(
248            "gtk_file_chooser_set_select_multiple");
249    fp_gtk_file_chooser_get_current_folder = dl_symbol(
250            "gtk_file_chooser_get_current_folder");
251    fp_gtk_file_chooser_get_filenames = dl_symbol(
252            "gtk_file_chooser_get_filenames");
253    fp_gtk_g_slist_length = dl_symbol("g_slist_length");
254    fp_gdk_x11_drawable_get_xid = dl_symbol("gdk_x11_window_get_xid");
255}
256
257static void empty() {}
258
259static gboolean gtk3_version_3_10 = TRUE;
260static gboolean gtk3_version_3_14 = FALSE;
261
262GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
263{
264    gboolean result;
265    int i;
266    int (*handler)();
267    int (*io_handler)();
268    char *gtk_modules_env;
269    gtk3_libhandle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL);
270    if (gtk3_libhandle == NULL) {
271        return FALSE;
272    }
273
274    gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL);
275    if (gthread_libhandle == NULL) {
276        gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL);
277        if (gthread_libhandle == NULL)
278            return FALSE;
279    }
280
281    if (setjmp(j) == 0)
282    {
283        fp_gtk_check_version = dl_symbol("gtk_check_version");
284
285        /* GLib */
286        fp_glib_check_version = dlsym(gtk3_libhandle, "glib_check_version");
287        if (!fp_glib_check_version) {
288            dlerror();
289        }
290        fp_g_free = dl_symbol("g_free");
291        fp_g_object_unref = dl_symbol("g_object_unref");
292
293        fp_g_main_context_iteration =
294            dl_symbol("g_main_context_iteration");
295
296        fp_g_value_init = dl_symbol("g_value_init");
297        fp_g_type_is_a = dl_symbol("g_type_is_a");
298        fp_g_value_get_boolean = dl_symbol("g_value_get_boolean");
299        fp_g_value_get_char = dl_symbol("g_value_get_char");
300        fp_g_value_get_uchar = dl_symbol("g_value_get_uchar");
301        fp_g_value_get_int = dl_symbol("g_value_get_int");
302        fp_g_value_get_uint = dl_symbol("g_value_get_uint");
303        fp_g_value_get_long = dl_symbol("g_value_get_long");
304        fp_g_value_get_ulong = dl_symbol("g_value_get_ulong");
305        fp_g_value_get_int64 = dl_symbol("g_value_get_int64");
306        fp_g_value_get_uint64 = dl_symbol("g_value_get_uint64");
307        fp_g_value_get_float = dl_symbol("g_value_get_float");
308        fp_g_value_get_double = dl_symbol("g_value_get_double");
309        fp_g_value_get_string = dl_symbol("g_value_get_string");
310        fp_g_value_get_enum = dl_symbol("g_value_get_enum");
311        fp_g_value_get_flags = dl_symbol("g_value_get_flags");
312        fp_g_value_get_param = dl_symbol("g_value_get_param");
313        fp_g_value_get_boxed = dl_symbol("g_value_get_boxed");
314        fp_g_value_get_pointer = dl_symbol("g_value_get_pointer");
315
316        fp_g_object_get = dl_symbol("g_object_get");
317        fp_g_object_set = dl_symbol("g_object_set");
318
319        fp_g_str_has_prefix = dl_symbol("g_str_has_prefix");
320        fp_g_strsplit = dl_symbol("g_strsplit");
321        fp_g_strfreev = dl_symbol("g_strfreev");
322
323        /* GDK */
324        fp_gdk_get_default_root_window =
325            dl_symbol("gdk_get_default_root_window");
326
327        /* Pixbuf */
328        fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new");
329        fp_gdk_pixbuf_new_from_file =
330                dl_symbol("gdk_pixbuf_new_from_file");
331        fp_gdk_pixbuf_get_from_drawable =
332                    dl_symbol("gdk_pixbuf_get_from_window");
333        fp_gdk_pixbuf_get_width = dl_symbol("gdk_pixbuf_get_width");
334        fp_gdk_pixbuf_get_height = dl_symbol("gdk_pixbuf_get_height");
335        fp_gdk_pixbuf_get_pixels = dl_symbol("gdk_pixbuf_get_pixels");
336        fp_gdk_pixbuf_get_rowstride =
337                dl_symbol("gdk_pixbuf_get_rowstride");
338        fp_gdk_pixbuf_get_has_alpha =
339                dl_symbol("gdk_pixbuf_get_has_alpha");
340        fp_gdk_pixbuf_get_bits_per_sample =
341                dl_symbol("gdk_pixbuf_get_bits_per_sample");
342        fp_gdk_pixbuf_get_n_channels =
343                dl_symbol("gdk_pixbuf_get_n_channels");
344        fp_gdk_pixbuf_get_colorspace =
345                dl_symbol("gdk_pixbuf_get_colorspace");
346
347        fp_cairo_image_surface_create = dl_symbol("cairo_image_surface_create");
348        fp_cairo_surface_destroy = dl_symbol("cairo_surface_destroy");
349        fp_cairo_create = dl_symbol("cairo_create");
350        fp_cairo_destroy = dl_symbol("cairo_destroy");
351        fp_cairo_fill = dl_symbol("cairo_fill");
352        fp_cairo_rectangle = dl_symbol("cairo_rectangle");
353        fp_cairo_set_source_rgb = dl_symbol("cairo_set_source_rgb");
354        fp_cairo_set_source_rgba = dl_symbol("cairo_set_source_rgba");
355        fp_cairo_surface_flush = dl_symbol("cairo_surface_flush");
356        fp_cairo_paint = dl_symbol("cairo_paint");
357        fp_cairo_clip = dl_symbol("cairo_clip");
358        fp_cairo_image_surface_get_data =
359                       dl_symbol("cairo_image_surface_get_data");
360        fp_cairo_image_surface_get_stride =
361                       dl_symbol("cairo_image_surface_get_stride");
362
363        fp_gdk_pixbuf_get_from_surface =
364                       dl_symbol("gdk_pixbuf_get_from_surface");
365
366        fp_gtk_widget_get_state = dl_symbol("gtk_widget_get_state");
367        fp_gtk_widget_set_state = dl_symbol("gtk_widget_set_state");
368
369        fp_gtk_widget_is_focus = dl_symbol("gtk_widget_is_focus");
370        fp_gtk_widget_set_allocation = dl_symbol("gtk_widget_set_allocation");
371        fp_gtk_widget_get_parent = dl_symbol("gtk_widget_get_parent");
372        fp_gtk_widget_get_window = dl_symbol("gtk_widget_get_window");
373
374        fp_gtk_widget_get_style_context =
375                       dl_symbol("gtk_widget_get_style_context");
376        fp_gtk_style_context_get_color =
377                       dl_symbol("gtk_style_context_get_color");
378        fp_gtk_style_context_get_background_color =
379                       dl_symbol("gtk_style_context_get_background_color");
380        fp_gtk_widget_get_state_flags = dl_symbol("gtk_widget_get_state_flags");
381        fp_gtk_style_context_set_state =
382                       dl_symbol("gtk_style_context_set_state");
383        fp_gtk_style_context_add_class =
384                       dl_symbol("gtk_style_context_add_class");
385        fp_gtk_style_context_save = dl_symbol("gtk_style_context_save");
386        fp_gtk_style_context_restore = dl_symbol("gtk_style_context_restore");
387        fp_gtk_render_check = dl_symbol("gtk_render_check");
388        fp_gtk_render_option = dl_symbol("gtk_render_option");
389        fp_gtk_render_extension = dl_symbol("gtk_render_extension");
390        fp_gtk_render_expander = dl_symbol("gtk_render_expander");
391        fp_gtk_render_frame_gap = dl_symbol("gtk_render_frame_gap");
392        fp_gtk_render_line = dl_symbol("gtk_render_line");
393        fp_gtk_widget_render_icon_pixbuf =
394                      dl_symbol("gtk_widget_render_icon_pixbuf");
395        if (fp_gtk_check_version(3, 10, 0)) {
396            gtk3_version_3_10 = FALSE;
397        } else {
398            fp_gdk_window_create_similar_image_surface =
399                       dl_symbol("gdk_window_create_similar_image_surface");
400        }
401        gtk3_version_3_14 = !fp_gtk_check_version(3, 14, 0);
402
403        fp_gdk_window_create_similar_surface =
404                      dl_symbol("gdk_window_create_similar_surface");
405        fp_gtk_settings_get_for_screen =
406                      dl_symbol("gtk_settings_get_for_screen");
407        fp_gtk_widget_get_screen = dl_symbol("gtk_widget_get_screen");
408        fp_gtk_css_provider_get_named = dl_symbol("gtk_css_provider_get_named");
409        fp_gtk_style_context_add_provider =
410                      dl_symbol("gtk_style_context_add_provider");
411        fp_gtk_render_frame = dl_symbol("gtk_render_frame");
412        fp_gtk_render_focus = dl_symbol("gtk_render_focus");
413        fp_gtk_render_handle = dl_symbol("gtk_render_handle");
414        fp_gtk_render_arrow = dl_symbol("gtk_render_arrow");
415
416        fp_gtk_style_context_get_property =
417                      dl_symbol("gtk_style_context_get_property");
418        fp_gtk_scrolled_window_set_shadow_type =
419                      dl_symbol("gtk_scrolled_window_set_shadow_type");
420        fp_gtk_render_slider = dl_symbol("gtk_render_slider");
421        fp_gtk_style_context_get_padding =
422                      dl_symbol("gtk_style_context_get_padding");
423        fp_gtk_range_set_inverted = dl_symbol("gtk_range_set_inverted");
424        fp_gtk_style_context_get_font = dl_symbol("gtk_style_context_get_font");
425        fp_gtk_widget_get_allocated_width =
426                      dl_symbol("gtk_widget_get_allocated_width");
427        fp_gtk_widget_get_allocated_height =
428                      dl_symbol("gtk_widget_get_allocated_height");
429        fp_gtk_icon_theme_get_default = dl_symbol("gtk_icon_theme_get_default");
430        fp_gtk_icon_theme_load_icon = dl_symbol("gtk_icon_theme_load_icon");
431
432        fp_gtk_adjustment_set_lower = dl_symbol("gtk_adjustment_set_lower");
433        fp_gtk_adjustment_set_page_increment =
434                      dl_symbol("gtk_adjustment_set_page_increment");
435        fp_gtk_adjustment_set_page_size =
436                      dl_symbol("gtk_adjustment_set_page_size");
437        fp_gtk_adjustment_set_step_increment =
438                      dl_symbol("gtk_adjustment_set_step_increment");
439        fp_gtk_adjustment_set_upper = dl_symbol("gtk_adjustment_set_upper");
440        fp_gtk_adjustment_set_value = dl_symbol("gtk_adjustment_set_value");
441
442        fp_gtk_render_activity = dl_symbol("gtk_render_activity");
443        fp_gtk_render_background = dl_symbol("gtk_render_background");
444        fp_gtk_style_context_has_class =
445                      dl_symbol("gtk_style_context_has_class");
446
447        fp_gtk_style_context_set_junction_sides =
448                      dl_symbol("gtk_style_context_set_junction_sides");
449        fp_gtk_style_context_add_region =
450                      dl_symbol("gtk_style_context_add_region");
451
452        fp_gtk_init_check = dl_symbol("gtk_init_check");
453
454        /* GTK widgets */
455        fp_gtk_arrow_new = dl_symbol("gtk_arrow_new");
456        fp_gtk_button_new = dl_symbol("gtk_button_new");
457        fp_gtk_spin_button_new = dl_symbol("gtk_spin_button_new");
458        fp_gtk_check_button_new = dl_symbol("gtk_check_button_new");
459        fp_gtk_check_menu_item_new =
460                dl_symbol("gtk_check_menu_item_new");
461        fp_gtk_color_selection_dialog_new =
462                dl_symbol("gtk_color_selection_dialog_new");
463        fp_gtk_entry_new = dl_symbol("gtk_entry_new");
464        fp_gtk_fixed_new = dl_symbol("gtk_fixed_new");
465        fp_gtk_handle_box_new = dl_symbol("gtk_handle_box_new");
466        fp_gtk_image_new = dl_symbol("gtk_image_new");
467        fp_gtk_hpaned_new = dl_symbol("gtk_hpaned_new");
468        fp_gtk_vpaned_new = dl_symbol("gtk_vpaned_new");
469        fp_gtk_scale_new = dl_symbol("gtk_scale_new");
470        fp_gtk_hscrollbar_new = dl_symbol("gtk_hscrollbar_new");
471        fp_gtk_vscrollbar_new = dl_symbol("gtk_vscrollbar_new");
472        fp_gtk_hseparator_new = dl_symbol("gtk_hseparator_new");
473        fp_gtk_vseparator_new = dl_symbol("gtk_vseparator_new");
474        fp_gtk_label_new = dl_symbol("gtk_label_new");
475        fp_gtk_menu_new = dl_symbol("gtk_menu_new");
476        fp_gtk_menu_bar_new = dl_symbol("gtk_menu_bar_new");
477        fp_gtk_menu_item_new = dl_symbol("gtk_menu_item_new");
478        fp_gtk_menu_item_set_submenu =
479                dl_symbol("gtk_menu_item_set_submenu");
480        fp_gtk_notebook_new = dl_symbol("gtk_notebook_new");
481        fp_gtk_progress_bar_new =
482            dl_symbol("gtk_progress_bar_new");
483        fp_gtk_progress_bar_set_orientation =
484            dl_symbol("gtk_orientable_set_orientation");
485        fp_gtk_radio_button_new =
486            dl_symbol("gtk_radio_button_new");
487        fp_gtk_radio_menu_item_new =
488            dl_symbol("gtk_radio_menu_item_new");
489        fp_gtk_scrolled_window_new =
490            dl_symbol("gtk_scrolled_window_new");
491        fp_gtk_separator_menu_item_new =
492            dl_symbol("gtk_separator_menu_item_new");
493        fp_gtk_text_view_new = dl_symbol("gtk_text_view_new");
494        fp_gtk_toggle_button_new =
495            dl_symbol("gtk_toggle_button_new");
496        fp_gtk_toolbar_new = dl_symbol("gtk_toolbar_new");
497        fp_gtk_tree_view_new = dl_symbol("gtk_tree_view_new");
498        fp_gtk_viewport_new = dl_symbol("gtk_viewport_new");
499        fp_gtk_window_new = dl_symbol("gtk_window_new");
500        fp_gtk_window_present = dl_symbol("gtk_window_present");
501        fp_gtk_window_move = dl_symbol("gtk_window_move");
502        fp_gtk_window_resize = dl_symbol("gtk_window_resize");
503
504          fp_gtk_dialog_new = dl_symbol("gtk_dialog_new");
505        fp_gtk_frame_new = dl_symbol("gtk_frame_new");
506
507        fp_gtk_adjustment_new = dl_symbol("gtk_adjustment_new");
508        fp_gtk_container_add = dl_symbol("gtk_container_add");
509        fp_gtk_menu_shell_append =
510            dl_symbol("gtk_menu_shell_append");
511        fp_gtk_widget_realize = dl_symbol("gtk_widget_realize");
512        fp_gtk_widget_destroy = dl_symbol("gtk_widget_destroy");
513        fp_gtk_widget_render_icon =
514            dl_symbol("gtk_widget_render_icon");
515        fp_gtk_widget_set_name =
516            dl_symbol("gtk_widget_set_name");
517        fp_gtk_widget_set_parent =
518            dl_symbol("gtk_widget_set_parent");
519        fp_gtk_widget_set_direction =
520            dl_symbol("gtk_widget_set_direction");
521        fp_gtk_widget_style_get =
522            dl_symbol("gtk_widget_style_get");
523        fp_gtk_widget_class_install_style_property =
524            dl_symbol("gtk_widget_class_install_style_property");
525        fp_gtk_widget_class_find_style_property =
526            dl_symbol("gtk_widget_class_find_style_property");
527        fp_gtk_widget_style_get_property =
528            dl_symbol("gtk_widget_style_get_property");
529        fp_pango_font_description_to_string =
530            dl_symbol("pango_font_description_to_string");
531        fp_gtk_settings_get_default =
532            dl_symbol("gtk_settings_get_default");
533        fp_gtk_widget_get_settings =
534            dl_symbol("gtk_widget_get_settings");
535        fp_gtk_border_get_type =  dl_symbol("gtk_border_get_type");
536        fp_gtk_arrow_set = dl_symbol("gtk_arrow_set");
537        fp_gtk_widget_size_request =
538            dl_symbol("gtk_widget_size_request");
539        fp_gtk_range_get_adjustment =
540            dl_symbol("gtk_range_get_adjustment");
541
542        fp_gtk_widget_hide = dl_symbol("gtk_widget_hide");
543        fp_gtk_main_quit = dl_symbol("gtk_main_quit");
544        fp_g_signal_connect_data = dl_symbol("g_signal_connect_data");
545        fp_gtk_widget_show = dl_symbol("gtk_widget_show");
546        fp_gtk_main = dl_symbol("gtk_main");
547
548        fp_g_path_get_dirname = dl_symbol("g_path_get_dirname");
549
550        fp_gdk_threads_enter = dl_symbol("gdk_threads_enter");
551        fp_gdk_threads_leave = dl_symbol("gdk_threads_leave");
552
553        /**
554         * Functions for sun_awt_X11_GtkFileDialogPeer.c
555         */
556        gtk3_file_chooser_load();
557
558        fp_gtk_combo_box_new = dlsym(gtk3_libhandle, "gtk_combo_box_new");
559        fp_gtk_combo_box_entry_new = dlsym(gtk3_libhandle,
560                                                "gtk_combo_box_new_with_entry");
561        fp_gtk_separator_tool_item_new = dlsym(gtk3_libhandle,
562                                                 "gtk_separator_tool_item_new");
563
564        fp_g_list_append = dl_symbol("g_list_append");
565        fp_g_list_free = dl_symbol("g_list_free");
566        fp_g_list_free_full = dl_symbol("g_list_free_full");
567    }
568    /* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION
569     * Otherwise we can check the return value of setjmp method.
570     */
571    else
572    {
573        dlclose(gtk3_libhandle);
574        gtk3_libhandle = NULL;
575
576        dlclose(gthread_libhandle);
577        gthread_libhandle = NULL;
578
579        return NULL;
580    }
581
582    /*
583     * Strip the AT-SPI GTK_MODULEs if present
584     */
585    gtk_modules_env = getenv ("GTK_MODULES");
586    if (gtk_modules_env && strstr (gtk_modules_env, "atk-bridge") ||
587        gtk_modules_env && strstr (gtk_modules_env, "gail"))
588    {
589        /* the new env will be smaller than the old one */
590        gchar *s, *new_env = SAFE_SIZE_STRUCT_ALLOC(malloc,
591                sizeof(ENV_PREFIX), 1, strlen (gtk_modules_env));
592
593        if (new_env != NULL )
594        {
595            /* careful, strtok modifies its args */
596            gchar *tmp_env = strdup (gtk_modules_env);
597            strcpy(new_env, ENV_PREFIX);
598
599            /* strip out 'atk-bridge' and 'gail' */
600            size_t PREFIX_LENGTH = strlen(ENV_PREFIX);
601            while (s = strtok(tmp_env, ":"))
602            {
603                if ((!strstr (s, "atk-bridge")) && (!strstr (s, "gail")))
604                {
605                    if (strlen (new_env) > PREFIX_LENGTH) {
606                        new_env = strcat (new_env, ":");
607                    }
608                    new_env = strcat(new_env, s);
609                }
610                if (tmp_env)
611                {
612                    free (tmp_env);
613                    tmp_env = NULL; /* next call to strtok arg1==NULL */
614                }
615            }
616            putenv (new_env);
617            free (new_env);
618            free (tmp_env);
619        }
620    }
621    /*
622     * GTK should be initialized with gtk_init_check() before use.
623     *
624     * gtk_init_check installs its own error handlers. It is critical that
625     * we preserve error handler set from AWT. Otherwise we'll crash on
626     * BadMatch errors which we would normally ignore. The IO error handler
627     * is preserved here, too, just for consistency.
628    */
629    AWT_LOCK();
630    handler = XSetErrorHandler(NULL);
631    io_handler = XSetIOErrorHandler(NULL);
632    result = (*fp_gtk_init_check)(NULL, NULL);
633    XSetErrorHandler(handler);
634    XSetIOErrorHandler(io_handler);
635    AWT_UNLOCK();
636    /* Initialize widget array. */
637    for (i = 0; i < _GTK_WIDGET_TYPE_SIZE; i++)
638    {
639        gtk3_widgets[i] = NULL;
640    }
641    if (result) {
642        GtkApi* gtk = (GtkApi*)malloc(sizeof(GtkApi));
643        gtk3_init(gtk);
644        return gtk;
645    }
646    return NULL;
647}
648
649static int gtk3_unload()
650{
651    int i;
652    char *gtk3_error;
653
654    if (!gtk3_libhandle)
655        return TRUE;
656
657    /* Release painting objects */
658    if (surface != NULL) {
659        fp_cairo_destroy(cr);
660        fp_cairo_surface_destroy(surface);
661        surface = NULL;
662    }
663
664    if (gtk3_window != NULL) {
665        /* Destroying toplevel widget will destroy all contained widgets */
666        (*fp_gtk_widget_destroy)(gtk3_window);
667
668        /* Unset some static data so they get reinitialized on next load */
669        gtk3_window = NULL;
670    }
671
672    dlerror();
673    dlclose(gtk3_libhandle);
674    dlclose(gthread_libhandle);
675    if ((gtk3_error = dlerror()) != NULL)
676    {
677        return FALSE;
678    }
679    return TRUE;
680}
681
682/* Dispatch all pending events from the GTK event loop.
683 * This is needed to catch theme change and update widgets' style.
684 */
685static void flush_gtk_event_loop()
686{
687    while((*fp_g_main_context_iteration)(NULL));
688}
689
690/*
691 * Initialize components of containment hierarchy. This creates a GtkFixed
692 * inside a GtkWindow. All widgets get realized.
693 */
694static void init_containers()
695{
696    if (gtk3_window == NULL)
697    {
698        gtk3_window = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);
699        gtk3_fixed = (GtkFixed *)(*fp_gtk_fixed_new)();
700        (*fp_gtk_container_add)((GtkContainer*)gtk3_window,
701                                (GtkWidget *)gtk3_fixed);
702        (*fp_gtk_widget_realize)(gtk3_window);
703        (*fp_gtk_widget_realize)((GtkWidget *)gtk3_fixed);
704
705        GtkSettings* settings = fp_gtk_settings_get_for_screen(
706                                         fp_gtk_widget_get_screen(gtk3_window));
707        gchar*  strval = NULL;
708        fp_g_object_get(settings, "gtk-theme-name", &strval, NULL);
709        gtk3_css = fp_gtk_css_provider_get_named(strval, NULL);
710    }
711}
712
713/*
714 * Ensure everything is ready for drawing an element of the specified width
715 * and height.
716 *
717 * We should somehow handle translucent images. GTK can draw to X Drawables
718 * only, which don't support alpha. When we retrieve the image back from
719 * the server, translucency information is lost. There're several ways to
720 * work around this:
721 * 1) Subclass GdkPixmap and cache translucent objects on client side. This
722 * requires us to implement parts of X server drawing logic on client side.
723 * Many X requests can potentially be "translucent"; e.g. XDrawLine with
724 * fill=tile and a translucent tile is a "translucent" operation, whereas
725 * XDrawLine with fill=solid is an "opaque" one. Moreover themes can (and some
726 * do) intermix transparent and opaque operations which makes caching even
727 * more problematic.
728 * 2) Use Xorg 32bit ARGB visual when available. GDK has no native support
729 * for it (as of version 2.6). Also even in JDS 3 Xorg does not support
730 * these visuals by default, which makes optimizing for them pointless.
731 * We can consider doing this at a later point when ARGB visuals become more
732 * popular.
733 * 3') GTK has plans to use Cairo as its graphical backend (presumably in
734 * 2.8), and Cairo supports alpha. With it we could also get rid of the
735 * unnecessary round trip to server and do all the drawing on client side.
736 * 4) For now we draw to two different pixmaps and restore alpha channel by
737 * comparing results. This can be optimized by using subclassed pixmap and
738*/
739static void gtk3_init_painting(JNIEnv *env, gint width, gint height)
740{
741    init_containers();
742
743    if (cr) {
744        fp_cairo_destroy(cr);
745    }
746
747    if (surface != NULL) {
748        /* free old stuff */
749        fp_cairo_surface_destroy(surface);
750
751    }
752
753    if (gtk3_version_3_10) {
754        surface = fp_gdk_window_create_similar_image_surface(
755                           fp_gtk_widget_get_window(gtk3_window),
756                                         CAIRO_FORMAT_ARGB32, width, height, 1);
757    } else {
758        surface = fp_cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
759                                                                 width, height);
760    }
761
762    cr = fp_cairo_create(surface);
763}
764
765/*
766 * Restore image from white and black pixmaps and copy it into destination
767 * buffer. This method compares two pixbufs taken from white and black
768 * pixmaps and decodes color and alpha components. Pixbufs are RGB without
769 * alpha, destination buffer is ABGR.
770 *
771 * The return value is the transparency type of the resulting image, either
772 * one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and
773 * java_awt_Transparency_TRANSLUCENT.
774 */
775static gint gtk3_copy_image(gint *dst, gint width, gint height)
776{
777    gint i, j, r, g, b;
778    guchar *data;
779    gint stride, padding;
780
781    fp_cairo_surface_flush(surface);
782    data = (*fp_cairo_image_surface_get_data)(surface);
783    stride = (*fp_cairo_image_surface_get_stride)(surface);
784    padding = stride - width * 4;
785
786    for (i = 0; i < height; i++) {
787        for (j = 0; j < width; j++) {
788            int r = *data++;
789            int g = *data++;
790            int b = *data++;
791            int a = *data++;
792            *dst++ = (a << 24 | b << 16 | g << 8 | r);
793        }
794        data += padding;
795    }
796    return java_awt_Transparency_TRANSLUCENT;
797}
798
799static void gtk3_set_direction(GtkWidget *widget, GtkTextDirection dir)
800{
801    /*
802     * Some engines (inexplicably) look at the direction of the widget's
803     * parent, so we need to set the direction of both the widget and its
804     * parent.
805     */
806    (*fp_gtk_widget_set_direction)(widget, dir);
807    GtkWidget* parent = fp_gtk_widget_get_parent(widget);
808    if (parent != NULL) {
809        fp_gtk_widget_set_direction(parent, dir);
810    }
811}
812
813/* GTK state_type filter */
814static GtkStateType get_gtk_state_type(WidgetType widget_type, gint synth_state)
815{
816    GtkStateType result = GTK_STATE_NORMAL;
817
818    if ((synth_state & DISABLED) != 0) {
819        result = GTK_STATE_INSENSITIVE;
820    } else if ((synth_state & PRESSED) != 0) {
821        result = GTK_STATE_ACTIVE;
822    } else if ((synth_state & MOUSE_OVER) != 0) {
823        result = GTK_STATE_PRELIGHT;
824    }
825    return result;
826}
827
828static GtkStateFlags get_gtk_state_flags(gint synth_state)
829{
830    GtkStateFlags flags = 0;
831
832    if ((synth_state & DISABLED) != 0) {
833        flags |= GTK_STATE_FLAG_INSENSITIVE;
834    }
835    if (((synth_state & PRESSED) != 0 || (synth_state & SELECTED) != 0)) {
836        flags |= GTK_STATE_FLAG_ACTIVE;
837    }
838    if ((synth_state & MOUSE_OVER) != 0) {
839        flags |= GTK_STATE_FLAG_PRELIGHT;
840    }
841    if ((synth_state & FOCUSED) != 0) {
842        flags |= GTK_STATE_FLAG_FOCUSED;
843    }
844    return flags;
845}
846
847static GtkStateFlags get_gtk_flags(GtkStateType state_type) {
848    GtkStateFlags flags = 0;
849    switch (state_type)
850    {
851        case GTK_STATE_PRELIGHT:
852          flags |= GTK_STATE_FLAG_PRELIGHT;
853          break;
854        case GTK_STATE_SELECTED:
855          flags |= GTK_STATE_FLAG_SELECTED;
856          break;
857        case GTK_STATE_INSENSITIVE:
858          flags |= GTK_STATE_FLAG_INSENSITIVE;
859          break;
860        case GTK_STATE_ACTIVE:
861          flags |= GTK_STATE_FLAG_ACTIVE;
862          break;
863        case GTK_STATE_FOCUSED:
864          flags |= GTK_STATE_FLAG_FOCUSED;
865          break;
866        default:
867          break;
868    }
869    return flags;
870}
871
872/* GTK shadow_type filter */
873static GtkShadowType get_gtk_shadow_type(WidgetType widget_type,
874                                                               gint synth_state)
875{
876    GtkShadowType result = GTK_SHADOW_OUT;
877
878    if ((synth_state & SELECTED) != 0) {
879        result = GTK_SHADOW_IN;
880    }
881    return result;
882}
883
884
885static GtkWidget* gtk3_get_arrow(GtkArrowType arrow_type,
886                                                      GtkShadowType shadow_type)
887{
888    GtkWidget *arrow = NULL;
889    if (NULL == gtk3_widgets[_GTK_ARROW_TYPE])
890    {
891        gtk3_widgets[_GTK_ARROW_TYPE] = (*fp_gtk_arrow_new)(arrow_type,
892                                                                   shadow_type);
893        (*fp_gtk_container_add)((GtkContainer *)gtk3_fixed,
894                                                 gtk3_widgets[_GTK_ARROW_TYPE]);
895        (*fp_gtk_widget_realize)(gtk3_widgets[_GTK_ARROW_TYPE]);
896    }
897    arrow = gtk3_widgets[_GTK_ARROW_TYPE];
898
899    (*fp_gtk_arrow_set)(arrow, arrow_type, shadow_type);
900    return arrow;
901}
902
903static GtkAdjustment* create_adjustment()
904{
905    return (GtkAdjustment *)
906            (*fp_gtk_adjustment_new)(50.0, 0.0, 100.0, 10.0, 20.0, 20.0);
907}
908
909/**
910 * Returns a pointer to the cached native widget for the specified widget
911 * type.
912 */
913static GtkWidget *gtk3_get_widget(WidgetType widget_type)
914{
915    gboolean init_result = FALSE;
916    GtkWidget *result = NULL;
917    switch (widget_type)
918    {
919        case BUTTON:
920        case TABLE_HEADER:
921            if (init_result = (NULL == gtk3_widgets[_GTK_BUTTON_TYPE]))
922            {
923                gtk3_widgets[_GTK_BUTTON_TYPE] = (*fp_gtk_button_new)();
924            }
925            result = gtk3_widgets[_GTK_BUTTON_TYPE];
926            break;
927        case CHECK_BOX:
928            if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_BUTTON_TYPE]))
929            {
930                gtk3_widgets[_GTK_CHECK_BUTTON_TYPE] =
931                    (*fp_gtk_check_button_new)();
932            }
933            result = gtk3_widgets[_GTK_CHECK_BUTTON_TYPE];
934            break;
935        case CHECK_BOX_MENU_ITEM:
936            if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE]))
937            {
938                gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE] =
939                    (*fp_gtk_check_menu_item_new)();
940            }
941            result = gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE];
942            break;
943        /************************************************************
944         *    Creation a dedicated color chooser is dangerous because
945         * it deadlocks the EDT
946         ************************************************************/
947/*        case COLOR_CHOOSER:
948            if (init_result =
949                    (NULL == gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE]))
950            {
951                gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE] =
952                    (*fp_gtk_color_selection_dialog_new)(NULL);
953            }
954            result = gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE];
955            break;*/
956        case COMBO_BOX:
957            if (init_result = (NULL == gtk3_widgets[_GTK_COMBO_BOX_TYPE]))
958            {
959                gtk3_widgets[_GTK_COMBO_BOX_TYPE] =
960                    (*fp_gtk_combo_box_new)();
961            }
962            result = gtk3_widgets[_GTK_COMBO_BOX_TYPE];
963            break;
964        case COMBO_BOX_ARROW_BUTTON:
965            if (init_result =
966                    (NULL == gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE]))
967            {
968                gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE] =
969                     (*fp_gtk_toggle_button_new)();
970            }
971            result = gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE];
972            break;
973        case COMBO_BOX_TEXT_FIELD:
974            if (init_result =
975                    (NULL == gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE]))
976            {
977                result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] =
978                     (*fp_gtk_entry_new)();
979            }
980            result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE];
981            break;
982        case DESKTOP_ICON:
983        case INTERNAL_FRAME_TITLE_PANE:
984        case LABEL:
985            if (init_result = (NULL == gtk3_widgets[_GTK_LABEL_TYPE]))
986            {
987                gtk3_widgets[_GTK_LABEL_TYPE] =
988                    (*fp_gtk_label_new)(NULL);
989            }
990            result = gtk3_widgets[_GTK_LABEL_TYPE];
991            break;
992        case DESKTOP_PANE:
993        case PANEL:
994        case ROOT_PANE:
995            if (init_result = (NULL == gtk3_widgets[_GTK_CONTAINER_TYPE]))
996            {
997                /* There is no constructor for a container type.  I've
998                 * chosen GtkFixed container since it has a default
999                 * constructor.
1000                 */
1001                gtk3_widgets[_GTK_CONTAINER_TYPE] =
1002                    (*fp_gtk_fixed_new)();
1003            }
1004            result = gtk3_widgets[_GTK_CONTAINER_TYPE];
1005            break;
1006        case EDITOR_PANE:
1007        case TEXT_AREA:
1008        case TEXT_PANE:
1009            if (init_result = (NULL == gtk3_widgets[_GTK_TEXT_VIEW_TYPE]))
1010            {
1011                gtk3_widgets[_GTK_TEXT_VIEW_TYPE] =
1012                    (*fp_gtk_text_view_new)();
1013            }
1014            result = gtk3_widgets[_GTK_TEXT_VIEW_TYPE];
1015            break;
1016        case FORMATTED_TEXT_FIELD:
1017        case PASSWORD_FIELD:
1018        case TEXT_FIELD:
1019            if (init_result = (NULL == gtk3_widgets[_GTK_ENTRY_TYPE]))
1020            {
1021                gtk3_widgets[_GTK_ENTRY_TYPE] =
1022                    (*fp_gtk_entry_new)();
1023            }
1024            result = gtk3_widgets[_GTK_ENTRY_TYPE];
1025            break;
1026        case HANDLE_BOX:
1027            if (init_result = (NULL == gtk3_widgets[_GTK_HANDLE_BOX_TYPE]))
1028            {
1029                gtk3_widgets[_GTK_HANDLE_BOX_TYPE] =
1030                    (*fp_gtk_handle_box_new)();
1031            }
1032            result = gtk3_widgets[_GTK_HANDLE_BOX_TYPE];
1033            break;
1034        case HSCROLL_BAR:
1035        case HSCROLL_BAR_BUTTON_LEFT:
1036        case HSCROLL_BAR_BUTTON_RIGHT:
1037        case HSCROLL_BAR_TRACK:
1038        case HSCROLL_BAR_THUMB:
1039            if (init_result = (NULL == gtk3_widgets[_GTK_HSCROLLBAR_TYPE]))
1040            {
1041                gtk3_widgets[_GTK_HSCROLLBAR_TYPE] =
1042                    (*fp_gtk_hscrollbar_new)(create_adjustment());
1043            }
1044            result = gtk3_widgets[_GTK_HSCROLLBAR_TYPE];
1045            break;
1046        case HSEPARATOR:
1047            if (init_result = (NULL == gtk3_widgets[_GTK_HSEPARATOR_TYPE]))
1048            {
1049                gtk3_widgets[_GTK_HSEPARATOR_TYPE] =
1050                    (*fp_gtk_hseparator_new)();
1051            }
1052            result = gtk3_widgets[_GTK_HSEPARATOR_TYPE];
1053            break;
1054        case HSLIDER:
1055        case HSLIDER_THUMB:
1056        case HSLIDER_TRACK:
1057            if (init_result = (NULL == gtk3_widgets[_GTK_HSCALE_TYPE]))
1058            {
1059                gtk3_widgets[_GTK_HSCALE_TYPE] =
1060                    (*fp_gtk_scale_new)(GTK_ORIENTATION_HORIZONTAL, NULL);
1061            }
1062            result = gtk3_widgets[_GTK_HSCALE_TYPE];
1063            break;
1064        case HSPLIT_PANE_DIVIDER:
1065        case SPLIT_PANE:
1066            if (init_result = (NULL == gtk3_widgets[_GTK_HPANED_TYPE]))
1067            {
1068                gtk3_widgets[_GTK_HPANED_TYPE] = (*fp_gtk_hpaned_new)();
1069            }
1070            result = gtk3_widgets[_GTK_HPANED_TYPE];
1071            break;
1072        case IMAGE:
1073            if (init_result = (NULL == gtk3_widgets[_GTK_IMAGE_TYPE]))
1074            {
1075                gtk3_widgets[_GTK_IMAGE_TYPE] = (*fp_gtk_image_new)();
1076            }
1077            result = gtk3_widgets[_GTK_IMAGE_TYPE];
1078            break;
1079        case INTERNAL_FRAME:
1080            if (init_result = (NULL == gtk3_widgets[_GTK_WINDOW_TYPE]))
1081            {
1082                gtk3_widgets[_GTK_WINDOW_TYPE] =
1083                    (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);
1084            }
1085            result = gtk3_widgets[_GTK_WINDOW_TYPE];
1086            break;
1087        case TOOL_TIP:
1088            if (init_result = (NULL == gtk3_widgets[_GTK_TOOLTIP_TYPE]))
1089            {
1090                result = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);
1091                gtk3_widgets[_GTK_TOOLTIP_TYPE] = result;
1092            }
1093            result = gtk3_widgets[_GTK_TOOLTIP_TYPE];
1094            break;
1095        case LIST:
1096        case TABLE:
1097        case TREE:
1098        case TREE_CELL:
1099            if (init_result = (NULL == gtk3_widgets[_GTK_TREE_VIEW_TYPE]))
1100            {
1101                gtk3_widgets[_GTK_TREE_VIEW_TYPE] =
1102                    (*fp_gtk_tree_view_new)();
1103            }
1104            result = gtk3_widgets[_GTK_TREE_VIEW_TYPE];
1105            break;
1106        case TITLED_BORDER:
1107            if (init_result = (NULL == gtk3_widgets[_GTK_FRAME_TYPE]))
1108            {
1109                gtk3_widgets[_GTK_FRAME_TYPE] = fp_gtk_frame_new(NULL);
1110            }
1111            result = gtk3_widgets[_GTK_FRAME_TYPE];
1112            break;
1113        case POPUP_MENU:
1114            if (init_result = (NULL == gtk3_widgets[_GTK_MENU_TYPE]))
1115            {
1116                gtk3_widgets[_GTK_MENU_TYPE] =
1117                    (*fp_gtk_menu_new)();
1118            }
1119            result = gtk3_widgets[_GTK_MENU_TYPE];
1120            break;
1121        case MENU:
1122        case MENU_ITEM:
1123        case MENU_ITEM_ACCELERATOR:
1124            if (init_result = (NULL == gtk3_widgets[_GTK_MENU_ITEM_TYPE]))
1125            {
1126                gtk3_widgets[_GTK_MENU_ITEM_TYPE] =
1127                    (*fp_gtk_menu_item_new)();
1128            }
1129            result = gtk3_widgets[_GTK_MENU_ITEM_TYPE];
1130            break;
1131        case MENU_BAR:
1132            if (init_result = (NULL == gtk3_widgets[_GTK_MENU_BAR_TYPE]))
1133            {
1134                gtk3_widgets[_GTK_MENU_BAR_TYPE] =
1135                    (*fp_gtk_menu_bar_new)();
1136            }
1137            result = gtk3_widgets[_GTK_MENU_BAR_TYPE];
1138            break;
1139        case COLOR_CHOOSER:
1140        case OPTION_PANE:
1141            if (init_result = (NULL == gtk3_widgets[_GTK_DIALOG_TYPE]))
1142            {
1143                gtk3_widgets[_GTK_DIALOG_TYPE] =
1144                    (*fp_gtk_dialog_new)();
1145            }
1146            result = gtk3_widgets[_GTK_DIALOG_TYPE];
1147            break;
1148        case POPUP_MENU_SEPARATOR:
1149            if (init_result =
1150                    (NULL == gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE]))
1151            {
1152                gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE] =
1153                    (*fp_gtk_separator_menu_item_new)();
1154            }
1155            result = gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE];
1156            break;
1157        case HPROGRESS_BAR:
1158            if (init_result = (NULL == gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE]))
1159            {
1160                gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE] =
1161                    (*fp_gtk_progress_bar_new)();
1162            }
1163            result = gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE];
1164            break;
1165        case VPROGRESS_BAR:
1166            if (init_result = (NULL == gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE]))
1167            {
1168                gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE] =
1169                    (*fp_gtk_progress_bar_new)();
1170                /*
1171                 * Vertical JProgressBars always go bottom-to-top,
1172                 * regardless of the ComponentOrientation.
1173                 */
1174                (*fp_gtk_progress_bar_set_orientation)(
1175                    (GtkProgressBar *)gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE],
1176                    GTK_PROGRESS_BOTTOM_TO_TOP);
1177            }
1178            result = gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE];
1179            break;
1180        case RADIO_BUTTON:
1181            if (init_result = (NULL == gtk3_widgets[_GTK_RADIO_BUTTON_TYPE]))
1182            {
1183                gtk3_widgets[_GTK_RADIO_BUTTON_TYPE] =
1184                    (*fp_gtk_radio_button_new)(NULL);
1185            }
1186            result = gtk3_widgets[_GTK_RADIO_BUTTON_TYPE];
1187            break;
1188        case RADIO_BUTTON_MENU_ITEM:
1189            if (init_result =
1190                    (NULL == gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE]))
1191            {
1192                gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE] =
1193                    (*fp_gtk_radio_menu_item_new)(NULL);
1194            }
1195            result = gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE];
1196            break;
1197        case SCROLL_PANE:
1198            if (init_result =
1199                    (NULL == gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE]))
1200            {
1201                gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE] =
1202                    (*fp_gtk_scrolled_window_new)(NULL, NULL);
1203            }
1204            result = gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE];
1205            break;
1206        case SPINNER:
1207        case SPINNER_ARROW_BUTTON:
1208        case SPINNER_TEXT_FIELD:
1209            if (init_result = (NULL == gtk3_widgets[_GTK_SPIN_BUTTON_TYPE]))
1210            {
1211                result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE] =
1212                    (*fp_gtk_spin_button_new)(NULL, 0, 0);
1213            }
1214            result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE];
1215            break;
1216        case TABBED_PANE:
1217        case TABBED_PANE_TAB_AREA:
1218        case TABBED_PANE_CONTENT:
1219        case TABBED_PANE_TAB:
1220            if (init_result = (NULL == gtk3_widgets[_GTK_NOTEBOOK_TYPE]))
1221            {
1222                gtk3_widgets[_GTK_NOTEBOOK_TYPE] =
1223                    (*fp_gtk_notebook_new)(NULL);
1224            }
1225            result = gtk3_widgets[_GTK_NOTEBOOK_TYPE];
1226            break;
1227        case TOGGLE_BUTTON:
1228            if (init_result = (NULL == gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE]))
1229            {
1230                gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE] =
1231                    (*fp_gtk_toggle_button_new)(NULL);
1232            }
1233            result = gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE];
1234            break;
1235        case TOOL_BAR:
1236        case TOOL_BAR_DRAG_WINDOW:
1237            if (init_result = (NULL == gtk3_widgets[_GTK_TOOLBAR_TYPE]))
1238            {
1239                gtk3_widgets[_GTK_TOOLBAR_TYPE] =
1240                    (*fp_gtk_toolbar_new)(NULL);
1241            }
1242            result = gtk3_widgets[_GTK_TOOLBAR_TYPE];
1243            break;
1244        case TOOL_BAR_SEPARATOR:
1245            if (init_result =
1246                    (NULL == gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE]))
1247            {
1248                gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE] =
1249                    (*fp_gtk_separator_tool_item_new)();
1250            }
1251            result = gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE];
1252            break;
1253        case VIEWPORT:
1254            if (init_result = (NULL == gtk3_widgets[_GTK_VIEWPORT_TYPE]))
1255            {
1256                GtkAdjustment *adjustment = create_adjustment();
1257                gtk3_widgets[_GTK_VIEWPORT_TYPE] =
1258                    (*fp_gtk_viewport_new)(adjustment, adjustment);
1259            }
1260            result = gtk3_widgets[_GTK_VIEWPORT_TYPE];
1261            break;
1262        case VSCROLL_BAR:
1263        case VSCROLL_BAR_BUTTON_UP:
1264        case VSCROLL_BAR_BUTTON_DOWN:
1265        case VSCROLL_BAR_TRACK:
1266        case VSCROLL_BAR_THUMB:
1267            if (init_result = (NULL == gtk3_widgets[_GTK_VSCROLLBAR_TYPE]))
1268            {
1269                gtk3_widgets[_GTK_VSCROLLBAR_TYPE] =
1270                    (*fp_gtk_vscrollbar_new)(create_adjustment());
1271            }
1272            result = gtk3_widgets[_GTK_VSCROLLBAR_TYPE];
1273            break;
1274        case VSEPARATOR:
1275            if (init_result = (NULL == gtk3_widgets[_GTK_VSEPARATOR_TYPE]))
1276            {
1277                gtk3_widgets[_GTK_VSEPARATOR_TYPE] =
1278                    (*fp_gtk_vseparator_new)();
1279            }
1280            result = gtk3_widgets[_GTK_VSEPARATOR_TYPE];
1281            break;
1282        case VSLIDER:
1283        case VSLIDER_THUMB:
1284        case VSLIDER_TRACK:
1285            if (init_result = (NULL == gtk3_widgets[_GTK_VSCALE_TYPE]))
1286            {
1287                gtk3_widgets[_GTK_VSCALE_TYPE] =
1288                    (*fp_gtk_scale_new)(GTK_ORIENTATION_VERTICAL, NULL);
1289            }
1290            result = gtk3_widgets[_GTK_VSCALE_TYPE];
1291            /*
1292             * Vertical JSliders start at the bottom, while vertical
1293             * GtkVScale widgets start at the top (by default), so to fix
1294             * this we set the "inverted" flag to get the Swing behavior.
1295             */
1296             fp_gtk_range_set_inverted((GtkRange*)result, TRUE);
1297            break;
1298        case VSPLIT_PANE_DIVIDER:
1299            if (init_result = (NULL == gtk3_widgets[_GTK_VPANED_TYPE]))
1300            {
1301                gtk3_widgets[_GTK_VPANED_TYPE] = (*fp_gtk_vpaned_new)();
1302            }
1303            result = gtk3_widgets[_GTK_VPANED_TYPE];
1304            break;
1305        default:
1306            result = NULL;
1307            break;
1308    }
1309
1310    if (result != NULL && init_result)
1311    {
1312        if (widget_type == RADIO_BUTTON_MENU_ITEM ||
1313                widget_type == CHECK_BOX_MENU_ITEM ||
1314                widget_type == MENU_ITEM ||
1315                widget_type == MENU ||
1316                widget_type == POPUP_MENU_SEPARATOR)
1317        {
1318            GtkWidget *menu = gtk3_get_widget(POPUP_MENU);
1319            (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu, result);
1320        }
1321        else if (widget_type == POPUP_MENU)
1322        {
1323            GtkWidget *menu_bar = gtk3_get_widget(MENU_BAR);
1324            GtkWidget *root_menu = (*fp_gtk_menu_item_new)();
1325            (*fp_gtk_menu_item_set_submenu)((GtkMenuItem*)root_menu, result);
1326            (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu_bar, root_menu);
1327        }
1328        else if (widget_type == COMBO_BOX_TEXT_FIELD )
1329        {
1330            GtkWidget* combo = gtk3_get_widget(COMBO_BOX);
1331
1332            /*
1333            * We add a regular GtkButton/GtkEntry to a GtkComboBoxEntry
1334            * in order to trick engines into thinking it's a real combobox
1335            * arrow button/text field.
1336            */
1337
1338            fp_gtk_container_add ((GtkContainer*)(combo), result);
1339            GtkStyleContext* context = fp_gtk_widget_get_style_context (combo);
1340            fp_gtk_style_context_add_class (context, "combobox-entry");
1341            context = fp_gtk_widget_get_style_context (result);
1342            fp_gtk_style_context_add_class (context, "combobox");
1343            fp_gtk_style_context_add_class (context, "entry");
1344        }
1345        else if (widget_type == COMBO_BOX_ARROW_BUTTON )
1346        {
1347            GtkWidget* combo = gtk3_get_widget(COMBO_BOX);
1348            fp_gtk_widget_set_parent(result, combo);
1349        }
1350        else if (widget_type != TOOL_TIP &&
1351                 widget_type != INTERNAL_FRAME &&
1352                 widget_type != OPTION_PANE)
1353        {
1354            (*fp_gtk_container_add)((GtkContainer *)gtk3_fixed, result);
1355        }
1356        (*fp_gtk_widget_realize)(result);
1357    }
1358    return result;
1359}
1360
1361static void gtk3_paint_arrow(WidgetType widget_type, GtkStateType state_type,
1362        GtkShadowType shadow_type, const gchar *detail,
1363        gint x, gint y, gint width, gint height,
1364        GtkArrowType arrow_type, gboolean fill)
1365{
1366    gdouble xx, yy, a = G_PI;
1367    int s = width;
1368    gtk3_widget = gtk3_get_arrow(arrow_type, shadow_type);
1369
1370    switch (widget_type)
1371    {
1372        case SPINNER_ARROW_BUTTON:
1373            s = (int)(0.4 * width + 0.5) + 1;
1374            if (arrow_type == GTK_ARROW_UP) {
1375                a = 0;
1376            } else if (arrow_type == GTK_ARROW_DOWN) {
1377                a = G_PI;
1378            }
1379            break;
1380
1381        case HSCROLL_BAR_BUTTON_LEFT:
1382            s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1;
1383            a = 3 * G_PI / 2;
1384            break;
1385
1386        case HSCROLL_BAR_BUTTON_RIGHT:
1387            s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1;
1388            a = G_PI / 2;
1389            break;
1390
1391        case VSCROLL_BAR_BUTTON_UP:
1392            s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1;
1393            a = 0;
1394            break;
1395
1396        case VSCROLL_BAR_BUTTON_DOWN:
1397            s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1;
1398            a = G_PI;
1399            break;
1400
1401        case COMBO_BOX_ARROW_BUTTON:
1402            s = (int)(0.3 * height + 0.5) + 1;
1403            a = G_PI;
1404            break;
1405
1406        case TABLE:
1407            s = (int)(0.8 * height + 0.5) + 1;
1408            if (arrow_type == GTK_ARROW_UP) {
1409                a = G_PI;
1410            } else if (arrow_type == GTK_ARROW_DOWN) {
1411                a = 0;
1412            }
1413            break;
1414
1415        case MENU_ITEM:
1416            if (arrow_type == GTK_ARROW_UP) {
1417                a = G_PI;
1418            } else if (arrow_type == GTK_ARROW_DOWN) {
1419                a = 0;
1420            } else if (arrow_type == GTK_ARROW_RIGHT) {
1421                a = G_PI / 2;
1422            } else if (arrow_type == GTK_ARROW_LEFT) {
1423                a = 3 * G_PI / 2;
1424            }
1425            break;
1426
1427        default:
1428            if (arrow_type == GTK_ARROW_UP) {
1429                a = G_PI;
1430            } else if (arrow_type == GTK_ARROW_DOWN) {
1431                a = 0;
1432            } else if (arrow_type == GTK_ARROW_RIGHT) {
1433                a = G_PI / 2;
1434            } else if (arrow_type == GTK_ARROW_LEFT) {
1435                a = 3 * G_PI / 2;
1436            }
1437            break;
1438    }
1439
1440    if (s < width && s < height) {
1441        xx = x + (0.5 * (width - s) + 0.5);
1442        yy = y + (0.5 * (height - s) + 0.5);
1443    } else {
1444        xx = x;
1445        yy = y;
1446    }
1447
1448    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1449    fp_gtk_style_context_save (context);
1450
1451
1452    if (detail != NULL) {
1453        transform_detail_string(detail, context);
1454    }
1455
1456    GtkStateFlags flags = get_gtk_flags(state_type);
1457
1458    fp_gtk_style_context_set_state (context, flags);
1459
1460    (*fp_gtk_render_arrow)(context, cr, a, xx, yy, s);
1461
1462    fp_gtk_style_context_restore (context);
1463}
1464
1465static void gtk3_paint_box(WidgetType widget_type, GtkStateType state_type,
1466                    GtkShadowType shadow_type, const gchar *detail,
1467                    gint x, gint y, gint width, gint height,
1468                    gint synth_state, GtkTextDirection dir)
1469{
1470    gtk3_widget = gtk3_get_widget(widget_type);
1471
1472    if (widget_type == HSLIDER_TRACK) {
1473        /*
1474         * For horizontal JSliders with right-to-left orientation, we need
1475         * to set the "inverted" flag to match the native GTK behavior where
1476         * the foreground highlight is on the right side of the slider thumb.
1477         * This is needed especially for the ubuntulooks engine, which looks
1478         * exclusively at the "inverted" flag to determine on which side of
1479         * the thumb to paint the highlight...
1480         */
1481        fp_gtk_range_set_inverted((GtkRange*)gtk3_widget, dir ==
1482                                                              GTK_TEXT_DIR_RTL);
1483
1484        /*
1485         * Note however that other engines like clearlooks will look at both
1486         * the "inverted" field and the text direction to determine how
1487         * the foreground highlight is painted:
1488         *     !inverted && ltr --> paint highlight on left side
1489         *     !inverted && rtl --> paint highlight on right side
1490         *      inverted && ltr --> paint highlight on right side
1491         *      inverted && rtl --> paint highlight on left side
1492         * So the only way to reliably get the desired results for horizontal
1493         * JSlider (i.e., highlight on left side for LTR ComponentOrientation
1494         * and highlight on right side for RTL ComponentOrientation) is to
1495         * always override text direction as LTR, and then set the "inverted"
1496         * flag accordingly (as we have done above).
1497         */
1498        dir = GTK_TEXT_DIR_LTR;
1499    }
1500
1501    /*
1502     * Some engines (e.g. clearlooks) will paint the shadow of certain
1503     * widgets (e.g. COMBO_BOX_ARROW_BUTTON) differently depending on the
1504     * the text direction.
1505     */
1506    gtk3_set_direction(gtk3_widget, dir);
1507
1508    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1509    fp_gtk_style_context_save (context);
1510
1511    transform_detail_string(detail, context);
1512
1513    GtkStateFlags flags = get_gtk_flags(state_type);
1514
1515    if (shadow_type == GTK_SHADOW_IN && widget_type != COMBO_BOX_ARROW_BUTTON) {
1516        flags |= GTK_STATE_FLAG_ACTIVE;
1517    }
1518
1519    if (synth_state & MOUSE_OVER) {
1520        flags |= GTK_STATE_FLAG_PRELIGHT;
1521    }
1522
1523    if (synth_state & FOCUSED) {
1524        flags |= GTK_STATE_FLAG_FOCUSED;
1525    }
1526
1527    if (synth_state & DEFAULT) {
1528        fp_gtk_style_context_add_class (context, "default");
1529    }
1530
1531    fp_gtk_style_context_set_state (context, flags);
1532
1533    if (fp_gtk_style_context_has_class(context, "progressbar")) {
1534        fp_gtk_render_activity (context, cr, x, y, width, height);
1535    } else {
1536        fp_gtk_render_background (context, cr, x, y, width, height);
1537        if (shadow_type != GTK_SHADOW_NONE) {
1538            fp_gtk_render_frame(context, cr, x, y, width, height);
1539        }
1540    }
1541
1542    fp_gtk_style_context_restore (context);
1543    /*
1544     * Reset the text direction to the default value so that we don't
1545     * accidentally affect other operations and widgets.
1546     */
1547    gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR);
1548}
1549
1550static void gtk3_paint_box_gap(WidgetType widget_type, GtkStateType state_type,
1551        GtkShadowType shadow_type, const gchar *detail,
1552        gint x, gint y, gint width, gint height,
1553        GtkPositionType gap_side, gint gap_x, gint gap_width)
1554{
1555    gtk3_widget = gtk3_get_widget(widget_type);
1556
1557    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1558
1559    fp_gtk_style_context_save (context);
1560
1561    GtkStateFlags flags = get_gtk_flags(state_type);
1562    fp_gtk_style_context_set_state(context, flags);
1563
1564    if (detail != 0) {
1565        transform_detail_string(detail, context);
1566    }
1567    fp_gtk_render_background(context, cr, x, y, width, height);
1568
1569    if (shadow_type != GTK_SHADOW_NONE) {
1570        fp_gtk_render_frame_gap(context, cr, x, y, width, height, gap_side,
1571                                    (gdouble)gap_x, (gdouble)gap_x + gap_width);
1572    }
1573    fp_gtk_style_context_restore (context);
1574}
1575
1576static void gtk3_paint_check(WidgetType widget_type, gint synth_state,
1577        const gchar *detail, gint x, gint y, gint width, gint height)
1578{
1579    gtk3_widget = gtk3_get_widget(widget_type);
1580
1581    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1582
1583    fp_gtk_style_context_save (context);
1584
1585    GtkStateFlags flags = get_gtk_state_flags(synth_state);
1586    if (gtk3_version_3_14 && (synth_state & SELECTED)) {
1587        flags = GTK_STATE_FLAG_CHECKED;
1588    }
1589    fp_gtk_style_context_set_state(context, flags);
1590
1591    fp_gtk_style_context_add_class (context, "check");
1592
1593    fp_gtk_render_check (context, cr, x, y, width, height);
1594
1595    fp_gtk_style_context_restore (context);
1596}
1597
1598
1599static void gtk3_paint_expander(WidgetType widget_type, GtkStateType state_type,
1600        const gchar *detail, gint x, gint y, gint width, gint height,
1601        GtkExpanderStyle expander_style)
1602{
1603    gtk3_widget = gtk3_get_widget(widget_type);
1604
1605    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1606
1607    fp_gtk_style_context_save (context);
1608
1609    GtkStateFlags flags = get_gtk_flags(state_type);
1610    if (expander_style == GTK_EXPANDER_EXPANDED) {
1611        flags |= GTK_STATE_FLAG_ACTIVE;
1612    }
1613
1614    fp_gtk_style_context_set_state(context, flags);
1615
1616    if (detail != 0) {
1617        transform_detail_string(detail, context);
1618    }
1619
1620    fp_gtk_render_expander (context, cr, x + 2, y + 2, width - 4, height - 4);
1621
1622    fp_gtk_style_context_restore (context);
1623}
1624
1625static void gtk3_paint_extension(WidgetType widget_type, GtkStateType state_type,
1626        GtkShadowType shadow_type, const gchar *detail,
1627        gint x, gint y, gint width, gint height, GtkPositionType gap_side)
1628{
1629    gtk3_widget = gtk3_get_widget(widget_type);
1630
1631    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1632
1633    fp_gtk_style_context_save (context);
1634
1635    GtkStateFlags flags = GTK_STATE_FLAG_NORMAL;
1636
1637    if (state_type == 0) {
1638        flags = GTK_STATE_FLAG_ACTIVE;
1639    }
1640
1641    fp_gtk_style_context_set_state(context, flags);
1642
1643    if (detail != 0) {
1644        transform_detail_string(detail, context);
1645    }
1646    switch(gap_side) {
1647      case GTK_POS_LEFT:
1648        fp_gtk_style_context_add_class(context, "right");
1649        break;
1650      case GTK_POS_RIGHT:
1651        fp_gtk_style_context_add_class(context, "left");
1652        break;
1653      case GTK_POS_TOP:
1654        fp_gtk_style_context_add_class(context, "bottom");
1655        break;
1656      case GTK_POS_BOTTOM:
1657        fp_gtk_style_context_add_class(context, "top");
1658        break;
1659      default:
1660        break;
1661    }
1662
1663    fp_gtk_render_extension(context, cr, x, y, width, height, gap_side);
1664
1665    fp_gtk_style_context_restore (context);
1666}
1667
1668static void gtk3_paint_flat_box(WidgetType widget_type, GtkStateType state_type,
1669        GtkShadowType shadow_type, const gchar *detail,
1670        gint x, gint y, gint width, gint height, gboolean has_focus)
1671{
1672    if (state_type == GTK_STATE_PRELIGHT &&
1673        (widget_type == CHECK_BOX || widget_type == RADIO_BUTTON)) {
1674        return;
1675    }
1676    gtk3_widget = gtk3_get_widget(widget_type);
1677
1678    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1679
1680    fp_gtk_style_context_save (context);
1681
1682    if (detail != 0) {
1683        transform_detail_string(detail, context);
1684    }
1685
1686    GtkStateFlags flags = get_gtk_flags(state_type);
1687
1688    if (has_focus) {
1689        flags |= GTK_STATE_FLAG_FOCUSED;
1690    }
1691
1692    fp_gtk_style_context_set_state (context, flags);
1693
1694    if (widget_type == COMBO_BOX_TEXT_FIELD) {
1695        width += height /2;
1696    }
1697
1698    fp_gtk_render_background (context, cr, x, y, width, height);
1699
1700    fp_gtk_style_context_restore (context);
1701}
1702
1703static void gtk3_paint_focus(WidgetType widget_type, GtkStateType state_type,
1704        const char *detail, gint x, gint y, gint width, gint height)
1705{
1706    gtk3_widget = gtk3_get_widget(widget_type);
1707
1708    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1709    fp_gtk_style_context_save (context);
1710
1711    transform_detail_string(detail, context);
1712    fp_gtk_render_focus (context, cr, x, y, width, height);
1713
1714    fp_gtk_style_context_restore (context);
1715
1716}
1717
1718static void gtk3_paint_handle(WidgetType widget_type, GtkStateType state_type,
1719        GtkShadowType shadow_type, const gchar *detail,
1720        gint x, gint y, gint width, gint height, GtkOrientation orientation)
1721{
1722    gtk3_widget = gtk3_get_widget(widget_type);
1723
1724    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1725
1726    fp_gtk_style_context_save (context);
1727
1728    GtkStateFlags flags = get_gtk_flags(state_type);
1729    fp_gtk_style_context_set_state(context, GTK_STATE_FLAG_PRELIGHT);
1730
1731    if (detail != 0) {
1732        transform_detail_string(detail, context);
1733        fp_gtk_style_context_add_class (context, "handlebox_bin");
1734    }
1735
1736    fp_gtk_render_handle(context, cr, x, y, width, height);
1737    fp_gtk_render_background(context, cr, x, y, width, height);
1738
1739    fp_gtk_style_context_restore (context);
1740}
1741
1742static void gtk3_paint_hline(WidgetType widget_type, GtkStateType state_type,
1743        const gchar *detail, gint x, gint y, gint width, gint height)
1744{
1745    gtk3_widget = gtk3_get_widget(widget_type);
1746
1747    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1748
1749    fp_gtk_style_context_save (context);
1750
1751    if (detail != 0) {
1752        transform_detail_string(detail, context);
1753    }
1754
1755    fp_gtk_render_line(context, cr, x, y, x + width, y);
1756
1757    fp_gtk_style_context_restore (context);
1758}
1759
1760static void gtk3_paint_vline(WidgetType widget_type, GtkStateType state_type,
1761        const gchar *detail, gint x, gint y, gint width, gint height)
1762{
1763    gtk3_widget = gtk3_get_widget(widget_type);
1764
1765
1766    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1767
1768    fp_gtk_style_context_save (context);
1769
1770    if (detail != 0) {
1771        transform_detail_string(detail, context);
1772    }
1773
1774    fp_gtk_render_line(context, cr, x, y, x, y + height);
1775
1776    fp_gtk_style_context_restore (context);
1777}
1778
1779static void gtk3_paint_option(WidgetType widget_type, gint synth_state,
1780        const gchar *detail, gint x, gint y, gint width, gint height)
1781{
1782     gtk3_widget = gtk3_get_widget(widget_type);
1783
1784     GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1785
1786     fp_gtk_style_context_save (context);
1787
1788     GtkStateFlags flags = get_gtk_state_flags(synth_state);
1789     if (gtk3_version_3_14 && (synth_state & SELECTED)) {
1790         flags = GTK_STATE_FLAG_CHECKED;
1791     }
1792     fp_gtk_style_context_set_state(context, flags);
1793
1794     if (detail != 0) {
1795         transform_detail_string(detail, context);
1796     }
1797
1798     fp_gtk_render_option(context, cr, x, y, width, height);
1799
1800     fp_gtk_style_context_restore (context);
1801}
1802
1803static void gtk3_paint_shadow(WidgetType widget_type, GtkStateType state_type,
1804                       GtkShadowType shadow_type, const gchar *detail,
1805                       gint x, gint y, gint width, gint height,
1806                       gint synth_state, GtkTextDirection dir)
1807{
1808    if (shadow_type == GTK_SHADOW_NONE) {
1809        return;
1810    }
1811    gtk3_widget = gtk3_get_widget(widget_type);
1812
1813    /*
1814     * Some engines (e.g. clearlooks) will paint the shadow of certain
1815     * widgets (e.g. COMBO_BOX_TEXT_FIELD) differently depending on the
1816     * the text direction.
1817     */
1818    gtk3_set_direction(gtk3_widget, dir);
1819
1820
1821    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1822    fp_gtk_style_context_save (context);
1823
1824    if (detail) {
1825        transform_detail_string(detail, context);
1826    }
1827
1828    GtkStateFlags flags = get_gtk_flags(state_type);
1829
1830    if (synth_state & MOUSE_OVER) {
1831        flags |= GTK_STATE_FLAG_PRELIGHT;
1832    }
1833
1834    if (synth_state & FOCUSED) {
1835        flags |= GTK_STATE_FLAG_FOCUSED;
1836    }
1837
1838    fp_gtk_style_context_set_state (context, flags);
1839
1840    if (widget_type == COMBO_BOX_TEXT_FIELD) {
1841        width += height / 2;
1842    }
1843    fp_gtk_render_frame(context, cr, x, y, width, height);
1844
1845    fp_gtk_style_context_restore (context);
1846
1847    /*
1848     * Reset the text direction to the default value so that we don't
1849     * accidentally affect other operations and widgets.
1850     */
1851    gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR);
1852}
1853
1854static void gtk3_paint_slider(WidgetType widget_type, GtkStateType state_type,
1855        GtkShadowType shadow_type, const gchar *detail,
1856        gint x, gint y, gint width, gint height, GtkOrientation orientation,
1857        gboolean has_focus)
1858{
1859    gtk3_widget = gtk3_get_widget(widget_type);
1860
1861    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1862
1863    fp_gtk_style_context_save (context);
1864
1865    if (detail) {
1866       transform_detail_string(detail, context);
1867    }
1868
1869    GtkStateFlags flags = get_gtk_flags(state_type);
1870
1871    if (state_type == GTK_STATE_ACTIVE) {
1872        flags |= GTK_STATE_FLAG_PRELIGHT;
1873    }
1874
1875    if (has_focus) {
1876        flags |= GTK_STATE_FLAG_FOCUSED;
1877    }
1878
1879    fp_gtk_style_context_set_state (context, flags);
1880
1881    (*fp_gtk_render_slider)(context, cr, x, y, width, height, orientation);
1882
1883    fp_gtk_style_context_restore (context);
1884}
1885
1886static void gtk3_paint_background(WidgetType widget_type,
1887             GtkStateType state_type, gint x, gint y, gint width, gint height) {
1888    gtk3_widget = gtk3_get_widget(widget_type);
1889
1890    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1891    fp_gtk_style_context_save (context);
1892
1893    GtkStateFlags flags = get_gtk_flags(state_type);
1894
1895    fp_gtk_style_context_set_state (context, flags);
1896
1897    fp_gtk_render_background (context, cr, x, y, width, height);
1898
1899    fp_gtk_style_context_restore (context);
1900}
1901
1902static GdkPixbuf *gtk3_get_stock_icon(gint widget_type, const gchar *stock_id,
1903        GtkIconSize size, GtkTextDirection direction, const char *detail)
1904{
1905    int sz;
1906
1907    switch(size) {
1908      case GTK_ICON_SIZE_MENU:
1909        sz = 16;
1910        break;
1911      case GTK_ICON_SIZE_SMALL_TOOLBAR:
1912        sz = 18;
1913        break;
1914      case GTK_ICON_SIZE_LARGE_TOOLBAR:
1915        sz = 24;
1916        break;
1917      case GTK_ICON_SIZE_BUTTON:
1918        sz = 20;
1919        break;
1920      case GTK_ICON_SIZE_DND:
1921        sz = 32;
1922        break;
1923      case GTK_ICON_SIZE_DIALOG:
1924        sz = 48;
1925        break;
1926      default:
1927        sz = 0;
1928        break;
1929    }
1930
1931    init_containers();
1932    gtk3_widget = gtk3_get_widget((widget_type < 0) ? IMAGE : widget_type);
1933    (*fp_gtk_widget_set_direction)(gtk3_widget, direction);
1934    GtkIconTheme *icon_theme = fp_gtk_icon_theme_get_default();
1935    GdkPixbuf *result = fp_gtk_icon_theme_load_icon(icon_theme, stock_id, sz,
1936                                             GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
1937    return result;
1938}
1939
1940static jboolean gtk3_get_pixbuf_data(JNIEnv *env, GdkPixbuf* pixbuf,
1941                              jmethodID icon_upcall_method, jobject this) {
1942    if (!pixbuf) {
1943        return JNI_FALSE;
1944    }
1945    guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf);
1946    if (pixbuf_data) {
1947        int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf);
1948        int width = (*fp_gdk_pixbuf_get_width)(pixbuf);
1949        int height = (*fp_gdk_pixbuf_get_height)(pixbuf);
1950        int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf);
1951        int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);
1952        gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf);
1953
1954        jbyteArray data = (*env)->NewByteArray(env, (row_stride * height));
1955        JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
1956
1957        (*env)->SetByteArrayRegion(env, data, 0, (row_stride * height),
1958                                   (jbyte *)pixbuf_data);
1959        (*fp_g_object_unref)(pixbuf);
1960
1961        /* Call the callback method to create the image on the Java side. */
1962        (*env)->CallVoidMethod(env, this, icon_upcall_method, data,
1963                width, height, row_stride, bps, channels, alpha);
1964        return JNI_TRUE;
1965    }
1966    return JNI_FALSE;
1967}
1968
1969static jboolean gtk3_get_file_icon_data(JNIEnv *env, const char *filename,
1970                 GError **error, jmethodID icon_upcall_method, jobject this) {
1971    GdkPixbuf* pixbuf = fp_gdk_pixbuf_new_from_file(filename, error);
1972    return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this);
1973}
1974
1975static jboolean gtk3_get_icon_data(JNIEnv *env, gint widget_type,
1976                              const gchar *stock_id, GtkIconSize size,
1977                              GtkTextDirection direction, const char *detail,
1978                              jmethodID icon_upcall_method, jobject this) {
1979    GdkPixbuf* pixbuf = gtk3_get_stock_icon(widget_type, stock_id, size,
1980                                       direction, detail);
1981    return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this);
1982}
1983
1984/*************************************************/
1985static gint gtk3_get_xthickness(JNIEnv *env, WidgetType widget_type)
1986{
1987    init_containers();
1988
1989    gtk3_widget = gtk3_get_widget(widget_type);
1990    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
1991    if (context) {
1992        GtkBorder padding;
1993        fp_gtk_style_context_get_padding(context, 0, &padding);
1994        return padding.left + 1;
1995    }
1996    return 0;
1997}
1998
1999static gint gtk3_get_ythickness(JNIEnv *env, WidgetType widget_type)
2000{
2001    init_containers();
2002
2003    gtk3_widget = gtk3_get_widget(widget_type);
2004    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
2005    if (context) {
2006        GtkBorder padding;
2007        fp_gtk_style_context_get_padding(context, 0, &padding);
2008        return padding.top + 1;
2009    }
2010    return 0;
2011}
2012
2013/*************************************************/
2014static guint8 recode_color(gdouble channel)
2015{
2016    guint16 result = (guint16)(channel * 65535);
2017    if (result > 65535) {
2018        result = 65535;
2019    }
2020    return (guint8)( result >> 8);
2021}
2022
2023static GtkStateFlags gtk3_get_state_flags(GtkStateType state_type) {
2024    switch (state_type)
2025    {
2026        case GTK_STATE_NORMAL:
2027            return GTK_STATE_FLAG_NORMAL;
2028        case GTK_STATE_ACTIVE:
2029            return GTK_STATE_FLAG_ACTIVE;
2030        case GTK_STATE_PRELIGHT:
2031            return GTK_STATE_FLAG_PRELIGHT;
2032        case GTK_STATE_SELECTED:
2033            return GTK_STATE_FLAG_SELECTED;
2034        case GTK_STATE_INSENSITIVE:
2035            return GTK_STATE_FLAG_INSENSITIVE;
2036        case GTK_STATE_INCONSISTENT:
2037            return GTK_STATE_FLAG_INCONSISTENT;
2038        case GTK_STATE_FOCUSED:
2039            return GTK_STATE_FLAG_FOCUSED;
2040    }
2041    return 0;
2042}
2043
2044
2045static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b) {
2046  gdouble min;
2047  gdouble max;
2048  gdouble red;
2049  gdouble green;
2050  gdouble blue;
2051  gdouble h, l, s;
2052  gdouble delta;
2053
2054  red = *r;
2055  green = *g;
2056  blue = *b;
2057
2058  if (red > green)
2059    {
2060      if (red > blue)
2061        max = red;
2062      else
2063        max = blue;
2064
2065      if (green < blue)
2066        min = green;
2067      else
2068        min = blue;
2069    }
2070  else
2071    {
2072      if (green > blue)
2073        max = green;
2074      else
2075        max = blue;
2076
2077      if (red < blue)
2078        min = red;
2079      else
2080        min = blue;
2081    }
2082
2083  l = (max + min) / 2;
2084  s = 0;
2085  h = 0;
2086
2087  if (max != min)
2088    {
2089      if (l <= 0.5)
2090        s = (max - min) / (max + min);
2091      else
2092        s = (max - min) / (2 - max - min);
2093
2094      delta = max -min;
2095      if (red == max)
2096        h = (green - blue) / delta;
2097      else if (green == max)
2098        h = 2 + (blue - red) / delta;
2099      else if (blue == max)
2100        h = 4 + (red - green) / delta;
2101
2102      h *= 60;
2103      if (h < 0.0)
2104        h += 360;
2105    }
2106
2107  *r = h;
2108  *g = l;
2109  *b = s;
2110}
2111
2112static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s)
2113{
2114  gdouble hue;
2115  gdouble lightness;
2116  gdouble saturation;
2117  gdouble m1, m2;
2118  gdouble r, g, b;
2119
2120  lightness = *l;
2121  saturation = *s;
2122
2123  if (lightness <= 0.5)
2124    m2 = lightness * (1 + saturation);
2125  else
2126    m2 = lightness + saturation - lightness * saturation;
2127  m1 = 2 * lightness - m2;
2128
2129  if (saturation == 0)
2130    {
2131      *h = lightness;
2132      *l = lightness;
2133      *s = lightness;
2134    }
2135  else
2136    {
2137      hue = *h + 120;
2138      while (hue > 360)
2139        hue -= 360;
2140      while (hue < 0)
2141        hue += 360;
2142
2143      if (hue < 60)
2144        r = m1 + (m2 - m1) * hue / 60;
2145      else if (hue < 180)
2146        r = m2;
2147      else if (hue < 240)
2148        r = m1 + (m2 - m1) * (240 - hue) / 60;
2149      else
2150        r = m1;
2151
2152      hue = *h;
2153      while (hue > 360)
2154        hue -= 360;
2155      while (hue < 0)
2156        hue += 360;
2157
2158      if (hue < 60)
2159        g = m1 + (m2 - m1) * hue / 60;
2160      else if (hue < 180)
2161        g = m2;
2162      else if (hue < 240)
2163        g = m1 + (m2 - m1) * (240 - hue) / 60;
2164      else
2165        g = m1;
2166
2167      hue = *h - 120;
2168      while (hue > 360)
2169        hue -= 360;
2170      while (hue < 0)
2171        hue += 360;
2172
2173      if (hue < 60)
2174        b = m1 + (m2 - m1) * hue / 60;
2175      else if (hue < 180)
2176        b = m2;
2177      else if (hue < 240)
2178        b = m1 + (m2 - m1) * (240 - hue) / 60;
2179      else
2180        b = m1;
2181
2182      *h = r;
2183      *l = g;
2184      *s = b;
2185    }
2186}
2187
2188
2189
2190static void gtk3_style_shade (const GdkRGBA *a, GdkRGBA *b, gdouble k) {
2191  gdouble red = a->red;
2192  gdouble green = a->green;
2193  gdouble blue = a->blue;
2194
2195  rgb_to_hls (&red, &green, &blue);
2196
2197  green *= k;
2198  if (green > 1.0)
2199    green = 1.0;
2200  else if (green < 0.0)
2201    green = 0.0;
2202
2203  blue *= k;
2204  if (blue > 1.0)
2205    blue = 1.0;
2206  else if (blue < 0.0)
2207    blue = 0.0;
2208
2209  hls_to_rgb (&red, &green, &blue);
2210
2211  b->red = red;
2212  b->green = green;
2213  b->blue = blue;
2214}
2215
2216static GdkRGBA gtk3_get_color_for_flags(GtkStyleContext* context,
2217                                  GtkStateFlags flags, ColorType color_type) {
2218    GdkRGBA c, color;
2219    color.alpha = 1;
2220
2221    switch (color_type)
2222    {
2223        case FOREGROUND:
2224        case TEXT_FOREGROUND:
2225            fp_gtk_style_context_get_color(context, flags, &color);
2226            break;
2227        case BACKGROUND:
2228        case TEXT_BACKGROUND:
2229            fp_gtk_style_context_get_background_color(context, flags, &color);
2230            break;
2231        case LIGHT:
2232            c = gtk3_get_color_for_flags(context, flags, BACKGROUND);
2233            gtk3_style_shade(&c, &color, LIGHTNESS_MULT);
2234            break;
2235        case DARK:
2236            c = gtk3_get_color_for_flags(context, flags, BACKGROUND);
2237            gtk3_style_shade (&c, &color, DARKNESS_MULT);
2238            break;
2239        case MID:
2240            {
2241                GdkRGBA c1 = gtk3_get_color_for_flags(context, flags, LIGHT);
2242                GdkRGBA c2 = gtk3_get_color_for_flags(context, flags, DARK);
2243                color.red = (c1.red + c2.red) / 2;
2244                color.green = (c1.green + c2.green) / 2;
2245                color.blue = (c1.blue + c2.blue) / 2;
2246            }
2247            break;
2248        case FOCUS:
2249        case BLACK:
2250            color.red = 0;
2251            color.green = 0;
2252            color.blue = 0;
2253            break;
2254        case WHITE:
2255            color.red = 1;
2256            color.green = 1;
2257            color.blue = 1;
2258            break;
2259    }
2260    return color;
2261}
2262
2263static gint gtk3_get_color_for_state(JNIEnv *env, WidgetType widget_type,
2264                              GtkStateType state_type, ColorType color_type)
2265{
2266
2267    gint result = 0;
2268
2269    GtkStateFlags flags = gtk3_get_state_flags(state_type);
2270
2271    init_containers();
2272
2273    gtk3_widget = gtk3_get_widget(widget_type);
2274
2275    GtkStyleContext* context = fp_gtk_widget_get_style_context(gtk3_widget);
2276
2277    if (widget_type == TOOL_TIP) {
2278        fp_gtk_style_context_add_class(context, "tooltip");
2279    }
2280    if (widget_type == CHECK_BOX_MENU_ITEM
2281     || widget_type == RADIO_BUTTON_MENU_ITEM) {
2282        flags &= GTK_STATE_FLAG_NORMAL | GTK_STATE_FLAG_SELECTED
2283                  | GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_FOCUSED;
2284    }
2285
2286    GdkRGBA color = gtk3_get_color_for_flags(context, flags, color_type);
2287
2288    if (recode_color(color.alpha) == 0) {
2289        color = gtk3_get_color_for_flags(
2290        fp_gtk_widget_get_style_context(gtk3_get_widget(INTERNAL_FRAME)),
2291        0, BACKGROUND);
2292    }
2293
2294    result = recode_color(color.alpha) << 24 | recode_color(color.red) << 16 |
2295             recode_color(color.green) << 8 | recode_color(color.blue);
2296
2297    return result;
2298}
2299
2300/*************************************************/
2301static jobject create_Boolean(JNIEnv *env, jboolean boolean_value);
2302static jobject create_Integer(JNIEnv *env, jint int_value);
2303static jobject create_Long(JNIEnv *env, jlong long_value);
2304static jobject create_Float(JNIEnv *env, jfloat float_value);
2305static jobject create_Double(JNIEnv *env, jdouble double_value);
2306static jobject create_Character(JNIEnv *env, jchar char_value);
2307static jobject create_Insets(JNIEnv *env, GtkBorder *border);
2308
2309static jobject gtk3_get_class_value(JNIEnv *env, WidgetType widget_type,
2310                                                     const char* key)
2311{
2312    init_containers();
2313
2314    gtk3_widget = gtk3_get_widget(widget_type);
2315
2316    GValue value = { 0, { { 0 } } };
2317
2318    GParamSpec* param = (*fp_gtk_widget_class_find_style_property)(
2319                                    ((GTypeInstance*)gtk3_widget)->g_class, key);
2320    if ( param )
2321    {
2322        (*fp_g_value_init)( &value, param->value_type );
2323        (*fp_gtk_widget_style_get_property)(gtk3_widget, key, &value);
2324
2325        if ((*fp_g_type_is_a)( param->value_type, G_TYPE_BOOLEAN ))
2326        {
2327            gboolean val = (*fp_g_value_get_boolean)(&value);
2328            return create_Boolean(env, (jboolean)val);
2329        }
2330        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_CHAR ))
2331        {
2332            gchar val = (*fp_g_value_get_char)(&value);
2333            return create_Character(env, (jchar)val);
2334        }
2335        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UCHAR ))
2336        {
2337            guchar val = (*fp_g_value_get_uchar)(&value);
2338            return create_Character(env, (jchar)val);
2339        }
2340        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT ))
2341        {
2342            gint val = (*fp_g_value_get_int)(&value);
2343            return create_Integer(env, (jint)val);
2344        }
2345        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT ))
2346        {
2347            guint val = (*fp_g_value_get_uint)(&value);
2348                    return create_Integer(env, (jint)val);
2349        }
2350        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_LONG ))
2351        {
2352            glong val = (*fp_g_value_get_long)(&value);
2353            return create_Long(env, (jlong)val);
2354        }
2355        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ULONG ))
2356        {
2357            gulong val = (*fp_g_value_get_ulong)(&value);
2358            return create_Long(env, (jlong)val);
2359        }
2360        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT64 ))
2361        {
2362            gint64 val = (*fp_g_value_get_int64)(&value);
2363            return create_Long(env, (jlong)val);
2364        }
2365        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT64 ))
2366        {
2367            guint64 val = (*fp_g_value_get_uint64)(&value);
2368            return create_Long(env, (jlong)val);
2369        }
2370        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLOAT ))
2371        {
2372            gfloat val = (*fp_g_value_get_float)(&value);
2373            return create_Float(env, (jfloat)val);
2374        }
2375        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_DOUBLE ))
2376        {
2377            gdouble val = (*fp_g_value_get_double)(&value);
2378            return create_Double(env, (jdouble)val);
2379        }
2380        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ENUM ))
2381        {
2382            gint val = (*fp_g_value_get_enum)(&value);
2383            return create_Integer(env, (jint)val);
2384        }
2385        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLAGS ))
2386        {
2387            guint val = (*fp_g_value_get_flags)(&value);
2388            return create_Integer(env, (jint)val);
2389        }
2390        else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_STRING ))
2391        {
2392            const gchar* val = (*fp_g_value_get_string)(&value);
2393
2394            /* We suppose that all values come in C locale and
2395             * utf-8 representation of a string is the same as
2396             * the string itself. If this isn't so we should
2397             * use g_convert.
2398             */
2399            return (*env)->NewStringUTF(env, val);
2400        }
2401        else if ((*fp_g_type_is_a)( param->value_type, GTK_TYPE_BORDER ))
2402        {
2403            GtkBorder *border = (GtkBorder*)(*fp_g_value_get_boxed)(&value);
2404            return border ? create_Insets(env, border) : NULL;
2405        }
2406
2407        /*      TODO: Other types are not supported yet.*/
2408/*        else if((*fp_g_type_is_a)( param->value_type, G_TYPE_PARAM ))
2409        {
2410            GParamSpec* val = (*fp_g_value_get_param)(&value);
2411            printf( "Param: %p\n", val );
2412        }
2413        else if((*fp_g_type_is_a)( param->value_type, G_TYPE_BOXED ))
2414        {
2415            gpointer* val = (*fp_g_value_get_boxed)(&value);
2416            printf( "Boxed: %p\n", val );
2417        }
2418        else if((*fp_g_type_is_a)( param->value_type, G_TYPE_POINTER ))
2419        {
2420            gpointer* val = (*fp_g_value_get_pointer)(&value);
2421            printf( "Pointer: %p\n", val );
2422        }
2423        else if((*fp_g_type_is_a)( param->value_type, G_TYPE_OBJECT ))
2424        {
2425            GObject* val = (GObject*)(*fp_g_value_get_object)(&value);
2426            printf( "Object: %p\n", val );
2427        }*/
2428    }
2429
2430    return NULL;
2431}
2432
2433static void gtk3_set_range_value(WidgetType widget_type, jdouble value,
2434                          jdouble min, jdouble max, jdouble visible)
2435{
2436    GtkAdjustment *adj;
2437
2438    gtk3_widget = gtk3_get_widget(widget_type);
2439
2440    adj = (*fp_gtk_range_get_adjustment)((GtkRange *)gtk3_widget);
2441
2442    fp_gtk_adjustment_set_value(adj, value);
2443    fp_gtk_adjustment_set_lower(adj, min);
2444    fp_gtk_adjustment_set_upper(adj, max);
2445    fp_gtk_adjustment_set_page_size(adj, visible);
2446}
2447
2448/*************************************************/
2449static jobject create_Object(JNIEnv *env, jmethodID *cid,
2450                             const char* class_name,
2451                             const char* signature,
2452                             jvalue* value)
2453{
2454    jclass  class;
2455    jobject result;
2456
2457    class = (*env)->FindClass(env, class_name);
2458    if (class == NULL)
2459        return NULL; /* can't find/load the class, exception thrown */
2460
2461    if (*cid == NULL)
2462    {
2463        *cid = (*env)->GetMethodID(env, class, "<init>", signature);
2464        if (*cid == NULL)
2465        {
2466            (*env)->DeleteLocalRef(env, class);
2467            return NULL; /* can't find/get the method, exception thrown */
2468        }
2469    }
2470
2471    result = (*env)->NewObjectA(env, class, *cid, value);
2472
2473    (*env)->DeleteLocalRef(env, class);
2474    return result;
2475}
2476
2477jobject create_Boolean(JNIEnv *env, jboolean boolean_value)
2478{
2479    static jmethodID cid = NULL;
2480    jvalue value;
2481
2482    value.z = boolean_value;
2483
2484    return create_Object(env, &cid, "java/lang/Boolean", "(Z)V", &value);
2485}
2486
2487jobject create_Integer(JNIEnv *env, jint int_value)
2488{
2489    static jmethodID cid = NULL;
2490    jvalue value;
2491
2492    value.i = int_value;
2493
2494    return create_Object(env, &cid, "java/lang/Integer", "(I)V", &value);
2495}
2496
2497jobject create_Long(JNIEnv *env, jlong long_value)
2498{
2499    static jmethodID cid = NULL;
2500    jvalue value;
2501
2502    value.j = long_value;
2503
2504    return create_Object(env, &cid, "java/lang/Long", "(J)V", &value);
2505}
2506
2507jobject create_Float(JNIEnv *env, jfloat float_value)
2508{
2509    static jmethodID cid = NULL;
2510    jvalue value;
2511
2512    value.f = float_value;
2513
2514    return create_Object(env, &cid, "java/lang/Float", "(F)V", &value);
2515}
2516
2517jobject create_Double(JNIEnv *env, jdouble double_value)
2518{
2519    static jmethodID cid = NULL;
2520    jvalue value;
2521
2522    value.d = double_value;
2523
2524    return create_Object(env, &cid, "java/lang/Double", "(D)V", &value);
2525}
2526
2527jobject create_Character(JNIEnv *env, jchar char_value)
2528{
2529    static jmethodID cid = NULL;
2530    jvalue value;
2531
2532    value.c = char_value;
2533
2534    return create_Object(env, &cid, "java/lang/Character", "(C)V", &value);
2535}
2536
2537
2538jobject create_Insets(JNIEnv *env, GtkBorder *border)
2539{
2540    static jmethodID cid = NULL;
2541    jvalue values[4];
2542
2543    values[0].i = border->top;
2544    values[1].i = border->left;
2545    values[2].i = border->bottom;
2546    values[3].i = border->right;
2547
2548    return create_Object(env, &cid, "java/awt/Insets", "(IIII)V", values);
2549}
2550
2551/*********************************************/
2552static jstring gtk3_get_pango_font_name(JNIEnv *env, WidgetType widget_type)
2553{
2554    init_containers();
2555
2556    gtk3_widget = gtk3_get_widget(widget_type);
2557    jstring  result = NULL;
2558    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
2559    if (context)
2560    {
2561        PangoFontDescription* fd = fp_gtk_style_context_get_font(context, 0);
2562        gchar* val = (*fp_pango_font_description_to_string)(fd);
2563        result = (*env)->NewStringUTF(env, val);
2564        (*fp_g_free)( val );
2565    }
2566
2567    return result;
2568}
2569
2570/***********************************************/
2571static jobject get_string_property(JNIEnv *env, GtkSettings* settings,
2572                                                             const gchar* key) {
2573    jobject result = NULL;
2574    gchar*  strval = NULL;
2575
2576    (*fp_g_object_get)(settings, key, &strval, NULL);
2577    result = (*env)->NewStringUTF(env, strval);
2578    (*fp_g_free)(strval);
2579
2580    return result;
2581}
2582
2583static jobject get_integer_property(JNIEnv *env, GtkSettings* settings,
2584                                                             const gchar* key) {
2585    gint intval = 0;
2586    (*fp_g_object_get)(settings, key, &intval, NULL);
2587    return create_Integer(env, intval);
2588}
2589
2590static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings,
2591                                                             const gchar* key) {
2592    gint intval = 0;
2593    (*fp_g_object_get)(settings, key, &intval, NULL);
2594    return create_Boolean(env, intval);
2595}
2596
2597static jobject gtk3_get_setting(JNIEnv *env, Setting property)
2598{
2599    GtkSettings* settings = (*fp_gtk_settings_get_default)();
2600
2601    switch (property)
2602    {
2603        case GTK_FONT_NAME:
2604            return get_string_property(env, settings, "gtk-font-name");
2605        case GTK_ICON_SIZES:
2606            return get_string_property(env, settings, "gtk-icon-sizes");
2607        case GTK_CURSOR_BLINK:
2608            return get_boolean_property(env, settings, "gtk-cursor-blink");
2609        case GTK_CURSOR_BLINK_TIME:
2610            return get_integer_property(env, settings, "gtk-cursor-blink-time");
2611    }
2612
2613    return NULL;
2614}
2615
2616static void transform_detail_string (const gchar *detail,
2617                                                     GtkStyleContext *context) {
2618  if (!detail)
2619    return;
2620
2621  if (strcmp (detail, "arrow") == 0)
2622    fp_gtk_style_context_add_class (context, "arrow");
2623  else if (strcmp (detail, "button") == 0)
2624    fp_gtk_style_context_add_class (context, "button");
2625  else if (strcmp (detail, "buttondefault") == 0)
2626    {
2627      fp_gtk_style_context_add_class (context, "button");
2628      fp_gtk_style_context_add_class (context, "default");
2629    }
2630  else if (strcmp (detail, "calendar") == 0)
2631    fp_gtk_style_context_add_class (context, "calendar");
2632  else if (strcmp (detail, "cellcheck") == 0)
2633    {
2634      fp_gtk_style_context_add_class (context, "cell");
2635      fp_gtk_style_context_add_class (context, "check");
2636    }
2637  else if (strcmp (detail, "cellradio") == 0)
2638    {
2639      fp_gtk_style_context_add_class (context, "cell");
2640      fp_gtk_style_context_add_class (context, "radio");
2641    }
2642  else if (strcmp (detail, "checkbutton") == 0)
2643    fp_gtk_style_context_add_class (context, "check");
2644  else if (strcmp (detail, "check") == 0)
2645    {
2646      fp_gtk_style_context_add_class (context, "check");
2647      fp_gtk_style_context_add_class (context, "menu");
2648    }
2649  else if (strcmp (detail, "radiobutton") == 0)
2650    {
2651      fp_gtk_style_context_add_class (context, "radio");
2652    }
2653  else if (strcmp (detail, "option") == 0)
2654    {
2655      fp_gtk_style_context_add_class (context, "radio");
2656      fp_gtk_style_context_add_class (context, "menu");
2657    }
2658  else if (strcmp (detail, "entry") == 0 ||
2659           strcmp (detail, "entry_bg") == 0)
2660    fp_gtk_style_context_add_class (context, "entry");
2661  else if (strcmp (detail, "expander") == 0)
2662    fp_gtk_style_context_add_class (context, "expander");
2663  else if (strcmp (detail, "tooltip") == 0)
2664    fp_gtk_style_context_add_class (context, "tooltip");
2665  else if (strcmp (detail, "frame") == 0)
2666    fp_gtk_style_context_add_class (context, "frame");
2667  else if (strcmp (detail, "scrolled_window") == 0)
2668    fp_gtk_style_context_add_class (context, "scrolled-window");
2669  else if (strcmp (detail, "viewport") == 0 ||
2670           strcmp (detail, "viewportbin") == 0)
2671    fp_gtk_style_context_add_class (context, "viewport");
2672  else if (strncmp (detail, "trough", 6) == 0)
2673    fp_gtk_style_context_add_class (context, "trough");
2674  else if (strcmp (detail, "spinbutton") == 0)
2675    fp_gtk_style_context_add_class (context, "spinbutton");
2676  else if (strcmp (detail, "spinbutton_up") == 0)
2677    {
2678      fp_gtk_style_context_add_class (context, "spinbutton");
2679      fp_gtk_style_context_add_class (context, "button");
2680      fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
2681    }
2682  else if (strcmp (detail, "spinbutton_down") == 0)
2683    {
2684      fp_gtk_style_context_add_class (context, "spinbutton");
2685      fp_gtk_style_context_add_class (context, "button");
2686      fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
2687    }
2688  else if ((detail[0] == 'h' || detail[0] == 'v') &&
2689           strncmp (&detail[1], "scrollbar_", 9) == 0)
2690    {
2691      fp_gtk_style_context_add_class (context, "button");
2692      fp_gtk_style_context_add_class (context, "scrollbar");
2693    }
2694  else if (strcmp (detail, "slider") == 0)
2695    {
2696      fp_gtk_style_context_add_class (context, "slider");
2697      fp_gtk_style_context_add_class (context, "scrollbar");
2698    }
2699  else if (strcmp (detail, "vscale") == 0 ||
2700           strcmp (detail, "hscale") == 0)
2701    {
2702      fp_gtk_style_context_add_class (context, "slider");
2703      fp_gtk_style_context_add_class (context, "scale");
2704    }
2705  else if (strcmp (detail, "menuitem") == 0)
2706    {
2707      fp_gtk_style_context_add_class (context, "menuitem");
2708      fp_gtk_style_context_add_class (context, "menu");
2709    }
2710  else if (strcmp (detail, "menu") == 0)
2711    {
2712      fp_gtk_style_context_add_class (context, "popup");
2713      fp_gtk_style_context_add_class (context, "menu");
2714    }
2715  else if (strcmp (detail, "accellabel") == 0)
2716    fp_gtk_style_context_add_class (context, "accelerator");
2717  else if (strcmp (detail, "menubar") == 0)
2718    fp_gtk_style_context_add_class (context, "menubar");
2719  else if (strcmp (detail, "base") == 0)
2720    fp_gtk_style_context_add_class (context, "background");
2721  else if (strcmp (detail, "bar") == 0 ||
2722           strcmp (detail, "progressbar") == 0)
2723    fp_gtk_style_context_add_class (context, "progressbar");
2724  else if (strcmp (detail, "toolbar") == 0)
2725    fp_gtk_style_context_add_class (context, "toolbar");
2726  else if (strcmp (detail, "handlebox_bin") == 0)
2727    fp_gtk_style_context_add_class (context, "dock");
2728  else if (strcmp (detail, "notebook") == 0)
2729    fp_gtk_style_context_add_class (context, "notebook");
2730  else if (strcmp (detail, "tab") == 0)
2731  {
2732      fp_gtk_style_context_add_class (context, "notebook");
2733      fp_gtk_style_context_add_region (context, "tab", 0);
2734  } else if (strcmp (detail, "paned") == 0) {
2735      fp_gtk_style_context_add_class (context, "pane-separator");
2736  }
2737  else if (fp_g_str_has_prefix (detail, "cell"))
2738    {
2739      GtkRegionFlags row, col;
2740      gboolean ruled = FALSE;
2741      gchar** tokens;
2742      guint i;
2743
2744      tokens = fp_g_strsplit (detail, "_", -1);
2745      row = col = 0;
2746      i = 0;
2747
2748      while (tokens[i])
2749        {
2750          if (strcmp (tokens[i], "even") == 0)
2751            row |= GTK_REGION_EVEN;
2752          else if (strcmp (tokens[i], "odd") == 0)
2753            row |= GTK_REGION_ODD;
2754          else if (strcmp (tokens[i], "start") == 0)
2755            col |= GTK_REGION_FIRST;
2756          else if (strcmp (tokens[i], "end") == 0)
2757            col |= GTK_REGION_LAST;
2758          else if (strcmp (tokens[i], "ruled") == 0)
2759            ruled = TRUE;
2760          else if (strcmp (tokens[i], "sorted") == 0)
2761            col |= GTK_REGION_SORTED;
2762
2763          i++;
2764        }
2765
2766      if (!ruled)
2767        row &= ~(GTK_REGION_EVEN | GTK_REGION_ODD);
2768
2769      fp_gtk_style_context_add_class (context, "cell");
2770      fp_gtk_style_context_add_region (context, "row", row);
2771      fp_gtk_style_context_add_region (context, "column", col);
2772
2773      fp_g_strfreev (tokens);
2774    }
2775}
2776
2777static gboolean gtk3_get_drawable_data(JNIEnv *env, jintArray pixelArray,
2778     int x, jint y, jint width, jint height, jint jwidth, int dx, int dy,
2779                                                                   jint scale) {
2780    GdkPixbuf *pixbuf;
2781    jint *ary;
2782
2783    GdkWindow *root = (*fp_gdk_get_default_root_window)();
2784    pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(root, x, y, width, height);
2785    if (pixbuf && scale != 1) {
2786        GdkPixbuf *scaledPixbuf;
2787        x /= scale;
2788        y /= scale;
2789        width /= scale;
2790        height /= scale;
2791        dx /= scale;
2792        dy /= scale;
2793        scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height,
2794                                                     GDK_INTERP_BILINEAR);
2795        (*fp_g_object_unref)(pixbuf);
2796        pixbuf = scaledPixbuf;
2797    }
2798
2799    if (pixbuf) {
2800        int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);
2801        int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf);
2802        if ((*fp_gdk_pixbuf_get_width)(pixbuf) == width
2803                && (*fp_gdk_pixbuf_get_height)(pixbuf) == height
2804                && (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 8
2805                && (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB
2806                && nchan >= 3
2807                ) {
2808            guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf);
2809            ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL);
2810            if (ary) {
2811                jint _x, _y;
2812                int index;
2813                for (_y = 0; _y < height; _y++) {
2814                    for (_x = 0; _x < width; _x++) {
2815                        p = pix + _y * stride + _x * nchan;
2816
2817                        index = (_y + dy) * jwidth + (_x + dx);
2818                        ary[index] = 0xff000000
2819                                        | (p[0] << 16)
2820                                        | (p[1] << 8)
2821                                        | (p[2]);
2822
2823                    }
2824                }
2825                (*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0);
2826            }
2827        }
2828        (*fp_g_object_unref)(pixbuf);
2829    }
2830    return JNI_FALSE;
2831}
2832
2833static GdkWindow* gtk3_get_window(void *widget) {
2834    return fp_gtk_widget_get_window((GtkWidget*)widget);
2835}
2836
2837static void gtk3_init(GtkApi* gtk) {
2838    gtk->version = GTK_3;
2839
2840    gtk->show_uri_load = &gtk3_show_uri_load;
2841    gtk->unload = &gtk3_unload;
2842    gtk->flush_event_loop = &flush_gtk_event_loop;
2843    gtk->gtk_check_version = fp_gtk_check_version;
2844    gtk->get_setting = &gtk3_get_setting;
2845
2846    gtk->paint_arrow = &gtk3_paint_arrow;
2847    gtk->paint_box = &gtk3_paint_box;
2848    gtk->paint_box_gap = &gtk3_paint_box_gap;
2849    gtk->paint_expander = &gtk3_paint_expander;
2850    gtk->paint_extension = &gtk3_paint_extension;
2851    gtk->paint_flat_box = &gtk3_paint_flat_box;
2852    gtk->paint_focus = &gtk3_paint_focus;
2853    gtk->paint_handle = &gtk3_paint_handle;
2854    gtk->paint_hline = &gtk3_paint_hline;
2855    gtk->paint_vline = &gtk3_paint_vline;
2856    gtk->paint_option = &gtk3_paint_option;
2857    gtk->paint_shadow = &gtk3_paint_shadow;
2858    gtk->paint_slider = &gtk3_paint_slider;
2859    gtk->paint_background = &gtk3_paint_background;
2860    gtk->paint_check = &gtk3_paint_check;
2861    gtk->set_range_value = &gtk3_set_range_value;
2862
2863    gtk->init_painting = &gtk3_init_painting;
2864    gtk->copy_image = &gtk3_copy_image;
2865
2866    gtk->get_xthickness = &gtk3_get_xthickness;
2867    gtk->get_ythickness = &gtk3_get_ythickness;
2868    gtk->get_color_for_state = &gtk3_get_color_for_state;
2869    gtk->get_class_value = &gtk3_get_class_value;
2870
2871    gtk->get_pango_font_name = &gtk3_get_pango_font_name;
2872    gtk->get_icon_data = &gtk3_get_icon_data;
2873    gtk->get_file_icon_data = &gtk3_get_file_icon_data;
2874    gtk->gdk_threads_enter = fp_gdk_threads_enter;
2875    gtk->gdk_threads_leave = fp_gdk_threads_leave;
2876    gtk->gtk_show_uri = fp_gtk_show_uri;
2877    gtk->get_drawable_data = &gtk3_get_drawable_data;
2878    gtk->g_free = fp_g_free;
2879
2880    gtk->gtk_file_chooser_get_filename = fp_gtk_file_chooser_get_filename;
2881    gtk->gtk_widget_hide = fp_gtk_widget_hide;
2882    gtk->gtk_main_quit = fp_gtk_main_quit;
2883    gtk->gtk_file_chooser_dialog_new = fp_gtk_file_chooser_dialog_new;
2884    gtk->gtk_file_chooser_set_current_folder =
2885                          fp_gtk_file_chooser_set_current_folder;
2886    gtk->gtk_file_chooser_set_filename = fp_gtk_file_chooser_set_filename;
2887    gtk->gtk_file_chooser_set_current_name =
2888                          fp_gtk_file_chooser_set_current_name;
2889    gtk->gtk_file_filter_add_custom = fp_gtk_file_filter_add_custom;
2890    gtk->gtk_file_chooser_set_filter = fp_gtk_file_chooser_set_filter;
2891    gtk->gtk_file_chooser_get_type = fp_gtk_file_chooser_get_type;
2892    gtk->gtk_file_filter_new = fp_gtk_file_filter_new;
2893    gtk->gtk_file_chooser_set_do_overwrite_confirmation =
2894                          fp_gtk_file_chooser_set_do_overwrite_confirmation;
2895    gtk->gtk_file_chooser_set_select_multiple =
2896                          fp_gtk_file_chooser_set_select_multiple;
2897    gtk->gtk_file_chooser_get_current_folder =
2898                          fp_gtk_file_chooser_get_current_folder;
2899    gtk->gtk_file_chooser_get_filenames = fp_gtk_file_chooser_get_filenames;
2900    gtk->gtk_g_slist_length = fp_gtk_g_slist_length;
2901    gtk->g_signal_connect_data = fp_g_signal_connect_data;
2902    gtk->gtk_widget_show = fp_gtk_widget_show;
2903    gtk->gtk_main = fp_gtk_main;
2904    gtk->gtk_main_level = fp_gtk_main_level;
2905    gtk->g_path_get_dirname = fp_g_path_get_dirname;
2906    gtk->gdk_x11_drawable_get_xid = fp_gdk_x11_drawable_get_xid;
2907    gtk->gtk_widget_destroy = fp_gtk_widget_destroy;
2908    gtk->gtk_window_present = fp_gtk_window_present;
2909    gtk->gtk_window_move = fp_gtk_window_move;
2910    gtk->gtk_window_resize = fp_gtk_window_resize;
2911    gtk->get_window = &gtk3_get_window;
2912
2913    gtk->g_object_unref = fp_g_object_unref;
2914    gtk->g_list_append = fp_g_list_append;
2915    gtk->g_list_free = fp_g_list_free;
2916    gtk->g_list_free_full = fp_g_list_free_full;
2917}
2918