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