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