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