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