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