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