a4ade77
From ec023e99774d90e3ac16a3a5b4e55c6cdf9fb3c1 Mon Sep 17 00:00:00 2001
a4ade77
From: Paul Cornett <paulcor@users.noreply.github.com>
a4ade77
Date: Sat, 10 Dec 2016 21:49:06 -0800
a4ade77
Subject: [PATCH] Fix rendering of check and radio buttons with GTK+ >= 3.20
a4ade77
a4ade77
(cherry picked from commit e627970ba6126113fdf09db69c50582b369d0d8a)
a4ade77
---
a4ade77
 src/gtk/renderer.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++---------
a4ade77
 1 file changed, 153 insertions(+), 31 deletions(-)
a4ade77
a4ade77
diff --git a/src/gtk/renderer.cpp b/src/gtk/renderer.cpp
a4ade77
index 965d5fe..c89b0d3 100644
a4ade77
--- a/src/gtk/renderer.cpp
a4ade77
+++ b/src/gtk/renderer.cpp
a4ade77
@@ -503,6 +503,49 @@ wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
a4ade77
 wxSize
a4ade77
 wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
a4ade77
 {
a4ade77
+#ifdef __WXGTK3__
a4ade77
+    int min_width, min_height;
a4ade77
+    GtkWidgetPath* path = gtk_widget_path_new();
a4ade77
+    GtkStyleContext* sc = gtk_style_context_new();
a4ade77
+    GtkStyleContext* sc1 = NULL;
a4ade77
+    gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON);
a4ade77
+#if GTK_CHECK_VERSION(3,20,0)
a4ade77
+    if (gtk_check_version(3,20,0) == NULL)
a4ade77
+    {
a4ade77
+        gtk_widget_path_iter_set_object_name(path, -1, "checkbutton");
a4ade77
+        sc1 = gtk_style_context_new();
a4ade77
+        gtk_style_context_set_path(sc1, path);
a4ade77
+        gtk_widget_path_append_type(path, G_TYPE_NONE);
a4ade77
+        gtk_widget_path_iter_set_object_name(path, -1, "check");
a4ade77
+        gtk_style_context_set_path(sc, path);
a4ade77
+        gtk_style_context_set_parent(sc, sc1);
a4ade77
+        gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
a4ade77
+            "min-width", &min_width, "min-height", &min_height, NULL);
a4ade77
+        GtkBorder margin;
a4ade77
+        gtk_style_context_get_margin(sc, GTK_STATE_FLAG_NORMAL, &margin);
a4ade77
+        min_width += margin.left + margin.right;
a4ade77
+        min_height += margin.top + margin.bottom;
a4ade77
+    }
a4ade77
+    else
a4ade77
+#endif
a4ade77
+    {
a4ade77
+        gtk_style_context_set_path(sc, path);
a4ade77
+        GValue value = G_VALUE_INIT;
a4ade77
+        g_value_init(&value, G_TYPE_INT);
a4ade77
+        gtk_style_context_get_style_property(sc, "indicator-size", &value);
a4ade77
+        min_width = g_value_get_int(&value);
a4ade77
+        gtk_style_context_get_style_property(sc, "indicator-spacing", &value);
a4ade77
+        min_width += 2 * g_value_get_int(&value);
a4ade77
+        min_height = min_width;
a4ade77
+        g_value_unset(&value);
a4ade77
+    }
a4ade77
+    gtk_widget_path_unref(path);
a4ade77
+    g_object_unref(sc);
a4ade77
+    if (sc1)
a4ade77
+        g_object_unref(sc1);
a4ade77
+
a4ade77
+    return wxSize(min_width, min_height);
a4ade77
+#else // !__WXGTK3__
a4ade77
     gint indicator_size, indicator_spacing;
a4ade77
     gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
a4ade77
                          "indicator_size", &indicator_size,
a4ade77
@@ -511,6 +554,7 @@ wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
a4ade77
 
a4ade77
     int size = indicator_size + indicator_spacing * 2;
a4ade77
     return wxSize(size, size);
a4ade77
+#endif // !__WXGTK3__
a4ade77
 }
a4ade77
 
a4ade77
 void
a4ade77
@@ -519,6 +563,7 @@ wxRendererGTK::DrawCheckBox(wxWindow* win,
a4ade77
                             const wxRect& rect,
a4ade77
                             int flags )
a4ade77
 {
a4ade77
+#ifndef __WXGTK3__
a4ade77
     GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget();
a4ade77
 
a4ade77
     gint indicator_size, indicator_spacing;
a4ade77
@@ -527,7 +572,6 @@ wxRendererGTK::DrawCheckBox(wxWindow* win,
a4ade77
                          "indicator_spacing", &indicator_spacing,
a4ade77
                          NULL);
a4ade77
 
a4ade77
-#ifndef __WXGTK3__
a4ade77
     GtkStateType state;
a4ade77
 
a4ade77
     if ( flags & wxCONTROL_PRESSED )
a4ade77
@@ -551,31 +595,68 @@ wxRendererGTK::DrawCheckBox(wxWindow* win,
a4ade77
 
a4ade77
 #ifdef __WXGTK3__
a4ade77
     cairo_t* cr = wxGetGTKDrawable(win, dc);
a4ade77
-    if (cr)
a4ade77
+    if (cr == NULL)
a4ade77
+        return;
a4ade77
+
a4ade77
+    int state = GTK_STATE_FLAG_NORMAL;
a4ade77
+    if (flags & wxCONTROL_CHECKED)
a4ade77
     {
a4ade77
-        int stateFlags = GTK_STATE_FLAG_NORMAL;
a4ade77
-        if (flags & wxCONTROL_CHECKED)
a4ade77
-        {
a4ade77
-            stateFlags = GTK_STATE_FLAG_ACTIVE;
a4ade77
-            if (gtk_check_version(3,14,0) == NULL)
a4ade77
-                stateFlags = GTK_STATE_FLAG_CHECKED;
a4ade77
-        }
a4ade77
-        if (flags & wxCONTROL_DISABLED)
a4ade77
-            stateFlags |= GTK_STATE_FLAG_INSENSITIVE;
a4ade77
-        if (flags & wxCONTROL_UNDETERMINED)
a4ade77
-            stateFlags |= GTK_STATE_FLAG_INCONSISTENT;
a4ade77
-        if (flags & wxCONTROL_CURRENT)
a4ade77
-            stateFlags |= GTK_STATE_FLAG_PRELIGHT;
a4ade77
-        GtkStyleContext* sc = gtk_widget_get_style_context(button);
a4ade77
-        gtk_style_context_save(sc);
a4ade77
-        gtk_style_context_set_state(sc, GtkStateFlags(stateFlags));
a4ade77
-        gtk_style_context_add_class(sc, GTK_STYLE_CLASS_CHECK);
a4ade77
-        gtk_render_check(sc, cr,
a4ade77
-            rect.x + (rect.width - indicator_size) / 2,
a4ade77
-            rect.y + (rect.height - indicator_size) / 2,
a4ade77
-            indicator_size, indicator_size);
a4ade77
-        gtk_style_context_restore(sc);
a4ade77
+        state = GTK_STATE_FLAG_ACTIVE;
a4ade77
+        if (gtk_check_version(3,14,0) == NULL)
a4ade77
+            state = GTK_STATE_FLAG_CHECKED;
a4ade77
+    }
a4ade77
+    if (flags & wxCONTROL_DISABLED)
a4ade77
+        state |= GTK_STATE_FLAG_INSENSITIVE;
a4ade77
+    if (flags & wxCONTROL_UNDETERMINED)
a4ade77
+        state |= GTK_STATE_FLAG_INCONSISTENT;
a4ade77
+    if (flags & wxCONTROL_CURRENT)
a4ade77
+        state |= GTK_STATE_FLAG_PRELIGHT;
a4ade77
+
a4ade77
+    int min_width, min_height;
a4ade77
+    GtkWidgetPath* path = gtk_widget_path_new();
a4ade77
+    GtkStyleContext* sc = gtk_style_context_new();
a4ade77
+    GtkStyleContext* sc1 = NULL;
a4ade77
+    gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON);
a4ade77
+#if GTK_CHECK_VERSION(3,20,0)
a4ade77
+    if (gtk_check_version(3,20,0) == NULL)
a4ade77
+    {
a4ade77
+        gtk_widget_path_iter_set_object_name(path, -1, "checkbutton");
a4ade77
+        sc1 = gtk_style_context_new();
a4ade77
+        gtk_style_context_set_path(sc1, path);
a4ade77
+        gtk_widget_path_append_type(path, G_TYPE_NONE);
a4ade77
+        gtk_widget_path_iter_set_object_name(path, -1, "check");
a4ade77
+        gtk_style_context_set_path(sc, path);
a4ade77
+        gtk_style_context_set_parent(sc, sc1);
a4ade77
+        gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
a4ade77
+            "min-width", &min_width, "min-height", &min_height, NULL);
a4ade77
+    }
a4ade77
+    else
a4ade77
+#endif
a4ade77
+    {
a4ade77
+        gtk_style_context_set_path(sc, path);
a4ade77
+        GValue value = G_VALUE_INIT;
a4ade77
+        g_value_init(&value, G_TYPE_INT);
a4ade77
+        gtk_style_context_get_style_property(sc, "indicator-size", &value);
a4ade77
+        min_width = g_value_get_int(&value);
a4ade77
+        min_height = min_width;
a4ade77
+        g_value_unset(&value);
a4ade77
     }
a4ade77
+
a4ade77
+    // need save/restore for GTK+ 3.6 & 3.8
a4ade77
+    gtk_style_context_save(sc);
a4ade77
+    gtk_style_context_set_state(sc, GtkStateFlags(state));
a4ade77
+    const int x = rect.x + (rect.width - min_width) / 2;
a4ade77
+    const int y = rect.y + (rect.height - min_height) / 2;
a4ade77
+    gtk_render_background(sc, cr, x, y, min_width, min_height);
a4ade77
+    gtk_render_frame(sc, cr, x, y, min_width, min_height);
a4ade77
+    gtk_style_context_add_class(sc, "check");
a4ade77
+    gtk_render_check(sc, cr, x, y, min_width, min_height);
a4ade77
+    gtk_style_context_restore(sc);
a4ade77
+
a4ade77
+    gtk_widget_path_unref(path);
a4ade77
+    g_object_unref(sc);
a4ade77
+    if (sc1)
a4ade77
+        g_object_unref(sc1);
a4ade77
 #else
a4ade77
     GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
a4ade77
     if (gdk_window == NULL)
a4ade77
@@ -869,8 +950,6 @@ void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect,
a4ade77
     if (drawable == NULL)
a4ade77
         return;
a4ade77
 
a4ade77
-    GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget();
a4ade77
-
a4ade77
 #ifdef __WXGTK3__
a4ade77
     int state = GTK_STATE_FLAG_NORMAL;
a4ade77
     if (flags & wxCONTROL_CHECKED)
a4ade77
@@ -879,18 +958,61 @@ void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect,
a4ade77
         if (gtk_check_version(3,14,0) == NULL)
a4ade77
             state = GTK_STATE_FLAG_CHECKED;
a4ade77
     }
a4ade77
-    else if (flags & wxCONTROL_UNDETERMINED)
a4ade77
-        state = GTK_STATE_FLAG_INCONSISTENT;
a4ade77
     if (flags & wxCONTROL_DISABLED)
a4ade77
         state |= GTK_STATE_FLAG_INSENSITIVE;
a4ade77
+    if (flags & wxCONTROL_UNDETERMINED)
a4ade77
+        state |= GTK_STATE_FLAG_INCONSISTENT;
a4ade77
+    if (flags & wxCONTROL_CURRENT)
a4ade77
+        state |= GTK_STATE_FLAG_PRELIGHT;
a4ade77
+
a4ade77
+    int min_width, min_height;
a4ade77
+    GtkWidgetPath* path = gtk_widget_path_new();
a4ade77
+    GtkStyleContext* sc = gtk_style_context_new();
a4ade77
+    GtkStyleContext* sc1 = NULL;
a4ade77
+    gtk_widget_path_append_type(path, GTK_TYPE_RADIO_BUTTON);
a4ade77
+#if GTK_CHECK_VERSION(3,20,0)
a4ade77
+    if (gtk_check_version(3,20,0) == NULL)
a4ade77
+    {
a4ade77
+        gtk_widget_path_iter_set_object_name(path, -1, "radiobutton");
a4ade77
+        sc1 = gtk_style_context_new();
a4ade77
+        gtk_style_context_set_path(sc1, path);
a4ade77
+        gtk_widget_path_append_type(path, G_TYPE_NONE);
a4ade77
+        gtk_widget_path_iter_set_object_name(path, -1, "radio");
a4ade77
+        gtk_style_context_set_path(sc, path);
a4ade77
+        gtk_style_context_set_parent(sc, sc1);
a4ade77
+        gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
a4ade77
+            "min-width", &min_width, "min-height", &min_height, NULL);
a4ade77
+    }
a4ade77
+    else
a4ade77
+#endif
a4ade77
+    {
a4ade77
+        gtk_style_context_set_path(sc, path);
a4ade77
+        GValue value = G_VALUE_INIT;
a4ade77
+        g_value_init(&value, G_TYPE_INT);
a4ade77
+        gtk_style_context_get_style_property(sc, "indicator-size", &value);
a4ade77
+        min_width = g_value_get_int(&value);
a4ade77
+        min_height = min_width;
a4ade77
+        g_value_unset(&value);
a4ade77
+    }
a4ade77
 
a4ade77
-    GtkStyleContext* sc = gtk_widget_get_style_context(button);
a4ade77
+    // need save/restore for GTK+ 3.6 & 3.8
a4ade77
     gtk_style_context_save(sc);
a4ade77
-    gtk_style_context_add_class(sc, GTK_STYLE_CLASS_RADIO);
a4ade77
     gtk_style_context_set_state(sc, GtkStateFlags(state));
a4ade77
-    gtk_render_option(sc, drawable, rect.x, rect.y, rect.width, rect.height); 
a4ade77
+    const int x = rect.x + (rect.width - min_width) / 2;
a4ade77
+    const int y = rect.y + (rect.height - min_height) / 2;
a4ade77
+    gtk_render_background(sc, drawable, x, y, min_width, min_height);
a4ade77
+    gtk_render_frame(sc, drawable, x, y, min_width, min_height);
a4ade77
+    gtk_style_context_add_class(sc, "radio");
a4ade77
+    gtk_render_option(sc, drawable, x, y, min_width, min_height);
a4ade77
     gtk_style_context_restore(sc);
a4ade77
+
a4ade77
+    gtk_widget_path_unref(path);
a4ade77
+    g_object_unref(sc);
a4ade77
+    if (sc1)
a4ade77
+        g_object_unref(sc1);
a4ade77
 #else
a4ade77
+    GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget();
a4ade77
+
a4ade77
     GtkShadowType shadow_type = GTK_SHADOW_OUT;
a4ade77
     if ( flags & wxCONTROL_CHECKED )
a4ade77
         shadow_type = GTK_SHADOW_IN;