8218469: JSlider display issue with slider for GTKLookAndFeel
authorpbansal
Fri, 15 Feb 2019 10:58:57 +0530
changeset 53800 76668d618a99
parent 53799 af2ed7605f8c
child 53801 2a3bc7e69b31
8218469: JSlider display issue with slider for GTKLookAndFeel 8218470: JScrollBar display issue with GTKLookAndFeel 8218472: JProgressBar display issue with GTKLookAndFeel 8203627: Swing applications with JRadioButton and JCheckbox fail to render correctly when using GTK3 and the GTK L&F Reviewed-by: serb, prr
src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java
src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c
src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h
--- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java	Thu Feb 14 20:20:49 2019 +0000
+++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java	Fri Feb 15 10:58:57 2019 +0530
@@ -767,6 +767,14 @@
         if (classKey != null) {
             Object value = getClassSpecificValue(classKey);
             if (value != null) {
+                //This is a workaround as the "slider-length" property has been
+                //deprecated for GtkScale from gtk 3.20, so default value of 31
+                //is used and makes redering of slider wrong. Value 14 is being
+                //used as default value for Slider.thumbHeight is 14 and making
+                //width 14 as well makes slider thumb render in proper shape
+                if ("Slider.thumbWidth".equals(key) && value.equals(31)) {
+                    return 14;
+                }
                 return value;
             }
         }
@@ -779,8 +787,15 @@
             return getColorForState(context, ColorType.FOREGROUND);
         }
         else if (key == "ScrollBar.minimumThumbSize") {
+            //This is a workaround as the "min-slider-length" property has been
+            //deprecated for GtkScrollBar from gtk 3.20, so default value of 21
+            //is used and makes ScrollBar thumb very small. Value 40 is being
+            //used as this is the value mentioned in css files
             int len =
                 getClassSpecificIntValue(context, "min-slider-length", 21);
+            if (len == 21) {
+                len = 40;
+            }
             JScrollBar sb = (JScrollBar)context.getComponent();
             if (sb.getOrientation() == JScrollBar.HORIZONTAL) {
                 return new DimensionUIResource(len, 0);
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c	Thu Feb 14 20:20:49 2019 +0000
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c	Fri Feb 15 10:58:57 2019 +0530
@@ -258,6 +258,7 @@
 
 static gboolean gtk3_version_3_10 = TRUE;
 static gboolean gtk3_version_3_14 = FALSE;
+static gboolean gtk3_version_3_20 = FALSE;
 
 GtkApi* gtk3_load(JNIEnv *env, const char* lib_name)
 {
@@ -400,6 +401,18 @@
         }
         gtk3_version_3_14 = !fp_gtk_check_version(3, 14, 0);
 
+        if (!fp_gtk_check_version(3, 20, 0)) {
+            gtk3_version_3_20 = TRUE;
+            fp_gtk_widget_path_copy = dl_symbol("gtk_widget_path_copy");
+            fp_gtk_widget_path_new = dl_symbol("gtk_widget_path_new");
+            fp_gtk_widget_path_append_type = dl_symbol("gtk_widget_path_append_type");
+            fp_gtk_widget_path_iter_set_object_name = dl_symbol("gtk_widget_path_iter_set_object_name");
+            fp_gtk_style_context_set_path = dl_symbol("gtk_style_context_set_path");
+            fp_gtk_widget_path_unref = dl_symbol("gtk_widget_path_unref");
+            fp_gtk_style_context_get_path = dl_symbol("gtk_style_context_get_path");
+            fp_gtk_style_context_new = dl_symbol("gtk_style_context_new");
+        }
+
         fp_gdk_window_create_similar_surface =
                       dl_symbol("gdk_window_create_similar_surface");
         fp_gtk_settings_get_for_screen =
@@ -561,7 +574,6 @@
                                                 "gtk_combo_box_new_with_entry");
         fp_gtk_separator_tool_item_new = dlsym(gtk3_libhandle,
                                                  "gtk_separator_tool_item_new");
-
         fp_g_list_append = dl_symbol("g_list_append");
         fp_g_list_free = dl_symbol("g_list_free");
         fp_g_list_free_full = dl_symbol("g_list_free_full");
@@ -1362,6 +1374,90 @@
     return result;
 }
 
+static void append_element (GtkWidgetPath *path, const gchar *selector)
+{
+    fp_gtk_widget_path_append_type (path, G_TYPE_NONE);
+    fp_gtk_widget_path_iter_set_object_name (path, -1, selector);
+}
+
+static GtkWidgetPath* createWidgetPath(const GtkWidgetPath* path) {
+    if (path == NULL) {
+        return fp_gtk_widget_path_new();
+    } else {
+        return fp_gtk_widget_path_copy(path);
+    }
+}
+
+static GtkStyleContext* get_style(WidgetType widget_type, const gchar *detail)
+{
+    if (!gtk3_version_3_20) {
+        gtk3_widget = gtk3_get_widget(widget_type);
+        GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
+        fp_gtk_style_context_save (context);
+        if (detail != 0) {
+             transform_detail_string(detail, context);
+        }
+        return context;
+    } else {
+        gtk3_widget = gtk3_get_widget(widget_type);
+        GtkStyleContext* widget_context = fp_gtk_widget_get_style_context (gtk3_widget);
+        GtkWidgetPath *path = NULL;
+        if (detail != 0) {
+            if (strcmp(detail, "checkbutton") == 0) {
+                path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+                append_element(path, "check");
+            } else if (strcmp(detail, "radiobutton") == 0) {
+                path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+                append_element(path, "radio");
+            } else if (strcmp(detail, "vscale") == 0 || strcmp(detail, "hscale") == 0) {
+                path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+                append_element(path, "slider");
+            } else if (strcmp(detail, "trough") == 0) {
+                //This is a fast solution to the scrollbar trough not being rendered properly
+                if (widget_type == HSCROLL_BAR || widget_type == HSCROLL_BAR_TRACK ||
+                    widget_type == VSCROLL_BAR || widget_type == VSCROLL_BAR_TRACK) {
+                    path = createWidgetPath (NULL);
+                } else {
+                    path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+                }
+                append_element(path, detail);
+            } else if (strcmp(detail, "bar") == 0) {
+                path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+                append_element(path, "trough");
+                append_element(path, "progress");
+            } else if (strcmp(detail, "vscrollbar") == 0 || strcmp(detail, "hscrollbar") == 0) {
+                path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+                append_element(path, "button");
+            } else if (strcmp(detail, "check") == 0) {
+                path = createWidgetPath (NULL);
+                append_element(path, detail);
+            } else if (strcmp(detail, "option") == 0) {
+                path = createWidgetPath (NULL);
+                append_element(path, "radio");
+            } else {
+                path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+                append_element(path, detail);
+            }
+        } else {
+            path = createWidgetPath (fp_gtk_style_context_get_path (widget_context));
+        }
+
+        GtkStyleContext *context = fp_gtk_style_context_new ();
+        fp_gtk_style_context_set_path (context, path);
+        fp_gtk_widget_path_unref (path);
+        return context;
+    }
+}
+
+static void disposeOrRestoreContext(GtkStyleContext *context)
+{
+    if (!gtk3_version_3_20) {
+        fp_gtk_style_context_restore (context);
+    } else {
+        fp_g_object_unref (context);
+    }
+}
+
 static void gtk3_paint_arrow(WidgetType widget_type, GtkStateType state_type,
         GtkShadowType shadow_type, const gchar *detail,
         gint x, gint y, gint width, gint height,
@@ -1509,13 +1605,9 @@
      */
     gtk3_set_direction(gtk3_widget, dir);
 
-    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
-    fp_gtk_style_context_save (context);
-
-    transform_detail_string(detail, context);
+    GtkStyleContext* context = get_style(widget_type, detail);
 
     GtkStateFlags flags = get_gtk_flags(state_type);
-
     if (shadow_type == GTK_SHADOW_IN && widget_type != COMBO_BOX_ARROW_BUTTON) {
         flags |= GTK_STATE_FLAG_ACTIVE;
     }
@@ -1532,23 +1624,31 @@
         fp_gtk_style_context_add_class (context, "default");
     }
 
+    if (fp_gtk_style_context_has_class(context, "trough")) {
+        flags |= GTK_STATE_FLAG_BACKDROP;
+    }
+
     fp_gtk_style_context_set_state (context, flags);
 
-    if (fp_gtk_style_context_has_class(context, "progressbar")) {
-        fp_gtk_render_activity (context, cr, x, y, width, height);
-    } else {
-        fp_gtk_render_background (context, cr, x, y, width, height);
-        if (shadow_type != GTK_SHADOW_NONE) {
-            fp_gtk_render_frame(context, cr, x, y, width, height);
-        }
+    fp_gtk_render_background (context, cr, x, y, width, height);
+    if (shadow_type != GTK_SHADOW_NONE) {
+        fp_gtk_render_frame(context, cr, x, y, width, height);
     }
 
-    fp_gtk_style_context_restore (context);
+    disposeOrRestoreContext(context);
+
     /*
      * Reset the text direction to the default value so that we don't
      * accidentally affect other operations and widgets.
      */
     gtk3_set_direction(gtk3_widget, GTK_TEXT_DIR_LTR);
+
+    //This is a fast solution to the scrollbar trough not being rendered properly
+    if ((widget_type == HSCROLL_BAR || widget_type == HSCROLL_BAR_TRACK ||
+        widget_type == VSCROLL_BAR || widget_type == VSCROLL_BAR_TRACK) && detail != 0) {
+        gtk3_paint_box(widget_type, state_type, shadow_type, NULL,
+                    x, y, width, height, synth_state, dir);
+    }
 }
 
 static void gtk3_paint_box_gap(WidgetType widget_type, GtkStateType state_type,
@@ -1580,23 +1680,19 @@
 static void gtk3_paint_check(WidgetType widget_type, gint synth_state,
         const gchar *detail, gint x, gint y, gint width, gint height)
 {
-    gtk3_widget = gtk3_get_widget(widget_type);
-
-    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
-
-    fp_gtk_style_context_save (context);
+    GtkStyleContext* context = get_style(widget_type, detail);
 
     GtkStateFlags flags = get_gtk_state_flags(synth_state);
     if (gtk3_version_3_14 && (synth_state & SELECTED)) {
-        flags = GTK_STATE_FLAG_CHECKED;
+        flags &= ~GTK_STATE_FLAG_SELECTED;
+        flags |= GTK_STATE_FLAG_CHECKED;
     }
     fp_gtk_style_context_set_state(context, flags);
 
-    fp_gtk_style_context_add_class (context, "check");
-
-    fp_gtk_render_check (context, cr, x, y, width, height);
-
-    fp_gtk_style_context_restore (context);
+    fp_gtk_render_background(context, cr, x, y, width, height);
+    fp_gtk_render_frame(context, cr, x, y, width, height);
+    fp_gtk_render_check(context, cr, x, y, width, height);
+    disposeOrRestoreContext(context);
 }
 
 
@@ -1684,7 +1780,6 @@
     gtk3_widget = gtk3_get_widget(widget_type);
 
     GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
-
     fp_gtk_style_context_save (context);
 
     if (detail != 0) {
@@ -1787,25 +1882,19 @@
 static void gtk3_paint_option(WidgetType widget_type, gint synth_state,
         const gchar *detail, gint x, gint y, gint width, gint height)
 {
-     gtk3_widget = gtk3_get_widget(widget_type);
-
-     GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
-
-     fp_gtk_style_context_save (context);
+     GtkStyleContext* context = get_style(widget_type, detail);
 
      GtkStateFlags flags = get_gtk_state_flags(synth_state);
      if (gtk3_version_3_14 && (synth_state & SELECTED)) {
-         flags = GTK_STATE_FLAG_CHECKED;
+         flags &= ~GTK_STATE_FLAG_SELECTED;
+         flags |= GTK_STATE_FLAG_CHECKED;
      }
      fp_gtk_style_context_set_state(context, flags);
 
-     if (detail != 0) {
-         transform_detail_string(detail, context);
-     }
-
+     fp_gtk_render_background(context, cr, x, y, width, height);
+     fp_gtk_render_frame(context, cr, x, y, width, height);
      fp_gtk_render_option(context, cr, x, y, width, height);
-
-     fp_gtk_style_context_restore (context);
+     disposeOrRestoreContext(context);
 }
 
 static void gtk3_paint_shadow(WidgetType widget_type, GtkStateType state_type,
@@ -1864,15 +1953,7 @@
         gint x, gint y, gint width, gint height, GtkOrientation orientation,
         gboolean has_focus)
 {
-    gtk3_widget = gtk3_get_widget(widget_type);
-
-    GtkStyleContext* context = fp_gtk_widget_get_style_context (gtk3_widget);
-
-    fp_gtk_style_context_save (context);
-
-    if (detail) {
-       transform_detail_string(detail, context);
-    }
+    GtkStyleContext *context = get_style(widget_type, detail);
 
     GtkStateFlags flags = get_gtk_flags(state_type);
 
@@ -1886,9 +1967,10 @@
 
     fp_gtk_style_context_set_state (context, flags);
 
+    fp_gtk_render_background (context, cr, x, y, width, height);
+    fp_gtk_render_frame(context, cr, x, y, width, height);
     (*fp_gtk_render_slider)(context, cr, x, y, width, height, orientation);
-
-    fp_gtk_style_context_restore (context);
+    disposeOrRestoreContext(context);
 }
 
 static void gtk3_paint_background(WidgetType widget_type,
--- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h	Thu Feb 14 20:20:49 2019 +0000
+++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h	Fri Feb 15 10:58:57 2019 +0530
@@ -162,6 +162,7 @@
 typedef void GtkRange;
 typedef void GtkProgressBar;
 typedef void GtkProgress;
+typedef void GtkWidgetPath;
 
 /* Some real structures */
 typedef struct
@@ -238,7 +239,6 @@
   GType    owner_type;
 } GParamSpec;
 
-
 static gchar* (*fp_glib_check_version)(guint required_major,
                            guint required_minor, guint required_micro);
 
@@ -573,5 +573,18 @@
 static void (*fp_gtk_widget_size_request)(GtkWidget *widget,
                                           GtkRequisition *requisition);
 static GtkAdjustment* (*fp_gtk_range_get_adjustment)(GtkRange* range);
+static GtkWidgetPath* (*fp_gtk_widget_path_copy)
+        (const GtkWidgetPath *path);
+static const GtkWidgetPath* (*fp_gtk_style_context_get_path)
+        (GtkStyleContext *context);
+static GtkWidgetPath* (*fp_gtk_widget_path_new) (void);
+static gint (*fp_gtk_widget_path_append_type)
+        (GtkWidgetPath *path, GType type);
+static void (*fp_gtk_widget_path_iter_set_object_name)
+        (GtkWidgetPath *path, gint pos, const char *name);
+static void (*fp_gtk_style_context_set_path)
+        (GtkStyleContext *context, GtkWidgetPath *path);
+static void (*fp_gtk_widget_path_unref) (GtkWidgetPath *path);
+static GtkStyleContext* (*fp_gtk_style_context_new) (void);
 
 #endif /* !_GTK3_INTERFACE_H */