1 /* 2 * Copyright (c) 2005, 2017, 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 <stdio.h> 30 #include <string.h> 31 #include "gtk2_interface.h" 32 #include "java_awt_Transparency.h" 33 #include "jvm_md.h" 34 #include "sizecalc.h" 35 #include <jni_util.h> 36 #include "awt.h" 37 38 #define GTK_TYPE_BORDER ((*fp_gtk_border_get_type)()) 39 40 #define G_TYPE_FUNDAMENTAL_SHIFT (2) 41 #define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) 42 43 #define CONV_BUFFER_SIZE 128 44 45 #define NO_SYMBOL_EXCEPTION 1 46 47 static void *gtk2_libhandle = NULL; 48 static void *gthread_libhandle = NULL; 49 50 static jmp_buf j; 51 52 /* Widgets */ 53 static GtkWidget *gtk2_widget = NULL; 54 static GtkWidget *gtk2_window = NULL; 55 static GtkFixed *gtk2_fixed = NULL; 56 57 /* Paint system */ 58 static GdkPixmap *gtk2_white_pixmap = NULL; 59 static GdkPixmap *gtk2_black_pixmap = NULL; 60 static GdkPixbuf *gtk2_white_pixbuf = NULL; 61 static GdkPixbuf *gtk2_black_pixbuf = NULL; 62 static int gtk2_pixbuf_width = 0; 63 static int gtk2_pixbuf_height = 0; 64 65 /* Static buffer for conversion from java.lang.String to UTF-8 */ 66 static char convertionBuffer[CONV_BUFFER_SIZE]; 67 68 static gboolean new_combo = TRUE; 69 const char ENV_PREFIX[] = "GTK_MODULES="; 70 71 static GtkWidget *gtk2_widgets[_GTK_WIDGET_TYPE_SIZE]; 72 73 /************************* 74 * Glib function pointers 75 *************************/ 76 77 static gboolean (*fp_g_main_context_iteration)(GMainContext *context, 78 gboolean may_block); 79 80 static GValue* (*fp_g_value_init)(GValue *value, GType g_type); 81 static gboolean (*fp_g_type_is_a)(GType type, GType is_a_type); 82 static gboolean (*fp_g_value_get_boolean)(const GValue *value); 83 static gchar (*fp_g_value_get_char)(const GValue *value); 84 static guchar (*fp_g_value_get_uchar)(const GValue *value); 85 static gint (*fp_g_value_get_int)(const GValue *value); 86 static guint (*fp_g_value_get_uint)(const GValue *value); 87 static glong (*fp_g_value_get_long)(const GValue *value); 88 static gulong (*fp_g_value_get_ulong)(const GValue *value); 89 static gint64 (*fp_g_value_get_int64)(const GValue *value); 90 static guint64 (*fp_g_value_get_uint64)(const GValue *value); 91 static gfloat (*fp_g_value_get_float)(const GValue *value); 92 static gdouble (*fp_g_value_get_double)(const GValue *value); 93 static const gchar* (*fp_g_value_get_string)(const GValue *value); 94 static gint (*fp_g_value_get_enum)(const GValue *value); 95 static guint (*fp_g_value_get_flags)(const GValue *value); 96 static GParamSpec* (*fp_g_value_get_param)(const GValue *value); 97 static gpointer* (*fp_g_value_get_boxed)(const GValue *value); 98 static gpointer* (*fp_g_value_get_pointer)(const GValue *value); 99 static GObject* (*fp_g_value_get_object)(const GValue *value); 100 static GParamSpec* (*fp_g_param_spec_int)(const gchar *name, 101 const gchar *nick, const gchar *blurb, 102 gint minimum, gint maximum, gint default_value, 103 GParamFlags flags); 104 static void (*fp_g_object_get)(gpointer object, 105 const gchar* fpn, ...); 106 static void (*fp_g_object_set)(gpointer object, 107 const gchar *first_property_name, 108 ...); 109 /************************ 110 * GDK function pointers 111 ************************/ 112 static GdkPixmap *(*fp_gdk_pixmap_new)(GdkDrawable *drawable, 113 gint width, gint height, gint depth); 114 static GdkGC *(*fp_gdk_gc_new)(GdkDrawable*); 115 static void (*fp_gdk_rgb_gc_set_foreground)(GdkGC*, guint32); 116 static void (*fp_gdk_draw_rectangle)(GdkDrawable*, GdkGC*, gboolean, 117 gint, gint, gint, gint); 118 static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace, 119 gboolean has_alpha, int bits_per_sample, int width, int height); 120 static GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest, 121 GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y, 122 int dest_x, int dest_y, int width, int height); 123 static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable, 124 gint* width, gint* height); 125 126 /************************ 127 * Gtk function pointers 128 ************************/ 129 static gboolean (*fp_gtk_init_check)(int* argc, char** argv); 130 131 /* Painting */ 132 static void (*fp_gtk_paint_hline)(GtkStyle* style, GdkWindow* window, 133 GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, 134 const gchar* detail, gint x1, gint x2, gint y); 135 static void (*fp_gtk_paint_vline)(GtkStyle* style, GdkWindow* window, 136 GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, 137 const gchar* detail, gint y1, gint y2, gint x); 138 static void (*fp_gtk_paint_shadow)(GtkStyle* style, GdkWindow* window, 139 GtkStateType state_type, GtkShadowType shadow_type, 140 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 141 gint x, gint y, gint width, gint height); 142 static void (*fp_gtk_paint_arrow)(GtkStyle* style, GdkWindow* window, 143 GtkStateType state_type, GtkShadowType shadow_type, 144 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 145 GtkArrowType arrow_type, gboolean fill, gint x, gint y, 146 gint width, gint height); 147 static void (*fp_gtk_paint_diamond)(GtkStyle* style, GdkWindow* window, 148 GtkStateType state_type, GtkShadowType shadow_type, 149 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 150 gint x, gint y, gint width, gint height); 151 static void (*fp_gtk_paint_box)(GtkStyle* style, GdkWindow* window, 152 GtkStateType state_type, GtkShadowType shadow_type, 153 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 154 gint x, gint y, gint width, gint height); 155 static void (*fp_gtk_paint_flat_box)(GtkStyle* style, GdkWindow* window, 156 GtkStateType state_type, GtkShadowType shadow_type, 157 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 158 gint x, gint y, gint width, gint height); 159 static void (*fp_gtk_paint_check)(GtkStyle* style, GdkWindow* window, 160 GtkStateType state_type, GtkShadowType shadow_type, 161 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 162 gint x, gint y, gint width, gint height); 163 static void (*fp_gtk_paint_option)(GtkStyle* style, GdkWindow* window, 164 GtkStateType state_type, GtkShadowType shadow_type, 165 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 166 gint x, gint y, gint width, gint height); 167 static void (*fp_gtk_paint_box_gap)(GtkStyle* style, GdkWindow* window, 168 GtkStateType state_type, GtkShadowType shadow_type, 169 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 170 gint x, gint y, gint width, gint height, 171 GtkPositionType gap_side, gint gap_x, gint gap_width); 172 static void (*fp_gtk_paint_extension)(GtkStyle* style, GdkWindow* window, 173 GtkStateType state_type, GtkShadowType shadow_type, 174 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 175 gint x, gint y, gint width, gint height, GtkPositionType gap_side); 176 static void (*fp_gtk_paint_focus)(GtkStyle* style, GdkWindow* window, 177 GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, 178 const gchar* detail, gint x, gint y, gint width, gint height); 179 static void (*fp_gtk_paint_slider)(GtkStyle* style, GdkWindow* window, 180 GtkStateType state_type, GtkShadowType shadow_type, 181 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 182 gint x, gint y, gint width, gint height, GtkOrientation orientation); 183 static void (*fp_gtk_paint_handle)(GtkStyle* style, GdkWindow* window, 184 GtkStateType state_type, GtkShadowType shadow_type, 185 GdkRectangle* area, GtkWidget* widget, const gchar* detail, 186 gint x, gint y, gint width, gint height, GtkOrientation orientation); 187 static void (*fp_gtk_paint_expander)(GtkStyle* style, GdkWindow* window, 188 GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, 189 const gchar* detail, gint x, gint y, GtkExpanderStyle expander_style); 190 static void (*fp_gtk_style_apply_default_background)(GtkStyle* style, 191 GdkWindow* window, gboolean set_bg, GtkStateType state_type, 192 GdkRectangle* area, gint x, gint y, gint width, gint height); 193 194 /* Widget creation */ 195 static GtkWidget* (*fp_gtk_arrow_new)(GtkArrowType arrow_type, 196 GtkShadowType shadow_type); 197 static GtkWidget* (*fp_gtk_button_new)(); 198 static GtkWidget* (*fp_gtk_check_button_new)(); 199 static GtkWidget* (*fp_gtk_check_menu_item_new)(); 200 static GtkWidget* (*fp_gtk_color_selection_dialog_new)(const gchar* title); 201 static GtkWidget* (*fp_gtk_combo_box_new)(); 202 static GtkWidget* (*fp_gtk_combo_box_entry_new)(); 203 static GtkWidget* (*fp_gtk_entry_new)(); 204 static GtkWidget* (*fp_gtk_fixed_new)(); 205 static GtkWidget* (*fp_gtk_handle_box_new)(); 206 static GtkWidget* (*fp_gtk_hpaned_new)(); 207 static GtkWidget* (*fp_gtk_vpaned_new)(); 208 static GtkWidget* (*fp_gtk_hscale_new)(GtkAdjustment* adjustment); 209 static GtkWidget* (*fp_gtk_vscale_new)(GtkAdjustment* adjustment); 210 static GtkWidget* (*fp_gtk_hscrollbar_new)(GtkAdjustment* adjustment); 211 static GtkWidget* (*fp_gtk_vscrollbar_new)(GtkAdjustment* adjustment); 212 static GtkWidget* (*fp_gtk_hseparator_new)(); 213 static GtkWidget* (*fp_gtk_vseparator_new)(); 214 static GtkWidget* (*fp_gtk_image_new)(); 215 static GtkWidget* (*fp_gtk_label_new)(const gchar* str); 216 static GtkWidget* (*fp_gtk_menu_new)(); 217 static GtkWidget* (*fp_gtk_menu_bar_new)(); 218 static GtkWidget* (*fp_gtk_menu_item_new)(); 219 static GtkWidget* (*fp_gtk_notebook_new)(); 220 static GtkWidget* (*fp_gtk_progress_bar_new)(); 221 static GtkWidget* (*fp_gtk_progress_bar_set_orientation)( 222 GtkProgressBar *pbar, 223 GtkProgressBarOrientation orientation); 224 static GtkWidget* (*fp_gtk_radio_button_new)(GSList *group); 225 static GtkWidget* (*fp_gtk_radio_menu_item_new)(GSList *group); 226 static GtkWidget* (*fp_gtk_scrolled_window_new)(GtkAdjustment *hadjustment, 227 GtkAdjustment *vadjustment); 228 static GtkWidget* (*fp_gtk_separator_menu_item_new)(); 229 static GtkWidget* (*fp_gtk_separator_tool_item_new)(); 230 static GtkWidget* (*fp_gtk_text_view_new)(); 231 static GtkWidget* (*fp_gtk_toggle_button_new)(); 232 static GtkWidget* (*fp_gtk_toolbar_new)(); 233 static GtkWidget* (*fp_gtk_tree_view_new)(); 234 static GtkWidget* (*fp_gtk_viewport_new)(GtkAdjustment *hadjustment, 235 GtkAdjustment *vadjustment); 236 static GtkWidget* (*fp_gtk_window_new)(GtkWindowType type); 237 static GtkWidget* (*fp_gtk_dialog_new)(); 238 static GtkWidget* (*fp_gtk_spin_button_new)(GtkAdjustment *adjustment, 239 gdouble climb_rate, guint digits); 240 static GtkWidget* (*fp_gtk_frame_new)(const gchar *label); 241 242 /* Other widget operations */ 243 static GtkObject* (*fp_gtk_adjustment_new)(gdouble value, 244 gdouble lower, gdouble upper, gdouble step_increment, 245 gdouble page_increment, gdouble page_size); 246 static void (*fp_gtk_container_add)(GtkContainer *window, GtkWidget *widget); 247 static void (*fp_gtk_menu_shell_append)(GtkMenuShell *menu_shell, 248 GtkWidget *child); 249 static void (*fp_gtk_menu_item_set_submenu)(GtkMenuItem *menu_item, 250 GtkWidget *submenu); 251 static void (*fp_gtk_widget_realize)(GtkWidget *widget); 252 static GdkPixbuf* (*fp_gtk_widget_render_icon)(GtkWidget *widget, 253 const gchar *stock_id, GtkIconSize size, const gchar *detail); 254 static void (*fp_gtk_widget_set_name)(GtkWidget *widget, const gchar *name); 255 static void (*fp_gtk_widget_set_parent)(GtkWidget *widget, GtkWidget *parent); 256 static void (*fp_gtk_widget_set_direction)(GtkWidget *widget, 257 GtkTextDirection direction); 258 static void (*fp_gtk_widget_style_get)(GtkWidget *widget, 259 const gchar *first_property_name, ...); 260 static void (*fp_gtk_widget_class_install_style_property)( 261 GtkWidgetClass* class, GParamSpec *pspec); 262 static GParamSpec* (*fp_gtk_widget_class_find_style_property)( 263 GtkWidgetClass* class, const gchar* property_name); 264 static void (*fp_gtk_widget_style_get_property)(GtkWidget* widget, 265 const gchar* property_name, GValue* value); 266 static char* (*fp_pango_font_description_to_string)( 267 const PangoFontDescription* fd); 268 static GtkSettings* (*fp_gtk_settings_get_default)(); 269 static GtkSettings* (*fp_gtk_widget_get_settings)(GtkWidget *widget); 270 static GType (*fp_gtk_border_get_type)(); 271 static void (*fp_gtk_arrow_set)(GtkWidget* arrow, 272 GtkArrowType arrow_type, 273 GtkShadowType shadow_type); 274 static void (*fp_gtk_widget_size_request)(GtkWidget *widget, 275 GtkRequisition *requisition); 276 static GtkAdjustment* (*fp_gtk_range_get_adjustment)(GtkRange* range); 277 278 /* Method bodies */ 279 280 static void throw_exception(JNIEnv *env, const char* name, const char* message) 281 { 282 jclass class = (*env)->FindClass(env, name); 283 284 if (class != NULL) 285 (*env)->ThrowNew(env, class, message); 286 287 (*env)->DeleteLocalRef(env, class); 288 } 289 290 /* This is a workaround for the bug: 291 * http://sourceware.org/bugzilla/show_bug.cgi?id=1814 292 * (dlsym/dlopen clears dlerror state) 293 * This bug is specific to Linux, but there is no harm in 294 * applying this workaround on Solaris as well. 295 */ 296 static void* dl_symbol(const char* name) 297 { 298 void* result = dlsym(gtk2_libhandle, name); 299 if (!result) 300 longjmp(j, NO_SYMBOL_EXCEPTION); 301 302 return result; 303 } 304 305 static void* dl_symbol_gthread(const char* name) 306 { 307 void* result = dlsym(gthread_libhandle, name); 308 if (!result) 309 longjmp(j, NO_SYMBOL_EXCEPTION); 310 311 return result; 312 } 313 314 gboolean gtk2_check(const char* lib_name, gboolean load) 315 { 316 if (gtk2_libhandle != NULL) { 317 /* We've already successfully opened the GTK libs, so return true. */ 318 return TRUE; 319 } else { 320 void *lib = NULL; 321 #ifdef RTLD_NOLOAD 322 /* Just check if gtk libs are already in the process space */ 323 lib = dlopen(lib_name, RTLD_LAZY | RTLD_NOLOAD); 324 if (!load || lib != NULL) { 325 return lib != NULL; 326 } 327 #else 328 #ifdef _AIX 329 /* On AIX we could implement this with the help of loadquery(L_GETINFO, ..) */ 330 /* (see reload_table() in hotspot/src/os/aix/vm/loadlib_aix.cpp) but it is */ 331 /* probably not worth it because most AIX servers don't have GTK libs anyway */ 332 #endif 333 #endif 334 335 lib = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); 336 337 if (lib == NULL) { 338 return FALSE; 339 } 340 341 fp_gtk_check_version = dlsym(lib, "gtk_check_version"); 342 /* Check for GTK 2.2+ */ 343 if (!fp_gtk_check_version(2, 2, 0)) { 344 return TRUE; 345 } 346 347 // 8048289: workaround for https://bugzilla.gnome.org/show_bug.cgi?id=733065 348 // dlclose(lib); 349 350 return FALSE; 351 } 352 } 353 354 #define ADD_SUPPORTED_ACTION(actionStr) \ 355 do { \ 356 jfieldID fld_action = (*env)->GetStaticFieldID(env, cls_action, actionStr, "Ljava/awt/Desktop$Action;"); \ 357 if (!(*env)->ExceptionCheck(env)) { \ 358 jobject action = (*env)->GetStaticObjectField(env, cls_action, fld_action); \ 359 (*env)->CallBooleanMethod(env, supportedActions, mid_arrayListAdd, action); \ 360 } else { \ 361 (*env)->ExceptionClear(env); \ 362 } \ 363 } while(0); 364 365 366 static void update_supported_actions(JNIEnv *env) { 367 GVfs * (*fp_g_vfs_get_default) (void); 368 const gchar * const * (*fp_g_vfs_get_supported_uri_schemes) (GVfs * vfs); 369 const gchar * const * schemes = NULL; 370 371 jclass cls_action = (*env)->FindClass(env, "java/awt/Desktop$Action"); 372 CHECK_NULL(cls_action); 373 jclass cls_xDesktopPeer = (*env)->FindClass(env, "sun/awt/X11/XDesktopPeer"); 374 CHECK_NULL(cls_xDesktopPeer); 375 jfieldID fld_supportedActions = (*env)->GetStaticFieldID(env, cls_xDesktopPeer, "supportedActions", "Ljava/util/List;"); 376 CHECK_NULL(fld_supportedActions); 377 jobject supportedActions = (*env)->GetStaticObjectField(env, cls_xDesktopPeer, fld_supportedActions); 378 379 jclass cls_arrayList = (*env)->FindClass(env, "java/util/ArrayList"); 380 CHECK_NULL(cls_arrayList); 381 jmethodID mid_arrayListAdd = (*env)->GetMethodID(env, cls_arrayList, "add", "(Ljava/lang/Object;)Z"); 382 CHECK_NULL(mid_arrayListAdd); 383 jmethodID mid_arrayListClear = (*env)->GetMethodID(env, cls_arrayList, "clear", "()V"); 384 CHECK_NULL(mid_arrayListClear); 385 386 (*env)->CallVoidMethod(env, supportedActions, mid_arrayListClear); 387 388 ADD_SUPPORTED_ACTION("OPEN"); 389 390 /** 391 * gtk_show_uri() documentation says: 392 * 393 * > you need to install gvfs to get support for uri schemes such as http:// 394 * > or ftp://, as only local files are handled by GIO itself. 395 * 396 * So OPEN action was safely added here. 397 * However, it looks like Solaris 11 have gvfs support only for 32-bit 398 * applications only by default. 399 */ 400 401 fp_g_vfs_get_default = dl_symbol("g_vfs_get_default"); 402 fp_g_vfs_get_supported_uri_schemes = dl_symbol("g_vfs_get_supported_uri_schemes"); 403 dlerror(); 404 405 if (fp_g_vfs_get_default && fp_g_vfs_get_supported_uri_schemes) { 406 GVfs * vfs = fp_g_vfs_get_default(); 407 schemes = vfs ? fp_g_vfs_get_supported_uri_schemes(vfs) : NULL; 408 if (schemes) { 409 int i = 0; 410 while (schemes[i]) { 411 if (strcmp(schemes[i], "http") == 0) { 412 ADD_SUPPORTED_ACTION("BROWSE"); 413 ADD_SUPPORTED_ACTION("MAIL"); 414 break; 415 } 416 i++; 417 } 418 } 419 } else { 420 #ifdef INTERNAL_BUILD 421 fprintf(stderr, "Cannot load g_vfs_get_supported_uri_schemes\n"); 422 #endif /* INTERNAL_BUILD */ 423 } 424 425 } 426 /** 427 * Functions for awt_Desktop.c 428 */ 429 static gboolean gtk2_show_uri_load(JNIEnv *env) { 430 gboolean success = FALSE; 431 dlerror(); 432 const char *gtk_version = fp_gtk_check_version(2, 14, 0); 433 if (gtk_version != NULL) { 434 // The gtk_show_uri is available from GTK+ 2.14 435 #ifdef INTERNAL_BUILD 436 fprintf (stderr, "The version of GTK is %s. " 437 "The gtk_show_uri function is supported " 438 "since GTK+ 2.14.\n", gtk_version); 439 #endif /* INTERNAL_BUILD */ 440 } else { 441 // Loading symbols only if the GTK version is 2.14 and higher 442 fp_gtk_show_uri = dl_symbol("gtk_show_uri"); 443 const char *dlsym_error = dlerror(); 444 if (dlsym_error) { 445 #ifdef INTERNAL_BUILD 446 fprintf (stderr, "Cannot load symbol: %s \n", dlsym_error); 447 #endif /* INTERNAL_BUILD */ 448 } else if (fp_gtk_show_uri == NULL) { 449 #ifdef INTERNAL_BUILD 450 fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n"); 451 #endif /* INTERNAL_BUILD */ 452 } else { 453 gtk->gtk_show_uri = fp_gtk_show_uri; 454 update_supported_actions(env); 455 success = TRUE; 456 } 457 } 458 return success; 459 } 460 461 /** 462 * Functions for sun_awt_X11_GtkFileDialogPeer.c 463 */ 464 static void gtk2_file_chooser_load() 465 { 466 fp_gtk_file_chooser_get_filename = dl_symbol( 467 "gtk_file_chooser_get_filename"); 468 fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new"); 469 fp_gtk_file_chooser_set_current_folder = dl_symbol( 470 "gtk_file_chooser_set_current_folder"); 471 fp_gtk_file_chooser_set_filename = dl_symbol( 472 "gtk_file_chooser_set_filename"); 473 fp_gtk_file_chooser_set_current_name = dl_symbol( 474 "gtk_file_chooser_set_current_name"); 475 fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom"); 476 fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter"); 477 fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type"); 478 fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new"); 479 if (fp_gtk_check_version(2, 8, 0) == NULL) { 480 fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol( 481 "gtk_file_chooser_set_do_overwrite_confirmation"); 482 } 483 fp_gtk_file_chooser_set_select_multiple = dl_symbol( 484 "gtk_file_chooser_set_select_multiple"); 485 fp_gtk_file_chooser_get_current_folder = dl_symbol( 486 "gtk_file_chooser_get_current_folder"); 487 fp_gtk_file_chooser_get_filenames = dl_symbol( 488 "gtk_file_chooser_get_filenames"); 489 fp_gtk_g_slist_length = dl_symbol("g_slist_length"); 490 } 491 492 GtkApi* gtk2_load(JNIEnv *env, const char* lib_name) 493 { 494 gboolean result; 495 int i; 496 int (*handler)(); 497 int (*io_handler)(); 498 char *gtk_modules_env; 499 500 gtk2_libhandle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); 501 if (gtk2_libhandle == NULL) { 502 return FALSE; 503 } 504 505 gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); 506 if (gthread_libhandle == NULL) { 507 gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL); 508 if (gthread_libhandle == NULL) 509 return FALSE; 510 } 511 512 if (setjmp(j) == 0) 513 { 514 fp_gtk_check_version = dl_symbol("gtk_check_version"); 515 /* Check for GTK 2.2+ */ 516 if (fp_gtk_check_version(2, 2, 0)) { 517 longjmp(j, NO_SYMBOL_EXCEPTION); 518 } 519 520 /* GLib */ 521 fp_glib_check_version = dlsym(gtk2_libhandle, "glib_check_version"); 522 if (!fp_glib_check_version) { 523 dlerror(); 524 } 525 fp_g_free = dl_symbol("g_free"); 526 fp_g_object_unref = dl_symbol("g_object_unref"); 527 528 fp_g_main_context_iteration = 529 dl_symbol("g_main_context_iteration"); 530 531 fp_g_value_init = dl_symbol("g_value_init"); 532 fp_g_type_is_a = dl_symbol("g_type_is_a"); 533 534 fp_g_value_get_boolean = dl_symbol("g_value_get_boolean"); 535 fp_g_value_get_char = dl_symbol("g_value_get_char"); 536 fp_g_value_get_uchar = dl_symbol("g_value_get_uchar"); 537 fp_g_value_get_int = dl_symbol("g_value_get_int"); 538 fp_g_value_get_uint = dl_symbol("g_value_get_uint"); 539 fp_g_value_get_long = dl_symbol("g_value_get_long"); 540 fp_g_value_get_ulong = dl_symbol("g_value_get_ulong"); 541 fp_g_value_get_int64 = dl_symbol("g_value_get_int64"); 542 fp_g_value_get_uint64 = dl_symbol("g_value_get_uint64"); 543 fp_g_value_get_float = dl_symbol("g_value_get_float"); 544 fp_g_value_get_double = dl_symbol("g_value_get_double"); 545 fp_g_value_get_string = dl_symbol("g_value_get_string"); 546 fp_g_value_get_enum = dl_symbol("g_value_get_enum"); 547 fp_g_value_get_flags = dl_symbol("g_value_get_flags"); 548 fp_g_value_get_param = dl_symbol("g_value_get_param"); 549 fp_g_value_get_boxed = dl_symbol("g_value_get_boxed"); 550 fp_g_value_get_pointer = dl_symbol("g_value_get_pointer"); 551 fp_g_value_get_object = dl_symbol("g_value_get_object"); 552 fp_g_param_spec_int = dl_symbol("g_param_spec_int"); 553 fp_g_object_get = dl_symbol("g_object_get"); 554 fp_g_object_set = dl_symbol("g_object_set"); 555 556 /* GDK */ 557 fp_gdk_pixmap_new = dl_symbol("gdk_pixmap_new"); 558 fp_gdk_pixbuf_get_from_drawable = 559 dl_symbol("gdk_pixbuf_get_from_drawable"); 560 fp_gdk_gc_new = dl_symbol("gdk_gc_new"); 561 fp_gdk_rgb_gc_set_foreground = 562 dl_symbol("gdk_rgb_gc_set_foreground"); 563 fp_gdk_draw_rectangle = dl_symbol("gdk_draw_rectangle"); 564 fp_gdk_drawable_get_size = dl_symbol("gdk_drawable_get_size"); 565 566 /* Pixbuf */ 567 fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new"); 568 fp_gdk_pixbuf_new_from_file = 569 dl_symbol("gdk_pixbuf_new_from_file"); 570 fp_gdk_pixbuf_get_width = dl_symbol("gdk_pixbuf_get_width"); 571 fp_gdk_pixbuf_get_height = dl_symbol("gdk_pixbuf_get_height"); 572 fp_gdk_pixbuf_get_pixels = dl_symbol("gdk_pixbuf_get_pixels"); 573 fp_gdk_pixbuf_get_rowstride = 574 dl_symbol("gdk_pixbuf_get_rowstride"); 575 fp_gdk_pixbuf_get_has_alpha = 576 dl_symbol("gdk_pixbuf_get_has_alpha"); 577 fp_gdk_pixbuf_get_bits_per_sample = 578 dl_symbol("gdk_pixbuf_get_bits_per_sample"); 579 fp_gdk_pixbuf_get_n_channels = 580 dl_symbol("gdk_pixbuf_get_n_channels"); 581 582 /* GTK painting */ 583 fp_gtk_init_check = dl_symbol("gtk_init_check"); 584 fp_gtk_paint_hline = dl_symbol("gtk_paint_hline"); 585 fp_gtk_paint_vline = dl_symbol("gtk_paint_vline"); 586 fp_gtk_paint_shadow = dl_symbol("gtk_paint_shadow"); 587 fp_gtk_paint_arrow = dl_symbol("gtk_paint_arrow"); 588 fp_gtk_paint_diamond = dl_symbol("gtk_paint_diamond"); 589 fp_gtk_paint_box = dl_symbol("gtk_paint_box"); 590 fp_gtk_paint_flat_box = dl_symbol("gtk_paint_flat_box"); 591 fp_gtk_paint_check = dl_symbol("gtk_paint_check"); 592 fp_gtk_paint_option = dl_symbol("gtk_paint_option"); 593 fp_gtk_paint_box_gap = dl_symbol("gtk_paint_box_gap"); 594 fp_gtk_paint_extension = dl_symbol("gtk_paint_extension"); 595 fp_gtk_paint_focus = dl_symbol("gtk_paint_focus"); 596 fp_gtk_paint_slider = dl_symbol("gtk_paint_slider"); 597 fp_gtk_paint_handle = dl_symbol("gtk_paint_handle"); 598 fp_gtk_paint_expander = dl_symbol("gtk_paint_expander"); 599 fp_gtk_style_apply_default_background = 600 dl_symbol("gtk_style_apply_default_background"); 601 602 /* GTK widgets */ 603 fp_gtk_arrow_new = dl_symbol("gtk_arrow_new"); 604 fp_gtk_button_new = dl_symbol("gtk_button_new"); 605 fp_gtk_spin_button_new = dl_symbol("gtk_spin_button_new"); 606 fp_gtk_check_button_new = dl_symbol("gtk_check_button_new"); 607 fp_gtk_check_menu_item_new = 608 dl_symbol("gtk_check_menu_item_new"); 609 fp_gtk_color_selection_dialog_new = 610 dl_symbol("gtk_color_selection_dialog_new"); 611 fp_gtk_entry_new = dl_symbol("gtk_entry_new"); 612 fp_gtk_fixed_new = dl_symbol("gtk_fixed_new"); 613 fp_gtk_handle_box_new = dl_symbol("gtk_handle_box_new"); 614 fp_gtk_image_new = dl_symbol("gtk_image_new"); 615 fp_gtk_hpaned_new = dl_symbol("gtk_hpaned_new"); 616 fp_gtk_vpaned_new = dl_symbol("gtk_vpaned_new"); 617 fp_gtk_hscale_new = dl_symbol("gtk_hscale_new"); 618 fp_gtk_vscale_new = dl_symbol("gtk_vscale_new"); 619 fp_gtk_hscrollbar_new = dl_symbol("gtk_hscrollbar_new"); 620 fp_gtk_vscrollbar_new = dl_symbol("gtk_vscrollbar_new"); 621 fp_gtk_hseparator_new = dl_symbol("gtk_hseparator_new"); 622 fp_gtk_vseparator_new = dl_symbol("gtk_vseparator_new"); 623 fp_gtk_label_new = dl_symbol("gtk_label_new"); 624 fp_gtk_menu_new = dl_symbol("gtk_menu_new"); 625 fp_gtk_menu_bar_new = dl_symbol("gtk_menu_bar_new"); 626 fp_gtk_menu_item_new = dl_symbol("gtk_menu_item_new"); 627 fp_gtk_menu_item_set_submenu = 628 dl_symbol("gtk_menu_item_set_submenu"); 629 fp_gtk_notebook_new = dl_symbol("gtk_notebook_new"); 630 fp_gtk_progress_bar_new = 631 dl_symbol("gtk_progress_bar_new"); 632 fp_gtk_progress_bar_set_orientation = 633 dl_symbol("gtk_progress_bar_set_orientation"); 634 fp_gtk_radio_button_new = 635 dl_symbol("gtk_radio_button_new"); 636 fp_gtk_radio_menu_item_new = 637 dl_symbol("gtk_radio_menu_item_new"); 638 fp_gtk_scrolled_window_new = 639 dl_symbol("gtk_scrolled_window_new"); 640 fp_gtk_separator_menu_item_new = 641 dl_symbol("gtk_separator_menu_item_new"); 642 fp_gtk_text_view_new = dl_symbol("gtk_text_view_new"); 643 fp_gtk_toggle_button_new = 644 dl_symbol("gtk_toggle_button_new"); 645 fp_gtk_toolbar_new = dl_symbol("gtk_toolbar_new"); 646 fp_gtk_tree_view_new = dl_symbol("gtk_tree_view_new"); 647 fp_gtk_viewport_new = dl_symbol("gtk_viewport_new"); 648 fp_gtk_window_new = dl_symbol("gtk_window_new"); 649 fp_gtk_window_present = dl_symbol("gtk_window_present"); 650 fp_gtk_window_move = dl_symbol("gtk_window_move"); 651 fp_gtk_window_resize = dl_symbol("gtk_window_resize"); 652 653 fp_gtk_dialog_new = dl_symbol("gtk_dialog_new"); 654 fp_gtk_frame_new = dl_symbol("gtk_frame_new"); 655 656 fp_gtk_adjustment_new = dl_symbol("gtk_adjustment_new"); 657 fp_gtk_container_add = dl_symbol("gtk_container_add"); 658 fp_gtk_menu_shell_append = 659 dl_symbol("gtk_menu_shell_append"); 660 fp_gtk_widget_realize = dl_symbol("gtk_widget_realize"); 661 fp_gtk_widget_destroy = dl_symbol("gtk_widget_destroy"); 662 fp_gtk_widget_render_icon = 663 dl_symbol("gtk_widget_render_icon"); 664 fp_gtk_widget_set_name = 665 dl_symbol("gtk_widget_set_name"); 666 fp_gtk_widget_set_parent = 667 dl_symbol("gtk_widget_set_parent"); 668 fp_gtk_widget_set_direction = 669 dl_symbol("gtk_widget_set_direction"); 670 fp_gtk_widget_style_get = 671 dl_symbol("gtk_widget_style_get"); 672 fp_gtk_widget_class_install_style_property = 673 dl_symbol("gtk_widget_class_install_style_property"); 674 fp_gtk_widget_class_find_style_property = 675 dl_symbol("gtk_widget_class_find_style_property"); 676 fp_gtk_widget_style_get_property = 677 dl_symbol("gtk_widget_style_get_property"); 678 fp_pango_font_description_to_string = 679 dl_symbol("pango_font_description_to_string"); 680 fp_gtk_settings_get_default = 681 dl_symbol("gtk_settings_get_default"); 682 fp_gtk_widget_get_settings = 683 dl_symbol("gtk_widget_get_settings"); 684 fp_gtk_border_get_type = dl_symbol("gtk_border_get_type"); 685 fp_gtk_arrow_set = dl_symbol("gtk_arrow_set"); 686 fp_gtk_widget_size_request = 687 dl_symbol("gtk_widget_size_request"); 688 fp_gtk_range_get_adjustment = 689 dl_symbol("gtk_range_get_adjustment"); 690 691 fp_gtk_widget_hide = dl_symbol("gtk_widget_hide"); 692 fp_gtk_main_quit = dl_symbol("gtk_main_quit"); 693 fp_g_signal_connect_data = dl_symbol("g_signal_connect_data"); 694 fp_gtk_widget_show = dl_symbol("gtk_widget_show"); 695 fp_gtk_main = dl_symbol("gtk_main"); 696 697 fp_g_path_get_dirname = dl_symbol("g_path_get_dirname"); 698 699 /** 700 * GLib thread system 701 */ 702 if (GLIB_CHECK_VERSION(2, 20, 0)) { 703 fp_g_thread_get_initialized = dl_symbol_gthread("g_thread_get_initialized"); 704 } 705 fp_g_thread_init = dl_symbol_gthread("g_thread_init"); 706 fp_gdk_threads_init = dl_symbol("gdk_threads_init"); 707 fp_gdk_threads_enter = dl_symbol("gdk_threads_enter"); 708 fp_gdk_threads_leave = dl_symbol("gdk_threads_leave"); 709 710 /** 711 * Functions for sun_awt_X11_GtkFileDialogPeer.c 712 */ 713 if (fp_gtk_check_version(2, 4, 0) == NULL) { 714 // The current GtkFileChooser is available from GTK+ 2.4 715 gtk2_file_chooser_load(); 716 } 717 718 /* Some functions may be missing in pre-2.4 GTK. 719 We handle them specially here. 720 */ 721 fp_gtk_combo_box_new = dlsym(gtk2_libhandle, "gtk_combo_box_new"); 722 if (fp_gtk_combo_box_new == NULL) { 723 fp_gtk_combo_box_new = dl_symbol("gtk_combo_new"); 724 } 725 726 fp_gtk_combo_box_entry_new = 727 dlsym(gtk2_libhandle, "gtk_combo_box_entry_new"); 728 if (fp_gtk_combo_box_entry_new == NULL) { 729 fp_gtk_combo_box_entry_new = dl_symbol("gtk_combo_new"); 730 new_combo = FALSE; 731 } 732 733 fp_gtk_separator_tool_item_new = 734 dlsym(gtk2_libhandle, "gtk_separator_tool_item_new"); 735 if (fp_gtk_separator_tool_item_new == NULL) { 736 fp_gtk_separator_tool_item_new = 737 dl_symbol("gtk_vseparator_new"); 738 } 739 } 740 /* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION 741 * Otherwise we can check the return value of setjmp method. 742 */ 743 else 744 { 745 dlclose(gtk2_libhandle); 746 gtk2_libhandle = NULL; 747 748 dlclose(gthread_libhandle); 749 gthread_libhandle = NULL; 750 751 return FALSE; 752 } 753 754 /* 755 * Strip the AT-SPI GTK_MODULES if present 756 */ 757 gtk_modules_env = getenv ("GTK_MODULES"); 758 if ((gtk_modules_env && strstr(gtk_modules_env, "atk-bridge")) || 759 (gtk_modules_env && strstr(gtk_modules_env, "gail"))) { 760 /* careful, strtok modifies its args */ 761 gchar *tmp_env = strdup(gtk_modules_env); 762 if (tmp_env) { 763 /* the new env will be smaller than the old one */ 764 gchar *s, *new_env = SAFE_SIZE_STRUCT_ALLOC(malloc, 765 sizeof(ENV_PREFIX), 1, strlen (gtk_modules_env)); 766 767 if (new_env) { 768 strcpy(new_env, ENV_PREFIX); 769 770 /* strip out 'atk-bridge' and 'gail' */ 771 size_t PREFIX_LENGTH = strlen(ENV_PREFIX); 772 gchar *tmp_ptr = NULL; 773 for (s = strtok_r(tmp_env, ":", &tmp_ptr); s; 774 s = strtok_r(NULL, ":", &tmp_ptr)) { 775 if ((!strstr(s, "atk-bridge")) && (!strstr(s, "gail"))) { 776 if (strlen(new_env) > PREFIX_LENGTH) { 777 new_env = strcat(new_env, ":"); 778 } 779 new_env = strcat(new_env, s); 780 } 781 } 782 if (putenv(new_env) != 0) { 783 /* no free() on success, putenv() doesn't copy string */ 784 free(new_env); 785 } 786 } 787 free(tmp_env); 788 } 789 } 790 /* 791 * GTK should be initialized with gtk_init_check() before use. 792 * 793 * gtk_init_check installs its own error handlers. It is critical that 794 * we preserve error handler set from AWT. Otherwise we'll crash on 795 * BadMatch errors which we would normally ignore. The IO error handler 796 * is preserved here, too, just for consistency. 797 */ 798 AWT_LOCK(); 799 handler = XSetErrorHandler(NULL); 800 io_handler = XSetIOErrorHandler(NULL); 801 802 if (fp_gtk_check_version(2, 2, 0) == NULL) { 803 jclass clazz = (*env)->FindClass(env, "sun/misc/GThreadHelper"); 804 jmethodID mid_getAndSetInitializationNeededFlag = 805 (*env)->GetStaticMethodID(env, clazz, "getAndSetInitializationNeededFlag", "()Z"); 806 jmethodID mid_lock = (*env)->GetStaticMethodID(env, clazz, "lock", "()V"); 807 jmethodID mid_unlock = (*env)->GetStaticMethodID(env, clazz, "unlock", "()V"); 808 809 // Init the thread system to use GLib in a thread-safe mode 810 (*env)->CallStaticVoidMethod(env, clazz, mid_lock); 811 812 // Calling g_thread_init() multiple times leads to crash on GLib < 2.24 813 // We can use g_thread_get_initialized () but it is available only for 814 // GLib >= 2.20. We rely on GThreadHelper for GLib < 2.20. 815 gboolean is_g_thread_get_initialized = FALSE; 816 if (GLIB_CHECK_VERSION(2, 20, 0)) { 817 is_g_thread_get_initialized = fp_g_thread_get_initialized(); 818 } 819 820 if (!(*env)->CallStaticBooleanMethod(env, clazz, mid_getAndSetInitializationNeededFlag)) { 821 if (!is_g_thread_get_initialized) { 822 fp_g_thread_init(NULL); 823 } 824 825 //According the GTK documentation, gdk_threads_init() should be 826 //called before gtk_init() or gtk_init_check() 827 fp_gdk_threads_init(); 828 } 829 (*env)->CallStaticVoidMethod(env, clazz, mid_unlock); 830 } 831 result = (*fp_gtk_init_check)(NULL, NULL); 832 833 XSetErrorHandler(handler); 834 XSetIOErrorHandler(io_handler); 835 AWT_UNLOCK(); 836 837 /* Initialize widget array. */ 838 for (i = 0; i < _GTK_WIDGET_TYPE_SIZE; i++) 839 { 840 gtk2_widgets[i] = NULL; 841 } 842 843 844 if (result) { 845 GtkApi* gtk = (GtkApi*)malloc(sizeof(GtkApi)); 846 gtk2_init(gtk); 847 return gtk; 848 } 849 return NULL; 850 } 851 852 int gtk2_unload() 853 { 854 int i; 855 char *gtk2_error; 856 857 if (!gtk2_libhandle) 858 return TRUE; 859 860 /* Release painting objects */ 861 if (gtk2_white_pixmap != NULL) { 862 (*fp_g_object_unref)(gtk2_white_pixmap); 863 (*fp_g_object_unref)(gtk2_black_pixmap); 864 (*fp_g_object_unref)(gtk2_white_pixbuf); 865 (*fp_g_object_unref)(gtk2_black_pixbuf); 866 gtk2_white_pixmap = gtk2_black_pixmap = 867 gtk2_white_pixbuf = gtk2_black_pixbuf = NULL; 868 } 869 gtk2_pixbuf_width = 0; 870 gtk2_pixbuf_height = 0; 871 872 if (gtk2_window != NULL) { 873 /* Destroying toplevel widget will destroy all contained widgets */ 874 (*fp_gtk_widget_destroy)(gtk2_window); 875 876 /* Unset some static data so they get reinitialized on next load */ 877 gtk2_window = NULL; 878 } 879 880 dlerror(); 881 dlclose(gtk2_libhandle); 882 dlclose(gthread_libhandle); 883 if ((gtk2_error = dlerror()) != NULL) 884 { 885 return FALSE; 886 } 887 return TRUE; 888 } 889 890 /* Dispatch all pending events from the GTK event loop. 891 * This is needed to catch theme change and update widgets' style. 892 */ 893 static void flush_gtk_event_loop() 894 { 895 while( (*fp_g_main_context_iteration)(NULL, FALSE)); 896 } 897 898 /* 899 * Initialize components of containment hierarchy. This creates a GtkFixed 900 * inside a GtkWindow. All widgets get realized. 901 */ 902 static void init_containers() 903 { 904 if (gtk2_window == NULL) 905 { 906 gtk2_window = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); 907 gtk2_fixed = (GtkFixed *)(*fp_gtk_fixed_new)(); 908 (*fp_gtk_container_add)((GtkContainer*)gtk2_window, 909 (GtkWidget *)gtk2_fixed); 910 (*fp_gtk_widget_realize)(gtk2_window); 911 (*fp_gtk_widget_realize)((GtkWidget *)gtk2_fixed); 912 } 913 } 914 915 /* 916 * Ensure everything is ready for drawing an element of the specified width 917 * and height. 918 * 919 * We should somehow handle translucent images. GTK can draw to X Drawables 920 * only, which don't support alpha. When we retrieve the image back from 921 * the server, translucency information is lost. There're several ways to 922 * work around this: 923 * 1) Subclass GdkPixmap and cache translucent objects on client side. This 924 * requires us to implement parts of X server drawing logic on client side. 925 * Many X requests can potentially be "translucent"; e.g. XDrawLine with 926 * fill=tile and a translucent tile is a "translucent" operation, whereas 927 * XDrawLine with fill=solid is an "opaque" one. Moreover themes can (and some 928 * do) intermix transparent and opaque operations which makes caching even 929 * more problematic. 930 * 2) Use Xorg 32bit ARGB visual when available. GDK has no native support 931 * for it (as of version 2.6). Also even in JDS 3 Xorg does not support 932 * these visuals by default, which makes optimizing for them pointless. 933 * We can consider doing this at a later point when ARGB visuals become more 934 * popular. 935 * 3') GTK has plans to use Cairo as its graphical backend (presumably in 936 * 2.8), and Cairo supports alpha. With it we could also get rid of the 937 * unnecessary round trip to server and do all the drawing on client side. 938 * 4) For now we draw to two different pixmaps and restore alpha channel by 939 * comparing results. This can be optimized by using subclassed pixmap and 940 * doing the second drawing only if necessary. 941 */ 942 static void gtk2_init_painting(JNIEnv *env, gint width, gint height) 943 { 944 GdkGC *gc; 945 GdkPixbuf *white, *black; 946 947 init_containers(); 948 949 if (gtk2_pixbuf_width < width || gtk2_pixbuf_height < height) 950 { 951 white = (*fp_gdk_pixbuf_new)(GDK_COLORSPACE_RGB, TRUE, 8, width, height); 952 black = (*fp_gdk_pixbuf_new)(GDK_COLORSPACE_RGB, TRUE, 8, width, height); 953 954 if (white == NULL || black == NULL) 955 { 956 snprintf(convertionBuffer, CONV_BUFFER_SIZE, "Couldn't create pixbuf of size %dx%d", width, height); 957 throw_exception(env, "java/lang/RuntimeException", convertionBuffer); 958 fp_gdk_threads_leave(); 959 return; 960 } 961 962 if (gtk2_white_pixmap != NULL) { 963 /* free old stuff */ 964 (*fp_g_object_unref)(gtk2_white_pixmap); 965 (*fp_g_object_unref)(gtk2_black_pixmap); 966 (*fp_g_object_unref)(gtk2_white_pixbuf); 967 (*fp_g_object_unref)(gtk2_black_pixbuf); 968 } 969 970 gtk2_white_pixmap = (*fp_gdk_pixmap_new)(gtk2_window->window, width, height, -1); 971 gtk2_black_pixmap = (*fp_gdk_pixmap_new)(gtk2_window->window, width, height, -1); 972 973 gtk2_white_pixbuf = white; 974 gtk2_black_pixbuf = black; 975 976 gtk2_pixbuf_width = width; 977 gtk2_pixbuf_height = height; 978 } 979 980 /* clear the pixmaps */ 981 gc = (*fp_gdk_gc_new)(gtk2_white_pixmap); 982 (*fp_gdk_rgb_gc_set_foreground)(gc, 0xffffff); 983 (*fp_gdk_draw_rectangle)(gtk2_white_pixmap, gc, TRUE, 0, 0, width, height); 984 (*fp_g_object_unref)(gc); 985 986 gc = (*fp_gdk_gc_new)(gtk2_black_pixmap); 987 (*fp_gdk_rgb_gc_set_foreground)(gc, 0x000000); 988 (*fp_gdk_draw_rectangle)(gtk2_black_pixmap, gc, TRUE, 0, 0, width, height); 989 (*fp_g_object_unref)(gc); 990 } 991 992 /* 993 * Restore image from white and black pixmaps and copy it into destination 994 * buffer. This method compares two pixbufs taken from white and black 995 * pixmaps and decodes color and alpha components. Pixbufs are RGB without 996 * alpha, destination buffer is ABGR. 997 * 998 * The return value is the transparency type of the resulting image, either 999 * one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and 1000 * java_awt_Transparency_TRANSLUCENT. 1001 */ 1002 static gint gtk2_copy_image(gint *dst, gint width, gint height) 1003 { 1004 gint i, j, r, g, b; 1005 guchar *white, *black; 1006 gint stride, padding; 1007 gboolean is_opaque = TRUE; 1008 gboolean is_bitmask = TRUE; 1009 1010 (*fp_gdk_pixbuf_get_from_drawable)(gtk2_white_pixbuf, gtk2_white_pixmap, 1011 NULL, 0, 0, 0, 0, width, height); 1012 (*fp_gdk_pixbuf_get_from_drawable)(gtk2_black_pixbuf, gtk2_black_pixmap, 1013 NULL, 0, 0, 0, 0, width, height); 1014 1015 white = (*fp_gdk_pixbuf_get_pixels)(gtk2_white_pixbuf); 1016 black = (*fp_gdk_pixbuf_get_pixels)(gtk2_black_pixbuf); 1017 stride = (*fp_gdk_pixbuf_get_rowstride)(gtk2_black_pixbuf); 1018 padding = stride - width * 4; 1019 1020 for (i = 0; i < height; i++) { 1021 for (j = 0; j < width; j++) { 1022 int r1 = *white++; 1023 int r2 = *black++; 1024 int alpha = 0xff + r2 - r1; 1025 1026 switch (alpha) { 1027 case 0: /* transparent pixel */ 1028 r = g = b = 0; 1029 black += 3; 1030 white += 3; 1031 is_opaque = FALSE; 1032 break; 1033 1034 case 0xff: /* opaque pixel */ 1035 r = r2; 1036 g = *black++; 1037 b = *black++; 1038 black++; 1039 white += 3; 1040 break; 1041 1042 default: /* translucent pixel */ 1043 r = 0xff * r2 / alpha; 1044 g = 0xff * *black++ / alpha; 1045 b = 0xff * *black++ / alpha; 1046 black++; 1047 white += 3; 1048 is_opaque = FALSE; 1049 is_bitmask = FALSE; 1050 break; 1051 } 1052 1053 *dst++ = (alpha << 24 | r << 16 | g << 8 | b); 1054 } 1055 1056 white += padding; 1057 black += padding; 1058 } 1059 return is_opaque ? java_awt_Transparency_OPAQUE : 1060 (is_bitmask ? java_awt_Transparency_BITMASK : 1061 java_awt_Transparency_TRANSLUCENT); 1062 } 1063 1064 static void 1065 gtk2_set_direction(GtkWidget *widget, GtkTextDirection dir) 1066 { 1067 /* 1068 * Some engines (inexplicably) look at the direction of the widget's 1069 * parent, so we need to set the direction of both the widget and its 1070 * parent. 1071 */ 1072 (*fp_gtk_widget_set_direction)(widget, dir); 1073 if (widget->parent != NULL) { 1074 (*fp_gtk_widget_set_direction)(widget->parent, dir); 1075 } 1076 } 1077 1078 /* 1079 * Initializes the widget to correct state for some engines. 1080 * This is a pure empirical method. 1081 */ 1082 static void init_toggle_widget(WidgetType widget_type, gint synth_state) 1083 { 1084 gboolean is_active = ((synth_state & SELECTED) != 0); 1085 1086 if (widget_type == RADIO_BUTTON || 1087 widget_type == CHECK_BOX || 1088 widget_type == TOGGLE_BUTTON) { 1089 ((GtkToggleButton*)gtk2_widget)->active = is_active; 1090 } 1091 1092 if ((synth_state & FOCUSED) != 0) { 1093 ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS; 1094 } else { 1095 ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS; 1096 } 1097 1098 if ((synth_state & MOUSE_OVER) != 0 && (synth_state & PRESSED) == 0 || 1099 (synth_state & FOCUSED) != 0 && (synth_state & PRESSED) != 0) { 1100 gtk2_widget->state = GTK_STATE_PRELIGHT; 1101 } else if ((synth_state & DISABLED) != 0) { 1102 gtk2_widget->state = GTK_STATE_INSENSITIVE; 1103 } else { 1104 gtk2_widget->state = is_active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL; 1105 } 1106 } 1107 1108 /* GTK state_type filter */ 1109 static GtkStateType get_gtk_state_type(WidgetType widget_type, gint synth_state) 1110 { 1111 GtkStateType result = GTK_STATE_NORMAL; 1112 1113 if ((synth_state & DISABLED) != 0) { 1114 result = GTK_STATE_INSENSITIVE; 1115 } else if ((synth_state & PRESSED) != 0) { 1116 result = GTK_STATE_ACTIVE; 1117 } else if ((synth_state & MOUSE_OVER) != 0) { 1118 result = GTK_STATE_PRELIGHT; 1119 } 1120 return result; 1121 } 1122 1123 /* GTK shadow_type filter */ 1124 static GtkShadowType get_gtk_shadow_type(WidgetType widget_type, gint synth_state) 1125 { 1126 GtkShadowType result = GTK_SHADOW_OUT; 1127 1128 if ((synth_state & SELECTED) != 0) { 1129 result = GTK_SHADOW_IN; 1130 } 1131 return result; 1132 } 1133 1134 1135 static GtkWidget* gtk2_get_arrow(GtkArrowType arrow_type, GtkShadowType shadow_type) 1136 { 1137 GtkWidget *arrow = NULL; 1138 if (NULL == gtk2_widgets[_GTK_ARROW_TYPE]) 1139 { 1140 gtk2_widgets[_GTK_ARROW_TYPE] = (*fp_gtk_arrow_new)(arrow_type, shadow_type); 1141 (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, gtk2_widgets[_GTK_ARROW_TYPE]); 1142 (*fp_gtk_widget_realize)(gtk2_widgets[_GTK_ARROW_TYPE]); 1143 } 1144 arrow = gtk2_widgets[_GTK_ARROW_TYPE]; 1145 1146 (*fp_gtk_arrow_set)(arrow, arrow_type, shadow_type); 1147 return arrow; 1148 } 1149 1150 static GtkAdjustment* create_adjustment() 1151 { 1152 return (GtkAdjustment *) 1153 (*fp_gtk_adjustment_new)(50.0, 0.0, 100.0, 10.0, 20.0, 20.0); 1154 } 1155 1156 /** 1157 * Returns a pointer to the cached native widget for the specified widget 1158 * type. 1159 */ 1160 static GtkWidget *gtk2_get_widget(WidgetType widget_type) 1161 { 1162 gboolean init_result = FALSE; 1163 GtkWidget *result = NULL; 1164 switch (widget_type) 1165 { 1166 case BUTTON: 1167 case TABLE_HEADER: 1168 if (init_result = (NULL == gtk2_widgets[_GTK_BUTTON_TYPE])) 1169 { 1170 gtk2_widgets[_GTK_BUTTON_TYPE] = (*fp_gtk_button_new)(); 1171 } 1172 result = gtk2_widgets[_GTK_BUTTON_TYPE]; 1173 break; 1174 case CHECK_BOX: 1175 if (init_result = (NULL == gtk2_widgets[_GTK_CHECK_BUTTON_TYPE])) 1176 { 1177 gtk2_widgets[_GTK_CHECK_BUTTON_TYPE] = 1178 (*fp_gtk_check_button_new)(); 1179 } 1180 result = gtk2_widgets[_GTK_CHECK_BUTTON_TYPE]; 1181 break; 1182 case CHECK_BOX_MENU_ITEM: 1183 if (init_result = (NULL == gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE])) 1184 { 1185 gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE] = 1186 (*fp_gtk_check_menu_item_new)(); 1187 } 1188 result = gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE]; 1189 break; 1190 /************************************************************ 1191 * Creation a dedicated color chooser is dangerous because 1192 * it deadlocks the EDT 1193 ************************************************************/ 1194 /* case COLOR_CHOOSER: 1195 if (init_result = 1196 (NULL == gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE])) 1197 { 1198 gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE] = 1199 (*fp_gtk_color_selection_dialog_new)(NULL); 1200 } 1201 result = gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE]; 1202 break;*/ 1203 case COMBO_BOX: 1204 if (init_result = (NULL == gtk2_widgets[_GTK_COMBO_BOX_TYPE])) 1205 { 1206 gtk2_widgets[_GTK_COMBO_BOX_TYPE] = 1207 (*fp_gtk_combo_box_new)(); 1208 } 1209 result = gtk2_widgets[_GTK_COMBO_BOX_TYPE]; 1210 break; 1211 case COMBO_BOX_ARROW_BUTTON: 1212 if (init_result = 1213 (NULL == gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE])) 1214 { 1215 gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE] = 1216 (*fp_gtk_toggle_button_new)(); 1217 } 1218 result = gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE]; 1219 break; 1220 case COMBO_BOX_TEXT_FIELD: 1221 if (init_result = 1222 (NULL == gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE])) 1223 { 1224 result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] = 1225 (*fp_gtk_entry_new)(); 1226 } 1227 result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE]; 1228 break; 1229 case DESKTOP_ICON: 1230 case INTERNAL_FRAME_TITLE_PANE: 1231 case LABEL: 1232 if (init_result = (NULL == gtk2_widgets[_GTK_LABEL_TYPE])) 1233 { 1234 gtk2_widgets[_GTK_LABEL_TYPE] = 1235 (*fp_gtk_label_new)(NULL); 1236 } 1237 result = gtk2_widgets[_GTK_LABEL_TYPE]; 1238 break; 1239 case DESKTOP_PANE: 1240 case PANEL: 1241 case ROOT_PANE: 1242 if (init_result = (NULL == gtk2_widgets[_GTK_CONTAINER_TYPE])) 1243 { 1244 /* There is no constructor for a container type. I've 1245 * chosen GtkFixed container since it has a default 1246 * constructor. 1247 */ 1248 gtk2_widgets[_GTK_CONTAINER_TYPE] = 1249 (*fp_gtk_fixed_new)(); 1250 } 1251 result = gtk2_widgets[_GTK_CONTAINER_TYPE]; 1252 break; 1253 case EDITOR_PANE: 1254 case TEXT_AREA: 1255 case TEXT_PANE: 1256 if (init_result = (NULL == gtk2_widgets[_GTK_TEXT_VIEW_TYPE])) 1257 { 1258 gtk2_widgets[_GTK_TEXT_VIEW_TYPE] = 1259 (*fp_gtk_text_view_new)(); 1260 } 1261 result = gtk2_widgets[_GTK_TEXT_VIEW_TYPE]; 1262 break; 1263 case FORMATTED_TEXT_FIELD: 1264 case PASSWORD_FIELD: 1265 case TEXT_FIELD: 1266 if (init_result = (NULL == gtk2_widgets[_GTK_ENTRY_TYPE])) 1267 { 1268 gtk2_widgets[_GTK_ENTRY_TYPE] = 1269 (*fp_gtk_entry_new)(); 1270 } 1271 result = gtk2_widgets[_GTK_ENTRY_TYPE]; 1272 break; 1273 case HANDLE_BOX: 1274 if (init_result = (NULL == gtk2_widgets[_GTK_HANDLE_BOX_TYPE])) 1275 { 1276 gtk2_widgets[_GTK_HANDLE_BOX_TYPE] = 1277 (*fp_gtk_handle_box_new)(); 1278 } 1279 result = gtk2_widgets[_GTK_HANDLE_BOX_TYPE]; 1280 break; 1281 case HSCROLL_BAR: 1282 case HSCROLL_BAR_BUTTON_LEFT: 1283 case HSCROLL_BAR_BUTTON_RIGHT: 1284 case HSCROLL_BAR_TRACK: 1285 case HSCROLL_BAR_THUMB: 1286 if (init_result = (NULL == gtk2_widgets[_GTK_HSCROLLBAR_TYPE])) 1287 { 1288 gtk2_widgets[_GTK_HSCROLLBAR_TYPE] = 1289 (*fp_gtk_hscrollbar_new)(create_adjustment()); 1290 } 1291 result = gtk2_widgets[_GTK_HSCROLLBAR_TYPE]; 1292 break; 1293 case HSEPARATOR: 1294 if (init_result = (NULL == gtk2_widgets[_GTK_HSEPARATOR_TYPE])) 1295 { 1296 gtk2_widgets[_GTK_HSEPARATOR_TYPE] = 1297 (*fp_gtk_hseparator_new)(); 1298 } 1299 result = gtk2_widgets[_GTK_HSEPARATOR_TYPE]; 1300 break; 1301 case HSLIDER: 1302 case HSLIDER_THUMB: 1303 case HSLIDER_TRACK: 1304 if (init_result = (NULL == gtk2_widgets[_GTK_HSCALE_TYPE])) 1305 { 1306 gtk2_widgets[_GTK_HSCALE_TYPE] = 1307 (*fp_gtk_hscale_new)(NULL); 1308 } 1309 result = gtk2_widgets[_GTK_HSCALE_TYPE]; 1310 break; 1311 case HSPLIT_PANE_DIVIDER: 1312 case SPLIT_PANE: 1313 if (init_result = (NULL == gtk2_widgets[_GTK_HPANED_TYPE])) 1314 { 1315 gtk2_widgets[_GTK_HPANED_TYPE] = (*fp_gtk_hpaned_new)(); 1316 } 1317 result = gtk2_widgets[_GTK_HPANED_TYPE]; 1318 break; 1319 case IMAGE: 1320 if (init_result = (NULL == gtk2_widgets[_GTK_IMAGE_TYPE])) 1321 { 1322 gtk2_widgets[_GTK_IMAGE_TYPE] = (*fp_gtk_image_new)(); 1323 } 1324 result = gtk2_widgets[_GTK_IMAGE_TYPE]; 1325 break; 1326 case INTERNAL_FRAME: 1327 if (init_result = (NULL == gtk2_widgets[_GTK_WINDOW_TYPE])) 1328 { 1329 gtk2_widgets[_GTK_WINDOW_TYPE] = 1330 (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); 1331 } 1332 result = gtk2_widgets[_GTK_WINDOW_TYPE]; 1333 break; 1334 case TOOL_TIP: 1335 if (init_result = (NULL == gtk2_widgets[_GTK_TOOLTIP_TYPE])) 1336 { 1337 result = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); 1338 (*fp_gtk_widget_set_name)(result, "gtk-tooltips"); 1339 gtk2_widgets[_GTK_TOOLTIP_TYPE] = result; 1340 } 1341 result = gtk2_widgets[_GTK_TOOLTIP_TYPE]; 1342 break; 1343 case LIST: 1344 case TABLE: 1345 case TREE: 1346 case TREE_CELL: 1347 if (init_result = (NULL == gtk2_widgets[_GTK_TREE_VIEW_TYPE])) 1348 { 1349 gtk2_widgets[_GTK_TREE_VIEW_TYPE] = 1350 (*fp_gtk_tree_view_new)(); 1351 } 1352 result = gtk2_widgets[_GTK_TREE_VIEW_TYPE]; 1353 break; 1354 case TITLED_BORDER: 1355 if (init_result = (NULL == gtk2_widgets[_GTK_FRAME_TYPE])) 1356 { 1357 gtk2_widgets[_GTK_FRAME_TYPE] = fp_gtk_frame_new(NULL); 1358 } 1359 result = gtk2_widgets[_GTK_FRAME_TYPE]; 1360 break; 1361 case POPUP_MENU: 1362 if (init_result = (NULL == gtk2_widgets[_GTK_MENU_TYPE])) 1363 { 1364 gtk2_widgets[_GTK_MENU_TYPE] = 1365 (*fp_gtk_menu_new)(); 1366 } 1367 result = gtk2_widgets[_GTK_MENU_TYPE]; 1368 break; 1369 case MENU: 1370 case MENU_ITEM: 1371 case MENU_ITEM_ACCELERATOR: 1372 if (init_result = (NULL == gtk2_widgets[_GTK_MENU_ITEM_TYPE])) 1373 { 1374 gtk2_widgets[_GTK_MENU_ITEM_TYPE] = 1375 (*fp_gtk_menu_item_new)(); 1376 } 1377 result = gtk2_widgets[_GTK_MENU_ITEM_TYPE]; 1378 break; 1379 case MENU_BAR: 1380 if (init_result = (NULL == gtk2_widgets[_GTK_MENU_BAR_TYPE])) 1381 { 1382 gtk2_widgets[_GTK_MENU_BAR_TYPE] = 1383 (*fp_gtk_menu_bar_new)(); 1384 } 1385 result = gtk2_widgets[_GTK_MENU_BAR_TYPE]; 1386 break; 1387 case COLOR_CHOOSER: 1388 case OPTION_PANE: 1389 if (init_result = (NULL == gtk2_widgets[_GTK_DIALOG_TYPE])) 1390 { 1391 gtk2_widgets[_GTK_DIALOG_TYPE] = 1392 (*fp_gtk_dialog_new)(); 1393 } 1394 result = gtk2_widgets[_GTK_DIALOG_TYPE]; 1395 break; 1396 case POPUP_MENU_SEPARATOR: 1397 if (init_result = 1398 (NULL == gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE])) 1399 { 1400 gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE] = 1401 (*fp_gtk_separator_menu_item_new)(); 1402 } 1403 result = gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE]; 1404 break; 1405 case HPROGRESS_BAR: 1406 if (init_result = (NULL == gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE])) 1407 { 1408 gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE] = 1409 (*fp_gtk_progress_bar_new)(); 1410 } 1411 result = gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE]; 1412 break; 1413 case VPROGRESS_BAR: 1414 if (init_result = (NULL == gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE])) 1415 { 1416 gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE] = 1417 (*fp_gtk_progress_bar_new)(); 1418 /* 1419 * Vertical JProgressBars always go bottom-to-top, 1420 * regardless of the ComponentOrientation. 1421 */ 1422 (*fp_gtk_progress_bar_set_orientation)( 1423 (GtkProgressBar *)gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE], 1424 GTK_PROGRESS_BOTTOM_TO_TOP); 1425 } 1426 result = gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE]; 1427 break; 1428 case RADIO_BUTTON: 1429 if (init_result = (NULL == gtk2_widgets[_GTK_RADIO_BUTTON_TYPE])) 1430 { 1431 gtk2_widgets[_GTK_RADIO_BUTTON_TYPE] = 1432 (*fp_gtk_radio_button_new)(NULL); 1433 } 1434 result = gtk2_widgets[_GTK_RADIO_BUTTON_TYPE]; 1435 break; 1436 case RADIO_BUTTON_MENU_ITEM: 1437 if (init_result = 1438 (NULL == gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE])) 1439 { 1440 gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE] = 1441 (*fp_gtk_radio_menu_item_new)(NULL); 1442 } 1443 result = gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE]; 1444 break; 1445 case SCROLL_PANE: 1446 if (init_result = 1447 (NULL == gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE])) 1448 { 1449 gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE] = 1450 (*fp_gtk_scrolled_window_new)(NULL, NULL); 1451 } 1452 result = gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE]; 1453 break; 1454 case SPINNER: 1455 case SPINNER_ARROW_BUTTON: 1456 case SPINNER_TEXT_FIELD: 1457 if (init_result = (NULL == gtk2_widgets[_GTK_SPIN_BUTTON_TYPE])) 1458 { 1459 result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE] = 1460 (*fp_gtk_spin_button_new)(NULL, 0, 0); 1461 } 1462 result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE]; 1463 break; 1464 case TABBED_PANE: 1465 case TABBED_PANE_TAB_AREA: 1466 case TABBED_PANE_CONTENT: 1467 case TABBED_PANE_TAB: 1468 if (init_result = (NULL == gtk2_widgets[_GTK_NOTEBOOK_TYPE])) 1469 { 1470 gtk2_widgets[_GTK_NOTEBOOK_TYPE] = 1471 (*fp_gtk_notebook_new)(NULL); 1472 } 1473 result = gtk2_widgets[_GTK_NOTEBOOK_TYPE]; 1474 break; 1475 case TOGGLE_BUTTON: 1476 if (init_result = (NULL == gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE])) 1477 { 1478 gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE] = 1479 (*fp_gtk_toggle_button_new)(NULL); 1480 } 1481 result = gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE]; 1482 break; 1483 case TOOL_BAR: 1484 case TOOL_BAR_DRAG_WINDOW: 1485 if (init_result = (NULL == gtk2_widgets[_GTK_TOOLBAR_TYPE])) 1486 { 1487 gtk2_widgets[_GTK_TOOLBAR_TYPE] = 1488 (*fp_gtk_toolbar_new)(NULL); 1489 } 1490 result = gtk2_widgets[_GTK_TOOLBAR_TYPE]; 1491 break; 1492 case TOOL_BAR_SEPARATOR: 1493 if (init_result = 1494 (NULL == gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE])) 1495 { 1496 gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE] = 1497 (*fp_gtk_separator_tool_item_new)(); 1498 } 1499 result = gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE]; 1500 break; 1501 case VIEWPORT: 1502 if (init_result = (NULL == gtk2_widgets[_GTK_VIEWPORT_TYPE])) 1503 { 1504 GtkAdjustment *adjustment = create_adjustment(); 1505 gtk2_widgets[_GTK_VIEWPORT_TYPE] = 1506 (*fp_gtk_viewport_new)(adjustment, adjustment); 1507 } 1508 result = gtk2_widgets[_GTK_VIEWPORT_TYPE]; 1509 break; 1510 case VSCROLL_BAR: 1511 case VSCROLL_BAR_BUTTON_UP: 1512 case VSCROLL_BAR_BUTTON_DOWN: 1513 case VSCROLL_BAR_TRACK: 1514 case VSCROLL_BAR_THUMB: 1515 if (init_result = (NULL == gtk2_widgets[_GTK_VSCROLLBAR_TYPE])) 1516 { 1517 gtk2_widgets[_GTK_VSCROLLBAR_TYPE] = 1518 (*fp_gtk_vscrollbar_new)(create_adjustment()); 1519 } 1520 result = gtk2_widgets[_GTK_VSCROLLBAR_TYPE]; 1521 break; 1522 case VSEPARATOR: 1523 if (init_result = (NULL == gtk2_widgets[_GTK_VSEPARATOR_TYPE])) 1524 { 1525 gtk2_widgets[_GTK_VSEPARATOR_TYPE] = 1526 (*fp_gtk_vseparator_new)(); 1527 } 1528 result = gtk2_widgets[_GTK_VSEPARATOR_TYPE]; 1529 break; 1530 case VSLIDER: 1531 case VSLIDER_THUMB: 1532 case VSLIDER_TRACK: 1533 if (init_result = (NULL == gtk2_widgets[_GTK_VSCALE_TYPE])) 1534 { 1535 gtk2_widgets[_GTK_VSCALE_TYPE] = 1536 (*fp_gtk_vscale_new)(NULL); 1537 } 1538 result = gtk2_widgets[_GTK_VSCALE_TYPE]; 1539 /* 1540 * Vertical JSliders start at the bottom, while vertical 1541 * GtkVScale widgets start at the top (by default), so to fix 1542 * this we set the "inverted" flag to get the Swing behavior. 1543 */ 1544 ((GtkRange*)result)->inverted = 1; 1545 break; 1546 case VSPLIT_PANE_DIVIDER: 1547 if (init_result = (NULL == gtk2_widgets[_GTK_VPANED_TYPE])) 1548 { 1549 gtk2_widgets[_GTK_VPANED_TYPE] = (*fp_gtk_vpaned_new)(); 1550 } 1551 result = gtk2_widgets[_GTK_VPANED_TYPE]; 1552 break; 1553 default: 1554 result = NULL; 1555 break; 1556 } 1557 1558 if (result != NULL && init_result) 1559 { 1560 if (widget_type == RADIO_BUTTON_MENU_ITEM || 1561 widget_type == CHECK_BOX_MENU_ITEM || 1562 widget_type == MENU_ITEM || 1563 widget_type == MENU || 1564 widget_type == POPUP_MENU_SEPARATOR) 1565 { 1566 GtkWidget *menu = gtk2_get_widget(POPUP_MENU); 1567 (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu, result); 1568 } 1569 else if (widget_type == POPUP_MENU) 1570 { 1571 GtkWidget *menu_bar = gtk2_get_widget(MENU_BAR); 1572 GtkWidget *root_menu = (*fp_gtk_menu_item_new)(); 1573 (*fp_gtk_menu_item_set_submenu)((GtkMenuItem*)root_menu, result); 1574 (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu_bar, root_menu); 1575 } 1576 else if (widget_type == COMBO_BOX_ARROW_BUTTON || 1577 widget_type == COMBO_BOX_TEXT_FIELD) 1578 { 1579 /* 1580 * We add a regular GtkButton/GtkEntry to a GtkComboBoxEntry 1581 * in order to trick engines into thinking it's a real combobox 1582 * arrow button/text field. 1583 */ 1584 GtkWidget *combo = (*fp_gtk_combo_box_entry_new)(); 1585 1586 if (new_combo && widget_type == COMBO_BOX_ARROW_BUTTON) { 1587 (*fp_gtk_widget_set_parent)(result, combo); 1588 ((GtkBin*)combo)->child = result; 1589 } else { 1590 (*fp_gtk_container_add)((GtkContainer *)combo, result); 1591 } 1592 (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, combo); 1593 } 1594 else if (widget_type != TOOL_TIP && 1595 widget_type != INTERNAL_FRAME && 1596 widget_type != OPTION_PANE) 1597 { 1598 (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, result); 1599 } 1600 (*fp_gtk_widget_realize)(result); 1601 } 1602 return result; 1603 } 1604 1605 void gtk2_paint_arrow(WidgetType widget_type, GtkStateType state_type, 1606 GtkShadowType shadow_type, const gchar *detail, 1607 gint x, gint y, gint width, gint height, 1608 GtkArrowType arrow_type, gboolean fill) 1609 { 1610 static int w, h; 1611 static GtkRequisition size; 1612 1613 if (widget_type == COMBO_BOX_ARROW_BUTTON || widget_type == TABLE) 1614 gtk2_widget = gtk2_get_arrow(arrow_type, shadow_type); 1615 else 1616 gtk2_widget = gtk2_get_widget(widget_type); 1617 1618 switch (widget_type) 1619 { 1620 case SPINNER_ARROW_BUTTON: 1621 x = 1; 1622 y = ((arrow_type == GTK_ARROW_UP) ? 2 : 0); 1623 height -= 2; 1624 width -= 3; 1625 1626 w = width / 2; 1627 w -= w % 2 - 1; 1628 h = (w + 1) / 2; 1629 break; 1630 1631 case HSCROLL_BAR_BUTTON_LEFT: 1632 case HSCROLL_BAR_BUTTON_RIGHT: 1633 case VSCROLL_BAR_BUTTON_UP: 1634 case VSCROLL_BAR_BUTTON_DOWN: 1635 w = width / 2; 1636 h = height / 2; 1637 break; 1638 1639 case COMBO_BOX_ARROW_BUTTON: 1640 case TABLE: 1641 x = 1; 1642 (*fp_gtk_widget_size_request)(gtk2_widget, &size); 1643 w = size.width - ((GtkMisc*)gtk2_widget)->xpad * 2; 1644 h = size.height - ((GtkMisc*)gtk2_widget)->ypad * 2; 1645 w = h = MIN(MIN(w, h), MIN(width,height)) * 0.7; 1646 break; 1647 1648 default: 1649 w = width; 1650 h = height; 1651 break; 1652 } 1653 x += (width - w) / 2; 1654 y += (height - h) / 2; 1655 1656 (*fp_gtk_paint_arrow)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1657 shadow_type, NULL, gtk2_widget, detail, arrow_type, fill, 1658 x, y, w, h); 1659 (*fp_gtk_paint_arrow)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1660 shadow_type, NULL, gtk2_widget, detail, arrow_type, fill, 1661 x, y, w, h); 1662 } 1663 1664 static void gtk2_paint_box(WidgetType widget_type, GtkStateType state_type, 1665 GtkShadowType shadow_type, const gchar *detail, 1666 gint x, gint y, gint width, gint height, 1667 gint synth_state, GtkTextDirection dir) 1668 { 1669 gtk2_widget = gtk2_get_widget(widget_type); 1670 1671 /* 1672 * The clearlooks engine sometimes looks at the widget's state field 1673 * instead of just the state_type variable that we pass in, so to account 1674 * for those cases we set the widget's state field accordingly. The 1675 * flags field is similarly important for things like focus/default state. 1676 */ 1677 gtk2_widget->state = state_type; 1678 1679 if (widget_type == HSLIDER_TRACK) { 1680 /* 1681 * For horizontal JSliders with right-to-left orientation, we need 1682 * to set the "inverted" flag to match the native GTK behavior where 1683 * the foreground highlight is on the right side of the slider thumb. 1684 * This is needed especially for the ubuntulooks engine, which looks 1685 * exclusively at the "inverted" flag to determine on which side of 1686 * the thumb to paint the highlight... 1687 */ 1688 ((GtkRange*)gtk2_widget)->inverted = (dir == GTK_TEXT_DIR_RTL); 1689 1690 /* 1691 * Note however that other engines like clearlooks will look at both 1692 * the "inverted" field and the text direction to determine how 1693 * the foreground highlight is painted: 1694 * !inverted && ltr --> paint highlight on left side 1695 * !inverted && rtl --> paint highlight on right side 1696 * inverted && ltr --> paint highlight on right side 1697 * inverted && rtl --> paint highlight on left side 1698 * So the only way to reliably get the desired results for horizontal 1699 * JSlider (i.e., highlight on left side for LTR ComponentOrientation 1700 * and highlight on right side for RTL ComponentOrientation) is to 1701 * always override text direction as LTR, and then set the "inverted" 1702 * flag accordingly (as we have done above). 1703 */ 1704 dir = GTK_TEXT_DIR_LTR; 1705 } 1706 1707 /* 1708 * Some engines (e.g. clearlooks) will paint the shadow of certain 1709 * widgets (e.g. COMBO_BOX_ARROW_BUTTON) differently depending on the 1710 * the text direction. 1711 */ 1712 gtk2_set_direction(gtk2_widget, dir); 1713 1714 switch (widget_type) { 1715 case BUTTON: 1716 if (synth_state & DEFAULT) { 1717 ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_DEFAULT; 1718 } else { 1719 ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_DEFAULT; 1720 } 1721 break; 1722 case TOGGLE_BUTTON: 1723 init_toggle_widget(widget_type, synth_state); 1724 break; 1725 case HSCROLL_BAR_BUTTON_LEFT: 1726 /* 1727 * The clearlooks engine will draw a "left" button when: 1728 * x == w->allocation.x 1729 * 1730 * The ubuntulooks engine will draw a "left" button when: 1731 * [x,y,width,height] 1732 * intersects 1733 * [w->alloc.x,w->alloc.y,width,height] 1734 * 1735 * The values that are set below should ensure that a "left" 1736 * button is rendered for both of these (and other) engines. 1737 */ 1738 gtk2_widget->allocation.x = x; 1739 gtk2_widget->allocation.y = y; 1740 gtk2_widget->allocation.width = width; 1741 gtk2_widget->allocation.height = height; 1742 break; 1743 case HSCROLL_BAR_BUTTON_RIGHT: 1744 /* 1745 * The clearlooks engine will draw a "right" button when: 1746 * x + width == w->allocation.x + w->allocation.width 1747 * 1748 * The ubuntulooks engine will draw a "right" button when: 1749 * [x,y,width,height] 1750 * does not intersect 1751 * [w->alloc.x,w->alloc.y,width,height] 1752 * but does intersect 1753 * [w->alloc.x+width,w->alloc.y,width,height] 1754 * 1755 * The values that are set below should ensure that a "right" 1756 * button is rendered for both of these (and other) engines. 1757 */ 1758 gtk2_widget->allocation.x = x+width; 1759 gtk2_widget->allocation.y = 0; 1760 gtk2_widget->allocation.width = 0; 1761 gtk2_widget->allocation.height = height; 1762 break; 1763 case VSCROLL_BAR_BUTTON_UP: 1764 /* 1765 * The clearlooks engine will draw an "up" button when: 1766 * y == w->allocation.y 1767 * 1768 * The ubuntulooks engine will draw an "up" button when: 1769 * [x,y,width,height] 1770 * intersects 1771 * [w->alloc.x,w->alloc.y,width,height] 1772 * 1773 * The values that are set below should ensure that an "up" 1774 * button is rendered for both of these (and other) engines. 1775 */ 1776 gtk2_widget->allocation.x = x; 1777 gtk2_widget->allocation.y = y; 1778 gtk2_widget->allocation.width = width; 1779 gtk2_widget->allocation.height = height; 1780 break; 1781 case VSCROLL_BAR_BUTTON_DOWN: 1782 /* 1783 * The clearlooks engine will draw a "down" button when: 1784 * y + height == w->allocation.y + w->allocation.height 1785 * 1786 * The ubuntulooks engine will draw a "down" button when: 1787 * [x,y,width,height] 1788 * does not intersect 1789 * [w->alloc.x,w->alloc.y,width,height] 1790 * but does intersect 1791 * [w->alloc.x,w->alloc.y+height,width,height] 1792 * 1793 * The values that are set below should ensure that a "down" 1794 * button is rendered for both of these (and other) engines. 1795 */ 1796 gtk2_widget->allocation.x = x; 1797 gtk2_widget->allocation.y = y+height; 1798 gtk2_widget->allocation.width = width; 1799 gtk2_widget->allocation.height = 0; 1800 break; 1801 default: 1802 break; 1803 } 1804 1805 (*fp_gtk_paint_box)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1806 shadow_type, NULL, gtk2_widget, detail, x, y, width, height); 1807 (*fp_gtk_paint_box)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1808 shadow_type, NULL, gtk2_widget, detail, x, y, width, height); 1809 1810 /* 1811 * Reset the text direction to the default value so that we don't 1812 * accidentally affect other operations and widgets. 1813 */ 1814 gtk2_set_direction(gtk2_widget, GTK_TEXT_DIR_LTR); 1815 } 1816 1817 void gtk2_paint_box_gap(WidgetType widget_type, GtkStateType state_type, 1818 GtkShadowType shadow_type, const gchar *detail, 1819 gint x, gint y, gint width, gint height, 1820 GtkPositionType gap_side, gint gap_x, gint gap_width) 1821 { 1822 /* Clearlooks needs a real clip area to paint the gap properly */ 1823 GdkRectangle area = { x, y, width, height }; 1824 1825 gtk2_widget = gtk2_get_widget(widget_type); 1826 (*fp_gtk_paint_box_gap)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1827 shadow_type, &area, gtk2_widget, detail, 1828 x, y, width, height, gap_side, gap_x, gap_width); 1829 (*fp_gtk_paint_box_gap)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1830 shadow_type, &area, gtk2_widget, detail, 1831 x, y, width, height, gap_side, gap_x, gap_width); 1832 } 1833 1834 static void gtk2_paint_check(WidgetType widget_type, gint synth_state, 1835 const gchar *detail, gint x, gint y, gint width, gint height) 1836 { 1837 GtkStateType state_type = get_gtk_state_type(widget_type, synth_state); 1838 GtkShadowType shadow_type = get_gtk_shadow_type(widget_type, synth_state); 1839 1840 gtk2_widget = gtk2_get_widget(widget_type); 1841 init_toggle_widget(widget_type, synth_state); 1842 1843 (*fp_gtk_paint_check)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1844 shadow_type, NULL, gtk2_widget, detail, 1845 x, y, width, height); 1846 (*fp_gtk_paint_check)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1847 shadow_type, NULL, gtk2_widget, detail, 1848 x, y, width, height); 1849 } 1850 1851 static void gtk2_paint_diamond(WidgetType widget_type, GtkStateType state_type, 1852 GtkShadowType shadow_type, const gchar *detail, 1853 gint x, gint y, gint width, gint height) 1854 { 1855 gtk2_widget = gtk2_get_widget(widget_type); 1856 (*fp_gtk_paint_diamond)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1857 shadow_type, NULL, gtk2_widget, detail, 1858 x, y, width, height); 1859 (*fp_gtk_paint_diamond)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1860 shadow_type, NULL, gtk2_widget, detail, 1861 x, y, width, height); 1862 } 1863 1864 static void gtk2_paint_expander(WidgetType widget_type, GtkStateType state_type, 1865 const gchar *detail, gint x, gint y, gint width, gint height, 1866 GtkExpanderStyle expander_style) 1867 { 1868 gtk2_widget = gtk2_get_widget(widget_type); 1869 (*fp_gtk_paint_expander)(gtk2_widget->style, gtk2_white_pixmap, 1870 state_type, NULL, gtk2_widget, detail, 1871 x + width / 2, y + height / 2, expander_style); 1872 (*fp_gtk_paint_expander)(gtk2_widget->style, gtk2_black_pixmap, 1873 state_type, NULL, gtk2_widget, detail, 1874 x + width / 2, y + height / 2, expander_style); 1875 } 1876 1877 static void gtk2_paint_extension(WidgetType widget_type, GtkStateType state_type, 1878 GtkShadowType shadow_type, const gchar *detail, 1879 gint x, gint y, gint width, gint height, GtkPositionType gap_side) 1880 { 1881 gtk2_widget = gtk2_get_widget(widget_type); 1882 (*fp_gtk_paint_extension)(gtk2_widget->style, gtk2_white_pixmap, 1883 state_type, shadow_type, NULL, gtk2_widget, detail, 1884 x, y, width, height, gap_side); 1885 (*fp_gtk_paint_extension)(gtk2_widget->style, gtk2_black_pixmap, 1886 state_type, shadow_type, NULL, gtk2_widget, detail, 1887 x, y, width, height, gap_side); 1888 } 1889 1890 static void gtk2_paint_flat_box(WidgetType widget_type, GtkStateType state_type, 1891 GtkShadowType shadow_type, const gchar *detail, 1892 gint x, gint y, gint width, gint height, gboolean has_focus) 1893 { 1894 gtk2_widget = gtk2_get_widget(widget_type); 1895 1896 if (has_focus) 1897 ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS; 1898 else 1899 ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS; 1900 1901 (*fp_gtk_paint_flat_box)(gtk2_widget->style, gtk2_white_pixmap, 1902 state_type, shadow_type, NULL, gtk2_widget, detail, 1903 x, y, width, height); 1904 (*fp_gtk_paint_flat_box)(gtk2_widget->style, gtk2_black_pixmap, 1905 state_type, shadow_type, NULL, gtk2_widget, detail, 1906 x, y, width, height); 1907 } 1908 1909 static void gtk2_paint_focus(WidgetType widget_type, GtkStateType state_type, 1910 const char *detail, gint x, gint y, gint width, gint height) 1911 { 1912 gtk2_widget = gtk2_get_widget(widget_type); 1913 (*fp_gtk_paint_focus)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1914 NULL, gtk2_widget, detail, x, y, width, height); 1915 (*fp_gtk_paint_focus)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1916 NULL, gtk2_widget, detail, x, y, width, height); 1917 } 1918 1919 static void gtk2_paint_handle(WidgetType widget_type, GtkStateType state_type, 1920 GtkShadowType shadow_type, const gchar *detail, 1921 gint x, gint y, gint width, gint height, GtkOrientation orientation) 1922 { 1923 gtk2_widget = gtk2_get_widget(widget_type); 1924 (*fp_gtk_paint_handle)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1925 shadow_type, NULL, gtk2_widget, detail, 1926 x, y, width, height, orientation); 1927 (*fp_gtk_paint_handle)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1928 shadow_type, NULL, gtk2_widget, detail, 1929 x, y, width, height, orientation); 1930 } 1931 1932 static void gtk2_paint_hline(WidgetType widget_type, GtkStateType state_type, 1933 const gchar *detail, gint x, gint y, gint width, gint height) 1934 { 1935 gtk2_widget = gtk2_get_widget(widget_type); 1936 (*fp_gtk_paint_hline)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1937 NULL, gtk2_widget, detail, x, x + width, y); 1938 (*fp_gtk_paint_hline)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1939 NULL, gtk2_widget, detail, x, x + width, y); 1940 } 1941 1942 static void gtk2_paint_option(WidgetType widget_type, gint synth_state, 1943 const gchar *detail, gint x, gint y, gint width, gint height) 1944 { 1945 GtkStateType state_type = get_gtk_state_type(widget_type, synth_state); 1946 GtkShadowType shadow_type = get_gtk_shadow_type(widget_type, synth_state); 1947 1948 gtk2_widget = gtk2_get_widget(widget_type); 1949 init_toggle_widget(widget_type, synth_state); 1950 1951 (*fp_gtk_paint_option)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1952 shadow_type, NULL, gtk2_widget, detail, 1953 x, y, width, height); 1954 (*fp_gtk_paint_option)(gtk2_widget->style, gtk2_black_pixmap, state_type, 1955 shadow_type, NULL, gtk2_widget, detail, 1956 x, y, width, height); 1957 } 1958 1959 static void gtk2_paint_shadow(WidgetType widget_type, GtkStateType state_type, 1960 GtkShadowType shadow_type, const gchar *detail, 1961 gint x, gint y, gint width, gint height, 1962 gint synth_state, GtkTextDirection dir) 1963 { 1964 gtk2_widget = gtk2_get_widget(widget_type); 1965 1966 /* 1967 * The clearlooks engine sometimes looks at the widget's state field 1968 * instead of just the state_type variable that we pass in, so to account 1969 * for those cases we set the widget's state field accordingly. The 1970 * flags field is similarly important for things like focus state. 1971 */ 1972 gtk2_widget->state = state_type; 1973 1974 /* 1975 * Some engines (e.g. clearlooks) will paint the shadow of certain 1976 * widgets (e.g. COMBO_BOX_TEXT_FIELD) differently depending on the 1977 * the text direction. 1978 */ 1979 gtk2_set_direction(gtk2_widget, dir); 1980 1981 switch (widget_type) { 1982 case COMBO_BOX_TEXT_FIELD: 1983 case FORMATTED_TEXT_FIELD: 1984 case PASSWORD_FIELD: 1985 case SPINNER_TEXT_FIELD: 1986 case TEXT_FIELD: 1987 if (synth_state & FOCUSED) { 1988 ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS; 1989 } else { 1990 ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS; 1991 } 1992 break; 1993 default: 1994 break; 1995 } 1996 1997 (*fp_gtk_paint_shadow)(gtk2_widget->style, gtk2_white_pixmap, state_type, 1998 shadow_type, NULL, gtk2_widget, detail, x, y, width, height); 1999 (*fp_gtk_paint_shadow)(gtk2_widget->style, gtk2_black_pixmap, state_type, 2000 shadow_type, NULL, gtk2_widget, detail, x, y, width, height); 2001 2002 /* 2003 * Reset the text direction to the default value so that we don't 2004 * accidentally affect other operations and widgets. 2005 */ 2006 gtk2_set_direction(gtk2_widget, GTK_TEXT_DIR_LTR); 2007 } 2008 2009 static void gtk2_paint_slider(WidgetType widget_type, GtkStateType state_type, 2010 GtkShadowType shadow_type, const gchar *detail, 2011 gint x, gint y, gint width, gint height, GtkOrientation orientation, 2012 gboolean has_focus) 2013 { 2014 gtk2_widget = gtk2_get_widget(widget_type); 2015 (*fp_gtk_paint_slider)(gtk2_widget->style, gtk2_white_pixmap, state_type, 2016 shadow_type, NULL, gtk2_widget, detail, 2017 x, y, width, height, orientation); 2018 (*fp_gtk_paint_slider)(gtk2_widget->style, gtk2_black_pixmap, state_type, 2019 shadow_type, NULL, gtk2_widget, detail, 2020 x, y, width, height, orientation); 2021 } 2022 2023 static void gtk2_paint_vline(WidgetType widget_type, GtkStateType state_type, 2024 const gchar *detail, gint x, gint y, gint width, gint height) 2025 { 2026 gtk2_widget = gtk2_get_widget(widget_type); 2027 (*fp_gtk_paint_vline)(gtk2_widget->style, gtk2_white_pixmap, state_type, 2028 NULL, gtk2_widget, detail, y, y + height, x); 2029 (*fp_gtk_paint_vline)(gtk2_widget->style, gtk2_black_pixmap, state_type, 2030 NULL, gtk2_widget, detail, y, y + height, x); 2031 } 2032 2033 static void gtk_paint_background(WidgetType widget_type, GtkStateType state_type, 2034 gint x, gint y, gint width, gint height) 2035 { 2036 gtk2_widget = gtk2_get_widget(widget_type); 2037 (*fp_gtk_style_apply_default_background)(gtk2_widget->style, 2038 gtk2_white_pixmap, TRUE, state_type, NULL, x, y, width, height); 2039 (*fp_gtk_style_apply_default_background)(gtk2_widget->style, 2040 gtk2_black_pixmap, TRUE, state_type, NULL, x, y, width, height); 2041 } 2042 2043 static GdkPixbuf *gtk2_get_stock_icon(gint widget_type, const gchar *stock_id, 2044 GtkIconSize size, GtkTextDirection direction, const char *detail) 2045 { 2046 init_containers(); 2047 gtk2_widget = gtk2_get_widget((widget_type < 0) ? IMAGE : widget_type); 2048 gtk2_widget->state = GTK_STATE_NORMAL; 2049 (*fp_gtk_widget_set_direction)(gtk2_widget, direction); 2050 return (*fp_gtk_widget_render_icon)(gtk2_widget, stock_id, size, detail); 2051 } 2052 2053 static jboolean gtk2_get_pixbuf_data(JNIEnv *env, GdkPixbuf* pixbuf, 2054 jmethodID icon_upcall_method, jobject this) { 2055 if (!pixbuf) { 2056 return JNI_FALSE; 2057 } 2058 guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf); 2059 if (pixbuf_data) { 2060 int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); 2061 int width = (*fp_gdk_pixbuf_get_width)(pixbuf); 2062 int height = (*fp_gdk_pixbuf_get_height)(pixbuf); 2063 int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf); 2064 int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); 2065 gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf); 2066 2067 jbyteArray data = (*env)->NewByteArray(env, (row_stride * height)); 2068 JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); 2069 2070 (*env)->SetByteArrayRegion(env, data, 0, (row_stride * height), 2071 (jbyte *)pixbuf_data); 2072 (*fp_g_object_unref)(pixbuf); 2073 2074 /* Call the callback method to create the image on the Java side. */ 2075 (*env)->CallVoidMethod(env, this, icon_upcall_method, data, 2076 width, height, row_stride, bps, channels, alpha); 2077 return JNI_TRUE; 2078 } 2079 return JNI_FALSE; 2080 } 2081 2082 static jboolean gtk2_get_file_icon_data(JNIEnv *env, const char *filename, 2083 GError **error, jmethodID icon_upcall_method, jobject this) { 2084 GdkPixbuf* pixbuf = fp_gdk_pixbuf_new_from_file(filename, error); 2085 return gtk2_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); 2086 } 2087 2088 static jboolean gtk2_get_icon_data(JNIEnv *env, gint widget_type, 2089 const gchar *stock_id, GtkIconSize size, 2090 GtkTextDirection direction, const char *detail, 2091 jmethodID icon_upcall_method, jobject this) { 2092 GdkPixbuf* pixbuf = gtk2_get_stock_icon(widget_type, stock_id, size, 2093 direction, detail); 2094 return gtk2_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); 2095 } 2096 2097 /*************************************************/ 2098 static gint gtk2_get_xthickness(JNIEnv *env, WidgetType widget_type) 2099 { 2100 init_containers(); 2101 2102 gtk2_widget = gtk2_get_widget(widget_type); 2103 GtkStyle* style = gtk2_widget->style; 2104 return style->xthickness; 2105 } 2106 2107 static gint gtk2_get_ythickness(JNIEnv *env, WidgetType widget_type) 2108 { 2109 init_containers(); 2110 2111 gtk2_widget = gtk2_get_widget(widget_type); 2112 GtkStyle* style = gtk2_widget->style; 2113 return style->ythickness; 2114 } 2115 2116 /*************************************************/ 2117 static guint8 recode_color(guint16 channel) 2118 { 2119 return (guint8)(channel>>8); 2120 } 2121 2122 static gint gtk2_get_color_for_state(JNIEnv *env, WidgetType widget_type, 2123 GtkStateType state_type, ColorType color_type) 2124 { 2125 gint result = 0; 2126 GdkColor *color = NULL; 2127 2128 init_containers(); 2129 2130 gtk2_widget = gtk2_get_widget(widget_type); 2131 GtkStyle* style = gtk2_widget->style; 2132 2133 switch (color_type) 2134 { 2135 case FOREGROUND: 2136 color = &(style->fg[state_type]); 2137 break; 2138 case BACKGROUND: 2139 color = &(style->bg[state_type]); 2140 break; 2141 case TEXT_FOREGROUND: 2142 color = &(style->text[state_type]); 2143 break; 2144 case TEXT_BACKGROUND: 2145 color = &(style->base[state_type]); 2146 break; 2147 case LIGHT: 2148 color = &(style->light[state_type]); 2149 break; 2150 case DARK: 2151 color = &(style->dark[state_type]); 2152 break; 2153 case MID: 2154 color = &(style->mid[state_type]); 2155 break; 2156 case FOCUS: 2157 case BLACK: 2158 color = &(style->black); 2159 break; 2160 case WHITE: 2161 color = &(style->white); 2162 break; 2163 } 2164 2165 if (color) 2166 result = recode_color(color->red) << 16 | 2167 recode_color(color->green) << 8 | 2168 recode_color(color->blue); 2169 2170 return result; 2171 } 2172 2173 /*************************************************/ 2174 static jobject create_Boolean(JNIEnv *env, jboolean boolean_value); 2175 static jobject create_Integer(JNIEnv *env, jint int_value); 2176 static jobject create_Long(JNIEnv *env, jlong long_value); 2177 static jobject create_Float(JNIEnv *env, jfloat float_value); 2178 static jobject create_Double(JNIEnv *env, jdouble double_value); 2179 static jobject create_Character(JNIEnv *env, jchar char_value); 2180 static jobject create_Insets(JNIEnv *env, GtkBorder *border); 2181 2182 static jobject gtk2_get_class_value(JNIEnv *env, WidgetType widget_type, 2183 const char* key) 2184 { 2185 init_containers(); 2186 2187 gtk2_widget = gtk2_get_widget(widget_type); 2188 2189 GValue value; 2190 value.g_type = 0; 2191 2192 GParamSpec* param = (*fp_gtk_widget_class_find_style_property)( 2193 ((GTypeInstance*)gtk2_widget)->g_class, key); 2194 if( param ) 2195 { 2196 (*fp_g_value_init)( &value, param->value_type ); 2197 (*fp_gtk_widget_style_get_property)(gtk2_widget, key, &value); 2198 2199 if( (*fp_g_type_is_a)( param->value_type, G_TYPE_BOOLEAN )) 2200 { 2201 gboolean val = (*fp_g_value_get_boolean)(&value); 2202 return create_Boolean(env, (jboolean)val); 2203 } 2204 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_CHAR )) 2205 { 2206 gchar val = (*fp_g_value_get_char)(&value); 2207 return create_Character(env, (jchar)val); 2208 } 2209 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UCHAR )) 2210 { 2211 guchar val = (*fp_g_value_get_uchar)(&value); 2212 return create_Character(env, (jchar)val); 2213 } 2214 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_INT )) 2215 { 2216 gint val = (*fp_g_value_get_int)(&value); 2217 return create_Integer(env, (jint)val); 2218 } 2219 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UINT )) 2220 { 2221 guint val = (*fp_g_value_get_uint)(&value); 2222 return create_Integer(env, (jint)val); 2223 } 2224 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_LONG )) 2225 { 2226 glong val = (*fp_g_value_get_long)(&value); 2227 return create_Long(env, (jlong)val); 2228 } 2229 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_ULONG )) 2230 { 2231 gulong val = (*fp_g_value_get_ulong)(&value); 2232 return create_Long(env, (jlong)val); 2233 } 2234 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_INT64 )) 2235 { 2236 gint64 val = (*fp_g_value_get_int64)(&value); 2237 return create_Long(env, (jlong)val); 2238 } 2239 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UINT64 )) 2240 { 2241 guint64 val = (*fp_g_value_get_uint64)(&value); 2242 return create_Long(env, (jlong)val); 2243 } 2244 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_FLOAT )) 2245 { 2246 gfloat val = (*fp_g_value_get_float)(&value); 2247 return create_Float(env, (jfloat)val); 2248 } 2249 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_DOUBLE )) 2250 { 2251 gdouble val = (*fp_g_value_get_double)(&value); 2252 return create_Double(env, (jdouble)val); 2253 } 2254 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_ENUM )) 2255 { 2256 gint val = (*fp_g_value_get_enum)(&value); 2257 return create_Integer(env, (jint)val); 2258 } 2259 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_FLAGS )) 2260 { 2261 guint val = (*fp_g_value_get_flags)(&value); 2262 return create_Integer(env, (jint)val); 2263 } 2264 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_STRING )) 2265 { 2266 const gchar* val = (*fp_g_value_get_string)(&value); 2267 2268 /* We suppose that all values come in C locale and 2269 * utf-8 representation of a string is the same as 2270 * the string itself. If this isn't so we should 2271 * use g_convert. 2272 */ 2273 return (*env)->NewStringUTF(env, val); 2274 } 2275 else if( (*fp_g_type_is_a)( param->value_type, GTK_TYPE_BORDER )) 2276 { 2277 GtkBorder *border = (GtkBorder*)(*fp_g_value_get_boxed)(&value); 2278 return border ? create_Insets(env, border) : NULL; 2279 } 2280 2281 /* TODO: Other types are not supported yet.*/ 2282 /* else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_PARAM )) 2283 { 2284 GParamSpec* val = (*fp_g_value_get_param)(&value); 2285 printf( "Param: %p\n", val ); 2286 } 2287 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_BOXED )) 2288 { 2289 gpointer* val = (*fp_g_value_get_boxed)(&value); 2290 printf( "Boxed: %p\n", val ); 2291 } 2292 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_POINTER )) 2293 { 2294 gpointer* val = (*fp_g_value_get_pointer)(&value); 2295 printf( "Pointer: %p\n", val ); 2296 } 2297 else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_OBJECT )) 2298 { 2299 GObject* val = (GObject*)(*fp_g_value_get_object)(&value); 2300 printf( "Object: %p\n", val ); 2301 }*/ 2302 } 2303 2304 return NULL; 2305 } 2306 2307 static void gtk2_set_range_value(WidgetType widget_type, jdouble value, 2308 jdouble min, jdouble max, jdouble visible) 2309 { 2310 GtkAdjustment *adj; 2311 2312 gtk2_widget = gtk2_get_widget(widget_type); 2313 2314 adj = (*fp_gtk_range_get_adjustment)((GtkRange *)gtk2_widget); 2315 adj->value = (gdouble)value; 2316 adj->lower = (gdouble)min; 2317 adj->upper = (gdouble)max; 2318 adj->page_size = (gdouble)visible; 2319 } 2320 2321 /*************************************************/ 2322 static jobject create_Object(JNIEnv *env, jmethodID *cid, 2323 const char* class_name, 2324 const char* signature, 2325 jvalue* value) 2326 { 2327 jclass class; 2328 jobject result; 2329 2330 class = (*env)->FindClass(env, class_name); 2331 if( class == NULL ) 2332 return NULL; /* can't find/load the class, exception thrown */ 2333 2334 if( *cid == NULL) 2335 { 2336 *cid = (*env)->GetMethodID(env, class, "<init>", signature); 2337 if( *cid == NULL ) 2338 { 2339 (*env)->DeleteLocalRef(env, class); 2340 return NULL; /* can't find/get the method, exception thrown */ 2341 } 2342 } 2343 2344 result = (*env)->NewObjectA(env, class, *cid, value); 2345 2346 (*env)->DeleteLocalRef(env, class); 2347 return result; 2348 } 2349 2350 jobject create_Boolean(JNIEnv *env, jboolean boolean_value) 2351 { 2352 static jmethodID cid = NULL; 2353 jvalue value; 2354 2355 value.z = boolean_value; 2356 2357 return create_Object(env, &cid, "java/lang/Boolean", "(Z)V", &value); 2358 } 2359 2360 jobject create_Integer(JNIEnv *env, jint int_value) 2361 { 2362 static jmethodID cid = NULL; 2363 jvalue value; 2364 2365 value.i = int_value; 2366 2367 return create_Object(env, &cid, "java/lang/Integer", "(I)V", &value); 2368 } 2369 2370 jobject create_Long(JNIEnv *env, jlong long_value) 2371 { 2372 static jmethodID cid = NULL; 2373 jvalue value; 2374 2375 value.j = long_value; 2376 2377 return create_Object(env, &cid, "java/lang/Long", "(J)V", &value); 2378 } 2379 2380 jobject create_Float(JNIEnv *env, jfloat float_value) 2381 { 2382 static jmethodID cid = NULL; 2383 jvalue value; 2384 2385 value.f = float_value; 2386 2387 return create_Object(env, &cid, "java/lang/Float", "(F)V", &value); 2388 } 2389 2390 jobject create_Double(JNIEnv *env, jdouble double_value) 2391 { 2392 static jmethodID cid = NULL; 2393 jvalue value; 2394 2395 value.d = double_value; 2396 2397 return create_Object(env, &cid, "java/lang/Double", "(D)V", &value); 2398 } 2399 2400 jobject create_Character(JNIEnv *env, jchar char_value) 2401 { 2402 static jmethodID cid = NULL; 2403 jvalue value; 2404 2405 value.c = char_value; 2406 2407 return create_Object(env, &cid, "java/lang/Character", "(C)V", &value); 2408 } 2409 2410 2411 jobject create_Insets(JNIEnv *env, GtkBorder *border) 2412 { 2413 static jmethodID cid = NULL; 2414 jvalue values[4]; 2415 2416 values[0].i = border->top; 2417 values[1].i = border->left; 2418 values[2].i = border->bottom; 2419 values[3].i = border->right; 2420 2421 return create_Object(env, &cid, "java/awt/Insets", "(IIII)V", values); 2422 } 2423 2424 /*********************************************/ 2425 static jstring gtk2_get_pango_font_name(JNIEnv *env, WidgetType widget_type) 2426 { 2427 init_containers(); 2428 2429 gtk2_widget = gtk2_get_widget(widget_type); 2430 jstring result = NULL; 2431 GtkStyle* style = gtk2_widget->style; 2432 2433 if (style && style->font_desc) 2434 { 2435 gchar* val = (*fp_pango_font_description_to_string)(style->font_desc); 2436 result = (*env)->NewStringUTF(env, val); 2437 (*fp_g_free)( val ); 2438 } 2439 2440 return result; 2441 } 2442 2443 /***********************************************/ 2444 static jobject get_string_property(JNIEnv *env, GtkSettings* settings, const gchar* key) 2445 { 2446 jobject result = NULL; 2447 gchar* strval = NULL; 2448 2449 (*fp_g_object_get)(settings, key, &strval, NULL); 2450 result = (*env)->NewStringUTF(env, strval); 2451 (*fp_g_free)(strval); 2452 2453 return result; 2454 } 2455 2456 static jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key) 2457 { 2458 gint intval = 0; 2459 (*fp_g_object_get)(settings, key, &intval, NULL); 2460 return create_Integer(env, intval); 2461 } 2462 2463 static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, const gchar* key) 2464 { 2465 gint intval = 0; 2466 (*fp_g_object_get)(settings, key, &intval, NULL); 2467 return create_Boolean(env, intval); 2468 } 2469 2470 static jobject gtk2_get_setting(JNIEnv *env, Setting property) 2471 { 2472 GtkSettings* settings = (*fp_gtk_settings_get_default)(); 2473 2474 switch (property) 2475 { 2476 case GTK_FONT_NAME: 2477 return get_string_property(env, settings, "gtk-font-name"); 2478 case GTK_ICON_SIZES: 2479 return get_string_property(env, settings, "gtk-icon-sizes"); 2480 case GTK_CURSOR_BLINK: 2481 return get_boolean_property(env, settings, "gtk-cursor-blink"); 2482 case GTK_CURSOR_BLINK_TIME: 2483 return get_integer_property(env, settings, "gtk-cursor-blink-time"); 2484 } 2485 2486 return NULL; 2487 } 2488 2489 static GdkWindow* gtk2_get_window(void *widget) { 2490 return ((GtkWidget*)widget)->window; 2491 } 2492 2493 void gtk2_init(GtkApi* gtk) { 2494 gtk->version = GTK_2; 2495 2496 gtk->show_uri_load = >k2_show_uri_load; 2497 gtk->unload = >k2_unload; 2498 gtk->flush_event_loop = &flush_gtk_event_loop; 2499 gtk->gtk_check_version = fp_gtk_check_version; 2500 gtk->get_setting = >k2_get_setting; 2501 2502 gtk->paint_arrow = >k2_paint_arrow; 2503 gtk->paint_box = >k2_paint_box; 2504 gtk->paint_box_gap = >k2_paint_box_gap; 2505 gtk->paint_expander = >k2_paint_expander; 2506 gtk->paint_extension = >k2_paint_extension; 2507 gtk->paint_flat_box = >k2_paint_flat_box; 2508 gtk->paint_focus = >k2_paint_focus; 2509 gtk->paint_handle = >k2_paint_handle; 2510 gtk->paint_hline = >k2_paint_hline; 2511 gtk->paint_vline = >k2_paint_vline; 2512 gtk->paint_option = >k2_paint_option; 2513 gtk->paint_shadow = >k2_paint_shadow; 2514 gtk->paint_slider = >k2_paint_slider; 2515 gtk->paint_background = >k_paint_background; 2516 gtk->paint_check = >k2_paint_check; 2517 gtk->set_range_value = >k2_set_range_value; 2518 2519 gtk->init_painting = >k2_init_painting; 2520 gtk->copy_image = >k2_copy_image; 2521 2522 gtk->get_xthickness = >k2_get_xthickness; 2523 gtk->get_ythickness = >k2_get_ythickness; 2524 gtk->get_color_for_state = >k2_get_color_for_state; 2525 gtk->get_class_value = >k2_get_class_value; 2526 2527 gtk->get_pango_font_name = >k2_get_pango_font_name; 2528 gtk->get_icon_data = >k2_get_icon_data; 2529 gtk->get_file_icon_data = >k2_get_file_icon_data; 2530 gtk->gdk_threads_enter = fp_gdk_threads_enter; 2531 gtk->gdk_threads_leave = fp_gdk_threads_leave; 2532 gtk->gtk_show_uri = fp_gtk_show_uri; 2533 gtk->g_free = fp_g_free; 2534 2535 gtk->gtk_file_chooser_get_filename = fp_gtk_file_chooser_get_filename; 2536 gtk->gtk_widget_hide = fp_gtk_widget_hide; 2537 gtk->gtk_main_quit = fp_gtk_main_quit; 2538 gtk->gtk_file_chooser_dialog_new = fp_gtk_file_chooser_dialog_new; 2539 gtk->gtk_file_chooser_set_current_folder = 2540 fp_gtk_file_chooser_set_current_folder; 2541 gtk->gtk_file_chooser_set_filename = fp_gtk_file_chooser_set_filename; 2542 gtk->gtk_file_chooser_set_current_name = 2543 fp_gtk_file_chooser_set_current_name; 2544 gtk->gtk_file_filter_add_custom = fp_gtk_file_filter_add_custom; 2545 gtk->gtk_file_chooser_set_filter = fp_gtk_file_chooser_set_filter; 2546 gtk->gtk_file_chooser_get_type = fp_gtk_file_chooser_get_type; 2547 gtk->gtk_file_filter_new = fp_gtk_file_filter_new; 2548 gtk->gtk_file_chooser_set_do_overwrite_confirmation = 2549 fp_gtk_file_chooser_set_do_overwrite_confirmation; 2550 gtk->gtk_file_chooser_set_select_multiple = 2551 fp_gtk_file_chooser_set_select_multiple; 2552 gtk->gtk_file_chooser_get_current_folder = 2553 fp_gtk_file_chooser_get_current_folder; 2554 gtk->gtk_file_chooser_get_filenames = fp_gtk_file_chooser_get_filenames; 2555 gtk->gtk_g_slist_length = fp_gtk_g_slist_length; 2556 gtk->g_signal_connect_data = fp_g_signal_connect_data; 2557 gtk->gtk_widget_show = fp_gtk_widget_show; 2558 gtk->gtk_main = fp_gtk_main; 2559 gtk->gtk_main_level = fp_gtk_main_level; 2560 gtk->g_path_get_dirname = fp_g_path_get_dirname; 2561 gtk->gtk_widget_destroy = fp_gtk_widget_destroy; 2562 gtk->gtk_window_present = fp_gtk_window_present; 2563 gtk->gtk_window_move = fp_gtk_window_move; 2564 gtk->gtk_window_resize = fp_gtk_window_resize; 2565 gtk->get_window = >k2_get_window; 2566 2567 gtk->g_object_unref = fp_g_object_unref; 2568 gtk->g_list_append = fp_g_list_append; 2569 gtk->g_list_free = fp_g_list_free; 2570 gtk->g_list_free_full = fp_g_list_free_full; 2571 }