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