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