Path: blob/master/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
66646 views
/*1* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifdef HEADLESS26#error This file should not be included in headless library27#endif2829#include <dlfcn.h>30#include <setjmp.h>31#include <X11/Xlib.h>32#include <limits.h>33#include <string.h>34#include "gtk3_interface.h"35#include "java_awt_Transparency.h"36#include "sizecalc.h"37#include <jni_util.h>38#include <stdio.h>39#include "awt.h"4041static void *gtk3_libhandle = NULL;42static void *gthread_libhandle = NULL;4344static jmp_buf j;4546/* Widgets */47static GtkWidget *gtk3_widget = NULL;48static GtkWidget *gtk3_window = NULL;49static GtkFixed *gtk3_fixed = NULL;50static GtkStyleProvider *gtk3_css = NULL;5152/* Paint system */53static cairo_surface_t *surface = NULL;54static cairo_t *cr = NULL;5556static const char ENV_PREFIX[] = "GTK_MODULES=";5758static GtkWidget *gtk3_widgets[_GTK_WIDGET_TYPE_SIZE];5960/* This is a workaround for the bug:61* http://sourceware.org/bugzilla/show_bug.cgi?id=181462* (dlsym/dlopen clears dlerror state)63* This bug is specific to Linux, but there is no harm in64* applying this workaround on Solaris as well.65*/66static void* dl_symbol(const char* name)67{68void* result = dlsym(gtk3_libhandle, name);69if (!result)70longjmp(j, NO_SYMBOL_EXCEPTION);7172return result;73}7475static void* dl_symbol_gthread(const char* name)76{77void* result = dlsym(gthread_libhandle, name);78if (!result)79longjmp(j, NO_SYMBOL_EXCEPTION);8081return result;82}8384gboolean gtk3_check(const char* lib_name, gboolean load)85{86if (gtk3_libhandle != NULL) {87/* We've already successfully opened the GTK libs, so return true. */88return TRUE;89} else {90#ifdef RTLD_NOLOAD91void *lib = dlopen(lib_name, RTLD_LAZY | RTLD_NOLOAD);92if (!load || lib != NULL) {93return lib != NULL;94}95#else96#ifdef _AIX97/* On AIX we could implement this with the help of loadquery(L_GETINFO, ..) */98/* (see reload_table() in hotspot/src/os/aix/vm/loadlib_aix.cpp) but it is */99/* probably not worth it because most AIX servers don't have GTK libs anyway */100#endif101#endif102return dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL) != NULL;103}104}105106#define ADD_SUPPORTED_ACTION(actionStr) \107do { \108jfieldID fld_action = (*env)->GetStaticFieldID(env, cls_action, actionStr, \109"Ljava/awt/Desktop$Action;"); \110if (!(*env)->ExceptionCheck(env)) { \111jobject action = (*env)->GetStaticObjectField(env, cls_action, \112fld_action); \113(*env)->CallBooleanMethod(env, supportedActions, mid_arrayListAdd, \114action); \115} else { \116(*env)->ExceptionClear(env); \117} \118} while(0);119120121static void update_supported_actions(JNIEnv *env) {122GVfs * (*fp_g_vfs_get_default) (void);123const gchar * const * (*fp_g_vfs_get_supported_uri_schemes) (GVfs * vfs);124const gchar * const * schemes = NULL;125126jclass cls_action = (*env)->FindClass(env, "java/awt/Desktop$Action");127CHECK_NULL(cls_action);128jclass cls_xDesktopPeer = (*env)->129FindClass(env, "sun/awt/X11/XDesktopPeer");130CHECK_NULL(cls_xDesktopPeer);131jfieldID fld_supportedActions = (*env)->GetStaticFieldID(env,132cls_xDesktopPeer, "supportedActions", "Ljava/util/List;");133CHECK_NULL(fld_supportedActions);134jobject supportedActions = (*env)->GetStaticObjectField(env,135cls_xDesktopPeer, fld_supportedActions);136137jclass cls_arrayList = (*env)->FindClass(env, "java/util/ArrayList");138CHECK_NULL(cls_arrayList);139jmethodID mid_arrayListAdd = (*env)->GetMethodID(env, cls_arrayList, "add",140"(Ljava/lang/Object;)Z");141CHECK_NULL(mid_arrayListAdd);142jmethodID mid_arrayListClear = (*env)->GetMethodID(env, cls_arrayList,143"clear", "()V");144CHECK_NULL(mid_arrayListClear);145146(*env)->CallVoidMethod(env, supportedActions, mid_arrayListClear);147148ADD_SUPPORTED_ACTION("OPEN");149150/**151* gtk_show_uri() documentation says:152*153* > you need to install gvfs to get support for uri schemes such as http://154* > or ftp://, as only local files are handled by GIO itself.155*156* So OPEN action was safely added here.157* However, it looks like Solaris 11 have gvfs support only for 32-bit158* applications only by default.159*/160161fp_g_vfs_get_default = dl_symbol("g_vfs_get_default");162fp_g_vfs_get_supported_uri_schemes =163dl_symbol("g_vfs_get_supported_uri_schemes");164dlerror();165166if (fp_g_vfs_get_default && fp_g_vfs_get_supported_uri_schemes) {167GVfs * vfs = fp_g_vfs_get_default();168schemes = vfs ? fp_g_vfs_get_supported_uri_schemes(vfs) : NULL;169if (schemes) {170int i = 0;171while (schemes[i]) {172if (strcmp(schemes[i], "http") == 0) {173ADD_SUPPORTED_ACTION("BROWSE");174ADD_SUPPORTED_ACTION("MAIL");175break;176}177i++;178}179}180} else {181#ifdef DEBUG182fprintf(stderr, "Cannot load g_vfs_get_supported_uri_schemes\n");183#endif /* DEBUG */184}185186}187/**188* Functions for awt_Desktop.c189*/190static gboolean gtk3_show_uri_load(JNIEnv *env) {191gboolean success = FALSE;192dlerror();193fp_gtk_show_uri = dl_symbol("gtk_show_uri");194const char *dlsym_error = dlerror();195if (dlsym_error) {196#ifdef DEBUG197fprintf (stderr, "Cannot load symbol: %s \n", dlsym_error);198#endif /* DEBUG */199} else if (fp_gtk_show_uri == NULL) {200#ifdef DEBUG201fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n");202#endif /* DEBUG */203} else {204gtk->gtk_show_uri = fp_gtk_show_uri;205update_supported_actions(env);206success = TRUE;207}208return success;209}210211/**212* Functions for sun_awt_X11_GtkFileDialogPeer.c213*/214static void gtk3_file_chooser_load()215{216fp_gtk_file_chooser_get_filename = dl_symbol(217"gtk_file_chooser_get_filename");218fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new");219fp_gtk_file_chooser_set_current_folder = dl_symbol(220"gtk_file_chooser_set_current_folder");221fp_gtk_file_chooser_set_filename = dl_symbol(222"gtk_file_chooser_set_filename");223fp_gtk_file_chooser_set_current_name = dl_symbol(224"gtk_file_chooser_set_current_name");225fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom");226fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter");227fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type");228fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new");229fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol(230"gtk_file_chooser_set_do_overwrite_confirmation");231fp_gtk_file_chooser_set_select_multiple = dl_symbol(232"gtk_file_chooser_set_select_multiple");233fp_gtk_file_chooser_get_current_folder = dl_symbol(234"gtk_file_chooser_get_current_folder");235fp_gtk_file_chooser_get_filenames = dl_symbol(236"gtk_file_chooser_get_filenames");237fp_gtk_g_slist_length = dl_symbol("g_slist_length");238fp_gdk_x11_drawable_get_xid = dl_symbol("gdk_x11_window_get_xid");239}240241static void empty() {}242243static gboolean gtk3_version_3_10 = TRUE;244static gboolean gtk3_version_3_14 = FALSE;245static gboolean gtk3_version_3_20 = FALSE;246247GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)248{249gboolean result;250int i;251int (*handler)();252int (*io_handler)();253char *gtk_modules_env;254gtk3_libhandle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL);255if (gtk3_libhandle == NULL) {256return FALSE;257}258259gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL);260if (gthread_libhandle == NULL) {261gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL);262if (gthread_libhandle == NULL)263return FALSE;264}265266if (setjmp(j) == 0)267{268fp_gtk_check_version = dl_symbol("gtk_check_version");269270/* GLib */271fp_glib_check_version = dlsym(gtk3_libhandle, "glib_check_version");272if (!fp_glib_check_version) {273dlerror();274}275fp_g_free = dl_symbol("g_free");276fp_g_object_unref = dl_symbol("g_object_unref");277278fp_g_main_context_iteration =279dl_symbol("g_main_context_iteration");280281fp_g_value_init = dl_symbol("g_value_init");282fp_g_type_is_a = dl_symbol("g_type_is_a");283fp_g_value_get_boolean = dl_symbol("g_value_get_boolean");284fp_g_value_get_char = dl_symbol("g_value_get_char");285fp_g_value_get_uchar = dl_symbol("g_value_get_uchar");286fp_g_value_get_int = dl_symbol("g_value_get_int");287fp_g_value_get_uint = dl_symbol("g_value_get_uint");288fp_g_value_get_long = dl_symbol("g_value_get_long");289fp_g_value_get_ulong = dl_symbol("g_value_get_ulong");290fp_g_value_get_int64 = dl_symbol("g_value_get_int64");291fp_g_value_get_uint64 = dl_symbol("g_value_get_uint64");292fp_g_value_get_float = dl_symbol("g_value_get_float");293fp_g_value_get_double = dl_symbol("g_value_get_double");294fp_g_value_get_string = dl_symbol("g_value_get_string");295fp_g_value_get_enum = dl_symbol("g_value_get_enum");296fp_g_value_get_flags = dl_symbol("g_value_get_flags");297fp_g_value_get_param = dl_symbol("g_value_get_param");298fp_g_value_get_boxed = dl_symbol("g_value_get_boxed");299fp_g_value_get_pointer = dl_symbol("g_value_get_pointer");300301fp_g_object_get = dl_symbol("g_object_get");302fp_g_object_set = dl_symbol("g_object_set");303304fp_g_str_has_prefix = dl_symbol("g_str_has_prefix");305fp_g_strsplit = dl_symbol("g_strsplit");306fp_g_strfreev = dl_symbol("g_strfreev");307308/* GDK */309fp_gdk_get_default_root_window =310dl_symbol("gdk_get_default_root_window");311312/* Pixbuf */313fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new");314fp_gdk_pixbuf_new_from_file =315dl_symbol("gdk_pixbuf_new_from_file");316fp_gdk_pixbuf_get_from_drawable =317dl_symbol("gdk_pixbuf_get_from_window");318fp_gdk_pixbuf_get_width = dl_symbol("gdk_pixbuf_get_width");319fp_gdk_pixbuf_get_height = dl_symbol("gdk_pixbuf_get_height");320fp_gdk_pixbuf_get_pixels = dl_symbol("gdk_pixbuf_get_pixels");321fp_gdk_pixbuf_get_rowstride =322dl_symbol("gdk_pixbuf_get_rowstride");323fp_gdk_pixbuf_get_has_alpha =324dl_symbol("gdk_pixbuf_get_has_alpha");325fp_gdk_pixbuf_get_bits_per_sample =326dl_symbol("gdk_pixbuf_get_bits_per_sample");327fp_gdk_pixbuf_get_n_channels =328dl_symbol("gdk_pixbuf_get_n_channels");329fp_gdk_pixbuf_get_colorspace =330dl_symbol("gdk_pixbuf_get_colorspace");331332fp_cairo_image_surface_create = dl_symbol("cairo_image_surface_create");333fp_cairo_surface_destroy = dl_symbol("cairo_surface_destroy");334fp_cairo_surface_status = dl_symbol("cairo_surface_status");335fp_cairo_create = dl_symbol("cairo_create");336fp_cairo_destroy = dl_symbol("cairo_destroy");337fp_cairo_status = dl_symbol("cairo_status");338fp_cairo_fill = dl_symbol("cairo_fill");339fp_cairo_rectangle = dl_symbol("cairo_rectangle");340fp_cairo_set_source_rgb = dl_symbol("cairo_set_source_rgb");341fp_cairo_set_source_rgba = dl_symbol("cairo_set_source_rgba");342fp_cairo_surface_flush = dl_symbol("cairo_surface_flush");343fp_cairo_paint = dl_symbol("cairo_paint");344fp_cairo_clip = dl_symbol("cairo_clip");345fp_cairo_image_surface_get_data =346dl_symbol("cairo_image_surface_get_data");347fp_cairo_image_surface_get_stride =348dl_symbol("cairo_image_surface_get_stride");349350fp_gdk_pixbuf_get_from_surface =351dl_symbol("gdk_pixbuf_get_from_surface");352353fp_gtk_widget_get_state = dl_symbol("gtk_widget_get_state");354fp_gtk_widget_set_state = dl_symbol("gtk_widget_set_state");355356fp_gtk_widget_is_focus = dl_symbol("gtk_widget_is_focus");357fp_gtk_widget_set_allocation = dl_symbol("gtk_widget_set_allocation");358fp_gtk_widget_get_parent = dl_symbol("gtk_widget_get_parent");359fp_gtk_widget_get_window = dl_symbol("gtk_widget_get_window");360361fp_gtk_widget_get_style_context =362dl_symbol("gtk_widget_get_style_context");363fp_gtk_style_context_get_color =364dl_symbol("gtk_style_context_get_color");365fp_gtk_style_context_get_background_color =366dl_symbol("gtk_style_context_get_background_color");367fp_gtk_widget_get_state_flags = dl_symbol("gtk_widget_get_state_flags");368fp_gtk_style_context_set_state =369dl_symbol("gtk_style_context_set_state");370fp_gtk_style_context_add_class =371dl_symbol("gtk_style_context_add_class");372fp_gtk_style_context_save = dl_symbol("gtk_style_context_save");373fp_gtk_style_context_restore = dl_symbol("gtk_style_context_restore");374fp_gtk_render_check = dl_symbol("gtk_render_check");375fp_gtk_render_option = dl_symbol("gtk_render_option");376fp_gtk_render_extension = dl_symbol("gtk_render_extension");377fp_gtk_render_expander = dl_symbol("gtk_render_expander");378fp_gtk_render_frame_gap = dl_symbol("gtk_render_frame_gap");379fp_gtk_render_line = dl_symbol("gtk_render_line");380fp_gtk_widget_render_icon_pixbuf =381dl_symbol("gtk_widget_render_icon_pixbuf");382if (fp_gtk_check_version(3, 10, 0)) {383gtk3_version_3_10 = FALSE;384} else {385fp_gdk_window_create_similar_image_surface =386dl_symbol("gdk_window_create_similar_image_surface");387fp_gdk_window_get_scale_factor =388dl_symbol("gdk_window_get_scale_factor");389}390gtk3_version_3_14 = !fp_gtk_check_version(3, 14, 0);391392if (!fp_gtk_check_version(3, 20, 0)) {393gtk3_version_3_20 = TRUE;394fp_gtk_widget_path_copy = dl_symbol("gtk_widget_path_copy");395fp_gtk_widget_path_new = dl_symbol("gtk_widget_path_new");396fp_gtk_widget_path_append_type = dl_symbol("gtk_widget_path_append_type");397fp_gtk_widget_path_iter_set_object_name = dl_symbol("gtk_widget_path_iter_set_object_name");398fp_gtk_style_context_set_path = dl_symbol("gtk_style_context_set_path");399fp_gtk_widget_path_unref = dl_symbol("gtk_widget_path_unref");400fp_gtk_style_context_get_path = dl_symbol("gtk_style_context_get_path");401fp_gtk_style_context_new = dl_symbol("gtk_style_context_new");402}403404fp_gdk_window_create_similar_surface =405dl_symbol("gdk_window_create_similar_surface");406fp_gtk_settings_get_for_screen =407dl_symbol("gtk_settings_get_for_screen");408fp_gtk_widget_get_screen = dl_symbol("gtk_widget_get_screen");409fp_gtk_css_provider_get_named = dl_symbol("gtk_css_provider_get_named");410fp_gtk_style_context_add_provider =411dl_symbol("gtk_style_context_add_provider");412fp_gtk_render_frame = dl_symbol("gtk_render_frame");413fp_gtk_render_focus = dl_symbol("gtk_render_focus");414fp_gtk_render_handle = dl_symbol("gtk_render_handle");415fp_gtk_render_arrow = dl_symbol("gtk_render_arrow");416417fp_gtk_style_context_get_property =418dl_symbol("gtk_style_context_get_property");419fp_gtk_scrolled_window_set_shadow_type =420dl_symbol("gtk_scrolled_window_set_shadow_type");421fp_gtk_render_slider = dl_symbol("gtk_render_slider");422fp_gtk_style_context_get_padding =423dl_symbol("gtk_style_context_get_padding");424fp_gtk_range_set_inverted = dl_symbol("gtk_range_set_inverted");425fp_gtk_style_context_get_font = dl_symbol("gtk_style_context_get_font");426fp_gtk_widget_get_allocated_width =427dl_symbol("gtk_widget_get_allocated_width");428fp_gtk_widget_get_allocated_height =429dl_symbol("gtk_widget_get_allocated_height");430fp_gtk_icon_theme_get_default = dl_symbol("gtk_icon_theme_get_default");431fp_gtk_icon_theme_load_icon = dl_symbol("gtk_icon_theme_load_icon");432433fp_gtk_adjustment_set_lower = dl_symbol("gtk_adjustment_set_lower");434fp_gtk_adjustment_set_page_increment =435dl_symbol("gtk_adjustment_set_page_increment");436fp_gtk_adjustment_set_page_size =437dl_symbol("gtk_adjustment_set_page_size");438fp_gtk_adjustment_set_step_increment =439dl_symbol("gtk_adjustment_set_step_increment");440fp_gtk_adjustment_set_upper = dl_symbol("gtk_adjustment_set_upper");441fp_gtk_adjustment_set_value = dl_symbol("gtk_adjustment_set_value");442443fp_gtk_render_activity = dl_symbol("gtk_render_activity");444fp_gtk_render_background = dl_symbol("gtk_render_background");445fp_gtk_style_context_has_class =446dl_symbol("gtk_style_context_has_class");447448fp_gtk_style_context_set_junction_sides =449dl_symbol("gtk_style_context_set_junction_sides");450fp_gtk_style_context_add_region =451dl_symbol("gtk_style_context_add_region");452453fp_gtk_init_check = dl_symbol("gtk_init_check");454455/* GTK widgets */456fp_gtk_arrow_new = dl_symbol("gtk_arrow_new");457fp_gtk_button_new = dl_symbol("gtk_button_new");458fp_gtk_spin_button_new = dl_symbol("gtk_spin_button_new");459fp_gtk_check_button_new = dl_symbol("gtk_check_button_new");460fp_gtk_check_menu_item_new =461dl_symbol("gtk_check_menu_item_new");462fp_gtk_color_selection_dialog_new =463dl_symbol("gtk_color_selection_dialog_new");464fp_gtk_entry_new = dl_symbol("gtk_entry_new");465fp_gtk_fixed_new = dl_symbol("gtk_fixed_new");466fp_gtk_handle_box_new = dl_symbol("gtk_handle_box_new");467fp_gtk_image_new = dl_symbol("gtk_image_new");468fp_gtk_paned_new = dl_symbol("gtk_paned_new");469fp_gtk_scale_new = dl_symbol("gtk_scale_new");470fp_gtk_hscrollbar_new = dl_symbol("gtk_hscrollbar_new");471fp_gtk_vscrollbar_new = dl_symbol("gtk_vscrollbar_new");472fp_gtk_hseparator_new = dl_symbol("gtk_hseparator_new");473fp_gtk_vseparator_new = dl_symbol("gtk_vseparator_new");474fp_gtk_label_new = dl_symbol("gtk_label_new");475fp_gtk_menu_new = dl_symbol("gtk_menu_new");476fp_gtk_menu_bar_new = dl_symbol("gtk_menu_bar_new");477fp_gtk_menu_item_new = dl_symbol("gtk_menu_item_new");478fp_gtk_menu_item_set_submenu =479dl_symbol("gtk_menu_item_set_submenu");480fp_gtk_notebook_new = dl_symbol("gtk_notebook_new");481fp_gtk_progress_bar_new =482dl_symbol("gtk_progress_bar_new");483fp_gtk_progress_bar_set_orientation =484dl_symbol("gtk_orientable_set_orientation");485fp_gtk_radio_button_new =486dl_symbol("gtk_radio_button_new");487fp_gtk_radio_menu_item_new =488dl_symbol("gtk_radio_menu_item_new");489fp_gtk_scrolled_window_new =490dl_symbol("gtk_scrolled_window_new");491fp_gtk_separator_menu_item_new =492dl_symbol("gtk_separator_menu_item_new");493fp_gtk_text_view_new = dl_symbol("gtk_text_view_new");494fp_gtk_toggle_button_new =495dl_symbol("gtk_toggle_button_new");496fp_gtk_toolbar_new = dl_symbol("gtk_toolbar_new");497fp_gtk_tree_view_new = dl_symbol("gtk_tree_view_new");498fp_gtk_viewport_new = dl_symbol("gtk_viewport_new");499fp_gtk_window_new = dl_symbol("gtk_window_new");500fp_gtk_window_present = dl_symbol("gtk_window_present");501fp_gtk_window_move = dl_symbol("gtk_window_move");502fp_gtk_window_resize = dl_symbol("gtk_window_resize");503504fp_gtk_dialog_new = dl_symbol("gtk_dialog_new");505fp_gtk_frame_new = dl_symbol("gtk_frame_new");506507fp_gtk_adjustment_new = dl_symbol("gtk_adjustment_new");508fp_gtk_container_add = dl_symbol("gtk_container_add");509fp_gtk_menu_shell_append =510dl_symbol("gtk_menu_shell_append");511fp_gtk_widget_realize = dl_symbol("gtk_widget_realize");512fp_gtk_widget_destroy = dl_symbol("gtk_widget_destroy");513fp_gtk_widget_render_icon =514dl_symbol("gtk_widget_render_icon");515fp_gtk_widget_set_name =516dl_symbol("gtk_widget_set_name");517fp_gtk_widget_set_parent =518dl_symbol("gtk_widget_set_parent");519fp_gtk_widget_set_direction =520dl_symbol("gtk_widget_set_direction");521fp_gtk_widget_style_get =522dl_symbol("gtk_widget_style_get");523fp_gtk_widget_class_install_style_property =524dl_symbol("gtk_widget_class_install_style_property");525fp_gtk_widget_class_find_style_property =526dl_symbol("gtk_widget_class_find_style_property");527fp_gtk_widget_style_get_property =528dl_symbol("gtk_widget_style_get_property");529fp_pango_font_description_to_string =530dl_symbol("pango_font_description_to_string");531fp_gtk_settings_get_default =532dl_symbol("gtk_settings_get_default");533fp_gtk_widget_get_settings =534dl_symbol("gtk_widget_get_settings");535fp_gtk_border_get_type = dl_symbol("gtk_border_get_type");536fp_gtk_arrow_set = dl_symbol("gtk_arrow_set");537fp_gtk_widget_size_request =538dl_symbol("gtk_widget_size_request");539fp_gtk_range_get_adjustment =540dl_symbol("gtk_range_get_adjustment");541542fp_gtk_widget_hide = dl_symbol("gtk_widget_hide");543fp_gtk_main_quit = dl_symbol("gtk_main_quit");544fp_g_signal_connect_data = dl_symbol("g_signal_connect_data");545fp_gtk_widget_show = dl_symbol("gtk_widget_show");546fp_gtk_main = dl_symbol("gtk_main");547548fp_g_path_get_dirname = dl_symbol("g_path_get_dirname");549550fp_gdk_threads_init = dl_symbol("gdk_threads_init");551fp_gdk_threads_enter = dl_symbol("gdk_threads_enter");552fp_gdk_threads_leave = dl_symbol("gdk_threads_leave");553554/**555* Functions for sun_awt_X11_GtkFileDialogPeer.c556*/557gtk3_file_chooser_load();558559fp_gtk_combo_box_new = dlsym(gtk3_libhandle, "gtk_combo_box_new");560fp_gtk_combo_box_entry_new = dlsym(gtk3_libhandle,561"gtk_combo_box_new_with_entry");562fp_gtk_separator_tool_item_new = dlsym(gtk3_libhandle,563"gtk_separator_tool_item_new");564fp_g_list_append = dl_symbol("g_list_append");565fp_g_list_free = dl_symbol("g_list_free");566fp_g_list_free_full = dl_symbol("g_list_free_full");567}568/* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION569* Otherwise we can check the return value of setjmp method.570*/571else572{573dlclose(gtk3_libhandle);574gtk3_libhandle = NULL;575576dlclose(gthread_libhandle);577gthread_libhandle = NULL;578579return NULL;580}581582/*583* Strip the AT-SPI GTK_MODULES if present584*/585gtk_modules_env = getenv ("GTK_MODULES");586if ((gtk_modules_env && strstr(gtk_modules_env, "atk-bridge")) ||587(gtk_modules_env && strstr(gtk_modules_env, "gail"))) {588/* careful, strtok modifies its args */589gchar *tmp_env = strdup(gtk_modules_env);590if (tmp_env) {591/* the new env will be smaller than the old one */592gchar *s, *new_env = SAFE_SIZE_STRUCT_ALLOC(malloc,593sizeof(ENV_PREFIX), 1, strlen (gtk_modules_env));594595if (new_env) {596strcpy(new_env, ENV_PREFIX);597598/* strip out 'atk-bridge' and 'gail' */599size_t PREFIX_LENGTH = strlen(ENV_PREFIX);600gchar *tmp_ptr = NULL;601for (s = strtok_r(tmp_env, ":", &tmp_ptr); s;602s = strtok_r(NULL, ":", &tmp_ptr)) {603if ((!strstr(s, "atk-bridge")) && (!strstr(s, "gail"))) {604if (strlen(new_env) > PREFIX_LENGTH) {605new_env = strcat(new_env, ":");606}607new_env = strcat(new_env, s);608}609}610if (putenv(new_env) != 0) {611/* no free() on success, putenv() doesn't copy string */612free(new_env);613}614}615free(tmp_env);616}617}618/*619* GTK should be initialized with gtk_init_check() before use.620*621* gtk_init_check installs its own error handlers. It is critical that622* we preserve error handler set from AWT. Otherwise we'll crash on623* BadMatch errors which we would normally ignore. The IO error handler624* is preserved here, too, just for consistency.625*/626AWT_LOCK();627handler = XSetErrorHandler(NULL);628io_handler = XSetIOErrorHandler(NULL);629630//According the GTK documentation, gdk_threads_init() should be631//called before gtk_init() or gtk_init_check()632fp_gdk_threads_init();633result = (*fp_gtk_init_check)(NULL, NULL);634635XSetErrorHandler(handler);636XSetIOErrorHandler(io_handler);637AWT_UNLOCK();638639/* Initialize widget array. */640for (i = 0; i < _GTK_WIDGET_TYPE_SIZE; i++)641{642gtk3_widgets[i] = NULL;643}644if (result) {645GtkApi* gtk = (GtkApi*)malloc(sizeof(GtkApi));646gtk3_init(gtk);647return gtk;648}649return NULL;650}651652static int gtk3_unload()653{654int i;655char *gtk3_error;656657if (!gtk3_libhandle)658return TRUE;659660/* Release painting objects */661if (surface != NULL) {662fp_cairo_destroy(cr);663fp_cairo_surface_destroy(surface);664surface = NULL;665}666667if (gtk3_window != NULL) {668/* Destroying toplevel widget will destroy all contained widgets */669(*fp_gtk_widget_destroy)(gtk3_window);670671/* Unset some static data so they get reinitialized on next load */672gtk3_window = NULL;673}674675dlerror();676dlclose(gtk3_libhandle);677dlclose(gthread_libhandle);678if ((gtk3_error = dlerror()) != NULL)679{680return FALSE;681}682return TRUE;683}684685/* Dispatch all pending events from the GTK event loop.686* This is needed to catch theme change and update widgets' style.687*/688static void flush_gtk_event_loop()689{690while((*fp_g_main_context_iteration)(NULL, FALSE));691}692693/*694* Initialize components of containment hierarchy. This creates a GtkFixed695* inside a GtkWindow. All widgets get realized.696*/697static void init_containers()698{699if (gtk3_window == NULL)700{701gtk3_window = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);702gtk3_fixed = (GtkFixed *)(*fp_gtk_fixed_new)();703(*fp_gtk_container_add)((GtkContainer*)gtk3_window,704(GtkWidget *)gtk3_fixed);705(*fp_gtk_widget_realize)(gtk3_window);706(*fp_gtk_widget_realize)((GtkWidget *)gtk3_fixed);707708GtkSettings* settings = fp_gtk_settings_get_for_screen(709fp_gtk_widget_get_screen(gtk3_window));710gchar* strval = NULL;711fp_g_object_get(settings, "gtk-theme-name", &strval, NULL);712gtk3_css = fp_gtk_css_provider_get_named(strval, NULL);713}714}715716/*717* Ensure everything is ready for drawing an element of the specified width718* and height.719*720* We should somehow handle translucent images. GTK can draw to X Drawables721* only, which don't support alpha. When we retrieve the image back from722* the server, translucency information is lost. There're several ways to723* work around this:724* 1) Subclass GdkPixmap and cache translucent objects on client side. This725* requires us to implement parts of X server drawing logic on client side.726* Many X requests can potentially be "translucent"; e.g. XDrawLine with727* fill=tile and a translucent tile is a "translucent" operation, whereas728* XDrawLine with fill=solid is an "opaque" one. Moreover themes can (and some729* do) intermix transparent and opaque operations which makes caching even730* more problematic.731* 2) Use Xorg 32bit ARGB visual when available. GDK has no native support732* for it (as of version 2.6). Also even in JDS 3 Xorg does not support733* these visuals by default, which makes optimizing for them pointless.734* We can consider doing this at a later point when ARGB visuals become more735* popular.736* 3') GTK has plans to use Cairo as its graphical backend (presumably in737* 2.8), and Cairo supports alpha. With it we could also get rid of the738* unnecessary round trip to server and do all the drawing on client side.739* 4) For now we draw to two different pixmaps and restore alpha channel by740* comparing results. This can be optimized by using subclassed pixmap and741*/742static void gtk3_init_painting(JNIEnv *env, gint width, gint height)743{744init_containers();745746if (cr) {747fp_cairo_destroy(cr);748}749750if (surface != NULL) {751/* free old stuff */752fp_cairo_surface_destroy(surface);753754}755756if (gtk3_version_3_10) {757surface = fp_gdk_window_create_similar_image_surface(758fp_gtk_widget_get_window(gtk3_window),759CAIRO_FORMAT_ARGB32, width, height, 1);760} else {761surface = fp_cairo_image_surface_create(CAIRO_FORMAT_ARGB32,762width, height);763}764765cr = fp_cairo_create(surface);766if (fp_cairo_surface_status(surface) || fp_cairo_status(cr)) {767JNU_ThrowOutOfMemoryError(env, "The surface size is too big");768}769}770771/*772* Restore image from white and black pixmaps and copy it into destination773* buffer. This method compares two pixbufs taken from white and black774* pixmaps and decodes color and alpha components. Pixbufs are RGB without775* alpha, destination buffer is ABGR.776*777* The return value is the transparency type of the resulting image, either778* one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and779* java_awt_Transparency_TRANSLUCENT.780*/781static gint gtk3_copy_image(gint *dst, gint width, gint height)782{783gint i, j, r, g, b;784guchar *data;785gint stride, padding;786787fp_cairo_surface_flush(surface);788data = (*fp_cairo_image_surface_get_data)(surface);789stride = (*fp_cairo_image_surface_get_stride)(surface);790padding = stride - width * 4;791if (stride > 0 && padding >= 0) {792for (i = 0; i < height; i++) {793for (j = 0; j < width; j++) {794int r = *data++;795int g = *data++;796int b = *data++;797int a = *data++;798*dst++ = (a << 24 | b << 16 | g << 8 | r);799}800data += padding;801}802}803return java_awt_Transparency_TRANSLUCENT;804}805806static void gtk3_set_direction(GtkWidget *widget, GtkTextDirection dir)807{808/*809* Some engines (inexplicably) look at the direction of the widget's810* parent, so we need to set the direction of both the widget and its811* parent.812*/813(*fp_gtk_widget_set_direction)(widget, dir);814GtkWidget* parent = fp_gtk_widget_get_parent(widget);815if (parent != NULL) {816fp_gtk_widget_set_direction(parent, dir);817}818}819820static GtkStateFlags get_gtk_state_flags(gint synth_state)821{822GtkStateFlags flags = 0;823824if ((synth_state & DISABLED) != 0) {825flags |= GTK_STATE_FLAG_INSENSITIVE;826}827if (((synth_state & PRESSED) != 0 || (synth_state & SELECTED) != 0)) {828flags |= GTK_STATE_FLAG_ACTIVE;829}830if ((synth_state & MOUSE_OVER) != 0) {831flags |= GTK_STATE_FLAG_PRELIGHT;832}833if ((synth_state & FOCUSED) != 0) {834flags |= GTK_STATE_FLAG_FOCUSED;835}836return flags;837}838839static GtkStateFlags get_gtk_flags(GtkStateType state_type) {840GtkStateFlags flags = 0;841switch (state_type)842{843case GTK_STATE_PRELIGHT:844flags |= GTK_STATE_FLAG_PRELIGHT;845break;846case GTK_STATE_SELECTED:847flags |= GTK_STATE_FLAG_SELECTED;848break;849case GTK_STATE_INSENSITIVE:850flags |= GTK_STATE_FLAG_INSENSITIVE;851break;852case GTK_STATE_ACTIVE:853flags |= GTK_STATE_FLAG_ACTIVE;854break;855case GTK_STATE_FOCUSED:856flags |= GTK_STATE_FLAG_FOCUSED;857break;858default:859break;860}861return flags;862}863864static GtkWidget* gtk3_get_arrow(GtkArrowType arrow_type,865GtkShadowType shadow_type)866{867GtkWidget *arrow = NULL;868if (NULL == gtk3_widgets[_GTK_ARROW_TYPE])869{870gtk3_widgets[_GTK_ARROW_TYPE] = (*fp_gtk_arrow_new)(arrow_type,871shadow_type);872(*fp_gtk_container_add)((GtkContainer *)gtk3_fixed,873gtk3_widgets[_GTK_ARROW_TYPE]);874(*fp_gtk_widget_realize)(gtk3_widgets[_GTK_ARROW_TYPE]);875}876arrow = gtk3_widgets[_GTK_ARROW_TYPE];877878(*fp_gtk_arrow_set)(arrow, arrow_type, shadow_type);879return arrow;880}881882static GtkAdjustment* create_adjustment()883{884return (GtkAdjustment *)885(*fp_gtk_adjustment_new)(50.0, 0.0, 100.0, 10.0, 20.0, 20.0);886}887888/**889* Returns a pointer to the cached native widget for the specified widget890* type.891*/892static GtkWidget *gtk3_get_widget(WidgetType widget_type)893{894gboolean init_result = FALSE;895GtkWidget *result = NULL;896switch (widget_type)897{898case BUTTON:899case TABLE_HEADER:900if (init_result = (NULL == gtk3_widgets[_GTK_BUTTON_TYPE]))901{902gtk3_widgets[_GTK_BUTTON_TYPE] = (*fp_gtk_button_new)();903}904result = gtk3_widgets[_GTK_BUTTON_TYPE];905break;906case CHECK_BOX:907if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_BUTTON_TYPE]))908{909gtk3_widgets[_GTK_CHECK_BUTTON_TYPE] =910(*fp_gtk_check_button_new)();911}912result = gtk3_widgets[_GTK_CHECK_BUTTON_TYPE];913break;914case CHECK_BOX_MENU_ITEM:915if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE]))916{917gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE] =918(*fp_gtk_check_menu_item_new)();919}920result = gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE];921break;922/************************************************************923* Creation a dedicated color chooser is dangerous because924* it deadlocks the EDT925************************************************************/926/* case COLOR_CHOOSER:927if (init_result =928(NULL == gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE]))929{930gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE] =931(*fp_gtk_color_selection_dialog_new)(NULL);932}933result = gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE];934break;*/935case COMBO_BOX:936if (init_result = (NULL == gtk3_widgets[_GTK_COMBO_BOX_TYPE]))937{938gtk3_widgets[_GTK_COMBO_BOX_TYPE] =939(*fp_gtk_combo_box_new)();940}941result = gtk3_widgets[_GTK_COMBO_BOX_TYPE];942break;943case COMBO_BOX_ARROW_BUTTON:944if (init_result =945(NULL == gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE]))946{947gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE] =948(*fp_gtk_toggle_button_new)();949}950result = gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE];951break;952case COMBO_BOX_TEXT_FIELD:953if (init_result =954(NULL == gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE]))955{956result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] =957(*fp_gtk_entry_new)();958}959result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE];960break;961case DESKTOP_ICON:962case INTERNAL_FRAME_TITLE_PANE:963case LABEL:964if (init_result = (NULL == gtk3_widgets[_GTK_LABEL_TYPE]))965{966gtk3_widgets[_GTK_LABEL_TYPE] =967(*fp_gtk_label_new)(NULL);968}969result = gtk3_widgets[_GTK_LABEL_TYPE];970break;971case DESKTOP_PANE:972case PANEL:973case ROOT_PANE:974if (init_result = (NULL == gtk3_widgets[_GTK_CONTAINER_TYPE]))975{976/* There is no constructor for a container type. I've977* chosen GtkFixed container since it has a default978* constructor.979*/980gtk3_widgets[_GTK_CONTAINER_TYPE] =981(*fp_gtk_fixed_new)();982}983result = gtk3_widgets[_GTK_CONTAINER_TYPE];984break;985case EDITOR_PANE:986case TEXT_AREA:987case TEXT_PANE:988if (init_result = (NULL == gtk3_widgets[_GTK_TEXT_VIEW_TYPE]))989{990gtk3_widgets[_GTK_TEXT_VIEW_TYPE] =991(*fp_gtk_text_view_new)();992}993result = gtk3_widgets[_GTK_TEXT_VIEW_TYPE];994break;995case FORMATTED_TEXT_FIELD:996case PASSWORD_FIELD:997case TEXT_FIELD:998if (init_result = (NULL == gtk3_widgets[_GTK_ENTRY_TYPE]))999{1000gtk3_widgets[_GTK_ENTRY_TYPE] =1001(*fp_gtk_entry_new)();1002}1003result = gtk3_widgets[_GTK_ENTRY_TYPE];1004break;1005case HANDLE_BOX:1006if (init_result = (NULL == gtk3_widgets[_GTK_HANDLE_BOX_TYPE]))1007{1008gtk3_widgets[_GTK_HANDLE_BOX_TYPE] =1009(*fp_gtk_handle_box_new)();1010}1011result = gtk3_widgets[_GTK_HANDLE_BOX_TYPE];1012break;1013case HSCROLL_BAR:1014case HSCROLL_BAR_BUTTON_LEFT:1015case HSCROLL_BAR_BUTTON_RIGHT:1016case HSCROLL_BAR_TRACK:1017case HSCROLL_BAR_THUMB:1018if (init_result = (NULL == gtk3_widgets[_GTK_HSCROLLBAR_TYPE]))1019{1020gtk3_widgets[_GTK_HSCROLLBAR_TYPE] =1021(*fp_gtk_hscrollbar_new)(create_adjustment());1022}1023result = gtk3_widgets[_GTK_HSCROLLBAR_TYPE];1024break;1025case HSEPARATOR:1026if (init_result = (NULL == gtk3_widgets[_GTK_HSEPARATOR_TYPE]))1027{1028gtk3_widgets[_GTK_HSEPARATOR_TYPE] =1029(*fp_gtk_hseparator_new)();1030}1031result = gtk3_widgets[_GTK_HSEPARATOR_TYPE];1032break;1033case HSLIDER:1034case HSLIDER_THUMB:1035case HSLIDER_TRACK:1036if (init_result = (NULL == gtk3_widgets[_GTK_HSCALE_TYPE]))1037{1038gtk3_widgets[_GTK_HSCALE_TYPE] =1039(*fp_gtk_scale_new)(GTK_ORIENTATION_HORIZONTAL, NULL);1040}1041result = gtk3_widgets[_GTK_HSCALE_TYPE];1042break;1043case HSPLIT_PANE_DIVIDER:1044case SPLIT_PANE:1045if (init_result = (NULL == gtk3_widgets[_GTK_HPANED_TYPE]))1046{1047gtk3_widgets[_GTK_HPANED_TYPE] = (*fp_gtk_paned_new)(GTK_ORIENTATION_HORIZONTAL);1048}1049result = gtk3_widgets[_GTK_HPANED_TYPE];1050break;1051case IMAGE:1052if (init_result = (NULL == gtk3_widgets[_GTK_IMAGE_TYPE]))1053{1054gtk3_widgets[_GTK_IMAGE_TYPE] = (*fp_gtk_image_new)();1055}1056result = gtk3_widgets[_GTK_IMAGE_TYPE];1057break;1058case INTERNAL_FRAME:1059if (init_result = (NULL == gtk3_widgets[_GTK_WINDOW_TYPE]))1060{1061gtk3_widgets[_GTK_WINDOW_TYPE] =1062(*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);1063}1064result = gtk3_widgets[_GTK_WINDOW_TYPE];1065break;1066case TOOL_TIP:1067if (init_result = (NULL == gtk3_widgets[_GTK_TOOLTIP_TYPE]))1068{1069result = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);1070gtk3_widgets[_GTK_TOOLTIP_TYPE] = result;1071}1072result = gtk3_widgets[_GTK_TOOLTIP_TYPE];1073break;1074case LIST:1075case TABLE:1076case TREE:1077case TREE_CELL:1078if (init_result = (NULL == gtk3_widgets[_GTK_TREE_VIEW_TYPE]))1079{1080gtk3_widgets[_GTK_TREE_VIEW_TYPE] =1081(*fp_gtk_tree_view_new)();1082}1083result = gtk3_widgets[_GTK_TREE_VIEW_TYPE];1084break;1085case TITLED_BORDER:1086if (init_result = (NULL == gtk3_widgets[_GTK_FRAME_TYPE]))1087{1088gtk3_widgets[_GTK_FRAME_TYPE] = fp_gtk_frame_new(NULL);1089}1090result = gtk3_widgets[_GTK_FRAME_TYPE];1091break;1092case POPUP_MENU:1093if (init_result = (NULL == gtk3_widgets[_GTK_MENU_TYPE]))1094{1095gtk3_widgets[_GTK_MENU_TYPE] =1096(*fp_gtk_menu_new)();1097}1098result = gtk3_widgets[_GTK_MENU_TYPE];1099break;1100case MENU:1101case MENU_ITEM:1102case MENU_ITEM_ACCELERATOR:1103if (init_result = (NULL == gtk3_widgets[_GTK_MENU_ITEM_TYPE]))1104{1105gtk3_widgets[_GTK_MENU_ITEM_TYPE] =1106(*fp_gtk_menu_item_new)();1107}1108result = gtk3_widgets[_GTK_MENU_ITEM_TYPE];1109break;1110case MENU_BAR:1111if (init_result = (NULL == gtk3_widgets[_GTK_MENU_BAR_TYPE]))1112{1113gtk3_widgets[_GTK_MENU_BAR_TYPE] =1114(*fp_gtk_menu_bar_new)();1115}1116result = gtk3_widgets[_GTK_MENU_BAR_TYPE];1117break;1118case COLOR_CHOOSER:1119case OPTION_PANE:1120if (init_result = (NULL == gtk3_widgets[_GTK_DIALOG_TYPE]))1121{1122gtk3_widgets[_GTK_DIALOG_TYPE] =1123(*fp_gtk_dialog_new)();1124}1125result = gtk3_widgets[_GTK_DIALOG_TYPE];1126break;1127case POPUP_MENU_SEPARATOR:1128if (init_result =1129(NULL == gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE]))1130{1131gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE] =1132(*fp_gtk_separator_menu_item_new)();1133}1134result = gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE];1135break;1136case HPROGRESS_BAR:1137if (init_result = (NULL == gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE]))1138{1139gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE] =1140(*fp_gtk_progress_bar_new)();1141}1142result = gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE];1143break;1144case VPROGRESS_BAR:1145if (init_result = (NULL == gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE]))1146{1147gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE] =1148(*fp_gtk_progress_bar_new)();1149/*1150* Vertical JProgressBars always go bottom-to-top,1151* regardless of the ComponentOrientation.1152*/1153(*fp_gtk_progress_bar_set_orientation)(1154(GtkProgressBar *)gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE],1155GTK_PROGRESS_BOTTOM_TO_TOP);1156}1157result = gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE];1158break;1159case RADIO_BUTTON:1160if (init_result = (NULL == gtk3_widgets[_GTK_RADIO_BUTTON_TYPE]))1161{1162gtk3_widgets[_GTK_RADIO_BUTTON_TYPE] =1163(*fp_gtk_radio_button_new)(NULL);1164}1165result = gtk3_widgets[_GTK_RADIO_BUTTON_TYPE];1166break;1167case RADIO_BUTTON_MENU_ITEM:1168if (init_result =1169(NULL == gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE]))1170{1171gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE] =1172(*fp_gtk_radio_menu_item_new)(NULL);1173}1174result = gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE];1175break;1176case SCROLL_PANE:1177if (init_result =1178(NULL == gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE]))1179{1180gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE] =1181(*fp_gtk_scrolled_window_new)(NULL, NULL);1182}1183result = gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE];1184break;1185case SPINNER:1186case SPINNER_ARROW_BUTTON:1187case SPINNER_TEXT_FIELD:1188if (init_result = (NULL == gtk3_widgets[_GTK_SPIN_BUTTON_TYPE]))1189{1190result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE] =1191(*fp_gtk_spin_button_new)(NULL, 0, 0);1192}1193result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE];1194break;1195case TABBED_PANE:1196case TABBED_PANE_TAB_AREA:1197case TABBED_PANE_CONTENT:1198case TABBED_PANE_TAB:1199if (init_result = (NULL == gtk3_widgets[_GTK_NOTEBOOK_TYPE]))1200{1201gtk3_widgets[_GTK_NOTEBOOK_TYPE] =1202(*fp_gtk_notebook_new)(NULL);1203}1204result = gtk3_widgets[_GTK_NOTEBOOK_TYPE];1205break;1206case TOGGLE_BUTTON:1207if (init_result = (NULL == gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE]))1208{1209gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE] =1210(*fp_gtk_toggle_button_new)(NULL);1211}1212result = gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE];1213break;1214case TOOL_BAR:1215case TOOL_BAR_DRAG_WINDOW:1216if (init_result = (NULL == gtk3_widgets[_GTK_TOOLBAR_TYPE]))1217{1218gtk3_widgets[_GTK_TOOLBAR_TYPE] =1219(*fp_gtk_toolbar_new)(NULL);1220}1221result = gtk3_widgets[_GTK_TOOLBAR_TYPE];1222break;1223case TOOL_BAR_SEPARATOR:1224if (init_result =1225(NULL == gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE]))1226{1227gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE] =1228(*fp_gtk_separator_tool_item_new)();1229}1230result = gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE];1231break;1232case VIEWPORT:1233if (init_result = (NULL == gtk3_widgets[_GTK_VIEWPORT_TYPE]))1234{1235GtkAdjustment *adjustment = create_adjustment();1236gtk3_widgets[_GTK_VIEWPORT_TYPE] =1237(*fp_gtk_viewport_new)(adjustment, adjustment);1238}1239result = gtk3_widgets[_GTK_VIEWPORT_TYPE];1240break;1241case VSCROLL_BAR:1242case VSCROLL_BAR_BUTTON_UP:1243case VSCROLL_BAR_BUTTON_DOWN:1244case VSCROLL_BAR_TRACK:1245case VSCROLL_BAR_THUMB:1246if (init_result = (NULL == gtk3_widgets[_GTK_VSCROLLBAR_TYPE]))1247{1248gtk3_widgets[_GTK_VSCROLLBAR_TYPE] =1249(*fp_gtk_vscrollbar_new)(create_adjustment());1250}1251result = gtk3_widgets[_GTK_VSCROLLBAR_TYPE];1252break;1253case VSEPARATOR:1254if (init_result = (NULL == gtk3_widgets[_GTK_VSEPARATOR_TYPE]))1255{1256gtk3_widgets[_GTK_VSEPARATOR_TYPE] =1257(*fp_gtk_vseparator_new)();1258}1259result = gtk3_widgets[_GTK_VSEPARATOR_TYPE];1260break;1261case VSLIDER:1262case VSLIDER_THUMB:1263case VSLIDER_TRACK:1264if (init_result = (NULL == gtk3_widgets[_GTK_VSCALE_TYPE]))1265{1266gtk3_widgets[_GTK_VSCALE_TYPE] =1267(*fp_gtk_scale_new)(GTK_ORIENTATION_VERTICAL, NULL);1268}1269result = gtk3_widgets[_GTK_VSCALE_TYPE];1270/*1271* Vertical JSliders start at the bottom, while vertical1272* GtkVScale widgets start at the top (by default), so to fix1273* this we set the "inverted" flag to get the Swing behavior.1274*/1275fp_gtk_range_set_inverted((GtkRange*)result, TRUE);1276break;1277case VSPLIT_PANE_DIVIDER:1278if (init_result = (NULL == gtk3_widgets[_GTK_VPANED_TYPE]))1279{1280gtk3_widgets[_GTK_VPANED_TYPE] = (*fp_gtk_paned_new)(GTK_ORIENTATION_VERTICAL);1281}1282result = gtk3_widgets[_GTK_VPANED_TYPE];1283break;1284default:1285result = NULL;1286break;1287}12881289if (result != NULL && init_result)1290{1291if (widget_type == RADIO_BUTTON_MENU_ITEM ||1292widget_type == CHECK_BOX_MENU_ITEM ||1293widget_type == MENU_ITEM ||1294widget_type == MENU ||1295widget_type == POPUP_MENU_SEPARATOR)1296{1297GtkWidget *menu = gtk3_get_widget(POPUP_MENU);1298(*fp_gtk_menu_shell_append)((GtkMenuShell *)menu, result);1299}1300else if (widget_type == POPUP_MENU)1301{1302GtkWidget *menu_bar = gtk3_get_widget(MENU_BAR);1303GtkWidget *root_menu = (*fp_gtk_menu_item_new)();1304(*fp_gtk_menu_item_set_submenu)((GtkMenuItem*)root_menu, result);1305(*fp_gtk_menu_shell_append)((GtkMenuShell *)menu_bar, root_menu);1306}1307else if (widget_type == COMBO_BOX_TEXT_FIELD )1308{1309GtkWidget* combo = gtk3_get_widget(COMBO_BOX);13101311/*1312* We add a regular GtkButton/GtkEntry to a GtkComboBoxEntry1313* in order to trick engines into thinking it's a real combobox1314* arrow button/text field.1315*/13161317fp_gtk_container_add ((GtkContainer*)(combo), result);1318GtkStyleContext* context = fp_gtk_widget_get_style_context (combo);1319fp_gtk_style_context_add_class (context, "combobox-entry");1320context = fp_gtk_widget_get_style_context (result);1321fp_gtk_style_context_add_class (context, "combobox");1322fp_gtk_style_context_add_class (context, "entry");1323}1324else if (widget_type == COMBO_BOX_ARROW_BUTTON )1325{1326GtkWidget* combo = gtk3_get_widget(COMBO_BOX);1327fp_gtk_widget_set_parent(result, combo);1328}1329else if (widget_type != TOOL_TIP &&1330widget_type != INTERNAL_FRAME &&1331widget_type != OPTION_PANE)1332{1333(*fp_gtk_container_add)((GtkContainer *)gtk3_fixed, result);1334}1335(*fp_gtk_widget_realize)(result);1336}1337return result;1338}13391340static void append_element (GtkWidgetPath *path, const gchar *selector)1341{1342fp_gtk_widget_path_append_type (path, G_TYPE_NONE);1343fp_gtk_widget_path_iter_set_object_name (path, -1, selector);1344}13451346static GtkWidgetPath* createWidgetPath(const GtkWidgetPath* path) {1347if (path == NULL) {1348return fp_gtk_widget_path_new();1349} else {1350return fp_gtk_widget_path_copy(path);1351}1352}13531354static GtkStyleContext* get_style(WidgetType widget_type, const gchar *detail)1355{1356if (!gtk3_version_3_20) {1357gtk3_widget = gtk3_get_widget(widget_type);1358GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1359fp_gtk_style_context_save (context);1360if (detail != 0) {1361transform_detail_string(detail, context);1362}1363return context;1364} else {1365gtk3_widget = gtk3_get_widget(widget_type);1366GtkStyleContext* widget_context = fp_gtk_widget_get_style_context (gtk3_widget);1367GtkWidgetPath *path = NULL;1368if (detail != 0) {1369if (strcmp(detail, "checkbutton") == 0) {1370path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1371append_element(path, "check");1372} else if (strcmp(detail, "radiobutton") == 0) {1373path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1374append_element(path, "radio");1375} else if (strcmp(detail, "vscale") == 0 || strcmp(detail, "hscale") == 0) {1376path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1377append_element(path, "slider");1378} else if (strcmp(detail, "trough") == 0) {1379//This is a fast solution to the scrollbar trough not being rendered properly1380if (widget_type == HSCROLL_BAR || widget_type == HSCROLL_BAR_TRACK ||1381widget_type == VSCROLL_BAR || widget_type == VSCROLL_BAR_TRACK) {1382path = createWidgetPath (NULL);1383} else {1384path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1385}1386append_element(path, detail);1387} else if (strcmp(detail, "bar") == 0) {1388path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1389append_element(path, "trough");1390append_element(path, "progress");1391} else if (strcmp(detail, "vscrollbar") == 0 || strcmp(detail, "hscrollbar") == 0) {1392path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1393append_element(path, "button");1394} else if (strcmp(detail, "check") == 0) {1395path = createWidgetPath (NULL);1396append_element(path, detail);1397} else if (strcmp(detail, "option") == 0) {1398path = createWidgetPath (NULL);1399append_element(path, "radio");1400} else if (strcmp(detail, "paned") == 0) {1401path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1402append_element(path, "paned");1403append_element(path, "separator");1404} else if (strcmp(detail, "spinbutton_down") == 0 || strcmp(detail, "spinbutton_up") == 0) {1405path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1406append_element(path, "spinbutton");1407append_element(path, "button");1408} else {1409path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1410append_element(path, detail);1411}1412} else {1413path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1414}14151416GtkStyleContext *context = fp_gtk_style_context_new ();1417fp_gtk_style_context_set_path (context, path);1418fp_gtk_widget_path_unref (path);1419return context;1420}1421}14221423static void disposeOrRestoreContext(GtkStyleContext *context)1424{1425if (!gtk3_version_3_20) {1426fp_gtk_style_context_restore (context);1427} else {1428fp_g_object_unref (context);1429}1430}14311432static void gtk3_paint_arrow(WidgetType widget_type, GtkStateType state_type,1433GtkShadowType shadow_type, const gchar *detail,1434gint x, gint y, gint width, gint height,1435GtkArrowType arrow_type, gboolean fill)1436{1437gdouble xx, yy, a = G_PI;1438int s = width;1439gtk3_widget = gtk3_get_arrow(arrow_type, shadow_type);14401441switch (widget_type)1442{1443case SPINNER_ARROW_BUTTON:1444s = (int)(0.4 * width + 0.5) + 1;1445if (arrow_type == GTK_ARROW_UP) {1446a = 0;1447} else if (arrow_type == GTK_ARROW_DOWN) {1448a = G_PI;1449}1450break;14511452case HSCROLL_BAR_BUTTON_LEFT:1453s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1;1454a = 3 * G_PI / 2;1455break;14561457case HSCROLL_BAR_BUTTON_RIGHT:1458s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1;1459a = G_PI / 2;1460break;14611462case VSCROLL_BAR_BUTTON_UP:1463s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1;1464a = 0;1465break;14661467case VSCROLL_BAR_BUTTON_DOWN:1468s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1;1469a = G_PI;1470break;14711472case COMBO_BOX_ARROW_BUTTON:1473s = (int)(0.3 * height + 0.5) + 1;1474a = G_PI;1475break;14761477case TABLE:1478s = (int)(0.8 * height + 0.5) + 1;1479if (arrow_type == GTK_ARROW_UP) {1480a = G_PI;1481} else if (arrow_type == GTK_ARROW_DOWN) {1482a = 0;1483}1484break;14851486case MENU_ITEM:1487if (arrow_type == GTK_ARROW_UP) {1488a = G_PI;1489} else if (arrow_type == GTK_ARROW_DOWN) {1490a = 0;1491} else if (arrow_type == GTK_ARROW_RIGHT) {1492a = G_PI / 2;1493} else if (arrow_type == GTK_ARROW_LEFT) {1494a = 3 * G_PI / 2;1495}1496break;14971498default:1499if (arrow_type == GTK_ARROW_UP) {1500a = G_PI;1501} else if (arrow_type == GTK_ARROW_DOWN) {1502a = 0;1503} else if (arrow_type == GTK_ARROW_RIGHT) {1504a = G_PI / 2;1505} else if (arrow_type == GTK_ARROW_LEFT) {1506a = 3 * G_PI / 2;1507}1508break;1509}15101511if (s < width && s < height) {1512xx = x + (0.5 * (width - s) + 0.5);1513yy = y + (0.5 * (height - s) + 0.5);1514} else {1515xx = x;1516yy = y;1517}15181519GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1520fp_gtk_style_context_save (context);152115221523if (detail != NULL) {1524transform_detail_string(detail, context);1525}15261527GtkStateFlags flags = get_gtk_flags(state_type);15281529fp_gtk_style_context_set_state (context, flags);15301531(*fp_gtk_render_arrow)(context, cr, a, xx, yy, s);15321533fp_gtk_style_context_restore (context);1534}15351536static void gtk3_paint_box(WidgetType widget_type, GtkStateType state_type,1537GtkShadowType shadow_type, const gchar *detail,1538gint x, gint y, gint width, gint height,1539gint synth_state, GtkTextDirection dir)1540{1541gtk3_widget = gtk3_get_widget(widget_type);15421543if (widget_type == HSLIDER_TRACK) {1544/*1545* For horizontal JSliders with right-to-left orientation, we need1546* to set the "inverted" flag to match the native GTK behavior where1547* the foreground highlight is on the right side of the slider thumb.1548* This is needed especially for the ubuntulooks engine, which looks1549* exclusively at the "inverted" flag to determine on which side of1550* the thumb to paint the highlight...1551*/1552fp_gtk_range_set_inverted((GtkRange*)gtk3_widget, dir ==1553GTK_TEXT_DIR_RTL);15541555/*1556* Note however that other engines like clearlooks will look at both1557* the "inverted" field and the text direction to determine how1558* the foreground highlight is painted:1559* !inverted && ltr --> paint highlight on left side1560* !inverted && rtl --> paint highlight on right side1561* inverted && ltr --> paint highlight on right side1562* inverted && rtl --> paint highlight on left side1563* So the only way to reliably get the desired results for horizontal1564* JSlider (i.e., highlight on left side for LTR ComponentOrientation1565* and highlight on right side for RTL ComponentOrientation) is to1566* always override text direction as LTR, and then set the "inverted"1567* flag accordingly (as we have done above).1568*/1569dir = GTK_TEXT_DIR_LTR;1570}15711572/*1573* Some engines (e.g. clearlooks) will paint the shadow of certain1574* widgets (e.g. COMBO_BOX_ARROW_BUTTON) differently depending on the1575* the text direction.1576*/1577gtk3_set_direction(gtk3_widget, dir);15781579GtkStyleContext* context = get_style(widget_type, detail);15801581GtkStateFlags flags = get_gtk_flags(state_type);1582if (shadow_type == GTK_SHADOW_IN && widget_type != COMBO_BOX_ARROW_BUTTON) {1583flags |= GTK_STATE_FLAG_ACTIVE;1584}15851586if (synth_state & MOUSE_OVER) {1587flags |= GTK_STATE_FLAG_PRELIGHT;1588}15891590if (synth_state & FOCUSED) {1591flags |= GTK_STATE_FLAG_FOCUSED;1592}15931594if (synth_state & DEFAULT) {1595fp_gtk_style_context_add_class (context, "default");1596}15971598if (fp_gtk_style_context_has_class(context, "trough")) {1599flags |= GTK_STATE_FLAG_BACKDROP;1600}16011602fp_gtk_style_context_set_state (context, flags);16031604fp_gtk_render_background (context, cr, x, y, width, height);1605if (shadow_type != GTK_SHADOW_NONE) {1606fp_gtk_render_frame(context, cr, x, y, width, height);1607}16081609disposeOrRestoreContext(context);16101611/*1612* Reset the text direction to the default value so that we don't1613* accidentally affect other operations and widgets.1614*/1615gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR);16161617//This is a fast solution to the scrollbar trough not being rendered properly1618if ((widget_type == HSCROLL_BAR || widget_type == HSCROLL_BAR_TRACK ||1619widget_type == VSCROLL_BAR || widget_type == VSCROLL_BAR_TRACK) && detail != 0) {1620gtk3_paint_box(widget_type, state_type, shadow_type, NULL,1621x, y, width, height, synth_state, dir);1622}1623}16241625static void gtk3_paint_box_gap(WidgetType widget_type, GtkStateType state_type,1626GtkShadowType shadow_type, const gchar *detail,1627gint x, gint y, gint width, gint height,1628GtkPositionType gap_side, gint gap_x, gint gap_width)1629{1630gtk3_widget = gtk3_get_widget(widget_type);16311632GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);16331634fp_gtk_style_context_save (context);16351636GtkStateFlags flags = get_gtk_flags(state_type);1637fp_gtk_style_context_set_state(context, flags);16381639if (detail != 0) {1640transform_detail_string(detail, context);1641}1642fp_gtk_render_background(context, cr, x, y, width, height);16431644if (shadow_type != GTK_SHADOW_NONE) {1645fp_gtk_render_frame_gap(context, cr, x, y, width, height, gap_side,1646(gdouble)gap_x, (gdouble)gap_x + gap_width);1647}1648fp_gtk_style_context_restore (context);1649}16501651static void gtk3_paint_check(WidgetType widget_type, gint synth_state,1652const gchar *detail, gint x, gint y, gint width, gint height)1653{1654GtkStyleContext* context = get_style(widget_type, detail);16551656GtkStateFlags flags = get_gtk_state_flags(synth_state);1657if (gtk3_version_3_14 && (synth_state & SELECTED)) {1658flags &= ~GTK_STATE_FLAG_SELECTED;1659flags |= GTK_STATE_FLAG_CHECKED;1660}1661fp_gtk_style_context_set_state(context, flags);16621663fp_gtk_render_background(context, cr, x, y, width, height);1664fp_gtk_render_frame(context, cr, x, y, width, height);1665fp_gtk_render_check(context, cr, x, y, width, height);1666disposeOrRestoreContext(context);1667}166816691670static void gtk3_paint_expander(WidgetType widget_type, GtkStateType state_type,1671const gchar *detail, gint x, gint y, gint width, gint height,1672GtkExpanderStyle expander_style)1673{1674gtk3_widget = gtk3_get_widget(widget_type);16751676GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);16771678fp_gtk_style_context_save (context);16791680GtkStateFlags flags = get_gtk_flags(state_type);1681if (expander_style == GTK_EXPANDER_EXPANDED) {1682if (gtk3_version_3_14) {1683flags |= GTK_STATE_FLAG_CHECKED;1684} else {1685flags |= GTK_STATE_FLAG_ACTIVE;1686}1687}16881689fp_gtk_style_context_set_state(context, flags);16901691if (detail != 0) {1692transform_detail_string(detail, context);1693}16941695fp_gtk_render_expander (context, cr, x + 2, y + 2, width - 4, height - 4);16961697fp_gtk_style_context_restore (context);1698}16991700static void gtk3_paint_extension(WidgetType widget_type, GtkStateType state_type,1701GtkShadowType shadow_type, const gchar *detail,1702gint x, gint y, gint width, gint height, GtkPositionType gap_side)1703{1704gtk3_widget = gtk3_get_widget(widget_type);17051706GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);17071708fp_gtk_style_context_save (context);17091710GtkStateFlags flags = GTK_STATE_FLAG_NORMAL;17111712if (state_type == 0) {1713flags = GTK_STATE_FLAG_ACTIVE;1714}17151716fp_gtk_style_context_set_state(context, flags);17171718if (detail != 0) {1719transform_detail_string(detail, context);1720}1721switch(gap_side) {1722case GTK_POS_LEFT:1723fp_gtk_style_context_add_class(context, "right");1724break;1725case GTK_POS_RIGHT:1726fp_gtk_style_context_add_class(context, "left");1727break;1728case GTK_POS_TOP:1729fp_gtk_style_context_add_class(context, "bottom");1730break;1731case GTK_POS_BOTTOM:1732fp_gtk_style_context_add_class(context, "top");1733break;1734default:1735break;1736}17371738fp_gtk_render_extension(context, cr, x, y, width, height, gap_side);17391740fp_gtk_style_context_restore (context);1741}17421743static void gtk3_paint_flat_box(WidgetType widget_type, GtkStateType state_type,1744GtkShadowType shadow_type, const gchar *detail,1745gint x, gint y, gint width, gint height, gboolean has_focus)1746{1747if (state_type == GTK_STATE_PRELIGHT &&1748(widget_type == CHECK_BOX || widget_type == RADIO_BUTTON)) {1749return;1750}17511752GtkStyleContext* context = NULL;1753if (widget_type == TOOL_TIP) {1754context = get_style(widget_type, detail);1755fp_gtk_style_context_add_class(context, "background");1756} else {1757gtk3_widget = gtk3_get_widget(widget_type);1758context = fp_gtk_widget_get_style_context (gtk3_widget);1759fp_gtk_style_context_save (context);1760if (detail != 0) {1761transform_detail_string(detail, context);1762}1763}17641765GtkStateFlags flags = get_gtk_flags(state_type);17661767if (has_focus) {1768flags |= GTK_STATE_FLAG_FOCUSED;1769}17701771fp_gtk_style_context_set_state (context, flags);17721773if (widget_type == COMBO_BOX_TEXT_FIELD) {1774width += height /2;1775}17761777fp_gtk_render_background (context, cr, x, y, width, height);1778if (widget_type == TOOL_TIP) {1779disposeOrRestoreContext(context);1780} else {1781fp_gtk_style_context_restore (context);1782}1783}17841785static void gtk3_paint_focus(WidgetType widget_type, GtkStateType state_type,1786const char *detail, gint x, gint y, gint width, gint height)1787{1788gtk3_widget = gtk3_get_widget(widget_type);17891790GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1791fp_gtk_style_context_save (context);17921793transform_detail_string(detail, context);1794fp_gtk_render_focus (context, cr, x, y, width, height);17951796fp_gtk_style_context_restore (context);17971798}17991800static void gtk3_paint_handle(WidgetType widget_type, GtkStateType state_type,1801GtkShadowType shadow_type, const gchar *detail,1802gint x, gint y, gint width, gint height, GtkOrientation orientation)1803{1804gtk3_widget = gtk3_get_widget(widget_type);18051806GtkStyleContext* context = get_style(widget_type, detail);18071808GtkStateFlags flags = get_gtk_flags(state_type);1809fp_gtk_style_context_set_state(context, GTK_STATE_FLAG_PRELIGHT);18101811if (detail != 0 && !(strcmp(detail, "paned") == 0)) {1812transform_detail_string(detail, context);1813fp_gtk_style_context_add_class (context, "handlebox_bin");1814}18151816if (!(strcmp(detail, "paned") == 0)) {1817fp_gtk_render_handle(context, cr, x, y, width, height);1818fp_gtk_render_background(context, cr, x, y, width, height);1819} else {1820if (orientation == GTK_ORIENTATION_VERTICAL) {1821fp_gtk_render_handle(context, cr, x+width/2, y, 2, height);1822fp_gtk_render_background(context, cr, x+width/2, y, 2, height);1823} else {1824fp_gtk_render_handle(context, cr, x, y+height/2, width, 2);1825fp_gtk_render_background(context, cr, x, y+height/2, width, 2);1826}1827}18281829disposeOrRestoreContext(context);1830}18311832static void gtk3_paint_hline(WidgetType widget_type, GtkStateType state_type,1833const gchar *detail, gint x, gint y, gint width, gint height)1834{1835gtk3_widget = gtk3_get_widget(widget_type);18361837GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);18381839fp_gtk_style_context_save (context);18401841if (detail != 0) {1842transform_detail_string(detail, context);1843}18441845fp_gtk_render_line(context, cr, x, y, x + width, y);18461847fp_gtk_style_context_restore (context);1848}18491850static void gtk3_paint_vline(WidgetType widget_type, GtkStateType state_type,1851const gchar *detail, gint x, gint y, gint width, gint height)1852{1853gtk3_widget = gtk3_get_widget(widget_type);185418551856GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);18571858fp_gtk_style_context_save (context);18591860if (detail != 0) {1861transform_detail_string(detail, context);1862}18631864fp_gtk_render_line(context, cr, x, y, x, y + height);18651866fp_gtk_style_context_restore (context);1867}18681869static void gtk3_paint_option(WidgetType widget_type, gint synth_state,1870const gchar *detail, gint x, gint y, gint width, gint height)1871{1872GtkStyleContext* context = get_style(widget_type, detail);18731874GtkStateFlags flags = get_gtk_state_flags(synth_state);1875if (gtk3_version_3_14 && (synth_state & SELECTED)) {1876flags &= ~GTK_STATE_FLAG_SELECTED;1877flags |= GTK_STATE_FLAG_CHECKED;1878}1879fp_gtk_style_context_set_state(context, flags);18801881fp_gtk_render_background(context, cr, x, y, width, height);1882fp_gtk_render_frame(context, cr, x, y, width, height);1883fp_gtk_render_option(context, cr, x, y, width, height);1884disposeOrRestoreContext(context);1885}18861887static void gtk3_paint_shadow(WidgetType widget_type, GtkStateType state_type,1888GtkShadowType shadow_type, const gchar *detail,1889gint x, gint y, gint width, gint height,1890gint synth_state, GtkTextDirection dir)1891{1892if (shadow_type == GTK_SHADOW_NONE) {1893return;1894}1895gtk3_widget = gtk3_get_widget(widget_type);18961897/*1898* Some engines (e.g. clearlooks) will paint the shadow of certain1899* widgets (e.g. COMBO_BOX_TEXT_FIELD) differently depending on the1900* the text direction.1901*/1902gtk3_set_direction(gtk3_widget, dir);190319041905GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1906fp_gtk_style_context_save (context);19071908if (detail) {1909transform_detail_string(detail, context);1910}19111912GtkStateFlags flags = get_gtk_flags(state_type);19131914if (synth_state & MOUSE_OVER) {1915flags |= GTK_STATE_FLAG_PRELIGHT;1916}19171918if (synth_state & FOCUSED) {1919flags |= GTK_STATE_FLAG_FOCUSED;1920}19211922fp_gtk_style_context_set_state (context, flags);19231924if (widget_type == COMBO_BOX_TEXT_FIELD) {1925width += height / 2;1926}1927fp_gtk_render_frame(context, cr, x, y, width, height);19281929fp_gtk_style_context_restore (context);19301931/*1932* Reset the text direction to the default value so that we don't1933* accidentally affect other operations and widgets.1934*/1935gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR);1936}19371938static void gtk3_paint_slider(WidgetType widget_type, GtkStateType state_type,1939GtkShadowType shadow_type, const gchar *detail,1940gint x, gint y, gint width, gint height, GtkOrientation orientation,1941gboolean has_focus)1942{1943GtkStyleContext *context = get_style(widget_type, detail);19441945GtkStateFlags flags = get_gtk_flags(state_type);19461947if (state_type == GTK_STATE_ACTIVE) {1948flags |= GTK_STATE_FLAG_PRELIGHT;1949}19501951if (has_focus) {1952flags |= GTK_STATE_FLAG_FOCUSED;1953}19541955fp_gtk_style_context_set_state (context, flags);19561957fp_gtk_render_background (context, cr, x, y, width, height);1958fp_gtk_render_frame(context, cr, x, y, width, height);1959(*fp_gtk_render_slider)(context, cr, x, y, width, height, orientation);1960disposeOrRestoreContext(context);1961}19621963static void gtk3_paint_background(WidgetType widget_type,1964GtkStateType state_type, gint x, gint y, gint width, gint height) {1965gtk3_widget = gtk3_get_widget(widget_type);19661967GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1968fp_gtk_style_context_save (context);19691970GtkStateFlags flags = get_gtk_flags(state_type);19711972fp_gtk_style_context_set_state (context, flags);19731974fp_gtk_render_background (context, cr, x, y, width, height);19751976fp_gtk_style_context_restore (context);1977}19781979static GdkPixbuf *gtk3_get_stock_icon(gint widget_type, const gchar *stock_id,1980GtkIconSize size, GtkTextDirection direction, const char *detail)1981{1982int sz;19831984switch(size) {1985case GTK_ICON_SIZE_MENU:1986sz = 16;1987break;1988case GTK_ICON_SIZE_SMALL_TOOLBAR:1989sz = 18;1990break;1991case GTK_ICON_SIZE_LARGE_TOOLBAR:1992sz = 24;1993break;1994case GTK_ICON_SIZE_BUTTON:1995sz = 20;1996break;1997case GTK_ICON_SIZE_DND:1998sz = 32;1999break;2000case GTK_ICON_SIZE_DIALOG:2001sz = 48;2002break;2003default:2004sz = 0;2005break;2006}20072008init_containers();2009gtk3_widget = gtk3_get_widget((widget_type < 0) ? IMAGE : widget_type);2010(*fp_gtk_widget_set_direction)(gtk3_widget, direction);2011GtkIconTheme *icon_theme = fp_gtk_icon_theme_get_default();2012GdkPixbuf *result = fp_gtk_icon_theme_load_icon(icon_theme, stock_id, sz,2013GTK_ICON_LOOKUP_USE_BUILTIN, NULL);2014return result;2015}20162017static jboolean gtk3_get_pixbuf_data(JNIEnv *env, GdkPixbuf* pixbuf,2018jmethodID icon_upcall_method, jobject this) {2019if (!pixbuf) {2020return JNI_FALSE;2021}2022guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf);2023if (pixbuf_data) {2024int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf);2025int width = (*fp_gdk_pixbuf_get_width)(pixbuf);2026int height = (*fp_gdk_pixbuf_get_height)(pixbuf);2027int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf);2028int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);2029gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf);20302031jbyteArray data = (*env)->NewByteArray(env, (row_stride * height));2032JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);20332034(*env)->SetByteArrayRegion(env, data, 0, (row_stride * height),2035(jbyte *)pixbuf_data);2036(*fp_g_object_unref)(pixbuf);20372038/* Call the callback method to create the image on the Java side. */2039(*env)->CallVoidMethod(env, this, icon_upcall_method, data,2040width, height, row_stride, bps, channels, alpha);2041return JNI_TRUE;2042}2043return JNI_FALSE;2044}20452046static jboolean gtk3_get_file_icon_data(JNIEnv *env, const char *filename,2047GError **error, jmethodID icon_upcall_method, jobject this) {2048GdkPixbuf* pixbuf = fp_gdk_pixbuf_new_from_file(filename, error);2049return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this);2050}20512052static jboolean gtk3_get_icon_data(JNIEnv *env, gint widget_type,2053const gchar *stock_id, GtkIconSize size,2054GtkTextDirection direction, const char *detail,2055jmethodID icon_upcall_method, jobject this) {2056GdkPixbuf* pixbuf = gtk3_get_stock_icon(widget_type, stock_id, size,2057direction, detail);2058return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this);2059}20602061/*************************************************/2062static gint gtk3_get_xthickness(JNIEnv *env, WidgetType widget_type)2063{2064init_containers();20652066gtk3_widget = gtk3_get_widget(widget_type);2067GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);2068if (context) {2069GtkBorder padding;2070fp_gtk_style_context_get_padding(context, 0, &padding);2071return padding.left + 1;2072}2073return 0;2074}20752076static gint gtk3_get_ythickness(JNIEnv *env, WidgetType widget_type)2077{2078init_containers();20792080gtk3_widget = gtk3_get_widget(widget_type);2081GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);2082if (context) {2083GtkBorder padding;2084fp_gtk_style_context_get_padding(context, 0, &padding);2085return padding.top + 1;2086}2087return 0;2088}20892090/*************************************************/2091static guint8 recode_color(gdouble channel)2092{2093guint16 result = (guint16)(channel * 65535);2094if (result > 65535) {2095result = 65535;2096}2097return (guint8)( result >> 8);2098}20992100static GtkStateFlags gtk3_get_state_flags(GtkStateType state_type) {2101switch (state_type)2102{2103case GTK_STATE_NORMAL:2104return GTK_STATE_FLAG_NORMAL;2105case GTK_STATE_ACTIVE:2106return GTK_STATE_FLAG_ACTIVE;2107case GTK_STATE_PRELIGHT:2108return GTK_STATE_FLAG_PRELIGHT;2109case GTK_STATE_SELECTED:2110return GTK_STATE_FLAG_SELECTED;2111case GTK_STATE_INSENSITIVE:2112return GTK_STATE_FLAG_INSENSITIVE;2113case GTK_STATE_INCONSISTENT:2114return GTK_STATE_FLAG_INCONSISTENT;2115case GTK_STATE_FOCUSED:2116return GTK_STATE_FLAG_FOCUSED;2117}2118return 0;2119}212021212122static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b) {2123gdouble min;2124gdouble max;2125gdouble red;2126gdouble green;2127gdouble blue;2128gdouble h, l, s;2129gdouble delta;21302131red = *r;2132green = *g;2133blue = *b;21342135if (red > green)2136{2137if (red > blue)2138max = red;2139else2140max = blue;21412142if (green < blue)2143min = green;2144else2145min = blue;2146}2147else2148{2149if (green > blue)2150max = green;2151else2152max = blue;21532154if (red < blue)2155min = red;2156else2157min = blue;2158}21592160l = (max + min) / 2;2161s = 0;2162h = 0;21632164if (max != min)2165{2166if (l <= 0.5)2167s = (max - min) / (max + min);2168else2169s = (max - min) / (2 - max - min);21702171delta = max -min;2172if (red == max)2173h = (green - blue) / delta;2174else if (green == max)2175h = 2 + (blue - red) / delta;2176else if (blue == max)2177h = 4 + (red - green) / delta;21782179h *= 60;2180if (h < 0.0)2181h += 360;2182}21832184*r = h;2185*g = l;2186*b = s;2187}21882189static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s)2190{2191gdouble hue;2192gdouble lightness;2193gdouble saturation;2194gdouble m1, m2;2195gdouble r, g, b;21962197lightness = *l;2198saturation = *s;21992200if (lightness <= 0.5)2201m2 = lightness * (1 + saturation);2202else2203m2 = lightness + saturation - lightness * saturation;2204m1 = 2 * lightness - m2;22052206if (saturation == 0)2207{2208*h = lightness;2209*l = lightness;2210*s = lightness;2211}2212else2213{2214hue = *h + 120;2215while (hue > 360)2216hue -= 360;2217while (hue < 0)2218hue += 360;22192220if (hue < 60)2221r = m1 + (m2 - m1) * hue / 60;2222else if (hue < 180)2223r = m2;2224else if (hue < 240)2225r = m1 + (m2 - m1) * (240 - hue) / 60;2226else2227r = m1;22282229hue = *h;2230while (hue > 360)2231hue -= 360;2232while (hue < 0)2233hue += 360;22342235if (hue < 60)2236g = m1 + (m2 - m1) * hue / 60;2237else if (hue < 180)2238g = m2;2239else if (hue < 240)2240g = m1 + (m2 - m1) * (240 - hue) / 60;2241else2242g = m1;22432244hue = *h - 120;2245while (hue > 360)2246hue -= 360;2247while (hue < 0)2248hue += 360;22492250if (hue < 60)2251b = m1 + (m2 - m1) * hue / 60;2252else if (hue < 180)2253b = m2;2254else if (hue < 240)2255b = m1 + (m2 - m1) * (240 - hue) / 60;2256else2257b = m1;22582259*h = r;2260*l = g;2261*s = b;2262}2263}2264226522662267static void gtk3_style_shade (const GdkRGBA *a, GdkRGBA *b, gdouble k) {2268gdouble red = a->red;2269gdouble green = a->green;2270gdouble blue = a->blue;22712272rgb_to_hls (&red, &green, &blue);22732274green *= k;2275if (green > 1.0)2276green = 1.0;2277else if (green < 0.0)2278green = 0.0;22792280blue *= k;2281if (blue > 1.0)2282blue = 1.0;2283else if (blue < 0.0)2284blue = 0.0;22852286hls_to_rgb (&red, &green, &blue);22872288b->red = red;2289b->green = green;2290b->blue = blue;2291}22922293static GdkRGBA gtk3_get_color_for_flags(GtkStyleContext* context,2294GtkStateFlags flags, ColorType color_type) {2295GdkRGBA c, color;2296color.alpha = 1;22972298switch (color_type)2299{2300case FOREGROUND:2301case TEXT_FOREGROUND:2302fp_gtk_style_context_get_color(context, flags, &color);2303break;2304case BACKGROUND:2305case TEXT_BACKGROUND:2306fp_gtk_style_context_get_background_color(context, flags, &color);2307break;2308case LIGHT:2309c = gtk3_get_color_for_flags(context, flags, BACKGROUND);2310gtk3_style_shade(&c, &color, LIGHTNESS_MULT);2311break;2312case DARK:2313c = gtk3_get_color_for_flags(context, flags, BACKGROUND);2314gtk3_style_shade (&c, &color, DARKNESS_MULT);2315break;2316case MID:2317{2318GdkRGBA c1 = gtk3_get_color_for_flags(context, flags, LIGHT);2319GdkRGBA c2 = gtk3_get_color_for_flags(context, flags, DARK);2320color.red = (c1.red + c2.red) / 2;2321color.green = (c1.green + c2.green) / 2;2322color.blue = (c1.blue + c2.blue) / 2;2323}2324break;2325case FOCUS:2326case BLACK:2327color.red = 0;2328color.green = 0;2329color.blue = 0;2330break;2331case WHITE:2332color.red = 1;2333color.green = 1;2334color.blue = 1;2335break;2336}2337return color;2338}23392340static gint gtk3_get_color_for_state(JNIEnv *env, WidgetType widget_type,2341GtkStateType state_type, ColorType color_type)2342{23432344gint result = 0;23452346GtkStateFlags flags = gtk3_get_state_flags(state_type);23472348init_containers();23492350if (gtk3_version_3_20) {2351if ((widget_type == TEXT_FIELD || widget_type == PASSWORD_FIELD || widget_type == SPINNER_TEXT_FIELD ||2352widget_type == FORMATTED_TEXT_FIELD) && state_type == GTK_STATE_SELECTED && color_type == TEXT_BACKGROUND) {2353widget_type = TEXT_AREA;2354}2355}23562357GtkStyleContext* context = NULL;2358if (widget_type == TOOL_TIP) {2359context = get_style(widget_type, "tooltip");2360} else {2361gtk3_widget = gtk3_get_widget(widget_type);2362context = fp_gtk_widget_get_style_context(gtk3_widget);2363}2364if (widget_type == CHECK_BOX_MENU_ITEM2365|| widget_type == RADIO_BUTTON_MENU_ITEM) {2366flags &= GTK_STATE_FLAG_NORMAL | GTK_STATE_FLAG_SELECTED2367| GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_FOCUSED;2368}23692370GdkRGBA color = gtk3_get_color_for_flags(context, flags, color_type);23712372if (recode_color(color.alpha) == 0) {2373color = gtk3_get_color_for_flags(2374fp_gtk_widget_get_style_context(gtk3_get_widget(INTERNAL_FRAME)),23750, BACKGROUND);2376}23772378result = recode_color(color.alpha) << 24 | recode_color(color.red) << 16 |2379recode_color(color.green) << 8 | recode_color(color.blue);2380if (widget_type == TOOL_TIP) {2381disposeOrRestoreContext(context);2382}2383return result;2384}23852386/*************************************************/2387static jobject create_Boolean(JNIEnv *env, jboolean boolean_value);2388static jobject create_Integer(JNIEnv *env, jint int_value);2389static jobject create_Long(JNIEnv *env, jlong long_value);2390static jobject create_Float(JNIEnv *env, jfloat float_value);2391static jobject create_Double(JNIEnv *env, jdouble double_value);2392static jobject create_Character(JNIEnv *env, jchar char_value);2393static jobject create_Insets(JNIEnv *env, GtkBorder *border);23942395static jobject gtk3_get_class_value(JNIEnv *env, WidgetType widget_type,2396const char* key)2397{2398init_containers();23992400gtk3_widget = gtk3_get_widget(widget_type);24012402GValue value = { 0, { { 0 } } };24032404GParamSpec* param = (*fp_gtk_widget_class_find_style_property)(2405((GTypeInstance*)gtk3_widget)->g_class, key);2406if ( param )2407{2408(*fp_g_value_init)( &value, param->value_type );2409(*fp_gtk_widget_style_get_property)(gtk3_widget, key, &value);24102411if ((*fp_g_type_is_a)( param->value_type, G_TYPE_BOOLEAN ))2412{2413gboolean val = (*fp_g_value_get_boolean)(&value);2414return create_Boolean(env, (jboolean)val);2415}2416else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_CHAR ))2417{2418gchar val = (*fp_g_value_get_char)(&value);2419return create_Character(env, (jchar)val);2420}2421else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UCHAR ))2422{2423guchar val = (*fp_g_value_get_uchar)(&value);2424return create_Character(env, (jchar)val);2425}2426else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT ))2427{2428gint val = (*fp_g_value_get_int)(&value);2429return create_Integer(env, (jint)val);2430}2431else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT ))2432{2433guint val = (*fp_g_value_get_uint)(&value);2434return create_Integer(env, (jint)val);2435}2436else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_LONG ))2437{2438glong val = (*fp_g_value_get_long)(&value);2439return create_Long(env, (jlong)val);2440}2441else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ULONG ))2442{2443gulong val = (*fp_g_value_get_ulong)(&value);2444return create_Long(env, (jlong)val);2445}2446else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT64 ))2447{2448gint64 val = (*fp_g_value_get_int64)(&value);2449return create_Long(env, (jlong)val);2450}2451else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT64 ))2452{2453guint64 val = (*fp_g_value_get_uint64)(&value);2454return create_Long(env, (jlong)val);2455}2456else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLOAT ))2457{2458gfloat val = (*fp_g_value_get_float)(&value);2459return create_Float(env, (jfloat)val);2460}2461else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_DOUBLE ))2462{2463gdouble val = (*fp_g_value_get_double)(&value);2464return create_Double(env, (jdouble)val);2465}2466else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ENUM ))2467{2468gint val = (*fp_g_value_get_enum)(&value);2469return create_Integer(env, (jint)val);2470}2471else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLAGS ))2472{2473guint val = (*fp_g_value_get_flags)(&value);2474return create_Integer(env, (jint)val);2475}2476else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_STRING ))2477{2478const gchar* val = (*fp_g_value_get_string)(&value);24792480/* We suppose that all values come in C locale and2481* utf-8 representation of a string is the same as2482* the string itself. If this isn't so we should2483* use g_convert.2484*/2485return (*env)->NewStringUTF(env, val);2486}2487else if ((*fp_g_type_is_a)( param->value_type, GTK_TYPE_BORDER ))2488{2489GtkBorder *border = (GtkBorder*)(*fp_g_value_get_boxed)(&value);2490return border ? create_Insets(env, border) : NULL;2491}24922493/* TODO: Other types are not supported yet.*/2494/* else if((*fp_g_type_is_a)( param->value_type, G_TYPE_PARAM ))2495{2496GParamSpec* val = (*fp_g_value_get_param)(&value);2497printf( "Param: %p\n", val );2498}2499else if((*fp_g_type_is_a)( param->value_type, G_TYPE_BOXED ))2500{2501gpointer* val = (*fp_g_value_get_boxed)(&value);2502printf( "Boxed: %p\n", val );2503}2504else if((*fp_g_type_is_a)( param->value_type, G_TYPE_POINTER ))2505{2506gpointer* val = (*fp_g_value_get_pointer)(&value);2507printf( "Pointer: %p\n", val );2508}2509else if((*fp_g_type_is_a)( param->value_type, G_TYPE_OBJECT ))2510{2511GObject* val = (GObject*)(*fp_g_value_get_object)(&value);2512printf( "Object: %p\n", val );2513}*/2514}25152516return NULL;2517}25182519static void gtk3_set_range_value(WidgetType widget_type, jdouble value,2520jdouble min, jdouble max, jdouble visible)2521{2522GtkAdjustment *adj;25232524gtk3_widget = gtk3_get_widget(widget_type);25252526adj = (*fp_gtk_range_get_adjustment)((GtkRange *)gtk3_widget);25272528fp_gtk_adjustment_set_value(adj, value);2529fp_gtk_adjustment_set_lower(adj, min);2530fp_gtk_adjustment_set_upper(adj, max);2531fp_gtk_adjustment_set_page_size(adj, visible);2532}25332534/*************************************************/2535static jobject create_Object(JNIEnv *env, jmethodID *cid,2536const char* class_name,2537const char* signature,2538jvalue* value)2539{2540jclass class;2541jobject result;25422543class = (*env)->FindClass(env, class_name);2544if (class == NULL)2545return NULL; /* can't find/load the class, exception thrown */25462547if (*cid == NULL)2548{2549*cid = (*env)->GetMethodID(env, class, "<init>", signature);2550if (*cid == NULL)2551{2552(*env)->DeleteLocalRef(env, class);2553return NULL; /* can't find/get the method, exception thrown */2554}2555}25562557result = (*env)->NewObjectA(env, class, *cid, value);25582559(*env)->DeleteLocalRef(env, class);2560return result;2561}25622563jobject create_Boolean(JNIEnv *env, jboolean boolean_value)2564{2565static jmethodID cid = NULL;2566jvalue value;25672568value.z = boolean_value;25692570return create_Object(env, &cid, "java/lang/Boolean", "(Z)V", &value);2571}25722573jobject create_Integer(JNIEnv *env, jint int_value)2574{2575static jmethodID cid = NULL;2576jvalue value;25772578value.i = int_value;25792580return create_Object(env, &cid, "java/lang/Integer", "(I)V", &value);2581}25822583jobject create_Long(JNIEnv *env, jlong long_value)2584{2585static jmethodID cid = NULL;2586jvalue value;25872588value.j = long_value;25892590return create_Object(env, &cid, "java/lang/Long", "(J)V", &value);2591}25922593jobject create_Float(JNIEnv *env, jfloat float_value)2594{2595static jmethodID cid = NULL;2596jvalue value;25972598value.f = float_value;25992600return create_Object(env, &cid, "java/lang/Float", "(F)V", &value);2601}26022603jobject create_Double(JNIEnv *env, jdouble double_value)2604{2605static jmethodID cid = NULL;2606jvalue value;26072608value.d = double_value;26092610return create_Object(env, &cid, "java/lang/Double", "(D)V", &value);2611}26122613jobject create_Character(JNIEnv *env, jchar char_value)2614{2615static jmethodID cid = NULL;2616jvalue value;26172618value.c = char_value;26192620return create_Object(env, &cid, "java/lang/Character", "(C)V", &value);2621}262226232624jobject create_Insets(JNIEnv *env, GtkBorder *border)2625{2626static jmethodID cid = NULL;2627jvalue values[4];26282629values[0].i = border->top;2630values[1].i = border->left;2631values[2].i = border->bottom;2632values[3].i = border->right;26332634return create_Object(env, &cid, "java/awt/Insets", "(IIII)V", values);2635}26362637/*********************************************/2638static jstring gtk3_get_pango_font_name(JNIEnv *env, WidgetType widget_type)2639{2640init_containers();26412642gtk3_widget = gtk3_get_widget(widget_type);2643jstring result = NULL;2644GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);2645if (context)2646{2647PangoFontDescription* fd = fp_gtk_style_context_get_font(context, 0);2648gchar* val = (*fp_pango_font_description_to_string)(fd);2649result = (*env)->NewStringUTF(env, val);2650(*fp_g_free)( val );2651}26522653return result;2654}26552656/***********************************************/2657static jobject get_string_property(JNIEnv *env, GtkSettings* settings,2658const gchar* key) {2659jobject result = NULL;2660gchar* strval = NULL;26612662(*fp_g_object_get)(settings, key, &strval, NULL);2663result = (*env)->NewStringUTF(env, strval);2664(*fp_g_free)(strval);26652666return result;2667}26682669static jobject get_integer_property(JNIEnv *env, GtkSettings* settings,2670const gchar* key) {2671gint intval = 0;2672(*fp_g_object_get)(settings, key, &intval, NULL);2673return create_Integer(env, intval);2674}26752676static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings,2677const gchar* key) {2678gint intval = 0;2679(*fp_g_object_get)(settings, key, &intval, NULL);2680return create_Boolean(env, intval);2681}26822683static jobject gtk3_get_setting(JNIEnv *env, Setting property)2684{2685GtkSettings* settings = (*fp_gtk_settings_get_default)();26862687switch (property)2688{2689case GTK_FONT_NAME:2690return get_string_property(env, settings, "gtk-font-name");2691case GTK_ICON_SIZES:2692return get_string_property(env, settings, "gtk-icon-sizes");2693case GTK_CURSOR_BLINK:2694return get_boolean_property(env, settings, "gtk-cursor-blink");2695case GTK_CURSOR_BLINK_TIME:2696return get_integer_property(env, settings, "gtk-cursor-blink-time");2697}26982699return NULL;2700}27012702static void transform_detail_string (const gchar *detail,2703GtkStyleContext *context) {2704if (!detail)2705return;27062707if (strcmp (detail, "arrow") == 0)2708fp_gtk_style_context_add_class (context, "arrow");2709else if (strcmp (detail, "button") == 0)2710fp_gtk_style_context_add_class (context, "button");2711else if (strcmp (detail, "buttondefault") == 0)2712{2713fp_gtk_style_context_add_class (context, "button");2714fp_gtk_style_context_add_class (context, "default");2715}2716else if (strcmp (detail, "calendar") == 0)2717fp_gtk_style_context_add_class (context, "calendar");2718else if (strcmp (detail, "cellcheck") == 0)2719{2720fp_gtk_style_context_add_class (context, "cell");2721fp_gtk_style_context_add_class (context, "check");2722}2723else if (strcmp (detail, "cellradio") == 0)2724{2725fp_gtk_style_context_add_class (context, "cell");2726fp_gtk_style_context_add_class (context, "radio");2727}2728else if (strcmp (detail, "checkbutton") == 0)2729fp_gtk_style_context_add_class (context, "check");2730else if (strcmp (detail, "check") == 0)2731{2732fp_gtk_style_context_add_class (context, "check");2733fp_gtk_style_context_add_class (context, "menu");2734}2735else if (strcmp (detail, "radiobutton") == 0)2736{2737fp_gtk_style_context_add_class (context, "radio");2738}2739else if (strcmp (detail, "option") == 0)2740{2741fp_gtk_style_context_add_class (context, "radio");2742fp_gtk_style_context_add_class (context, "menu");2743}2744else if (strcmp (detail, "entry") == 0 ||2745strcmp (detail, "entry_bg") == 0)2746fp_gtk_style_context_add_class (context, "entry");2747else if (strcmp (detail, "expander") == 0)2748fp_gtk_style_context_add_class (context, "expander");2749else if (strcmp (detail, "tooltip") == 0)2750fp_gtk_style_context_add_class (context, "tooltip");2751else if (strcmp (detail, "frame") == 0)2752fp_gtk_style_context_add_class (context, "frame");2753else if (strcmp (detail, "scrolled_window") == 0)2754fp_gtk_style_context_add_class (context, "scrolled-window");2755else if (strcmp (detail, "viewport") == 0 ||2756strcmp (detail, "viewportbin") == 0)2757fp_gtk_style_context_add_class (context, "viewport");2758else if (strncmp (detail, "trough", 6) == 0)2759fp_gtk_style_context_add_class (context, "trough");2760else if (strcmp (detail, "spinbutton") == 0)2761fp_gtk_style_context_add_class (context, "spinbutton");2762else if (strcmp (detail, "spinbutton_up") == 0)2763{2764fp_gtk_style_context_add_class (context, "spinbutton");2765fp_gtk_style_context_add_class (context, "button");2766fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);2767}2768else if (strcmp (detail, "spinbutton_down") == 0)2769{2770fp_gtk_style_context_add_class (context, "spinbutton");2771fp_gtk_style_context_add_class (context, "button");2772fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);2773}2774else if ((detail[0] == 'h' || detail[0] == 'v') &&2775strncmp (&detail[1], "scrollbar_", 9) == 0)2776{2777fp_gtk_style_context_add_class (context, "button");2778fp_gtk_style_context_add_class (context, "scrollbar");2779}2780else if (strcmp (detail, "slider") == 0)2781{2782fp_gtk_style_context_add_class (context, "slider");2783fp_gtk_style_context_add_class (context, "scrollbar");2784}2785else if (strcmp (detail, "vscale") == 0 ||2786strcmp (detail, "hscale") == 0)2787{2788fp_gtk_style_context_add_class (context, "slider");2789fp_gtk_style_context_add_class (context, "scale");2790}2791else if (strcmp (detail, "menuitem") == 0)2792{2793fp_gtk_style_context_add_class (context, "menuitem");2794fp_gtk_style_context_add_class (context, "menu");2795}2796else if (strcmp (detail, "menu") == 0)2797{2798fp_gtk_style_context_add_class (context, "popup");2799fp_gtk_style_context_add_class (context, "menu");2800}2801else if (strcmp (detail, "accellabel") == 0)2802fp_gtk_style_context_add_class (context, "accelerator");2803else if (strcmp (detail, "menubar") == 0)2804fp_gtk_style_context_add_class (context, "menubar");2805else if (strcmp (detail, "base") == 0)2806fp_gtk_style_context_add_class (context, "background");2807else if (strcmp (detail, "bar") == 0 ||2808strcmp (detail, "progressbar") == 0)2809fp_gtk_style_context_add_class (context, "progressbar");2810else if (strcmp (detail, "toolbar") == 0)2811fp_gtk_style_context_add_class (context, "toolbar");2812else if (strcmp (detail, "handlebox_bin") == 0)2813fp_gtk_style_context_add_class (context, "dock");2814else if (strcmp (detail, "notebook") == 0)2815fp_gtk_style_context_add_class (context, "notebook");2816else if (strcmp (detail, "tab") == 0)2817{2818fp_gtk_style_context_add_class (context, "notebook");2819fp_gtk_style_context_add_region (context, "tab", 0);2820} else if (strcmp (detail, "paned") == 0) {2821fp_gtk_style_context_add_class (context, "pane-separator");2822}2823else if (fp_g_str_has_prefix (detail, "cell"))2824{2825GtkRegionFlags row, col;2826gboolean ruled = FALSE;2827gchar** tokens;2828guint i;28292830tokens = fp_g_strsplit (detail, "_", -1);2831row = col = 0;2832i = 0;28332834while (tokens[i])2835{2836if (strcmp (tokens[i], "even") == 0)2837row |= GTK_REGION_EVEN;2838else if (strcmp (tokens[i], "odd") == 0)2839row |= GTK_REGION_ODD;2840else if (strcmp (tokens[i], "start") == 0)2841col |= GTK_REGION_FIRST;2842else if (strcmp (tokens[i], "end") == 0)2843col |= GTK_REGION_LAST;2844else if (strcmp (tokens[i], "ruled") == 0)2845ruled = TRUE;2846else if (strcmp (tokens[i], "sorted") == 0)2847col |= GTK_REGION_SORTED;28482849i++;2850}28512852if (!ruled)2853row &= ~(GTK_REGION_EVEN | GTK_REGION_ODD);28542855fp_gtk_style_context_add_class (context, "cell");2856fp_gtk_style_context_add_region (context, "row", row);2857fp_gtk_style_context_add_region (context, "column", col);28582859fp_g_strfreev (tokens);2860}2861}28622863static gboolean gtk3_get_drawable_data(JNIEnv *env, jintArray pixelArray,2864int x, jint y, jint width, jint height, jint jwidth, int dx, int dy,2865jint scale) {2866GdkPixbuf *pixbuf;2867jint *ary;28682869GdkWindow *root = (*fp_gdk_get_default_root_window)();2870if (gtk3_version_3_10) {2871int win_scale = (*fp_gdk_window_get_scale_factor)(root);2872pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(2873root, x, y, (int) (width / (float) win_scale + 0.5), (int) (height / (float) win_scale + 0.5));2874} else {2875pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(root, x, y, width, height);2876}28772878if (pixbuf && scale != 1) {2879GdkPixbuf *scaledPixbuf;2880x /= scale;2881y /= scale;2882width /= scale;2883height /= scale;2884dx /= scale;2885dy /= scale;2886scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height,2887GDK_INTERP_BILINEAR);2888(*fp_g_object_unref)(pixbuf);2889pixbuf = scaledPixbuf;2890}28912892if (pixbuf) {2893int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);2894int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf);2895if ((*fp_gdk_pixbuf_get_width)(pixbuf) >= width2896&& (*fp_gdk_pixbuf_get_height)(pixbuf) >= height2897&& (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 82898&& (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB2899&& nchan >= 32900) {2901guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf);2902ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL);2903if (ary) {2904jint _x, _y;2905int index;2906for (_y = 0; _y < height; _y++) {2907for (_x = 0; _x < width; _x++) {2908p = pix + (intptr_t) _y * stride + _x * nchan;29092910index = (_y + dy) * jwidth + (_x + dx);2911ary[index] = 0xff0000002912| (p[0] << 16)2913| (p[1] << 8)2914| (p[2]);29152916}2917}2918(*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0);2919}2920}2921(*fp_g_object_unref)(pixbuf);2922}2923return JNI_FALSE;2924}29252926static GdkWindow* gtk3_get_window(void *widget) {2927return fp_gtk_widget_get_window((GtkWidget*)widget);2928}29292930static void gtk3_init(GtkApi* gtk) {2931gtk->version = GTK_3;29322933gtk->show_uri_load = >k3_show_uri_load;2934gtk->unload = >k3_unload;2935gtk->flush_event_loop = &flush_gtk_event_loop;2936gtk->gtk_check_version = fp_gtk_check_version;2937gtk->get_setting = >k3_get_setting;29382939gtk->paint_arrow = >k3_paint_arrow;2940gtk->paint_box = >k3_paint_box;2941gtk->paint_box_gap = >k3_paint_box_gap;2942gtk->paint_expander = >k3_paint_expander;2943gtk->paint_extension = >k3_paint_extension;2944gtk->paint_flat_box = >k3_paint_flat_box;2945gtk->paint_focus = >k3_paint_focus;2946gtk->paint_handle = >k3_paint_handle;2947gtk->paint_hline = >k3_paint_hline;2948gtk->paint_vline = >k3_paint_vline;2949gtk->paint_option = >k3_paint_option;2950gtk->paint_shadow = >k3_paint_shadow;2951gtk->paint_slider = >k3_paint_slider;2952gtk->paint_background = >k3_paint_background;2953gtk->paint_check = >k3_paint_check;2954gtk->set_range_value = >k3_set_range_value;29552956gtk->init_painting = >k3_init_painting;2957gtk->copy_image = >k3_copy_image;29582959gtk->get_xthickness = >k3_get_xthickness;2960gtk->get_ythickness = >k3_get_ythickness;2961gtk->get_color_for_state = >k3_get_color_for_state;2962gtk->get_class_value = >k3_get_class_value;29632964gtk->get_pango_font_name = >k3_get_pango_font_name;2965gtk->get_icon_data = >k3_get_icon_data;2966gtk->get_file_icon_data = >k3_get_file_icon_data;2967gtk->gdk_threads_enter = fp_gdk_threads_enter;2968gtk->gdk_threads_leave = fp_gdk_threads_leave;2969gtk->gtk_show_uri = fp_gtk_show_uri;2970gtk->get_drawable_data = >k3_get_drawable_data;2971gtk->g_free = fp_g_free;29722973gtk->gtk_file_chooser_get_filename = fp_gtk_file_chooser_get_filename;2974gtk->gtk_widget_hide = fp_gtk_widget_hide;2975gtk->gtk_main_quit = fp_gtk_main_quit;2976gtk->gtk_file_chooser_dialog_new = fp_gtk_file_chooser_dialog_new;2977gtk->gtk_file_chooser_set_current_folder =2978fp_gtk_file_chooser_set_current_folder;2979gtk->gtk_file_chooser_set_filename = fp_gtk_file_chooser_set_filename;2980gtk->gtk_file_chooser_set_current_name =2981fp_gtk_file_chooser_set_current_name;2982gtk->gtk_file_filter_add_custom = fp_gtk_file_filter_add_custom;2983gtk->gtk_file_chooser_set_filter = fp_gtk_file_chooser_set_filter;2984gtk->gtk_file_chooser_get_type = fp_gtk_file_chooser_get_type;2985gtk->gtk_file_filter_new = fp_gtk_file_filter_new;2986gtk->gtk_file_chooser_set_do_overwrite_confirmation =2987fp_gtk_file_chooser_set_do_overwrite_confirmation;2988gtk->gtk_file_chooser_set_select_multiple =2989fp_gtk_file_chooser_set_select_multiple;2990gtk->gtk_file_chooser_get_current_folder =2991fp_gtk_file_chooser_get_current_folder;2992gtk->gtk_file_chooser_get_filenames = fp_gtk_file_chooser_get_filenames;2993gtk->gtk_g_slist_length = fp_gtk_g_slist_length;2994gtk->g_signal_connect_data = fp_g_signal_connect_data;2995gtk->gtk_widget_show = fp_gtk_widget_show;2996gtk->gtk_main = fp_gtk_main;2997gtk->gtk_main_level = fp_gtk_main_level;2998gtk->g_path_get_dirname = fp_g_path_get_dirname;2999gtk->gdk_x11_drawable_get_xid = fp_gdk_x11_drawable_get_xid;3000gtk->gtk_widget_destroy = fp_gtk_widget_destroy;3001gtk->gtk_window_present = fp_gtk_window_present;3002gtk->gtk_window_move = fp_gtk_window_move;3003gtk->gtk_window_resize = fp_gtk_window_resize;3004gtk->get_window = >k3_get_window;30053006gtk->g_object_unref = fp_g_object_unref;3007gtk->g_list_append = fp_g_list_append;3008gtk->g_list_free = fp_g_list_free;3009gtk->g_list_free_full = fp_g_list_free_full;3010}301130123013