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