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