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