Path: blob/master/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
41155 views
/*1* Copyright (c) 2005, 2020, 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];5960static void throw_exception(JNIEnv *env, const char* name, const char* message)61{62jclass class = (*env)->FindClass(env, name);6364if (class != NULL)65(*env)->ThrowNew(env, class, message);6667(*env)->DeleteLocalRef(env, class);68}6970static void gtk3_add_state(GtkWidget *widget, GtkStateType state) {71GtkStateType old_state = fp_gtk_widget_get_state(widget);72fp_gtk_widget_set_state(widget, old_state | state);73}7475static void gtk3_remove_state(GtkWidget *widget, GtkStateType state) {76GtkStateType old_state = fp_gtk_widget_get_state(widget);77fp_gtk_widget_set_state(widget, old_state & ~state);78}7980/* This is a workaround for the bug:81* http://sourceware.org/bugzilla/show_bug.cgi?id=181482* (dlsym/dlopen clears dlerror state)83* This bug is specific to Linux, but there is no harm in84* applying this workaround on Solaris as well.85*/86static void* dl_symbol(const char* name)87{88void* result = dlsym(gtk3_libhandle, name);89if (!result)90longjmp(j, NO_SYMBOL_EXCEPTION);9192return result;93}9495static void* dl_symbol_gthread(const char* name)96{97void* result = dlsym(gthread_libhandle, name);98if (!result)99longjmp(j, NO_SYMBOL_EXCEPTION);100101return result;102}103104gboolean gtk3_check(const char* lib_name, gboolean load)105{106if (gtk3_libhandle != NULL) {107/* We've already successfully opened the GTK libs, so return true. */108return TRUE;109} else {110#ifdef RTLD_NOLOAD111void *lib = dlopen(lib_name, RTLD_LAZY | RTLD_NOLOAD);112if (!load || lib != NULL) {113return lib != NULL;114}115#else116#ifdef _AIX117/* On AIX we could implement this with the help of loadquery(L_GETINFO, ..) */118/* (see reload_table() in hotspot/src/os/aix/vm/loadlib_aix.cpp) but it is */119/* probably not worth it because most AIX servers don't have GTK libs anyway */120#endif121#endif122return dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL) != NULL;123}124}125126#define ADD_SUPPORTED_ACTION(actionStr) \127do { \128jfieldID fld_action = (*env)->GetStaticFieldID(env, cls_action, actionStr, \129"Ljava/awt/Desktop$Action;"); \130if (!(*env)->ExceptionCheck(env)) { \131jobject action = (*env)->GetStaticObjectField(env, cls_action, \132fld_action); \133(*env)->CallBooleanMethod(env, supportedActions, mid_arrayListAdd, \134action); \135} else { \136(*env)->ExceptionClear(env); \137} \138} while(0);139140141static void update_supported_actions(JNIEnv *env) {142GVfs * (*fp_g_vfs_get_default) (void);143const gchar * const * (*fp_g_vfs_get_supported_uri_schemes) (GVfs * vfs);144const gchar * const * schemes = NULL;145146jclass cls_action = (*env)->FindClass(env, "java/awt/Desktop$Action");147CHECK_NULL(cls_action);148jclass cls_xDesktopPeer = (*env)->149FindClass(env, "sun/awt/X11/XDesktopPeer");150CHECK_NULL(cls_xDesktopPeer);151jfieldID fld_supportedActions = (*env)->GetStaticFieldID(env,152cls_xDesktopPeer, "supportedActions", "Ljava/util/List;");153CHECK_NULL(fld_supportedActions);154jobject supportedActions = (*env)->GetStaticObjectField(env,155cls_xDesktopPeer, fld_supportedActions);156157jclass cls_arrayList = (*env)->FindClass(env, "java/util/ArrayList");158CHECK_NULL(cls_arrayList);159jmethodID mid_arrayListAdd = (*env)->GetMethodID(env, cls_arrayList, "add",160"(Ljava/lang/Object;)Z");161CHECK_NULL(mid_arrayListAdd);162jmethodID mid_arrayListClear = (*env)->GetMethodID(env, cls_arrayList,163"clear", "()V");164CHECK_NULL(mid_arrayListClear);165166(*env)->CallVoidMethod(env, supportedActions, mid_arrayListClear);167168ADD_SUPPORTED_ACTION("OPEN");169170/**171* gtk_show_uri() documentation says:172*173* > you need to install gvfs to get support for uri schemes such as http://174* > or ftp://, as only local files are handled by GIO itself.175*176* So OPEN action was safely added here.177* However, it looks like Solaris 11 have gvfs support only for 32-bit178* applications only by default.179*/180181fp_g_vfs_get_default = dl_symbol("g_vfs_get_default");182fp_g_vfs_get_supported_uri_schemes =183dl_symbol("g_vfs_get_supported_uri_schemes");184dlerror();185186if (fp_g_vfs_get_default && fp_g_vfs_get_supported_uri_schemes) {187GVfs * vfs = fp_g_vfs_get_default();188schemes = vfs ? fp_g_vfs_get_supported_uri_schemes(vfs) : NULL;189if (schemes) {190int i = 0;191while (schemes[i]) {192if (strcmp(schemes[i], "http") == 0) {193ADD_SUPPORTED_ACTION("BROWSE");194ADD_SUPPORTED_ACTION("MAIL");195break;196}197i++;198}199}200} else {201#ifdef DEBUG202fprintf(stderr, "Cannot load g_vfs_get_supported_uri_schemes\n");203#endif /* DEBUG */204}205206}207/**208* Functions for awt_Desktop.c209*/210static gboolean gtk3_show_uri_load(JNIEnv *env) {211gboolean success = FALSE;212dlerror();213fp_gtk_show_uri = dl_symbol("gtk_show_uri");214const char *dlsym_error = dlerror();215if (dlsym_error) {216#ifdef DEBUG217fprintf (stderr, "Cannot load symbol: %s \n", dlsym_error);218#endif /* DEBUG */219} else if (fp_gtk_show_uri == NULL) {220#ifdef DEBUG221fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n");222#endif /* DEBUG */223} else {224gtk->gtk_show_uri = fp_gtk_show_uri;225update_supported_actions(env);226success = TRUE;227}228return success;229}230231/**232* Functions for sun_awt_X11_GtkFileDialogPeer.c233*/234static void gtk3_file_chooser_load()235{236fp_gtk_file_chooser_get_filename = dl_symbol(237"gtk_file_chooser_get_filename");238fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new");239fp_gtk_file_chooser_set_current_folder = dl_symbol(240"gtk_file_chooser_set_current_folder");241fp_gtk_file_chooser_set_filename = dl_symbol(242"gtk_file_chooser_set_filename");243fp_gtk_file_chooser_set_current_name = dl_symbol(244"gtk_file_chooser_set_current_name");245fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom");246fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter");247fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type");248fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new");249fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol(250"gtk_file_chooser_set_do_overwrite_confirmation");251fp_gtk_file_chooser_set_select_multiple = dl_symbol(252"gtk_file_chooser_set_select_multiple");253fp_gtk_file_chooser_get_current_folder = dl_symbol(254"gtk_file_chooser_get_current_folder");255fp_gtk_file_chooser_get_filenames = dl_symbol(256"gtk_file_chooser_get_filenames");257fp_gtk_g_slist_length = dl_symbol("g_slist_length");258fp_gdk_x11_drawable_get_xid = dl_symbol("gdk_x11_window_get_xid");259}260261static void empty() {}262263static gboolean gtk3_version_3_10 = TRUE;264static gboolean gtk3_version_3_14 = FALSE;265static gboolean gtk3_version_3_20 = FALSE;266267GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)268{269gboolean result;270int i;271int (*handler)();272int (*io_handler)();273char *gtk_modules_env;274gtk3_libhandle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL);275if (gtk3_libhandle == NULL) {276return FALSE;277}278279gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL);280if (gthread_libhandle == NULL) {281gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL);282if (gthread_libhandle == NULL)283return FALSE;284}285286if (setjmp(j) == 0)287{288fp_gtk_check_version = dl_symbol("gtk_check_version");289290/* GLib */291fp_glib_check_version = dlsym(gtk3_libhandle, "glib_check_version");292if (!fp_glib_check_version) {293dlerror();294}295fp_g_free = dl_symbol("g_free");296fp_g_object_unref = dl_symbol("g_object_unref");297298fp_g_main_context_iteration =299dl_symbol("g_main_context_iteration");300301fp_g_value_init = dl_symbol("g_value_init");302fp_g_type_is_a = dl_symbol("g_type_is_a");303fp_g_value_get_boolean = dl_symbol("g_value_get_boolean");304fp_g_value_get_char = dl_symbol("g_value_get_char");305fp_g_value_get_uchar = dl_symbol("g_value_get_uchar");306fp_g_value_get_int = dl_symbol("g_value_get_int");307fp_g_value_get_uint = dl_symbol("g_value_get_uint");308fp_g_value_get_long = dl_symbol("g_value_get_long");309fp_g_value_get_ulong = dl_symbol("g_value_get_ulong");310fp_g_value_get_int64 = dl_symbol("g_value_get_int64");311fp_g_value_get_uint64 = dl_symbol("g_value_get_uint64");312fp_g_value_get_float = dl_symbol("g_value_get_float");313fp_g_value_get_double = dl_symbol("g_value_get_double");314fp_g_value_get_string = dl_symbol("g_value_get_string");315fp_g_value_get_enum = dl_symbol("g_value_get_enum");316fp_g_value_get_flags = dl_symbol("g_value_get_flags");317fp_g_value_get_param = dl_symbol("g_value_get_param");318fp_g_value_get_boxed = dl_symbol("g_value_get_boxed");319fp_g_value_get_pointer = dl_symbol("g_value_get_pointer");320321fp_g_object_get = dl_symbol("g_object_get");322fp_g_object_set = dl_symbol("g_object_set");323324fp_g_str_has_prefix = dl_symbol("g_str_has_prefix");325fp_g_strsplit = dl_symbol("g_strsplit");326fp_g_strfreev = dl_symbol("g_strfreev");327328/* GDK */329fp_gdk_get_default_root_window =330dl_symbol("gdk_get_default_root_window");331332/* Pixbuf */333fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new");334fp_gdk_pixbuf_new_from_file =335dl_symbol("gdk_pixbuf_new_from_file");336fp_gdk_pixbuf_get_from_drawable =337dl_symbol("gdk_pixbuf_get_from_window");338fp_gdk_pixbuf_get_width = dl_symbol("gdk_pixbuf_get_width");339fp_gdk_pixbuf_get_height = dl_symbol("gdk_pixbuf_get_height");340fp_gdk_pixbuf_get_pixels = dl_symbol("gdk_pixbuf_get_pixels");341fp_gdk_pixbuf_get_rowstride =342dl_symbol("gdk_pixbuf_get_rowstride");343fp_gdk_pixbuf_get_has_alpha =344dl_symbol("gdk_pixbuf_get_has_alpha");345fp_gdk_pixbuf_get_bits_per_sample =346dl_symbol("gdk_pixbuf_get_bits_per_sample");347fp_gdk_pixbuf_get_n_channels =348dl_symbol("gdk_pixbuf_get_n_channels");349fp_gdk_pixbuf_get_colorspace =350dl_symbol("gdk_pixbuf_get_colorspace");351352fp_cairo_image_surface_create = dl_symbol("cairo_image_surface_create");353fp_cairo_surface_destroy = dl_symbol("cairo_surface_destroy");354fp_cairo_surface_status = dl_symbol("cairo_surface_status");355fp_cairo_create = dl_symbol("cairo_create");356fp_cairo_destroy = dl_symbol("cairo_destroy");357fp_cairo_status = dl_symbol("cairo_status");358fp_cairo_fill = dl_symbol("cairo_fill");359fp_cairo_rectangle = dl_symbol("cairo_rectangle");360fp_cairo_set_source_rgb = dl_symbol("cairo_set_source_rgb");361fp_cairo_set_source_rgba = dl_symbol("cairo_set_source_rgba");362fp_cairo_surface_flush = dl_symbol("cairo_surface_flush");363fp_cairo_paint = dl_symbol("cairo_paint");364fp_cairo_clip = dl_symbol("cairo_clip");365fp_cairo_image_surface_get_data =366dl_symbol("cairo_image_surface_get_data");367fp_cairo_image_surface_get_stride =368dl_symbol("cairo_image_surface_get_stride");369370fp_gdk_pixbuf_get_from_surface =371dl_symbol("gdk_pixbuf_get_from_surface");372373fp_gtk_widget_get_state = dl_symbol("gtk_widget_get_state");374fp_gtk_widget_set_state = dl_symbol("gtk_widget_set_state");375376fp_gtk_widget_is_focus = dl_symbol("gtk_widget_is_focus");377fp_gtk_widget_set_allocation = dl_symbol("gtk_widget_set_allocation");378fp_gtk_widget_get_parent = dl_symbol("gtk_widget_get_parent");379fp_gtk_widget_get_window = dl_symbol("gtk_widget_get_window");380381fp_gtk_widget_get_style_context =382dl_symbol("gtk_widget_get_style_context");383fp_gtk_style_context_get_color =384dl_symbol("gtk_style_context_get_color");385fp_gtk_style_context_get_background_color =386dl_symbol("gtk_style_context_get_background_color");387fp_gtk_widget_get_state_flags = dl_symbol("gtk_widget_get_state_flags");388fp_gtk_style_context_set_state =389dl_symbol("gtk_style_context_set_state");390fp_gtk_style_context_add_class =391dl_symbol("gtk_style_context_add_class");392fp_gtk_style_context_save = dl_symbol("gtk_style_context_save");393fp_gtk_style_context_restore = dl_symbol("gtk_style_context_restore");394fp_gtk_render_check = dl_symbol("gtk_render_check");395fp_gtk_render_option = dl_symbol("gtk_render_option");396fp_gtk_render_extension = dl_symbol("gtk_render_extension");397fp_gtk_render_expander = dl_symbol("gtk_render_expander");398fp_gtk_render_frame_gap = dl_symbol("gtk_render_frame_gap");399fp_gtk_render_line = dl_symbol("gtk_render_line");400fp_gtk_widget_render_icon_pixbuf =401dl_symbol("gtk_widget_render_icon_pixbuf");402if (fp_gtk_check_version(3, 10, 0)) {403gtk3_version_3_10 = FALSE;404} else {405fp_gdk_window_create_similar_image_surface =406dl_symbol("gdk_window_create_similar_image_surface");407fp_gdk_window_get_scale_factor =408dl_symbol("gdk_window_get_scale_factor");409}410gtk3_version_3_14 = !fp_gtk_check_version(3, 14, 0);411412if (!fp_gtk_check_version(3, 20, 0)) {413gtk3_version_3_20 = TRUE;414fp_gtk_widget_path_copy = dl_symbol("gtk_widget_path_copy");415fp_gtk_widget_path_new = dl_symbol("gtk_widget_path_new");416fp_gtk_widget_path_append_type = dl_symbol("gtk_widget_path_append_type");417fp_gtk_widget_path_iter_set_object_name = dl_symbol("gtk_widget_path_iter_set_object_name");418fp_gtk_style_context_set_path = dl_symbol("gtk_style_context_set_path");419fp_gtk_widget_path_unref = dl_symbol("gtk_widget_path_unref");420fp_gtk_style_context_get_path = dl_symbol("gtk_style_context_get_path");421fp_gtk_style_context_new = dl_symbol("gtk_style_context_new");422}423424fp_gdk_window_create_similar_surface =425dl_symbol("gdk_window_create_similar_surface");426fp_gtk_settings_get_for_screen =427dl_symbol("gtk_settings_get_for_screen");428fp_gtk_widget_get_screen = dl_symbol("gtk_widget_get_screen");429fp_gtk_css_provider_get_named = dl_symbol("gtk_css_provider_get_named");430fp_gtk_style_context_add_provider =431dl_symbol("gtk_style_context_add_provider");432fp_gtk_render_frame = dl_symbol("gtk_render_frame");433fp_gtk_render_focus = dl_symbol("gtk_render_focus");434fp_gtk_render_handle = dl_symbol("gtk_render_handle");435fp_gtk_render_arrow = dl_symbol("gtk_render_arrow");436437fp_gtk_style_context_get_property =438dl_symbol("gtk_style_context_get_property");439fp_gtk_scrolled_window_set_shadow_type =440dl_symbol("gtk_scrolled_window_set_shadow_type");441fp_gtk_render_slider = dl_symbol("gtk_render_slider");442fp_gtk_style_context_get_padding =443dl_symbol("gtk_style_context_get_padding");444fp_gtk_range_set_inverted = dl_symbol("gtk_range_set_inverted");445fp_gtk_style_context_get_font = dl_symbol("gtk_style_context_get_font");446fp_gtk_widget_get_allocated_width =447dl_symbol("gtk_widget_get_allocated_width");448fp_gtk_widget_get_allocated_height =449dl_symbol("gtk_widget_get_allocated_height");450fp_gtk_icon_theme_get_default = dl_symbol("gtk_icon_theme_get_default");451fp_gtk_icon_theme_load_icon = dl_symbol("gtk_icon_theme_load_icon");452453fp_gtk_adjustment_set_lower = dl_symbol("gtk_adjustment_set_lower");454fp_gtk_adjustment_set_page_increment =455dl_symbol("gtk_adjustment_set_page_increment");456fp_gtk_adjustment_set_page_size =457dl_symbol("gtk_adjustment_set_page_size");458fp_gtk_adjustment_set_step_increment =459dl_symbol("gtk_adjustment_set_step_increment");460fp_gtk_adjustment_set_upper = dl_symbol("gtk_adjustment_set_upper");461fp_gtk_adjustment_set_value = dl_symbol("gtk_adjustment_set_value");462463fp_gtk_render_activity = dl_symbol("gtk_render_activity");464fp_gtk_render_background = dl_symbol("gtk_render_background");465fp_gtk_style_context_has_class =466dl_symbol("gtk_style_context_has_class");467468fp_gtk_style_context_set_junction_sides =469dl_symbol("gtk_style_context_set_junction_sides");470fp_gtk_style_context_add_region =471dl_symbol("gtk_style_context_add_region");472473fp_gtk_init_check = dl_symbol("gtk_init_check");474475/* GTK widgets */476fp_gtk_arrow_new = dl_symbol("gtk_arrow_new");477fp_gtk_button_new = dl_symbol("gtk_button_new");478fp_gtk_spin_button_new = dl_symbol("gtk_spin_button_new");479fp_gtk_check_button_new = dl_symbol("gtk_check_button_new");480fp_gtk_check_menu_item_new =481dl_symbol("gtk_check_menu_item_new");482fp_gtk_color_selection_dialog_new =483dl_symbol("gtk_color_selection_dialog_new");484fp_gtk_entry_new = dl_symbol("gtk_entry_new");485fp_gtk_fixed_new = dl_symbol("gtk_fixed_new");486fp_gtk_handle_box_new = dl_symbol("gtk_handle_box_new");487fp_gtk_image_new = dl_symbol("gtk_image_new");488fp_gtk_paned_new = dl_symbol("gtk_paned_new");489fp_gtk_scale_new = dl_symbol("gtk_scale_new");490fp_gtk_hscrollbar_new = dl_symbol("gtk_hscrollbar_new");491fp_gtk_vscrollbar_new = dl_symbol("gtk_vscrollbar_new");492fp_gtk_hseparator_new = dl_symbol("gtk_hseparator_new");493fp_gtk_vseparator_new = dl_symbol("gtk_vseparator_new");494fp_gtk_label_new = dl_symbol("gtk_label_new");495fp_gtk_menu_new = dl_symbol("gtk_menu_new");496fp_gtk_menu_bar_new = dl_symbol("gtk_menu_bar_new");497fp_gtk_menu_item_new = dl_symbol("gtk_menu_item_new");498fp_gtk_menu_item_set_submenu =499dl_symbol("gtk_menu_item_set_submenu");500fp_gtk_notebook_new = dl_symbol("gtk_notebook_new");501fp_gtk_progress_bar_new =502dl_symbol("gtk_progress_bar_new");503fp_gtk_progress_bar_set_orientation =504dl_symbol("gtk_orientable_set_orientation");505fp_gtk_radio_button_new =506dl_symbol("gtk_radio_button_new");507fp_gtk_radio_menu_item_new =508dl_symbol("gtk_radio_menu_item_new");509fp_gtk_scrolled_window_new =510dl_symbol("gtk_scrolled_window_new");511fp_gtk_separator_menu_item_new =512dl_symbol("gtk_separator_menu_item_new");513fp_gtk_text_view_new = dl_symbol("gtk_text_view_new");514fp_gtk_toggle_button_new =515dl_symbol("gtk_toggle_button_new");516fp_gtk_toolbar_new = dl_symbol("gtk_toolbar_new");517fp_gtk_tree_view_new = dl_symbol("gtk_tree_view_new");518fp_gtk_viewport_new = dl_symbol("gtk_viewport_new");519fp_gtk_window_new = dl_symbol("gtk_window_new");520fp_gtk_window_present = dl_symbol("gtk_window_present");521fp_gtk_window_move = dl_symbol("gtk_window_move");522fp_gtk_window_resize = dl_symbol("gtk_window_resize");523524fp_gtk_dialog_new = dl_symbol("gtk_dialog_new");525fp_gtk_frame_new = dl_symbol("gtk_frame_new");526527fp_gtk_adjustment_new = dl_symbol("gtk_adjustment_new");528fp_gtk_container_add = dl_symbol("gtk_container_add");529fp_gtk_menu_shell_append =530dl_symbol("gtk_menu_shell_append");531fp_gtk_widget_realize = dl_symbol("gtk_widget_realize");532fp_gtk_widget_destroy = dl_symbol("gtk_widget_destroy");533fp_gtk_widget_render_icon =534dl_symbol("gtk_widget_render_icon");535fp_gtk_widget_set_name =536dl_symbol("gtk_widget_set_name");537fp_gtk_widget_set_parent =538dl_symbol("gtk_widget_set_parent");539fp_gtk_widget_set_direction =540dl_symbol("gtk_widget_set_direction");541fp_gtk_widget_style_get =542dl_symbol("gtk_widget_style_get");543fp_gtk_widget_class_install_style_property =544dl_symbol("gtk_widget_class_install_style_property");545fp_gtk_widget_class_find_style_property =546dl_symbol("gtk_widget_class_find_style_property");547fp_gtk_widget_style_get_property =548dl_symbol("gtk_widget_style_get_property");549fp_pango_font_description_to_string =550dl_symbol("pango_font_description_to_string");551fp_gtk_settings_get_default =552dl_symbol("gtk_settings_get_default");553fp_gtk_widget_get_settings =554dl_symbol("gtk_widget_get_settings");555fp_gtk_border_get_type = dl_symbol("gtk_border_get_type");556fp_gtk_arrow_set = dl_symbol("gtk_arrow_set");557fp_gtk_widget_size_request =558dl_symbol("gtk_widget_size_request");559fp_gtk_range_get_adjustment =560dl_symbol("gtk_range_get_adjustment");561562fp_gtk_widget_hide = dl_symbol("gtk_widget_hide");563fp_gtk_main_quit = dl_symbol("gtk_main_quit");564fp_g_signal_connect_data = dl_symbol("g_signal_connect_data");565fp_gtk_widget_show = dl_symbol("gtk_widget_show");566fp_gtk_main = dl_symbol("gtk_main");567568fp_g_path_get_dirname = dl_symbol("g_path_get_dirname");569570fp_gdk_threads_init = dl_symbol("gdk_threads_init");571fp_gdk_threads_enter = dl_symbol("gdk_threads_enter");572fp_gdk_threads_leave = dl_symbol("gdk_threads_leave");573574/**575* Functions for sun_awt_X11_GtkFileDialogPeer.c576*/577gtk3_file_chooser_load();578579fp_gtk_combo_box_new = dlsym(gtk3_libhandle, "gtk_combo_box_new");580fp_gtk_combo_box_entry_new = dlsym(gtk3_libhandle,581"gtk_combo_box_new_with_entry");582fp_gtk_separator_tool_item_new = dlsym(gtk3_libhandle,583"gtk_separator_tool_item_new");584fp_g_list_append = dl_symbol("g_list_append");585fp_g_list_free = dl_symbol("g_list_free");586fp_g_list_free_full = dl_symbol("g_list_free_full");587}588/* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION589* Otherwise we can check the return value of setjmp method.590*/591else592{593dlclose(gtk3_libhandle);594gtk3_libhandle = NULL;595596dlclose(gthread_libhandle);597gthread_libhandle = NULL;598599return NULL;600}601602/*603* Strip the AT-SPI GTK_MODULES if present604*/605gtk_modules_env = getenv ("GTK_MODULES");606if ((gtk_modules_env && strstr(gtk_modules_env, "atk-bridge")) ||607(gtk_modules_env && strstr(gtk_modules_env, "gail"))) {608/* careful, strtok modifies its args */609gchar *tmp_env = strdup(gtk_modules_env);610if (tmp_env) {611/* the new env will be smaller than the old one */612gchar *s, *new_env = SAFE_SIZE_STRUCT_ALLOC(malloc,613sizeof(ENV_PREFIX), 1, strlen (gtk_modules_env));614615if (new_env) {616strcpy(new_env, ENV_PREFIX);617618/* strip out 'atk-bridge' and 'gail' */619size_t PREFIX_LENGTH = strlen(ENV_PREFIX);620gchar *tmp_ptr = NULL;621for (s = strtok_r(tmp_env, ":", &tmp_ptr); s;622s = strtok_r(NULL, ":", &tmp_ptr)) {623if ((!strstr(s, "atk-bridge")) && (!strstr(s, "gail"))) {624if (strlen(new_env) > PREFIX_LENGTH) {625new_env = strcat(new_env, ":");626}627new_env = strcat(new_env, s);628}629}630if (putenv(new_env) != 0) {631/* no free() on success, putenv() doesn't copy string */632free(new_env);633}634}635free(tmp_env);636}637}638/*639* GTK should be initialized with gtk_init_check() before use.640*641* gtk_init_check installs its own error handlers. It is critical that642* we preserve error handler set from AWT. Otherwise we'll crash on643* BadMatch errors which we would normally ignore. The IO error handler644* is preserved here, too, just for consistency.645*/646AWT_LOCK();647handler = XSetErrorHandler(NULL);648io_handler = XSetIOErrorHandler(NULL);649650//According the GTK documentation, gdk_threads_init() should be651//called before gtk_init() or gtk_init_check()652fp_gdk_threads_init();653result = (*fp_gtk_init_check)(NULL, NULL);654655XSetErrorHandler(handler);656XSetIOErrorHandler(io_handler);657AWT_UNLOCK();658659/* Initialize widget array. */660for (i = 0; i < _GTK_WIDGET_TYPE_SIZE; i++)661{662gtk3_widgets[i] = NULL;663}664if (result) {665GtkApi* gtk = (GtkApi*)malloc(sizeof(GtkApi));666gtk3_init(gtk);667return gtk;668}669return NULL;670}671672static int gtk3_unload()673{674int i;675char *gtk3_error;676677if (!gtk3_libhandle)678return TRUE;679680/* Release painting objects */681if (surface != NULL) {682fp_cairo_destroy(cr);683fp_cairo_surface_destroy(surface);684surface = NULL;685}686687if (gtk3_window != NULL) {688/* Destroying toplevel widget will destroy all contained widgets */689(*fp_gtk_widget_destroy)(gtk3_window);690691/* Unset some static data so they get reinitialized on next load */692gtk3_window = NULL;693}694695dlerror();696dlclose(gtk3_libhandle);697dlclose(gthread_libhandle);698if ((gtk3_error = dlerror()) != NULL)699{700return FALSE;701}702return TRUE;703}704705/* Dispatch all pending events from the GTK event loop.706* This is needed to catch theme change and update widgets' style.707*/708static void flush_gtk_event_loop()709{710while((*fp_g_main_context_iteration)(NULL, FALSE));711}712713/*714* Initialize components of containment hierarchy. This creates a GtkFixed715* inside a GtkWindow. All widgets get realized.716*/717static void init_containers()718{719if (gtk3_window == NULL)720{721gtk3_window = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);722gtk3_fixed = (GtkFixed *)(*fp_gtk_fixed_new)();723(*fp_gtk_container_add)((GtkContainer*)gtk3_window,724(GtkWidget *)gtk3_fixed);725(*fp_gtk_widget_realize)(gtk3_window);726(*fp_gtk_widget_realize)((GtkWidget *)gtk3_fixed);727728GtkSettings* settings = fp_gtk_settings_get_for_screen(729fp_gtk_widget_get_screen(gtk3_window));730gchar* strval = NULL;731fp_g_object_get(settings, "gtk-theme-name", &strval, NULL);732gtk3_css = fp_gtk_css_provider_get_named(strval, NULL);733}734}735736/*737* Ensure everything is ready for drawing an element of the specified width738* and height.739*740* We should somehow handle translucent images. GTK can draw to X Drawables741* only, which don't support alpha. When we retrieve the image back from742* the server, translucency information is lost. There're several ways to743* work around this:744* 1) Subclass GdkPixmap and cache translucent objects on client side. This745* requires us to implement parts of X server drawing logic on client side.746* Many X requests can potentially be "translucent"; e.g. XDrawLine with747* fill=tile and a translucent tile is a "translucent" operation, whereas748* XDrawLine with fill=solid is an "opaque" one. Moreover themes can (and some749* do) intermix transparent and opaque operations which makes caching even750* more problematic.751* 2) Use Xorg 32bit ARGB visual when available. GDK has no native support752* for it (as of version 2.6). Also even in JDS 3 Xorg does not support753* these visuals by default, which makes optimizing for them pointless.754* We can consider doing this at a later point when ARGB visuals become more755* popular.756* 3') GTK has plans to use Cairo as its graphical backend (presumably in757* 2.8), and Cairo supports alpha. With it we could also get rid of the758* unnecessary round trip to server and do all the drawing on client side.759* 4) For now we draw to two different pixmaps and restore alpha channel by760* comparing results. This can be optimized by using subclassed pixmap and761*/762static void gtk3_init_painting(JNIEnv *env, gint width, gint height)763{764init_containers();765766if (cr) {767fp_cairo_destroy(cr);768}769770if (surface != NULL) {771/* free old stuff */772fp_cairo_surface_destroy(surface);773774}775776if (gtk3_version_3_10) {777surface = fp_gdk_window_create_similar_image_surface(778fp_gtk_widget_get_window(gtk3_window),779CAIRO_FORMAT_ARGB32, width, height, 1);780} else {781surface = fp_cairo_image_surface_create(CAIRO_FORMAT_ARGB32,782width, height);783}784785cr = fp_cairo_create(surface);786if (fp_cairo_surface_status(surface) || fp_cairo_status(cr)) {787JNU_ThrowOutOfMemoryError(env, "The surface size is too big");788}789}790791/*792* Restore image from white and black pixmaps and copy it into destination793* buffer. This method compares two pixbufs taken from white and black794* pixmaps and decodes color and alpha components. Pixbufs are RGB without795* alpha, destination buffer is ABGR.796*797* The return value is the transparency type of the resulting image, either798* one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and799* java_awt_Transparency_TRANSLUCENT.800*/801static gint gtk3_copy_image(gint *dst, gint width, gint height)802{803gint i, j, r, g, b;804guchar *data;805gint stride, padding;806807fp_cairo_surface_flush(surface);808data = (*fp_cairo_image_surface_get_data)(surface);809stride = (*fp_cairo_image_surface_get_stride)(surface);810padding = stride - width * 4;811if (stride > 0 && padding >= 0) {812for (i = 0; i < height; i++) {813for (j = 0; j < width; j++) {814int r = *data++;815int g = *data++;816int b = *data++;817int a = *data++;818*dst++ = (a << 24 | b << 16 | g << 8 | r);819}820data += padding;821}822}823return java_awt_Transparency_TRANSLUCENT;824}825826static void gtk3_set_direction(GtkWidget *widget, GtkTextDirection dir)827{828/*829* Some engines (inexplicably) look at the direction of the widget's830* parent, so we need to set the direction of both the widget and its831* parent.832*/833(*fp_gtk_widget_set_direction)(widget, dir);834GtkWidget* parent = fp_gtk_widget_get_parent(widget);835if (parent != NULL) {836fp_gtk_widget_set_direction(parent, dir);837}838}839840/* GTK state_type filter */841static GtkStateType get_gtk_state_type(WidgetType widget_type, gint synth_state)842{843GtkStateType result = GTK_STATE_NORMAL;844845if ((synth_state & DISABLED) != 0) {846result = GTK_STATE_INSENSITIVE;847} else if ((synth_state & PRESSED) != 0) {848result = GTK_STATE_ACTIVE;849} else if ((synth_state & MOUSE_OVER) != 0) {850result = GTK_STATE_PRELIGHT;851}852return result;853}854855static GtkStateFlags get_gtk_state_flags(gint synth_state)856{857GtkStateFlags flags = 0;858859if ((synth_state & DISABLED) != 0) {860flags |= GTK_STATE_FLAG_INSENSITIVE;861}862if (((synth_state & PRESSED) != 0 || (synth_state & SELECTED) != 0)) {863flags |= GTK_STATE_FLAG_ACTIVE;864}865if ((synth_state & MOUSE_OVER) != 0) {866flags |= GTK_STATE_FLAG_PRELIGHT;867}868if ((synth_state & FOCUSED) != 0) {869flags |= GTK_STATE_FLAG_FOCUSED;870}871return flags;872}873874static GtkStateFlags get_gtk_flags(GtkStateType state_type) {875GtkStateFlags flags = 0;876switch (state_type)877{878case GTK_STATE_PRELIGHT:879flags |= GTK_STATE_FLAG_PRELIGHT;880break;881case GTK_STATE_SELECTED:882flags |= GTK_STATE_FLAG_SELECTED;883break;884case GTK_STATE_INSENSITIVE:885flags |= GTK_STATE_FLAG_INSENSITIVE;886break;887case GTK_STATE_ACTIVE:888flags |= GTK_STATE_FLAG_ACTIVE;889break;890case GTK_STATE_FOCUSED:891flags |= GTK_STATE_FLAG_FOCUSED;892break;893default:894break;895}896return flags;897}898899/* GTK shadow_type filter */900static GtkShadowType get_gtk_shadow_type(WidgetType widget_type,901gint synth_state)902{903GtkShadowType result = GTK_SHADOW_OUT;904905if ((synth_state & SELECTED) != 0) {906result = GTK_SHADOW_IN;907}908return result;909}910911912static GtkWidget* gtk3_get_arrow(GtkArrowType arrow_type,913GtkShadowType shadow_type)914{915GtkWidget *arrow = NULL;916if (NULL == gtk3_widgets[_GTK_ARROW_TYPE])917{918gtk3_widgets[_GTK_ARROW_TYPE] = (*fp_gtk_arrow_new)(arrow_type,919shadow_type);920(*fp_gtk_container_add)((GtkContainer *)gtk3_fixed,921gtk3_widgets[_GTK_ARROW_TYPE]);922(*fp_gtk_widget_realize)(gtk3_widgets[_GTK_ARROW_TYPE]);923}924arrow = gtk3_widgets[_GTK_ARROW_TYPE];925926(*fp_gtk_arrow_set)(arrow, arrow_type, shadow_type);927return arrow;928}929930static GtkAdjustment* create_adjustment()931{932return (GtkAdjustment *)933(*fp_gtk_adjustment_new)(50.0, 0.0, 100.0, 10.0, 20.0, 20.0);934}935936/**937* Returns a pointer to the cached native widget for the specified widget938* type.939*/940static GtkWidget *gtk3_get_widget(WidgetType widget_type)941{942gboolean init_result = FALSE;943GtkWidget *result = NULL;944switch (widget_type)945{946case BUTTON:947case TABLE_HEADER:948if (init_result = (NULL == gtk3_widgets[_GTK_BUTTON_TYPE]))949{950gtk3_widgets[_GTK_BUTTON_TYPE] = (*fp_gtk_button_new)();951}952result = gtk3_widgets[_GTK_BUTTON_TYPE];953break;954case CHECK_BOX:955if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_BUTTON_TYPE]))956{957gtk3_widgets[_GTK_CHECK_BUTTON_TYPE] =958(*fp_gtk_check_button_new)();959}960result = gtk3_widgets[_GTK_CHECK_BUTTON_TYPE];961break;962case CHECK_BOX_MENU_ITEM:963if (init_result = (NULL == gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE]))964{965gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE] =966(*fp_gtk_check_menu_item_new)();967}968result = gtk3_widgets[_GTK_CHECK_MENU_ITEM_TYPE];969break;970/************************************************************971* Creation a dedicated color chooser is dangerous because972* it deadlocks the EDT973************************************************************/974/* case COLOR_CHOOSER:975if (init_result =976(NULL == gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE]))977{978gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE] =979(*fp_gtk_color_selection_dialog_new)(NULL);980}981result = gtk3_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE];982break;*/983case COMBO_BOX:984if (init_result = (NULL == gtk3_widgets[_GTK_COMBO_BOX_TYPE]))985{986gtk3_widgets[_GTK_COMBO_BOX_TYPE] =987(*fp_gtk_combo_box_new)();988}989result = gtk3_widgets[_GTK_COMBO_BOX_TYPE];990break;991case COMBO_BOX_ARROW_BUTTON:992if (init_result =993(NULL == gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE]))994{995gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE] =996(*fp_gtk_toggle_button_new)();997}998result = gtk3_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE];999break;1000case COMBO_BOX_TEXT_FIELD:1001if (init_result =1002(NULL == gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE]))1003{1004result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] =1005(*fp_gtk_entry_new)();1006}1007result = gtk3_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE];1008break;1009case DESKTOP_ICON:1010case INTERNAL_FRAME_TITLE_PANE:1011case LABEL:1012if (init_result = (NULL == gtk3_widgets[_GTK_LABEL_TYPE]))1013{1014gtk3_widgets[_GTK_LABEL_TYPE] =1015(*fp_gtk_label_new)(NULL);1016}1017result = gtk3_widgets[_GTK_LABEL_TYPE];1018break;1019case DESKTOP_PANE:1020case PANEL:1021case ROOT_PANE:1022if (init_result = (NULL == gtk3_widgets[_GTK_CONTAINER_TYPE]))1023{1024/* There is no constructor for a container type. I've1025* chosen GtkFixed container since it has a default1026* constructor.1027*/1028gtk3_widgets[_GTK_CONTAINER_TYPE] =1029(*fp_gtk_fixed_new)();1030}1031result = gtk3_widgets[_GTK_CONTAINER_TYPE];1032break;1033case EDITOR_PANE:1034case TEXT_AREA:1035case TEXT_PANE:1036if (init_result = (NULL == gtk3_widgets[_GTK_TEXT_VIEW_TYPE]))1037{1038gtk3_widgets[_GTK_TEXT_VIEW_TYPE] =1039(*fp_gtk_text_view_new)();1040}1041result = gtk3_widgets[_GTK_TEXT_VIEW_TYPE];1042break;1043case FORMATTED_TEXT_FIELD:1044case PASSWORD_FIELD:1045case TEXT_FIELD:1046if (init_result = (NULL == gtk3_widgets[_GTK_ENTRY_TYPE]))1047{1048gtk3_widgets[_GTK_ENTRY_TYPE] =1049(*fp_gtk_entry_new)();1050}1051result = gtk3_widgets[_GTK_ENTRY_TYPE];1052break;1053case HANDLE_BOX:1054if (init_result = (NULL == gtk3_widgets[_GTK_HANDLE_BOX_TYPE]))1055{1056gtk3_widgets[_GTK_HANDLE_BOX_TYPE] =1057(*fp_gtk_handle_box_new)();1058}1059result = gtk3_widgets[_GTK_HANDLE_BOX_TYPE];1060break;1061case HSCROLL_BAR:1062case HSCROLL_BAR_BUTTON_LEFT:1063case HSCROLL_BAR_BUTTON_RIGHT:1064case HSCROLL_BAR_TRACK:1065case HSCROLL_BAR_THUMB:1066if (init_result = (NULL == gtk3_widgets[_GTK_HSCROLLBAR_TYPE]))1067{1068gtk3_widgets[_GTK_HSCROLLBAR_TYPE] =1069(*fp_gtk_hscrollbar_new)(create_adjustment());1070}1071result = gtk3_widgets[_GTK_HSCROLLBAR_TYPE];1072break;1073case HSEPARATOR:1074if (init_result = (NULL == gtk3_widgets[_GTK_HSEPARATOR_TYPE]))1075{1076gtk3_widgets[_GTK_HSEPARATOR_TYPE] =1077(*fp_gtk_hseparator_new)();1078}1079result = gtk3_widgets[_GTK_HSEPARATOR_TYPE];1080break;1081case HSLIDER:1082case HSLIDER_THUMB:1083case HSLIDER_TRACK:1084if (init_result = (NULL == gtk3_widgets[_GTK_HSCALE_TYPE]))1085{1086gtk3_widgets[_GTK_HSCALE_TYPE] =1087(*fp_gtk_scale_new)(GTK_ORIENTATION_HORIZONTAL, NULL);1088}1089result = gtk3_widgets[_GTK_HSCALE_TYPE];1090break;1091case HSPLIT_PANE_DIVIDER:1092case SPLIT_PANE:1093if (init_result = (NULL == gtk3_widgets[_GTK_HPANED_TYPE]))1094{1095gtk3_widgets[_GTK_HPANED_TYPE] = (*fp_gtk_paned_new)(GTK_ORIENTATION_HORIZONTAL);1096}1097result = gtk3_widgets[_GTK_HPANED_TYPE];1098break;1099case IMAGE:1100if (init_result = (NULL == gtk3_widgets[_GTK_IMAGE_TYPE]))1101{1102gtk3_widgets[_GTK_IMAGE_TYPE] = (*fp_gtk_image_new)();1103}1104result = gtk3_widgets[_GTK_IMAGE_TYPE];1105break;1106case INTERNAL_FRAME:1107if (init_result = (NULL == gtk3_widgets[_GTK_WINDOW_TYPE]))1108{1109gtk3_widgets[_GTK_WINDOW_TYPE] =1110(*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);1111}1112result = gtk3_widgets[_GTK_WINDOW_TYPE];1113break;1114case TOOL_TIP:1115if (init_result = (NULL == gtk3_widgets[_GTK_TOOLTIP_TYPE]))1116{1117result = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL);1118gtk3_widgets[_GTK_TOOLTIP_TYPE] = result;1119}1120result = gtk3_widgets[_GTK_TOOLTIP_TYPE];1121break;1122case LIST:1123case TABLE:1124case TREE:1125case TREE_CELL:1126if (init_result = (NULL == gtk3_widgets[_GTK_TREE_VIEW_TYPE]))1127{1128gtk3_widgets[_GTK_TREE_VIEW_TYPE] =1129(*fp_gtk_tree_view_new)();1130}1131result = gtk3_widgets[_GTK_TREE_VIEW_TYPE];1132break;1133case TITLED_BORDER:1134if (init_result = (NULL == gtk3_widgets[_GTK_FRAME_TYPE]))1135{1136gtk3_widgets[_GTK_FRAME_TYPE] = fp_gtk_frame_new(NULL);1137}1138result = gtk3_widgets[_GTK_FRAME_TYPE];1139break;1140case POPUP_MENU:1141if (init_result = (NULL == gtk3_widgets[_GTK_MENU_TYPE]))1142{1143gtk3_widgets[_GTK_MENU_TYPE] =1144(*fp_gtk_menu_new)();1145}1146result = gtk3_widgets[_GTK_MENU_TYPE];1147break;1148case MENU:1149case MENU_ITEM:1150case MENU_ITEM_ACCELERATOR:1151if (init_result = (NULL == gtk3_widgets[_GTK_MENU_ITEM_TYPE]))1152{1153gtk3_widgets[_GTK_MENU_ITEM_TYPE] =1154(*fp_gtk_menu_item_new)();1155}1156result = gtk3_widgets[_GTK_MENU_ITEM_TYPE];1157break;1158case MENU_BAR:1159if (init_result = (NULL == gtk3_widgets[_GTK_MENU_BAR_TYPE]))1160{1161gtk3_widgets[_GTK_MENU_BAR_TYPE] =1162(*fp_gtk_menu_bar_new)();1163}1164result = gtk3_widgets[_GTK_MENU_BAR_TYPE];1165break;1166case COLOR_CHOOSER:1167case OPTION_PANE:1168if (init_result = (NULL == gtk3_widgets[_GTK_DIALOG_TYPE]))1169{1170gtk3_widgets[_GTK_DIALOG_TYPE] =1171(*fp_gtk_dialog_new)();1172}1173result = gtk3_widgets[_GTK_DIALOG_TYPE];1174break;1175case POPUP_MENU_SEPARATOR:1176if (init_result =1177(NULL == gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE]))1178{1179gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE] =1180(*fp_gtk_separator_menu_item_new)();1181}1182result = gtk3_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE];1183break;1184case HPROGRESS_BAR:1185if (init_result = (NULL == gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE]))1186{1187gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE] =1188(*fp_gtk_progress_bar_new)();1189}1190result = gtk3_widgets[_GTK_HPROGRESS_BAR_TYPE];1191break;1192case VPROGRESS_BAR:1193if (init_result = (NULL == gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE]))1194{1195gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE] =1196(*fp_gtk_progress_bar_new)();1197/*1198* Vertical JProgressBars always go bottom-to-top,1199* regardless of the ComponentOrientation.1200*/1201(*fp_gtk_progress_bar_set_orientation)(1202(GtkProgressBar *)gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE],1203GTK_PROGRESS_BOTTOM_TO_TOP);1204}1205result = gtk3_widgets[_GTK_VPROGRESS_BAR_TYPE];1206break;1207case RADIO_BUTTON:1208if (init_result = (NULL == gtk3_widgets[_GTK_RADIO_BUTTON_TYPE]))1209{1210gtk3_widgets[_GTK_RADIO_BUTTON_TYPE] =1211(*fp_gtk_radio_button_new)(NULL);1212}1213result = gtk3_widgets[_GTK_RADIO_BUTTON_TYPE];1214break;1215case RADIO_BUTTON_MENU_ITEM:1216if (init_result =1217(NULL == gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE]))1218{1219gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE] =1220(*fp_gtk_radio_menu_item_new)(NULL);1221}1222result = gtk3_widgets[_GTK_RADIO_MENU_ITEM_TYPE];1223break;1224case SCROLL_PANE:1225if (init_result =1226(NULL == gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE]))1227{1228gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE] =1229(*fp_gtk_scrolled_window_new)(NULL, NULL);1230}1231result = gtk3_widgets[_GTK_SCROLLED_WINDOW_TYPE];1232break;1233case SPINNER:1234case SPINNER_ARROW_BUTTON:1235case SPINNER_TEXT_FIELD:1236if (init_result = (NULL == gtk3_widgets[_GTK_SPIN_BUTTON_TYPE]))1237{1238result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE] =1239(*fp_gtk_spin_button_new)(NULL, 0, 0);1240}1241result = gtk3_widgets[_GTK_SPIN_BUTTON_TYPE];1242break;1243case TABBED_PANE:1244case TABBED_PANE_TAB_AREA:1245case TABBED_PANE_CONTENT:1246case TABBED_PANE_TAB:1247if (init_result = (NULL == gtk3_widgets[_GTK_NOTEBOOK_TYPE]))1248{1249gtk3_widgets[_GTK_NOTEBOOK_TYPE] =1250(*fp_gtk_notebook_new)(NULL);1251}1252result = gtk3_widgets[_GTK_NOTEBOOK_TYPE];1253break;1254case TOGGLE_BUTTON:1255if (init_result = (NULL == gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE]))1256{1257gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE] =1258(*fp_gtk_toggle_button_new)(NULL);1259}1260result = gtk3_widgets[_GTK_TOGGLE_BUTTON_TYPE];1261break;1262case TOOL_BAR:1263case TOOL_BAR_DRAG_WINDOW:1264if (init_result = (NULL == gtk3_widgets[_GTK_TOOLBAR_TYPE]))1265{1266gtk3_widgets[_GTK_TOOLBAR_TYPE] =1267(*fp_gtk_toolbar_new)(NULL);1268}1269result = gtk3_widgets[_GTK_TOOLBAR_TYPE];1270break;1271case TOOL_BAR_SEPARATOR:1272if (init_result =1273(NULL == gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE]))1274{1275gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE] =1276(*fp_gtk_separator_tool_item_new)();1277}1278result = gtk3_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE];1279break;1280case VIEWPORT:1281if (init_result = (NULL == gtk3_widgets[_GTK_VIEWPORT_TYPE]))1282{1283GtkAdjustment *adjustment = create_adjustment();1284gtk3_widgets[_GTK_VIEWPORT_TYPE] =1285(*fp_gtk_viewport_new)(adjustment, adjustment);1286}1287result = gtk3_widgets[_GTK_VIEWPORT_TYPE];1288break;1289case VSCROLL_BAR:1290case VSCROLL_BAR_BUTTON_UP:1291case VSCROLL_BAR_BUTTON_DOWN:1292case VSCROLL_BAR_TRACK:1293case VSCROLL_BAR_THUMB:1294if (init_result = (NULL == gtk3_widgets[_GTK_VSCROLLBAR_TYPE]))1295{1296gtk3_widgets[_GTK_VSCROLLBAR_TYPE] =1297(*fp_gtk_vscrollbar_new)(create_adjustment());1298}1299result = gtk3_widgets[_GTK_VSCROLLBAR_TYPE];1300break;1301case VSEPARATOR:1302if (init_result = (NULL == gtk3_widgets[_GTK_VSEPARATOR_TYPE]))1303{1304gtk3_widgets[_GTK_VSEPARATOR_TYPE] =1305(*fp_gtk_vseparator_new)();1306}1307result = gtk3_widgets[_GTK_VSEPARATOR_TYPE];1308break;1309case VSLIDER:1310case VSLIDER_THUMB:1311case VSLIDER_TRACK:1312if (init_result = (NULL == gtk3_widgets[_GTK_VSCALE_TYPE]))1313{1314gtk3_widgets[_GTK_VSCALE_TYPE] =1315(*fp_gtk_scale_new)(GTK_ORIENTATION_VERTICAL, NULL);1316}1317result = gtk3_widgets[_GTK_VSCALE_TYPE];1318/*1319* Vertical JSliders start at the bottom, while vertical1320* GtkVScale widgets start at the top (by default), so to fix1321* this we set the "inverted" flag to get the Swing behavior.1322*/1323fp_gtk_range_set_inverted((GtkRange*)result, TRUE);1324break;1325case VSPLIT_PANE_DIVIDER:1326if (init_result = (NULL == gtk3_widgets[_GTK_VPANED_TYPE]))1327{1328gtk3_widgets[_GTK_VPANED_TYPE] = (*fp_gtk_paned_new)(GTK_ORIENTATION_VERTICAL);1329}1330result = gtk3_widgets[_GTK_VPANED_TYPE];1331break;1332default:1333result = NULL;1334break;1335}13361337if (result != NULL && init_result)1338{1339if (widget_type == RADIO_BUTTON_MENU_ITEM ||1340widget_type == CHECK_BOX_MENU_ITEM ||1341widget_type == MENU_ITEM ||1342widget_type == MENU ||1343widget_type == POPUP_MENU_SEPARATOR)1344{1345GtkWidget *menu = gtk3_get_widget(POPUP_MENU);1346(*fp_gtk_menu_shell_append)((GtkMenuShell *)menu, result);1347}1348else if (widget_type == POPUP_MENU)1349{1350GtkWidget *menu_bar = gtk3_get_widget(MENU_BAR);1351GtkWidget *root_menu = (*fp_gtk_menu_item_new)();1352(*fp_gtk_menu_item_set_submenu)((GtkMenuItem*)root_menu, result);1353(*fp_gtk_menu_shell_append)((GtkMenuShell *)menu_bar, root_menu);1354}1355else if (widget_type == COMBO_BOX_TEXT_FIELD )1356{1357GtkWidget* combo = gtk3_get_widget(COMBO_BOX);13581359/*1360* We add a regular GtkButton/GtkEntry to a GtkComboBoxEntry1361* in order to trick engines into thinking it's a real combobox1362* arrow button/text field.1363*/13641365fp_gtk_container_add ((GtkContainer*)(combo), result);1366GtkStyleContext* context = fp_gtk_widget_get_style_context (combo);1367fp_gtk_style_context_add_class (context, "combobox-entry");1368context = fp_gtk_widget_get_style_context (result);1369fp_gtk_style_context_add_class (context, "combobox");1370fp_gtk_style_context_add_class (context, "entry");1371}1372else if (widget_type == COMBO_BOX_ARROW_BUTTON )1373{1374GtkWidget* combo = gtk3_get_widget(COMBO_BOX);1375fp_gtk_widget_set_parent(result, combo);1376}1377else if (widget_type != TOOL_TIP &&1378widget_type != INTERNAL_FRAME &&1379widget_type != OPTION_PANE)1380{1381(*fp_gtk_container_add)((GtkContainer *)gtk3_fixed, result);1382}1383(*fp_gtk_widget_realize)(result);1384}1385return result;1386}13871388static void append_element (GtkWidgetPath *path, const gchar *selector)1389{1390fp_gtk_widget_path_append_type (path, G_TYPE_NONE);1391fp_gtk_widget_path_iter_set_object_name (path, -1, selector);1392}13931394static GtkWidgetPath* createWidgetPath(const GtkWidgetPath* path) {1395if (path == NULL) {1396return fp_gtk_widget_path_new();1397} else {1398return fp_gtk_widget_path_copy(path);1399}1400}14011402static GtkStyleContext* get_style(WidgetType widget_type, const gchar *detail)1403{1404if (!gtk3_version_3_20) {1405gtk3_widget = gtk3_get_widget(widget_type);1406GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1407fp_gtk_style_context_save (context);1408if (detail != 0) {1409transform_detail_string(detail, context);1410}1411return context;1412} else {1413gtk3_widget = gtk3_get_widget(widget_type);1414GtkStyleContext* widget_context = fp_gtk_widget_get_style_context (gtk3_widget);1415GtkWidgetPath *path = NULL;1416if (detail != 0) {1417if (strcmp(detail, "checkbutton") == 0) {1418path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1419append_element(path, "check");1420} else if (strcmp(detail, "radiobutton") == 0) {1421path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1422append_element(path, "radio");1423} else if (strcmp(detail, "vscale") == 0 || strcmp(detail, "hscale") == 0) {1424path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1425append_element(path, "slider");1426} else if (strcmp(detail, "trough") == 0) {1427//This is a fast solution to the scrollbar trough not being rendered properly1428if (widget_type == HSCROLL_BAR || widget_type == HSCROLL_BAR_TRACK ||1429widget_type == VSCROLL_BAR || widget_type == VSCROLL_BAR_TRACK) {1430path = createWidgetPath (NULL);1431} else {1432path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1433}1434append_element(path, detail);1435} else if (strcmp(detail, "bar") == 0) {1436path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1437append_element(path, "trough");1438append_element(path, "progress");1439} else if (strcmp(detail, "vscrollbar") == 0 || strcmp(detail, "hscrollbar") == 0) {1440path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1441append_element(path, "button");1442} else if (strcmp(detail, "check") == 0) {1443path = createWidgetPath (NULL);1444append_element(path, detail);1445} else if (strcmp(detail, "option") == 0) {1446path = createWidgetPath (NULL);1447append_element(path, "radio");1448} else if (strcmp(detail, "paned") == 0) {1449path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1450append_element(path, "paned");1451append_element(path, "separator");1452} else if (strcmp(detail, "spinbutton_down") == 0 || strcmp(detail, "spinbutton_up") == 0) {1453path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1454append_element(path, "spinbutton");1455append_element(path, "button");1456} else {1457path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1458append_element(path, detail);1459}1460} else {1461path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));1462}14631464GtkStyleContext *context = fp_gtk_style_context_new ();1465fp_gtk_style_context_set_path (context, path);1466fp_gtk_widget_path_unref (path);1467return context;1468}1469}14701471static void disposeOrRestoreContext(GtkStyleContext *context)1472{1473if (!gtk3_version_3_20) {1474fp_gtk_style_context_restore (context);1475} else {1476fp_g_object_unref (context);1477}1478}14791480static void gtk3_paint_arrow(WidgetType widget_type, GtkStateType state_type,1481GtkShadowType shadow_type, const gchar *detail,1482gint x, gint y, gint width, gint height,1483GtkArrowType arrow_type, gboolean fill)1484{1485gdouble xx, yy, a = G_PI;1486int s = width;1487gtk3_widget = gtk3_get_arrow(arrow_type, shadow_type);14881489switch (widget_type)1490{1491case SPINNER_ARROW_BUTTON:1492s = (int)(0.4 * width + 0.5) + 1;1493if (arrow_type == GTK_ARROW_UP) {1494a = 0;1495} else if (arrow_type == GTK_ARROW_DOWN) {1496a = G_PI;1497}1498break;14991500case HSCROLL_BAR_BUTTON_LEFT:1501s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1;1502a = 3 * G_PI / 2;1503break;15041505case HSCROLL_BAR_BUTTON_RIGHT:1506s = (int)(0.5 * MIN(height, width * 2) + 0.5) + 1;1507a = G_PI / 2;1508break;15091510case VSCROLL_BAR_BUTTON_UP:1511s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1;1512a = 0;1513break;15141515case VSCROLL_BAR_BUTTON_DOWN:1516s = (int)(0.5 * MIN(height * 2, width) + 0.5) + 1;1517a = G_PI;1518break;15191520case COMBO_BOX_ARROW_BUTTON:1521s = (int)(0.3 * height + 0.5) + 1;1522a = G_PI;1523break;15241525case TABLE:1526s = (int)(0.8 * height + 0.5) + 1;1527if (arrow_type == GTK_ARROW_UP) {1528a = G_PI;1529} else if (arrow_type == GTK_ARROW_DOWN) {1530a = 0;1531}1532break;15331534case MENU_ITEM:1535if (arrow_type == GTK_ARROW_UP) {1536a = G_PI;1537} else if (arrow_type == GTK_ARROW_DOWN) {1538a = 0;1539} else if (arrow_type == GTK_ARROW_RIGHT) {1540a = G_PI / 2;1541} else if (arrow_type == GTK_ARROW_LEFT) {1542a = 3 * G_PI / 2;1543}1544break;15451546default:1547if (arrow_type == GTK_ARROW_UP) {1548a = G_PI;1549} else if (arrow_type == GTK_ARROW_DOWN) {1550a = 0;1551} else if (arrow_type == GTK_ARROW_RIGHT) {1552a = G_PI / 2;1553} else if (arrow_type == GTK_ARROW_LEFT) {1554a = 3 * G_PI / 2;1555}1556break;1557}15581559if (s < width && s < height) {1560xx = x + (0.5 * (width - s) + 0.5);1561yy = y + (0.5 * (height - s) + 0.5);1562} else {1563xx = x;1564yy = y;1565}15661567GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1568fp_gtk_style_context_save (context);156915701571if (detail != NULL) {1572transform_detail_string(detail, context);1573}15741575GtkStateFlags flags = get_gtk_flags(state_type);15761577fp_gtk_style_context_set_state (context, flags);15781579(*fp_gtk_render_arrow)(context, cr, a, xx, yy, s);15801581fp_gtk_style_context_restore (context);1582}15831584static void gtk3_paint_box(WidgetType widget_type, GtkStateType state_type,1585GtkShadowType shadow_type, const gchar *detail,1586gint x, gint y, gint width, gint height,1587gint synth_state, GtkTextDirection dir)1588{1589gtk3_widget = gtk3_get_widget(widget_type);15901591if (widget_type == HSLIDER_TRACK) {1592/*1593* For horizontal JSliders with right-to-left orientation, we need1594* to set the "inverted" flag to match the native GTK behavior where1595* the foreground highlight is on the right side of the slider thumb.1596* This is needed especially for the ubuntulooks engine, which looks1597* exclusively at the "inverted" flag to determine on which side of1598* the thumb to paint the highlight...1599*/1600fp_gtk_range_set_inverted((GtkRange*)gtk3_widget, dir ==1601GTK_TEXT_DIR_RTL);16021603/*1604* Note however that other engines like clearlooks will look at both1605* the "inverted" field and the text direction to determine how1606* the foreground highlight is painted:1607* !inverted && ltr --> paint highlight on left side1608* !inverted && rtl --> paint highlight on right side1609* inverted && ltr --> paint highlight on right side1610* inverted && rtl --> paint highlight on left side1611* So the only way to reliably get the desired results for horizontal1612* JSlider (i.e., highlight on left side for LTR ComponentOrientation1613* and highlight on right side for RTL ComponentOrientation) is to1614* always override text direction as LTR, and then set the "inverted"1615* flag accordingly (as we have done above).1616*/1617dir = GTK_TEXT_DIR_LTR;1618}16191620/*1621* Some engines (e.g. clearlooks) will paint the shadow of certain1622* widgets (e.g. COMBO_BOX_ARROW_BUTTON) differently depending on the1623* the text direction.1624*/1625gtk3_set_direction(gtk3_widget, dir);16261627GtkStyleContext* context = get_style(widget_type, detail);16281629GtkStateFlags flags = get_gtk_flags(state_type);1630if (shadow_type == GTK_SHADOW_IN && widget_type != COMBO_BOX_ARROW_BUTTON) {1631flags |= GTK_STATE_FLAG_ACTIVE;1632}16331634if (synth_state & MOUSE_OVER) {1635flags |= GTK_STATE_FLAG_PRELIGHT;1636}16371638if (synth_state & FOCUSED) {1639flags |= GTK_STATE_FLAG_FOCUSED;1640}16411642if (synth_state & DEFAULT) {1643fp_gtk_style_context_add_class (context, "default");1644}16451646if (fp_gtk_style_context_has_class(context, "trough")) {1647flags |= GTK_STATE_FLAG_BACKDROP;1648}16491650fp_gtk_style_context_set_state (context, flags);16511652fp_gtk_render_background (context, cr, x, y, width, height);1653if (shadow_type != GTK_SHADOW_NONE) {1654fp_gtk_render_frame(context, cr, x, y, width, height);1655}16561657disposeOrRestoreContext(context);16581659/*1660* Reset the text direction to the default value so that we don't1661* accidentally affect other operations and widgets.1662*/1663gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR);16641665//This is a fast solution to the scrollbar trough not being rendered properly1666if ((widget_type == HSCROLL_BAR || widget_type == HSCROLL_BAR_TRACK ||1667widget_type == VSCROLL_BAR || widget_type == VSCROLL_BAR_TRACK) && detail != 0) {1668gtk3_paint_box(widget_type, state_type, shadow_type, NULL,1669x, y, width, height, synth_state, dir);1670}1671}16721673static void gtk3_paint_box_gap(WidgetType widget_type, GtkStateType state_type,1674GtkShadowType shadow_type, const gchar *detail,1675gint x, gint y, gint width, gint height,1676GtkPositionType gap_side, gint gap_x, gint gap_width)1677{1678gtk3_widget = gtk3_get_widget(widget_type);16791680GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);16811682fp_gtk_style_context_save (context);16831684GtkStateFlags flags = get_gtk_flags(state_type);1685fp_gtk_style_context_set_state(context, flags);16861687if (detail != 0) {1688transform_detail_string(detail, context);1689}1690fp_gtk_render_background(context, cr, x, y, width, height);16911692if (shadow_type != GTK_SHADOW_NONE) {1693fp_gtk_render_frame_gap(context, cr, x, y, width, height, gap_side,1694(gdouble)gap_x, (gdouble)gap_x + gap_width);1695}1696fp_gtk_style_context_restore (context);1697}16981699static void gtk3_paint_check(WidgetType widget_type, gint synth_state,1700const gchar *detail, gint x, gint y, gint width, gint height)1701{1702GtkStyleContext* context = get_style(widget_type, detail);17031704GtkStateFlags flags = get_gtk_state_flags(synth_state);1705if (gtk3_version_3_14 && (synth_state & SELECTED)) {1706flags &= ~GTK_STATE_FLAG_SELECTED;1707flags |= GTK_STATE_FLAG_CHECKED;1708}1709fp_gtk_style_context_set_state(context, flags);17101711fp_gtk_render_background(context, cr, x, y, width, height);1712fp_gtk_render_frame(context, cr, x, y, width, height);1713fp_gtk_render_check(context, cr, x, y, width, height);1714disposeOrRestoreContext(context);1715}171617171718static void gtk3_paint_expander(WidgetType widget_type, GtkStateType state_type,1719const gchar *detail, gint x, gint y, gint width, gint height,1720GtkExpanderStyle expander_style)1721{1722gtk3_widget = gtk3_get_widget(widget_type);17231724GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);17251726fp_gtk_style_context_save (context);17271728GtkStateFlags flags = get_gtk_flags(state_type);1729if (expander_style == GTK_EXPANDER_EXPANDED) {1730if (gtk3_version_3_14) {1731flags |= GTK_STATE_FLAG_CHECKED;1732} else {1733flags |= GTK_STATE_FLAG_ACTIVE;1734}1735}17361737fp_gtk_style_context_set_state(context, flags);17381739if (detail != 0) {1740transform_detail_string(detail, context);1741}17421743fp_gtk_render_expander (context, cr, x + 2, y + 2, width - 4, height - 4);17441745fp_gtk_style_context_restore (context);1746}17471748static void gtk3_paint_extension(WidgetType widget_type, GtkStateType state_type,1749GtkShadowType shadow_type, const gchar *detail,1750gint x, gint y, gint width, gint height, GtkPositionType gap_side)1751{1752gtk3_widget = gtk3_get_widget(widget_type);17531754GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);17551756fp_gtk_style_context_save (context);17571758GtkStateFlags flags = GTK_STATE_FLAG_NORMAL;17591760if (state_type == 0) {1761flags = GTK_STATE_FLAG_ACTIVE;1762}17631764fp_gtk_style_context_set_state(context, flags);17651766if (detail != 0) {1767transform_detail_string(detail, context);1768}1769switch(gap_side) {1770case GTK_POS_LEFT:1771fp_gtk_style_context_add_class(context, "right");1772break;1773case GTK_POS_RIGHT:1774fp_gtk_style_context_add_class(context, "left");1775break;1776case GTK_POS_TOP:1777fp_gtk_style_context_add_class(context, "bottom");1778break;1779case GTK_POS_BOTTOM:1780fp_gtk_style_context_add_class(context, "top");1781break;1782default:1783break;1784}17851786fp_gtk_render_extension(context, cr, x, y, width, height, gap_side);17871788fp_gtk_style_context_restore (context);1789}17901791static void gtk3_paint_flat_box(WidgetType widget_type, GtkStateType state_type,1792GtkShadowType shadow_type, const gchar *detail,1793gint x, gint y, gint width, gint height, gboolean has_focus)1794{1795if (state_type == GTK_STATE_PRELIGHT &&1796(widget_type == CHECK_BOX || widget_type == RADIO_BUTTON)) {1797return;1798}17991800GtkStyleContext* context = NULL;1801if (widget_type == TOOL_TIP) {1802context = get_style(widget_type, detail);1803fp_gtk_style_context_add_class(context, "background");1804} else {1805gtk3_widget = gtk3_get_widget(widget_type);1806context = fp_gtk_widget_get_style_context (gtk3_widget);1807fp_gtk_style_context_save (context);1808if (detail != 0) {1809transform_detail_string(detail, context);1810}1811}18121813GtkStateFlags flags = get_gtk_flags(state_type);18141815if (has_focus) {1816flags |= GTK_STATE_FLAG_FOCUSED;1817}18181819fp_gtk_style_context_set_state (context, flags);18201821if (widget_type == COMBO_BOX_TEXT_FIELD) {1822width += height /2;1823}18241825fp_gtk_render_background (context, cr, x, y, width, height);1826if (widget_type == TOOL_TIP) {1827disposeOrRestoreContext(context);1828} else {1829fp_gtk_style_context_restore (context);1830}1831}18321833static void gtk3_paint_focus(WidgetType widget_type, GtkStateType state_type,1834const char *detail, gint x, gint y, gint width, gint height)1835{1836gtk3_widget = gtk3_get_widget(widget_type);18371838GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1839fp_gtk_style_context_save (context);18401841transform_detail_string(detail, context);1842fp_gtk_render_focus (context, cr, x, y, width, height);18431844fp_gtk_style_context_restore (context);18451846}18471848static void gtk3_paint_handle(WidgetType widget_type, GtkStateType state_type,1849GtkShadowType shadow_type, const gchar *detail,1850gint x, gint y, gint width, gint height, GtkOrientation orientation)1851{1852gtk3_widget = gtk3_get_widget(widget_type);18531854GtkStyleContext* context = get_style(widget_type, detail);18551856GtkStateFlags flags = get_gtk_flags(state_type);1857fp_gtk_style_context_set_state(context, GTK_STATE_FLAG_PRELIGHT);18581859if (detail != 0 && !(strcmp(detail, "paned") == 0)) {1860transform_detail_string(detail, context);1861fp_gtk_style_context_add_class (context, "handlebox_bin");1862}18631864if (!(strcmp(detail, "paned") == 0)) {1865fp_gtk_render_handle(context, cr, x, y, width, height);1866fp_gtk_render_background(context, cr, x, y, width, height);1867} else {1868if (orientation == GTK_ORIENTATION_VERTICAL) {1869fp_gtk_render_handle(context, cr, x+width/2, y, 2, height);1870fp_gtk_render_background(context, cr, x+width/2, y, 2, height);1871} else {1872fp_gtk_render_handle(context, cr, x, y+height/2, width, 2);1873fp_gtk_render_background(context, cr, x, y+height/2, width, 2);1874}1875}18761877disposeOrRestoreContext(context);1878}18791880static void gtk3_paint_hline(WidgetType widget_type, GtkStateType state_type,1881const gchar *detail, gint x, gint y, gint width, gint height)1882{1883gtk3_widget = gtk3_get_widget(widget_type);18841885GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);18861887fp_gtk_style_context_save (context);18881889if (detail != 0) {1890transform_detail_string(detail, context);1891}18921893fp_gtk_render_line(context, cr, x, y, x + width, y);18941895fp_gtk_style_context_restore (context);1896}18971898static void gtk3_paint_vline(WidgetType widget_type, GtkStateType state_type,1899const gchar *detail, gint x, gint y, gint width, gint height)1900{1901gtk3_widget = gtk3_get_widget(widget_type);190219031904GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);19051906fp_gtk_style_context_save (context);19071908if (detail != 0) {1909transform_detail_string(detail, context);1910}19111912fp_gtk_render_line(context, cr, x, y, x, y + height);19131914fp_gtk_style_context_restore (context);1915}19161917static void gtk3_paint_option(WidgetType widget_type, gint synth_state,1918const gchar *detail, gint x, gint y, gint width, gint height)1919{1920GtkStyleContext* context = get_style(widget_type, detail);19211922GtkStateFlags flags = get_gtk_state_flags(synth_state);1923if (gtk3_version_3_14 && (synth_state & SELECTED)) {1924flags &= ~GTK_STATE_FLAG_SELECTED;1925flags |= GTK_STATE_FLAG_CHECKED;1926}1927fp_gtk_style_context_set_state(context, flags);19281929fp_gtk_render_background(context, cr, x, y, width, height);1930fp_gtk_render_frame(context, cr, x, y, width, height);1931fp_gtk_render_option(context, cr, x, y, width, height);1932disposeOrRestoreContext(context);1933}19341935static void gtk3_paint_shadow(WidgetType widget_type, GtkStateType state_type,1936GtkShadowType shadow_type, const gchar *detail,1937gint x, gint y, gint width, gint height,1938gint synth_state, GtkTextDirection dir)1939{1940if (shadow_type == GTK_SHADOW_NONE) {1941return;1942}1943gtk3_widget = gtk3_get_widget(widget_type);19441945/*1946* Some engines (e.g. clearlooks) will paint the shadow of certain1947* widgets (e.g. COMBO_BOX_TEXT_FIELD) differently depending on the1948* the text direction.1949*/1950gtk3_set_direction(gtk3_widget, dir);195119521953GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);1954fp_gtk_style_context_save (context);19551956if (detail) {1957transform_detail_string(detail, context);1958}19591960GtkStateFlags flags = get_gtk_flags(state_type);19611962if (synth_state & MOUSE_OVER) {1963flags |= GTK_STATE_FLAG_PRELIGHT;1964}19651966if (synth_state & FOCUSED) {1967flags |= GTK_STATE_FLAG_FOCUSED;1968}19691970fp_gtk_style_context_set_state (context, flags);19711972if (widget_type == COMBO_BOX_TEXT_FIELD) {1973width += height / 2;1974}1975fp_gtk_render_frame(context, cr, x, y, width, height);19761977fp_gtk_style_context_restore (context);19781979/*1980* Reset the text direction to the default value so that we don't1981* accidentally affect other operations and widgets.1982*/1983gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR);1984}19851986static void gtk3_paint_slider(WidgetType widget_type, GtkStateType state_type,1987GtkShadowType shadow_type, const gchar *detail,1988gint x, gint y, gint width, gint height, GtkOrientation orientation,1989gboolean has_focus)1990{1991GtkStyleContext *context = get_style(widget_type, detail);19921993GtkStateFlags flags = get_gtk_flags(state_type);19941995if (state_type == GTK_STATE_ACTIVE) {1996flags |= GTK_STATE_FLAG_PRELIGHT;1997}19981999if (has_focus) {2000flags |= GTK_STATE_FLAG_FOCUSED;2001}20022003fp_gtk_style_context_set_state (context, flags);20042005fp_gtk_render_background (context, cr, x, y, width, height);2006fp_gtk_render_frame(context, cr, x, y, width, height);2007(*fp_gtk_render_slider)(context, cr, x, y, width, height, orientation);2008disposeOrRestoreContext(context);2009}20102011static void gtk3_paint_background(WidgetType widget_type,2012GtkStateType state_type, gint x, gint y, gint width, gint height) {2013gtk3_widget = gtk3_get_widget(widget_type);20142015GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);2016fp_gtk_style_context_save (context);20172018GtkStateFlags flags = get_gtk_flags(state_type);20192020fp_gtk_style_context_set_state (context, flags);20212022fp_gtk_render_background (context, cr, x, y, width, height);20232024fp_gtk_style_context_restore (context);2025}20262027static GdkPixbuf *gtk3_get_stock_icon(gint widget_type, const gchar *stock_id,2028GtkIconSize size, GtkTextDirection direction, const char *detail)2029{2030int sz;20312032switch(size) {2033case GTK_ICON_SIZE_MENU:2034sz = 16;2035break;2036case GTK_ICON_SIZE_SMALL_TOOLBAR:2037sz = 18;2038break;2039case GTK_ICON_SIZE_LARGE_TOOLBAR:2040sz = 24;2041break;2042case GTK_ICON_SIZE_BUTTON:2043sz = 20;2044break;2045case GTK_ICON_SIZE_DND:2046sz = 32;2047break;2048case GTK_ICON_SIZE_DIALOG:2049sz = 48;2050break;2051default:2052sz = 0;2053break;2054}20552056init_containers();2057gtk3_widget = gtk3_get_widget((widget_type < 0) ? IMAGE : widget_type);2058(*fp_gtk_widget_set_direction)(gtk3_widget, direction);2059GtkIconTheme *icon_theme = fp_gtk_icon_theme_get_default();2060GdkPixbuf *result = fp_gtk_icon_theme_load_icon(icon_theme, stock_id, sz,2061GTK_ICON_LOOKUP_USE_BUILTIN, NULL);2062return result;2063}20642065static jboolean gtk3_get_pixbuf_data(JNIEnv *env, GdkPixbuf* pixbuf,2066jmethodID icon_upcall_method, jobject this) {2067if (!pixbuf) {2068return JNI_FALSE;2069}2070guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf);2071if (pixbuf_data) {2072int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf);2073int width = (*fp_gdk_pixbuf_get_width)(pixbuf);2074int height = (*fp_gdk_pixbuf_get_height)(pixbuf);2075int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf);2076int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);2077gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf);20782079jbyteArray data = (*env)->NewByteArray(env, (row_stride * height));2080JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);20812082(*env)->SetByteArrayRegion(env, data, 0, (row_stride * height),2083(jbyte *)pixbuf_data);2084(*fp_g_object_unref)(pixbuf);20852086/* Call the callback method to create the image on the Java side. */2087(*env)->CallVoidMethod(env, this, icon_upcall_method, data,2088width, height, row_stride, bps, channels, alpha);2089return JNI_TRUE;2090}2091return JNI_FALSE;2092}20932094static jboolean gtk3_get_file_icon_data(JNIEnv *env, const char *filename,2095GError **error, jmethodID icon_upcall_method, jobject this) {2096GdkPixbuf* pixbuf = fp_gdk_pixbuf_new_from_file(filename, error);2097return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this);2098}20992100static jboolean gtk3_get_icon_data(JNIEnv *env, gint widget_type,2101const gchar *stock_id, GtkIconSize size,2102GtkTextDirection direction, const char *detail,2103jmethodID icon_upcall_method, jobject this) {2104GdkPixbuf* pixbuf = gtk3_get_stock_icon(widget_type, stock_id, size,2105direction, detail);2106return gtk3_get_pixbuf_data(env, pixbuf, icon_upcall_method, this);2107}21082109/*************************************************/2110static gint gtk3_get_xthickness(JNIEnv *env, WidgetType widget_type)2111{2112init_containers();21132114gtk3_widget = gtk3_get_widget(widget_type);2115GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);2116if (context) {2117GtkBorder padding;2118fp_gtk_style_context_get_padding(context, 0, &padding);2119return padding.left + 1;2120}2121return 0;2122}21232124static gint gtk3_get_ythickness(JNIEnv *env, WidgetType widget_type)2125{2126init_containers();21272128gtk3_widget = gtk3_get_widget(widget_type);2129GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);2130if (context) {2131GtkBorder padding;2132fp_gtk_style_context_get_padding(context, 0, &padding);2133return padding.top + 1;2134}2135return 0;2136}21372138/*************************************************/2139static guint8 recode_color(gdouble channel)2140{2141guint16 result = (guint16)(channel * 65535);2142if (result > 65535) {2143result = 65535;2144}2145return (guint8)( result >> 8);2146}21472148static GtkStateFlags gtk3_get_state_flags(GtkStateType state_type) {2149switch (state_type)2150{2151case GTK_STATE_NORMAL:2152return GTK_STATE_FLAG_NORMAL;2153case GTK_STATE_ACTIVE:2154return GTK_STATE_FLAG_ACTIVE;2155case GTK_STATE_PRELIGHT:2156return GTK_STATE_FLAG_PRELIGHT;2157case GTK_STATE_SELECTED:2158return GTK_STATE_FLAG_SELECTED;2159case GTK_STATE_INSENSITIVE:2160return GTK_STATE_FLAG_INSENSITIVE;2161case GTK_STATE_INCONSISTENT:2162return GTK_STATE_FLAG_INCONSISTENT;2163case GTK_STATE_FOCUSED:2164return GTK_STATE_FLAG_FOCUSED;2165}2166return 0;2167}216821692170static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b) {2171gdouble min;2172gdouble max;2173gdouble red;2174gdouble green;2175gdouble blue;2176gdouble h, l, s;2177gdouble delta;21782179red = *r;2180green = *g;2181blue = *b;21822183if (red > green)2184{2185if (red > blue)2186max = red;2187else2188max = blue;21892190if (green < blue)2191min = green;2192else2193min = blue;2194}2195else2196{2197if (green > blue)2198max = green;2199else2200max = blue;22012202if (red < blue)2203min = red;2204else2205min = blue;2206}22072208l = (max + min) / 2;2209s = 0;2210h = 0;22112212if (max != min)2213{2214if (l <= 0.5)2215s = (max - min) / (max + min);2216else2217s = (max - min) / (2 - max - min);22182219delta = max -min;2220if (red == max)2221h = (green - blue) / delta;2222else if (green == max)2223h = 2 + (blue - red) / delta;2224else if (blue == max)2225h = 4 + (red - green) / delta;22262227h *= 60;2228if (h < 0.0)2229h += 360;2230}22312232*r = h;2233*g = l;2234*b = s;2235}22362237static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s)2238{2239gdouble hue;2240gdouble lightness;2241gdouble saturation;2242gdouble m1, m2;2243gdouble r, g, b;22442245lightness = *l;2246saturation = *s;22472248if (lightness <= 0.5)2249m2 = lightness * (1 + saturation);2250else2251m2 = lightness + saturation - lightness * saturation;2252m1 = 2 * lightness - m2;22532254if (saturation == 0)2255{2256*h = lightness;2257*l = lightness;2258*s = lightness;2259}2260else2261{2262hue = *h + 120;2263while (hue > 360)2264hue -= 360;2265while (hue < 0)2266hue += 360;22672268if (hue < 60)2269r = m1 + (m2 - m1) * hue / 60;2270else if (hue < 180)2271r = m2;2272else if (hue < 240)2273r = m1 + (m2 - m1) * (240 - hue) / 60;2274else2275r = m1;22762277hue = *h;2278while (hue > 360)2279hue -= 360;2280while (hue < 0)2281hue += 360;22822283if (hue < 60)2284g = m1 + (m2 - m1) * hue / 60;2285else if (hue < 180)2286g = m2;2287else if (hue < 240)2288g = m1 + (m2 - m1) * (240 - hue) / 60;2289else2290g = m1;22912292hue = *h - 120;2293while (hue > 360)2294hue -= 360;2295while (hue < 0)2296hue += 360;22972298if (hue < 60)2299b = m1 + (m2 - m1) * hue / 60;2300else if (hue < 180)2301b = m2;2302else if (hue < 240)2303b = m1 + (m2 - m1) * (240 - hue) / 60;2304else2305b = m1;23062307*h = r;2308*l = g;2309*s = b;2310}2311}2312231323142315static void gtk3_style_shade (const GdkRGBA *a, GdkRGBA *b, gdouble k) {2316gdouble red = a->red;2317gdouble green = a->green;2318gdouble blue = a->blue;23192320rgb_to_hls (&red, &green, &blue);23212322green *= k;2323if (green > 1.0)2324green = 1.0;2325else if (green < 0.0)2326green = 0.0;23272328blue *= k;2329if (blue > 1.0)2330blue = 1.0;2331else if (blue < 0.0)2332blue = 0.0;23332334hls_to_rgb (&red, &green, &blue);23352336b->red = red;2337b->green = green;2338b->blue = blue;2339}23402341static GdkRGBA gtk3_get_color_for_flags(GtkStyleContext* context,2342GtkStateFlags flags, ColorType color_type) {2343GdkRGBA c, color;2344color.alpha = 1;23452346switch (color_type)2347{2348case FOREGROUND:2349case TEXT_FOREGROUND:2350fp_gtk_style_context_get_color(context, flags, &color);2351break;2352case BACKGROUND:2353case TEXT_BACKGROUND:2354fp_gtk_style_context_get_background_color(context, flags, &color);2355break;2356case LIGHT:2357c = gtk3_get_color_for_flags(context, flags, BACKGROUND);2358gtk3_style_shade(&c, &color, LIGHTNESS_MULT);2359break;2360case DARK:2361c = gtk3_get_color_for_flags(context, flags, BACKGROUND);2362gtk3_style_shade (&c, &color, DARKNESS_MULT);2363break;2364case MID:2365{2366GdkRGBA c1 = gtk3_get_color_for_flags(context, flags, LIGHT);2367GdkRGBA c2 = gtk3_get_color_for_flags(context, flags, DARK);2368color.red = (c1.red + c2.red) / 2;2369color.green = (c1.green + c2.green) / 2;2370color.blue = (c1.blue + c2.blue) / 2;2371}2372break;2373case FOCUS:2374case BLACK:2375color.red = 0;2376color.green = 0;2377color.blue = 0;2378break;2379case WHITE:2380color.red = 1;2381color.green = 1;2382color.blue = 1;2383break;2384}2385return color;2386}23872388static gint gtk3_get_color_for_state(JNIEnv *env, WidgetType widget_type,2389GtkStateType state_type, ColorType color_type)2390{23912392gint result = 0;23932394GtkStateFlags flags = gtk3_get_state_flags(state_type);23952396init_containers();23972398if (gtk3_version_3_20) {2399if ((widget_type == TEXT_FIELD || widget_type == PASSWORD_FIELD || widget_type == SPINNER_TEXT_FIELD ||2400widget_type == FORMATTED_TEXT_FIELD) && state_type == GTK_STATE_SELECTED && color_type == TEXT_BACKGROUND) {2401widget_type = TEXT_AREA;2402}2403}24042405GtkStyleContext* context = NULL;2406if (widget_type == TOOL_TIP) {2407context = get_style(widget_type, "tooltip");2408} else {2409gtk3_widget = gtk3_get_widget(widget_type);2410context = fp_gtk_widget_get_style_context(gtk3_widget);2411}2412if (widget_type == CHECK_BOX_MENU_ITEM2413|| widget_type == RADIO_BUTTON_MENU_ITEM) {2414flags &= GTK_STATE_FLAG_NORMAL | GTK_STATE_FLAG_SELECTED2415| GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_FOCUSED;2416}24172418GdkRGBA color = gtk3_get_color_for_flags(context, flags, color_type);24192420if (recode_color(color.alpha) == 0) {2421color = gtk3_get_color_for_flags(2422fp_gtk_widget_get_style_context(gtk3_get_widget(INTERNAL_FRAME)),24230, BACKGROUND);2424}24252426result = recode_color(color.alpha) << 24 | recode_color(color.red) << 16 |2427recode_color(color.green) << 8 | recode_color(color.blue);2428if (widget_type == TOOL_TIP) {2429disposeOrRestoreContext(context);2430}2431return result;2432}24332434/*************************************************/2435static jobject create_Boolean(JNIEnv *env, jboolean boolean_value);2436static jobject create_Integer(JNIEnv *env, jint int_value);2437static jobject create_Long(JNIEnv *env, jlong long_value);2438static jobject create_Float(JNIEnv *env, jfloat float_value);2439static jobject create_Double(JNIEnv *env, jdouble double_value);2440static jobject create_Character(JNIEnv *env, jchar char_value);2441static jobject create_Insets(JNIEnv *env, GtkBorder *border);24422443static jobject gtk3_get_class_value(JNIEnv *env, WidgetType widget_type,2444const char* key)2445{2446init_containers();24472448gtk3_widget = gtk3_get_widget(widget_type);24492450GValue value = { 0, { { 0 } } };24512452GParamSpec* param = (*fp_gtk_widget_class_find_style_property)(2453((GTypeInstance*)gtk3_widget)->g_class, key);2454if ( param )2455{2456(*fp_g_value_init)( &value, param->value_type );2457(*fp_gtk_widget_style_get_property)(gtk3_widget, key, &value);24582459if ((*fp_g_type_is_a)( param->value_type, G_TYPE_BOOLEAN ))2460{2461gboolean val = (*fp_g_value_get_boolean)(&value);2462return create_Boolean(env, (jboolean)val);2463}2464else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_CHAR ))2465{2466gchar val = (*fp_g_value_get_char)(&value);2467return create_Character(env, (jchar)val);2468}2469else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UCHAR ))2470{2471guchar val = (*fp_g_value_get_uchar)(&value);2472return create_Character(env, (jchar)val);2473}2474else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT ))2475{2476gint val = (*fp_g_value_get_int)(&value);2477return create_Integer(env, (jint)val);2478}2479else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT ))2480{2481guint val = (*fp_g_value_get_uint)(&value);2482return create_Integer(env, (jint)val);2483}2484else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_LONG ))2485{2486glong val = (*fp_g_value_get_long)(&value);2487return create_Long(env, (jlong)val);2488}2489else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ULONG ))2490{2491gulong val = (*fp_g_value_get_ulong)(&value);2492return create_Long(env, (jlong)val);2493}2494else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_INT64 ))2495{2496gint64 val = (*fp_g_value_get_int64)(&value);2497return create_Long(env, (jlong)val);2498}2499else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_UINT64 ))2500{2501guint64 val = (*fp_g_value_get_uint64)(&value);2502return create_Long(env, (jlong)val);2503}2504else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLOAT ))2505{2506gfloat val = (*fp_g_value_get_float)(&value);2507return create_Float(env, (jfloat)val);2508}2509else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_DOUBLE ))2510{2511gdouble val = (*fp_g_value_get_double)(&value);2512return create_Double(env, (jdouble)val);2513}2514else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_ENUM ))2515{2516gint val = (*fp_g_value_get_enum)(&value);2517return create_Integer(env, (jint)val);2518}2519else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_FLAGS ))2520{2521guint val = (*fp_g_value_get_flags)(&value);2522return create_Integer(env, (jint)val);2523}2524else if ((*fp_g_type_is_a)( param->value_type, G_TYPE_STRING ))2525{2526const gchar* val = (*fp_g_value_get_string)(&value);25272528/* We suppose that all values come in C locale and2529* utf-8 representation of a string is the same as2530* the string itself. If this isn't so we should2531* use g_convert.2532*/2533return (*env)->NewStringUTF(env, val);2534}2535else if ((*fp_g_type_is_a)( param->value_type, GTK_TYPE_BORDER ))2536{2537GtkBorder *border = (GtkBorder*)(*fp_g_value_get_boxed)(&value);2538return border ? create_Insets(env, border) : NULL;2539}25402541/* TODO: Other types are not supported yet.*/2542/* else if((*fp_g_type_is_a)( param->value_type, G_TYPE_PARAM ))2543{2544GParamSpec* val = (*fp_g_value_get_param)(&value);2545printf( "Param: %p\n", val );2546}2547else if((*fp_g_type_is_a)( param->value_type, G_TYPE_BOXED ))2548{2549gpointer* val = (*fp_g_value_get_boxed)(&value);2550printf( "Boxed: %p\n", val );2551}2552else if((*fp_g_type_is_a)( param->value_type, G_TYPE_POINTER ))2553{2554gpointer* val = (*fp_g_value_get_pointer)(&value);2555printf( "Pointer: %p\n", val );2556}2557else if((*fp_g_type_is_a)( param->value_type, G_TYPE_OBJECT ))2558{2559GObject* val = (GObject*)(*fp_g_value_get_object)(&value);2560printf( "Object: %p\n", val );2561}*/2562}25632564return NULL;2565}25662567static void gtk3_set_range_value(WidgetType widget_type, jdouble value,2568jdouble min, jdouble max, jdouble visible)2569{2570GtkAdjustment *adj;25712572gtk3_widget = gtk3_get_widget(widget_type);25732574adj = (*fp_gtk_range_get_adjustment)((GtkRange *)gtk3_widget);25752576fp_gtk_adjustment_set_value(adj, value);2577fp_gtk_adjustment_set_lower(adj, min);2578fp_gtk_adjustment_set_upper(adj, max);2579fp_gtk_adjustment_set_page_size(adj, visible);2580}25812582/*************************************************/2583static jobject create_Object(JNIEnv *env, jmethodID *cid,2584const char* class_name,2585const char* signature,2586jvalue* value)2587{2588jclass class;2589jobject result;25902591class = (*env)->FindClass(env, class_name);2592if (class == NULL)2593return NULL; /* can't find/load the class, exception thrown */25942595if (*cid == NULL)2596{2597*cid = (*env)->GetMethodID(env, class, "<init>", signature);2598if (*cid == NULL)2599{2600(*env)->DeleteLocalRef(env, class);2601return NULL; /* can't find/get the method, exception thrown */2602}2603}26042605result = (*env)->NewObjectA(env, class, *cid, value);26062607(*env)->DeleteLocalRef(env, class);2608return result;2609}26102611jobject create_Boolean(JNIEnv *env, jboolean boolean_value)2612{2613static jmethodID cid = NULL;2614jvalue value;26152616value.z = boolean_value;26172618return create_Object(env, &cid, "java/lang/Boolean", "(Z)V", &value);2619}26202621jobject create_Integer(JNIEnv *env, jint int_value)2622{2623static jmethodID cid = NULL;2624jvalue value;26252626value.i = int_value;26272628return create_Object(env, &cid, "java/lang/Integer", "(I)V", &value);2629}26302631jobject create_Long(JNIEnv *env, jlong long_value)2632{2633static jmethodID cid = NULL;2634jvalue value;26352636value.j = long_value;26372638return create_Object(env, &cid, "java/lang/Long", "(J)V", &value);2639}26402641jobject create_Float(JNIEnv *env, jfloat float_value)2642{2643static jmethodID cid = NULL;2644jvalue value;26452646value.f = float_value;26472648return create_Object(env, &cid, "java/lang/Float", "(F)V", &value);2649}26502651jobject create_Double(JNIEnv *env, jdouble double_value)2652{2653static jmethodID cid = NULL;2654jvalue value;26552656value.d = double_value;26572658return create_Object(env, &cid, "java/lang/Double", "(D)V", &value);2659}26602661jobject create_Character(JNIEnv *env, jchar char_value)2662{2663static jmethodID cid = NULL;2664jvalue value;26652666value.c = char_value;26672668return create_Object(env, &cid, "java/lang/Character", "(C)V", &value);2669}267026712672jobject create_Insets(JNIEnv *env, GtkBorder *border)2673{2674static jmethodID cid = NULL;2675jvalue values[4];26762677values[0].i = border->top;2678values[1].i = border->left;2679values[2].i = border->bottom;2680values[3].i = border->right;26812682return create_Object(env, &cid, "java/awt/Insets", "(IIII)V", values);2683}26842685/*********************************************/2686static jstring gtk3_get_pango_font_name(JNIEnv *env, WidgetType widget_type)2687{2688init_containers();26892690gtk3_widget = gtk3_get_widget(widget_type);2691jstring result = NULL;2692GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);2693if (context)2694{2695PangoFontDescription* fd = fp_gtk_style_context_get_font(context, 0);2696gchar* val = (*fp_pango_font_description_to_string)(fd);2697result = (*env)->NewStringUTF(env, val);2698(*fp_g_free)( val );2699}27002701return result;2702}27032704/***********************************************/2705static jobject get_string_property(JNIEnv *env, GtkSettings* settings,2706const gchar* key) {2707jobject result = NULL;2708gchar* strval = NULL;27092710(*fp_g_object_get)(settings, key, &strval, NULL);2711result = (*env)->NewStringUTF(env, strval);2712(*fp_g_free)(strval);27132714return result;2715}27162717static jobject get_integer_property(JNIEnv *env, GtkSettings* settings,2718const gchar* key) {2719gint intval = 0;2720(*fp_g_object_get)(settings, key, &intval, NULL);2721return create_Integer(env, intval);2722}27232724static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings,2725const gchar* key) {2726gint intval = 0;2727(*fp_g_object_get)(settings, key, &intval, NULL);2728return create_Boolean(env, intval);2729}27302731static jobject gtk3_get_setting(JNIEnv *env, Setting property)2732{2733GtkSettings* settings = (*fp_gtk_settings_get_default)();27342735switch (property)2736{2737case GTK_FONT_NAME:2738return get_string_property(env, settings, "gtk-font-name");2739case GTK_ICON_SIZES:2740return get_string_property(env, settings, "gtk-icon-sizes");2741case GTK_CURSOR_BLINK:2742return get_boolean_property(env, settings, "gtk-cursor-blink");2743case GTK_CURSOR_BLINK_TIME:2744return get_integer_property(env, settings, "gtk-cursor-blink-time");2745}27462747return NULL;2748}27492750static void transform_detail_string (const gchar *detail,2751GtkStyleContext *context) {2752if (!detail)2753return;27542755if (strcmp (detail, "arrow") == 0)2756fp_gtk_style_context_add_class (context, "arrow");2757else if (strcmp (detail, "button") == 0)2758fp_gtk_style_context_add_class (context, "button");2759else if (strcmp (detail, "buttondefault") == 0)2760{2761fp_gtk_style_context_add_class (context, "button");2762fp_gtk_style_context_add_class (context, "default");2763}2764else if (strcmp (detail, "calendar") == 0)2765fp_gtk_style_context_add_class (context, "calendar");2766else if (strcmp (detail, "cellcheck") == 0)2767{2768fp_gtk_style_context_add_class (context, "cell");2769fp_gtk_style_context_add_class (context, "check");2770}2771else if (strcmp (detail, "cellradio") == 0)2772{2773fp_gtk_style_context_add_class (context, "cell");2774fp_gtk_style_context_add_class (context, "radio");2775}2776else if (strcmp (detail, "checkbutton") == 0)2777fp_gtk_style_context_add_class (context, "check");2778else if (strcmp (detail, "check") == 0)2779{2780fp_gtk_style_context_add_class (context, "check");2781fp_gtk_style_context_add_class (context, "menu");2782}2783else if (strcmp (detail, "radiobutton") == 0)2784{2785fp_gtk_style_context_add_class (context, "radio");2786}2787else if (strcmp (detail, "option") == 0)2788{2789fp_gtk_style_context_add_class (context, "radio");2790fp_gtk_style_context_add_class (context, "menu");2791}2792else if (strcmp (detail, "entry") == 0 ||2793strcmp (detail, "entry_bg") == 0)2794fp_gtk_style_context_add_class (context, "entry");2795else if (strcmp (detail, "expander") == 0)2796fp_gtk_style_context_add_class (context, "expander");2797else if (strcmp (detail, "tooltip") == 0)2798fp_gtk_style_context_add_class (context, "tooltip");2799else if (strcmp (detail, "frame") == 0)2800fp_gtk_style_context_add_class (context, "frame");2801else if (strcmp (detail, "scrolled_window") == 0)2802fp_gtk_style_context_add_class (context, "scrolled-window");2803else if (strcmp (detail, "viewport") == 0 ||2804strcmp (detail, "viewportbin") == 0)2805fp_gtk_style_context_add_class (context, "viewport");2806else if (strncmp (detail, "trough", 6) == 0)2807fp_gtk_style_context_add_class (context, "trough");2808else if (strcmp (detail, "spinbutton") == 0)2809fp_gtk_style_context_add_class (context, "spinbutton");2810else if (strcmp (detail, "spinbutton_up") == 0)2811{2812fp_gtk_style_context_add_class (context, "spinbutton");2813fp_gtk_style_context_add_class (context, "button");2814fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);2815}2816else if (strcmp (detail, "spinbutton_down") == 0)2817{2818fp_gtk_style_context_add_class (context, "spinbutton");2819fp_gtk_style_context_add_class (context, "button");2820fp_gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);2821}2822else if ((detail[0] == 'h' || detail[0] == 'v') &&2823strncmp (&detail[1], "scrollbar_", 9) == 0)2824{2825fp_gtk_style_context_add_class (context, "button");2826fp_gtk_style_context_add_class (context, "scrollbar");2827}2828else if (strcmp (detail, "slider") == 0)2829{2830fp_gtk_style_context_add_class (context, "slider");2831fp_gtk_style_context_add_class (context, "scrollbar");2832}2833else if (strcmp (detail, "vscale") == 0 ||2834strcmp (detail, "hscale") == 0)2835{2836fp_gtk_style_context_add_class (context, "slider");2837fp_gtk_style_context_add_class (context, "scale");2838}2839else if (strcmp (detail, "menuitem") == 0)2840{2841fp_gtk_style_context_add_class (context, "menuitem");2842fp_gtk_style_context_add_class (context, "menu");2843}2844else if (strcmp (detail, "menu") == 0)2845{2846fp_gtk_style_context_add_class (context, "popup");2847fp_gtk_style_context_add_class (context, "menu");2848}2849else if (strcmp (detail, "accellabel") == 0)2850fp_gtk_style_context_add_class (context, "accelerator");2851else if (strcmp (detail, "menubar") == 0)2852fp_gtk_style_context_add_class (context, "menubar");2853else if (strcmp (detail, "base") == 0)2854fp_gtk_style_context_add_class (context, "background");2855else if (strcmp (detail, "bar") == 0 ||2856strcmp (detail, "progressbar") == 0)2857fp_gtk_style_context_add_class (context, "progressbar");2858else if (strcmp (detail, "toolbar") == 0)2859fp_gtk_style_context_add_class (context, "toolbar");2860else if (strcmp (detail, "handlebox_bin") == 0)2861fp_gtk_style_context_add_class (context, "dock");2862else if (strcmp (detail, "notebook") == 0)2863fp_gtk_style_context_add_class (context, "notebook");2864else if (strcmp (detail, "tab") == 0)2865{2866fp_gtk_style_context_add_class (context, "notebook");2867fp_gtk_style_context_add_region (context, "tab", 0);2868} else if (strcmp (detail, "paned") == 0) {2869fp_gtk_style_context_add_class (context, "pane-separator");2870}2871else if (fp_g_str_has_prefix (detail, "cell"))2872{2873GtkRegionFlags row, col;2874gboolean ruled = FALSE;2875gchar** tokens;2876guint i;28772878tokens = fp_g_strsplit (detail, "_", -1);2879row = col = 0;2880i = 0;28812882while (tokens[i])2883{2884if (strcmp (tokens[i], "even") == 0)2885row |= GTK_REGION_EVEN;2886else if (strcmp (tokens[i], "odd") == 0)2887row |= GTK_REGION_ODD;2888else if (strcmp (tokens[i], "start") == 0)2889col |= GTK_REGION_FIRST;2890else if (strcmp (tokens[i], "end") == 0)2891col |= GTK_REGION_LAST;2892else if (strcmp (tokens[i], "ruled") == 0)2893ruled = TRUE;2894else if (strcmp (tokens[i], "sorted") == 0)2895col |= GTK_REGION_SORTED;28962897i++;2898}28992900if (!ruled)2901row &= ~(GTK_REGION_EVEN | GTK_REGION_ODD);29022903fp_gtk_style_context_add_class (context, "cell");2904fp_gtk_style_context_add_region (context, "row", row);2905fp_gtk_style_context_add_region (context, "column", col);29062907fp_g_strfreev (tokens);2908}2909}29102911static gboolean gtk3_get_drawable_data(JNIEnv *env, jintArray pixelArray,2912int x, jint y, jint width, jint height, jint jwidth, int dx, int dy,2913jint scale) {2914GdkPixbuf *pixbuf;2915jint *ary;29162917GdkWindow *root = (*fp_gdk_get_default_root_window)();2918if (gtk3_version_3_10) {2919int win_scale = (*fp_gdk_window_get_scale_factor)(root);2920pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(2921root, x, y, (int) (width / (float) win_scale + 0.5), (int) (height / (float) win_scale + 0.5));2922} else {2923pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(root, x, y, width, height);2924}29252926if (pixbuf && scale != 1) {2927GdkPixbuf *scaledPixbuf;2928x /= scale;2929y /= scale;2930width /= scale;2931height /= scale;2932dx /= scale;2933dy /= scale;2934scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height,2935GDK_INTERP_BILINEAR);2936(*fp_g_object_unref)(pixbuf);2937pixbuf = scaledPixbuf;2938}29392940if (pixbuf) {2941int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf);2942int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf);2943if ((*fp_gdk_pixbuf_get_width)(pixbuf) >= width2944&& (*fp_gdk_pixbuf_get_height)(pixbuf) >= height2945&& (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 82946&& (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB2947&& nchan >= 32948) {2949guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf);2950ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL);2951if (ary) {2952jint _x, _y;2953int index;2954for (_y = 0; _y < height; _y++) {2955for (_x = 0; _x < width; _x++) {2956p = pix + (intptr_t) _y * stride + _x * nchan;29572958index = (_y + dy) * jwidth + (_x + dx);2959ary[index] = 0xff0000002960| (p[0] << 16)2961| (p[1] << 8)2962| (p[2]);29632964}2965}2966(*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0);2967}2968}2969(*fp_g_object_unref)(pixbuf);2970}2971return JNI_FALSE;2972}29732974static GdkWindow* gtk3_get_window(void *widget) {2975return fp_gtk_widget_get_window((GtkWidget*)widget);2976}29772978static void gtk3_init(GtkApi* gtk) {2979gtk->version = GTK_3;29802981gtk->show_uri_load = >k3_show_uri_load;2982gtk->unload = >k3_unload;2983gtk->flush_event_loop = &flush_gtk_event_loop;2984gtk->gtk_check_version = fp_gtk_check_version;2985gtk->get_setting = >k3_get_setting;29862987gtk->paint_arrow = >k3_paint_arrow;2988gtk->paint_box = >k3_paint_box;2989gtk->paint_box_gap = >k3_paint_box_gap;2990gtk->paint_expander = >k3_paint_expander;2991gtk->paint_extension = >k3_paint_extension;2992gtk->paint_flat_box = >k3_paint_flat_box;2993gtk->paint_focus = >k3_paint_focus;2994gtk->paint_handle = >k3_paint_handle;2995gtk->paint_hline = >k3_paint_hline;2996gtk->paint_vline = >k3_paint_vline;2997gtk->paint_option = >k3_paint_option;2998gtk->paint_shadow = >k3_paint_shadow;2999gtk->paint_slider = >k3_paint_slider;3000gtk->paint_background = >k3_paint_background;3001gtk->paint_check = >k3_paint_check;3002gtk->set_range_value = >k3_set_range_value;30033004gtk->init_painting = >k3_init_painting;3005gtk->copy_image = >k3_copy_image;30063007gtk->get_xthickness = >k3_get_xthickness;3008gtk->get_ythickness = >k3_get_ythickness;3009gtk->get_color_for_state = >k3_get_color_for_state;3010gtk->get_class_value = >k3_get_class_value;30113012gtk->get_pango_font_name = >k3_get_pango_font_name;3013gtk->get_icon_data = >k3_get_icon_data;3014gtk->get_file_icon_data = >k3_get_file_icon_data;3015gtk->gdk_threads_enter = fp_gdk_threads_enter;3016gtk->gdk_threads_leave = fp_gdk_threads_leave;3017gtk->gtk_show_uri = fp_gtk_show_uri;3018gtk->get_drawable_data = >k3_get_drawable_data;3019gtk->g_free = fp_g_free;30203021gtk->gtk_file_chooser_get_filename = fp_gtk_file_chooser_get_filename;3022gtk->gtk_widget_hide = fp_gtk_widget_hide;3023gtk->gtk_main_quit = fp_gtk_main_quit;3024gtk->gtk_file_chooser_dialog_new = fp_gtk_file_chooser_dialog_new;3025gtk->gtk_file_chooser_set_current_folder =3026fp_gtk_file_chooser_set_current_folder;3027gtk->gtk_file_chooser_set_filename = fp_gtk_file_chooser_set_filename;3028gtk->gtk_file_chooser_set_current_name =3029fp_gtk_file_chooser_set_current_name;3030gtk->gtk_file_filter_add_custom = fp_gtk_file_filter_add_custom;3031gtk->gtk_file_chooser_set_filter = fp_gtk_file_chooser_set_filter;3032gtk->gtk_file_chooser_get_type = fp_gtk_file_chooser_get_type;3033gtk->gtk_file_filter_new = fp_gtk_file_filter_new;3034gtk->gtk_file_chooser_set_do_overwrite_confirmation =3035fp_gtk_file_chooser_set_do_overwrite_confirmation;3036gtk->gtk_file_chooser_set_select_multiple =3037fp_gtk_file_chooser_set_select_multiple;3038gtk->gtk_file_chooser_get_current_folder =3039fp_gtk_file_chooser_get_current_folder;3040gtk->gtk_file_chooser_get_filenames = fp_gtk_file_chooser_get_filenames;3041gtk->gtk_g_slist_length = fp_gtk_g_slist_length;3042gtk->g_signal_connect_data = fp_g_signal_connect_data;3043gtk->gtk_widget_show = fp_gtk_widget_show;3044gtk->gtk_main = fp_gtk_main;3045gtk->gtk_main_level = fp_gtk_main_level;3046gtk->g_path_get_dirname = fp_g_path_get_dirname;3047gtk->gdk_x11_drawable_get_xid = fp_gdk_x11_drawable_get_xid;3048gtk->gtk_widget_destroy = fp_gtk_widget_destroy;3049gtk->gtk_window_present = fp_gtk_window_present;3050gtk->gtk_window_move = fp_gtk_window_move;3051gtk->gtk_window_resize = fp_gtk_window_resize;3052gtk->get_window = >k3_get_window;30533054gtk->g_object_unref = fp_g_object_unref;3055gtk->g_list_append = fp_g_list_append;3056gtk->g_list_free = fp_g_list_free;3057gtk->g_list_free_full = fp_g_list_free_full;3058}305930603061