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