Add GtkStyleContext helper class

Manages ownership of GtkStyleContext and GtkWidgetPath, provides functions
for creating and querying style contexts.
This commit is contained in:
Paul Cornett
2018-06-05 09:21:25 -07:00
parent c8f563f269
commit 102be6a3cc
3 changed files with 211 additions and 306 deletions

View File

@@ -0,0 +1,46 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/gtk/private/stylecontext.h
// Purpose: GtkStyleContext helper class
// Author: Paul Cornett
// Created: 2018-06-04
// Copyright: (c) 2018 Paul Cornett
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_GTK_PRIVATE_STYLECONTEXT_H_
#define _WX_GTK_PRIVATE_STYLECONTEXT_H_
#ifdef __WXGTK3__
class wxGtkStyleContext
{
public:
wxGtkStyleContext();
~wxGtkStyleContext();
wxGtkStyleContext& Add(GType type, const char* objectName, ...) G_GNUC_NULL_TERMINATED;
wxGtkStyleContext& Add(const char* objectName);
wxGtkStyleContext& AddButton();
wxGtkStyleContext& AddCheckButton();
wxGtkStyleContext& AddHeaderbar();
wxGtkStyleContext& AddLabel();
wxGtkStyleContext& AddMenu();
wxGtkStyleContext& AddMenuItem();
wxGtkStyleContext& AddTextview(const char* child1 = NULL, const char* child2 = NULL);
wxGtkStyleContext& AddTooltip();
wxGtkStyleContext& AddTreeview();
wxGtkStyleContext& AddTreeviewHeaderButton(int pos);
wxGtkStyleContext& AddWindow(const char* className2 = NULL);
void Bg(wxColour& color, int state = GTK_STATE_FLAG_NORMAL) const;
void Fg(wxColour& color, int state = GTK_STATE_FLAG_NORMAL) const;
void Border(wxColour& color) const;
operator GtkStyleContext*() { return m_context; }
private:
GtkStyleContext* m_context;
GtkWidgetPath* const m_path;
wxDECLARE_NO_COPY_CLASS(wxGtkStyleContext);
};
#endif // __WXGTK3__
#endif // _WX_GTK_PRIVATE_STYLECONTEXT_H_

View File

@@ -38,6 +38,7 @@
#endif #endif
#include "wx/gtk/private.h" #include "wx/gtk/private.h"
#include "wx/gtk/private/stylecontext.h"
#if defined(__WXGTK3__) && !GTK_CHECK_VERSION(3,14,0) #if defined(__WXGTK3__) && !GTK_CHECK_VERSION(3,14,0)
#define GTK_STATE_FLAG_CHECKED (1 << 11) #define GTK_STATE_FLAG_CHECKED (1 << 11)
@@ -230,58 +231,18 @@ wxRendererGTK::DrawHeaderButton(wxWindow *win,
#if GTK_CHECK_VERSION(3,20,0) #if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL) if (gtk_check_version(3,20,0) == NULL)
{ {
GtkWidgetPath* path = gtk_widget_path_new();
GtkStyleContext* parent;
GtkStyleContext* sc = gtk_style_context_new();
gtk_widget_path_append_type(path, GTK_TYPE_WINDOW);
gtk_widget_path_iter_set_object_name(path, -1, "window");
gtk_widget_path_iter_add_class(path, -1, "background");
gtk_style_context_set_path(sc, path);
parent = sc;
sc = gtk_style_context_new();
gtk_widget_path_append_type(path, GTK_TYPE_TREE_VIEW);
gtk_widget_path_iter_set_object_name(path, -1, "treeview");
gtk_widget_path_iter_add_class(path, -1, "view");
gtk_style_context_set_path(sc, path);
gtk_style_context_set_parent(sc, parent);
g_object_unref(parent);
parent = sc;
sc = gtk_style_context_new();
gtk_widget_path_append_type(path, G_TYPE_NONE);
gtk_widget_path_iter_set_object_name(path, -1, "header");
gtk_style_context_set_path(sc, path);
gtk_style_context_set_parent(sc, parent);
g_object_unref(parent);
parent = sc;
sc = gtk_style_context_new();
int pos = 1; int pos = 1;
if (flags & wxCONTROL_SPECIAL) if (flags & wxCONTROL_SPECIAL)
pos = 0; pos = 0;
if (flags & wxCONTROL_DIRTY) if (flags & wxCONTROL_DIRTY)
pos = 2; pos = 2;
GtkWidgetPath* siblings = gtk_widget_path_new();
gtk_widget_path_append_type(siblings, GTK_TYPE_BUTTON); wxGtkStyleContext sc;
gtk_widget_path_iter_set_object_name(siblings, -1, "button"); sc.AddTreeviewHeaderButton(pos);
gtk_widget_path_append_type(siblings, GTK_TYPE_BUTTON);
gtk_widget_path_iter_set_object_name(siblings, -1, "button");
gtk_widget_path_append_type(siblings, GTK_TYPE_BUTTON);
gtk_widget_path_iter_set_object_name(siblings, -1, "button");
gtk_widget_path_append_with_siblings(path, siblings, pos);
gtk_widget_path_unref(siblings);
gtk_style_context_set_path(sc, path);
gtk_style_context_set_parent(sc, parent);
g_object_unref(parent);
gtk_widget_path_unref(path);
gtk_style_context_set_state(sc, stateTypeToFlags[state]); gtk_style_context_set_state(sc, stateTypeToFlags[state]);
gtk_render_background(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height); gtk_render_background(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height);
gtk_render_frame(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height); gtk_render_frame(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height);
g_object_unref(sc);
} }
else else
#endif #endif
@@ -477,36 +438,14 @@ wxRendererGTK::DrawSplitterSash(wxWindow* win,
x_diff = rect.width; x_diff = rect.width;
#ifdef __WXGTK3__ #ifdef __WXGTK3__
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc = gtk_style_context_new(); sc.Add(GTK_TYPE_PANED, "paned", "pane-separator", NULL);
GtkStyleContext* sc1 = NULL;
gtk_widget_path_append_type(path, GTK_TYPE_PANED);
#if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL) if (gtk_check_version(3,20,0) == NULL)
{ sc.Add("separator");
gtk_widget_path_iter_set_object_name(path, -1, "paned");
sc1 = gtk_style_context_new();
gtk_style_context_set_path(sc1, path);
gtk_widget_path_append_type(path, G_TYPE_NONE);
gtk_widget_path_iter_set_object_name(path, -1, "separator");
gtk_style_context_set_path(sc, path);
gtk_style_context_set_parent(sc, sc1);
}
else
#endif
{
gtk_widget_path_iter_add_class(path, -1, GTK_STYLE_CLASS_PANE_SEPARATOR);
gtk_style_context_set_path(sc, path);
}
gtk_style_context_set_state(sc, gtk_style_context_set_state(sc,
flags & wxCONTROL_CURRENT ? GTK_STATE_FLAG_PRELIGHT : GTK_STATE_FLAG_NORMAL); flags & wxCONTROL_CURRENT ? GTK_STATE_FLAG_PRELIGHT : GTK_STATE_FLAG_NORMAL);
gtk_render_handle(sc, drawable, rect.x - x_diff, rect.y, rect.width, rect.height); gtk_render_handle(sc, drawable, rect.x - x_diff, rect.y, rect.width, rect.height);
gtk_widget_path_unref(path);
g_object_unref(sc);
if (sc1)
g_object_unref(sc1);
#else #else
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc); GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
if (gdk_window == NULL) if (gdk_window == NULL)
@@ -605,20 +544,11 @@ wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
{ {
#ifdef __WXGTK3__ #ifdef __WXGTK3__
int min_width, min_height; int min_width, min_height;
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc = gtk_style_context_new(); sc.AddCheckButton();
GtkStyleContext* sc1 = NULL;
gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON);
#if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL) if (gtk_check_version(3,20,0) == NULL)
{ {
gtk_widget_path_iter_set_object_name(path, -1, "checkbutton"); sc.Add("check");
sc1 = gtk_style_context_new();
gtk_style_context_set_path(sc1, path);
gtk_widget_path_append_type(path, G_TYPE_NONE);
gtk_widget_path_iter_set_object_name(path, -1, "check");
gtk_style_context_set_path(sc, path);
gtk_style_context_set_parent(sc, sc1);
gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
"min-width", &min_width, "min-height", &min_height, NULL); "min-width", &min_width, "min-height", &min_height, NULL);
GtkBorder margin; GtkBorder margin;
@@ -627,9 +557,7 @@ wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
min_height += margin.top + margin.bottom; min_height += margin.top + margin.bottom;
} }
else else
#endif
{ {
gtk_style_context_set_path(sc, path);
GValue value = G_VALUE_INIT; GValue value = G_VALUE_INIT;
g_value_init(&value, G_TYPE_INT); g_value_init(&value, G_TYPE_INT);
gtk_style_context_get_style_property(sc, "indicator-size", &value); gtk_style_context_get_style_property(sc, "indicator-size", &value);
@@ -639,10 +567,6 @@ wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
min_height = min_width; min_height = min_width;
g_value_unset(&value); g_value_unset(&value);
} }
gtk_widget_path_unref(path);
g_object_unref(sc);
if (sc1)
g_object_unref(sc1);
return wxSize(min_width, min_height); return wxSize(min_width, min_height);
#else // !__WXGTK3__ #else // !__WXGTK3__
@@ -713,27 +637,16 @@ wxRendererGTK::DrawCheckBox(wxWindow* win,
state |= GTK_STATE_FLAG_PRELIGHT; state |= GTK_STATE_FLAG_PRELIGHT;
int min_width, min_height; int min_width, min_height;
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc = gtk_style_context_new(); sc.AddCheckButton();
GtkStyleContext* sc1 = NULL;
gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON);
#if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL) if (gtk_check_version(3,20,0) == NULL)
{ {
gtk_widget_path_iter_set_object_name(path, -1, "checkbutton"); sc.Add("check");
sc1 = gtk_style_context_new();
gtk_style_context_set_path(sc1, path);
gtk_widget_path_append_type(path, G_TYPE_NONE);
gtk_widget_path_iter_set_object_name(path, -1, "check");
gtk_style_context_set_path(sc, path);
gtk_style_context_set_parent(sc, sc1);
gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
"min-width", &min_width, "min-height", &min_height, NULL); "min-width", &min_width, "min-height", &min_height, NULL);
} }
else else
#endif
{ {
gtk_style_context_set_path(sc, path);
GValue value = G_VALUE_INIT; GValue value = G_VALUE_INIT;
g_value_init(&value, G_TYPE_INT); g_value_init(&value, G_TYPE_INT);
gtk_style_context_get_style_property(sc, "indicator-size", &value); gtk_style_context_get_style_property(sc, "indicator-size", &value);
@@ -752,11 +665,6 @@ wxRendererGTK::DrawCheckBox(wxWindow* win,
gtk_style_context_add_class(sc, "check"); gtk_style_context_add_class(sc, "check");
gtk_render_check(sc, cr, x, y, min_width, min_height); gtk_render_check(sc, cr, x, y, min_width, min_height);
gtk_style_context_restore(sc); gtk_style_context_restore(sc);
gtk_widget_path_unref(path);
g_object_unref(sc);
if (sc1)
g_object_unref(sc1);
#else #else
GdkWindow* gdk_window = wxGetGTKDrawable(win, dc); GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
if (gdk_window == NULL) if (gdk_window == NULL)
@@ -923,22 +831,12 @@ void wxRendererGTK::DrawTextCtrl(wxWindow* win, wxDC& dc, const wxRect& rect, in
if (flags & wxCONTROL_DISABLED) if (flags & wxCONTROL_DISABLED)
state = GTK_STATE_FLAG_INSENSITIVE; state = GTK_STATE_FLAG_INSENSITIVE;
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc = gtk_style_context_new(); sc.Add(GTK_TYPE_ENTRY, "entry", "entry", NULL);
gtk_widget_path_append_type(path, GTK_TYPE_ENTRY);
#if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL)
gtk_widget_path_iter_set_object_name(path, -1, "entry");
#endif
gtk_widget_path_iter_add_class(path, -1, "entry");
gtk_style_context_set_path(sc, path);
gtk_style_context_set_state(sc, GtkStateFlags(state)); gtk_style_context_set_state(sc, GtkStateFlags(state));
gtk_render_background(sc, drawable, rect.x, rect.y, rect.width, rect.height); gtk_render_background(sc, drawable, rect.x, rect.y, rect.width, rect.height);
gtk_render_frame(sc, drawable, rect.x, rect.y, rect.width, rect.height); gtk_render_frame(sc, drawable, rect.x, rect.y, rect.width, rect.height);
gtk_widget_path_unref(path);
g_object_unref(sc);
#else #else
GtkWidget* entry = wxGTKPrivate::GetTextEntryWidget(); GtkWidget* entry = wxGTKPrivate::GetTextEntryWidget();
@@ -1082,27 +980,18 @@ void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect,
state |= GTK_STATE_FLAG_PRELIGHT; state |= GTK_STATE_FLAG_PRELIGHT;
int min_width, min_height; int min_width, min_height;
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc = gtk_style_context_new(); sc.Add(GTK_TYPE_RADIO_BUTTON, "radiobutton", NULL);
GtkStyleContext* sc1 = NULL;
gtk_widget_path_append_type(path, GTK_TYPE_RADIO_BUTTON);
#if GTK_CHECK_VERSION(3,20,0) #if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL) if (gtk_check_version(3,20,0) == NULL)
{ {
gtk_widget_path_iter_set_object_name(path, -1, "radiobutton"); sc.Add("radio");
sc1 = gtk_style_context_new();
gtk_style_context_set_path(sc1, path);
gtk_widget_path_append_type(path, G_TYPE_NONE);
gtk_widget_path_iter_set_object_name(path, -1, "radio");
gtk_style_context_set_path(sc, path);
gtk_style_context_set_parent(sc, sc1);
gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
"min-width", &min_width, "min-height", &min_height, NULL); "min-width", &min_width, "min-height", &min_height, NULL);
} }
else else
#endif #endif
{ {
gtk_style_context_set_path(sc, path);
GValue value = G_VALUE_INIT; GValue value = G_VALUE_INIT;
g_value_init(&value, G_TYPE_INT); g_value_init(&value, G_TYPE_INT);
gtk_style_context_get_style_property(sc, "indicator-size", &value); gtk_style_context_get_style_property(sc, "indicator-size", &value);
@@ -1121,11 +1010,6 @@ void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect,
gtk_style_context_add_class(sc, "radio"); gtk_style_context_add_class(sc, "radio");
gtk_render_option(sc, drawable, x, y, min_width, min_height); gtk_render_option(sc, drawable, x, y, min_width, min_height);
gtk_style_context_restore(sc); gtk_style_context_restore(sc);
gtk_widget_path_unref(path);
g_object_unref(sc);
if (sc1)
g_object_unref(sc1);
#else #else
GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget(); GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget();

View File

@@ -23,6 +23,7 @@
#include "wx/gtk/private/wrapgtk.h" #include "wx/gtk/private/wrapgtk.h"
#include "wx/gtk/private/gtk3-compat.h" #include "wx/gtk/private/gtk3-compat.h"
#include "wx/gtk/private/win_gtk.h" #include "wx/gtk/private/win_gtk.h"
#include "wx/gtk/private/stylecontext.h"
bool wxGetFrameExtents(GdkWindow* window, int* left, int* right, int* top, int* bottom); bool wxGetFrameExtents(GdkWindow* window, int* left, int* right, int* top, int* bottom);
@@ -192,60 +193,65 @@ static void notify_gtk_font_name(GObject*, GParamSpec*, void*)
// the same hierarchy in it. So the best way to get style information seems // the same hierarchy in it. So the best way to get style information seems
// to be creating the widget paths and context hierarchy directly. // to be creating the widget paths and context hierarchy directly.
static GtkStyleContext* StyleContext( //-----------------------------------------------------------------------------
GtkStyleContext* parent, // wxGtkStyleContext
GtkWidgetPath* path, //-----------------------------------------------------------------------------
GType type,
const char* objectName, wxGtkStyleContext::wxGtkStyleContext()
const char* className1 = NULL, : m_path(gtk_widget_path_new())
const char* className2 = NULL)
{ {
gtk_widget_path_append_type(path, type); m_context = NULL;
}
wxGtkStyleContext& wxGtkStyleContext::Add(GType type, const char* objectName, ...)
{
if (m_context == NULL && type != GTK_TYPE_WINDOW)
AddWindow();
gtk_widget_path_append_type(m_path, type);
#if GTK_CHECK_VERSION(3,20,0) #if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL) if (gtk_check_version(3,20,0) == NULL)
gtk_widget_path_iter_set_object_name(path, -1, objectName); gtk_widget_path_iter_set_object_name(m_path, -1, objectName);
#else
wxUnusedVar(objectName);
#endif #endif
if (className1) va_list args;
gtk_widget_path_iter_add_class(path, -1, className1); va_start(args, objectName);
if (className2) const char* className;
gtk_widget_path_iter_add_class(path, -1, className2); while ((className = va_arg(args, char*)))
gtk_widget_path_iter_add_class(m_path, -1, className);
va_end(args);
GtkStyleContext* sc = gtk_style_context_new(); GtkStyleContext* sc = gtk_style_context_new();
gtk_style_context_set_path(sc, path); gtk_style_context_set_path(sc, m_path);
if (parent) if (m_context)
{ {
#if GTK_CHECK_VERSION(3,4,0) #if GTK_CHECK_VERSION(3,4,0)
if (gtk_check_version(3,4,0) == NULL) if (gtk_check_version(3,4,0) == NULL)
gtk_style_context_set_parent(sc, parent); gtk_style_context_set_parent(sc, m_context);
#endif #endif
g_object_unref(parent); g_object_unref(m_context);
} }
return sc; m_context = sc;
return *this;
} }
static GtkStyleContext* StyleContext( wxGtkStyleContext& wxGtkStyleContext::Add(const char* objectName)
GtkWidgetPath* path,
GType type,
const char* objectName,
const char* className1 = NULL,
const char* className2 = NULL)
{ {
GtkStyleContext* sc; return Add(G_TYPE_NONE, objectName, NULL);
sc = StyleContext(NULL, path, GTK_TYPE_WINDOW, "window", "background");
sc = StyleContext(sc, path, type, objectName, className1, className2);
return sc;
} }
static void StyleContextFree(GtkStyleContext* sc) wxGtkStyleContext::~wxGtkStyleContext()
{ {
gtk_widget_path_unref(m_path);
if (m_context == NULL)
return;
if (gtk_check_version(3,16,0) == NULL || gtk_check_version(3,4,0)) if (gtk_check_version(3,16,0) == NULL || gtk_check_version(3,4,0))
{ {
g_object_unref(sc); g_object_unref(m_context);
return; return;
} }
#if GTK_CHECK_VERSION(3,4,0) #if GTK_CHECK_VERSION(3,4,0)
// GTK+ < 3.16 does not properly handle freeing child context before parent // GTK+ < 3.16 does not properly handle freeing child context before parent
GtkStyleContext* sc = m_context;
do { do {
GtkStyleContext* parent = gtk_style_context_get_parent(sc); GtkStyleContext* parent = gtk_style_context_get_parent(sc);
if (parent) if (parent)
@@ -259,74 +265,84 @@ static void StyleContextFree(GtkStyleContext* sc)
#endif #endif
} }
static GtkStyleContext* ButtonContext(GtkWidgetPath* path) wxGtkStyleContext& wxGtkStyleContext::AddButton()
{ {
GtkStyleContext* sc; return Add(GTK_TYPE_BUTTON, "button", "button", NULL);
sc = StyleContext(path, GTK_TYPE_BUTTON, "button", "button");
return sc;
} }
static GtkStyleContext* ButtonLabelContext(GtkWidgetPath* path) wxGtkStyleContext& wxGtkStyleContext::AddCheckButton()
{ {
GtkStyleContext* sc; return Add(GTK_TYPE_CHECK_BUTTON, "checkbutton", NULL);
sc = ButtonContext(path);
sc = StyleContext(sc, path, GTK_TYPE_LABEL, "label");
return sc;
} }
static GtkStyleContext* HeaderbarContext(GtkWidgetPath* path) #if GTK_CHECK_VERSION(3,10,0)
wxGtkStyleContext& wxGtkStyleContext::AddHeaderbar()
{ {
GtkStyleContext* sc; return Add(GTK_TYPE_HEADER_BAR, "headerbar", "titlebar", "header-bar", NULL);
sc = StyleContext(path, GTK_TYPE_HEADER_BAR, "headerbar", "titlebar", "header-bar"); }
return sc; #endif
wxGtkStyleContext& wxGtkStyleContext::AddLabel()
{
return Add(GTK_TYPE_LABEL, "label", NULL);
} }
static GtkStyleContext* HeaderbarLabelContext(GtkWidgetPath* path) wxGtkStyleContext& wxGtkStyleContext::AddMenu()
{ {
GtkStyleContext* sc; return AddWindow("popup").Add(GTK_TYPE_MENU, "menu", "menu", NULL);
sc = HeaderbarContext(path);
sc = StyleContext(sc, path, GTK_TYPE_LABEL, "label");
return sc;
} }
static GtkStyleContext* MenuContext(GtkWidgetPath* path) wxGtkStyleContext& wxGtkStyleContext::AddMenuItem()
{ {
GtkStyleContext* sc; return AddMenu().Add(GTK_TYPE_MENU_ITEM, "menuitem", "menuitem", NULL);
sc = StyleContext(NULL, path, GTK_TYPE_WINDOW, "window", "background", "popup");
sc = StyleContext(sc, path, GTK_TYPE_MENU, "menu", "menu");
return sc;
} }
static GtkStyleContext* MenuItemContext(GtkWidgetPath* path) wxGtkStyleContext& wxGtkStyleContext::AddTextview(const char* child1, const char* child2)
{ {
GtkStyleContext* sc; Add(GTK_TYPE_TEXT_VIEW, "textview", "view", NULL);
sc = MenuContext(path);
sc = StyleContext(sc, path, GTK_TYPE_MENU_ITEM, "menuitem", "menuitem");
return sc;
}
static GtkStyleContext* TextviewContext(GtkWidgetPath* path, const char* child1 = NULL, const char* child2 = NULL)
{
GtkStyleContext* sc;
sc = StyleContext(path, GTK_TYPE_TEXT_VIEW, "textview", "view");
if (child1 && gtk_check_version(3,20,0) == NULL) if (child1 && gtk_check_version(3,20,0) == NULL)
{ {
sc = StyleContext(sc, path, G_TYPE_NONE, child1); Add(child1);
if (child2) if (child2)
sc = StyleContext(sc, path, G_TYPE_NONE, child2); Add(child2);
} }
return sc; return *this;
} }
static GtkStyleContext* TreeviewContext(GtkWidgetPath* path) wxGtkStyleContext& wxGtkStyleContext::AddTreeview()
{ {
GtkStyleContext* sc; return Add(GTK_TYPE_TREE_VIEW, "treeview", "view", NULL);
sc = StyleContext(path, GTK_TYPE_TREE_VIEW, "treeview", "view");
return sc;
} }
static GtkStyleContext* TooltipContext(GtkWidgetPath* path) #if GTK_CHECK_VERSION(3,20,0)
wxGtkStyleContext& wxGtkStyleContext::AddTreeviewHeaderButton(int pos)
{ {
AddTreeview().Add("header");
GtkStyleContext* sc = gtk_style_context_new();
GtkWidgetPath* siblings = gtk_widget_path_new();
gtk_widget_path_append_type(siblings, GTK_TYPE_BUTTON);
gtk_widget_path_iter_set_object_name(siblings, -1, "button");
gtk_widget_path_append_type(siblings, GTK_TYPE_BUTTON);
gtk_widget_path_iter_set_object_name(siblings, -1, "button");
gtk_widget_path_append_type(siblings, GTK_TYPE_BUTTON);
gtk_widget_path_iter_set_object_name(siblings, -1, "button");
gtk_widget_path_append_with_siblings(m_path, siblings, pos);
gtk_widget_path_unref(siblings);
gtk_style_context_set_path(sc, m_path);
gtk_style_context_set_parent(sc, m_context);
g_object_unref(m_context);
m_context = sc;
return *this;
}
#endif // GTK_CHECK_VERSION(3,20,0)
wxGtkStyleContext& wxGtkStyleContext::AddTooltip()
{
wxASSERT(m_context == NULL);
GtkWidgetPath* path = m_path;
gtk_widget_path_append_type(path, GTK_TYPE_WINDOW); gtk_widget_path_append_type(path, GTK_TYPE_WINDOW);
#if GTK_CHECK_VERSION(3,20,0) #if GTK_CHECK_VERSION(3,20,0)
if (gtk_check_version(3,20,0) == NULL) if (gtk_check_version(3,20,0) == NULL)
@@ -335,17 +351,22 @@ static GtkStyleContext* TooltipContext(GtkWidgetPath* path)
gtk_widget_path_iter_add_class(path, -1, "background"); gtk_widget_path_iter_add_class(path, -1, "background");
gtk_widget_path_iter_add_class(path, -1, "tooltip"); gtk_widget_path_iter_add_class(path, -1, "tooltip");
gtk_widget_path_iter_set_name(path, -1, "gtk-tooltip"); gtk_widget_path_iter_set_name(path, -1, "gtk-tooltip");
GtkStyleContext* sc = gtk_style_context_new(); m_context = gtk_style_context_new();
gtk_style_context_set_path(sc, path); gtk_style_context_set_path(m_context, m_path);
return sc; return *this;
} }
static void bg(GtkStyleContext* sc, wxColour& color, int state = GTK_STATE_FLAG_NORMAL) wxGtkStyleContext& wxGtkStyleContext::AddWindow(const char* className2)
{
return Add(GTK_TYPE_WINDOW, "window", "background", className2, NULL);
}
void wxGtkStyleContext::Bg(wxColour& color, int state) const
{ {
GdkRGBA* rgba; GdkRGBA* rgba;
cairo_pattern_t* pattern = NULL; cairo_pattern_t* pattern = NULL;
gtk_style_context_set_state(sc, GtkStateFlags(state)); gtk_style_context_set_state(m_context, GtkStateFlags(state));
gtk_style_context_get(sc, GtkStateFlags(state), gtk_style_context_get(m_context, GtkStateFlags(state),
"background-color", &rgba, "background-image", &pattern, NULL); "background-color", &rgba, "background-image", &pattern, NULL);
color = wxColour(*rgba); color = wxColour(*rgba);
gdk_rgba_free(rgba); gdk_rgba_free(rgba);
@@ -401,43 +422,33 @@ static void bg(GtkStyleContext* sc, wxColour& color, int state = GTK_STATE_FLAG_
if (color.Alpha() == 0) if (color.Alpha() == 0)
{ {
// Try TLW as last resort, but not if we're already doing it // Try TLW as last resort, but not if we're already doing it
const GtkWidgetPath* path0 = gtk_style_context_get_path(sc); if (gtk_widget_path_length(m_path) > 1)
if (gtk_widget_path_length(path0) > 1 || wxGtkStyleContext().AddWindow().Bg(color, state);
gtk_widget_path_iter_get_object_type(path0, 0) != GTK_TYPE_WINDOW)
{
GtkWidgetPath* path = gtk_widget_path_new();
GtkStyleContext* sc2;
sc2 = StyleContext(NULL, path, GTK_TYPE_WINDOW, "window", "background");
gtk_widget_path_unref(path);
bg(sc2, color, state);
} }
}
StyleContextFree(sc);
} }
static void fg(GtkStyleContext* sc, wxColour& color, int state = GTK_STATE_FLAG_NORMAL) void wxGtkStyleContext::Fg(wxColour& color, int state) const
{ {
GdkRGBA rgba; GdkRGBA rgba;
gtk_style_context_set_state(sc, GtkStateFlags(state)); gtk_style_context_set_state(m_context, GtkStateFlags(state));
#ifdef __WXGTK4__ #ifdef __WXGTK4__
gtk_style_context_get_color(sc, &rgba); gtk_style_context_get_color(m_context, &rgba);
#else #else
gtk_style_context_get_color(sc, GtkStateFlags(state), &rgba); gtk_style_context_get_color(m_context, GtkStateFlags(state), &rgba);
#endif #endif
color = wxColour(rgba); color = wxColour(rgba);
StyleContextFree(sc);
} }
static void border(GtkStyleContext* sc, wxColour& color) void wxGtkStyleContext::Border(wxColour& color) const
{ {
GdkRGBA* rgba; GdkRGBA* rgba;
gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, "border-color", &rgba, NULL); gtk_style_context_get(m_context, GTK_STATE_FLAG_NORMAL, "border-color", &rgba, NULL);
color = wxColour(*rgba); color = wxColour(*rgba);
gdk_rgba_free(rgba); gdk_rgba_free(rgba);
StyleContextFree(sc);
} }
//-----------------------------------------------------------------------------
wxColour wxSystemSettingsNative::GetColour(wxSystemColour index) wxColour wxSystemSettingsNative::GetColour(wxSystemColour index)
{ {
if (unsigned(index) > wxSYS_COLOUR_MAX) if (unsigned(index) > wxSYS_COLOUR_MAX)
@@ -455,8 +466,7 @@ wxColour wxSystemSettingsNative::GetColour(wxSystemColour index)
G_CALLBACK(notify_gtk_theme_name), NULL); G_CALLBACK(notify_gtk_theme_name), NULL);
} }
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc;
switch (index) switch (index)
{ {
@@ -467,18 +477,17 @@ wxColour wxSystemSettingsNative::GetColour(wxSystemColour index)
#if GTK_CHECK_VERSION(3,10,0) #if GTK_CHECK_VERSION(3,10,0)
if (gtk_check_version(3,10,0) == NULL) if (gtk_check_version(3,10,0) == NULL)
{ {
sc = HeaderbarContext(path);
int state = GTK_STATE_FLAG_NORMAL; int state = GTK_STATE_FLAG_NORMAL;
if (index == wxSYS_COLOUR_INACTIVECAPTION || if (index == wxSYS_COLOUR_INACTIVECAPTION ||
index == wxSYS_COLOUR_GRADIENTINACTIVECAPTION) index == wxSYS_COLOUR_GRADIENTINACTIVECAPTION)
{ {
state = GTK_STATE_FLAG_BACKDROP; state = GTK_STATE_FLAG_BACKDROP;
} }
bg(sc, color, state); sc.AddHeaderbar().Bg(color, state);
break; break;
} }
#endif
wxFALLTHROUGH; wxFALLTHROUGH;
#endif
case wxSYS_COLOUR_3DLIGHT: case wxSYS_COLOUR_3DLIGHT:
case wxSYS_COLOUR_ACTIVEBORDER: case wxSYS_COLOUR_ACTIVEBORDER:
case wxSYS_COLOUR_BTNFACE: case wxSYS_COLOUR_BTNFACE:
@@ -486,64 +495,54 @@ wxColour wxSystemSettingsNative::GetColour(wxSystemColour index)
case wxSYS_COLOUR_INACTIVEBORDER: case wxSYS_COLOUR_INACTIVEBORDER:
case wxSYS_COLOUR_SCROLLBAR: case wxSYS_COLOUR_SCROLLBAR:
case wxSYS_COLOUR_WINDOWFRAME: case wxSYS_COLOUR_WINDOWFRAME:
sc = ButtonContext(path); sc.AddButton().Bg(color);
bg(sc, color);
break; break;
case wxSYS_COLOUR_HIGHLIGHT: case wxSYS_COLOUR_HIGHLIGHT:
sc = TextviewContext(path, "text", "selection"); sc.AddTextview("text", "selection");
bg(sc, color, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED); sc.Bg(color, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED);
break; break;
case wxSYS_COLOUR_HIGHLIGHTTEXT: case wxSYS_COLOUR_HIGHLIGHTTEXT:
sc = TextviewContext(path, "text", "selection"); sc.AddTextview("text", "selection");
fg(sc, color, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED); sc.Fg(color, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED);
break; break;
case wxSYS_COLOUR_WINDOWTEXT: case wxSYS_COLOUR_WINDOWTEXT:
sc = TextviewContext(path, "text"); sc.AddTextview("text").Fg(color);
fg(sc, color);
break; break;
case wxSYS_COLOUR_BTNHIGHLIGHT: case wxSYS_COLOUR_BTNHIGHLIGHT:
sc = ButtonContext(path); sc.AddButton().Bg(color, GTK_STATE_FLAG_PRELIGHT);
bg(sc, color, GTK_STATE_FLAG_PRELIGHT);
break; break;
case wxSYS_COLOUR_BTNSHADOW: case wxSYS_COLOUR_BTNSHADOW:
sc = ButtonContext(path); sc.AddButton().Border(color);
border(sc, color);
break; break;
case wxSYS_COLOUR_CAPTIONTEXT: case wxSYS_COLOUR_CAPTIONTEXT:
#if GTK_CHECK_VERSION(3,10,0) #if GTK_CHECK_VERSION(3,10,0)
if (gtk_check_version(3,10,0) == NULL) if (gtk_check_version(3,10,0) == NULL)
{ {
sc = HeaderbarLabelContext(path); sc.AddHeaderbar().AddLabel().Fg(color);
fg(sc, color);
break; break;
} }
#endif
wxFALLTHROUGH; wxFALLTHROUGH;
#endif
case wxSYS_COLOUR_BTNTEXT: case wxSYS_COLOUR_BTNTEXT:
sc = ButtonLabelContext(path); sc.AddButton().AddLabel().Fg(color);
fg(sc, color);
break; break;
case wxSYS_COLOUR_INACTIVECAPTIONTEXT: case wxSYS_COLOUR_INACTIVECAPTIONTEXT:
#if GTK_CHECK_VERSION(3,10,0) #if GTK_CHECK_VERSION(3,10,0)
if (gtk_check_version(3,10,0) == NULL) if (gtk_check_version(3,10,0) == NULL)
{ {
sc = HeaderbarLabelContext(path); sc.AddHeaderbar().AddLabel().Fg(color, GTK_STATE_FLAG_BACKDROP);
fg(sc, color, GTK_STATE_FLAG_BACKDROP);
break; break;
} }
#endif
wxFALLTHROUGH; wxFALLTHROUGH;
#endif
case wxSYS_COLOUR_GRAYTEXT: case wxSYS_COLOUR_GRAYTEXT:
sc = StyleContext(path, GTK_TYPE_LABEL, "label"); sc.AddLabel().Fg(color, GTK_STATE_FLAG_INSENSITIVE);
fg(sc, color, GTK_STATE_FLAG_INSENSITIVE);
break; break;
case wxSYS_COLOUR_HOTLIGHT: case wxSYS_COLOUR_HOTLIGHT:
sc = StyleContext(path, GTK_TYPE_LINK_BUTTON, "button", "link"); sc.Add(GTK_TYPE_LINK_BUTTON, "button", "link", NULL);
#ifdef __WXGTK4__ if (wx_is_at_least_gtk3(12))
fg(sc, color, GTK_STATE_FLAG_LINK); sc.Fg(color, GTK_STATE_FLAG_LINK);
#else #ifndef __WXGTK4__
if (gtk_check_version(3,12,0) == NULL)
fg(sc, color, GTK_STATE_FLAG_LINK);
else else
{ {
wxGCC_WARNING_SUPPRESS(deprecated-declarations) wxGCC_WARNING_SUPPRESS(deprecated-declarations)
@@ -556,53 +555,40 @@ wxColour wxSystemSettingsNative::GetColour(wxSystemColour index)
gdkColor = *link_color; gdkColor = *link_color;
color = wxColour(gdkColor); color = wxColour(gdkColor);
g_value_unset(&value); g_value_unset(&value);
StyleContextFree(sc);
wxGCC_WARNING_RESTORE() wxGCC_WARNING_RESTORE()
} }
#endif #endif
break; break;
case wxSYS_COLOUR_INFOBK: case wxSYS_COLOUR_INFOBK:
sc = TooltipContext(path); sc.AddTooltip().Bg(color);
bg(sc, color);
break; break;
case wxSYS_COLOUR_INFOTEXT: case wxSYS_COLOUR_INFOTEXT:
sc = TooltipContext(path); sc.AddTooltip().AddLabel().Fg(color);
sc = StyleContext(sc, path, GTK_TYPE_LABEL, "label");
fg(sc, color);
break; break;
case wxSYS_COLOUR_LISTBOX: case wxSYS_COLOUR_LISTBOX:
sc = TreeviewContext(path); sc.AddTreeview().Bg(color);
bg(sc, color);
break; break;
case wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT: case wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT:
sc = TreeviewContext(path); sc.AddTreeview().Fg(color, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED);
fg(sc, color, GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED);
break; break;
case wxSYS_COLOUR_LISTBOXTEXT: case wxSYS_COLOUR_LISTBOXTEXT:
sc = TreeviewContext(path); sc.AddTreeview().Fg(color);
fg(sc, color);
break; break;
case wxSYS_COLOUR_MENU: case wxSYS_COLOUR_MENU:
sc = MenuContext(path); sc.AddMenu().Bg(color);
bg(sc, color);
break; break;
case wxSYS_COLOUR_MENUBAR: case wxSYS_COLOUR_MENUBAR:
sc = StyleContext(path, GTK_TYPE_MENU_BAR, "menubar", "menubar"); sc.Add(GTK_TYPE_MENU_BAR, "menubar", "menubar", NULL).Bg(color);
bg(sc, color);
break; break;
case wxSYS_COLOUR_MENUHILIGHT: case wxSYS_COLOUR_MENUHILIGHT:
sc = MenuItemContext(path); sc.AddMenuItem().Bg(color, GTK_STATE_FLAG_PRELIGHT);
bg(sc, color, GTK_STATE_FLAG_PRELIGHT);
break; break;
case wxSYS_COLOUR_MENUTEXT: case wxSYS_COLOUR_MENUTEXT:
sc = MenuItemContext(path); sc.AddMenuItem().AddLabel().Fg(color);
sc = StyleContext(sc, path, GTK_TYPE_LABEL, "label");
fg(sc, color);
break; break;
case wxSYS_COLOUR_APPWORKSPACE: case wxSYS_COLOUR_APPWORKSPACE:
case wxSYS_COLOUR_WINDOW: case wxSYS_COLOUR_WINDOW:
sc = TextviewContext(path); sc.AddTextview().Bg(color);
bg(sc, color);
break; break;
case wxSYS_COLOUR_3DDKSHADOW: case wxSYS_COLOUR_3DDKSHADOW:
color.Set(0, 0, 0); color.Set(0, 0, 0);
@@ -613,8 +599,6 @@ wxColour wxSystemSettingsNative::GetColour(wxSystemColour index)
break; break;
} }
gtk_widget_path_unref(path);
return color; return color;
} }
#else // !__WXGTK3__ #else // !__WXGTK3__
@@ -790,13 +774,10 @@ wxFont wxSystemSettingsNative::GetFont( wxSystemFont index )
g_signal_connect(gtk_settings_get_default(), "notify::gtk-font-name", g_signal_connect(gtk_settings_get_default(), "notify::gtk-font-name",
G_CALLBACK(notify_gtk_font_name), NULL); G_CALLBACK(notify_gtk_font_name), NULL);
} }
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc; sc.AddButton().AddLabel();
sc = ButtonLabelContext(path);
gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL,
GTK_STYLE_PROPERTY_FONT, &info.description, NULL); GTK_STYLE_PROPERTY_FONT, &info.description, NULL);
gtk_widget_path_unref(path);
StyleContextFree(sc);
#else #else
info.description = ButtonStyle()->font_desc; info.description = ButtonStyle()->font_desc;
#endif #endif
@@ -877,15 +858,12 @@ static int GetScrollbarWidth()
if (wx_is_at_least_gtk3(20)) if (wx_is_at_least_gtk3(20))
{ {
GtkBorder border; GtkBorder border;
GtkWidgetPath* path = gtk_widget_path_new(); wxGtkStyleContext sc;
GtkStyleContext* sc; sc.Add(GTK_TYPE_SCROLLBAR, "scrollbar", "scrollbar", "vertical", "right", NULL);
sc = StyleContext(path, GTK_TYPE_SCROLLBAR, "scrollbar", "right");
gtk_style_context_get_border(sc, GTK_STATE_FLAG_NORMAL, &border); gtk_style_context_get_border(sc, GTK_STATE_FLAG_NORMAL, &border);
sc = StyleContext(sc, path, G_TYPE_NONE, "contents"); sc.Add("contents").Add("trough").Add("slider");
sc = StyleContext(sc, path, G_TYPE_NONE, "trough");
sc = StyleContext(sc, path, G_TYPE_NONE, "slider");
gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, "min-width", &width, NULL); gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, "min-width", &width, NULL);
width += border.left + border.right; width += border.left + border.right;
@@ -896,9 +874,6 @@ static int GetScrollbarWidth()
width += border.left + border.right; width += border.left + border.right;
gtk_style_context_get_margin(sc, GTK_STATE_FLAG_NORMAL, &border); gtk_style_context_get_margin(sc, GTK_STATE_FLAG_NORMAL, &border);
width += border.left + border.right; width += border.left + border.right;
gtk_widget_path_unref(path);
StyleContextFree(sc);
} }
else else
#endif #endif