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