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